本章内容,将为你分享如何在本地开发环境中运行并调试OpenAI官方给出的案例。通过学习官方案例,可以帮助你了解如何开发ChatGPT插件的API服务。通过本章内容,你将了解到:
要了解ChatGPT插件开发的基本知识和开发流程,请阅读上一章内容:ChatGPT插件开发(基础知识)。
目录索引
这些插件,可以在本地计算机上或通过云开发环境(如GitHub Codespaces、Replit或CodeSandbox)上运行。本章内容,我们通过运行和调试前两个插件,也就是待办事项插件,来学习如何开发ChatGPT插件。
阅读本章内容最好拥有以下的相关知识:
下面,我们就来在本地安装的环境中运行此案例。
第一步:安装开发库
首先,需要安装两个相关的开发库quart和quart_cors,步骤如下:
开始 --> Anaconda prompt
conda activate yourEnv
(如果你的开发环境不是base,需要执行此步来激活环境)pip install quart
pip install quart_cors
第二步:创建API代码文件 plugin_todo_v1.py
开发库安装完成以后,打开Visual Studio Code,创建一个新的文件命名为 plugin_todo_v1.py,并将以下代码贴到文件中。并修改app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")
将allow_origin
访问限制部分删除。
import json
import quart
import quart_cors
from quart import request
#app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com")
app = quart_cors.cors(quart.Quart(__name__)) # 删除了只需要来自openai.com的访问限制
_TODOS = {} #定义存储TODO的变量
@app.post("/todos/<string:username>") # 响应POST请求,用来添加用户的TODO
async def add_todo(username): # 添加TODO函数
request = await quart.request.get_json(force=True)
if username not in _TODOS:
_TODOS[username] = []
_TODOS[username].append(request["todo"])
return quart.Response(response='OK', status=200)
@app.get("/todos/<string:username>") #响应GET请求,读取用户的TODO数据
async def get_todos(username):
return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200)
@app.delete("/todos/<string:username>")
async def delete_todo(username):
request = await quart.request.get_json(force=True)
todo_idx = request["todo_idx"]
# fail silently, it's a simple plugin
if 0 <= todo_idx < len(_TODOS[username]):
_TODOS[username].pop(todo_idx)
return quart.Response(response='OK', status=200)
@app.get("/logo.png") #响应读取logo的请求
async def plugin_logo():
filename = 'logo.png'
return await quart.send_file(filename, mimetype='image/png')
@app.get("/.well-known/ai-plugin.json") #响应读取manifest文件的请求
async def plugin_manifest():
host = request.headers['Host']
with open("manifest.json") as f:
text = f.read()
text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
return quart.Response(text, mimetype="text/json")
@app.get("/openapi.yaml") #响应读取openAPI规范文件的请求
async def openapi_spec():
host = request.headers['Host']
with open("openapi.yaml") as f:
text = f.read()
text = text.replace("PLUGIN_HOSTNAME", f"https://{host}")
return quart.Response(text, mimetype="text/yaml")
def main():
app.run(debug=True, host="0.0.0.0", port=5002) #启动服务
if __name__ == "__main__":
main()
第三步:创建API测试代码 plugin_todo_v1_test.py
API服务代码准备好以后,开始准备测试代码。新建 plugin_todo_v1_test.py 文件,并将下面的代码拷贝到文件中。下面的代码,分别用来测试添加,删除和读取待办事项。
import requests
import json
import sys
# 测试程序,接受一个或两个参数
# 参数1 opt:add,list, del
# 参数2: add时, todo的文本
# list , N/A
# del , todo_id{0, 1, 2...}
opt=sys.argv[1] #
# 设置请求头
headers = {
"Content-Type": "application/json"
}
if opt=="add":
todo=sys.argv[2]
# 准备数据
data = {
"todo": todo
}
# 发送POST请求
response = requests.post("http://127.0.0.1:5002/todos/john", headers=headers, data=json.dumps(data))
if opt=="list":
# 发送POST请求
response = requests.get("http://127.0.0.1:5002/todos/john", headers=headers)
if opt=="del":
_id=int(sys.argv[2])
data = {
"todo_idx": _id
}
response = requests.delete("http://127.0.0.1:5002/todos/john", headers=headers, data=json.dumps(data))
# 打印响应结果
print(response.status_code)
print(response.content)
print(response)
这段 Python 代码是一个使用 requests 库发送 HTTP GET 请求的示例。该请求发送到本地主机上的 http://127.0.0.1:5002/todos/john API 端点。requests.get 方法是用于发送 HTTP GET 请求的函数。它接受两个参数。第一个参数是请求的 URL,这里是 http://127.0.0.1:5002/todos/john。第二个参数是一个可选参数,用于指定请求头部信息,这里是 headers 变量。在发送请求之后,响应数据被存储在 response 变量中。您可以使用 response 对象访问响应状态码、响应头部和响应体。例如,要获取响应体的 JSON 数据,可以使用 response.json() 方法。
第四步:测试
测试步骤如下:
操作步骤如下:
第一步:API服务端设置
复制 plugin_todo_v1.py 文件并重命名为plugin_todo_v2.py,并添加以下代码:
_SERVICE_AUTH_KEY = "yourAuthKey"
# Bearer 是身份验证协议 OAuth 2.0 中的一种类型
def assert_auth_header(req):
assert req.headers.get(
"Authorization", None) == f"Bearer {_SERVICE_AUTH_KEY}"
以上代码定义了一个 _SERVICE_AUTH_KEY 字符串变量,用来存储身份验证的令牌。然后,代码定义了一个名为 assert_auth_header 的函数,该函数用于验证请求头中是否包含了正确的身份验证令牌。
在函数内部,它检查传入的请求对象 req 的 header 中是否包含了一个名为 "Authorization" 的字段,并将其值与 _SERVICE_AUTH_KEY 拼接成一个 "Bearer" 令牌进行比较。如果两个值不相等,那么该函数将会抛出一个 AssertionError,表示身份验证失败。
为 add_todo,get_todos,delete_todo 函数中添加用来验证身份的代码。
assert_auth_header(quart.request)
在 add_todo,get_todos 和 delete_todo 函数中,assert_auth_header 函数用于验证请求头部是否包含了正确的身份验证令牌。如果身份验证失败,那么 assert_auth_header 函数将会抛出 AssertionError,并且函数不会继续执行。
通过将 assert_auth_header 函数嵌入到 add_todo,get_todos 和 delete_todo 函数中,可以确保这些函数只有在正确的身份验证令牌被传递时才会执行。这可以提高您的 API 的安全性,并保护其免受未经授权的访问。
第二步:测试代码部分修改
下面需要对测试代码进行相应的修改, 复制 plugin_todo_v1_test.py 为 plugin_todo_v2_test.py,并在文件中添加以下代码:
# 设置身份验证密钥
_SERVICE_AUTH_KEY = "yourAuthKey"
# 设置请求头
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {_SERVICE_AUTH_KEY}"
}
和上面的类似,_SERVICE_AUTH_KEY 是身份验证密钥。 headers 是一个字典,用于存储请求头部信息。在这个示例中,它包含了两个键值对。第一个键值对是 "Content-Type",其值为 "application/json",指定了请求体的 MIME 类型。第二个键值对是 "Authorization",其值为 "Bearer" 令牌,它包含了 _SERVICE_AUTH_KEY 的值,并指定了身份验证类型。
第三步:测试
测试步骤如下: