按要求废弃手写外壳,改用 Framework7 React(theme=ios)。参照 PeakWatch 的信息架构与卡片语言。 保留(这些是资产,不该重来): - 数据层 services/api.ts、聚合 lib/aggregate.ts、参考区间 lib/ranges.ts - 图表组件 Chart / Ring / Sparkline / BandBar / MetricCard / MetricStrip - 经校验的配色令牌(色盲安全 + 对比度,浅深两档) 替换: - 路由与外壳交给 F7:五个 Tab 各自独立导航栈,推入详情页不影响其他 Tab - 页面转场、橡皮筋滚动、大标题折叠、半透明栏 —— 这些正是换框架的理由, 手写做不像 - 底部标签栏改用 F7 Toolbar,触控目标与安全区由框架处理 配色接入: - 新增 f7theme.css 把我们的令牌映射到 F7 的 CSS 变量,让它的导航栏/ 列表/面板与我们的图表同属一套设计,而不是两种视觉打架 - F7 的深色靠 .dark 类,我们的靠 data-theme,两者在 App 里同步切换 fix: 图标显示为原始名称(squ/hea/cale…) - iconIos/iconMd 引用的是 framework7-icons 字体,没装就只会渲染出名字 其他: - tsconfig moduleResolution 改为 bundler —— F7 用 exports 映射, node 解析方式找不到它的类型 - 登录页不套 Tab 外壳,未登录时不该出现导航 桌面与手机都要好看:内容在宽屏收进 1100px 居中列并加密卡片列数, 窄屏走底部标签栏;两档都已实机核对。 bundle 190KB -> 399KB,是换取原生手感的代价。 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
63 lines
2.5 KiB
Plaintext
63 lines
2.5 KiB
Plaintext
# --- Server ---
|
|
# BACKEND_PORT takes precedence over PORT. Prefer it: many tools inject PORT
|
|
# for the frontend, and Flask would otherwise take the React dev server's port.
|
|
BACKEND_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) ---
|
|
# localhost stays in the production list on purpose: CORS is not an auth
|
|
# boundary — every data route requires a valid JWT — so allowing a developer's
|
|
# dev server costs nothing and saves toggling this on every session.
|
|
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 credentials are absent is skipped automatically.
|
|
|
|
# Self-hosted AI gateway (model id "gateway"). OpenAI-compatible; it fans out
|
|
# over nvidia/gemini/ollama itself and rotates several Gemini keys, so it
|
|
# absorbs single-vendor quota limits. Reached directly, bypassing any local
|
|
# HTTP proxy. NOTE: its NVIDIA upstream is a large reasoning model — replies
|
|
# can take 2-3 minutes, so set AI_TIMEOUT_SECONDS accordingly.
|
|
AI_GATEWAY_BASE_URL=http://129.146.203.203:5100/v1
|
|
AI_GATEWAY_TOKEN=
|
|
AI_GATEWAY_MODEL=ai-gateway-auto
|
|
|
|
# Google AI Studio -> "gemini-flash". Free-tier quota is small; 429s are common.
|
|
GEMINI_API_KEY=
|
|
|
|
# NVIDIA NIM -> "llama-70b", "nemotron-49b", "mistral-large".
|
|
# Model ids come from that account's live GET /v1/models — do not guess them.
|
|
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 is tried. Read per request, so changes need no restart.
|
|
AI_MODEL_CHAIN=gateway,gemini-flash,llama-70b
|
|
|
|
# Max days of history sent (CSV-encoded). Trimmed further per model so the
|
|
# payload always fits that model's own context window.
|
|
AI_DAY_BUDGET=365
|
|
|
|
AI_TIMEOUT_SECONDS=180
|
|
# Output cap. Reasoning models spend part of it thinking before they answer;
|
|
# entries that need more declare their own budget in services/ai.py.
|
|
AI_MAX_TOKENS=1024
|