使用 Elasticsearch 和 Jina 进行 AI 视频搜索:精准找到你需要的视频片段秒数

作者:Elasticsearch日期:2026/9/20

作者:来自 Elastic JD Armada

在每个镜头边界处剪切每个片段,并将每个场景嵌入为向量,然后通过一个纯文本查询返回文件以及可以放置到时间线上的精确秒数。

亲自体验 Search AI 的向量搜索,试试这个自主进度式实践学习。你现在可以开始免费云试用,或者立即在你的本地机器上试用 Elastic。


输入 warm sunset light over a mountain,就可以获得与之匹配的视频素材的精确秒数。Omnishot 是一个 AI 视频搜索应用,它会监视一个文件夹,并在每个场景边界处剪切每个片段。它使用 jina-embeddings-v5-omni-small 将每个场景嵌入为一个 1,024 维向量。同一个模型同时处理文本和视频,因此输入的查询和视频素材会进入同一个向量空间,而在 Elasticsearch 中进行最近邻搜索,就可以找到与描述相匹配的视频片段。一小时的视频素材大约会生成 1,200 个可搜索向量,而以前需要数小时才能完成数据摄取的文件夹,现在几分钟内就可以处理完成。

这个想法来自 Elastic 的一位视频编辑。她以前需要花费整个下午在 B-roll 文件夹中反复拖动播放进度条,只为了找到某个特定的画面。

通过描述搜索视频素材库

这个应用的工作方式如下:

  1. 选择一个视频素材文件夹。
  2. 使用视觉查询搜索片段(drone shot over a coastline)。
  3. 使用已存储的向量搜索相似片段。
  4. 在同一个视频片段中查找相似的视频片段。
  5. 在文件浏览器中显示该视频片段,可以直接放到时间线上。

AI 视频搜索管道的工作方式

管道流程如下:

  1. 一个监视器每四秒轮询一次关联的视频素材文件夹(默认为 clips/),检查是否有新的视频素材。
  2. PySceneDetect 检测每个视频片段中的场景边界。
  3. FFmpeg 在这些边界处剪切视频片段,并使用无损流复制,然后将每个场景片段转码为一个较小的代理文件。
  4. 代理文件通过 Jina API 发送给 jina-embeddings-v5-omni-small,该模型采样 32 帧并返回一个 1,024 维向量。
  5. 该向量被摄取到 Elasticsearch 中的 dense_vector 字段,并使用分层可导航小世界(HNSW)索引(一种近似最近邻图)。在查询时,编辑器输入的文本会通过同一个模型处理,然后针对已存储的视频片段向量执行 k 近邻(kNN)搜索。

同一个模型同时对文本和视频进行嵌入,这正是 Jina 的 omni 模型如此灵活的原因。视频片段和文本查询会被嵌入到同一个向量空间中,因此最近邻搜索实际上意味着:找到看起来与我用文本描述的内容相符的视频素材

构建 AI 视频搜索所需的组件

  • Elasticsearch(Serverless 或支持 dense vector 的 8.x 及更高版本)
  • Jina API 密钥
  • PySceneDetect
  • FFmpeg
  • Python 3.9+

下载用于搜索的示例视频素材

如果你手头没有可以用来搜索的视频素材,该代码仓库包含两个下载脚本:其中一个用于从 Pexels API 下载较短的库存视频片段,涵盖自然、城市、动物等类别。另一个使用 yt-dlp 直接从 YouTube 下载较长的纪录片风格视频。

1`
2
31.  python scripts/download_pexels.py --out ./clips --total 50
42.  python scripts/download_youtube.py --out ./clips --total 20
5
6`AI写代码
7

我们的目标是让短视频和长视频保持良好的组合,以展示分块策略变得多么重要。我们将在下一部分讨论这一点。

如何为嵌入对视频进行分块

jina-embeddings-v5-omni-small 会从你发送给它的任何视频中均匀采样 32 帧。对于一个 10 秒的视频片段来说,32 帧可以实现密集覆盖;几乎每个时刻都能被捕捉到。对于一部 10 分钟的纪录片,同样的 32 帧会被分散得非常稀疏,以至于整个镜头都可能被遗漏。下面的图示说明了 Jina 模型如何对每个视频片段进行采样,以及较长视频片段存在的局限性:

