Commit Graph

87 Commits

Author SHA1 Message Date
ericwyuan
f20b6c9254 fix(fam-edge): WatchProcessor 递归扫描子目录(GDrive 录像按 YYYYMMDDAM/PM 子目录组织) 2026-08-21 11:28:14 +08:00
ericwyuan
dbc5193659 fix(nas): sync_cursor 查询 key/value 列加反引号(MariaDB 保留字导致 /api/status 500) 2026-08-21 11:23:25 +08:00
ericwyuan
8ca02495bf fix(nas): start_core.sh 启动时 source 项目 .env 注入 ORACLE_SYNC_TOKEN 2026-08-21 11:09:46 +08:00
ericwyuan
8960a8bf6b fix(sql): sync_cursor 表 key/value 列加反引号(MariaDB 保留字) 2026-08-21 11:06:41 +08:00
ericwyuan
ec25f4f50c fix(fam-edge): ollama_adapter 补充缺失的 Dict 类型导入(修复 worker 启动 NameError) 2026-08-21 10:59:32 +08:00
ericwyuan
44026b65ea [阶段3] FAM-Core 瘦身为管理后台+Oracle-Sync 同步引擎,FAM-UI 改读同步镜像 - 删除 scheduler/dispatcher/poller/event_receiver/video_server,新增 oracle_sync 每30分钟拉增量写 sync_* 镜像表;member_manager/chat_handler 改走同步数据;UI 移除帧图改为事件时间线;DDL 新增 sync_videos/events/people/cursor 2026-08-21 10:38:26 +08:00
ericwyuan
9b1cc8f93b [阶段2] FAM-Edge 重构为整视频分析+同步接口+人物服务 - 移除切片/抽帧/队列,新增 oracle_db/person_service/qa/watch_processor/video_processor,api_gateway 提供 /api/oracle/sync 与 /api/oracle/people/correct 2026-08-21 10:38:15 +08:00
ericwyuan
ae1c13589f fix(人物管理): 头像优先选独照帧,避免双人图当头像
人物卡片头像挑选策略调整:
1. 优先『独照』帧——该帧只有当前人物一个标签且 face_count=1(双人图不再作为某人头像)
2. 无独照时退而求其次用 face_count 最大的帧
3. 最后按时间序第一张兜底
修复: 一张图出现两人时(如 event_21/frame_3 '人物1, 人物2'),两人卡片都拿双人图做头像、无法区分的问题
2026-08-21 05:54:38 +08:00
ericwyuan
73f6c77544 feat(人物管理): 头像优先选有人脸帧 + 人物合并到操作
1. person_photo 读 event 的 meta.json(face_count),优先挑人脸数最多的帧做头像,无 meta 时按时间序第一张兜底
2. 人物卡片新增「合并到」下拉框+按钮,调 /api/member/merge(source=当前人物,target=所选人物),展示替换明细数
3. 至此设计文档 8 项需求全部落地(Edge 画框/mark_frames 端点/meta.json/backfill/merge_member/merge 路由/UI 头像+合并)
2026-08-21 00:57:20 +08:00
ericwyuan
43b3178a9d feat(人物管理/红框标记): 关键帧人脸标记 + 人物命名重命名回溯 + 人物管理页改版
1. fam-edge 新增 frame_marker.py: Edge 端人脸检测画红框+统计人脸数(NAS ARM 太弱只存图零计算),orchestrator 分析后回传前标记,新增 /api/edge/mark_frames 批量补标端点
2. fam-core 新增 tools/backfill_mark_frames.py: 存量关键帧批量补红框(幂等+备份 frames_orig)
3. db_layer.name_member 增强: 支持自动注册新标签/重命名回溯(旧真名一并替换)/多人组合字符串 REPLACE
4. fam-ui 成员命名页改为人物管理页: 所有人物照片墙+命名重命名+统计去重
5. event_receiver/member_manager 配套适配
2026-08-21 00:53:30 +08:00
ericwyuan
47c42f24df docs: update PROGRESS.md - 人物统计去重与导航改进 2026-08-21 00:22:41 +08:00
ericwyuan
3fb86ee449 fix: 出现人物统计去重 + 导航移至页面顶部
- person 字段是自由文本,一帧可为多人组合且带括号特征描述
  ('张三 (红色T恤), 汤圆, 人物3'),COUNT(DISTINCT person) 把每种
  组合字符串当一个人物,全局误报 20 人。新增 resolve_persons:
  去括号描述 -> 按中英逗号/顿号/斜杠拆分 -> family_members
  抽象标签映射真名,去重后全局实际 6 人
