已开启
feat: add camera-observation skill #1
feat: add camera-observation skill #1
已开启
Lilili创建于 8月14日
Lilili
Lilili
8月14日

概述

新增 camera-observation 技能,包含摄像头实时画面捕获(Windows 侧)和 Mage-VL 模型分析(WSL
侧)的双进程管道,模型常驻加载不重复读权重

涉及文件:

  • atomcode/skills/camera-observation/SKILL.md
  • atomcode/skills/camera-observation/scripts/capture_live.py
  • atomcode/skills/camera-observation/scripts/realtime_analyze.py

关联 Issue

变更类型

  • [x ] ✨ 新功能

测试计划

已验证的 Provider

  • [x ] OpenAI

检查清单

likedislike
合并受阻
atomgit-bot
atomgit-bot成员
8月14日 评论:

变更摘要

本次 PR 新增了「摄像头实时观测」技能(camera-observation skill),核心由两段跨平台脚本协作完成:Windows 侧 capture_live.py 持续抓取摄像头画面并切分为短视频片段,WSL 侧 realtime_analyze.py 常驻加载 Mage-VL 模型并轮询分析这些片段、输出实时解说。改动聚焦于摄像头采集的健壮性处理与模型的离线、常驻推理流程。

主要改动

  • 新增 Windows 侧采集脚本 capture_live.py:通过 cv2.VideoCapture 持续读取摄像头,强制使用 CAP_DSHOW 后端打开,并输出到 cam_live/seg_<timestamp>.mp4,按 --segment 秒切分、以 --fps 控制帧率。
  • 新增抓帧失败重试与无效片段丢弃机制:cap.read() 失败时等待 0.2 秒后重试;片段小于 50KB 或少于 5 帧时调用 path.unlink(missing_ok=True) 删除该片段并继续,避免空/坏片段进入后续分析。
  • 新增 WSL 侧实时分析脚本 realtime_analyze.py:轮询 live_dir 下的新 seg_*.mp4,对每个片段按 --num-frames 均匀采样帧,调用 Mage-VL 模型生成解说并通过 seen 集合避免重复处理。
  • 新增模型离线加载与常驻机制:脚本设置 HF_HUB_OFFLINE=1 与 TRANSFORMERS_OFFLINE=1,使用 AutoProcessor、AutoModelForCausalLM 一次加载模型后常驻循环监听,analyze_segment 中通过 torch.inference_mode() 进行推理。
  • 新增可配置的提示词与采样参数:提供 DEFAULT_QUESTION 默认解说提示词(重点识别发光的 LCD 屏、GIF 动图及 LED 灯状态),并暴露 --question、--num-frames、--max-new-tokens、--model、--live-dir 等命令行参数。
likedislike
不准确?
atomgit-bot
atomgit-bot成员
8月14日 评论:

代码审查

我已逐一审查了两个变更文件,共报告 5 个问题。

审查结论

atomcode/skills/camera-observation/scripts/capture_live.py —— 发现 3 个问题:

  • P1:直接用最终文件名写入,分析端会读到未完成片段,导致每段画面被永久跳过(核心功能失效)
  • P3:--segment <= 0 时外层循环无 sleep,陷入建删空文件的热循环
  • P3:未使用的 import os(可选清理)

atomcode/skills/camera-observation/scripts/realtime_analyze.py —— 发现 2 个问题:

  • P3:--num-frames <= 0 产生空帧列表,导致每段分析失败
  • P3:未使用的 import sys(可选清理)

汇总

  • 发现数:P0 0 个,P1 1 个,P2 0 个,P3 4 个
  • 总体风险判断:中等偏高。最严重的是生产端/消费端之间缺少"文件完成"的同步机制(原子改名),它会使整个实时分析流水线实际上无法正常工作;其余为参数边界与死代码等次要问题,建议一并修复。
类型 数量
🔴 阻塞 1
🟡 建议 2

⛔ 需要修改

likedislike
不准确?
LililiLilili
8月14日 设置为草稿状态
atomgit-bot
atomgit-bot成员
8月14日 评论:

