Files
ds2api/core/deepseek.py

139 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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