- 导航从侧边栏 radio 改为顶部 segmented_control:窄屏下
  Streamlit 侧边栏自动收起,页面入口藏进汉堡菜单导致
  "成员命名/问答界面不见了";放主区域顶部任何屏宽可见
2026-08-21 00:22:24 +08:00
ericwyuan
5d574029b0 docs: update PROGRESS.md - Gemini 降级排查修复 2026-08-21 00:07:56 +08:00
ericwyuan
eaf4ef3bd3 fix: Gemini 模型 fallback 链 — 修复全量降级 NVIDIA
根因: 免费层配额 GenerateRequestsPerDayPerProjectPerModel 每天每
模型仅 20 请求,日均 30+ 任务耗尽后持续 429,全部降级 NVIDIA
(最近40任务 35 nvidia / 4 gemini)。

- gemini_adapter 抽 _generate() 模型链调用: 429 立即切换下一模型
  (flash -> flash-lite,各自独立 20/天配额),503 退避 3s 重试一次
  再切换;视觉分析与问答统一走该链
- config: gemini 增 fallback_models,nvidia 恢复 nemotron-omni
  (原生视频输入;此前 Oracle 线上手动改过未回传仓库,被旧配置
  覆盖回 llama-3.2 逐帧模式) + timeout 30->120
- 健康检查校验整条模型链

实测 task 73: flash 429 -> lite 1s 内接管,12 帧直出,event_52
落库 provider=gemini。
2026-08-21 00:07:34 +08:00
ericwyuan
7efbee89fb docs: update PROGRESS.md - 事件列表带年月日 2026-08-20 23:50:48 +08:00
ericwyuan
f50f98e292 ui: 事件列表条目带年月日 — 跨天事件可区分
跨多天的事件列表仅显示 HH:MM 无法区分日期。按钮标签加 MM-DD
前缀,摘要行加浅蓝 YYYY-MM-DD 前缀,摘要截断 26→30 字适配。
2026-08-20 23:50:31 +08:00
ericwyuan
6ecdffce04 docs: update PROGRESS.md - 压缩缓存回退补齐全部历史事件帧图 2026-08-20 22:42:31 +08:00
ericwyuan
80cc3249e5 feat: backfill_frames 支持压缩缓存回退 — 补齐全部历史事件帧图
原始视频被 Surveillance Station 保留策略删除后,回退到
/tmp/fam_compressed/task_{id}/ 的 480p 压缩副本抽帧。实测
event 18-27(08-14 晚间 10 事件)补 78 帧全部成功,至此
所有历史事件帧图齐全,UI 不再出现暂无帧图。
2026-08-20 22:42:08 +08:00
ericwyuan
3a3b68c428 docs: update PROGRESS.md - 历史事件关键帧补抽 2026-08-20 22:07:57 +08:00
ericwyuan
8a333d752d feat: 历史事件关键帧补抽工具 backfill_frames.py
Edge 帧图注入上线前的旧事件无帧图,事件列表第一屏全是占位符。
按 frame_timestamp - event_start_time 偏移从原始视频抽帧补齐,
幂等可重跑。NAS ffmpeg41 无 image2 muxer,用 -f singlejpeg 输出。
实测补 11 事件 65 帧全部成功(2026-08-14 的 10 个事件视频已被
清理,无法补)。
2026-08-20 22:07:36 +08:00
ericwyuan
634ff746a9 docs: update PROGRESS.md - UI时间轴重构 + 关键帧持久化 + multipart超时修复 2026-08-20 20:44:52 +08:00
ericwyuan
c5c8496409 fix: 直接上传multipart超时 — connect timeout 10s→120s
requests/urllib3 发送 multipart body 期间 socket timeout 取的是
connect timeout 值而非 read timeout,跨境 1.4MB/s 下 17MB 视频需
~117s,原 10s 上限导致 100% 超时重试耗尽标记 FAILED。实测 task
50/51 修复后直接上传成功。
2026-08-20 20:43:50 +08:00
ericwyuan
0d5173f442 feat: UI 时间轴重构 + 关键帧图片全链路持久化
界面重做(深色监控面板主题):
- 事件时间轴页: 左侧事件列表卡片 + 右侧关键帧时间轴
  (时间点 + 视频帧 + 人物/动作/衣着摘要 + 关注标记)
- 全局 CSS: 深色主题、卡片化按钮、统计卡、对话气泡、成员卡片
- 侧边栏任务队列状态徽章; 历史帧无图时优雅降级占位

关键帧持久化链路:
- Edge orchestrator: process_push_task 成功后把 keyframes
  base64 注入 frame_details[i].frame_image (位置对齐视觉输入帧)
- NAS event_receiver: 落库前 base64 解码写盘到
  fam-ui/static/frames/event_{id}/frame_{idx}.jpg
- payload 增量 ~300KB/事件 (6帧 jpeg q80), 队列/拉取均无压力

配置: fam-core/fam-ui 新增 storage.frame_image_dir
2026-08-20 19:50:36 +08:00
ericwyuan
963b6d7540 docs: update PROGRESS.md - 队列表schema迁移修复时区残留 + -f mp4修复 2026-08-20 18:51:51 +08:00
ericwyuan
9aba71c8ed fix: Edge队列时间戳根治 — INSERT显式北京时间 + 存量表schema迁移
795e8ac 只改了 CREATE TABLE 的 DEFAULT,但 DEFAULT 固化在已存在表的
schema 中,IF NOT EXISTS 不会更新旧表——新行 created_at 仍走旧
DEFAULT(localtime)=UTC。三处修复:
1. enqueue INSERT 显式写 created_at/updated_at (+8 hours),不再依赖 schema DEFAULT
2. _init_db 检测旧 schema 含 localtime 时重建表迁移(数据保留,幂等)
3. 存量数据修正: 行16/19 created_at +8h

验证: 本地迁移单测3例通过;线上行20(task 44) created_at=18:43:35
为北京时间(UTC机器当时10:43)。
2026-08-20 18:50:59 +08:00
ericwyuan
1b82db1493 fix: NAS压缩输出显式指定 -f mp4 — .tmp 扩展名导致 ffmpeg41 无法推断 muxer 2026-08-20 18:28:14 +08:00
ericwyuan
4e16330e87 docs: update PROGRESS.md - 压缩缓存原子性修复 2026-08-20 18:11:43 +08:00
ericwyuan
1994de22e0 fix: 压缩缓存原子性 — tmp+rename 杜绝半成品缓存被复用
根因: 服务被 kill 时 dispatcher 死亡但其 ffmpeg 子进程成为孤儿
(父进程转 init)继续写压缩产物。旧代码直接写最终路径,半成品文件
size>0 且 mtime 较新,缓存复用判断(size>0 && mtime>=src)会误判
为有效 → 重试任务上传损坏视频(此前 task 300 损坏视频之谜的根源)。
多次重启还会叠加多个孤儿 ffmpeg 争抢 ARM CPU。

修复:
1. 压缩输出写 {out}.{pid}.tmp(带 PID 防多进程冲突),
   成功后 os.replace 原子 rename — 缓存目录只可能出现完整产物
2. _cleanup_compress_cache 顺带清理超过 1h 的 .tmp 残留
3. TimeoutExpired/失败路径 _safe_remove(tmp)

运维: 已清理孤儿 ffmpeg×2(task 43/44)+缓存目录,重置对应任务。
2026-08-20 18:11:24 +08:00
ericwyuan
47cee9db4f docs: update PROGRESS.md - 视频时间语义修正 2026-08-20 17:58:50 +08:00
ericwyuan
80b2fcc40c fix: 视频时间语义修正 — 绝对时间戳偏移换算 + mtime 起点修正 + 直传超时
三处时间语义 bug(时区统一排查的延伸发现):

