40 Commits

Author SHA1 Message Date
ericwyuan
deaebf22b4 fix(fam-edge): 生产者扫描跳过已被 DiskGuard 清理的文件
生产者列目录之后、读 mtime 之前,DiskGuard 可能刚好把那个文件删了(两个后台线程
的正常竞态),os.path.getmtime 抛 FileNotFoundError。代价不是少处理一个文件,而是
**整轮扫描中断**——排在后面的新素材本轮全都登记不上,要等下一轮。

线上日志:生产者扫描异常: [Errno 2] No such file or directory:
/opt/fam-edge/gdrive_videos/20260911PM/Generic_ONVIF-001-20260911-234730-...mp4
(01:30:01 抛出,同一秒 DiskGuard 正在清理那批文件)

改成捕获 OSError 跳过该文件继续扫。新增 tests/test_video_queue.py:被删的跳过且
后面的照常登记、仍在写入的(mtime 太新)依然跳过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 09:35:15 +08:00
ericwyuan
3b5f7db51d fix(fam-edge): SQLite 改每线程一条连接,修好 DiskGuard 等一切并发写
OracleDB 原来在 __init__ 里建一条 check_same_thread=False 的连接给全进程共用,
而 VideoQueue / PersonService / DiskGuard 三个后台线程 + gunicorn 的请求线程都在
并发读写它。sqlite3 的连接对象本来就不是可并发共享的,事务状态互相踩踏,线上
累计刷出三类错误(同一个根因):

  database is locked                            71604 次
  cannot start a transaction within a transaction  378 次
  no more rows available                           92 次(堆栈落在 commit())

最严重的后果是磁盘守护形同虚设:DiskGuard 的清理被打断 2837 次,成功仅 128 次,
剩余空间在 2.7GB 和 16GB 之间来回荡——赶上 rclone 集中下载(实测 5 分钟写入
12.6GB)就掉进危险区。NAS 推来的运动事件被 500 打回也是它(失败批次不推进游标,
下一轮补推,所以没丢事件)。

改法:_conn 改成 @property,从 threading.local() 取当前线程的连接,没有就新建
(WAL + busy_timeout=10000)。做成 property 是因为外部调用方(api_gateway 的
activity 端点)也在直接用 db._conn.execute(...),这样全部现有调用点原样工作。
close() 相应改成收掉所有线程开过的连接。_write_lock 保留,复合写语义不变。

测试:新增 8 线程 × 25 轮并发读写、close 收连接两个用例;在旧代码上稳定复现
同族错误 cannot commit transaction - SQL statements in progress。

线上验证:重启后 DiskGuard 立刻跑通一轮(清 40 个文件,剩余回到 15.3GB),
三类 SQLite 错误在重启后的日志里均为 0。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 09:34:24 +08:00
ericwyuan
1964e976f4 refactor: 全量迁云——fam-core 直读甲骨文 SQLite,NAS 只剩推送进程
前一天刚把登录迁到甲骨文,隔天 NAS 上的 fam-core 又挂了导致数据接口 502。
盘点后确认:甲骨文的 SQLite 才是权威数据源(videos 3113 / events 16159 /
people 60 / model_calls 9876),NAS 的 MariaDB 全是它的镜像——前端读的数据
本来就产自甲骨文,绕了一圈回家又绕回来。

改动:
- db_layer.py 从 725 行重写成 377 行:MySQL 镜像查询改为直读 fam-edge 的
  SQLite。5 个 upsert_sync_*(约 300 行去重逻辑,8/29 和 9/3 两次 1062 事故的
  发源地)连同 oracle_sync.py 整个删除。SQL 方言:JSON_CONTAINS -> json_each
  (前置 json_valid,历史脏数据不会把查询搞崩)、LEFT() -> substr()、%s -> ?。
  函数名 get_sync_* 一并改掉——已经没有 sync 这回事了
- 新增 edge_client.py:写操作(改名/删除)、帧图头像、服务状态都打给同机
  fam-edge,全走 127.0.0.1
- 新增 fam-notifier/:motion_notifier 从 fam-core 拆出独立成服务,游标从
  MariaDB 换成本地 JSON 文件。NAS 上从此没有 Flask、没有数据库、没有监听端口
