基于 Google 多模态嵌入模型 EmbeddingGemma 2 的 Mac 菜单栏搜索工具,连视频和声音片段都能搜

DigUp 把照片、文档、代码和音视频片段变成可按含义搜索的本地资料,再带你跳到文件里的相关位置。

作者:Google Gemma · DigUp10-14 · 12 分钟

DigUp 是一款基于 Google 多模态嵌入模型 EmbeddingGemma 2 打造的 Mac 菜单栏搜索工具,可以搜索你选定文件夹里的各种内容,包括照片、文档、代码,以及视频和声音片段。它由开发者 Abdur Rahim 开源:描述你记得的内容,就能在本地找出相关文件,再跳到视频时刻、文档页码或代码段。

Mac 自带的 Spotlight 已能搜索文件名、文档正文和元数据。DigUp 进一步处理照片里的场景、录音里的话题,以及视频中出现的画面,例如:

  • 拍过的一段视频,只记得画面里出现过斑马,却想不起文件名;
  • 听过的一期播客,依稀记得聊到了睡眠话题,却只能拉动进度条盲猜;
  • 签过的一份长篇 PDF 租约合同,不知道宠物条款具体在第几页;
  • 本地代码仓库里的一段指数退避重试函数,文件名和函数名里都没有包含 retry。

它基于 Google DeepMind 推出的多模态嵌入模型 EmbeddingGemma 2,(嵌入模型把内容编码成一串可比较的数字,称为向量)在 Mac 本地为图片、截图、PDF、文本文档、音频和视频建立统一的向量表示,实现按文件“包含什么内容”而非“叫什么名字”进行语义检索。

更进一步,DigUp 的定位不只是指出文件本身,而是直接跳转到文件内部的相关位置:将播放器跳到出现相关画面的时间点、将播客定位到对应话题的音频区间、将 PDF 翻到相关条款所在的页码,或在编辑器中定位到相关代码段。所有切片与检索均在 Apple Silicon 本地完成,无需将个人文件上传到外部服务。


为什么一句话能找到照片和录音

要理解 DigUp 的检索逻辑,核心在于其搭载的多模态嵌入模型 EmbeddingGemma 2(由 Google DeepMind 开源,遵循 Apache 2.0 协议)。

不同输入,各自编码
文字与代码文本部分 · 270M 参数
照片与视频帧视觉编码器 · 170M 参数
语音与其他声音音频编码器 · 300M 参数
共享 768 维向量空间每个片段有自己的向量;一句文字查询的向量可与它们比较。

一种常见的多模态检索做法是先经过中间文字转换:用语音识别转出台词、用 OCR 提取画面字符,再基于纯文本计算相似度。这种链路依赖文字作为媒介,容易漏掉未被文字标注的信息,例如语音里的语调、背景声响,或是画面中的构图、动作与非文字细节。

EmbeddingGemma 2 走的是原生多模态对齐(Native Multimodality)路线:

  1. 统一的向量空间:模型总参数量为 740M(包括 270M 文本主干、170M 视觉编码器和 300M 音频编码器)。文本、静态图像、视频抽帧和音频切片均被映射到同一个 768 维向量空间中。
  2. 跨模态的可比表示:统一空间让文字查询能与图片、音频或视频片段直接计算余弦相似度。应用据此给候选资料排序,再让你查看原文件。
  3. 任务指令前缀(Task Instruction Prefixes):模型在训练时对不同任务使用了特定文本前缀引导。常规搜索查询使用 task: search result | query: {query};代码意图检索使用 task: code retrieval | query: {query};文档内容则包装为 title: {title} | text: {content}。前缀帮助文本向量更好地对齐目标检索场景。
  4. 编码器模块化解耦:视觉编码器和音频编码器相互独立。在仅需要根据输入文本进行匹配的搜索阶段,只需调入文本主干,无需同时加载视觉与音频编码组件。
进一步理解底层模型Google 开源多模态向量模型 EmbeddingGemma 2:用自然语言搜索文字、图片、声音和视频

了解模型按需加载、输入预算与向量压缩之间的取舍。

阅读模型解读 →

找到文件以后,怎样跳到对应页和时刻

如果只是把整部视频或几百页的 PDF 整体算成单个向量,检索结果最多只能指出文件本身。DigUp 的实际做法是将不同媒体切分为具备时间戳或位置元数据的片段(Segments),以便直接定位到文件内部。