1. NVIDIA 集锦偏移语义: frame_timestamps 是绝对时间
   'YYYY-MM-DD HH:MM:SS'(当日秒 77474s)被直接当视频内偏移用,
   seek 超出 30 分钟视频 → 0 帧 → 集锦恒为空 → 视频模式永远降级。
   修复: analyze_video 增加 event_start_time 参数,偏移 =
   帧时间 - 视频开始时间(跨午夜 +86400);orchestrator 两处
   调用点透传。另加 ffprobe 时长过滤跳过超界片段(日志明示),
   fps=15 统一 CFR 输出。

2. NAS dispatcher event_start_time: 原用文件 mtime(=录制结束
   时刻),真实开始时间应为 mtime - 视频时长,事件时间整体偏移
   一个视频周期(~30min)。新增 _probe_duration 用 ffmpeg 解析
   Duration(NAS 无独立 ffprobe)。

3. 直传超时: 压缩后 ~19MB 略低于 20MB 分块阈值走直传,
   timeout(10,120) 在 1Mbps 下传 19MB 需 ~152s 必超时(task 42
   三连败 FAILED)。加大到 (10, 300)。

测试数据陷阱记录: 两轮 0KB/9.47s 集锦异常均为测试时间戳超出
视频时长所致(1801s>1800s),单输入/多输入 concat 行为本身正常。
2026-08-20 17:58:16 +08:00
ericwyuan
3817609d1b docs: update PROGRESS.md - 时区统一北京时区修复 2026-08-20 17:42:35 +08:00
ericwyuan
795e8acc6c fix: 时区统一北京时区 — Edge(UTC机器)三处时间处理修复
背景: Oracle Edge 机器为 UTC 时区,NAS 与视频均为北京时间,
网页要求统一北京时区。排查结论: NAS 端(北京时间)与 UI(直读
MariaDB)均正确,问题集中在 Edge 端三处。

1. queue_manager: 7 处 datetime('now','localtime') 在 UTC 机器上
   写入 UTC 时间(比北京慢8h),全部改为 datetime('now','+8 hours')
2. preprocessor.compute_timestamps: event_start_time 缺失时 fallback
   datetime.now() 用了 Edge 本地时间(UTC),改为北京时间
   datetime.now(timezone(+8h));带时区的 ISO 输入统一转北京时间
3. nvidia_adapter._ts_to_seconds: 不支持生产格式
   'YYYY-MM-DD HH:MM:SS'(split后int抛ValueError全部返回-1),
   导致集锦视频永远为空、视频模式永远降级逐帧——上一轮引入的
   bug,测试用 HH:MM:SS 格式未暴露。现支持两种格式;drawtext
   标签与提示词同步为完整时间戳说明

数据修正: event 17(task 298 手动测试缺 event_start_time)的
frame_timestamp 全为 UTC,按视频文件名真实时间(04:34:10)重算;
Edge 队列存量时间戳 +8h。

验证: 单测三例通过(生产格式解析/fallback北京时间/ISO带时区转换);
task 41 新代码正确写入北京时间 17:36:52。
2026-08-20 17:41:59 +08:00
ericwyuan
4553ec6f07 docs: update PROGRESS.md - NVIDIA原生视频输入切换调研与实现 2026-08-20 17:22:08 +08:00
ericwyuan
55633d3302 feat: NVIDIA 切换到原生视频输入 — nemotron-3-nano-omni + 集锦视频单次调用
调研结论: build.nvidia.com 免费托管 API 上 video-llama3-8b 与
qwen2.5-vl-72b 已下线(404),nvidia/nemotron-3-nano-omni-30b-a3b-reasoning
可用(200, 40RPM 免费额度内),原生支持 video_url 输入(MP4 base64)。

实现:
1. nvidia_adapter 新增 analyze_video: 按关键帧时间点截取 ±1.5s 片段
   (drawtext 叠加时间戳,连字符避免冒号转义)拼集锦视频,640 宽 CRF28,
   base64 后经 video_url 单次调用,输出全 schema JSON(frame_details +
   global_summary + entities_json)并归一化对齐时间戳
