news 2026/9/17 6:06:11

Friend 开源项目实战:用 GPT-4o 构建 Smart Facts Collector,将非结构化笔记智能提取并写入 OMI 记忆 API

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Friend 开源项目实战:用 GPT-4o 构建 Smart Facts Collector,将非结构化笔记智能提取并写入 OMI 记忆 API

Friend 开源项目实战:用 GPT-4o 构建 Smart Facts Collector,将非结构化笔记智能提取并写入 OMI 记忆 API

【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend

本文以 Friend 仓库中 plugins/import/manual-import 的 Smart Facts Collector 为对象,讲解如何用 Flask + GPT-4o 搭建一个移动端友好的"事实采集器":它能把读书笔记、会议纪要、学习日志等杂乱文本自动提炼成有上下文、带来源归属的简洁记忆,并逐条提交到 OMI 的/v2/integrations/{app_id}/user/facts记忆接口。读完本文,你将掌握该工具的环境搭建、Omi App 外部集成配置、AI 提取与规则提取双通道降级逻辑,以及完整的源码级运行原理。

工具定位:为什么需要一个"手动导入"事实采集器

Friend(OMI)的核心产品理念是"AI 看到你的屏幕、听到你的对话并告诉你该做什么"。在这个过程中,除了实时对话流,用户往往还希望把线下积累的知识(读书笔记、会议纪要、个人学习日志、灵感清单)沉淀进 OMI 的记忆体系。Smart Facts Collector 正是这样一个"手动导入"通道:

  • 它提供一个移动端优化的 Web 页面(单文件 index.html),在任何手机浏览器上都能打开使用;
  • 后端 app.py 接收原始文本,先用 GPT-4o 智能提炼,提炼失败或未配置 API Key 时自动降级到基于正则的规则提取;
  • 提取出的每条记忆通过 OMI 外部集成 API 单独提交,写入用户自己的记忆库,供 OMI 后续检索与使用。

从仓库结构看,plugins 目录下还包含大量基于同一套/v2/integrations外部集成 API 构建的插件(如 hume-ai、notifications、zapier 等),Smart Facts Collector 与它们共享相同的集成鉴权与提交模型,是理解 OMI 插件生态最直观的入门示例。

环境搭建:从依赖安装到服务启动

1. 安装依赖

项目依赖集中在 requirements.txt 中,版本被精确锁定:

pip install -r requirements.txt

依赖清单(与源码 import 一一对应):