在 macOS 系统下,DigUp 调用 AVFoundation、PDFKit、Vision 与 ImageIO 框架实现文件解析与特征抽取:

1. 视频切片:关键帧抽样与图像指纹去重

视频是数据量最大的媒体类型。在后台处理时,DigUp 采取了抽样预算与指纹去重策略(见 Media+Apple.swift 源码):

  • 抽样步长与帧数预算:抽样步长按 max(3, duration / 1200) 秒计算。通常每 3 秒抽取一帧;当视频时长变长时,以最多 1,200 帧作为数量预算动态拉大步长,而不是只截取前 1,200 帧。每帧按 70 个视觉 soft token 的预算进行编码;
  • 均值哈希(aHash)去重:抽取出的每一帧会缩放至 8×8 灰度图并计算均值哈希。若相邻两帧的汉明距离在 4 位以内((hash ^ lastHash).nonzeroBitCount <= 4),表明画面高度近似,DigUp 会跳过该帧编码,仅将前一帧的代表区间向后延伸。它对幻灯片、固定机位等近似画面做去重,决定保留哪些画面代表后面的区间;
  • 画面与音轨分路处理:视频文件会被拆解为画面与声音两条独立路径。画面进行抽帧编码,音轨则提取后送入音频处理流程,分别支持画面动作搜索与口播台词搜索。

2. 音频切片:滑动窗口与静音切除

在音频处理上,EmbeddingGemma 2 的通用模型卡具备 8,192 token 的上下文窗口,理论上可容纳更长音频;而 DigUp 当前运行路径设定了单输入上限 30 秒(源码注释标明单次输入忽略 30 秒之后的内容):

  • 窗口规格:音频统一重采样为 16 kHz 单声道,切分为 30 秒的固定时间片,窗口之间以 25 秒步长滑动(即保留 5 秒重叠)。5 秒重叠让一部分跨边界的语句仍能落在完整窗口内;
  • 静音剔除:计算切片的均方根能量(RMS)。若 RMS ≤ 0.003(约低于 -50 dBFS),视作无声或极低底噪环境,直接跳过不生成向量,节省存储空间。

3. PDF 与长文档:两阶段调度与图文混合

面对长篇文档与合同,DigUp 设计了分批读取机制:

  • 按页数分流与两阶段调度:源码中设置 bigPDFPages = 50。50 页以内的 PDF 会在首次索引时整份读完;超过 50 页的长 PDF,第一阶段只读取前 30 页,确保大部分文件能快速进入可检索状态,30 页之后的内容则留待后台后续收尾(单文件上限 5,000 页)。普通文本文档也按前 40 块(约 6.4 万字符)优先索引、后续追加的策略处理;
  • 扫描件图文融合:单页提取文字少于 200 字时(常见于扫描件或幻灯片),DigUp 会将页面渲染为图像调用视觉编码器;同时结合 Apple Vision 进行 OCR,使扫描发票或单据中的编号也能被关键词检索覆盖。

4. 代码项目:独立索引与结构化行段

代码搜索在开启后使用独立的数据库(code.sqlite):

  • 行段切片:以完整代码行为单位切分,每段上限控制在约 1,800 字符。源码注释指出,切片过短容易切散函数逻辑,切片过长则容易模糊意图;
  • 规则过滤:遵循 .gitignore 规则,主动跳过依赖库、测试生成物、密钥和证书。

这种按窗口与抽样帧切分的机制也带来了粒度上的代价:系统定位给出的是命中的时间窗口或抽样帧,并非逐字逐帧的精细锚点;若某些关键画面在视频中仅短暂闪现且恰好落在抽样间隔之间,就存在错过的可能。


按含义找和按原词找,怎样配合

当所有片段的向量存入本地数据库后,如果直接比较一段文本查询与文本、图像、音视频之间的原始余弦相似度,往往会遇到模态间的分布差异。

1. 模态均值校准与标准化得分

在实际检索中,针对同一次输入查询,不同模态(文本、图像、音频)的原始余弦相似度分布可能具有不同的均值水平。若直接按原始相似度混排,均值偏高的模态可能会占据前列,从而掩盖其他模态中真正相关的候选内容。

