Files
sentinel-home-ai/fam-edge/config/config.yaml
ericwyuan 0d8e62607c feat(fam-edge): DSM 运动侦测预过滤 - 空转时段跳过云端视频分析
群晖 Surveillance Station 用 SYNO.SurveillanceStation.EventCenter.Event(未公开
文档的内部接口,参数是下划线风格 camera_ids/start_time/end_time,公开文档里的
cameraIds/fromTime/toTime 是旧版 Event API 的参数名,两者不通用)记录了摄像头
真实的运动侦测事件(event_type=10=运动,start_time+duration 精确到秒),比自己
本地跑 ffmpeg 帧差分更准、不需要额外算力,之前一直在这台 NAS 上验证可行性。

新增 DsmMotionClient:process_video() 分析每段视频前,先用视频的
[event_start, event_start+duration] 时间窗查一次这个接口,窗口内一条运动事件都
没有就跳过云端分析(标记 done,compute_provider=skipped_no_motion),省掉长期
无人时段白白消耗的 Gemini/NVIDIA 配额。

安全设计:查询本身失败/未配置/账号密码没填一律 fail-open(当作"有运动",照常
分析),不会因为这层可选优化漏检真实事件——这是一个纯粹的省配额优化,不能反过来
影响监控系统的可靠性。

新增 12 个单测覆盖:禁用/缺凭证时的 fail-open、登录失败、网络异常、无事件、有
事件、按 camera_id 过滤(响应是按 ds_id 分组不是按 camera_id,容易搞混)、
最短运动时长阈值、session 过期重登录重试、env 变量解析。

账号密码走 .env 的 DSM_ACCOUNT/DSM_PASSWORD,不明文入库。
2026-08-22 09:46:00 +08:00

