| import os |
| import sys |
| from dotenv import load_dotenv |
|
|
| |
| load_dotenv() |
|
|
| from fastapi import FastAPI, Depends, Request |
| from fastapi.responses import StreamingResponse |
| from fastapi.middleware.cors import CORSMiddleware |
| from app.utils.logger import logger |
| from app.utils.auth import verify_api_key |
| from app.deepclaude.deepclaude import DeepClaude |
|
|
| app = FastAPI(title="DeepClaude API") |
|
|
| |
| ALLOW_ORIGINS = os.getenv("ALLOW_ORIGINS", "*") |
|
|
| CLAUDE_API_KEY = os.getenv("CLAUDE_API_KEY") |
| CLAUDE_MODEL = os.getenv("CLAUDE_MODEL") |
| CLAUDE_PROVIDER = os.getenv("CLAUDE_PROVIDER", "anthropic") |
| CLAUDE_API_URL = os.getenv("CLAUDE_API_URL", "https://api.anthropic.com/v1/messages") |
|
|
| DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY") |
| DEEPSEEK_API_URL = os.getenv("DEEPSEEK_API_URL") |
| DEEPSEEK_MODEL = os.getenv("DEEPSEEK_MODEL") |
|
|
| IS_ORIGIN_REASONING = os.getenv("IS_ORIGIN_REASONING", "True").lower() == "true" |
|
|
| |
| allow_origins_list = ALLOW_ORIGINS.split(",") if ALLOW_ORIGINS else [] |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=allow_origins_list, |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| if not DEEPSEEK_API_KEY or not CLAUDE_API_KEY: |
| logger.critical("请设置环境变量 CLAUDE_API_KEY 和 DEEPSEEK_API_KEY") |
| sys.exit(1) |
|
|
| deep_claude = DeepClaude( |
| DEEPSEEK_API_KEY, |
| CLAUDE_API_KEY, |
| DEEPSEEK_API_URL, |
| CLAUDE_API_URL, |
| CLAUDE_PROVIDER, |
| IS_ORIGIN_REASONING |
| ) |
|
|
| |
| logger.debug("当前日志级别为 DEBUG") |
| logger.info("开始请求") |
|
|
| @app.get("/", dependencies=[Depends(verify_api_key)]) |
| async def root(): |
| logger.info("访问了根路径") |
| return {"message": "Welcome to DeepClaude API"} |
|
|
| @app.get("/v1/models") |
| async def list_models(): |
| """ |
| 获取可用模型列表 |
| 返回格式遵循 OpenAI API 标准 |
| """ |
| models = [{ |
| "id": "deepclaude", |
| "object": "model", |
| "created": 1677610602, |
| "owned_by": "deepclaude", |
| "permission": [{ |
| "id": "modelperm-deepclaude", |
| "object": "model_permission", |
| "created": 1677610602, |
| "allow_create_engine": False, |
| "allow_sampling": True, |
| "allow_logprobs": True, |
| "allow_search_indices": False, |
| "allow_view": True, |
| "allow_fine_tuning": False, |
| "organization": "*", |
| "group": None, |
| "is_blocking": False |
| }], |
| "root": "deepclaude", |
| "parent": None |
| }] |
| |
| return {"object": "list", "data": models} |
|
|
| @app.post("/v1/chat/completions", dependencies=[Depends(verify_api_key)]) |
| async def chat_completions(request: Request): |
| """处理聊天完成请求,支持流式和非流式输出 |
| |
| 请求体格式应与 OpenAI API 保持一致,包含: |
| - messages: 消息列表 |
| - model: 模型名称(可选) |
| - stream: 是否使用流式输出(可选,默认为 True) |
| - temperature: 随机性 (可选) |
| - top_p: top_p (可选) |
| - presence_penalty: 话题新鲜度(可选) |
| - frequency_penalty: 频率惩罚度(可选) |
| """ |
|
|
| try: |
| |
| body = await request.json() |
| messages = body.get("messages") |
|
|
| |
| model_arg = ( |
| get_and_validate_params(body) |
| ) |
| stream = model_arg[4] |
|
|
| |
| if stream: |
| return StreamingResponse( |
| deep_claude.chat_completions_with_stream( |
| messages=messages, |
| model_arg=model_arg[:4], |
| deepseek_model=DEEPSEEK_MODEL, |
| claude_model=CLAUDE_MODEL |
| ), |
| media_type="text/event-stream" |
| ) |
| else: |
| |
| response = await deep_claude.chat_completions_without_stream( |
| messages=messages, |
| model_arg=model_arg[:4], |
| deepseek_model=DEEPSEEK_MODEL, |
| claude_model=CLAUDE_MODEL |
| ) |
| return response |
|
|
| except Exception as e: |
| logger.error(f"处理请求时发生错误: {e}") |
| return {"error": str(e)} |
|
|
|
|
| def get_and_validate_params(body): |
| """提取获取和验证请求参数的函数""" |
| |
| temperature: float = body.get("temperature", 0.5) |
| top_p: float = body.get("top_p", 0.9) |
| presence_penalty: float = body.get("presence_penalty", 0.0) |
| frequency_penalty: float = body.get("frequency_penalty", 0.0) |
| stream: bool = body.get("stream", True) |
|
|
| if "sonnet" in body.get("model", ""): |
| if not isinstance(temperature, (float)) or temperature < 0.0 or temperature > 1.0: |
| raise ValueError("Sonnet 设定 temperature 必须在 0 到 1 之间") |
|
|
| return (temperature, top_p, presence_penalty, frequency_penalty, stream) |
|
|