依赖版本用途
Flask3.1.3Web 服务与/submit-memoriesAPI 路由
requests2.34.2向 OMI API 提交事实(requests.post
openai1.3.0调用 GPT-4o 完成智能提取(openai.OpenAI(...)
httpx>=0.23.0, <0.25.0为 OpenAI 客户端提供显式 HTTP 连接池与超时配置

2. 配置 OpenAI API Key(AI 提取必需)

在 app.py 中,API Key 从环境变量读取,这是推荐的安全做法:

# Linux/macOS export OPENAI_API_KEY=your_openai_api_key_here # Windows set OPENAI_API_KEY=your_openai_api_key_here

源码还通过load_dotenv()支持.env文件方式加载环境变量,因此你也可以在项目目录创建.env文件写入OPENAI_API_KEY=...,避免每次手动 export。若只是本地测试,也可直接修改 app.py 中的占位值,但不建议在生产中硬编码密钥。

值得说明的是,OpenAI 客户端在这里被显式配置为不依赖系统代理:httpx.Client(limits=httpx.Limits(max_keepalive_connections=5, max_connections=10), timeout=httpx.Timeout(timeout=30.0)),即最多 5 个保持连接、10 个并发连接、30 秒超时——这是为了规避常见代理环境导致 OpenAI 调用失败的问题。

3. 在 Omi App 中创建"外部集成"应用

这是与 Friend 生态对接的关键一步,原文档给出如下操作路径:

  1. 前往 App Store 安装 Omi AI App;
  2. 在 App 内创建一个新应用,选择"external integration capability"(外部集成能力),并勾选允许"facts"权限;
  3. 进入设置页,复制你的App ID,并生成private key(私钥)
  4. 回到 app.py,将生成好的 App ID 填入APP_ID、private key 填入API_KEY

源码中的对应常量如下:

APP_ID = "01JPP8Y2PA2YWQPTMDAFHXWX8E" # 替换为你自己的 App ID API_KEY = "get_this_api_key_in_omi_app" # 替换为你生成的 private key

其中API_URL会基于 App ID 动态拼出提交地址:

API_URL = f"https://api.omi.me/v2/integrations/{APP_ID}/user/facts"

这一 URL 模式在仓库内被多个插件复用,例如 plugins/composio/src/omi_api.py 中的create_fact使用完全相同的f"{API_BASE_URL}/{APP_ID}/user/facts?uid={user_id}"结构,可见它是 OMI 外部集成写入记忆的标准端点。

4. 启动服务并访问

python app.py

启动后终端会打印配置摘要(API URL、App ID、GPT-4o 提取是否启用等),服务监听http://localhost:5001。由于app.run(host='0.0.0.0', port=5001, debug=True)绑定了0.0.0.0,同一局域网内的手机也可以直接通过http://<电脑IP>:5001访问,这正是"移动端优化"的实际落地方式。

关键访问方式:页面通过 URL 参数?uid=YOUR_USER_ID识别当前用户,例如:

http://localhost:5001/?uid=YOUR_USER_ID

启动日志中也会打印该提示(Access with: http://localhost:5001/?uid=YOUR_USER_ID)。uid会随请求动态传给 OMI API,而不是硬编码在服务端,这是源码中特意注释的改进(USER_ID is now extracted dynamically from requests)。

使用流程:从粘贴文本到记忆入库

  1. 打开页面,在文本框中粘贴内容——支持各种非结构化格式:读书笔记、会议纪要、个人学习日志、要点列表等;
  2. 点击"Extract & Submit Memories"按钮;
  3. 应用依次执行:
    • 若 AI 提取开启(默认开启)且已配置 OpenAI API Key,使用 GPT-4o 智能识别与合并事实;
    • 若 AI 被关闭或不可用,自动降级为规则提取;
    • 展示提取出的每条记忆;
    • 逐条提交到 OMI API 并展示提交结果(成功/失败及错误信息)。

前端 index.html 的几个交互细节值得注意:

  • 页面顶部显示当前User ID,可通过Change按钮随时切换(会同步更新 URL 的uid参数);
  • 若 URL 中没有uid,页面会弹出醒目警告框("No User ID detected!")并禁用提交按钮,从交互层面强制先完成用户身份配置;
  • 提交期间按钮被禁用并显示加载动画,防止重复提交;
  • 每条提取结果以卡片形式展示,成功为绿色边框 + Success 徽章,失败为红色边框 + Failed 徽章并附错误原文;
  • 文本框中预置了示例输入(MrBeast / Made to Stick 两个带标题的要点块),方便首次体验。

源码深读:双通道提取与"记忆合并"策略

app.py 的核心处理链路由/submit-memories路由承载,其设计亮点在于AI 优先、规则兜底、合并上下文三件事。

GPT-4o 智能提取(主通道)

extract_memories_with_gpt是主提取函数,它的系统提示词(system prompt)浓缩了整套提取哲学:

  • 按标题合并:识别带标题的内容块(如 "MrBeast"、"Made to Stick"),把该标题下的要点合并为一条记忆,而不是碎片化成多条;
  • 来源归属开头:每条记忆以From MrBeast: ...From Made to Stick: ...这类短语开头,保留知识来源;
  • 直白具体、去填充词:明确禁止 "The user has learned that..."、"It appears that..." 等空话,并给出 BAD/GOOD 输出对照示例;
  • 长度硬约束:要求每条记忆500 字符以内

调用参数同样服务于"事实性优先":

response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}], temperature=0.2, # 低温,保证输出更事实、更稳定 max_tokens=2000, # 响应总 token 上限 )

返回内容按空行(\n\n)拆分为多条记忆;过短(<20 字符)的记忆被丢弃,超长记忆被截断到MAX_MEMORY_LENGTH = 500字符并追加...。源码中该常量从 2000 调整为 500 并附注释("Reduced from 2000 to 500 characters per memory"),说明设计者有意控制单条记忆体量,以适配 OMI 记忆系统的检索与展示粒度。

规则提取(兜底通道)

当 AI 关闭、API Key 未配置或调用抛异常时,extract_memories_consolidated接手。它同样遵循"合并上下文"思路,核心是一个三级递进的解析策略:

  1. 识别"标题 + 要点"结构:用正则([^\n-]+)(?:\n\s*[-*•]\s*[^\n]+)+匹配类似标题\n- 要点1\n- 要点2的段落,将要点以From {title}:前缀合并成一条记忆;若合并后超过 500 字符,则按标题拆分为多条续接记忆;
  2. 退化为段落提取:若无结构化小节,则按空行切分段落,跳过 <50 字符的短段落,超长段落按 500 字符切块;
  3. 兜底整段切块:若以上都无结果,直接把整段文本按 500 字符切块作为记忆。

这套规则通道保证工具在没有 OpenAI Key 时依然完全可用,只是提取质量从"语义理解"降级为"结构切分"。

提交环节的细节

  • 动态用户标识user_id = data.get('uid')从请求中提取,缺失时返回 400("Please include 'uid' in your request.");
  • 记忆元数据:每条记忆以{"text": memory, "text_source": "other", "text_source_spec": "learning_notes"}提交。text_source为 OMI 约定的来源枚举(如emailsocial_postother),text_source_spec记录更细的来源说明(这里是learning_notes);plugins/composio/src/omi_api.py 中同样强调text_source必须是email/social_post/other之一,可在自定义来源时把真实来源写进text_source_spec
  • 鉴权头{"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
  • 简单限流:从第二条记忆起,每条请求前time.sleep(0.5),即 0.5 秒间隔,防止瞬时打爆 OMI API(README 的 Technical Details 中明确提到 "Basic rate limiting is implemented to prevent API overload");
  • 逐条统计:每条请求独立记录status_codesuccess(以 200 为准),最后汇总成功/失败数、总处理耗时,并在终端打印完整请求体与响应体便于排障。

排查指南:端口冲突与 AI 提取失效

原文档的 Troubleshooting 部分归纳了两类最常见问题:

端口冲突

  • 修改 app.py 末行的app.run(host='0.0.0.0', port=5001, debug=True),把port换成空闲端口;
  • macOS 上 5000 端口常被AirPlay Receiver(隔空播放接收器)占用,可在系统设置 > 通用 > 隔空播放与接力中关闭该服务(README 给出的是 System Preferences > Sharing 路径)。

AI 提取不工作

  1. 确认OPENAI_API_KEY已正确设置(可检查启动日志:若显示GPT-4o extraction: DISABLED则说明未生效);
  2. 查看终端中是否有 API 报错(extract_memories_with_gpt的异常会打印❌ Error using GPT...并自动降级);
  3. 临时切换到规则提取通道继续使用,或检查是否因代理/网络导致 OpenAI 请求超时(源码已通过显式httpx.Client规避常见代理问题)。

扩展思考:把"手动导入"接入更大的记忆体系

从源码层面可以推断,这套工具的提交目标user/facts端点与 OMI 的记忆(memories)体系直接打通:前端把use_ai: true与原始文本一并 POST 到本地 Flask 服务,服务端完成提取后逐条写入 OMI,之后这些记忆即可被 OMI 的对话与记忆检索能力所使用。仓库中 plugins/iq_rating/main.py、plugins/composio/src/omi_api.py 分别展示了/memories/conversations等相邻端点,如果你想进一步扩展,可以让 Smart Facts Collector 支持批量导入、定时同步,或把text_source_spec从固定值改为携带书籍/会议/日期等结构化信息,从而让 OMI 的记忆检索获得更丰富的上下文。

总结

Smart Facts Collector 是一个麻雀虽小、五脏俱全的 OMI 插件示例:它把Flask 服务、GPT-4o 提示工程、正则规则引擎、外部集成鉴权、限流与错误降级完整串在一起。即使不配置任何 OpenAI Key,它也能以规则模式独立运行;配置 Key 后,则能获得"按来源合并、去填充词、500 字上限"的高质量记忆产出。对于想快速把自有知识沉淀进 Friend 记忆体系,或想学习 OMI/v2/integrations集成 API 的开发者,这是仓库中可以直接运行、逐行读懂的最佳起点。

【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 6:05:43

DMA完成通知CPU的机制:从硬件链路到驱动工程实践

1. 先说结论&#xff1a;DMA干完活&#xff0c;靠“敲门”通知CPUDMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;这个技术&#xff0c;在 AI Infra 里几乎是躲不开的。GPU要从主机内存拉权重、NVMe SSD要把模型数据读进内存、网卡要把远端数据搬进本…

作者头像 李华
网站建设 2026/9/17 6:05:07

iOS大文件音视频导入原理与实战指南

1. 项目概述&#xff1a;为什么iOS上导入大容量音视频会让人抓狂&#xff1f;“iOS导入大容量音视频用什么APP&#xff1f;文件处理能力横评”——这句话背后&#xff0c;藏着成千上万普通用户、内容创作者、自媒体剪辑者、教育工作者甚至小型影视团队的真实困境。不是他们不会…

作者头像 李华
网站建设 2026/9/17 6:04:56

100G FPGA UDP上板测试:系统级压力验证实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:04:16

ESP32双模选型避坑指南:Wi-Fi与蓝牙共存的真实边界

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:02:13

OSPF高级配置实战:从邻居状态机到DR选举与多区域设计

简介&#xff1a;一份面向网络工程师及网络技术学习者的OSPF高级配置PPT学习教案&#xff0c;围绕动态路由协议OSPF在实际网络中的进阶应用展开&#xff0c;重点讲解NSSA区域&#xff08;含no-summary参数与LSA 7处理&#xff09;、地址汇总命令、辅助地址的配置规则与应用场景…

作者头像 李华
网站建设 2026/9/17 6:01:08

木鸟短租网爬虫课设:requests+BeautifulSoup+pandas全流程实战

简介&#xff1a;面向大学生数据采集与预处理课程设计的完整项目资料&#xff0c;以木鸟短租网为实战对象&#xff0c;内含爬虫源码和课程设计报告&#xff0c;重点展示requests、BeautifulSoup、Scrapy、Selenium等技术的应用&#xff0c;覆盖数据采集、反爬应对、清洗与预处理…

作者头像 李华