feat: 新增运营公告端点 /api/notice

- 读取 notices/notice.json 下发公告,无文件时返回空
- 新增 notices_dir 配置项
This commit is contained in:
crosswk committed 2026-07-15 23:30:51 +08:00
1 parent 4680003a11
commit c1772935a5
4 files changed
+48

No files matched your search

+2
View File
@@ -36,6 +36,7 @@ class GatewayConfig:
class PathsConfig:
prompt_dir: str = str(_PROJECT_ROOT / "prompts")
releases_dir: str = str(_PROJECT_ROOT / "releases")
notices_dir: str = str(_PROJECT_ROOT / "notices")
@dataclass(slots=True)
@@ -460,6 +461,7 @@ def load_config(config_path: str | None = None, env_path: str | None = None) ->
paths=PathsConfig(
prompt_dir=prompt_dir,
releases_dir=_resolve_path(paths_raw.get("releases_dir"), _PROJECT_ROOT / "releases"),
notices_dir=_resolve_path(paths_raw.get("notices_dir"), _PROJECT_ROOT / "notices"),
),
asr=ASRConfig(
engine=str(asr_raw.get("engine") or defaults.asr.engine),
+7
View File
@@ -24,6 +24,7 @@ from .diagnostics import create_upload_token, router as diagnostics_router
from .llm import LLMEngine
from .logging_setup import attach_database_log_handler, bind_log_context, configure_logging, reset_log_context
from .ratelimit import RateLimitMiddleware
from .notice import read_notice
from .releases import read_public_download, read_release_manifest, resolve_release_file
from .telemetry import TelemetryService
@@ -519,6 +520,12 @@ async def post_feedback(request: Request):
return JSONResponse({"ok": True}, 200)
@app.get("/api/notice")
async def get_notice():
"""运营公告:客户端据此在 App 内展示通知。无公告时返回空对象。"""
return JSONResponse(read_notice(cfg), headers={"Cache-Control": "no-store"})
@app.get("/api/desktop-updates/{platform}/{arch}/manifest")
async def get_desktop_update_manifest(platform: str, arch: str):
return read_release_manifest(cfg, platform, arch)
+27
View File
@@ -0,0 +1,27 @@
"""运营公告(remote notice)。
与桌面更新机制完全解耦:客户端定期拉取 /api/notice,据此在 App 内展示一条公告
(例如引导旧版用户去官网/GitHub 手动下载新版)。只读、无副作用、无任何记录能力。
运维方式:编辑 <notices_dir>/notice.json 即可下发;删除或留空即撤下。
字段见 notice.example.json。
"""
from __future__ import annotations
import json
from pathlib import Path
from .config import Config
def read_notice(cfg: Config) -> dict:
"""读取当前公告;文件不存在或解析失败时返回空对象(客户端据此不展示)。"""
notice_file = Path(cfg.paths.notices_dir) / "notice.json"
try:
if not notice_file.is_file():
return {}
data = json.loads(notice_file.read_text(encoding="utf-8"))
return data if isinstance(data, dict) else {}
except Exception:
return {}
+12
View File
@@ -0,0 +1,12 @@
{
"id": "2026-07-16-manual-update",
"level": "warning",
"title": "请手动更新到最新版本",
"body": "由于旧版本的自动更新存在问题,请前往官网或 GitHub 下载安装最新版本,即可恢复正常的自动更新。",
"linkUrl": "https://sayitapp.site",
"linkLabel": "前往官网下载",
"maxVersion": "0.0.9",
"startAt": null,
"endAt": null,
"dismissible": true
}