- fam-core 移到甲骨文 /opt/fam-core(systemd,gunicorn -w 2,只绑
  127.0.0.1:5401——5400 被 chat-relay 占了)。Caddy 的 /api/* 从"frp 隧道
  回源 NAS"改成同机反代,forward_auth 闸门不变
- 前端删掉侧边栏同步面板、统计页同步状态、服务状态页的"NAS 同步"卡片与
  "立即同步"按钮(背后的镜像层已不存在);换成"NAS 运动推送"卡片,读
  fam-edge activity 新增的 motion 段(心跳年龄 + 最近事件)
- 顺带修掉一个隐蔽 bug:镜像表为保外键稳定用的是 NAS 本地自增 id,而帧图接口
  要的是甲骨文的 id,两边在 9/3 那次 id 重排后就对不上了。现在只有一套 id

测试:fam-core 21(新增 12 个 db_layer 用例:脏 JSON 不崩、人物精确匹配不误伤
"人物B"、日期过滤、统计口径、chat_history 懒建表)、fam-notifier 6、
fam-edge 157,全绿。

生产验证:甲骨文 /api/ui/stats 返回 videos 2965 / events 16159 / people 59;
NAS 侧 fam-notifier 已推送成功(事件 33070-33072 落库,心跳新鲜);
chat_history 19 条经 scripts/import_chat_history.py 迁移完成。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 08:03:32 +08:00
ericwyuan
2ad0472578 fix(fam-ui): 未登录自动跳转 OIDC + 登录/退出入口,打通 smart-camera 登录 2026-09-01 12:23:48 +08:00
ericwyuan
db4f46140b fix(start_core): export AUTH_HUB_* env + fix .env path; docs: cutover to smart-camera.zichuan.xyz 2026-09-01 12:14:51 +08:00
ericwyuan
5e1230d9b0 docs: 记录 auth-hub 生产 client 已注册,NAS 部署待执行
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 21:33:16 +08:00
ericwyuan
8120d2ae6a feat(fam-core): 登录改接 auth-hub 统一登录(OAuth2 Authorization Code + PKCE / OIDC)
移除本地 FAM_AUTH_USER/PASS 账号密码校验和内置登录表单,/login 改为 302
跳转 auth-hub /authorize,新增 /api/auth/callback 完成 code 换 token +
id_token 签名验证(PyJWT + JWKS),验证通过后种回原有 fam_session cookie,
is_authed()/全局登录拦截逻辑不变。接入参数走环境变量,未配置齐全 fail
closed。本地起 auth-hub 开发实例 + 真实浏览器验证过完整登录/登出闭环。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 21:32:26 +08:00
ericwyuan
c9354ed1a1 docs: 同步 8/28 迁移故障排查记录(FFmpeg 缺失 + 磁盘写满死循环 + DiskGuard)
README.md 新增 Disk-Guard 模块表条目、修正一处遗漏的机器规格描述
(2C12G -> 4C23G)、当前进度补充这次完整排查记录;PROGRESS.md 服务运行
状态表更新 + 新增详细的故障排查时间线记录。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 12:10:14 +08:00
ericwyuan
7948f55b02 docs: 同步 8/25 迁移(前端迁云 Caddy:80、Oracle 换新机 129.146.26.249、旧 IP 清理、Drive 中转设计说明) 2026-08-25 23:55:57 +08:00
ericwyuan
3cb08c9749 docs: 同步事件时间轴删除视频功能到 README/PROGRESS
补充 §5.1/§5.2 新增的 POST /api/oracle/video/delete + DELETE /api/ui/videos/<id>
端点说明、FAM-UI 页面表格、§12 当前进度;PROGRESS.md 记录完整变更 + 端到端
验证过程。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 04:28:55 +08:00
ericwyuan
2e370ab668 docs: 同步问答链路抽离到 ai-gateway 后的架构文档
README.md/PROGRESS.md 里大量描述还停留在"FAM-Edge 自己维护 Gemini→NVIDIA→
Ollama 问答降级链"的旧架构,跟实际代码(FAM-Edge 已改为转发客户端,模型链
整个搬到独立的 ai-gateway 服务)不一致,逐处订正:

- 新增 §3.4 AI-Gateway 模块章节、部署拓扑图、Gitea 仓库表新增 ai-gateway 条目
- 模块表(FAM-Core/FAM-Edge)、API 文档、数据库 compute_provider 说明更新
- §6.2/6.3 本地 Ollama 与模型适配器章节:去掉已删除的 OllamaAdapter/role=text,
  问答降级链路图重画为"FAM-Edge 转发 -> AI-Gateway 内部降级"
- 修复已经损坏(合并冲突残留)且过时的 fam-edge/config.yaml 示例,新增
  ai-gateway/config.yaml 示例;如实记录两份 .env 各自独立维护的实际部署状态
- PROGRESS.md 补一条 2026-08-23 变更记录 + 服务运行状态表新增 AI-Gateway 行

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 17:40:55 +08:00
ericwyuan
354ff18101 [文档] 代码-文档一致性整理 - README 同步 v3 全量(2.1网络/3模块表/4表结构/5 API含people-clips/6.1历史标注/8部署systemd+Vue3+config/12进度); docs/DEPLOY.md 重写为 v3; 删除过时 start_ui.sh(Streamlit); start_edge.sh 注明 systemd 为准; 补提交 test_motion_notifier 2026-08-22 13:14:38 +08:00
ericwyuan
ffcc292cce [文档] 同步 v3 运动事件驱动架构 - 整段素材分割运动片段再分析(不再整段送云端): README 1.1/2.2/2.2.1/2.3/模块表, PROGRESS 运行状态+变更记录; 记录 systemd 守护部署方式 2026-08-22 12:46:33 +08:00
ericwyuan
b2b537dde5 [文档] 同步 v3 运动监测架构(Webhook 驱动/去轮询) - README 补充 2.2.1 链路/API 表/模块表,PROGRESS 更新运行状态与变更记录 51-53 2026-08-22 11:11:15 +08:00
ericwyuan
47c42f24df docs: update PROGRESS.md - 人物统计去重与导航改进 2026-08-21 00:22:41 +08:00
ericwyuan
5d574029b0 docs: update PROGRESS.md - Gemini 降级排查修复 2026-08-21 00:07:56 +08:00
ericwyuan
7efbee89fb docs: update PROGRESS.md - 事件列表带年月日 2026-08-20 23:50:48 +08:00
ericwyuan
6ecdffce04 docs: update PROGRESS.md - 压缩缓存回退补齐全部历史事件帧图 2026-08-20 22:42:31 +08:00
ericwyuan
3a3b68c428 docs: update PROGRESS.md - 历史事件关键帧补抽 2026-08-20 22:07:57 +08:00
ericwyuan
634ff746a9 docs: update PROGRESS.md - UI时间轴重构 + 关键帧持久化 + multipart超时修复 2026-08-20 20:44:52 +08:00
ericwyuan
963b6d7540 docs: update PROGRESS.md - 队列表schema迁移修复时区残留 + -f mp4修复 2026-08-20 18:51:51 +08:00
ericwyuan
4e16330e87 docs: update PROGRESS.md - 压缩缓存原子性修复 2026-08-20 18:11:43 +08:00
ericwyuan
47cee9db4f docs: update PROGRESS.md - 视频时间语义修正 2026-08-20 17:58:50 +08:00
ericwyuan
3817609d1b docs: update PROGRESS.md - 时区统一北京时区修复 2026-08-20 17:42:35 +08:00
ericwyuan
4553ec6f07 docs: update PROGRESS.md - NVIDIA原生视频输入切换调研与实现 2026-08-20 17:22:08 +08:00
ericwyuan
8a62c46194 docs: update PROGRESS.md - Gemini视觉解析排查结论+业务全流程图 2026-08-20 16:15:28 +08:00
ericwyuan
a2554c9df0 docs: update PROGRESS.md - 视频上传问题根因(网络+逻辑双叠加)与四项修复 2026-08-20 15:36:35 +08:00
ericwyuan
a9a1b1dda5 docs: update PROGRESS.md - 串行上传+5MB分块+看门狗+chunk_size防护 2026-08-20 14:20:00 +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
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
2e43afb6b2 docs(README/PROGRESS): 文档收尾,与架构重构代码对齐
1. README 8.3 节:fam-core 配置示例更新(video_dir 生产路径 + chat_handler.qa_url),fam-edge 配置示例对齐新架构(role/usage=qa_fallback、gemini-flash-latest、实际 timeout)
2. README 1.3 节:历史视频积压标记已处理(forward-only);吞吐不足表述更新(无本地融合)
3. README 5.3 节:改名为云端结构化输出 JSON Schema,描述适配器解析 + format_cloud_result 校验两阶段
4. README 6.2 节:移除融合 timeout 行,num_predict 更新为 512,已知问题改述为专职问答兜底
5. README 10.5/10.6 节:Gemini 模型名修正为 gemini-flash-latest;NVIDIA 验证状态更新为已验证
6. README 12 节:架构重构与双端部署验证纳入已完成;v1.1 待办移除已完成项 1-5,保留单元测试/Tailscale/daily_summaries
7. PROGRESS.md:服务状态表更新(新架构、qwen2.5:7b);任务进度追加 32-38;技术决策记录追加云端直出直存与 Q&A 降级;聊天链路验证段更新为 run_qa 编排
2026-08-20 10:45:29 +08:00
ericwyuan
5adda97829 docs: add real video benchmark results to PROGRESS.md
- 30min 360MB video pipeline: 70s transfer + 39s keyframe + 820s AI = 929s total
- FFmpeg fast seek optimization: 180s+ → 33s (6-8x faster)
- AI analysis is the bottleneck: avg 68s/frame, 0.9 tokens/s on ARM CPU
2026-08-20 02:31:06 +08:00
ericwyuan
727642d38b feat: adaptive keyframe count based on video duration
- Replace fixed 5-8 keyframe limit with duration-based adaptive sizing
- Candidate frames: clamp(duration_min × 2, 30, 120)
- Keyframe cap: clamp(duration / 150s, 8, 30)
- 30min video → 12 keyframes (was 8), 60min → 24, 120min → 30
- Short videos (<12min) still get floor of 8 keyframes
- Add Ollama keep-alive config doc to PROGRESS.md (OLLAMA_KEEP_ALIVE=-1)
- Update config.yaml and config.yaml.example with new video params
2026-08-20 01:29:14 +08:00
ericwyuan
c596bf7603 feat: FAM-UI deployed on NAS (Streamlit 1.61.1)
- Streamlit 1.61.1 + pandas 2.3.3 installed in fam-ui venv (Python 3.10)
- FAM-UI running headless on 0.0.0.0:8501, HTTP 200, health=ok
- config.yaml synced to NAS (core_url + MariaDB unix_socket)
- All 5 services now running: FAM-Core, FAM-Edge, FAM-UI, MariaDB, Ollama
- PROGRESS.md: task 27 complete
2026-08-20 00:36:37 +08:00
ericwyuan
06e1e5a307 docs: update PROGRESS.md with chat proxy, Tailscale status, E2E results 2026-08-20 00:03:57 +08:00
ericwyuan
c8cd2f2665 fix: MariaDB JSON path compat for name_member + FAM-Core API verified
- name_member(): replace MySQL-only JSON_REPLACE/JSON_CONTAINS with wildcard
  JSON paths (unsupported in MariaDB 10.11) with Python-side JSON parsing
- FAM-Core venv rebuilt with Python 3.10.20 on NAS
- All API endpoints tested: health, status, member list, unnamed, naming
- POST /api/member/name: 人物A successfully named to 张三
- PROGRESS.md updated with full test results and task completion
2026-08-19 23:48:35 +08:00
ericwyuan
66b499725d [deploy] FAM-Core + FAM-Edge 服务启动 + Tailscale 跨服务器验证
- FAM-Core (NAS:8000): gunicorn 启动成功, scheduler+dispatcher 运行中
- FAM-Edge (Oracle:5000): gunicorn 启动成功, ollama 健康检查通过
- Tailscale 跨服务器连通: Oracle→NAS FAM-Core health=ok
- config.yaml 同步到 Oracle, FAM-Edge /health 返回 healthy_models=[ollama]
- PROGRESS.md 更新服务运行状态表
2026-08-19 23:32:35 +08:00
ericwyuan
47658fa068 [deploy] PyMySQL 替换 + Tailscale 组网 + config.yaml + 路径修复
- db_layer.py: mysql-connector-python(19MB) → PyMySQL(45KB), 去掉连接池
- config_loader.py: 修复路径解析 (2级→3级 dirname), FAM-Core + FAM-Edge 均修复
- Tailscale 组网完成: Oracle=100.74.137.126, NAS=100.70.234.39, 互通验证通过
- NAS Python 依赖: flask/gunicorn/pymysql/PyYAML 全部安装成功
- NAS 代码部署: /volume1/web/sentinel-home-ai/, FAM-Core 7 模块导入 PASS
- NAS DB 连接验证: PyMySQL → MariaDB 10.11.11, 6 张表可见, PASS
- config.yaml 创建: FAM-Core + FAM-Edge + FAM-UI (Tailscale IP + 密码)
- requirements.txt: mysql-connector-python → PyMySQL
2026-08-19 23:27:28 +08:00
ericwyuan
e5ac667586 [deploy] NAS MariaDB DDL 执行 + Tailscale 状态 + README 更新
- NAS MariaDB 10.11.11 确认可用, root 密码 iLoveJava5!
- DDL 执行成功: sentinel_home_ai 库 + 6 张表 (process_tasks, monitor_events, daily_summaries, event_details, chat_history, family_members)
- NAS Tailscale 已运行, IP: 100.70.234.39
- Oracle Tailscale 1.102.2 已安装, 待用户认证
- README 新增 MariaDB 密码 + Tailscale IP + NAS 型号信息
- PROGRESS.md 更新全部环境状态
2026-08-19 23:08:21 +08:00
ericwyuan
50d83539f6 [deploy] Oracle 环境部署 + 模型基准测试 + OllamaAdapter 优化
- Oracle 依赖安装: flask/gunicorn/requests/PyYAML/opencv/numpy 全部成功
- FAM-Edge 全部 8 个模块导入验证 PASS
- llava-phi3 基准测试: 冷启动 109s, 预热无限制 13.35s, 预热+num_predict=30 仅 4.34s PASS
- OllamaAdapter 新增 num_predict 可配置参数 (默认 500)
- config.yaml.example 新增 num_predict 配置项
- 创建 PROGRESS.md 进度追踪文档
2026-08-19 23:01:21 +08:00