DigUp 在 Searcher.swift 中采取了模态均值校准(Modality Centering)的处理方案:

  1. 计算各模态均值:统计当前查询下文本、图像、音频各模态各自的余弦均值。若某个模态的向量数量少于 20 个,则借用全体向量的平均分作为该模态的均值;
  2. 模态中心化:计算每个片段减去其模态均值后的差值:中心化差值 = 余弦相似度 − 对应模态的平均值。
  3. 计算联合标准差与校准得分:计算所有参与定标片段的中心化差值均值,以及跨模态的联合标准差(设 0.02 为下限),最终得出标准化 Z 分数:Z =(中心化差值 − 定标片段的中心化均值)÷ 联合标准差。
  4. 突出门槛过滤:设置门槛 zGate = 2.0。该分数衡量的是某个片段偏离其模态平均水平的标准差程度,用于判断其是否在所属模态中相对突出,而非直接等同于相关概率或检索准确率。使用各模态共同的联合标准差,可以避免样本分布较窄的模态被过度放大。

2. 精确匹配补充:为什么需要 FTS5 全文搜索?

嵌入模型擅长理解自然语言意图,但向量表示无法可靠保留逐字符的代码、编号或发票单号。

因此,DigUp 采用了双轨混合检索结构:

  • 语义轨(Meaning):依托 EmbeddingGemma 2 的向量相似度与模态校准得分;
  • 精确轨(Words):依托 SQLite 原生 FTS5 全文检索模块,对文件名、目录路径、文档文字与 OCR 提取字符进行词干提取与归一化检索。

系统根据查询词特征动态平衡两轨比重:

  • 常规搜索:以语义向量得分为主导,关键词命中提供额外加分;
  • 特殊编号查找(Lookup):源码中的 isLookup 判定要求查询中的所有有效词项均包含数字,且要么包含字母、要么数字长度达到 4 位及以上。例如输入单纯的订单编号 4815162342 或代码 K7Q2LM 时,会触发此模式,系统将关键词权重提升一倍,并将语义向量权重减半;但如果输入包含常规词汇的组合(如 invoice 4815162342,由于 invoice 并非停用词且不含数字),则不会触发该特殊权重;
  • 代码权重调优:在代码搜索中,像 app、get、running 等高频词汇在源文件中极为普遍,因此代码检索下的关键词权重被设为 1.0(常规搜索为 2.0),防止浅层词频重合干扰真实意图。

切换下面的查询例子,可以看到它进入哪个索引,以及含义与原词如何参与检索:

同一入口,两条检索线

换一种查询,看检索怎样走

输入含义由模型编码,具体编号交给关键词匹配。切换查询,可以看到两条通道如何配合。

查询zebra in a video
主索引 · index.sqlite普通资料与代码分别存放;code: 切到代码索引。
按含义找

EmbeddingGemma 2 → 向量比较

把查询和视频抽样画面放进同一 768 维空间,比较它们的语义相似度。

语义权重 1
按原词找

关键词 → FTS5 全文索引

在文件名、正文及 OCR 文字中查原词,为语义匹配补充线索。

关键词权重 2
合并排序语义分数按本次查询的模态分布校准,关键词按命中比例加权。
作者演示中的结果

Masai Mara - day 2.mp4

返回含斑马的相关画面位置,打开后从该处查看。

视频索引默认约每 3 秒抽样并去重;定位依据是抽样画面和保存的时间。


作者演示中,四种搜索各自返回什么

在开发者 Abdur Rahim 公开(并由 Google Gemma 官方账号转发推荐)的实机演示中,呈现了典型的工作流交互:

作者公开的 DigUp 运行剪辑演示,已补中英双语旁白与关键搜索词翻译。
依次呈现视频内斑马画面定位、播客内睡眠片段、租约合同条款、多语言照片以及 Zed 编辑器打开代码段的过程(约 60 秒)。 下载中英双语字幕视频 · 查看原视频

案例 1:视频画面定位(zebra in a video)

在搜索框键入 zebra in a video,候选列表命中名为 Masai Mara - day 2.mp4 的视频,并给出时间标记。

  • 直接动作:按回车键打开后,调用 QuickTime Player 并跳转至包含斑马画面的相关播放位置;
  • 权限机制:由于 macOS 的自动化控制权限要求,应用首次控制 QuickTime Player 时会弹出系统确认对话框,允许后即可直接控制播放器跳转。

