mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 01:53:53 +08:00
修改了coze的实现方式,使用了v3接口,修复了只能对话一次的bug
This commit is contained in:
@@ -147,7 +147,6 @@ LLM:
|
|||||||
type: coze
|
type: coze
|
||||||
bot_id: 你的bot_id
|
bot_id: 你的bot_id
|
||||||
user_id: 你的user_id
|
user_id: 你的user_id
|
||||||
base_url: "https://api.coze.cn/open_api/v2/chat" # 服务地址
|
|
||||||
personal_access_token: 你的coze个人令牌
|
personal_access_token: 你的coze个人令牌
|
||||||
LMStudioLLM:
|
LMStudioLLM:
|
||||||
# 定义LLM API类型
|
# 定义LLM API类型
|
||||||
|
|||||||
@@ -3,94 +3,35 @@ import requests
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from core.providers.llm.base import LLMProviderBase
|
from core.providers.llm.base import LLMProviderBase
|
||||||
|
import os
|
||||||
|
# official coze sdk for Python [cozepy](https://github.com/coze-dev/coze-py)
|
||||||
|
from cozepy import COZE_CN_BASE_URL
|
||||||
|
from cozepy import Coze, TokenAuth, Message, ChatStatus, MessageContentType, ChatEventType # noqa
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
|
|
||||||
# 定义用于匹配中文标点符号的正则表达式(包括句号、感叹号、问号、分号)
|
|
||||||
punctuation_pattern = re.compile(r'([。!?;])')
|
|
||||||
|
|
||||||
class LLMProvider(LLMProviderBase):
|
class LLMProvider(LLMProviderBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.personal_access_token = config.get("personal_access_token")
|
self.personal_access_token = config.get("personal_access_token")
|
||||||
self.bot_id = config.get("bot_id")
|
self.bot_id = config.get("bot_id")
|
||||||
self.user_id = config.get("user_id") # 默认用户 ID
|
self.user_id = config.get("user_id")
|
||||||
self.base_url = config.get("base_url")
|
|
||||||
|
|
||||||
def response(self, session_id, dialogue):
|
def response(self, session_id, dialogue):
|
||||||
try:
|
coze_api_token = self.personal_access_token
|
||||||
# 从对话中取出最新的用户消息
|
coze_api_base = COZE_CN_BASE_URL
|
||||||
last_msg = next(m for m in reversed(dialogue) if m["role"] == "user")
|
|
||||||
data = {
|
last_msg = next(m for m in reversed(dialogue) if m["role"] == "user")
|
||||||
"conversation_id": session_id,
|
|
||||||
"bot_id": self.bot_id,
|
coze = Coze(auth=TokenAuth(token=coze_api_token), base_url=coze_api_base)
|
||||||
"user": self.user_id,
|
|
||||||
"query": last_msg["content"],
|
for event in coze.chat.stream(
|
||||||
"stream": True
|
bot_id=self.bot_id,
|
||||||
}
|
user_id=self.user_id,
|
||||||
logger.bind(tag=TAG).info(f"发送到 Coze API 的请求数据: {json.dumps(data, ensure_ascii=False)}")
|
additional_messages=[
|
||||||
|
Message.build_user_question_text(last_msg["content"]),
|
||||||
headers = {
|
],
|
||||||
'Authorization': f'Bearer {self.personal_access_token}',
|
):
|
||||||
'Content-Type': 'application/json',
|
if event.event == ChatEventType.CONVERSATION_MESSAGE_DELTA:
|
||||||
'Accept': '*/*',
|
print(event.message.content, end="", flush=True)
|
||||||
'Host': 'api.coze.cn',
|
yield event.message.content
|
||||||
'Connection': 'keep-alive'
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(
|
|
||||||
self.base_url,
|
|
||||||
headers=headers,
|
|
||||||
json=data,
|
|
||||||
stream=True
|
|
||||||
)
|
|
||||||
logger.bind(tag=TAG).info(f"请求状态: {response.status_code}")
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
# 对每一行流数据进行处理,不做跨块累积
|
|
||||||
for line_bytes in response.iter_lines(decode_unicode=False):
|
|
||||||
if not line_bytes:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
# 使用 utf-8 解码,错误部分用替换符
|
|
||||||
line = line_bytes.decode('utf-8', errors='replace')
|
|
||||||
except Exception as e:
|
|
||||||
logger.bind(tag=TAG).error(f"解码失败: {e}")
|
|
||||||
continue
|
|
||||||
if line.startswith("data:"):
|
|
||||||
data_str = line[len("data:"):].strip()
|
|
||||||
if data_str == "[DONE]":
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
data_chunk = json.loads(data_str)
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
logger.bind(tag=TAG).error(f"JSON解析失败: {e} 数据: {line}")
|
|
||||||
continue
|
|
||||||
msg = data_chunk.get("message", {})
|
|
||||||
if msg.get("role") == "assistant" and msg.get("type") == "answer":
|
|
||||||
content = msg.get("content", "")
|
|
||||||
# 如果返回内容中包含标点符号,则按标点拆分,立即返回每个片段
|
|
||||||
if punctuation_pattern.search(content):
|
|
||||||
# 利用 finditer 找到每个标点,并返回以标点结尾的片段
|
|
||||||
start = 0
|
|
||||||
for match in punctuation_pattern.finditer(content):
|
|
||||||
end = match.end()
|
|
||||||
sentence = content[start:end].strip()
|
|
||||||
if sentence:
|
|
||||||
yield sentence
|
|
||||||
start = end
|
|
||||||
# 如果拆分后剩余内容也返回(不含标点),直接返回
|
|
||||||
if start < len(content):
|
|
||||||
remainder = content[start:].strip()
|
|
||||||
if remainder:
|
|
||||||
yield remainder
|
|
||||||
else:
|
|
||||||
# 如果没有标点,则直接返回这块内容
|
|
||||||
if content.strip():
|
|
||||||
yield content.strip()
|
|
||||||
else:
|
|
||||||
logger.bind(tag=TAG).error(f"请求失败,状态码: {response.status_code}")
|
|
||||||
yield f"【Coze服务响应异常:请求失败,状态码 {response.status_code}】"
|
|
||||||
except Exception as e:
|
|
||||||
logger.bind(tag=TAG).error(f"Error in Coze response generation: {e}")
|
|
||||||
yield "【Coze服务响应异常】"
|
|
||||||
+2
-1
@@ -16,4 +16,5 @@ aiohttp_cors==0.7.0
|
|||||||
ormsgpack==1.7.0
|
ormsgpack==1.7.0
|
||||||
ruamel.yaml==0.18.10
|
ruamel.yaml==0.18.10
|
||||||
loguru==0.7.3
|
loguru==0.7.3
|
||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
|
cozepy==0.12.0
|
||||||
Reference in New Issue
Block a user