Files
sentinel-home-ai/README.md
ericwyuan 3a5ea459a2 docs: 需求文档与 README 整合为单一文档
- 按当前代码实际状态重写:推送模式架构、自适应关键帧、实际 API 端点
- 补充实测性能基准(30min视频929s)、E2E 验证结果、可靠性加固机制
- 记录已知遗留问题(多图失效/吞吐不足)与 v1.1 计划
- 项目需求文档.md 内容并入后删除
2026-08-20 07:19:55 +08:00

488 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sentinel Home AI — 家庭多模态智能监控系统
> 多模型并行 + 交互式命名 + AI 对话的家庭监控系统。
> 本文档为项目需求文档与 README 的整合版按当前代码实际状态v1.0 E2E 已打通)编写。
> 最后更新2026-08-20
---
## 1. 项目简介与设计目标
系统持续分析家庭监控摄像头Synology Surveillance Station录制的视频抽取关键帧后调用视觉语言模型VLM分析画面中的人物、动作、衣着落库为结构化事件用户通过 Web UI 浏览事件、给"人物A/B/C"命名(批量回溯历史记录)、以及用自然语言向 AI 询问"汤圆今天干嘛了"。
### 1.1 首期范围(已基本完成)
- **FAM-Core**NAS 端单进程Task-Scheduler / Dispatcher / Event-Receiver / Chat-Handler / Member-Manager / Video-Server 六个子模块
- **FAM-Edge**Oracle 端单进程):接收视频上传 → FFmpeg 快速抽帧 → OpenCV 关键帧筛选 → VLM 视觉分析 → VLM 文本融合 → 结果同步返回 全链路
- **FAM-UI**NAS 端Streamlit 直读 DB事件列表 + 成员命名页 + AI 对话页 + 对话历史
- **数据库六张表**process_tasks / monitor_events / event_details / chat_history / family_members / daily_summaries预留
- **任务状态机**PENDING → PROCESSING → SUCCESS/FAILED含退避重试与僵尸任务回收
- **AI 对话**:查 event_details 拼上下文 → 经 FAM-Edge 代理调 Oracle Ollama 纯文本 → 返回回答并写 chat_history
- **交互式成员命名**VLM 按特征提取"人物A/B/C"落库,用户命名后批量回溯更新历史,后续分析直接用真名
### 1.2 不在首期范围(推迟 v1.1+
- Nginx 静态服务Video-Server 用 Flask `send_from_directory` 替代,且推送模式下已不再必需)
- 资源保护策略 BCPU/内存过载返回 503
- 心跳监控(用整体超时 + 僵尸任务回收兜底)
- API 业务接口鉴权(`/api/edge/*``/api/core/*` 不加鉴权)
- Cron 兜底清理(`finally` 清理足够)
- daily_summaries 每日摘要(表已建,逻辑未实现)
### 1.3 已知遗留问题v1.1 优先解决)
| 问题 | 现状 | 影响 |
|------|------|------|
| **llava-phi3 多图单请求失效** | `analyze_frames` 把全部关键帧放一次请求,输出长度仅 3~4垃圾内容融合阶段只能靠 known_members 上下文幻觉编造 | 事件内容质量差 |
| **吞吐不足** | 30s 视频全流程约 19 分钟(关键帧筛选 10min + VLM 5.5min + 融合 3min30min/360MB 视频实测 929s | 生产视频每 30 分钟新增一个,处理速度勉强跟上但无余量 |
| **Tailscale 端口不通** | NAS tailscaled 以 userspace 模式运行(无 TUN 网卡Oracle 无法反向访问 NAS当前 NAS→Oracle 走公网 IP | 推送模式已规避反向访问,但流量走公网 |
| **历史视频积压** | 正式目录 `/volume1/surveillance/Generic_ONVIF-001` 有约 285 个历史视频(~100GB288 个历史任务已标记 FAILED 避免全量上传 | 切回生产目录前需确认回补策略 |
**规划方向**:接入 Gemini`gemini-flash-latest`API Key 已验证可用,单帧 2~3s 且真正理解多图)作为主视觉分析模型,替换/补充 Ollama同步把 `analyze_frames` 改为逐帧请求。
---
## 2. 系统架构
### 2.1 物理节点与部署
| 节点 | 角色 | 硬件 | IP | 服务与端口 |
|------|------|------|-----|-----------|
| Synology NAS | FAM-Core + FAM-UI + 数据库 | DS220+ (Geminilake), DSM 7 | 家庭局域网 192.168.50.64 / Tailscale 100.70.234.39 | FAM-Core :8000, FAM-UI :8501, MariaDB :3306, Surveillance Station |
| Oracle Cloud | FAM-Edge | Ampere A1 2C12G ARM64无 GPU, Ubuntu 20.04 | 公网 129.146.203.203 / Tailscale 100.74.137.126 | FAM-Edge :5000, Ollama :11434仅本地 |
| 家庭网络 | 用户入口 | 普通终端 | 192.168.50.0/24 | 浏览器访问 `http://192.168.50.64:8501` |
**网络要点(推送模式)**
- 服务间通信只有一条:**NAS → Oracle 公网 IP:5000**HTTP 上传视频。Edge 不需要反向访问 NAS无 webhook、无视频拉取
- Oracle 端 Ollama 端口 11434 不对外暴露,聊天请求经 FAM-Edge `/api/edge/chat` 代理转发
- Tailscale 两节点已安装在线,但 NAS tailscaled 为 userspace 模式且防火墙端口不通,暂走公网 IP
### 2.2 部署拓扑与数据流(推送模式)
```
┌─────────────────────────────── NAS (192.168.50.64) ──────────────────────────────┐
│ │
│ Surveillance Station ──► /volume1/surveillance/Generic_ONVIF-001/ │
YYYYMMDDAM / YYYYMMDDPM 两级目录,~30min/350MB
│ │ │
│ ▼ │
│ FAM-Core (Flask :8000, gunicorn) │
│ ├─ Task-Scheduler: 60s 轮询视频目录,稳定文件建 PENDING 任务 │
│ ├─ Dispatcher: 30s 轮询multipart 上传视频 ──────────┐ │
│ │ (push_timeout=1800s同步等待响应) │ │
│ ├─ 僵尸回收: PROCESSING 超 push_timeout+120s 重置 PENDING │
│ ├─ Event-Receiver: /api/core/callback/event兼容保留
│ ├─ Chat-Handler ── /api/edge/chat 代理 ──────────────┐ │
│ ├─ Member-Manager / Video-Server(/media, token) │ │
│ ▼ │ │
│ MariaDB (sentinel_home_ai, 6 张表) │ │
│ │ │
│ FAM-UI (Streamlit :8501) 直读 DB │ │
└─────────────────────────────────────────────────────────┼─────────────────────────┘
│ HTTP (公网)
┌──────────────────────── Oracle Cloud (129.146.203.203) ──────────────────────────┐
│ FAM-Edge (Flask :5000, gunicorn --timeout 1800, 单 worker) │
│ ├─ POST /api/edge/video/pushmultipart 视频,同步分析,结果随响应返回) │
│ ├─ AI-Orchestrator: 健康检查 → 抽帧 → 选帧 → 压缩 → VLM 视觉 → 文本融合 │
│ ├─ POST /api/edge/chat代理转发本地 Ollama
│ ▼ │
│ Ollama :11434 (llava-phi3, OLLAMA_KEEP_ALIVE=-1 常驻) + FFmpeg + OpenCV │
└───────────────────────────────────────────────────────────────────────────────────┘
```
### 2.3 主链路时序(推送模式)
1. Scheduler 扫描到新视频(修改时间 > 60s 且大小稳定)→ 写 `process_tasks`PENDING
2. Dispatcher 领取 PENDING 任务 → 状态置 PROCESSING → 读本地视频文件multipart POST 到 Edge `/api/edge/video/push`payload 含 task_id / camera_name / event_start_time文件 mtime/ known_members_context
3. Edge 同步执行:
- a. 保存上传视频到临时目录(超时 60s
- b. FFmpeg 快速 seek`-ss <ts> -frames:v 1`)粗抽候选帧,帧数随视频时长自适应
- c. OpenCV MSE 帧差分析筛选关键帧 → 压缩(长边 ≤ 1024pxJPEG 质量 80
- d. 健康的模型适配器并行视觉分析Ollama 视觉超时 600sGemini 规划中)
- e. Ollama 纯文本融合(超时 300s→ JSON 结构化结果
- f. `event_end_time` = event_start_time + 视频时长Edge 推算)
- g. `finally` 清理临时文件
4. Edge 把结果 JSON 直接作为 HTTP 响应返回(无 webhook
5. Dispatcher 收到响应 → 调用 `apply_success_event()``monitor_events`1 条聚合)+ `event_details`(每关键帧 1 条)+ upsert 未命名成员 → 任务置 SUCCESS失败则退避重试`min(60×(retry+1)×2, 600)`s超 3 次 FAILED
**容错设计**
- Dispatcher 僵尸回收PROCESSING 状态超过 `push_timeout + 120s` 自动重置 PENDING应对进程重启/Edge 重启导致 in-flight 请求丢失)
- fam-core 日志双写stdout + `fam-core/logs/fam-core.log`daemon 模式下 stdout 不可见)
- 所有日志带 `task_id` 作为 trace_id各阶段耗时打 INFO
---
## 3. 模块设计
### 3.1 FAM-CoreNAS 端)
| 模块 | 文件 | 职责 |
|------|------|------|
| Task-Scheduler | `scheduler/scheduler.py` | 60s 轮询视频目录(`os.walk` 递归,支持 AM/PM 子目录),`video_path` 去重,稳定文件建 PENDING 任务 |
| Dispatcher | `dispatcher/dispatcher.py` | 30s 轮询 PENDINGmultipart 上传视频至 Edge push 端点;收响应后经 `apply_success_event` 落库;僵尸 PROCESSING 回收;退避重试 |
| Event-Receiver | `event_receiver/event_receiver.py` | `/api/core/callback/event`webhook 兼容保留);核心逻辑抽为 `apply_success_event(data)` 供 Dispatcher 推送模式复用;未命名 abstract_label 自动 upsert `family_members` |
| Chat-Handler | `chat_handler/chat_handler.py` | `/api/chat/ask` 查 event_details 拼上下文 → 经 Edge 代理调 Ollama → 写 chat_history明细 > 50 条按小时聚合 |
| Member-Manager | `member_manager/member_manager.py` | `/api/member/unnamed` / `/api/member/name` / `/api/member/list`;命名后批量回溯 UPDATE event_detailsMariaDB 不支持 `$[*]` JSON 路径Python 层逐行更新) |
| Video-Server | `video_server/video_server.py` | `/media/<path>?token=xxx` 静态视频服务(推送模式下主链路不再使用,保留备用) |
| 公共层 | `db_layer.py` / `config_loader.py` / `logger.py` | PyMySQL 连接unix_socketdatetime 空串归一化 NULL + NOT NULL 列兜底;文件日志 |
### 3.2 FAM-EdgeOracle 端)
| 模块 | 文件 | 职责 |
|------|------|------|
| API-Gateway | `api_gateway/api_gateway.py` | `POST /api/edge/video/push`multipart 上传 + 同步分析 + 结果返回);`POST /api/edge/video/analyze`(旧拉取模式,兼容保留);`POST /api/edge/chat`Ollama 代理);`GET /health`;单并发控制(处理中返回 429 |
| Video-Preprocessor | `video_preprocessor/preprocessor.py` | `save_upload` 保存上传视频FFmpeg 快速 seek 粗抽候选帧帧数自适应OpenCV MSE 帧差筛选关键帧(首末帧必选);压缩;`compute_timestamps` 用 start+偏移算绝对时间戳;`video_duration` 供 event_end_time 推算 |
| AI-Orchestrator | `ai_orchestrator/orchestrator.py` | 模型健康检查 → 健康适配器并行视觉分析 → 文本融合 → JSON 解析三层容错 + schema 校验;`process_push_task` 为推送模式入口(不触发 webhook |
| Model-Adapters | `model_adapters/` | `BaseModelAdapter` 抽象基类health_check / analyze_frames / get_timeout / 熔断器OllamaAdapter 已实现requests 直调 REST`num_predict` 可配GeminiAdapter 配置位预留 |
| Storage-Cleaner | `storage_cleaner/` | `finally` 删除临时视频与帧图片 |
### 3.3 FAM-UINAS 端)
Streamlit 应用(`fam-ui/src/app.py`),侧边栏切换页面:
| 页面 | 功能 |
|------|------|
| 📊 事件列表 | 按日期筛选 + 分页20 条/页)展示 monitor_events |
| 👤 成员命名 | 列出未命名人物 + 特征描述,输入真名后调 `/api/member/name` 批量回溯 |
| 💬 AI 对话 | 输入框 + 调 `/api/chat/ask`;按 queried_person 预设快捷提问 |
| 📜 对话历史 | chat_history 倒序展示 |
| 📈 统计图表 | compute_provider 占比bar_chart |
---
## 4. 数据库设计
库名 `sentinel_home_ai`MariaDB 10.11.11utf8mb4。完整 DDL 见 `scripts/ddl.sql`
### 4.1 表清单
| 表 | 用途 | 关键字段 |
|----|------|---------|
| `process_tasks` | 视频处理任务 | task_id, video_path, video_url, status(PENDING/PROCESSING/SUCCESS/FAILED), retry_count, max_retries, next_retry_at, error_message, failure_stage(ENUM) |
| `monitor_events` | 事件聚合(每任务 1 条) | event_id, task_id, event_start_time, event_end_time, camera_name, global_summary, entities_json(JSON), compute_provider(JSON 数组) |
| `event_details` | 每关键帧一条明细 | detail_id, event_id, task_id, frame_index, frame_timestamp, person, action, clothing, is_attention_event, source_providers(JSON) |
| `family_members` | 交互式命名 | member_id, abstract_label(如"人物A"), real_name(NULL=未命名), feature_description, first_seen_at, named_at, named_by |
| `chat_history` | AI 问答记录 | chat_id, user_question, ai_answer, context_summary, queried_date, queried_person |
| `daily_summaries` | 每日摘要(预留) | target_date, summary_text |
### 4.2 表关系与命名回溯
```
process_tasks (1) ─── (N) monitor_events (1) ─── (N) event_details
family_members 独立表:
- event_details.person 存 abstract_label未命名或 real_name命名后
- 命名后: UPDATE event_details SET person = real_name WHERE person = abstract_label
- monitor_events.entities_json 由 Python 层解析逐行更新MariaDB 不支持 $[*] 路径)
chat_history 独立表
```
### 4.3 compute_provider / source_providers
- `monitor_events.compute_provider`JSON 数组,记录本次任务实际成功调用的模型,如 `["ollama"]``["ollama","gemini"]`
- `event_details.source_providers`:该条明细被哪些模型识别到(可能少于 compute_provider
- 多模型交叉验证:多模型一致 → 可信度高;仅单一模型描述 → source_providers 仅含该模型;冲突 → 多数派为准
### 4.4 兼容性注意
- MariaDB 10.11 严格模式:**空字符串不能插 DATETIME 列**1292 错误)。`db_layer._dt_or_none` 将空串归一化 NULL`event_end_time` NOT NULL 列按 end→start→NOW 兜底;`frame_timestamp` 空值兜底 NOW
- MariaDB 不支持 MySQL 的 `$[*]` JSON 通配路径与 `->` 操作符JSON 字段在 Python 层处理
---
## 5. API 规范(实际实现)
### 5.1 FAM-EdgeOracle :5000
**POST /api/edge/video/push**(主链路,推送模式)
- 请求:`multipart/form-data`,字段 `video`(文件) / `task_id` / `camera_name` / `event_start_time` / `known_members_context`
- 处理同步执行完整分析流水线可能耗时数分钟gunicorn timeout 1800
- 响应200
```json
{
"task_id": 289,
"status": "success",
"event_start_time": "2026-08-20 01:06:44",
"event_end_time": "2026-08-20 01:07:13",
"camera_name": "客厅",
"global_summary": "...",
"entities_json": [{"person": "汤圆", "action": "...", "clothing": "..."}],
"frame_details": [
{"frame_index": 1, "frame_timestamp": "...", "person": "...", "action": "...",
"clothing": "...", "is_attention_event": false, "source_providers": ["ollama"]}
],
"compute_provider": ["ollama"]
}
```
- 失败:`{"task_id": ..., "status": "failed", "failure_stage": "vlm_visual", "error_message": "..."}`
- 429已有任务处理中单并发503全部模型不健康
**POST /api/edge/video/analyze** — 旧拉取模式Edge 拉 video_url + webhook 回调),兼容保留,主链路不再使用
**POST /api/edge/chat** — Ollama 聊天代理FAM-Core Chat-Handler 调用)
**GET /health** — 服务与模型健康状态(任务处理中可能无响应,单 worker 忙)
### 5.2 FAM-CoreNAS :8000
| 端点 | 方法 | 说明 |
|------|------|------|
| `/health` | GET | 服务健康 |
| `/api/status` | GET | scheduler/dispatcher 运行状态 |
| `/api/core/callback/event` | POST | Edge 回调webhook 兼容保留);推送模式下由 Dispatcher 内部调用 `apply_success_event` |
| `/api/chat/ask` | POST | 用户问答:`{"question","queried_person","queried_date"}``{"answer","context_summary","chat_id"}` |
| `/api/chat/history` | GET | 对话历史(`?date=``?person=&limit=` |
| `/api/member/unnamed` | GET | 未命名人物列表(含特征描述、出现次数) |
| `/api/member/name` | POST | 命名:`{"abstract_label","real_name","named_by"}` → 批量回溯 event_details/entities_json返回更新条数 |
| `/api/member/list` | GET | 全部成员 |
| `/media/<path>?token=xxx` | GET | 视频静态服务token 鉴权,推送模式下备用) |
### 5.3 融合输出 JSON Schema
三层容错解析:直接 `json.loads` → 提取 markdown fence ` ```json ... ``` ` → 贪婪匹配最大 `{...}`;再过 `validate_schema`(必填字段检查 + 脏数据清洗,`action` 由 AI 自由生成无枚举过滤,`is_attention_event` 由 AI 自行判断,`source_providers` 必须非空数组)。三层全失败 → 任务 FAILED 走重试。
---
## 6. 关键技术
### 6.1 视频预处理(自适应关键帧)
- **粗抽候选帧**FFmpeg 快速 seek逐帧 `ffmpeg -ss <ts> -frames:v 1`),替代 fps 滤镜全解码30min 视频从 180s+ 降到 33s6-8x 提速)
- **帧数自适应**:候选帧 `clamp(时长分钟×2, 30, 120)`;关键帧上限 `clamp(时长/150s, 8, 30)`30min→12 帧60min→24 帧,封顶 30
- **帧差筛选**OpenCV MSE首末帧必选MSE > 阈值 500 的保留,不足 min_key_frames=5 补足
- **压缩**:长边 > 1024px 才缩放JPEG 质量 80
- **异常兜底**ffprobe 失败退化为 60s 间隔抽帧;帧差异常退化为等距 5 帧
### 6.2 Ollama 调用ARM CPU 实测调优)
| 参数 | 值 | 依据 |
|------|-----|------|
| `OLLAMA_KEEP_ALIVE=-1` | 模型常驻内存 | 消除 55s 冷启动(常驻约 4.3GB12GB 内存够用) |
| `num_predict=60` | 限制生成 token | ARM 约 5 tok/s500 会单帧跑数分钟触发超时 |
| 视觉/模型 timeout | 600s | 实测 1024px 帧视觉编码 ~36s + 生成 ~12s/60token |
| 融合 timeout | 300s | — |
| gunicornEdge | `--timeout 1800` | 同步分析模式,默认 30s 会杀 worker |
| push_timeoutNAS | 1800s | 覆盖最坏情况30min 视频实测 929s |
**已知问题**llava-phi3 多图单请求基本失效N 张图一次调用输出长度仅 3~4。待改为逐帧请求或由 Gemini 承担主视觉分析。
### 6.3 模型适配器架构
- 抽象基类 `BaseModelAdapter``health_check()` / `analyze_frames()` / `get_timeout()` / 熔断器实例
- 模型清单由 `config.yaml``models` 数组动态决定,新增模型 = 实现适配器 + 配置加一项,主流程不动
- 每个云端模型独立熔断器(连续 5 次失败 → OPEN 15 分钟 → HALF_OPEN 探测);本地 Ollama 不启用熔断
- 健康探测Ollama `GET /api/tags`Gemini `GET /v1/models?key=...`;全部不健康返回 503
### 6.4 任务可靠性
- 状态机 PENDING → PROCESSING → SUCCESS/FAILED退避重试 `min(60×(retry+1)×2, 600)`smax_retries=3
- **僵尸任务回收**PROCESSING 超过 `push_timeout + 120s` 自动重置 PENDING应对 fam-core 重启 / Edge 重启 / in-flight 请求丢失)
- `failure_stage` ENUMdownload / extract / vlm_visual / vlm_fusion / callback
---
## 7. 性能基准(实测)
### 7.1 单图推理llava-phi3, Oracle ARM 2C12G
| 场景 | 总耗时 |
|------|--------|
| 冷启动(首次加载 2.9GB 模型) | 109s已由 keep-alive 消除) |
| 预热 + num_predict=30 | **4.3s** |
| 1024px 真实帧 + num_predict=60 | ~48.6s(视觉编码 36s 固定成本 + ~5 tok/s |
### 7.2 真实视频全流程30min / 360MB / 1080p H.264
| 步骤 | 耗时 |
|------|------|
| 视频上传 NAS→Oracle公网5.1 MB/s | 70s |
| FFmpeg 快速 seek 抽 60 候选帧 | 33s |
| OpenCV 关键帧筛选→12 帧) | 5s |
| 压缩 | 0.6s |
| Ollama 视觉分析12 帧) | 820savg 68s/帧0.9 tok/s |
| **总计** | **929s15.5min** |
### 7.3 E2E 验证2026-08-20
task_id=28930s 测试片段)全链路打通:推送 5.7MB → Edge 分析 1129s → 同步返回 → `monitor_events` event_id=1 + `event_details` 2 条落库,`event_end_time` 推算正确start+29s
---
## 8. 部署说明
### 8.1 部署位置与启动命令
| 组件 | 节点 | 路径 | 启动 |
|------|------|------|------|
| FAM-Core | NAS | `/volume1/web/sentinel-home-ai/fam-core/` | `./venv/bin/gunicorn --chdir <路径> -w 1 -b 0.0.0.0:8000 --timeout 120 --daemon --pid /tmp/fam-core-gunicorn.pid src.fam_core.app:app` |
| FAM-UI | NAS | `/volume1/web/sentinel-home-ai/fam-ui/` | `./venv/bin/streamlit run src/app.py`headless, :8501 |
| FAM-Edge | Oracle | `/opt/fam-edge/` | `venv/bin/gunicorn -w 1 -b 0.0.0.0:5000 --timeout 1800 src.fam_edge.app:app`(日志 `/tmp/fam-edge.log` |
| Ollama | Oracle | systemd 托管 | 环境变量 `OLLAMA_KEEP_ALIVE=-1` |
### 8.2 依赖
- **FAM-Core/UINAS, Python 3.10 venv**Flask, Gunicorn, **PyMySQL**45KB 纯 Python 替代 19MB mysql-connector, PyYAML, requestsFAM-UI 另需 Streamlit + pandas
- **FAM-EdgeOracle, Python 3.8+ venv**Flask, Gunicorn, requests, PyYAML, opencv-python, numpyGemini 用 requests 直调 REST不依赖 google-generativeai SDK
- **系统级**FFmpeg两端、Ollama + llava-phi3Oracle、MariaDB 10.11NAS
### 8.3 配置文件要点
**fam-core/config/config.yaml**NAS
```yaml
scheduler:
video_dir: "/volume1/web/sentinel-home-ai/e2e-test" # 当前指向 E2E 测试目录
# 正式目录: /volume1/surveillance/Generic_ONVIF-001YYYYMMDDAM/PM 两级子目录,
# os.walk 递归支持;切回前需处理 285 个历史视频积压,避免全量上传 ~100GB
dispatcher:
edge_url: "http://129.146.203.203:5000/api/edge/video/push"
push_timeout: 1800
chat_handler:
ollama_url: "http://129.146.203.203:5000/api/edge/chat" # 经 Edge 代理
```
**fam-edge/config/config.yaml**Oracle关键节选见 6.2`models` 数组含 ollamaenabled: true, num_predict: 60与 geminienabled: false, 待接入)。
### 8.4 运维注意事项
- NAS 部署目录**不是 git 仓库**(文件拷贝部署),同步代码用 stdin 管道:`ssh ... "cat > 远端路径" < 本地文件`
- NAS scp 子系统被禁用,同样用 stdin 管道传文件
- 远端 kill gunicorn 时 pkill/pgrep 会匹配 SSH 自身命令行导致断连,用 `pgrep -f 'gunicorn -w [1]'` 字符类技巧或 PID 文件
- fam-core 启动模块路径是 `src.fam_core.app:app`(不是 `fam_core.app:app`
- Edge 单 worker 处理任务期间 `/health` 可能不响应,属正常
---
## 9. 快速开始
```bash
# 1. 初始化数据库NAS
python scripts/init_db.py
# 2. 启动 FAM-CoreNAS
cd fam-core && gunicorn -w 1 -b 0.0.0.0:8000 --timeout 120 src.fam_core.app:app
# 3. 启动 FAM-EdgeOracle
cd fam-edge && gunicorn -w 1 -b 0.0.0.0:5000 --timeout 1800 src.fam_edge.app:app
# 4. 启动 FAM-UINAS
cd fam-ui && streamlit run src/app.py
# 或使用脚本
./scripts/start_core.sh && ./scripts/start_edge.sh && ./scripts/start_ui.sh
```
---
## 10. 服务器访问信息
### 10.1 Synology NASFAM-Core + FAM-UI + MariaDB
| 项目 | 值 |
|------|-----|
| IP | 192.168.50.64 |
| SSH 端口 | 2222scp 禁用,用 stdin 管道传文件) |
| SSH 用户 / 密码 | ericwyuan / iLoveJava5 |
| 系统 | Synology DS220+ (Geminilake), DSM 7 |
| Tailscale IP | 100.70.234.39userspace 模式,端口不通待修) |
| 登录命令 | `ssh -p 2222 ericwyuan@192.168.50.64` |
### 10.2 MariaDBNAS
| 项目 | 值 |
|------|-----|
| 版本 | MariaDB 10.11.11 |
| Socket | /run/mysqld/mysqld10.sock |
| Root 密码 | iLoveJava5! |
| 数据库名 | sentinel_home_ai |
| 连接 | `/usr/local/mariadb10/bin/mysql -S /run/mysqld/mysqld10.sock -u root -p`(非交互 PATH 下用 fam-core venv 的 PyMySQL + unix_socket 查询) |
### 10.3 Oracle CloudFAM-Edge + Ollama + FFmpeg
| 项目 | 值 |
|------|-----|
| 公网 IP | 129.146.203.203 |
| SSH 用户 | ubuntu密钥 `~/.ssh/oracle_sentinel` |
| 系统 | aarch64 (Ampere A1 2C12G), Ubuntu 20.04 LTS |
| Tailscale | 100.74.137.126(已安装在线,与 NAS 端口不通) |
| 登录命令 | `ssh -i ~/.ssh/oracle_sentinel ubuntu@129.146.203.203` |
### 10.4 Gitea 代码仓库
| 项目 | 值 |
|------|-----|
| URL | http://192.168.50.64:3000/ericwyuan/sentinel-home-ai |
| 账号 / 密码 | ericwyuan / iLoveJava5 |
### 10.5 Gemini APIGoogle AI Studio
| 项目 | 值 |
|------|-----|
| API Key | AQ.Ab8RN6I0l8hC7hLnNHRY6qOXdch5CTWczDNlS4c1XrneGHipUQ |
| 模型 | gemini-flash-latest |
| 端点 | https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent |
| 验证状态 | 2026-08-20 测试可用 |
```bash
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent" \
-H 'Content-Type: application/json' \
-H 'X-goog-api-key: AQ.Ab8RN6I0l8hC7hLnNHRY6qOXdch5CTWczDNlS4c1XrneGHipUQ' \
-X POST \
-d '{"contents":[{"parts":[{"text":"Explain how AI works in a few words"}]}]}'
```
---
## 11. 提交规范AI Agent 必读)
**工作流程(强制)**
1. **开工前**:仓库根目录 `git pull --rebase`
2. **每完成一项验收子任务**:立即 `git add` + `git commit` + `git push`,一任务一 commit不批量合并
3. **遇到阻塞**:先 commit 可工作部分message 加 `[WIP]` 前缀
4. **修 Bug**:单独 commit格式 `fix(模块): 问题简述`
**commit message 格式**
- 任务:`[阶段X.Y子任务号] 子任务名称 - 完成内容简述`
- Bug`fix(模块): 问题简述`
- 性能/文档:`perf(...)` / `docs(...)`
**禁止**:不 commit 直接继续;一次 commit 多个子任务;`git push --force`;跳过 hooks`--no-verify`)。
**自检清单**:任务对应哪一行验收标准?是否已 commit + pushmessage 是否合规?开工前是否 pull --rebase
---
## 12. 当前进度与 v1.1 计划
### 已完成(截至 2026-08-20
- 全部模块代码 + DDL + 部署脚本NAS/Oracle 双端部署运行
- 模型基准测试llava-phi3 预热 4.3s PASSOllama 常驻内存
- 架构改为推送模式NAS 上传整段视频 → Edge 同步分析 → 结果随响应返回)
- 关键帧自适应帧数 + FFmpeg 快速 seek6-8x 提速)
- FAM-Core API 全端点测试通过端到端聊天链路Core→Edge→Ollama验证
- FAM-UI 部署Streamlit 1.61.1
- 真实视频性能基准30min/360MB → 929s
- **E2E 全链路打通**task 289 → SUCCESSmonitor_events/event_details 落库正确
- 可靠性加固僵尸任务回收、文件日志、datetime 空值兜底、超时按实测调整
详细进度见 `PROGRESS.md`
### v1.1 待办
| # | 任务 | 优先级 |
|---|------|--------|
| 1 | 接入 Geminigemini-flash-latest作为视觉分析模型API Key 已验证) | 高 |
| 2 | analyze_frames 改逐帧请求(修复 llava-phi3 多图失效) | 高 |
| 3 | 切回生产视频目录(/volume1/surveillance/Generic_ONVIF-001确认历史视频回补策略 | 高 |
| 4 | 单元测试JSON parser / circuit breaker / schema 校验) | 中 |
| 5 | Tailscale 修复NAS userspace 模式升级,流量不走公网) | 低 |
| 6 | daily_summaries 每日摘要 | 低 |
---
文档结束