OpenAI开发系列(十四):通过Google API赋能大模型,打造智能邮件助理

授权声明: 本文基于九天Hector的原创课程资料创作,已获得其正式授权。
原课程出处:九天Hector的B站主页,感谢九天Hector为学习者带来的宝贵知识。
请尊重原创,转载或引用时,请标明来源。

全文共4000余字,预计阅读时间约20~35分钟 | 满满干货(附代码),建议收藏!

本文目标:提供一个结合OpenAI的Chat模型和Google API来开发智能邮件应用程序的详细构建流程

image-20230830130853352

代码下载点这里

一、介绍

大模型应用开发从谷歌云入手进行学习和尝试,是门槛最低、效率最高的方法。谷歌云上不仅有成百上千的各类应用的API,而且拥有统一的API制式和权限管理方法,调用过程非常方便,一个账号进行一次项目认证即可使用海量的API,外加详细完整的开发者文档,更是极大程度降低了上手使用API的门槛。

同时,谷歌云是功能完备的应用开发平台,如果不仅是尝试使用API进行前期的探索,而是希望真正意义上的完成企业级应用开发,也完全可以在谷歌云上进行。谷歌云不仅提供了完整的在线应用开发与发布流程,而且提供了(相对)廉价、稳定的云服务,开发者开发的应用程序可以直接在云端运行,并享受谷歌云提供的一整套应急、维护流程,以及实时可视化监控页面。

一个真实存在的问题是:国内还是存在访问限制,需要使用魔法

本文介绍一下如何将Gmail API接入Chat Completion模型,编写一个智能收发邮件的AI应用程序,起到一个抛砖引玉的作用。

二、Gmail API的OAuth授权

要调用谷歌的API,第一步是要进行授权。具体谷歌云Google Cloud与谷歌云API库的介绍,及如何完成Gmail API的OAuth授权过程,如果您了解的话可以跳过这一步,直接进入下面代码内容,如不清楚如何操作的,请看下面链接:

AI应用开发:Gmail API如何实现OAuth授权

Gmail API的OAuth授权过程的成功实现非常重要,使用谷歌云的其他API来构建更加复杂的AI应用程序,其中大多数都需要进行OAuth授权,如果已经完成了授权,则该凭证也是可以应用于其他API调用的,完成授权也是进行AI应用程序开发的前提。

三、借助Gmail API构建智能邮件收发应用程序

3.1 在Chat Completion模型中添加查阅邮件功能

先尝试将Gmail API接入Chat Completion模型中。在这三篇文章中:

OpenAI开发系列(十一):Function calling功能的实际应用流程与案例解析

OpenAI开发系列(十二):Function calling功能的流程优化与多轮对话实现

OpenAI开发系列(十三):利用Function calling功能开发基于大模型的实时天气查询助手

已经跑通了优化后的Function calling功能执行流程,对于开发一个AI应用程序,在确定了基本功能实现的目标之后,总共分四步进行:

  1. 按照需求编写外部功能函数并完成功能测试,确保函数可以正确运行
  2. 验证大语言模型是否具备解读外部函数结果和准确翻译外部函数参数的能力
  3. 将函数带入AutoFunctionGenerator封装类中,自动生成一系列功能函数的 JSON Schema 描述。
  4. 调用ChatConversation封装类,激活Function Calling功能,并输出最终推理结果

按照上述过程,要基于大模型实现基于Gmail API收发邮件的AI小程序,具体实现过程如下:

  • Step 1:测试外部函数功能可行性

当完成Gmail API的OAuth授权后,先测试能否通过调用Gmail API查阅最近的一封邮件信息,包括发件人、日期和邮件内容,代码如下:

def get_gmail_service(token_file):
    """
    从本地文件中加载授权凭据,并返回Gmail API客户端。

    参数:
    - token_file (str): 包含授权凭据的本地文件名。

    返回:
    - service: Gmail API客户端。
    """
    # 从本地文件加载授权凭据
    creds = Credentials.from_authorized_user_file(token_file)
    
    # 创建并返回Gmail API客户端
    service = build('gmail', 'v1', credentials=creds)
    return service