案例 2:播客对话定位(where they talk about sleep)

键入 where they talk about sleep 后,搜索列表命中音频文件 The Long Run - Ep 14.mp3。

播客搜索定位到 7 分 55 秒处
音频跳转演示画面。
匹配结果直接给出 7:55 的时刻标记,并在右侧预览面板中显示“playing from 7:55”。

案例 3:长篇 PDF 条款定位(the clause about pets in the lease)

检索长租合同中的宠物规定,系统从合同 Lease - 14 Elm Street.pdf 中定位至第 4 页。

PDF 合同第 4 页高亮显示宠物条款
PDF 页面定位与字符高亮。
预览直接显示第 4 页,并联动系统预览(Preview)的搜索框对查询关键词进行高亮标注。

案例 4:代码意图检索(code: retry with backoff)

当输入以 code: 前缀开头时,DigUp 针对配置的代码目录进行检索。

代码搜索命中 retry.ts 并提供打开至编辑器的按钮
代码检索定位代码段。
演示结果呈现了 retry.ts(第 1–47 行)代码范围与 retry.py,右侧提供“Open in Zed”快捷入口,点击即可在编辑器中打开对应代码段。

在代码检索逻辑中,意图搜索返回的是相关的代码段(stretches of lines);只有当用户输入确切的符号名称或标识符时,系统才会尝试定位到具体的定义行。除了 Zed,DigUp 还支持 VS Code、Cursor、Xcode、Sublime Text 与 JetBrains 系列等编辑器。

多语言与中文支持情况

  • 跨语言语义能力:EmbeddingGemma 2 预训练覆盖 100 多种语言,但各语言之间的表现并不完全一致;项目自身的评估集目前主要测试了英语、孟加拉语和阿拉伯语。正文中所附的中文查询示例为面向中文读者的译写参考,并非项目原有的测试用例;
  • 关键词与文字识别:在 FTS5 关键词层,SQLite 默认分词器对中文、日文、泰文等非空格分词语言不会按词切开;对于截图与图片中的文字识别,能力取决于 Apple Vision 框架(支持约 25 种语言);
  • 输入法体验改进:在 0.6.1 版本中,开发者修复了中文、日文、韩文等复合输入法(IME)在搜索框中键入拼音组合时字符被打散的问题,使输入过程保持连续。

资料留在本地,计算和存储怎么安排

在本地资源占用和系统架构设计上,DigUp 没有依赖外部守护进程或独立的专业向量数据库:

先建索引选定文件夹 → 分页、分段、抽帧 → Helper 调用 GPU 编码
本地 SQLite文件路径 + 片段位置 + 向量 + 关键词普通资料:index.sqlite 代码:code.sqlite
再搜索查询按需编码 → 向量与关键词比对 → 打开原文件中的相关位置
  1. 单文件本地存储与向量开销: DigUp 将文件记录、切片元数据和 768 维 float16 向量统一保存在一个本地 SQLite 文件中。以两万个向量片段为例,原始向量数据本身大约占用 30MB(仅为纯向量存储大小,不含其他元数据和主程序运行开销)。搜索时将这部分向量载入内存直接做矩阵点积比对,无需维护庞大的向量数据库服务。
  2. 助手进程执行完即退出: 重负荷的文件扫描与 GPU 向量编码由独立的 Helper 进程执行,借助 llama.cpp 的 Metal 后端调用 Mac GPU。当待处理队列完成后,该助手进程会主动退出并释放占用的计算资源;而在用户触发搜索时,主程序才会按需加载文本查询编码部分(README 估计约 250MB 内存),平时仅保留菜单栏常驻。
  3. 选哪些文件夹,就读哪些资料: DigUp 仅在用户选定的文件夹范围内读取文件,不修改、不移动原文件,也不上传所索引的内容。在扫描过程中,它会自动跳过密钥、证书、密码文件、隐藏目录(如 ~/.ssh)、应用包体与缓存,并跳过类似数据集的目录;对于保存在 iCloud 且未下载到本地的云端占位文件,DigUp 不会触发自动下载。网络请求仅用于初次拉取模型权重(约 865MB)以及每日版本更新检查(可在设置中关闭),不包含任何账户体系或使用遥测。应用采用 MIT 协议开源,底层模型采用 Apache 2.0 协议,Windows 与 Linux 版本目前尚在计划中。