所以,在进行任何嵌入之前,我们首先要进行分块。问题在于应该在哪里进行切分。下面的图示对比了三种策略:

  1. 固定长度分块:每隔 N 秒进行一次切分。这种方式简单且可预测,但切分点可能落在镜头中间。你最终可能得到一个一半是无人机航拍、一半是人物正面镜头的分块,这会导致搜索结果无法使用。对于这个使用场景来说,这并不是合适的选择。
  2. 基于转录文本的分块:首先对视频片段进行语音转文本,生成转录文本,然后对其应用文本分块技术,在主题边界处进行切分,并将这些边界映射回视频中的时间戳。这种策略非常适合播客、演讲和教育类内容,但不适合 B-roll,因为 B-roll 通常没有对白。
  3. 基于场景的分块:在视觉发生变化的位置进行切分,例如镜头切换、转场和剪切。每个分块都是一个特定的画面,这正是视频编辑需要搜索的内容。对于我们的使用场景,这是最合适的方式。

三种策略并列对比:

策略如何切分最适合缺点
固定长度每隔 N 秒内容均匀、成本可预测切分点可能落在镜头中间,产生混合分块
基于转录文本在语音转文本结果的主题边界处播客、演讲、教育视频对没有对白的 B-roll 无效
基于场景在视觉切换和转场处B-roll 和视频素材库依赖可靠的镜头检测

使用 PySceneDetect 检测场景边界

为了实现这一点,我们使用 PySceneDetect 查找剪切点:

1`
2
31.  from scenedetect import AdaptiveDetector, detect
4
53.  scenes = detect(
64.  str(video_path),
75.      AdaptiveDetector(
86.          adaptive_threshold=3.0,
97.          min_scene_len=int(min_scene_len_sec * 24),
108.      ),
119.  )
12
13`AI写代码
14

AdaptiveDetector 会将每一帧的变化与滚动平均值进行比较,从而避免摄像机平移和手持拍摄产生的运动被误判为镜头切换。最小场景长度默认为 1.5 秒,假设每秒 24 帧(FPS),也就是 36 帧,因此快速切换不会产生不到一秒的碎片。如果完全没有检测到边界,则整个视频片段会成为一个分块。随后,每个检测到的场景都会被剪切成独立的分块文件,并使用无损的 FFmpeg 流复制(-c copy),因此在代理文件处理步骤之前不会进行重新编码。

现在,这 32 个采样帧覆盖的是几秒钟内的特定视觉场景,而不是在不同视频片段中粗略地进行采样。

为什么发送 640px 的代理文件,而不是原始文件?

我们不会将原始的完整尺寸文件发送到嵌入 API。一个 4K ProRes 分块可能达到数百 MB,而模型本身也无法利用这种分辨率。它的视觉编码器大约每个 28x28 像素的区块生成一个 token ,而模型的默认配置将每帧限制为 1,280 个视觉 token,相当于大约 1 百万像素。任何更大的图像都会在编码之前缩小以符合这一限制,因此一个 4K 帧进入模型时,大约只有原始像素的八分之一。上传完整分辨率的视频素材,只会在从未使用的分辨率上浪费带宽和时间。如果想深入了解模型如何将帧转换为 patch token,请参阅我们关于 jina-embeddings-v5-omni 架构的深度解析

因此,我们使用 FFmpeg 将每个场景分块转码为轻量级代理文件:宽度为 640 px、移除音频,并采用高强度压缩。

1`
2
31.  import base64
42.  import subprocess
53.  import tempfile
64.  from pathlib import Path
7
86.  def make_video_input(
97.      chunk_path: Path,
108.      max_width: int = 640,
119.      crf: int = 28,
1210.      max_seconds: float = 3.0,
1311.  ) -> dict:
1412.      """Return a Jina video input dict with a short 640px proxy as base64."""
1513.      with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
1614.          proxy_path = tmp.name
1715.      try:
1816.          subprocess.run(
1917.              [
2018.                  "ffmpeg", "-y", "-loglevel", "error",
2119.                  "-i", str(chunk_path),
2220.                  "-t", str(max_seconds),
2321.                  "-vf",
2422.                  f"scale='if(gt(iw,ih),{max_width},-2)':'if(gt(iw,ih),-2,{max_width})'",
2523.                  "-c:v", "libx264", "-crf", str(crf), "-preset", "veryfast",
2624.                  "-an",  # drop audio, the model never hears it
2725.                  "-movflags", "+faststart",
2826.                  proxy_path,
2927.              ],
3028.              check=True,
3129.          )
3230.          data = base64.b64encode(Path(proxy_path).read_bytes()).decode("ascii")
3331.      finally:
3432.          Path(proxy_path).unlink(missing_ok=True)
3533.      return {"video": data}
36
37`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
38