def print_latest_email_info(service):
    """
    获取并打印用户的最新一封邮件的信息。

    参数:
    - service: Gmail API客户端。

    返回:
    无。
    """
    # 获取最新一封邮件的ID
    results = service.users().messages().list(userId='me', maxResults=1).execute()
    messages = results.get('messages', [])
    
    # 遍历邮件列表(这里只有一封邮件)
    for message in messages:
        # 获取邮件详细信息
        msg = service.users().messages().get(userId='me', id=message['id']).execute()
        
        # 获取邮件头部信息
        headers = msg['payload']['headers']
        
        # 初始化发件人和日期字段
        From, Date = "", ""
        
        # 提取发件人和日期信息
        for h in headers:
            name = h['name']
            if name.lower() == 'from':
                From = h['value']
            if name.lower() == 'date':
                Date = h['value']

        # 判断邮件是否有多个部分(例如正文和附件)
        if 'parts' in msg['payload']:
            part = msg['payload']['parts'][0]
            data = part['body']["data"] if part['mimeType'] == 'text/plain' else msg['payload']['body']["data"]
        else:
            data = msg['payload']['body']["data"]

        # 将数据从base64格式解码为文本
        data = data.replace("-", "+").replace("_", "/")
        decoded_data = base64.b64decode(data)
        str_text = str(decoded_data, "utf-8")
        
        # 将解码后的数据转换为email.message.Message对象
        msg_str = email.message_from_string(str_text)

        # 如果邮件有多个部分,只取第一个部分(通常是正文)
        if msg_str.is_multipart():
            text = msg_str.get_payload()[0]
        else:
            text = msg_str.get_payload()

        # 打印邮件信息
        print('From: {}'.format(From[:8]))
        print('Date: {}'.format(Date))
        print('Content: {}'.format(text))

看下输出结果:

# 示例使用
if __name__ == "__main__":
    # 获取Gmail API客户端
    service = get_gmail_service('token.json')
    
    # 获取并打印最新一封邮件的信息
    print_latest_email_info(service)

image-20230830085925424

看下邮箱状态:

image-20230727160611804

上述代码的核心流程是通过service.users().messages().list(userId=‘me’, maxResults=1).execute()获取了最近一封邮件的信息,并最终保留在msg中。

更多关于Gmail API返回结果信息可参考Gmail API官网功能介绍:https://developers.google.com/gmail/api/guides

  • Step 2:验证模型能否解读Gmail API返回结果

Gmail API 在不处理的情况下,返回的结果是这样的:

image-20230727160830560

尝试直接让Chat Completion模型解读msg结果,测试其解读邮件内容的能力,代码如下:

import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")

response = openai.ChatCompletion.create(
  model="gpt-4-0613",
  messages=[
    {"role": "system", "content": "我现在有一封邮件是通过Gmail API获取到的,在我Gmail邮箱中,最新的一封邮件内容如下:%s" % msg},
    {"role": "user", "content": "请问一下,这封邮件是谁发发送给我的,内容是什么?"}
  ]
)
response.choices[0].message['content']

看下输出结果:

image-20230727161135323

所以这也就意味着:使用Chat Completion模型来解析Gmail邮件内容是一个有效且可行的方案,因为该模型能准确地理解邮件中包含的信息。

  • Step 3:创建外部功能函数

按照Step 1中的代码流程,创建一个能够返回最近一封邮件信息的msg对象,并输出为JSON格式,函数如下:

