Merge branch 'code_interpreter' of https://github.com/garylin2099/MetaGPT into ci_dev

This commit is contained in:
yzlin 2024-02-07 21:52:35 +08:00
commit 42f3aaf18b
5 changed files with 146 additions and 1 deletions

27
examples/email_summary.py Normal file
View file

@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
"""
@Date : 2024/02/07
@Author : Tuo Zhou
@File : email_summary.py
"""
from metagpt.roles.ci.code_interpreter import CodeInterpreter
async def main():
# For email response prompt
email_account = "your_email_account"
# prompt = f"""I will give you your Outlook email account({email_account}) and password(email_password item in the environment variable). You need to find the latest email in my inbox with the sender's suffix @qq.com and reply to him "Thank you! I have received your email~"""""
prompt = f"""I will give you your Outlook email account({email_account}) and password(email_password item in the environment variable).
Firstly, Please help me fetch the latest 5 senders and full letter contents.
Then, summarize each of the 5 emails into one sentence(you can do this by yourself, no need import other models to do this) and output them in a markdown format."""
ci = CodeInterpreter(use_tools=True)
await ci.run(prompt)
if __name__ == "__main__":
import asyncio
asyncio.run(main())

View file

@ -10,6 +10,14 @@ from metagpt.tools.libs import (
sd_engine,
gpt_v_generator,
web_scraping,
email_login,
)
_ = data_preprocess, feature_engineering, sd_engine, gpt_v_generator, web_scraping # Avoid pre-commit error
_ = (
data_preprocess,
feature_engineering,
sd_engine,
gpt_v_generator,
web_scraping,
email_login,
) # Avoid pre-commit error

View file

@ -0,0 +1,58 @@
from imap_tools import MailBox
from metagpt.logs import logger
from metagpt.tools.tool_registry import register_tool
from metagpt.tools.tool_type import ToolType
# Define a dictionary mapping email domains to their IMAP server addresses
IMAP_SERVERS = {
"outlook.com": "imap-mail.outlook.com", # Outlook
"163.com": "imap.163.com", # 163 Mail
"qq.com": "imap.qq.com", # QQ Mail
"gmail.com": "imap.gmail.com", # Gmail
"yahoo.com": "imap.mail.yahoo.com", # Yahoo Mail
"icloud.com": "imap.mail.me.com", # iCloud Mail
"hotmail.com": "imap-mail.outlook.com", # Hotmail (同 Outlook)
"live.com": "imap-mail.outlook.com", # Live (同 Outlook)
"sina.com": "imap.sina.com", # Sina Mail
"sohu.com": "imap.sohu.com", # Sohu Mail
"yahoo.co.jp": "imap.mail.yahoo.co.jp", # Yahoo Mail Japan
"yandex.com": "imap.yandex.com", # Yandex Mail
"mail.ru": "imap.mail.ru", # Mail.ru
"aol.com": "imap.aol.com", # AOL Mail
"gmx.com": "imap.gmx.com", # GMX Mail
"zoho.com": "imap.zoho.com", # Zoho Mail
}
@register_tool(tool_type=ToolType.EMAIL_LOGIN.type_name)
def email_login_imap(email_address, email_password):
"""
Use imap_tools package to log in to your email (the email that supports IMAP protocol) to verify and return the account object.
Args:
email_address (str): Email address that needs to be logged in and linked.
email_password (str): Password for the email address that needs to be logged in and linked.
Returns:
object: The imap_tools's MailBox object returned after successfully connecting to the mailbox through imap_tools, including various information about this account (email, etc.), or None if login fails.
"""
# Extract the domain from the email address
domain = email_address.split("@")[-1]
# Determine the correct IMAP server
imap_server = IMAP_SERVERS.get(domain)
if not imap_server:
logger.error(f"IMAP server for {domain} not found.")
return None
# Attempt to log in to the email account
try:
mailbox = MailBox(imap_server).login(email_address, email_password)
logger.info("Login successful")
return mailbox
except Exception as e:
logger.error(f"Login failed: {e}")
return None

View file

@ -22,6 +22,10 @@ class ToolType(Enum):
desc="Only for changing value inplace.",
usage_prompt=DATA_PREPROCESS_PROMPT,
)
EMAIL_LOGIN = ToolTypeDef(
name="email_login",
desc="For logging to an email.",
)
FEATURE_ENGINEERING = ToolTypeDef(
name="feature_engineering",
desc="Only for creating new columns for input data.",

View file

@ -0,0 +1,48 @@
import os
import pytest
from metagpt.tools.libs.email_login import email_login_imap
# Configuration for the test IMAP servers
TEST_IMAP_SERVERS = {"outlook.com": "imap-mail.outlook.com"}
# Setup correct and incorrect email information
correct_email_address = "englishgpt@outlook.com"
correct_email_password = os.environ.get("outlook_email_password")
incorrect_email_address = "test@unknown.com"
incorrect_email_password = "incorrect_password"
@pytest.fixture
def imap_server_setup(mocker):
# Use the mocker fixture to mock the MailBox class
mock_mailbox = mocker.patch("metagpt.tools.libs.email_login.MailBox")
mock_mail_instance = mocker.Mock()
mock_mail_instance.login.return_value = mock_mail_instance
mock_mailbox.return_value = mock_mail_instance
return mock_mail_instance
def test_email_login_imap_success(imap_server_setup):
# Mock successful login
mailbox = email_login_imap(correct_email_address, correct_email_password)
assert mailbox is not None
# Correctly assert that the login method of the MailBox mock was called with the correct arguments
imap_server_setup.login.assert_called_with(correct_email_address, correct_email_password)
def test_email_login_imap_failure_due_to_incorrect_server(imap_server_setup):
# Attempt to login with an incorrect server
mailbox = email_login_imap(incorrect_email_address, incorrect_email_password)
assert mailbox is None
def test_email_login_imap_failure_due_to_wrong_credentials(imap_server_setup):
# Configure mock to throw an exception to simulate login failure due to incorrect credentials
imap_server_setup.login.side_effect = Exception("Login failed")
# Attempt to login which should simulate a failure
mailbox = email_login_imap(correct_email_address, incorrect_email_password)
assert mailbox is None
# Verify that the login method was called with the expected arguments
imap_server_setup.login.assert_called_with(correct_email_address, incorrect_email_password)