在自己的 Mac 上走通一次

持有 Apple Silicon Mac(M 系列芯片,macOS 14 及以上系统)的用户可以按以下路径上手体验:

第一步:获取与安装

  • Homebrew Cask 安装(需系统已安装 Homebrew,在终端执行):
    brew install --cask arahim3/tap/digup
    
  • 手动 DMG 下载:前往项目的 Releases 页面 下载经签名的 DigUp-0.6.1.dmg,打开 DMG 后将 DigUp 拖入 Applications 应用程序目录。

第二步:模型下载与本地导入

  1. 启动 DigUp 后,它会驻留在菜单栏中;
  2. 首次启动会自动下载 EmbeddingGemma 2 模型权重(约 865MB,其中文本主干约 310MB,音视觉编码器约 555MB);

    手动导入模型: 若本地网络直接下载受阻,可在 Settings → Storage 中点击 Use Files… 手动指定模型文件。所需文件为 ggml-org 维护的 Q8_0 量化权重:embeddinggemma-2-Q8_0.gguf 与 mmproj-embeddinggemma-2-Q8_0.gguf,可前往 Hugging Face 官方仓库入口 ggml-org/embeddinggemma-2-GGUF(固定版本 commit 为 bfcd298762cc34d0357ece5ebdd31791a3a374d8)下载对应的两个文件,选定后 DigUp 校验通过即可使用。

第三步:配置扫描目录与索引策略

在 DigUp 应用自身的 Settings 窗口中勾选需要索引的文件夹:

  • 首次体验建议:建议先选定一个文件数量较少的小型本地文件夹,观察菜单栏进度,待索引完成后再进行搜索尝试;
  • 耗时预期:几百个常见文件的初次索引通常只需几分钟,而对于庞大的“下载”等目录,README 明确指出首次扫描可能需要一小时左右;
  • 低电量与供电选项:当 Mac 开启“低电量模式”时后台索引会自动暂停,退出低电量模式后恢复;是否必须在连接电源时才进行索引则为单独的设置开关;
  • 定时索引:若不希望白天占用系统能耗,可在 Settings → Folders 中开启定时索引(默认设为凌晨 1:00 至 7:00 执行)。

第四步:常用全局快捷键

快捷键 用法
⇧⌘Space 打开搜索面板,快捷键可在 Settings 中修改
↑ / ↓ 选择结果,查看对应预览
↩ 打开结果中的页码、时刻或代码行段
Space 选中结果后用 Quick Look 查看
⌘↩ 在 Finder 中显示文件
⌘C 复制文件
⌘O 在较大的窗口中浏览同一搜索结果与筛选器

第五步:复制一种查询,查看命中的原文件

搜索时只需使用一种语言表达意图(支持英文或中文),前提是选定的检索目录中包含对应内容:

以下英文来自项目示例,中文为译写参考,选一种输入即可:

视频画面

zebra in a video
有斑马出现的视频

播客话题

where they talk about sleep
讨论睡眠的那段录音

PDF 条款

the clause about pets in the lease
租约中关于宠物的条款

代码意图

code: retry a failed call with backoff
code: 调用失败后按退避策略重试

先开启代码搜索: 代码搜索默认处于关闭状态。若需搜索代码,先在 Settings → Code 中添加目标代码仓库、开启功能并指定偏好的代码编辑器(如 Zed、VS Code、Cursor、Xcode 等),随后在搜索框以 code: 前缀开始检索。建议先在右侧面板查阅代码段预览再按回车打开;若未检索到预期结果,可检查目标目录是否已建立索引完毕、文件是否为云端未下载占位,并适当微调描述词。


文件名忘了,内容还能成为入口

DigUp 扩展了本地资料的检索入口:让照片画面、视频镜头、长录音片段、复杂文档条款以及代码逻辑,都能通过自然语言被直接检索并定位到具体位置。在完全依靠本地芯片算力、不上传个人隐私的前提下,它为 Mac 上的多媒体资产检索提供了一种轻量且实用的新路径。

↑ 正文结束
✓ 本篇全文免费开放

会员可复制、下载全文 Markdown,还能让你的 AI 订阅和提问。

阅读原文 ↗
📮 新解读第一时间进邮箱

读完觉得有用?留个邮箱,每篇新解读发布就送达,随时退订。