2. analyze_frames 保留为无视频文件时的降级路径; chat max_tokens
   512→2048(reasoning 模型 token 消耗大); timeout 20→120s
3. orchestrator.run_visual_analysis 增加 video_path 参数,fallback 循环
   对支持 analyze_video 的适配器优先走视频模式,失败自动降级逐帧

实测(360MB 测试视频, 3 关键帧): 集锦 107KB, 全程 37s, 动态动作识别准确
(走动→坐沙发→坐餐桌),跨片段综合摘要正常 — 显著优于旧逐帧静态识别。
2026-08-20 17:21:33 +08:00
ericwyuan
8a62c46194 docs: update PROGRESS.md - Gemini视觉解析排查结论+业务全流程图 2026-08-20 16:15:28 +08:00
ericwyuan
f4e742481d fix: json_parser 不再要求模型输出 compute_provider — Gemini 有效响应被误杀
根因: validate_schema 把 compute_provider 列为必填并校验非空数组,
但提示词模板从不要求模型输出该字段(它是 orchestrator 在解析成功后
自行填充的内部记账字段)。Gemini 返回完整合法 JSON 时被误判解析失败,
100% 复现。NVIDIA 走单帧轻量解析绕过了该校验,故此前仅 Gemini 受影响。

修复: compute_provider 从必填清单移除,缺失/非法时归一为空数组,
由 format_cloud_result 用实际成功的 provider 覆盖填充。

验证: 单元测试模拟 Gemini 真实输出(无 compute_provider + markdown
fence 包裹)解析通过。
2026-08-20 16:14:27 +08:00
ericwyuan
a2554c9df0 docs: update PROGRESS.md - 视频上传问题根因(网络+逻辑双叠加)与四项修复 2026-08-20 15:36:35 +08:00
ericwyuan
8cb5553beb fix: Edge端三处修复 — API key丢失致全模型失败 + 失败结果黑洞 + 重派发死锁
根因: Edge服务手动重启未source .env,GEMINI/NVIDIA key丢失,
所有视觉模型调用失败("All models failed"),且失败结果永不回传NAS。

1. config_loader: 启动时自动加载.env(export KEY=VALUE),已存在环境变量不覆盖
2. queue_manager.enqueue: FAILED(或已交付SUCCESS)行重置为PENDING复用重跑,
   修复 INSERT OR IGNORE + UNIQUE(nas_task_id) 导致的静默忽略死锁
3. get_undelivered_results: 包含FAILED状态,/results构造failed负载,
   NAS Poller可感知失败避免僵尸循环空转重传
4. ddl.sql: failure_stage ENUM 增加 'process'(与db_layer valid_stages对齐),
   修复 pymysql DataError 1265

验证: task 293(压缩后22MB) NVIDIA降级分析成功→event_id=13;
task 295 全链路成功→event_id=14;NAS端ENUM已同步ALTER
2026-08-20 15:35:40 +08:00
ericwyuan
203b076783 feat: NAS端FFmpeg预压缩 — 根治360MB视频跨境上传超时
根因诊断(网络问题,非代码逻辑):
- NAS(中国移动) → Oracle(美国Phoenix) 跨境上行带宽实测仅 0.5-0.9MB/s 且波动大
- 下载方向 3.0MB/s(非对称,典型国际出口拥塞)
- Tailscale P2P: ping 可通(224ms)但持续数据流被阻断(0 B/s, 127s超时)
- 360MB 原始视频上传需 10-20min,任何大分块都会超时

NAS dispatcher:
- 新增 _compress_video: 480p/CRF28/veryfast,静态监控场景实测 ~36x 压缩比
  (360MB → ~12MB,上传时间 20min → ~30s)
- ffmpeg 自动探测: CodecPack ffmpeg41(带libx264) > /usr/local/bin > PATH
  (Synology 系统 ffmpeg 被裁剪,无 h264 编解码)
