這周本來都在測試 OpenAI 與 Gemini 等 LLM, 周四突然想到 ESP8266/ESP32 用 MicroPython 不知道能否串接 OpenAI 等模型, 於是找出開發板, 複習 2022~2023 年鑽研一陣子的 xtools 函式庫, 經過這幾天的把玩, MicroPython 大致回魂了.
不過卻發現了 xtools 的一個問題, 由於 MicroPython 在 v1.23 版用 tsl 模組替換了 ussl 模組, 使得 xtools 在呼叫 urequests 與 xrequests 的函式時會出現找不到 ussl 的錯誤, 所以我又把韌體刷回 1.19 或 1.22 版, 順便改寫 xtoold 函式庫增加了傳貼圖的 line_sticker() 與傳圖片的 line_image() 函式 (但圖片不知為何傳不出來).
晚飯後開始來嚐試參考將之前用 requests 串接 OpenAI 模型的函式改寫為 MicroPython 版 :
def ask_gpt(prompt, api_key, model='gpt-4o-mini'):
url='https://api.openai.com/v1/chat/completions'
headers={'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'}
json={'model': model,
'messages': [{'role': 'user', 'content': prompt}]}
response=xrequests.post(url=url,headers=headers, json=json)
reply=response.json()
return reply['choices'][0]['message']['content']
參考 :
但不管使用 urequests 或 xrequests 的 post() 函式提出請求都出現錯誤, 紀錄如下 :
>>> import xrequests
>>> def ask_gpt(prompt, api_key, model='gpt-4o-mini'):
url='https://api.openai.com/v1/chat/completions'
headers={'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'}
json={'model': model,
'messages': [{'role': 'user', 'content': prompt}]}
response=xrequests.post(url=url,headers=headers, json=json)
reply=response.json()
return reply['choices'][0]['message']['content']
>>> api_key='在此輸入 OpenAI API key'
>>> prompt='Hello!'
>>> ask_gpt(prompt, api_key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in ask_gpt
File "xrequests.py", line 124, in post
File "xrequests.py", line 61, in request
OSError: -40
查詢 ChatGPT 得知 OSError: -40 通常是指 SSL/TLS 連線錯誤, 有可能是把韌體刷回 v1.23 以前版本之故, 因為 MicroPython v1.23 就是用 TLS 取代 SSL 來解決安全連線問題.
搜尋谷歌找到下面這篇文章 :
其範例程式碼如下 :
作者直接使用 urequests 模組的 post() 就能順利地得到回應, 我在想 v1.23 版韌體的 urequests 應該也有修改, 於是把一顆 ESP32 刷回最新版 v1.23 來測試. 不使用 xtools 函式庫, 用基本的 network 連上 WiFi :
MicroPython v1.23.0 on 2024-06-02; Generic ESP32 module with ESP32
Type "help()" for more information.
>>> import network
>>> import time
>>> def connect_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while not wlan.isconnected():
print('Connecting to WiFi...')
time.sleep(1)
print('Network Config:', wlan.ifconfig())
>>> ssid="ASUS-RT-AX3000"
>>> password="123456"
>>> connect_wifi(ssid, password)
True
Connecting to WiFi...
Connecting to WiFi...
Connecting to WiFi...
Network Config: ('192.168.50.48', '255.255.255.0', '192.168.50.1', '192.168.50.1')
連網成功後匯入 urequests, 然後修改上面的 ask_gpt() 函式, 改用 urequests.post() :
>>> import urequests
>>> def ask_gpt(prompt, api_key, model='gpt-4o-mini'):
url='https://api.openai.com/v1/chat/completions'
headers={'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'}
json={'model': model,
'messages': [{'role': 'user', 'content': prompt}]}
response=urequests.post(url=url,headers=headers, json=json)
reply=response.json()
return reply['choices'][0]['message']['content']
>>> prompt='Who are you?'
>>> api_key='在此輸入 OpenAI API key'
>>> ask_gpt(prompt, api_key)
'I am an AI language model created by OpenAI, designed to assist with a variety of tasks, including answering questions, providing information, and generating text based on prompts. How can I help you today?'
跟它打招呼 :
>>> prompt='Hello'
>>> ask_gpt(prompt, api_key)
'Hello! How can I assist you today?'
>>> prompt='嗨'
>>> ask_gpt(prompt, api_key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in ask_gpt
KeyError: choices
真不錯, 這樣一來跑 MicroPython 的開發板也能藉助 AI 增強功能了.
補充 :
我拿一顆 ESP8266 刷 v1.23 版韌體如法炮製卻不行 :
>>> ask_gpt(prompt, api_key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in ask_gpt
File "requests/__init__.py", line 186, in post
File "requests/__init__.py", line 95, in request
OSError: -40
詢問 ChatGPT 答覆為 ESP8266 的硬體與其 MicroPython 堆疊對 SSL/TSL 的支援有限. 所以要用 MicroPython 作 AI 應用必須採用 ESP32, 一般 4MB Flash 的就可以, 需要處理音訊或圖片則可用 16MB Flash 的 ESP32.
2024-09-26 補充 :
今天將上面以中文詢問出現錯誤的訊息 ChatGPT, 原來原因不是 MicroPython 不支援中文, 而是跟傳 Line Notify 訊息出錯原因一樣, 使用 urequests.post() 時應該將 payload 轉成字串後呼叫 encode() 以 utf-8 編碼為 bytes 類型用 data 參數傳送 (可見 MicroaPython 的 urequests 與 CPython 的 requests 模組不同, requests 用 json 參數傳遞字典沒問題, 但 xrequests 不行, 需用 data 參數) :
def ask_gpt(prompt, api_key, model='gpt-4o-mini'):
url='https://api.openai.com/v1/chat/completions'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
# 建立 data 參數字典
data={
'model': model,
'messages': [{'role': 'user', 'content': prompt}]
}
# 將字典轉成字串後再編碼成 UTF-8
payload=ujson.dumps(data).encode('utf-8')
# 發送 POST 請求
response=urequests.post(url, headers=headers, data=payload)
if response.status_code == 200:
reply=response.json() # 轉成字典
return reply['choices'][0]['message']['content']
else:
return response.json() # 返回錯誤信息
測試結果中英文都 OK :
>>> prompt='Hello'
>>> reply=xtools.ask_gpt(prompt, openai_api_key)
>>> print(reply)
Hello! How can I assist you today?
>>> prompt='嗨'
>>> reply=xtools.ask_gpt(prompt, openai_api_key)
>>> print(reply)
嗨!你好!有什么我可以帮助你的吗?
注意! 此處如果提示詞是中文, ask_gpt() 的回應預設會用簡體中文的 unicode 字串表示, 需用 print() 輸出才會解碼為中文, 例如 :
>>> prompt='你是誰?'
>>> xtools.ask_gpt(prompt, openai_api_key)
'\u6211\u662f\u4e00\u4e2a\u4eba\u5de5\u667a\u80fd\u52a9\u624b\uff0c\u65e8\u5728\u56de\u7b54\u95ee\u9898\u3001\u63d0\u4f9b\u4fe1\u606f\u548c\u5e2e\u52a9\u7528\u6237\u89e3\u51b3\u95ee\u9898\u3002\u6709\u4ec0\u9ebc\u6211\u53ef\u4ee5\u5e6b\u52a9\u4f60\u7684\u55ce\uff1f'
>>> print(xtools.ask_gpt(prompt, openai_api_key))
我是ChatGPT,一個由OpenAI開發的人工智慧語言模型。我的目的是幫助回答問題、提供資訊和進行對話。你有什麼想知道的嗎?
此函式已新增到 xtools.py 函式庫裡, 參考 :
沒有留言:
張貼留言