140 lines
7.1 KiB
YAML
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.
# FAM-Edge 配置文件 (Oracle 端) - 新架构 v2
#
# 新架构2026-08-21 重构):
# 1. 不再切片/抽帧:整视频直传云端 VLMGemini 用 Files APINVIDIA 用整视频 video_url
# 2. 视频来源rclone 从 Google 硬盘实时同步到本地 local_dir监听目录处理新视频
# 3. Oracle 自建 SQLite 库存储所有视频摘要/事件/人物,并对外提供同步接口供 NAS 拉取
# 4. 独立 person_service 汇总全量人物 -> LLM 合并为规范人物表 -> 回灌视频提示
# 5. NAS 仅作管理后台,每 30 分钟从甲骨文拉增量镜像到本地 MariaDB
# Oracle 端 HTTP 服务
server:
host: "0.0.0.0"
port: 5000
# Google 硬盘同步rclone 负责同步落地,本段仅描述监听行为)
gdrive_sync:
enabled: true
local_dir: "/opt/fam-edge/gdrive_videos" # rclone 同步落地目录video_processing 监听此目录)
watch_interval_sec: 30 # 监听新视频的轮询间隔
camera_name: "客厅" # 摄像头名称(注入视频提示)
# 文件名解析开始时间:监控文件名含时间戳时使用(如 2026-08-21_081500.mp4
parse_start_from_filename: true
# Oracle 本地库(视频摘要/事件/人物)
oracle_db:
path: "/opt/fam-edge/data/oracle.db"
# NAS 拉取同步接口鉴权 token与 NAS oracle_sync.token 一致,走 .env不明文入库
sync_api:
token: "${ORACLE_SYNC_TOKEN}"
# 人物识别服务
person_service:
enabled: true
schedule_interval_sec: 1800 # 每 30 分钟重新汇总一次人物
model: "gemini" # 用哪个模型做人物合并vision 模型也支持纯文本)
# 视频处理
video_processing:
max_concurrent: 1 # 消费者线程数(串行处理,避免云端并发超额)
timeout: 900 # 兜底单视频分析超时
timeout_multiplier: 2 # 模型消费超时倍数:在 models[i].timeout 原值上 ×2大视频上传+分析耗时)
max_retries: 10 # 单视频失败最大重试次数(配额/过载等瞬时故障给足重试机会)
retry_interval_sec: 3600 # 失败重试最小间隔:距上次失败 ≥1h 才重新入队,等配额恢复
file_validate: true # 登记入队前用 ffprobe 校验文件可解码;失败标记 invalid 不入队
stable_window_sec: 60 # 文件 mtime 稳定窗口写入中rclone 同步未完成)的文件跳过本轮
# 降级顺序:先 gemini 整视频,失败再 nvidia 整视频;两者都失败 -> 标记 failed
vision_order: ["gemini", "nvidia"]
# DSM 运动侦测预过滤2026-08-22 新增):分析前先查一下群晖 Surveillance Station
# 自己记录的运动侦测事件SYNO.SurveillanceStation.EventCenter.Event未公开文档的
# 内部接口,参数名是下划线风格 camera_ids/start_time/end_time这段时间窗口一条
# 运动事件都没有就跳过云端分析(标记 donecompute_provider=skipped_no_motion
# 省掉长期无人时段白白消耗的 Gemini/NVIDIA 配额。
# 账号密码走 .envDSM_ACCOUNT/DSM_PASSWORD不明文入库查询失败/未配置一律
# fail-open照常送云端分析不会因为这层可选优化漏检真实事件。
dsm_motion_prefilter:
enabled: true
host: "192.168.50.64"
port: 5000
account: "${DSM_ACCOUNT}"
password: "${DSM_PASSWORD}"
camera_id: 2 # Surveillance Station 里 Generic_ONVIF-001 的 camera_id
min_motion_seconds: 0 # 窗口内运动事件总时长需 ≥ 此值才算"有运动"0=有事件就算)
timeout_sec: 10
# 智能问答降级链与视频分析独立Gemini -> NVIDIA -> 本地 Ollama
models:
- provider: "gemini"
role: "vision"
enabled: true
model_name: "gemini-flash-latest" # 主模型(每日免费配额 20 请求,按模型独立)
fallback_models:
- "gemini-flash-lite-latest"
api_key: "${GEMINI_API_KEY}"
# 多 Key 轮换(各自独立 Google Cloud 项目,配额互不影响):主 key 配额用尽时
# 依次尝试这些 key每个 key 都会重新走一遍模型 fallback 链。key 本身放 .env
# 这里只放环境变量名,不直接写密钥。
extra_api_keys:
- "${GEMINI_API_KEY_2}"
- "${GEMINI_API_KEY_3}"
- "${GEMINI_API_KEY_4}"
# 每个 key 对应的 Google Cloud 项目名(顺序对应上面 api_key + extra_api_keys
# 用于模型统计页展示是哪个项目在跑,不填则退回 "key1/key2/..."
key_labels:
- "智能摄像头-1"
- "智能摄像头-2"
- "智能摄像头-3"
- "智能摄像头-4"
timeout: 600
# 模型级独立超时(最终值,不参与编排层 ×2 放大)
# gemini-flash-lite 实测 ~22-34s按用户要求放宽至 8 分钟480s避免大视频/排队时过早切断
model_timeouts:
"gemini-flash-lite-latest": 480
circuit_breaker:
enabled: true
threshold: 5
cooldown: 300
- provider: "nvidia"
role: "vision"
enabled: true
# 模型可用性实测记录2026-08-21用真实短视频逐个探测 chat.completions 接口):
# omni本行 model_namevideo_url 只认 base64 data URINVCF asset_id 引用
# 方式对它直接 500"Only base64 data URLs are supported for now")——本适配器
# 已改为 base64 内嵌整段视频,见 max_base64_mb。确认可用真实返回结构化 JSON
# nemotron-nano-12b-v2-vl走 asset_id 引用需要 NVCF-ASSET-DIR/
# NVCF-FUNCTION-ASSET-IDS 请求头,这两个头的值由 NVCF 服务端按内部路径生成,
# 客户端传什么都 400 "Invalid NVCF-ASSET-DIR",标准 OpenAI 兼容调用打不通,已移除。
# meta/llama-3.2-11b-vision-instruct明确不支持视频输入
# "At most 0 video(s) may be provided"),只能单图,已移除。
# base64 方案受请求体大小限制(实测约 25MB 上限),真实监控视频压缩后通常在
# 20MB 上下,超过 max_base64_mb 直接跳过(不做注定失败的慢速编码),不是本地
# 故意限制过窄——这是当前唯一能打通的 NVIDIA 视频理解路径。
model_name: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning"
fallback_models: []
base_url: "https://integrate.api.nvidia.com/v1"
api_key: "${NVIDIA_API_KEY}"
timeout: 600
max_base64_mb: 20 # 超过此大小直接跳过 NVIDIA不做注定失败的编码+上传
switch_interval_sec: 5 # 模型切换间隔:一个失败后等待再试下一个(未来加模型时用)
model_timeouts: # 模型级独立超时(最终值,不参与 ×2
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": 300
circuit_breaker:
enabled: true
threshold: 5
cooldown: 300
# 本地模型:纯文本 qwen2.5:7b仅参与智能问答兜底
- provider: "ollama"
role: "text"
usage: "qa_fallback"
enabled: true
model_name: "qwen2.5:7b"
base_url: "http://localhost:11434"
timeout: 120
num_predict: 512
circuit_breaker:
enabled: false