- scale 两级滤镜: force_original_aspect_ratio=decrease + trunc(iw/2)*2
  (h264 要求偶数尺寸,853x480 会报错)
- 压缩缓存 /tmp/fam_compressed/task_{id}/,源文件未变则重试复用,TTL 24h
- 压缩完成后重置 PROCESSING 状态(重置 stale 回收计时基准)
- 压缩失败回退原始文件分块上传
- _query_uploaded_chunks 失败时记录日志(原静默失败导致全量重传无感知)

Edge api_gateway:
- fix: total_chunks 变更清理旧分块后同步重写 meta.json
  (原 bug: meta.json 不更新导致每块上传都触发清理,删除同批新分块死循环)

config:
- stale_timeout 600→1800(覆盖压缩+上传+Edge队列积压总时长)
- 新增 ffmpeg_path / compress_timeout 配置项
2026-08-20 14:59:50 +08:00
ericwyuan
a9a1b1dda5 docs: update PROGRESS.md - 串行上传+5MB分块+看门狗+chunk_size防护 2026-08-20 14:20:00 +08:00
ericwyuan
5915cf4be3 fix: 分块大小减至5MB + Edge端chunk_size变更自动清理 + 断点续传防护
NAS dispatcher:
- CHUNK_SIZE 10MB→5MB(~1Mbps上行带宽下可靠传输)
- chunk上传timeout (30,120)→(60,180)(增加连接和读取余量)
- _query_uploaded_chunks 返回 (set, edge_total) 元组
- expected_total != edge_total 时跳过断点续传(防止chunk_size变更导致文件损坏)

Edge api_gateway:
- upload_chunk 检测 total_chunks 变更,自动清理旧分块
- 防止不同chunk_size的旧分块与新分块混合导致assemble后文件损坏
2026-08-20 14:18:29 +08:00
ericwyuan
d6054de060 fix: 分块大小减至10MB + 上传失败确认机制 + 重试前置检查
- CHUNK_SIZE 20MB→10MB,CHUNK_THRESHOLD 50MB→20MB,降低单次超时概率
- 新增 _query_uploaded_chunks 独立方法,connect timeout 10s→30s
- 分块上传失败后查询 Edge 确认是否实际收到,避免响应丢失导致不必要重试
- 补全 uploaded_set.add(idx) 防止重复上传已成功分块
- _poll_once 中前置 retry_count 检查,超限任务直接标记 FAILED
2026-08-20 13:55:59 +08:00
ericwyuan
881ea3f470 fix: dispatcher 串行上传 + 看门狗自动重启 + 线程状态真实检测
- Dispatcher limit=10→1: 一次只传一个视频,传完再传下一个
- 退避缩短: min(30*(n+1),300)s → 失败后更快重试(原 min(60*(n+1)*2,600)s)
- /api/status: 用 thread.is_alive() 替代 _running 布尔标志
- 三组件(scheduler/dispatcher/poller)添加 is_alive()+check_and_restart()
- app.py 新增 watchdog 线程: 每 60s 检测线程死亡并自动重启
2026-08-20 13:37:07 +08:00
ericwyuan
b6c13a9047 feat: 分块断点续传上传 — 20MB/块 + 分块级重试 + 断点查询
Edge 端新增 3 个端点:
- POST /api/edge/video/chunk: 接收单块,保存到 task_{id}/chunk_{index:04d}
- GET /api/edge/video/chunks: 查询已上传分块(断点续传)
- POST /api/edge/video/assemble: 合并全部分块入队

NAS Dispatcher 重写:
- 大文件(>50MB)自动分块上传(20MB/块)
- 每块最多重试 3 次(分块级重试,非整文件级)
- 上传前查询已上传分块,跳过已有的(断点续传)
- 全部上传后调 /assemble 合并入队
- 小文件(<=50MB)走直接上传路径
- max_retries 3→5(文件级重试次数)
- scheduler 切回生产目录