def fetch_latest_gmail_content(userId):
    """
    查询指定用户ID的Gmail邮箱中的最后一封邮件信息。
    
    参数:
    userId (str): 必填参数。表示需要查询的Gmail用户ID。注意,如果查询自己的邮箱,\
    userId需设置为'me'。

    返回:
    str: 包含最后一封邮件全部信息的JSON格式字符串。该对象由Gmail API创建并返回。\
    如果查询失败,返回包含错误信息的JSON格式字符串。
    """
    # 从本地文件中加载凭据
    creds = Credentials.from_authorized_user_file('token.json')
    
    # 创建 Gmail API 客户端
    service = build('gmail', 'v1', credentials=creds)
    
    # 列出用户的一封最新邮件
    results = service.users().messages().list(userId=userId, maxResults=1).execute()
    messages = results.get('messages', [])

    # 遍历邮件
    for message in messages:
        # 获取邮件的详细信息
        msg = service.users().messages().get(userId='me', id=message['id']).execute()
        
    # 只处理最新的邮件(列表中的第一个)
    if messages:
        # 获取邮件的详细信息
        msg = service.users().messages().get(userId=userId, id=messages[0]['id']).execute()
        return json.dumps(msg)
    else:
        return json.dumps({"error": "No messages found."})
  • Step 4:构建功能函数的JSON Schema对象

直接使用封装好的AutoFunctionGenerator类来为fetch_latest_gmail_content生成相应的JSON Schema对象。

functions_list = [fetch_latest_gmail_content]
generator = AutoFunctionGenerator(functions_list)
function_descriptions = generator.auto_generate()

看一下执行结果:

image-20230830092805416

  • Step 5:测试大模型是否能识别外部功能函数库

直接调用测试Chat Completion模型能否顺利创建满足格式的参数:

response = openai.ChatCompletion.create(
        model="gpt-4-0613",
        messages=[{"role": "user", "content": '请帮我查下我Gmail邮箱中最后一封邮件信息'}],
        functions=functions,
        function_call="auto",  
    )

看下结果:

image-20230830093059944

  • Step 4:验证对话效果

最后来测试下对话效果,还是使用优化好的messages自动拼接流程ChatConversation封装类和多轮对话函数chat_with_assistant

先测试不带入外部函数仓库时:

image-20230830093641821

再测试带入外部功能函数时:

image-20230830093755085

3.2 在Chat Completion模型中添加发送邮件功能

  • Step 1:重新获取授权

在谷歌云API中,一个API类别可能有多个功能,每个功能可能需要单独的授权。这主要通过设置SCOPES变量来实现,该变量是一个包含多个URL的列表。每个URL代表一个特定的API功能或权限。例如,以gmail.send结尾的URL表示发送邮件的权限,而以gmail.readonly结尾的URL则表示只有阅读邮件的权限。

目前生成的token.json仅包含阅读邮件的API授权,而没有包括发送邮件的权限。因此,首先需要更新API权限,以获得Gmail发送邮件的授权。可以使用之前用于获取授权的相同代码,但需在授权过程中添加发送邮件的权限。将新的授权文件保存为本地的token_send.json

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

SCOPES = ['https://www.googleapis.com/auth/gmail.send']

flow = InstalledAppFlow.from_client_secrets_file(
                # 此处替换你下载的OAuth授权命名文件
                'credentials-web1.json', SCOPES)
# 此处替换你自己设置的端口
creds = flow.run_local_server(port=9090, access_type='offline', prompt='consent')

with open('token_send.json', 'w') as token:
    token.write(creds.to_json())

如果这里不清楚怎么授权的,看Gmail API的OAuth授权部分

具体不同的API功能对应可以参考官方说明:https://developers.google.com/gmail/api/auth/scopes?hl=zh_CN

也可以一次性获得包含多个权限的授权文件,此时SCOPES可以按照如下方式进行定义,此时授权文件可以同时允许执行文件阅读和发送:

SCOPES = ['https://www.googleapis.com/auth/gmail.send','https://www.googleapis.com/auth/gmail.readonly']
  • Step 2:测试发送功能

完成授权之后,即可使用Gmail的发送邮件功能了,将授权文件改为token_send.json,具体代码实现流程如下:

