mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 08:25:26 +08:00
139 lines
4.8 KiB
Python
139 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""DeepSeek API 相关逻辑"""
|
||
import time
|
||
from curl_cffi import requests
|
||
from fastapi import HTTPException
|
||
|
||
from .config import CONFIG, save_config, logger
|
||
from .utils import get_account_identifier
|
||
from .constants import (
|
||
DEEPSEEK_HOST,
|
||
DEEPSEEK_LOGIN_URL,
|
||
DEEPSEEK_CREATE_SESSION_URL,
|
||
DEEPSEEK_CREATE_POW_URL,
|
||
DEEPSEEK_COMPLETION_URL,
|
||
BASE_HEADERS,
|
||
)
|
||
|
||
|
||
# get_account_identifier 已移至 core.utils
|
||
|
||
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# 登录函数:支持使用 email 或 mobile 登录
|
||
# ----------------------------------------------------------------------
|
||
def login_deepseek_via_account(account: dict) -> str:
|
||
"""使用 account 中的 email 或 mobile 登录 DeepSeek,
|
||
成功后将返回的 token 写入 account 并保存至配置文件,返回新 token。
|
||
"""
|
||
email = account.get("email", "").strip()
|
||
mobile = account.get("mobile", "").strip()
|
||
password = account.get("password", "").strip()
|
||
if not password or (not email and not mobile):
|
||
raise HTTPException(
|
||
status_code=400,
|
||
detail="账号缺少必要的登录信息(必须提供 email 或 mobile 以及 password)",
|
||
)
|
||
if email:
|
||
payload = {
|
||
"email": email,
|
||
"password": password,
|
||
"device_id": "deepseek_to_api",
|
||
"os": "android",
|
||
}
|
||
else:
|
||
payload = {
|
||
"mobile": mobile,
|
||
"area_code": None,
|
||
"password": password,
|
||
"device_id": "deepseek_to_api",
|
||
"os": "android",
|
||
}
|
||
try:
|
||
resp = requests.post(
|
||
DEEPSEEK_LOGIN_URL, headers=BASE_HEADERS, json=payload, impersonate="safari15_3"
|
||
)
|
||
resp.raise_for_status()
|
||
except Exception as e:
|
||
logger.error(f"[login_deepseek_via_account] 登录请求异常: {e}")
|
||
raise HTTPException(status_code=500, detail="Account login failed: 请求异常")
|
||
try:
|
||
logger.warning(f"[login_deepseek_via_account] {resp.text}")
|
||
data = resp.json()
|
||
except Exception as e:
|
||
logger.error(f"[login_deepseek_via_account] JSON解析失败: {e}")
|
||
raise HTTPException(
|
||
status_code=500, detail="Account login failed: invalid JSON response"
|
||
)
|
||
|
||
# 检查 API 错误码
|
||
if data.get("code") != 0:
|
||
error_msg = data.get("msg", "Unknown error")
|
||
logger.error(f"[login_deepseek_via_account] API错误: {error_msg}")
|
||
raise HTTPException(
|
||
status_code=500, detail=f"Account login failed: {error_msg}"
|
||
)
|
||
|
||
# 检查业务错误码
|
||
biz_code = data.get("data", {}).get("biz_code")
|
||
biz_msg = data.get("data", {}).get("biz_msg", "")
|
||
if biz_code != 0:
|
||
logger.error(f"[login_deepseek_via_account] 业务错误: {biz_msg}")
|
||
raise HTTPException(
|
||
status_code=500, detail=f"Account login failed: {biz_msg}"
|
||
)
|
||
|
||
# 校验响应数据格式是否正确
|
||
if (
|
||
data.get("data") is None
|
||
or data["data"].get("biz_data") is None
|
||
or data["data"]["biz_data"].get("user") is None
|
||
):
|
||
logger.error(f"[login_deepseek_via_account] 登录响应格式错误: {data}")
|
||
raise HTTPException(
|
||
status_code=500, detail="Account login failed: invalid response format"
|
||
)
|
||
new_token = data["data"]["biz_data"]["user"].get("token")
|
||
if not new_token:
|
||
logger.error(f"[login_deepseek_via_account] 登录响应中缺少 token: {data}")
|
||
raise HTTPException(
|
||
status_code=500, detail="Account login failed: missing token"
|
||
)
|
||
account["token"] = new_token
|
||
save_config(CONFIG)
|
||
return new_token
|
||
|
||
|
||
# ----------------------------------------------------------------------
|
||
# 封装对话接口调用的重试机制
|
||
# ----------------------------------------------------------------------
|
||
def call_completion_endpoint(payload: dict, headers: dict, max_attempts: int = 3):
|
||
"""调用 DeepSeek 对话接口,支持重试"""
|
||
attempts = 0
|
||
while attempts < max_attempts:
|
||
try:
|
||
deepseek_resp = requests.post(
|
||
DEEPSEEK_COMPLETION_URL,
|
||
headers=headers,
|
||
json=payload,
|
||
stream=True,
|
||
impersonate="safari15_3",
|
||
)
|
||
except Exception as e:
|
||
logger.warning(f"[call_completion_endpoint] 请求异常: {e}")
|
||
time.sleep(1)
|
||
attempts += 1
|
||
continue
|
||
if deepseek_resp.status_code == 200:
|
||
return deepseek_resp
|
||
else:
|
||
logger.warning(
|
||
f"[call_completion_endpoint] 调用对话接口失败, 状态码: {deepseek_resp.status_code}"
|
||
)
|
||
deepseek_resp.close()
|
||
time.sleep(1)
|
||
attempts += 1
|
||
return None
|