解决: 360MB 视频跨公网单次上传超时/断连问题
2026-08-20 12:27:30 +08:00
ericwyuan
fb4ccb64dc docs: update PROGRESS.md - 异步队列架构 + e2e验证 + 超时修复
新增任务 #43-47:
- SQLite异步队列 + TokenBucket速率限制 (Gemini 1000/NVIDIA 40 RPM, 2x burst)
- NAS Dispatcher enqueue模式 + Poller线程
- 超时分离模式 (10s connect, 60s read) + stale_timeout 600s
- e2e验证: task 312 (5.7MB) 全链路 93s PASS

新增技术决策 #14-16
新增待办 #51: 生产视频预压缩 (360MB HTTP上传超时)
2026-08-20 12:18:58 +08:00
ericwyuan
4f0f19bccd fix: dispatcher/poller 超时改为分离模式,stale_timeout 缩短到 10 分钟
- dispatcher 上传 timeout 从 300s 改为 (10s connect, 60s read)
  避免大文件上传无限阻塞 dispatcher 线程
- poller 拉取 timeout 从 30s 改为 (10s connect, 15s read)
- stale_timeout 从 3600s 缩短到 600s(10 分钟)
  更快回收卡死的 PROCESSING 任务
2026-08-20 12:12:19 +08:00
ericwyuan
02da23ef42 feat: 异步任务队列架构 - SQLite队列 + 速率限制 + NAS Poller
Edge端:
- 新增 SQLite 异步任务队列 (queue_manager + consumer)
- 新增 TokenBucket 速率限制器 (Gemini 1000 RPM, NVIDIA 40 RPM, burst 2x)
- 新增 /api/edge/video/enqueue + /api/edge/results 端点
- 消费者线程从队列消费任务,按速率限制调用AI模型
- orchestrator 集成 rate_limiter,Gemini优先→NVIDIA兜底

NAS端:
- Dispatcher 重构为 enqueue 模式(上传后立即返回,不等结果)
- 新增 Poller 线程(定期从Edge拉取结果写 MariaDB)
- app.py 启动 Poller,config.yaml 新增 poller 配置
- db_layer 更新 valid_stages 添加 'process'
2026-08-20 12:07:09 +08:00
ericwyuan
a4b9178a59 docs: update PROGRESS.md with NVIDIA/dispatcher fixes + batch processing validation
- Task 39: NVIDIA single-frame JSON parsing fix
- Task 40: Gemini timeout + circuit breaker tuning
- Task 41: dispatcher crash on invalid failure_stage
- Task 42: batch processing validated (task 291/297 SUCCESS)
2026-08-20 11:18:22 +08:00
ericwyuan
d75c745b95 fix: dispatcher crash on invalid failure_stage + per-task error isolation
Two fixes:
1. db_layer.update_task_status: map invalid failure_stage values (e.g.
   'process' from Edge) to 'callback' before DB write, preventing
   MariaDB ENUM DataError (1265 "Data truncated")
2. dispatcher._poll_once: wrap each task dispatch in try/except so one
   task's failure doesn't skip remaining tasks in the batch

Root cause: Edge returns failure_stage='process' but DB ENUM only allows
  download/extract/vlm_visual/vlm_fusion/callback. The DataError crashed
  _poll_once(), causing all subsequent PENDING tasks to be skipped.
2026-08-20 11:09:10 +08:00
ericwyuan
853cb21542 fix: NVIDIA single-frame JSON parsing + Gemini timeout/circuit breaker tuning
NVIDIA fix:
- Replace parse_vlm_json (requires full schema: global_summary/entities_json/
  frame_details/compute_provider) with lightweight _parse_single_frame_json
  that only extracts per-frame fields (person/action/clothing/etc)
- Root cause: NVIDIA adapter does per-frame analysis returning single-frame
  JSON, but parse_vlm_json rejected it for missing full-schema fields
- Verified: task 297 → 6/6 frames parsed successfully, first SUCCESS

Gemini + circuit breaker tuning:
- Gemini timeout: 30s → 90s (multi-image vision analysis needs more time)
- NVIDIA timeout: 20s → 30s (per-frame API call)
- Circuit breaker threshold: 3 → 5 (less aggressive tripping)
- Circuit breaker cooldown: 600s → 300s (faster recovery)
2026-08-20 11:02:26 +08:00