DEV Community

Cover image for 在 MicroPython 中使用 HTTP Post 傳送中文--以 OpenAI API 為例
codemee
codemee

Posted on • Edited on

4

在 MicroPython 中使用 HTTP Post 傳送中文--以 OpenAI API 為例

在 MicroPython 中利用 HTTP POST 傳送中文如果不注意會出錯, 本文以 OpenAI API 為例。OpenAI 雖然提供有 Python 的官方套件, 不過如果你是要在 MicroPython 中使用 OpeAnAI 的 API, 並不能直接套用, 這時就要回歸到 OpenAI API 最根本的 HTTP Post API 了。

最簡單的 OpenAI API

OpenAI 是透過 HTTP Post 提供服務, 以聊天為例, 用的是 ChatCompletion 服務:

因此, 最簡單的 OpenAI HTTP Post API 的程式就像是這樣:

import requests

API_KEY = '你的 OpenAI API 金鑰'

response = requests.post(
    'https://api.openai.com/v1/chat/completions',
    headers = {
        'Authorization': 'Bearer ' + API_KEY
    },
    json = {
        'model': 'gpt-3.5-turbo',
        "messages": [{"role": "user", "content": "你好"}]}
)
print(response.status_code)
print(response.reason)
reply = response.json()
print(reply["choices"][0]["message"]["content"])
Enter fullscreen mode Exit fullscreen mode

執行結果如下:

>>> %Run openai_pc.py
  200
  OK
  您好!我是语言模型AI的GPT-3,有什么可以帮助您的吗?
Enter fullscreen mode Exit fullscreen mode

改用 MicroPython

既然是使用 HTTP Post, 哪麼只要從 requests 模組改成 urequests 模組, 應該就可以原封不動照搬程式了, 我們來試看看:

import network     
import time
import urequests

# 連線至無線網路
sta=network.WLAN(network.STA_IF)
sta.active(True)   
sta.connect('你的無線網路名稱', '無線網路密碼')  
while not sta.isconnected() :
    pass
print('Wi-Fi連線成功')

API_KEY = '你的 OpenAI API 金鑰'

response = urequests.post(
    'https://api.openai.com/v1/chat/completions',
    headers = {
        'Authorization': 'Bearer ' + API_KEY
    },
    json = {
        'model': 'gpt-3.5-turbo',
        "messages": [{"role": "user", "content": "你好"}]}
)
print(response.status_code)
print(response.reason)
reply = response.json()
print(reply["choices"][0]["message"]["content"])
Enter fullscreen mode Exit fullscreen mode

不過執行後就會看到 OpenAI 伺服器端回覆 400 錯誤:

>>> %Run -c $EDITOR_CONTENT
  Wi-Fi連線成功
  400
  b'Bad Request'
  Traceback (most recent call last):
    File "<stdin>", line 32, in <module>
  KeyError: choices
Enter fullscreen mode Exit fullscreen mode

同樣的程式, 搬到 MicroPython 上會出錯, 第一個懷疑的就是中文編碼的問題, 如果把程式中傳遞的 "你好" 改成純英文試看看:

...
    json = {
        'model': 'gpt-3.5-turbo',
        "messages": [{"role": "user", "content": "hello"}]}
...
Enter fullscreen mode Exit fullscreen mode

再執行一次就會發現可以正確執行:

>>> %Run -c $EDITOR_CONTENT
Wi-Fi連線成功
200
b'OK'
Hello there! How may I assist you today?
Enter fullscreen mode Exit fullscreen mode

顯然問題就是出在 urequests.post 對於 json 參數的處理。

json 模組的中文處理

urequests.post 中會使用 json 模組 (MicroPython 中 json 與 ujson 是同一個模組) 的 dumps 函式將 Python 字典轉成字串格式的 JSON 資料, 可是它的輸出結果會保留以 UTF-16 編碼的中文字, 例如:

>>> import json
>>> json.dumps({"content": "你好"})
'{"content": "\u4f60\u597d"}'
Enter fullscreen mode Exit fullscreen mode

其中 \u4f60 是 "你" 的 UTF-16 編碼, 但是 json 規格需要的是 UTF8 編碼, 或是使用 "\u" 跳脫序列標註的 UTF-16 編碼, 好在 Str 的 encode 方法可以幫我們將字串轉換成 UTF8 編碼的位元組串:

>>> json.dumps({"content": "你好"}).encode('utf8')
b'{"content": "\xe4\xbd\xa0\xe5\xa5\xbd"}'
Enter fullscreen mode Exit fullscreen mode

這樣結果就對了。不過因為要自行處理字典轉 json 格式位元組的工作, 所以就不能直接在 urequests.post 中使用 json 參數傳入字典了。

改用 data 參數傳入 json 資料

urequests.postdata 參數可以直接傳入要送給伺服端的資料, 因此我們就可以將程式改成如下:

import network     
import time
import urequests
import ujson

# 連線至無線網路
sta=network.WLAN(network.STA_IF)
sta.active(True)   
sta.connect('你的無線網路名稱', '你的無線網路密碼')  
while not sta.isconnected() :
    pass
print('Wi-Fi連線成功')

API_KEY = '你的 OpenAI API 金鑰'

response = urequests.post(
    'https://api.openai.com/v1/chat/completions',
    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + API_KEY
    },
    data = ujson.dumps({
        'model': 'gpt-3.5-turbo',
        "messages": [{"role": "user", "content": "你好"}]
        }).encode('utf8')
)
print(response.status_code)
print(response.reason)
reply = response.json()
print(reply["choices"][0]["message"]["content"])
Enter fullscreen mode Exit fullscreen mode

要特別留意的是使用 json 參數傳入 Python 字典時, urequests.post 會幫你在表頭加上 'Content-Type: application/json', 自行使用 data 參數傳入 json 資料時就要記得在表頭補上標示遞交內容的格式, 否則無法正確執行。

這樣一來, 就可以正確叫用 API 了:

>>> %Run -c $EDITOR_CONTENT
  Wi-Fi連線成功
  200
  b'OK'
  你好!有什么我可以帮助您的吗?
Enter fullscreen mode Exit fullscreen mode

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (2)

Collapse
 
1289902828 profile image
1289902828

可以问下用的是哪个型号开发板吗,以及micropython的版本,感激不尽!

Collapse
 
codemee profile image
codemee

D1 mini 和 LOLIN32

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more