AtomGit AI 助手使用指南

在 PR 评论中使用命令即可触发。支持在普通评论和代码行评论中使用。

功能 命令 说明
代码审查 /ai review 检查代码质量、潜在问题、安全风险
PR 摘要 /ai summary 生成 PR 变更内容的结构化摘要
代码解释 /ai explain 解释代码变更的逻辑和意图
自由提问 @atomgit-bot <问题> 询问关于本 PR 的任何问题
帮助 /ai help 显示此帮助信息

免责声明

AI 助手可能存在误判,请结合自身判断。可以对评论点 👍 或 👎 帮助我们改进。

likedislike
不准确?
LililiLilili
8月14日 取消了草稿状态
LililiLilili
8月14日 设置为草稿状态
LililiLilili
8月14日 取消了草稿状态
LililiLilili
8月14日 修改了pull request 的描述
Lilili
Lilili
8月14日 评论:

/ai summary

likedislike
atomgit-bot
atomgit-bot成员
8月14日 评论:

⚠️ 已有 AI 任务正在处理中,请稍候,无需重复触发。

likedislike
不准确?
atomgit-bot
atomgit-bot成员8月14日进行代码检视1
atomcode/skills/camera-observation/scripts/capture_live.py
@@ -0,0 +6,4 @@
6+import argparse
7+import cv2
8+import time
9+import os
atomgit-bot
atomgit-bot8月14日评论:

🔵 Low Priority

变更行:capture_live.py:9 import os 在文件中从未被引用,属于死代码/未引用导入,lint 会告警且无任何用途。

建议:删除第 9 行未使用的 import os。

likedislike
不准确?
atomgit-bot
atomgit-bot成员8月14日进行代码检视1
atomcode/skills/camera-observation/scripts/realtime_analyze.py
@@ -0,0 +11,4 @@
11+"""
12+import argparse
13+import os
14+import sys
atomgit-bot
atomgit-bot8月14日评论:

🔵 Low Priority

变更行:realtime_analyze.py:14 import sys 在文件中从未被引用,属于死代码/未引用导入,lint 会告警且无任何用途。

建议:删除第 14 行未使用的 import sys。

likedislike
不准确?
atomgit-bot
atomgit-bot成员8月14日进行代码检视1
atomcode/skills/camera-observation/scripts/capture_live.py
@@ -0,0 +39,4 @@
39+ while True:
40+ stamp = time.strftime("%H%M%S")
41+ path = out / f"seg_{seg:04d}_{stamp}.mp4"
42+ writer = cv2.VideoWriter(str(path), cv2.VideoWriter_fourcc(*"mp4v"), args.fps, (w, h))
atomgit-bot
atomgit-bot8月14日评论:

🟠 High Priority

变更行:capture_live.py:42 直接用最终文件名 seg_XXXX.mp4 打开 cv2.VideoWriter 持续写入,直到第 53 行 writer.release() 才写入 mp4 的 moov 索引。
受影响行为/契约:realtime_analyze.py:96 用 glob("seg_*.mp4") 轮询并把新文件名立即加入 seen(第 97-99 行),没有任何"文件已完成"判断,默认假设目录里的 .mp4 都是完整片段。
失败模式:两个脚本并行运行时(这正是设计用途),capture_live 每 10 秒持续写一个文件,分析端每秒轮询,必然在文件还在写入时(moov 未写入、CAP_PROP_FRAME_COUNT 返回 0 或只读到前几帧)就把它抓走。此时 analyze_segment 返回"(无法读取片段)"或只分析到残缺帧;更关键的是该文件名已被加入 seen,等 10 秒后文件真正写完也不会再被分析。结果是几乎每一段画面都被永久跳过,整个实时分析流水线失效。

建议:先写入临时文件名(如 path.name + ".part",不会被 seg_*.mp4 匹配),在 writer.release() 后再 tmp_path.rename(path),确保分析端只会看到完整片段。

likedislike
不准确?