走进科学疑难问题出现
在调试fastapi程序的时候,报错碰到422错误
INFO: 192.168.0.99:46536 - "POST /v1/chat/completions/ HTTP/1.1" 422 Unprocessable Entity
干净利索,只有这一句报错,不管代码里加入多少print语句查看中间变量,都只有这一句话,就像根本没有走下去(事实上确实没有走下去)。
使用的测试语句是:
curl -X 'POST' \
'http://192.168.0.99:8000/v1/chat/completions/' \
-H 'accept: application/json' \
-d "{'msg':[ {'role': 'user', 'content': 'hello'} ]}"
不知道问题在哪,后来专门找了另一条测试语句,并写了/items/的代码,测试通过,没报错:
curl -X POST http://192.168.0.99:8000/items/ -H "Content-Type: application/json" \
-d '{"name": "Bruce_Lee", "description":"this is a book of Bruce_Lee", "price": 12}'
解决问题
然后就比对代码,比对/items/ 和/v1/chat/completions/ 里面代码的书写,甚至比对着写了个最简单的json数据,把这句"{'msg':[ {'role': 'user', 'content': 'hello'} ]}"学着对的那句简化成-d '{"msg": "hello"}
你还别说,输出了很多打印信息,证明程序跑下去了。当然因为简化json,中间还改了程序,再用回长段json的时候再改回去,总之是改的头昏眼花。
后来到文心一言里,让它帮我把单引号改成双引号,
提问:
请把单括号换成双括号{'msg':[ {'role': 'user', 'content': 'hello'} ]} (这里因为头昏,错把引号说成了括号,索性一言给我了份正确格式的答案)
回答
当您提到将“单括号”换成“双括号”时,我猜测您是指将某种不规范的或错误的括号使用方式更正为标准的 JSON 格式。在 JSON 中,对象(即键值对的集合)应该使用大括号
{}
来表示,而数组(即有序值的集合)应该使用方括号[]
来表示。根据您提供的示例
{'msg':[ {'role': 'user', 'content': 'hello'} ]}
,这实际上已经是一个有效的 JSON 字符串(尽管它可能被错误地称为“单括号”或“双括号”,这取决于上下文和解释者的视角)。在这个字符串中:
- 最外层的
{}
表示一个 JSON 对象。msg
是这个对象的一个键,其对应的值是一个 JSON 数组。- 这个数组由方括号
[]
表示,并且包含一个 JSON 对象。- 这个内部的对象又由大括号
{}
表示,并且有两个键值对:role
和content
。如果您的意图是确保这个 JSON 字符串被正确地用于
curl
命令中,那么您应该这样做:curl -X 'POST' \ 'http://192.168.0.99:8000/v1/chat/completions/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"messages":[{"role": "user", "content": "hello"}]}'
使用这份curl格式的代码,终于消除了422报错!
后来才知道(也许我以前就知道,只是忘记了) ,json一定要用双引号!
在 JSON 格式中,字符串值必须使用双引号 "
来界定,而不能使用单引号 '
。这是 JSON 标准的一部分,它确保了数据的一致性和可解析性。
json编程,砥砺前行!
总结下
这回对json格式算是印象深刻了,主要是受了python的影响,单引号和双引号混用,这才阴沟里翻了船。
最终问题解决,且原来计划的使用树莓派启动fastapi 中转openai指令,使ESP32开发板能够连上大模型,方案也被验证可行。
目前将fastapi 中转openai放置于树莓派2服务器上,
fastapi 中转openai配置
fastapi的代码为:
cat app.py
from typing import Annotated
import json
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel
from openai import OpenAI
import os
import time
from typing import Union, Optional
app = FastAPI()
API_KEY = "xxxx"
model="ernie-speed-8k"
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
class ChatItem(BaseModel):
messages: list
model: str | None = None
def ChatCompletions(
messages: list,
model: str,
# provider: Optional[ProviderType] = None,
stream: Optional[bool] = False,
# proxy: Optional[str] = None,
response_format: Optional[dict] = None,
max_tokens: Optional[int] = None,
stop: Optional[Union[list[str], str]] = None,
api_key: Optional[str] = None,
# ignored: Optional[list[str]] = None,
# ignore_working: Optional[bool] = False,
ignore_stream: Optional[bool] = False,
**kwargs):
client = OpenAI(
api_key=api_key, # 含有 AI Studio 访问令牌的环境变量,https://aistudio.baidu.com/account/accessToken,
base_url="https://aistudio.baidu.com/llm/lmapi/v3", # aistudio 大模型 api 服务域名
)
chat_completion = client.chat.completions.create(
messages=messages,
model=model,
)
print(f"==log for app chat_completion:{chat_completion} ")
# response = chat_completion.result
# print(f"==log for app response:{response}")
return chat_completion
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
@app.post("/v1/chat/completions/")
async def chat_completions(chatitem: ChatItem):
print(chatitem)
chatitemdict = chatitem.dict()
print(f"==== items:{chatitemdict}")
#print ("=" * 20 , messages, type(messages))
#yjson = json.loads(messages)
#print("="*10, yjson, type(yjson))
#zmessages = yjson["messages"]
#print("="*10, zmessages, typr(zmessages))
model="ernie-speed-8k"
messages = chatitem.messages
print(f"==== messages=chatitem.msg:{messages}")
y = ChatCompletions(messages=messages, model=model, api_key=API_KEY)
print("="*10, y)
z = y.choices[0].message.content
return z
@app.post("/items/")
async def create_item(item: Item):
print(f"==== get the Item type:{type(item)}, item:{item}")
item_dict = item.dict()
print(f"==== item_dict{item_dict}")
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
需要到AiStudio官网获取apk_key并填入上面的代码中,在树莓派启动fastapi服务器:
uvicorn app:app --host 0.0.0.0 --reload
最终测试命令为:
curl -X 'POST' \
'http://192.168.0.99:8000/v1/chat/completions/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"messages":[{"role": "user", "content": "hello"}]}'
省略一条head,这个命令也可以:
curl -X 'POST' \
'http://192.168.0.99:8000/v1/chat/completions/' \
-H 'Content-Type: application/json' \
-d '{"messages":[{"role": "user", "content": "hello"}]}'
ESP32S3开发板通过中转连星河大模型
在ESP32S3开发板的MicroPython环境下,使用requests来fastapi的中转服务器,连接成功:
import requests
response = requests.post(
'http://192.168.0.99:8000/v1/chat/completions/',
headers = {
'Content-Type': 'application/json',},
json = {
'model': "ernie-speed-8k",
"messages": [{"role": "user", "content": "hello"}]}
)
print(response.status_code, response.reason)
print(response.text)
输出显示:
>>> print(response.status_code, response.reason)
200 b'OK'
>>> print(response.text)
"你好!请问有什么需要我帮助你的吗?"
太棒了,使用这种解决方案,在家里使用一台树莓派做中转,就可以让家里的物联网设备都使用百度星河大模型啦!