我们来看一下这个函数中两个容易被忽略的部分。scale 滤镜会检查方向 gt(iw,ih),因此横向视频片段的宽度最多为 640 px,而纵向视频片段的高度最多为 640 px,而不会被强行拉伸变形。max_seconds 则将每个代理文件的时长限制为 3 秒。之所以可行,是因为每个分块都是一个独立的视觉内容,所以前几秒已经能够很好地代表整个分块,而在 3 秒内采样 32 帧已经可以实现密集覆盖。该函数返回 {"video": <base64>},这正是 Jina API 所要求的输入格式。

在一定范围内,画质损失并不重要。嵌入关注的是帧中包含什么内容,而不是视频素材的质量是否足以用于最终交付。但是,如果压缩得过于激进,视觉细节开始消失,模型可能就无法再可靠地判断每一帧中包含什么内容。目标是在不丢失重要视觉信息的情况下缩小文件。代理文件的大小从数百 MB 降到了几百 KB,因此摄取一个视频素材文件夹只需要几分钟,而不是几个小时。

随后,每个代理文件都会以 base64 字符串的形式发送到 Jina API,而 API 会返回该分块对应的 1,024 维向量:

1`
2
31.  resp = requests.post(
42.      "https://api.jina.ai/v1/embeddings",
53.      headers={"Authorization": f"Bearer {JINA_API_KEY}"},
64.      json={
75.          "model": "jina-embeddings-v5-omni-small",
86.          "task": "retrieval.passage",
97.          "dimensions": 1024,
108.          "embedding_type": "float",
119.          "normalized": True,
1210.          "input": [make_video_input(chunk_path)],  # {"video": "<base64>"}
1311.      },
1412.  )
1513.  embedding = resp.json()["data"][0]["embedding"]  # 1024 floats
16
17`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
18

task 参数在这里非常重要。分块会使用 task="retrieval.passage" 进行索引,而在搜索时,查询文本会使用 task="retrieval.query" 进行嵌入。该模型会生成针对检索进行调优的非对称嵌入,一侧用于文档,另一侧用于查询。

我们还将 dimensions 固定为 1024,并将 normalized 设置为 true。对于余弦相似度来说,并不要求进行归一化,因为余弦相似度衡量的是向量之间的夹角,而向量长度不会影响得分。归一化的作用是让每个向量都具有单位长度,而对于单位向量,点积就等于余弦相似度,因此引擎可以跳过向量长度的计算,直接使用普通点积来比较向量。

使用 Elasticsearch 时,你可以利用归一化向量,将字段的 similarity 映射为 "dot_product",而不是 cosine,从而跳过查询时的归一化开销。代码仓库为了安全起见仍然使用 cosine,因为即使某个未归一化的向量意外混入其中,它也仍然可以正常工作。

在代码仓库中,这个请求位于一个小型客户端类(backend/lib/embed_jina.py)中,该类还会在遇到速率限制和临时服务器错误时使用指数退避进行重试。获取向量后,我们就可以将这些向量摄取到 Elasticsearch 中。

将视频嵌入摄取到 Elasticsearch

首先,我们定义一个显式的映射。Elasticsearch 可以动态推断字段类型,这意味着在索引时,第一个写入的文档就可能决定字段的映射方式。在这里,我们希望明确指定:ID 应该使用 keywords;视频内时间戳,例如 start_secend_sec,应该使用 floats;最重要的是,嵌入字段需要配置为 1,024 维的 dense_vector,使用 cosine 相似度和 HNSW 索引。

下面是该索引的映射:

1`
2
31.  mappings = {
42.      "properties": {
53.          "chunk_id": {"type": "keyword"},
64.          "clip_id": {"type": "keyword"},
75.          "path": {"type": "keyword", "index": False},
86.          "start_sec": {"type": "float"},
97.          "end_sec": {"type": "float"},
108.          "duration": {"type": "float"},
119.          "strategy": {"type": "keyword"},
1210.          "uploaded_at": {"type": "date"},
1311.          "uploader": {"type": "keyword"},
1412.          "tags": {"type": "keyword"},
1513.          "transcript": {"type": "text", "analyzer": "english"},
1614.          "embedding": {
1715.              "type": "dense_vector",
1816.              "dims": 1024,
1917.              "index": True,
2018.              "similarity": "cosine",
2119.              "index_options": {"type": "hnsw"},
2220.          },
2321.      }
2422.  }
25
26`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
27

