补全注释
This commit is contained in:
parent
96fbc4da80
commit
f193c48ce1
13 changed files with 115 additions and 14 deletions
|
|
@ -27,11 +27,13 @@ bp = Blueprint('admin', __name__)
|
|||
@bp.route('/admin')
|
||||
@bp.route('/admin/')
|
||||
def admin_page():
|
||||
"""返回管理面板首页 HTML 页面,供浏览器进入配置界面。"""
|
||||
return send_from_directory(_STATIC_DIR, 'admin.html')
|
||||
|
||||
|
||||
@bp.route('/static/<path:filename>')
|
||||
def static_files(filename):
|
||||
"""提供管理面板所需的静态资源文件。"""
|
||||
return send_from_directory(_STATIC_DIR, filename)
|
||||
|
||||
|
||||
|
|
@ -40,6 +42,7 @@ def static_files(filename):
|
|||
|
||||
@bp.route('/v1/models', methods=['GET'])
|
||||
def list_models():
|
||||
"""返回当前配置的模型列表,供 Cursor 拉取可用模型。"""
|
||||
mappings = settings.get().get('model_mappings', {})
|
||||
models = [{
|
||||
'id': name,
|
||||
|
|
@ -61,6 +64,7 @@ def list_models():
|
|||
|
||||
@bp.route('/api/admin/login', methods=['POST'])
|
||||
def admin_login():
|
||||
"""校验管理面板登录密钥,并返回是否允许进入后台。"""
|
||||
data = request.get_json(force=True)
|
||||
if not Config.ACCESS_API_KEY:
|
||||
return jsonify({'ok': True, 'message': '未配置鉴权'})
|
||||
|
|
@ -74,6 +78,7 @@ def admin_login():
|
|||
|
||||
@bp.route('/api/admin/settings', methods=['GET'])
|
||||
def get_settings():
|
||||
"""读取当前生效的全局代理配置。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -88,6 +93,7 @@ def get_settings():
|
|||
|
||||
@bp.route('/api/admin/settings', methods=['PUT'])
|
||||
def update_settings():
|
||||
"""更新全局上游地址与密钥配置。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -104,6 +110,7 @@ def update_settings():
|
|||
|
||||
@bp.route('/api/admin/mappings', methods=['GET'])
|
||||
def list_mappings():
|
||||
"""列出所有模型映射配置,供管理面板读取和展示。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -112,6 +119,7 @@ def list_mappings():
|
|||
|
||||
@bp.route('/api/admin/mappings', methods=['POST'])
|
||||
def add_mapping():
|
||||
"""新增一条模型映射,并写入持久化配置。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -133,6 +141,7 @@ def add_mapping():
|
|||
|
||||
@bp.route('/api/admin/mappings/<path:name>', methods=['PUT'])
|
||||
def update_mapping(name):
|
||||
"""更新指定名称的模型映射,必要时支持重命名。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -158,6 +167,7 @@ def update_mapping(name):
|
|||
|
||||
@bp.route('/api/admin/mappings/<path:name>', methods=['DELETE'])
|
||||
def delete_mapping(name):
|
||||
"""删除指定名称的模型映射,并在存在时同步保存配置。"""
|
||||
err = _check_auth()
|
||||
if err:
|
||||
return err
|
||||
|
|
@ -185,7 +195,10 @@ def _check_auth():
|
|||
|
||||
|
||||
def _save_and_respond(data, log_msg):
|
||||
"""保存配置并返回响应"""
|
||||
"""保存配置并返回统一成功响应。
|
||||
|
||||
当写盘失败时,这里也负责把异常转成结构化的 JSON 错误返回。
|
||||
"""
|
||||
try:
|
||||
settings.save(data)
|
||||
except OSError as e:
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ def _handle_openai_stream(
|
|||
payload['stream'] = True
|
||||
|
||||
def generate():
|
||||
"""消费上游 OpenAI SSE,并逐段产出给 Cursor 的聊天补全流。"""
|
||||
resp, err = forward_request(url, headers, payload, stream=True)
|
||||
if err:
|
||||
yield chat_error_chunk(str(err))
|
||||
|
|
@ -235,6 +236,7 @@ def _handle_responses_stream(
|
|||
converter = ResponsesToCCStreamConverter(model=ctx.client_model)
|
||||
|
||||
def generate():
|
||||
"""消费上游 Responses 事件,并实时转换成聊天补全 chunk。"""
|
||||
resp, err = forward_request(url, headers, payload, stream=True)
|
||||
if err:
|
||||
yield chat_error_chunk(str(err))
|
||||
|
|
@ -314,6 +316,7 @@ def _handle_anthropic_stream(
|
|||
converter = AnthropicStreamConverter()
|
||||
|
||||
def generate():
|
||||
"""消费上游 Anthropic 事件流,并逐步映射为聊天补全 SSE。"""
|
||||
resp, err = forward_request(url, headers, payload, stream=True)
|
||||
if err:
|
||||
yield chat_error_chunk(str(err))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
@dataclass(frozen=True)
|
||||
class RouteContext:
|
||||
"""数据面路由使用的标准请求上下文。"""
|
||||
"""数据面路由使用的标准请求上下文。
|
||||
|
||||
路由层会先根据客户端模型名解析出统一上下文,后续处理函数只需要关心
|
||||
上游模型、后端类型、目标地址、鉴权信息和流式标记,而不必重复访问配置层。
|
||||
"""
|
||||
|
||||
client_model: str
|
||||
upstream_model: str
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ bp = Blueprint('messages', __name__)
|
|||
|
||||
@bp.route('/v1/messages', methods=['POST'])
|
||||
def messages_passthrough():
|
||||
"""透传 Anthropic Messages 请求,并在必要时补齐 thinking 兼容层。"""
|
||||
payload = request.get_json(force=True)
|
||||
model = payload.get('model', 'unknown')
|
||||
is_stream = payload.get('stream', False)
|
||||
|
|
@ -43,6 +44,7 @@ def messages_passthrough():
|
|||
|
||||
# 流式透传
|
||||
def generate():
|
||||
"""建立上游流式连接并逐段回传处理后的 SSE 数据。"""
|
||||
try:
|
||||
resp = req_lib.post(
|
||||
url, headers=headers, json=payload,
|
||||
|
|
@ -132,7 +134,7 @@ def _process_stream(resp):
|
|||
|
||||
|
||||
def _emit_thinking_blocks(text):
|
||||
"""生成 thinking block 的 SSE 事件序列"""
|
||||
"""生成一组等价的 Anthropic thinking block SSE 事件。"""
|
||||
yield (
|
||||
f'event: content_block_start\n'
|
||||
f'data: {json.dumps({"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": ""}})}\n\n'
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ def _handle_openai_stream(
|
|||
converter = ResponsesStreamConverter(model=ctx.client_model)
|
||||
|
||||
def generate():
|
||||
"""消费 OpenAI 聊天补全流,并实时改写为 Responses SSE。"""
|
||||
yield from converter.start_events()
|
||||
|
||||
resp, err = forward_request(url, headers, cc_payload, stream=True)
|
||||
|
|
@ -205,6 +206,7 @@ def _handle_responses_stream(
|
|||
converter = ResponsesStreamConverter(model=ctx.client_model)
|
||||
|
||||
def generate():
|
||||
"""透传上游原生 Responses 流,并做轻量模型名改写。"""
|
||||
resp, err = forward_request(url, headers, payload, stream=True)
|
||||
if err:
|
||||
yield responses_error_event(str(err))
|
||||
|
|
@ -275,6 +277,7 @@ def _handle_anthropic_stream(
|
|||
converter = ResponsesStreamConverter(model=ctx.client_model)
|
||||
|
||||
def generate():
|
||||
"""消费 Anthropic SSE,并直接映射为 Responses 事件序列。"""
|
||||
yield from converter.start_events()
|
||||
|
||||
resp, err = forward_request(url, headers, anthropic_payload, stream=True)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue