Files
get_wechat/chatlog_fastAPI/routers/settings.py
yuanzhipeng eecbe4172e feat(api): 将万川平台配置迁移至后端存储
- 移除前端localStorage依赖,改用后端SQLite作为唯一数据源
- 新增getWanchuanConfig和saveWanchuanConfig函数用于配置读写
- 添加getBoundKnowledgeBase函数统一获取绑定知识库信息
- 支持桌面应用端口变化时正确读取配置

refactor(settings): 重构万川平台配置管理逻辑

- 移除localStorage配置存储,改为后端API调用
- 实现配置自动恢复和防抖保存机制
- 添加token过期自动重登功能
- 优化知识库选择和连接状态管理

fix(knowledge): 修复知识库上传异步问题

- 将getBoundKnowledgeBase调用改为await异步处理
- 统一各页面的知识库信息获取方式
- 修正上传接口datasetId使用逻辑

feat(electron): 添加chatlog.exe存在性检查

- 新增ensureChatlogExe函数验证执行文件存在
- 防止杀毒软件误删导致的ENONENT错误
- 提供用户友好的错误提示和解决方案
2026-06-24 10:13:20 +08:00

100 lines
3.4 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.
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from typing import Optional, Any
import json
import aiosqlite
from database import get_db
router = APIRouter(prefix="/api/settings", tags=["settings"])
EDITABLE_KEYS = [
"ai_base_url", "ai_api_key", "ai_model", "summary_model",
"vision_model", "voice_model", "topic_analysis_prompt",
]
# 万川 AI 平台对接配置整体作为一条 JSON 存储,独立于上面的 AI 模型配置。
# 存到后端 SQLiteapp_settings 表)后,配置不再依赖前端 localStorage 的 origin
# 桌面应用exe即便后端端口/origin 变化也能跨次启动恢复平台地址、账号、密码与已选知识库。
WANCHUAN_KEY = "wanchuan_config"
def _mask_key(value: str) -> str:
if not value or len(value) <= 8:
return "*" * len(value) if value else ""
return value[:3] + "*" * (len(value) - 7) + value[-4:]
@router.get("")
async def get_settings(db: aiosqlite.Connection = Depends(get_db)):
result = {}
placeholders = ",".join("?" for _ in EDITABLE_KEYS)
async with db.execute(
f"SELECT key, value FROM app_settings WHERE key IN ({placeholders})",
EDITABLE_KEYS,
) as cur:
rows = await cur.fetchall()
for row in rows:
k, v = row["key"], row["value"]
result[k] = _mask_key(v) if k == "ai_api_key" else v
for k in EDITABLE_KEYS:
if k not in result:
result[k] = ""
return result
class SettingsUpdate(BaseModel):
ai_base_url: Optional[str] = None
ai_api_key: Optional[str] = None
ai_model: Optional[str] = None
summary_model: Optional[str] = None
vision_model: Optional[str] = None
voice_model: Optional[str] = None
topic_analysis_prompt: Optional[str] = None
@router.put("")
async def update_settings(body: SettingsUpdate, db: aiosqlite.Connection = Depends(get_db)):
updates = body.model_dump(exclude_none=True)
for k, v in updates.items():
if k not in EDITABLE_KEYS:
continue
if k == "ai_api_key" and "*" in v:
continue
await db.execute(
"INSERT INTO app_settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = ?",
(k, v, v),
)
await db.commit()
from services.runtime_settings import invalidate_cache
invalidate_cache()
return {"status": "ok"}
# ── 万川 AI 平台对接配置(整体 JSON 持久化) ──────────────────
# 前端把 { platformUrl, username, password, selectedKbId, selectedKbInfo } 整体存这里。
# 桌面应用 origin 变化不影响该配置(不依赖 localStorage
@router.get("/wanchuan")
async def get_wanchuan_config(db: aiosqlite.Connection = Depends(get_db)):
async with db.execute(
"SELECT value FROM app_settings WHERE key = ?", (WANCHUAN_KEY,)
) as cur:
row = await cur.fetchone()
if not row or not row["value"]:
return {}
try:
return json.loads(row["value"])
except (ValueError, TypeError):
return {}
@router.put("/wanchuan")
async def update_wanchuan_config(body: dict[str, Any], db: aiosqlite.Connection = Depends(get_db)):
value = json.dumps(body, ensure_ascii=False)
await db.execute(
"INSERT INTO app_settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = ?",
(WANCHUAN_KEY, value, value),
)
await db.commit()
return {"status": "ok"}