有几个值得注意的地方:

  • dims 为 1024,以匹配模型的输出。
  • similarity 使用 cosine,因为 Jina 嵌入是针对余弦距离进行训练的。正如前面提到的,对于归一化向量,dot_product 得分完全相同,而且速度会稍快一些,但为了安全起见,我们仍然使用 cosine。
  • 使用 HNSW 和 index: True 会在索引时构建近似最近邻图,因此查询时不需要对每个向量进行暴力搜索。
  • start_sec/end_sec 让我们能够直接将编辑器跳转到视频片段中的正确时间点,而不仅仅是找到正确的文件。
  • 其余字段都是普通元数据:path 会被存储,但不可搜索("index": False),这样应用就可以播放对应的分块文件;durationstrategy 描述分块的生成方式;tags/transcript 则为以后进行关键词和转录文本搜索预留空间。

这意味着每个场景分块对应一个文档,而不是每个视频片段对应一个文档。一部 10 分钟的纪录片可能会变成 80 个文档。关键在于每个文档都可以被独立找到。需要注意的是,视频本身不会被放入 Elasticsearch。一个文档只是向量加上几个元数据字段,其中包括一个 path,指向磁盘上的分块文件。视频素材仍然保留在原来的位置,而 Elasticsearch 纯粹充当索引,用来告诉我们哪个文件以及其中的哪几秒与查询匹配。

这个应用针对本地文件夹运行,因此path是文件系统路径。如果你要将其构建为托管服务,那么视频片段会存储在对象存储中,例如 Amazon S3 或 Google Cloud Storage,而该字段则会保存指向存储对象的指针,但整体架构保持不变。

对视频分块执行向量搜索

在查询时,编辑器中的文本会经过相同的模型。Warm sunset light 会变成一个 1,024 维的向量,与视频分块位于相同的向量空间中,然后我们让 Elasticsearch 查找它的最近邻:

1`
2
31.  res = es.search(
42.      index="broll",
53.      knn={
64.          "field": "embedding",
75.          "query_vector": query_vector,
86.          "k": 50,
97.          "num_candidates": 100,
108.      },
119.      size=50,
1210.      source_excludes=["embedding"],
1311.  )
1412.  hits = [{**h["_source"], "_score": h["_score"]} for h in res["hits"]["hits"]]
15
16`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
17

k 表示返回多少个邻居;num_candidates 表示每个分片在排序之前会考虑多少个候选结果。更高的候选数量意味着更好的召回率,但会带来略高的 latency 。我们还会从响应中排除 embedding 字段,因为每个命中结果包含 1,000 个浮点数,而对于 UI 从不读取的值来说,这会产生大量 payload。我们获取的结果数量会多于实际显示的数量(对于九张卡片的网格会获取 50 个),这是因为接下来还需要进行进一步处理。

_查找相似视频片段_的工作方式相同,只不过查询向量不再来自嵌入后的文本,而是来自一个已存储的视频分块嵌入。不需要调用第二次模型;该向量已经存在于索引中。

对来自同一视频片段的结果进行去重

我遇到的一个问题是,同一个视频片段中的分块太多,以至于占满了整个结果网格。搜索 mountains 时,一部 10 分钟的自然纪录片可能有十几个分块与查询匹配,从而把其他所有视频片段都挤出了顶部结果。这在技术上是正确的,但对于希望获得更多选择的编辑来说,实际上并没有什么用。

解决方法是保留每个视频片段中得分最高的分块,作为每张结果卡片的代表,同时允许用户展开卡片,查看来自同一视频片段的其他匹配分块:

1`
2
31.  def _hits_payload(hits, exclude_id: str | None = None, k: int = 9):
42.      """One card per clip (best chunk first), counting matched sibling scenes."""
53.      out = []
64.      cards_by_clip = {}
75.      for h in hits:  # hits arrive sorted by score
86.          if h["chunk_id"] == exclude_id:
97.              continue
108.          clip_id = h["clip_id"]
119.          card = cards_by_clip.get(clip_id)
1210.          if card is None:
1311.              card = {**_chunk_payload(h), "more_matches": 0}
1412.              cards_by_clip[clip_id] = card
1513.              out.append(card)
1614.          else:
1715.              # A lower-ranked scene from a clip we already show.
1816.              card["more_matches"] += 1
1917.      return out[:k]
20
21`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
22

