灵儿巴斯

 找回密码
 立即注册
查看: 1086|回复: 0

使用esp32驱动chatgpt

[复制链接]

110

主题

29

回帖

658

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
658
发表于 2024-1-11 01:33:02 | 显示全部楼层 |阅读模式
在 MicroPython 中使用 OpenAI API - DEV Community

https://dev.to/codemee/zai-micropython-zhong-shi-yong-openai-api-2epc
OpenAI 雖然提供有 [color=var(--link-branded-color)]Python 的官方套件, 不過如果你是要在 MicroPython 中使用 OpeAnAI 的 API, 並不能直接套用, 這時就要回歸到 OpenAI API 最根本的 HTTP Post API 了。
最簡單的 OpenAI API
OpenAI 是透過 HTTP Post 提供服務, 以聊天為例, 用的是 [color=var(--link-branded-color)]ChatCompletion 服務:
因此, 最簡單的 OpenAI HTTP Post API 的程式就像是這樣:
[color=var(--syntax-text-color)][color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]requests[color=var(--syntax-text-color)]API_KEY [color=var(--syntax-error-color)]= [color=var(--syntax-string-color)]'你的 OpenAI API 金鑰'[color=var(--syntax-text-color)]response [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]requests[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]post[color=var(--syntax-text-color)](    [color=var(--syntax-string-color)]'https://api.openai.com/v1/chat/completions'[color=var(--syntax-text-color)],    [color=var(--syntax-text-color)]headers [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'Authorization'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'Bearer ' [color=var(--syntax-error-color)]+ [color=var(--syntax-text-color)]API_KEY    [color=var(--syntax-text-color)]},    [color=var(--syntax-text-color)]json [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'model'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'gpt-3.5-turbo'[color=var(--syntax-text-color)],        [color=var(--syntax-string-color)]"messages"[color=var(--syntax-text-color)]: [color=var(--syntax-text-color)][{[color=var(--syntax-string-color)]"role"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"user"[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"你好"[color=var(--syntax-text-color)]}]}[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]status_code[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]reason[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]reply [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]json[color=var(--syntax-text-color)]()[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]reply[color=var(--syntax-text-color)][[color=var(--syntax-string-color)]"choices"[color=var(--syntax-text-color)]][[color=var(--syntax-literal-color)]0[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"message"[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]])


執行結果如下:
[color=var(--syntax-text-color)]>>> %Run openai_pc.py  200  OK  您好!我是语言模型AI的GPT-3,有什么可以帮助您的吗?


改用 MicroPython
既然是使用 HTTP Post, 哪麼只要從 requests 模組改成 urequests 模組, 應該就可以原封不動照搬程式了, 我們來試看看:
[color=var(--syntax-text-color)][color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]network     [color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]time[color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]urequests[color=var(--syntax-comment-color)]# 連線至無線網路[color=var(--syntax-text-color)]sta[color=var(--syntax-error-color)]=[color=var(--syntax-text-color)]network[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]WLAN[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]network[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]STA_IF[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]active[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]True[color=var(--syntax-text-color)])   [color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]connect[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'你的無線網路名稱'[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]'無線網路密碼'[color=var(--syntax-text-color)])  [color=var(--syntax-declaration-color)]while [color=var(--syntax-error-color)]not [color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]isconnected[color=var(--syntax-text-color)]() [color=var(--syntax-text-color)]:    [color=var(--syntax-declaration-color)]pass[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'Wi-Fi連線成功'[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]API_KEY [color=var(--syntax-error-color)]= [color=var(--syntax-string-color)]'你的 OpenAI API 金鑰'[color=var(--syntax-text-color)]response [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]urequests[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]post[color=var(--syntax-text-color)](    [color=var(--syntax-string-color)]'https://api.openai.com/v1/chat/completions'[color=var(--syntax-text-color)],    [color=var(--syntax-text-color)]headers [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'Authorization'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'Bearer ' [color=var(--syntax-error-color)]+ [color=var(--syntax-text-color)]API_KEY    [color=var(--syntax-text-color)]},    [color=var(--syntax-text-color)]json [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'model'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'gpt-3.5-turbo'[color=var(--syntax-text-color)],        [color=var(--syntax-string-color)]"messages"[color=var(--syntax-text-color)]: [color=var(--syntax-text-color)][{[color=var(--syntax-string-color)]"role"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"user"[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"你好"[color=var(--syntax-text-color)]}]}[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]status_code[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]reason[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]reply [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]json[color=var(--syntax-text-color)]()[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]reply[color=var(--syntax-text-color)][[color=var(--syntax-string-color)]"choices"[color=var(--syntax-text-color)]][[color=var(--syntax-literal-color)]0[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"message"[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]])


不過執行後就會看到 OpenAI 伺服器端回覆 400 錯誤:
[color=var(--syntax-text-color)]>>> %Run -c $EDITOR_CONTENT  Wi-Fi連線成功  400  b'Bad Request'  Traceback (most recent call last):    File "<stdin>", line 32, in <module>  KeyError: choices


同樣的錯誤, 搬到 MicroPython 上會出錯, 第一個懷疑的就是中文編碼的問題, 如果把程式中傳遞的 "你好" 改成純英文試看看:
[color=var(--syntax-text-color)][color=var(--syntax-text-color)]...    [color=var(--syntax-text-color)]json [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'model'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'gpt-3.5-turbo'[color=var(--syntax-text-color)],        [color=var(--syntax-string-color)]"messages"[color=var(--syntax-text-color)]: [color=var(--syntax-text-color)][{[color=var(--syntax-string-color)]"role"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"user"[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"hello"[color=var(--syntax-text-color)]}]}[color=var(--syntax-text-color)]...


再執行一次就會發現可以正確執行:
[color=var(--syntax-text-color)]>>> %Run -c $EDITOR_CONTENTWi-Fi連線成功200b'OK'Hello there! How may I assist you today?


顯然問題就是出在 [color=var(--link-branded-color)]urequests.post 對於 [color=var(--link-branded-color)]json 參數的處理。
json 模組的中文處理
在 [color=var(--link-branded-color)]urequests.post 中會使用 json 模組 (MicroPython 中 json 與 ujson 是同一個模組) 的 dumps 函式將 Python 字典轉成字串格式的 JSON 資料, 可是它的輸出結果會保留以 UTF-16 編碼的中文字, 例如:
[color=var(--syntax-text-color)][color=var(--syntax-error-color)]>>> [color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]json[color=var(--syntax-error-color)]>>> [color=var(--syntax-text-color)]json[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]dumps[color=var(--syntax-text-color)]({[color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"你好"[color=var(--syntax-text-color)]})[color=var(--syntax-string-color)]'{"content": "[color=var(--syntax-literal-color)]\u4f60\u597d[color=var(--syntax-string-color)]"}'


其中 \u4f60 是 [color=var(--link-branded-color)]"你" 的 UTF-16 編碼, 但是 [color=var(--link-branded-color)]json 規格需要的是 UTF8 編碼, 或是[color=var(--link-branded-color)]使用 "\u" 跳脫序列標註的 UTF-16 編碼, 好在 Str 的 encode 方法可以幫我們將字串轉換成 UTF8 編碼的位元組串:
[color=var(--syntax-text-color)][color=var(--syntax-error-color)]>>> [color=var(--syntax-text-color)]json[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]dumps[color=var(--syntax-text-color)]({[color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"你好"[color=var(--syntax-text-color)]}).[color=var(--syntax-text-color)]encode[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'utf8'[color=var(--syntax-text-color)])[color=var(--syntax-string-color)]b[color=var(--syntax-string-color)]'{"content": "[color=var(--syntax-literal-color)]\xe4\xbd\xa0\xe5\xa5\xbd[color=var(--syntax-string-color)]"}'


這樣結果就對了。不過因為要自行處理字典轉 json 格式位元組的工作, 所以就不能直接在 urequests.post 中使用 json 參數傳入字典了。
改用 data 參數傳入 json 資料
urequests.post 有 data 參數可以直接傳入要送給伺服端的資料, 因此我們就可以將程式改成如下:
[color=var(--syntax-text-color)][color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]network     [color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]time[color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]urequests[color=var(--syntax-error-color)]import [color=var(--syntax-text-color)]ujson[color=var(--syntax-comment-color)]# 連線至無線網路[color=var(--syntax-text-color)]sta[color=var(--syntax-error-color)]=[color=var(--syntax-text-color)]network[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]WLAN[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]network[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]STA_IF[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]active[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]True[color=var(--syntax-text-color)])   [color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]connect[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'你的無線網路名稱'[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]'你的無線網路密碼'[color=var(--syntax-text-color)])  [color=var(--syntax-declaration-color)]while [color=var(--syntax-error-color)]not [color=var(--syntax-text-color)]sta[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]isconnected[color=var(--syntax-text-color)]() [color=var(--syntax-text-color)]:    [color=var(--syntax-declaration-color)]pass[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'Wi-Fi連線成功'[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]API_KEY [color=var(--syntax-error-color)]= [color=var(--syntax-string-color)]'你的 OpenAI API 金鑰'[color=var(--syntax-text-color)]response [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]urequests[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]post[color=var(--syntax-text-color)](    [color=var(--syntax-string-color)]'https://api.openai.com/v1/chat/completions'[color=var(--syntax-text-color)],    [color=var(--syntax-text-color)]headers [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]{        [color=var(--syntax-string-color)]'Content-Type'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'application/json'[color=var(--syntax-text-color)],        [color=var(--syntax-string-color)]'Authorization'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'Bearer ' [color=var(--syntax-error-color)]+ [color=var(--syntax-text-color)]API_KEY    [color=var(--syntax-text-color)]},    [color=var(--syntax-text-color)]data [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]ujson[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]dumps[color=var(--syntax-text-color)]({        [color=var(--syntax-string-color)]'model'[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]'gpt-3.5-turbo'[color=var(--syntax-text-color)],        [color=var(--syntax-string-color)]"messages"[color=var(--syntax-text-color)]: [color=var(--syntax-text-color)][{[color=var(--syntax-string-color)]"role"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"user"[color=var(--syntax-text-color)], [color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]: [color=var(--syntax-string-color)]"你好"        [color=var(--syntax-text-color)]}).[color=var(--syntax-text-color)]encode[color=var(--syntax-text-color)]([color=var(--syntax-string-color)]'utf8'[color=var(--syntax-text-color)])[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]status_code[color=var(--syntax-text-color)])[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]reason[color=var(--syntax-text-color)])[color=var(--syntax-text-color)]reply [color=var(--syntax-error-color)]= [color=var(--syntax-text-color)]response[color=var(--syntax-text-color)].[color=var(--syntax-text-color)]json[color=var(--syntax-text-color)]()[color=var(--syntax-declaration-color)]print[color=var(--syntax-text-color)]([color=var(--syntax-text-color)]reply[color=var(--syntax-text-color)][[color=var(--syntax-string-color)]"choices"[color=var(--syntax-text-color)]][[color=var(--syntax-literal-color)]0[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"message"[color=var(--syntax-text-color)]][[color=var(--syntax-string-color)]"content"[color=var(--syntax-text-color)]])


要特別留意的是使用 json 參數傳入 Python 字典時, urequests.post 會幫你[color=var(--link-branded-color)]在表頭加上 'Content-Type: application/json', 自行使用 data 參數傳入 json 資料時就要記得在表頭補上標示遞交內容的格式, 否則無法正確執行。
這樣一來, 就可以正確叫用 API 了:
[color=var(--syntax-text-color)]>>> %Run -c $EDITOR_CONTENT  Wi-Fi連線成功  200  b'OK'  你好!有什么我

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

粤ICP备2021173439号-2

GMT+8, 2026-4-14 23:58 , Processed in 0.086015 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表