Files
xiaozhi-esp32-server/core/utils/llm.py
T

175 lines
6.1 KiB
Python
Raw Normal View History

2025-02-02 23:01:14 +08:00
import json
import logging
import openai
import requests
2025-02-09 16:44:57 +08:00
from datetime import datetime
from core.utils.util import is_segment
from core.utils.util import get_string_no_punctuation_or_emoji
from core.utils.util import read_config, get_project_dir
2025-02-02 23:01:14 +08:00
from abc import ABC, abstractmethod
logger = logging.getLogger(__name__)
class LLM(ABC):
@abstractmethod
2025-02-09 16:44:57 +08:00
def response(self, session_id, dialogue):
2025-02-02 23:01:14 +08:00
"""LLM response generator"""
pass
class DeepSeekLLM(LLM):
def __init__(self, config):
self.model_name = config.get("model_name")
self.api_key = config.get("api_key")
self.base_url = config.get("url")
self.client = openai.OpenAI(api_key=self.api_key, base_url=self.base_url)
2025-02-09 16:44:57 +08:00
def response(self, session_id, dialogue):
2025-02-02 23:01:14 +08:00
logger.info(f"Generating response using {dialogue}")
try:
responses = self.client.chat.completions.create(
model=self.model_name,
messages=dialogue,
stream=True
)
for chunk in responses:
# 检查是否存在有效的choice且content不为空
if chunk.choices and len(chunk.choices) > 0:
delta = chunk.choices[0].delta
content = getattr(delta, 'content', '')
if content: # 仅在content非空时生成
yield content
except Exception as e:
logger.error(f"Error in response generation: {e}")
class ChatGLMLLM(LLM):
def __init__(self, config):
self.model_name = config.get("model_name")
self.api_key = config.get("api_key")
self.base_url = config.get("url")
self.client = openai.OpenAI(api_key=self.api_key, base_url=self.base_url)
2025-02-09 16:44:57 +08:00
def response(self, session_id, dialogue):
2025-02-02 23:01:14 +08:00
try:
responses = self.client.chat.completions.create(
model=self.model_name,
messages=dialogue,
stream=True
)
for chunk in responses:
# 检查是否存在有效的choice且content不为空
if chunk.choices and len(chunk.choices) > 0:
delta = chunk.choices[0].delta
content = getattr(delta, 'content', '')
if content: # 仅在content非空时生成
yield content
except Exception as e:
logger.error(f"Error in response generation: {e}")
2025-02-09 16:44:57 +08:00
class AliLLM(LLM):
def __init__(self, config):
self.model_name = config.get("model_name")
self.api_key = config.get("api_key")
self.base_url = config.get("base_url")
self.client = openai.OpenAI(api_key=self.api_key, base_url=self.base_url)
def response(self, session_id, dialogue):
try:
responses = self.client.chat.completions.create(
model=self.model_name,
messages=dialogue,
stream=True
)
for chunk in responses:
# 检查是否存在有效的choice且content不为空
if chunk.choices and len(chunk.choices) > 0:
delta = chunk.choices[0].delta
content = getattr(delta, 'content', '')
if content: # 仅在content非空时生成
yield content
except Exception as e:
logger.error(f"Error in response generation: {e}")
2025-02-02 23:01:14 +08:00
class DifyLLM(LLM):
def __init__(self, config):
self.api_key = config["api_key"]
self.base_url = config.get("base_url", "https://api.dify.ai/v1").rstrip('/')
2025-02-09 16:44:57 +08:00
def response(self, session_id, dialogue):
2025-02-02 23:01:14 +08:00
try:
# 取最后一条用户消息
last_msg = next(m for m in reversed(dialogue) if m["role"] == "user")
# 发起流式请求
with requests.post(
f"{self.base_url}/chat-messages",
headers={"Authorization": f"Bearer {self.api_key}"},
json={
"query": last_msg["content"],
"response_mode": "streaming",
2025-02-09 16:44:57 +08:00
"user": session_id,
2025-02-02 23:01:14 +08:00
"inputs": {}
},
stream=True
) as r:
for line in r.iter_lines():
if line.startswith(b'data: '):
event = json.loads(line[6:])
if event.get('answer'):
yield event['answer']
except Exception:
yield "【服务响应异常】"
def create_instance(class_name, *args, **kwargs):
# 获取类对象
cls_map = {
"DeepSeekLLM": DeepSeekLLM,
"ChatGLMLLM": ChatGLMLLM,
"DifyLLM": DifyLLM,
2025-02-09 16:44:57 +08:00
"AliLLM": AliLLM,
2025-02-02 23:01:14 +08:00
# 可扩展其他LLM实现
}
if cls := cls_map.get(class_name):
return cls(*args, **kwargs)
raise ValueError(f"不支持的LLM类型: {class_name}")
2025-02-09 16:44:57 +08:00
if __name__ == "__main__":
"""
响应速度测试
"""
config = read_config(get_project_dir() + "config.yaml")
llm = create_instance(
config["selected_module"]["LLM"],
config["LLM"][config["selected_module"]["LLM"]]
)
start_time = datetime.now()
dialogue = []
dialogue.append({"role": "system", "content": config.get("prompt")})
dialogue.append({"role": "user", "content": "你好小智"})
llm_responses = llm.response("test", dialogue)
response_message = []
first_text = None
start = 0
for content in llm_responses:
response_message.append(content)
if is_segment(response_message):
segment_text = "".join(response_message[start:])
segment_text = get_string_no_punctuation_or_emoji(segment_text)
if len(segment_text) > 0:
if first_text is None:
first_text = segment_text
print("大模型首次返回耗时:" + str(datetime.now() - start_time))
start = len(response_message)
print("大模型返回总耗时:" + str(datetime.now() - start_time))