- 彻底移除「每 N 次请求强制思考」的间隔调度机制(思考/非思考交替导致缓存命中率极低) - 运行模式收敛为 fast/thinking:原 deep 改名 thinking,历史数据读取时映射 - 新增推理强度五档滑块(low/medium/high/xhigh/max + 默认不传参),置于模型/模式弹窗 - 模型配置新增 reasoning_effort 开关;档位会话级持久化到对话 meta,随对话保存/恢复 - 个人空间新增「默认推理强度」;新用户默认运行模式改为 thinking - 滑块交互:JS 插值驱动(点击/拖动/吸附全程平滑),首帧档位语义定位无闪烁 - 保存链路:前端防抖 600ms + conversation_id 兜底,修复 /new 发消息丢档位、切对话恢复错误
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
# ========== api_client.py ==========
|
||
# utils/api_client.py - OpenAI-compatible API 客户端(支持Web模式)
|
||
|
||
import httpx
|
||
import json
|
||
import asyncio
|
||
import base64
|
||
import mimetypes
|
||
import os
|
||
from typing import List, Dict, Optional, AsyncGenerator, Any
|
||
from pathlib import Path
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
from typing import Tuple
|
||
try:
|
||
from config import (
|
||
OUTPUT_FORMATS,
|
||
DEFAULT_RESPONSE_MAX_TOKENS,
|
||
LOGS_DIR,
|
||
)
|
||
except ImportError:
|
||
import sys
|
||
from pathlib import Path
|
||
project_root = Path(__file__).resolve().parents[1]
|
||
if str(project_root) not in sys.path:
|
||
sys.path.insert(0, str(project_root))
|
||
from config import (
|
||
OUTPUT_FORMATS,
|
||
DEFAULT_RESPONSE_MAX_TOKENS,
|
||
LOGS_DIR,
|
||
)
|
||
|
||
from utils.log_rotation import append_line, prune_dir
|
||
|
||
|
||
|
||
from utils.api_client.utils import _api_dump_enabled
|
||
|
||
class DeepSeekClientBaseMixin:
|
||
def __init__(self, thinking_mode: bool = True, web_mode: bool = False):
|
||
# 模型 API 配置(端点 / 密钥 / 模型 ID)由 apply_profile 从 custom_models 注入;
|
||
# 这里仅初始化为空,未应用任何模型档案前不可直接发请求。
|
||
self.fast_api_config = {
|
||
"base_url": "",
|
||
"api_key": "",
|
||
"model_id": ""
|
||
}
|
||
self.thinking_api_config = {
|
||
"base_url": "",
|
||
"api_key": "",
|
||
"model_id": ""
|
||
}
|
||
self.fast_max_tokens = None
|
||
self.thinking_max_tokens = None
|
||
self.fast_extra_params: Dict = {}
|
||
self.thinking_extra_params: Dict = {}
|
||
# 上下文预算(由上层在每次请求前设置)
|
||
self.current_context_tokens: int = 0
|
||
self.max_context_tokens: Optional[int] = None
|
||
self.default_context_window: Optional[int] = None
|
||
self.thinking_mode = thinking_mode # True=思考模式(每次请求都用思考配置), False=快速模式
|
||
self.web_mode = web_mode # Web模式标志,用于禁用print输出
|
||
# 兼容旧代码路径
|
||
self.api_base_url = self.fast_api_config["base_url"]
|
||
self.api_key = self.fast_api_config["api_key"]
|
||
self.model_id = self.fast_api_config["model_id"]
|
||
self.model_key = None # 由宿主终端注入,便于做模型兼容处理
|
||
self.model_multimodal = "none" # 由模型 profile 注入,model_key 不可用时用于能力兜底
|
||
self.project_path: Optional[str] = None
|
||
# 推理强度(reasoning effort):None=默认(不传参);由会话级设置注入
|
||
self.reasoning_effort: Optional[str] = None
|
||
self.supports_reasoning_effort = False # 当前模型是否支持推理强度,由 apply_profile 注入
|
||
# 最近一次API错误详情
|
||
self.last_error_info: Optional[Dict[str, Any]] = None
|
||
# 请求体落盘目录(跟随 LOGS_DIR,默认 ~/.astrion/<mode>/logs/api_requests)
|
||
self.request_dump_dir = Path(LOGS_DIR) / "api_requests"
|
||
self.debug_log_path = Path(LOGS_DIR) / "api_debug.log"
|
||
|
||
def _resolve_env_value(self, name: str) -> Optional[str]:
|
||
"""从环境变量获取配置(已由 config/__init__.py 统一注入)。"""
|
||
value = os.environ.get(name)
|
||
if value is None:
|
||
return None
|
||
value = value.strip()
|
||
return value or None
|
||
|
||
def _print(self, message: str, end: str = "\n", flush: bool = False):
|
||
"""安全的打印函数,在Web模式下不输出"""
|
||
if not self.web_mode:
|
||
print(message, end=end, flush=flush)
|