Show HN:macOS 上针对每张照片和每帧视频的 AI 搜索

Hacker News Top 工具

摘要

SCM(Screen Memories)是一款本地优先的 macOS 应用,为任意文件夹中的每张照片和每个视频帧提供 AI 驱动的搜索,支持场景级视频搜索、OCR、基于 Whisper 的对白搜索以及可选的本地 LLM 对话——全部在设备上离线运行。该应用开源,可通过 Homebrew 安装,使用 Bun、Electron 和视觉模型(默认 CLIP)构建。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/10/04 14:34

allenv0/SCM

来源:https://github.com/allenv0/SCM

SCM — Screen Memories

针对 macOS 上任意文件夹中的每一张照片、每一帧视频的深度 AI 搜索。本地优先 —— 无需账号、无需云端、无需上传。推理全部在你的 Mac 上运行。

有什么不同

  • 像思考一样搜索 —— 用自然语言描述一段记忆,剩下的交给本地视觉模型完成。
  • 视频,精确到时刻 —— 场景被切分并生成向量嵌入,让你直接命中那一镜头,而不只是那个文件。
  • 文字与对白同样可搜 —— 对画面可见文字进行 OCR;通过 Whisper 实现精确台词搜索,两者都是独立模式。
  • 标签页与提示词归你 —— 任何查询都能保存为标签页;「截图」和「邮件」标签页可开关。
  • 自维护的媒体库 —— 被监控的文件夹自动导入,内容哈希对重命名去重,切换模型时在后台重新嵌入,不阻塞搜索。
  • 真正私密 —— 你的媒体文件从不离开本机。模型权重只需下载一次,之后完全离线。

五种搜索方式

模式能找到什么
文件按语义匹配整个照片/视频 —— 视觉排序,并有文件名与短语加成
场景视频内部的片段 —— 搜索一个镜头,跳转到它的时间码
OCR图像与帧中可见的文字,逐字面匹配(Tesseract;英语 + 35 种语言可开关)
对白视频中精确说出的台词(Whisper),分精确度层级
LLM (可选启用)基于 Mac 已提取的对白、OCR 文本和文件名进行本地对话 —— 回答附引用出处