from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from email.mime.text import MIMEText
import base64
import json

def send_email_via_gmail_api(to, subject, message_text, creds_file='token_send.json'):
    """
    使用 Gmail API 发送邮件。
    
    参数:
    - to (str): 接收者的邮箱地址。
    - subject (str): 邮件的主题。
    - message_text (str): 邮件的正文内容。
    - creds_file (str): 存储 Gmail API 凭据的本地 JSON 文件名。
    
    返回:
    - dict: 如果发送成功,返回一个包含发送邮件的 ID 和状态的字典。如果发送失败,返回 None。
    """
    
    def create_message(to, subject, message_text):
        """创建一个 MIME 邮件对象"""
        message = MIMEText(message_text)
        message['to'] = to
        message['from'] = 'me'  # 'me' 表示授权用户自己
        message['subject'] = subject
        raw_message = base64.urlsafe_b64encode(message.as_string().encode('utf-8')).decode('utf-8')
        return {
            'raw': raw_message
        }

    def send_message(service, user_id, message):
        """使用 Gmail API 发送邮件"""
        try:
            sent_message = service.users().messages().send(userId=user_id, body=message).execute()
            print(f'Message Id: {sent_message["id"]}')
            return sent_message
        except Exception as e:
            print(f'An error occurred: {e}')
            return None

    # 从本地 JSON 文件加载 Gmail API 凭据
    creds = Credentials.from_authorized_user_file(creds_file)
    
    # 创建 Gmail API 客户端
    service = build('gmail', 'v1', credentials=creds)
    
    # 创建邮件消息
    message = create_message(to, subject, message_text)
    
    # 发送邮件消息
    result = send_message(service, 'me', message)
    
    return json.dumps(result)

看下函数的测试结果:

# 示例用法
to_address = 'snowball950123@gmail.com'
subject = '测试'
message_text = '测试 Gmail API 的邮件发送功能'
result = send_email_via_gmail_api(to_address, subject, message_text)
print(f"发送结果: {result}")

image-20230830102930102

看下邮箱是否收到:

image-20230830103036418

  • Step 3:封装发送邮件的功能函数
def send_email(to, subject, message_text):
    """
    借助Gmail API创建并发送邮件函数
    :param to: 必要参数,字符串类型,用于表示邮件发送的目标邮箱地址;
    :param subject: 必要参数,字符串类型,表示邮件主题;
    :param message_text: 必要参数,字符串类型,表示邮件全部正文;
    :return:返回发送结果字典,若成功发送,则返回包含邮件ID和发送状态的字典。
    """
    
    creds_file='token_send.json'
    
    def create_message(to, subject, message_text):
        """创建一个MIME邮件"""
        message = MIMEText(message_text)
        message['to'] = to
        message['from'] = 'me'
        message['subject'] = subject
        raw_message = base64.urlsafe_b64encode(message.as_string().encode('utf-8')).decode('utf-8')
        return {
            'raw': raw_message
        }

    def send_message(service, user_id, message):
        """发送邮件"""
        try:
            sent_message = service.users().messages().send(userId=user_id, body=message).execute()
            print(f'Message Id: {sent_message["id"]}')
            return sent_message
        except Exception as e:
            print(f'An error occurred: {e}')
            return None

    # 从本地文件中加载凭据
    creds = Credentials.from_authorized_user_file(creds_file)

    # 创建 Gmail API 客户端
    service = build('gmail', 'v1', credentials=creds)

    message = create_message(to, subject, message_text)
    res = send_message(service, 'me', message)

    return json.dumps(res)
  • Step 4:测试下functions参数
functions_list = [send_gmail]
generator = AutoFunctionGenerator(functions_list)
function_descriptions = generator.auto_generate()

看下生成的JSON Schema对象描述:

image-20230830123859581

  • Step 5:测试Chat Completion是否能正确解析
