學習如何構建一個帶有服務級認證的簡單待辦事項插件。
首先,查看服務級認證頁面,然後定義一個 ai-plugin.json 文件,其中包含以下字段:
```json
{
"schema_version": "v1",
"name_for_human": "待辦事項列表(服務認證)",
"name_for_model": "todo",
"description_for_human": "管理您的待辦事項列表。您可以添加、删除和查看您的待辦事項。",
"description_for_model": "用于管理待辦事項列表的插件,您可以添加、删除和查看您的待辦事項。",
"auth": {
"type": "service_http",
"authorization_type": "bearer",
"verification_tokens": {
"openai": "請用在ChatGPT用戶界面中生成的驗證令牌替換此字符串"
}
},
"api": {
"type": "openapi",
"url": "https://example.com/openapi.yaml"
},
"logo_url": "https://example.com/logo.png",
"contact_email": "support@example.com",
"legal_info_url": "https://example.com/legal"
}
```
請注意,服務級認證插件需要驗證令牌。在您設置服務訪問令牌後,該令牌是在ChatGPT web UI中的插件安裝過程中生成的。
您還需要将 "example.com" 更新為您的遠程服務器的名稱。
接下來,我們可以定義API端點,為特定用戶創建、删除和獲取待辦事項列表。端點還檢查用戶是否已認證。
```python
import json
import quart
import quart_cors
from quart import requestapp = quart_cors.cors(quart.Quart(__name__))
# 此密鑰可以是任何内容,盡管您可能希望随機生成一個序列。
_SERVICE_AUTH_KEY = "REPLACE_ME"
_TODOS = {}def assert_auth_header(req):
assert req.headers.get(
"Authorization", None) == f"Bearer {_SERVICE_AUTH_KEY}"@app.post("/todos/<string:username>")
async def add_todo(username):
assert_auth_header(quart.request)
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>")
async def get_todos(username):
assert_auth_header(quart.request)
return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200)@app.delete("/todos/<string:username>")
async def delete_todo(username):
assert_auth_header(quart.request)
request = await quart.request.get_json(force=True)
todo_idx = request["todo_idx"]
if 0 <= todo_idx < len(_TODOS[username]):
_TODOS[username].pop(todo_idx)
return quart.Response(response='OK', status=200)@app.get("/logo.png")
async def plugin_logo():
filename = 'logo.png'
return await quart.send_file(filename, mimetype='image/png')@app.get("/.well-known/ai-plugin.json")
async def plugin_manifest():
host = request.headers['Host']
with open("ai-plugin.json") as f:
text = f.read()
return quart.Response(text, mimetype="text/json")@app.get("/openapi.yaml")
async def openapi_spec():
host = request.headers['Host']
with open("openapi.yaml") as f:
text = f.read()
return quart.Response(text, mimetype="text/yaml")def main():
app.run(debug=True, host="0.0.0.0", port=5002)if __name__ == "__main__":
main()
```
最後,我們需要設置并定義一個OpenAPI規範,以匹配我們遠程服務器上定義的端點。通常,無論認證方法如何,OpenAPI規範的外觀都是相同的。使用自動OpenAPI生成器在創建您的OpenAPI規範時可以減少出錯的機會。
openapi: 3.0.1
info:
title: TODO Plugin
description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global".
version: "v1"
servers:
- url: https://example.com
paths:
/todos/{username}:
get:
operationId: getTodos
summary: Get the list of todos
parameters:
- in: path
name: username
schema:
type: string
required: true
description: The name of the user.
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/getTodosResponse"
post:
operationId: addTodo
summary: Add a todo to the list
parameters:
- in: path
name: username
schema:
type: string
required: true
description: The name of the user.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/addTodoRequest"
responses:
"200":
description: OK
delete:
operationId: deleteTodo
summary: Delete a todo from the list
parameters:
- in: path
name: username
schema:
type: string
required: true
description: The name of the user.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/deleteTodoRequest"
responses:
"200":
description: OKcomponents:
schemas:
getTodosResponse:
type: object
properties:
todos:
type: array
items:
type: string
description: The list of todos.
addTodoRequest:
type: object
required:
- todo
properties:
todo:
type: string
description: The todo to add to the list.
required: true
deleteTodoRequest:
type: object
required:
- todo_idx
properties:
todo_idx:
type: integer
description: The index of the todo to delete.
required: true
评论