这就是为什么我们会在查询时过量获取结果。先获取 50 个命中结果,将其折叠为每个视频片段一张卡片,然后显示 9 张。exclude_id 用于处理_查找相似视频片段_的情况,否则作为种子的视频分块本身可能会再次出现在顶部结果中;而 _chunk_payload 则简单地将每个命中结果裁剪为 UI 所需的字段。more_matches 数量会在 UI 中显示为“来自此视频片段的另外 +4 个结果”徽章。展开该徽章不会再次调用嵌入 API;应用会缓存最近的查询向量,并通过针对该视频片段进行过滤的 kNN 搜索重新执行查询,同时对 clip_id 使用 term 过滤器。

结论:场景分块在规模化场景下的成本

以上就是完整的设置流程;它从监视一个文件夹开始,在场景边界处进行切分,为代理文件生成嵌入,对向量建立索引,最后使用自然语言进行搜索。编辑器输入他们需要的视频画面,系统就会返回相应的视频素材以及时间戳,并提供一种快速获取实际视频片段的方式。

该索引中的每个向量都是 1,024 个 float32 值,大约为 4 KB。即使对于演示来说,这个大小也不算多。我们的 70 个视频片段的文件夹会生成几百个分块,对应几 MB 的向量。但场景分块的规模增长非常快。按照每个场景大约 3 秒计算,1 小时的视频素材已经会产生约 1,200 个向量,因此一个规模适中的 1,000 小时视频档案就会超过 100 万个向量,对应数 GB 的浮点数;而一个拥有数亿个向量的大型视频素材库,其索引规模则会达到 TB 级别。由于 HNSW 希望将这些向量保存在内存中,以便快速搜索,因此成本可能会迅速增加。在本系列的第 2 部分中,我们将比较量化与降维这两种非常不同的缩减索引大小的方法,以及每种方法在召回率方面需要付出的代价。

原文:www.elastic.co/search-labs…


使用 Elasticsearch 和 Jina 进行 AI 视频搜索:精准找到你需要的视频片段秒数》 是转载文章,点击查看原文


相关推荐


Anker 首届黑客松挑战赛|9 月 7 日报名启动
火山引擎Agent社区2026/9/11

AI 时代为什么需要数据底座 在生成式 AI 深入业务的过程中,越来越多团队发现:AI 应用落地的难点,不只在模型本身,也在 AI 时代的数据链路建设。 业务数据在传统数据库里,向量在独立的向量库里,全文检索又是另一套引擎;数据在多个系统间来回搬运,还要接入各类工具和平台,同步成本、数据一致性风险和运维复杂度都在上升。 作为 MongoDB 社区迄今最新的版本,MongoDB 8.3 在读取、写入和复杂查询性能上都有明显提升,并把向量检索与 Auto Embedding 能力带进数据库引擎。 今


【体验毛坯房】Deep Harness 入门教程
程序员三明治2026/9/3

👨‍💻程序员三明治:个人主页 🔥 个人专栏: 《设计模式精解》 《重学数据结构》 《AI探索日志》 《从0带你学深度强化学习》 🤞先做到 再看见! 目录 DeepSeek Harness到底是什么?和CC、Codex这些Agent有什么区别?为什么Harness会火?安装方式**路线 A:npm 一行命令(最省事)****路线 B:交给 AI Agent 帮你安装****路线 C:桌面客户端(小白首选,想自己折腾、看源码、搞插件的,可以用这种方式)*


[SAP ABAP] Excel批量维护货源清单
胡说八道的大双、2026/8/26

在SAP中,货源清单是控制物料只能从特定供应商处采购的主数据,它定义了物料与供应商、工厂、采购组织之间的合法供应关系 相对于逐条使用事务代码 ME01 维护货源清单,开发自定义程序,通过Excel批量维护货源清单,能够降低用户的使用门槛,同时提升用户的工作效率 Excel导入模板 效果展示 用户在Excel导入模板填写相关信息以后,进行文件上传操作 点击执行按钮,效果如下所示: 提示Tips:自定义程序,增设了数据校验逻辑,当用户执行Excel文件上传以后,会进行ALV报


centos flink配置读写hbase
abcy0712132026/8/13

Apache Flink 是一个开源流处理框架,可以用来处理有界和无界的数据流。HBase 是一个开源的、非关系型的分布式数据库,它运行在 Hadoop 上,提供了高可靠性、高性能、列式存储和可伸缩性。将 Flink 配置为读写 HBase,可以有效地结合两者的优势,用于实时数据处理和分析。 以下是如何在 CentOS 系统上配置 Flink 以读写 HBase 的步骤: 1. 安装 Java 确保你的 CentOS 系统上已经安装了 Java。Flink 需要 Java 环境。 sud