response = openai.ChatCompletion.create(
        model="gpt-4-0613",
        messages=[{"role": "user", "content": '我想发送一个Gmail邮件,主要内容是:让小陈明天早上9点半来我办公室开会,商量一下我的100亿该怎么花'}],
        functions=functions,
        function_call="auto"
    )

response

看下返回结果:

image-20230728095249243

模型会根据语义创建邮件的主题和内容

  • Step 6:多轮对话验证

当不调用外部功能函数时:

chat_with_assistant()

看下对话过程:

image-20230830124655682

当调用send_email外部功能函数时:

functions_list = [send_email]
chat_with_assistant(functions_list=functions_list)

看一下对话过程:

image-20230830124344782

然后在邮箱中查看查收的邮件:

image-20230830124906260

至此,就将邮件发送功能也完整集成到Chat Completion模型当中了。

3.3 在Chat模型中同时调用邮件发送和查询功能

在分别跑通了邮件发送功能之后,可以尝试在一个对话中同时调用这两个功能。毕竟大多数AI应用都是围绕某一方面应用的多功能集合,例如对于一个智能收发邮件助手的AI应用来说,收件和发件肯定是最基本的功能需求。

要在一个Chat模型中集成收件和发件两方面功能,只需要在functions_list同时添加get_latest_email和send_email即可,代码如下:

functions_list = [fetch_latest_gmail_content, send_email]
chat_with_assistant(functions_list=functions_list)

看下结果:

image-20230830100906058

image-20230729094428977

至此,就完成了在一个Chat Completion对话中同时调用发件和收件功能。

四、总结

随着Chat Completion模型集成的外部工具API越来越丰富,其智能化的应用范围也逐渐扩大。不过,需要清楚的认识到:集成这些外部工具API并不是一件简单的事情。这不仅需要获取各种API的访问权限,还需要具备相应的编程和API调用知识。例如,仅仅为了开发一个能够智能收发邮件的应用,就需要投入大量时间去理解API授权和函数编写,所以如何利用大模型来协助开发者完成这些中间过程,是一个非常有价值的研究和探索方向

最后,感谢您阅读这篇文章!如果您觉得有所收获,别忘了点赞、收藏并关注我,这是我持续创作的动力。您有任何问题或建议,都可以在评论区留言,我会尽力回答并接受您的反馈。如果您希望了解某个特定主题,也欢迎告诉我,我会乐于创作与之相关的文章。谢谢您的支持,期待与您共同成长!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
AI模型赋能人形机器人可以被视为迈向通用人工智能的一大步。人形机器人是一种能够模拟人类外貌、行为和交流的机器,结合AI模型的能力,可以实现更高级别的人工智能功能。 首先,AI模型的强大计算能力和学习能力使得人形机器人能够更加准确地理解和模仿人类的动作和表情。通过对大量数据的学习,AI模型能够理解并推断人类的情绪、意图和行为,从而更好地与人类进行交互和沟通。这种与人类的自然交流方式可以让机器人更好地融入人类社会,满足人类的各种需求。 其次,AI模型赋能的人形机器人在应用领域具有广泛的潜力。例如,在医疗领域,人形机器人可以通过感知和理解病人的情绪和需求来提供情感支持和护理服务。在教育领域,人形机器人可以根据学生的学习情况和兴趣定制教学内容,提供个性化的教育体验。在服务行业中,人形机器人可以担任引导员、导游员等角色,为人们提供导航和咨询服务。 最后,AI模型赋能的人形机器人还有助于推动人工智能技术的发展和创新。通过将大模型与机器人相结合,各种新的应用和功能不断涌现出来。同时,人形机器人的使用也可以促进对于伦理、隐私和安全等相关问题的讨论和解决。 总的来说,AI模型赋能人形机器人是迈向通用人工智能的一大步。它能够实现更加准确和自然的人机交互,拓展人工智能在各个领域的应用,并推动人工智能技术的发展和创新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法小陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值