环境要求

  • macOS(使用 electron-builder 打包;菜单栏/托盘功能仅限 macOS)
  • Bun(https://bun.sh)—— 本项目使用 bun 作为包管理器和运行器
  • 已安装 Node 依赖:bun install
  • 首次使用某个模型时会下载其权重(默认 CLIP 约 435MB);之后完全离线。

下载

最简单的安装方式是通过 Homebrew(Apple Silicon,macOS 12+)。

该 tap 中的 cask 会在每次安装和升级时自动清除 macOS 隔离标记(quarantine flag),因此应用无需任何手动 Gatekeeper 操作即可启动:

brew tap allenv0/scm
brew trust allenv0/scm
brew install --cask allenv0/scm/scm

升级时行为相同:

brew upgrade --cask allenv0/scm/scm

偏好最小权限?只信任该 cask 而不是整个 tap:

brew tap allenv0/scm
brew trust --cask allenv0/scm/scm
brew install --cask scm

该 tap 位于 allenv0/homebrew-scm(https://github.com/allenv0/homebrew-scm)。

开发

bun run dev     # 构建渲染进程 bundle,然后启动 Electron 应用
bun start       # 不重新构建,直接启动 Electron 应用
bun run build   # 仅重新构建渲染进程 bundle 到 dist/

构建应用包(DMG / ZIP)

bun run dist            # 若钥匙串中有身份则进行签名
bun run dist:unsigned   # 跳过代码签名查找

该命令按顺序执行两个步骤:

  1. vite build —— 将 React 渲染层编译到 dist/(会拾取 src/ 下的所有更改)。
  2. electron-builder --mac —— 打包应用。它会将新生成的 dist/ bundle 与 main.js、preload.js、main-lib/ 和 indexer/ 一起打包(文件列表在 package.json 的 build.files 中配置),然后生成安装程序。

输出: 安装程序生成在 dist-app/ 目录(参见 package.json 中的 build.directories.output)—— 找 SCM-0.2.4.dmg 和 SCM-0.2.4.zip。


功能特性

文件

开始输入时会先进行即时的文件名关键词预筛,随后由视觉模型接管:结果通过与图像嵌入的余弦相似度打分,并有受控的短语和文件名加成、按模型校准的诚实底线(honesty floor),以及近重复多样性过滤。每个图块都带有一个「为何匹配」徽章(视觉匹配 / 文件名匹配 / …),悬停时显示各分项得分的详细拆解。中文(CJK)查询以重叠二元词切分搜索(“台北車站” 同时匹配台北、車站)。

场景

所有视频中的每个场景片段都会被评分,因此命中即精确到镜头:图块显示场景海报图并带时间码徽章,打开视频会直接跳转到该时刻。噪声门控会返回「无场景匹配」,而不是用乱码淹没网格;每个视频最多贡献 3 个场景。

OCR

逐字面匹配查询词元中在每张图像 OCR 文本里可见的比例 —— 文件名被忽略,不涉及任何视觉模型,因此即使 AI 引擎预热中或处于离线状态也能工作。匹配到的词在图块和灯箱中以琥珀色框标出。

对白

对 Whisper 转写文本进行精确的逐字面检索 —— 无嵌入、无阈值,AI 引擎关闭也能用。结果分三个层级:精确台词(单次发言中的连续短语)、精确词(单次发言或 ≤8 秒窗口内的全部词),以及说出的词(同一视频中的全部词)。匹配词在语音片段中高亮显示;打开结果会直接定位到该行。

LLM(Ask)

可选启用 —— 在设置 → LLMs Chat 中启用前不会下载或运行任何东西。绑定在回环地址上的 llama.cpp sidecar 会基于应用已提取的证据回答你的问题 —— 对白台词、OCR 文本和文件名关键词命中 —— 并给出可点击的编号引用,逐 token 流式输出,带实时 tok/s 读数。以 /screenshots、/videos、/email 开头可缩小语料范围;Stop 可保留部分回答;证据为空时会在模型运行前短路退出。

聊天模型大小说明
Qwen3 1.7B(默认)~1.1GB日常对话快速;适合 8GB 内存的 Mac
Llama 3.2 3B~2GB更强的长回答能力;需要留有余量

标签页与媒体库视图

  • 内置浏览标签页:全部、视频,以及截图和邮件 —— 后两者可在设置 → Smart Tabs 中开关。选择「视频」时会自动启用场景模式。
  • 任何查询都可保存为标签页:搜索栏下方的图钉按钮会保存当前提示词及其模式(文件/场景/OCR/对白)—— 最多 20 个标签页,可重命名,每个都会按保存时的状态精确恢复。
  • 五个语义视图对应可重映射的快捷键(默认 ⌘1–⌘5),另有 ⌘I 导入 / AI Insights,⌘, 打开设置。
  • 搜索保持在所选标签页内:选择截图、邮件、视频或任何已保存的标签页,结果会被过滤到该范围内 —— 先定范围,再搜索。在 LLM 聊天中同样明确:以 /screenshots、/videos、/email 开头可在模型运行前缩小语料范围。

邮件标签页

展示可见 OCR 文本中包含电子邮件地址的照片 —— 这是一个叠加视图(照片仍保留其原有分类)。检测对 OCR 容错:它会重新拼接 Tesseract 被词框拆散的地址,并处理逗号代替点号的噪声(“gmail,com”)、被拆分的 TLD(“gmail. com”)、括号混淆(“allen [at] gmail [dot] com”)以及口述的地址(“allen at gmail dot com”)。图块显示联系人条,展开后可复制或撰写邮件。

截图标签页

截图分类对重命名免疫。四个信号,按优先级排列:手动覆盖(右键任意图块)→ 文件名词汇(覆盖 20+ 种语言中的 30+ 种本地化系统截图名称)→ PNG/JPEG 元数据探测(从 PNG 文本块 / EXIF UserComment 中读取 “screenshot”,因此重命名后的 Bildschirmfoto 仍能正确分类)→ 来源文件夹提示。其余全部归入「项目」。

视觉模型

通过 ONNX Runtime 提供四个可切换的模型;针对每个媒体库独立选择当前激活模型:

模型角色速度(CPU)下载量
CLIP ViT-L/14@336(默认)真实场景下最佳的视频场景搜索~480–570ms/张~435MB
SigLIP-2-B/16最快的批量导入~50–100ms/张~412MB
SigLIP-2-L/16@256高细节(1024 维)—— 小物体、标牌、屏幕文字~200ms/张~850MB
SigLIP-B/16@384极致细节~480ms/张~214MB

切换模型会对整个媒体库重新嵌入:切换立即生效,剩余部分在后台填充,期间搜索会回退到文件名关键词。每个模型的文字均值居中处理会消除文本嵌入的偏差,使相似度分数在不同模型间保持诚实可比。

视频搜索管线

ffmpeg 扫描每个视频的镜头边界,并根据你在设置 → 视频搜索中选择的密度生成片段计划 —— 每个预设都会在你确认前展示实测的时间与磁盘开销:

预设每个采样点间隔秒数片段预算
Eco604–32
Balanced(默认)308–128
Detailed1512–256
Ultra516–1024
Ultra Pro2.524–2048(需要确认)

每个片段会对其中点帧生成嵌入并保留一张海报图;镜头计划按文件缓存(路径 + 大小 + 修改时间 + 配置指纹),因此重复导入会完全跳过检测。

对白转写: Whisper tiny.en(~150MB,默认)或 base.en(~300MB)—— 切换后会对每个视频重新转写。整段视频会对三帧(20/50/80%)生成嵌入后取平均;GIF 则取中间帧的平均嵌入。

OCR

Tesseract 运行在独立 worker 中,与视觉模型分离。英语始终开启;另有 35 种语言可在设置 → 照片搜索中开关(默认:简体 + 繁体中文、日语、韩语)。每个语言包只需下载一次(~2.4–5MB;默认集合约 ~17MB),之后完全离线。词框与文本一同存储,因此匹配时可在原位高亮;中文(CJK)文本无空格拼接,被词框拆散的邮件片段会被重新拼接。

导入与媒体库管理

  • 导入方式:⌘I、拖放,或受监控的文件夹 —— 导入一个文件夹即开始监控它(实时 fs.watch 加上每次启动时的重新同步)。问题文件最多重试 3 次,之后会在 watch 同步中暂缺,直到文件发生变化。
  • 对重命名免疫的去重:每个文件在复制前都会进行内容哈希(SHA-256),伪装的扩展名会被 MIME 嗅探规范化。
  • 命名的嵌入版本(设置 → 库):整个可搜索状态的时间点快照 —— 索引、每个模型的嵌入 bin、场景和转写 sidecar —— 支持恢复(先自动备份)以及「全新开始」危险区。上限:10 个。
  • 所有内容位于 ~/Library/Application Support/scm 下(MEMORIES_DATA_DIR 可覆盖此路径):索引 JSON、每个模型的 Float32 嵌入 bin、场景和转写 sidecar、缩略图与海报图。

构造即隐私

  • 渲染进程是沙箱化的 app:// bundle —— contextIsolation、操作系统沙箱,以及锁定为 'self' 的 CSP(外加用于展示字体的 Google Fonts CDN,离线时回退到等宽字体)。
  • 只有主进程 worker 会执行下载,且每种内容仅下载一次:视觉模型权重(Hugging Face)、OCR 语言包(Tesseract CDN)、Whisper 权重,以及 —— 仅当你选择启用 —— llama.cpp sidecar 和 GGUF 聊天模型(GitHub + Hugging Face),下载时进行 sha256 校验。
  • 媒体文件被复制到应用管理的媒体库中,并从磁盘流式读取。无遥测、无账号、无上传。

设置与细节打磨

一个 macOS 风格的设置面板,含十个标签页(库、外观、网格、Smart Tabs、照片搜索、视频搜索、LLMs Chat、全局快捷键、键盘、菜单栏)。核心之外还有:浅色/深色/系统主题、灯箱的 CRT 屏幕效果、6 个可选应用图标、仅菜单栏模式、可录制的全局快捷键、首次运行引导导览、后台任务托盘(场景 / 转写 / OCR)带全局暂停,以及显示版本号和已索引视频数的状态栏。

注意事项

  • 首次构建较慢: electron-builder 首次运行时会下载 Electron 二进制文件和 ffmpeg;后续构建会快得多。
  • 代码签名: 若钥匙串中未配置 Apple Developer 身份,DMG 将以未签名方式构建。应用仍可在本地运行,但 macOS 首次启动时可能要求右键 → 打开。
  • 重建会自动拾取更改: 由于 main.js、preload.js、main-lib/ 和 indexer/ 都是从源码打包(而非使用缓存),在修改其中任何一个后执行 bun run dist 即可生成全新的安装包。

测试

bun run test:all       # 完整验证套件(单元 + 冒烟测试)
bun run smoke:indexer  # CLIP 索引器的无头冒烟测试
bun test test/         # 单元测试(纯模块,无需 Electron)
bun run lint           # eslint
bun run format:check   # prettier
  • 单元测试覆盖纯核心模块:排序、对白精确匹配、中文(CJK)词元切分、Whisper 模型阶梯、MIME 嗅探、转写融合等(参见 package.json 中的 test:* 脚本)。
  • E2E 冒烟测试通过 ELECTRON_SMOKE_* 环境变量在 Electron 应用内部运行 —— 十余个场景,从启动/协议检查到搜索矩阵、模型迁移以及 Ask 模式(驱动脚本位于 scripts/e2e/,在 main.js 中调度;例如 bun run smoke:ask、smoke:deep、smoke:grid)。
  • 基准测试: bun run bench:inference、bench:enrich 和 bench:detect 会将 JSON 报告写入 MDs/bench-*。

项目结构

main.js          Electron 主进程:媒体库、IPC、索引器 worker 池、app:// 协议
preload.js       contextBridge —— 向渲染进程暴露 window.memories
main-lib/        从 main.js 拆分出的主进程模块(设置、媒体库存储、排序搜索、Ask 检索、LLM sidecar 配置、嵌入版本……)
indexer/         视觉/OCR/ASR worker(utility 进程)+ 视频工具 + 模型注册表
src/             React 渲染层(网格、搜索模式、灯箱、标签页、设置、引导导览)
scripts/         基准测试脚本、E2E 驱动、冒烟测试套件(smoke-all.sh)
test/            单元测试 + 集成测试
MDs/             设计文档、基准测试报告、计划
dist/            vite 构建输出(渲染进程 bundle)
dist-app/        electron-builder 输出(DMG / ZIP)

相似文章

Invenio

Product Hunt

Invenio 为 Mac 视频和照片库提供本地 AI 搜索。

标记你的照片

Product Hunt

一款Mac应用,利用AI为Apple Photos生成关键词,完全在设备上运行。