services/ai.py: - 模型目录(catalog)按短 id 索引,业务代码不感知厂商 gemini-flash (Google, 1M 上下文) llama-70b / qwen-72b / deepseek-r1 (NVIDIA NIM, 128k) 仅注册纯文本模型,不含视觉模型 - 两个 provider: GeminiProvider、OpenAICompatProvider (后者兼容 NVIDIA NIM / Ollama / vLLM) - 大上下文: 每日指标序列化为 CSV 而非 JSON,同样的数据 token 数约为 1/4,一整年历史仍远小于最小的 128k 窗口;按 AI_DAY_BUDGET 截断 - 兜底链: 首选模型超时/报错/返回无法解析的文本时自动降级到下一个, meta.fallbackFrom 记录降级路径 - 响应解析容忍 markdown 代码块包裹和 JSON 前的多余句子 services/analysis.py: - get_ai_recommendations(): 所有模型都失败时回落到规则引擎, 端点始终 200,meta.source 区分 ai / rules routes/analysis.py: - GET /api/analysis/models 列出模型及各自是否已配置密钥 - GET /api/analysis/ai-recommendations?model=&days= tests/test_ai.py (59 通过, 全程 mock 不联网): - prompt: 大预算截断保留最新的天、缺失指标不写成 "None"、 一年数据估算 token 数上界 - 解析: 代码块包裹/前置句子/单对象/非法 priority/空建议 等 7 种畸形输入 - provider: 超时、HTTP 4xx/5xx、响应结构异常均转为 AIError; 未配置密钥时不发出任何请求 - 兜底: gemini 超时后 llama 接管、首个成功则不再调用第二个 - 端点: /models 不泄漏 API key;无密钥时仍返回 200 + 规则建议 密钥一律从环境变量读取,.env.example 只留空占位符。 全量: 161 passed, 1 skipped Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
43 lines
1.3 KiB
Plaintext
43 lines
1.3 KiB
Plaintext
# --- Server ---
|
|
PORT=5000
|
|
|
|
# --- Database: sqlite (default) or mariadb ---
|
|
DB_TYPE=sqlite
|
|
# SQLite file (used when DB_TYPE=sqlite)
|
|
DATABASE_PATH=./data/health.db
|
|
|
|
# MariaDB (used when DB_TYPE=mariadb) — runs on the NAS
|
|
# MARIADB_SOCKET=/run/mysqld/mysqld10.sock
|
|
# MARIADB_HOST=127.0.0.1
|
|
# MARIADB_PORT=3306
|
|
# MARIADB_USER=root
|
|
# MARIADB_PASSWORD=your_nas_mariadb_root_password
|
|
# MARIADB_DATABASE=garmin_health_lab
|
|
|
|
# --- Auth ---
|
|
# CHANGE THIS in production! Used to sign JWTs (7-day expiry by default).
|
|
JWT_SECRET=dev_secret_change_me
|
|
JWT_EXPIRY_DAYS=7
|
|
|
|
# --- CORS (comma-separated allowed front-end origins) ---
|
|
CORS_ORIGIN=http://localhost:3000,http://localhost:5173
|
|
|
|
# --- AI models (text-only, large context) ---
|
|
# Put REAL keys in backend/.env — that file is gitignored. Never commit keys.
|
|
# Any model whose key is absent is skipped automatically.
|
|
|
|
# Google AI Studio -> the "gemini-flash" model id
|
|
GEMINI_API_KEY=
|
|
|
|
# NVIDIA NIM (OpenAI-compatible) -> "llama-70b", "qwen-72b", "deepseek-r1"
|
|
NVIDIA_API_KEY=
|
|
# NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
|
|
|
|
# Preference order. The first configured model answers; if it fails or times
|
|
# out, the next one is tried automatically.
|
|
AI_MODEL_CHAIN=gemini-flash,llama-70b,qwen-72b
|
|
|
|
# Max days of history sent to the model (CSV-encoded, ~4 chars/day).
|
|
AI_DAY_BUDGET=365
|
|
AI_TIMEOUT_SECONDS=45
|