从算力到智能体,面向 Agentic AI 的基础设施演进
阿里云大数据AI技术2026/8/4

摘要 当大模型的能力边界不断扩展,真正决定 AI 价值上限的已不再只是算法本身,而是支撑其落地的基础设施体系。本文基于 2026 Agentic AI 超级智能体系统架构峰会演讲,系统阐述了阿里云 PAI 平台如何围绕算力、推理与场景三条主线构建面向 Agentic AI 的全栈基础设施——从数十万卡集群的统一调度与训推一体,到企业级 Token 服务 TokenWorks 的 KV Cache 感知调度与 SLO 保障,再到 Physical AI、自动驾驶、具身智能等场景化方案的落地,以及 


AI名词完整入门教程【看懂各种黑话】
一条泥憨鱼2026/7/27

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临) 🎬精选专栏:数据结构与算法,Java ,AI与Agent 前言: Harness、Loop、MCP、Agent、Skill……每次看到这些词都想关掉页面? 我懂。先别管它们 看一个你大概率会遇到的场景: ▎ 你是一个课程主理人,手头攒了几十份直播逐字稿、一堆学员问答、案例截图、产品说明。你想搞一个「AI 内容生产小助手」——能读你的资料,帮你出公众号文章、小红书文案、课程大纲。拿不准的信息它会先翻知识库,需要配图的时候能自己生


C++11核心特性全解:从C++98到现代C++的全面升级(万字总结)
邪修king2026/7/19

观众老爷们大家好 我是邪修KING 本文属于系列C++ 进阶篇 ,欢迎来到C++进阶篇博客 C++重点语法运用! 一、C++11简介:为什么需要C++11? C++11 是 C++ 的第⼆个主要版本,并且是从 C++98 起的最重要更新。它引⼊了⼤量更改,标准化了既 有实践,并改进了对 C++ 程序员可⽤的抽象。在它最终由 ISO 在 2011 年 8 ⽉ 12 ⽇采纳前,⼈们曾使 ⽤名称“C++0x”,因为它曾被期待在 2010 年之前发布。C++03 与 C++11 期


我开源了 BeeWeave,给 AI Agent 搭一个越用越懂你的知识创作台
超级东哥CyberFD2026/7/11

GitHub 项目地址 : github.com/ptonlix/bee… 事情是这样的。 过去一段时间,我一直在用 Claude Code、Codex、OpenClaw 这些 Agent 做研究、写文章、整理知识。 它们很强,真的很强。你把资料扔进去,它能总结。你给一个主题,它能起草。你让它分析一个仓库,它也能很快摸清结构。 但我反复遇到一个很烦的问题。 每开一个新会话,很多事情都要重新讲一遍。 我以前研究过什么,我对某个问题已经形成了什么判断,上一篇文章留下了哪些线索,哪些资料可信,哪些坑已


FPGA与STM32的双核协奏曲:硬核拆解中速采集卡的高速数据流与双缓冲机制
zlinear数据采集卡2026/7/3

zlinear开源电子 前言 大家好,我是ZLinear的硬件工程师。 在之前的博文中,我们聊了常速采集卡DABL-7606的过采样算法与通信协议。不少读者看后私信问:“张工,如果我的采样率要求更高,比如要到200K甚至500K SPS,同时还要输出多路DDS波形和带加减速的PWM脉冲,单靠一颗STM32还能扛得住吗?” 答案是:很难,且极其吃力。 当采样率攀升到百K级别,且涉及多通道同步、复杂波形输出时,单核MCU的中断响应延迟和DMA总线带宽就会成为明显的瓶颈。为了彻底打破这个性能


开发了一个进阶版Apple健康
神奇的程序员2026/6/25

前言 使用iPhone + Apple Watch组合有段时间了,当初买的时候,想着用它来记录我的跑步数据,但是坚持了没多久,我就懒惰了,手表最大的作用就成了睡眠监测工具了,由于作息一直比较规律(晚11~早7),就没怎么关注过这些。 最近半年时间,时不时的熬夜写开源项目,我开始关注自己的健康状况了,打开系统自带的的健康app把玩了一番,发现它的数据特别全,但是有几个不好用的地方: 首页的内容比较分散,指标都是以列表的形式进行展示的 指标层级较深,需要切来切去,很多指标我更希望将他们展示到一个大

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读