feat: Initialize project with FastAPI backend, React web UI, Vercel sync, and API integrations.

This commit is contained in:
CJACK
2026-02-01 02:17:01 +08:00
parent fc7de77151
commit bc260899c1
35 changed files with 5730 additions and 1954 deletions

175
core/session_manager.py Normal file
View File

@@ -0,0 +1,175 @@
# -*- coding: utf-8 -*-
"""会话管理模块 - 封装公共的会话创建和 PoW 获取逻辑"""
from curl_cffi import requests as cffi_requests
from fastapi import HTTPException, Request
from .config import logger
from .auth import (
get_auth_headers,
choose_new_account,
get_account_identifier,
release_account,
)
from .deepseek import (
DEEPSEEK_CREATE_SESSION_URL,
DEEPSEEK_CREATE_POW_URL,
login_deepseek_via_account,
call_completion_endpoint,
)
from .pow import get_pow_response
def create_session(request: Request, max_attempts: int = 3) -> str | None:
"""创建 DeepSeek 会话
Args:
request: FastAPI 请求对象
max_attempts: 最大重试次数
Returns:
会话 ID如果失败返回 None
"""
attempts = 0
while attempts < max_attempts:
headers = get_auth_headers(request)
try:
resp = cffi_requests.post(
DEEPSEEK_CREATE_SESSION_URL,
headers=headers,
json={"agent": "chat"},
impersonate="safari15_3",
)
except Exception as e:
logger.error(f"[create_session] 请求异常: {e}")
attempts += 1
continue
try:
data = resp.json()
except Exception as e:
logger.error(f"[create_session] JSON解析异常: {e}")
data = {}
if resp.status_code == 200 and data.get("code") == 0:
session_id = data["data"]["biz_data"]["id"]
resp.close()
return session_id
else:
code = data.get("code")
logger.warning(
f"[create_session] 创建会话失败, code={code}, msg={data.get('msg')}"
)
resp.close()
# 配置模式下尝试切换账号
if request.state.use_config_token:
current_id = get_account_identifier(request.state.account)
if not hasattr(request.state, "tried_accounts"):
request.state.tried_accounts = []
if current_id not in request.state.tried_accounts:
request.state.tried_accounts.append(current_id)
new_account = choose_new_account(request.state.tried_accounts)
if new_account is None:
break
try:
login_deepseek_via_account(new_account)
except Exception as e:
logger.error(
f"[create_session] 账号 {get_account_identifier(new_account)} 登录失败:{e}"
)
attempts += 1
continue
request.state.account = new_account
request.state.deepseek_token = new_account.get("token")
else:
attempts += 1
continue
attempts += 1
return None
def get_pow(request: Request, max_attempts: int = 3) -> str | None:
"""获取 PoW 响应的包装函数
Args:
request: FastAPI 请求对象
max_attempts: 最大重试次数
Returns:
Base64 编码的 PoW 响应,如果失败返回 None
"""
return get_pow_response(
request,
get_auth_headers,
choose_new_account,
login_deepseek_via_account,
DEEPSEEK_CREATE_POW_URL,
max_attempts,
)
def prepare_completion_request(
request: Request,
session_id: str,
prompt: str,
thinking_enabled: bool = False,
search_enabled: bool = False,
max_attempts: int = 3,
):
"""准备并执行对话补全请求
Args:
request: FastAPI 请求对象
session_id: 会话 ID
prompt: 处理后的提示词
thinking_enabled: 是否启用思考模式
search_enabled: 是否启用搜索
max_attempts: 最大重试次数
Returns:
DeepSeek 响应对象,如果失败返回 None
"""
pow_resp = get_pow(request, max_attempts)
if not pow_resp:
return None
headers = {**get_auth_headers(request), "x-ds-pow-response": pow_resp}
payload = {
"chat_session_id": session_id,
"parent_message_id": None,
"prompt": prompt,
"ref_file_ids": [],
"thinking_enabled": thinking_enabled,
"search_enabled": search_enabled,
}
return call_completion_endpoint(payload, headers, max_attempts)
def get_model_config(model: str) -> tuple[bool, bool]:
"""根据模型名称获取配置
Args:
model: 模型名称
Returns:
(thinking_enabled, search_enabled) 元组
"""
model_lower = model.lower()
if model_lower in ["deepseek-v3", "deepseek-chat"]:
return False, False
elif model_lower in ["deepseek-r1", "deepseek-reasoner"]:
return True, False
elif model_lower in ["deepseek-v3-search", "deepseek-chat-search"]:
return False, True
elif model_lower in ["deepseek-r1-search", "deepseek-reasoner-search"]:
return True, True
else:
return None, None # 不支持的模型
def cleanup_account(request: Request):
"""清理账号资源(将账号放回队列)"""
if getattr(request.state, "use_config_token", False) and hasattr(request.state, "account"):
release_account(request.state.account)