重构代码

This commit is contained in:
h88782481 2026-03-22 08:24:19 +08:00
parent 56faf4fcf1
commit 70361242ab
9 changed files with 1195 additions and 1579 deletions

155
adapters/helpers.py Normal file
View file

@ -0,0 +1,155 @@
"""适配器公共辅助函数
收敛多个适配器都在重复实现的 CC 格式构建逻辑
- CC 消息/Usage/Tool Call/Stream Chunk 的标准构造
- 内容扁平化JSON 安全解析工具输出序列化
"""
from __future__ import annotations
import json
from typing import Any
from utils.http import gen_id
JsonDict = dict[str, Any]
# ═══════════════════════════════════════════════════════════
# CC 格式标准构造
# ═══════════════════════════════════════════════════════════
def build_cc_message(
content_text: str,
reasoning_text: str = '',
tool_calls: list[JsonDict] | None = None,
) -> JsonDict:
"""构造标准的 CC assistant 消息。"""
message: JsonDict = {
'role': 'assistant',
'content': content_text or None,
}
if reasoning_text:
message['reasoning_content'] = reasoning_text
if tool_calls:
message['tool_calls'] = tool_calls
return message
def build_cc_usage(input_tokens: int, output_tokens: int) -> JsonDict:
"""构造标准的 CC usage 字典。"""
return {
'prompt_tokens': input_tokens,
'completion_tokens': output_tokens,
'total_tokens': input_tokens + output_tokens,
}
def build_cc_tool_call(
call_id: str,
name: str,
arguments: str,
*,
index: int | None = None,
) -> JsonDict:
"""构造标准的 CC tool_call 结构。"""
tc: JsonDict = {
'id': call_id or gen_id('call_'),
'type': 'function',
'function': {
'name': name,
'arguments': arguments,
},
}
if index is not None:
tc['index'] = index
return tc
def make_cc_chunk(
chunk_id: str,
delta: JsonDict,
finish_reason: str | None = None,
model: str = '',
) -> JsonDict:
"""构造标准的 CC 流式 chunk。"""
choice: JsonDict = {'index': 0, 'delta': delta}
if finish_reason:
choice['finish_reason'] = finish_reason
return {
'id': chunk_id,
'object': 'chat.completion.chunk',
'model': model,
'choices': [choice],
}
def build_cc_response(
response_id: str,
message: JsonDict,
finish_reason: str,
usage: JsonDict,
model: str = '',
) -> JsonDict:
"""构造标准的 CC 非流式响应。"""
return {
'id': response_id,
'object': 'chat.completion',
'model': model,
'choices': [{
'index': 0,
'message': message,
'finish_reason': finish_reason,
}],
'usage': usage,
}
# ═══════════════════════════════════════════════════════════
# 通用文本/JSON 处理
# ═══════════════════════════════════════════════════════════
def extract_text(content: Any) -> str:
"""从多种内容格式中提取并拼接纯文本。
支持字符串内容块列表OpenAI/Anthropic/Responses 风格
"""
if isinstance(content, str):
return content
if not isinstance(content, list):
return str(content) if content is not None else ''
parts: list[str] = []
for part in content:
if isinstance(part, str):
parts.append(part)
elif isinstance(part, dict):
part_type = part.get('type', '')
if part_type in ('text', 'output_text', 'input_text'):
parts.append(part.get('text', ''))
elif part_type == 'refusal':
parts.append(part.get('refusal', ''))
elif 'text' in part and not part_type:
parts.append(part['text'])
return '\n'.join(parts) if parts else ''
def parse_json_safe(text: Any, fallback: Any = None) -> Any:
"""安全解析 JSON失败时返回 fallback。"""
if not isinstance(text, str):
return text if text is not None else (fallback if fallback is not None else {})
try:
return json.loads(text)
except (json.JSONDecodeError, ValueError):
return fallback if fallback is not None else {}
def stringify_content(content: Any) -> str:
"""将任意内容序列化为字符串。"""
if isinstance(content, str):
return content
if content is None:
return ''
return json.dumps(content, ensure_ascii=False)