mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 08:25:26 +08:00
119 lines
4.5 KiB
Python
119 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""消息处理模块"""
|
||
import re
|
||
|
||
from .config import CONFIG, logger
|
||
|
||
# Claude 默认模型
|
||
CLAUDE_DEFAULT_MODEL = "claude-sonnet-4-20250514"
|
||
|
||
# 预编译正则表达式(性能优化)
|
||
_MARKDOWN_IMAGE_PATTERN = re.compile(r"!\[(.*?)\]\((.*?)\)")
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# 消息预处理函数,将多轮对话合并成最终 prompt
|
||
# ----------------------------------------------------------------------
|
||
def messages_prepare(messages: list) -> str:
|
||
"""处理消息列表,合并连续相同角色的消息,并添加角色标签:
|
||
- 对于 assistant 消息,加上 <|Assistant|> 前缀及 <|end▁of▁sentence|> 结束标签;
|
||
- 对于 user/system 消息(除第一条外)加上 <|User|> 前缀;
|
||
- 如果消息 content 为数组,则提取其中 type 为 "text" 的部分;
|
||
- 最后移除 markdown 图片格式的内容。
|
||
"""
|
||
processed = []
|
||
for m in messages:
|
||
role = m.get("role", "")
|
||
content = m.get("content", "")
|
||
if isinstance(content, list):
|
||
texts = [
|
||
item.get("text", "") for item in content if item.get("type") == "text"
|
||
]
|
||
text = "\n".join(texts)
|
||
else:
|
||
text = str(content)
|
||
processed.append({"role": role, "text": text})
|
||
if not processed:
|
||
return ""
|
||
# 合并连续同一角色的消息
|
||
merged = [processed[0]]
|
||
for msg in processed[1:]:
|
||
if msg["role"] == merged[-1]["role"]:
|
||
merged[-1]["text"] += "\n\n" + msg["text"]
|
||
else:
|
||
merged.append(msg)
|
||
# 添加标签
|
||
parts = []
|
||
for idx, block in enumerate(merged):
|
||
role = block["role"]
|
||
text = block["text"]
|
||
if role == "assistant":
|
||
parts.append(f"<|Assistant|>{text}<|end▁of▁sentence|>")
|
||
elif role in ("user", "system"):
|
||
if idx > 0:
|
||
parts.append(f"<|User|>{text}")
|
||
else:
|
||
parts.append(text)
|
||
else:
|
||
parts.append(text)
|
||
final_prompt = "".join(parts)
|
||
# 仅移除 markdown 图片格式(不全部移除 !)- 使用预编译的正则表达式
|
||
final_prompt = _MARKDOWN_IMAGE_PATTERN.sub(r"[\1](\2)", final_prompt)
|
||
return final_prompt
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# OpenAI到Claude格式转换函数
|
||
# ----------------------------------------------------------------------
|
||
def convert_claude_to_deepseek(claude_request: dict) -> dict:
|
||
"""将Claude格式的请求转换为DeepSeek格式(基于现有OpenAI接口)"""
|
||
messages = claude_request.get("messages", [])
|
||
model = claude_request.get("model", CLAUDE_DEFAULT_MODEL)
|
||
|
||
# 从配置文件读取Claude模型映射
|
||
claude_mapping = CONFIG.get(
|
||
"claude_model_mapping", {"fast": "deepseek-chat", "slow": "deepseek-chat"}
|
||
)
|
||
|
||
# Claude模型映射到DeepSeek模型 - 基于配置和模型特征判断
|
||
if (
|
||
"opus" in model.lower()
|
||
or "reasoner" in model.lower()
|
||
or "slow" in model.lower()
|
||
):
|
||
deepseek_model = claude_mapping.get("slow", "deepseek-chat")
|
||
else:
|
||
deepseek_model = claude_mapping.get("fast", "deepseek-chat")
|
||
|
||
deepseek_request = {"model": deepseek_model, "messages": messages.copy()}
|
||
|
||
# 处理system消息 - 将system参数转换为system role消息
|
||
if "system" in claude_request:
|
||
system_msg = {"role": "system", "content": claude_request["system"]}
|
||
deepseek_request["messages"].insert(0, system_msg)
|
||
|
||
# 添加可选参数
|
||
if "temperature" in claude_request:
|
||
deepseek_request["temperature"] = claude_request["temperature"]
|
||
if "top_p" in claude_request:
|
||
deepseek_request["top_p"] = claude_request["top_p"]
|
||
if "stop_sequences" in claude_request:
|
||
deepseek_request["stop"] = claude_request["stop_sequences"]
|
||
if "stream" in claude_request:
|
||
deepseek_request["stream"] = claude_request["stream"]
|
||
|
||
return deepseek_request
|
||
|
||
|
||
def convert_deepseek_to_claude_format(
|
||
deepseek_response: dict, original_claude_model: str = CLAUDE_DEFAULT_MODEL
|
||
) -> dict:
|
||
"""将DeepSeek响应转换为Claude格式的OpenAI响应"""
|
||
# DeepSeek响应已经是OpenAI格式,只需要修改模型名称
|
||
if isinstance(deepseek_response, dict):
|
||
claude_response = deepseek_response.copy()
|
||
claude_response["model"] = original_claude_model
|
||
return claude_response
|
||
|
||
return deepseek_response
|