Skip to main content
OrbitPilot

OrbitPilot 聊天小部件 — 流式、可移动、移动 & 语音

它是什么

OrbitPilot 现在是一个 全球浮动聊天小部件,供已登录用户使用:在角落里的一个 🚐 按钮打开一个面板,您可以在 任何 页面上使用。该面板是 非阻塞 的(在其打开时继续浏览),可拖动,可折叠,并且 记忆其位置 和您打开的对话,随着您在网站上的移动而保持。

新功能

  • 流式回答 — 回复逐字出现,而不是等待后才出现。
  • 停止 — 在回答中途停止 AI。停止会保存迄今为止写的内容,不会消耗您的月度配额。
  • 复制/下载整个聊天 — 面板顶部和底部的按钮(下载为 .txt 文字记录)。
  • 复制单条消息 — 将鼠标悬停在任意气泡上以获取复制图标。
  • 最大化 窗口,浏览您的 聊天历史,并开始 新的对话。
  • 语音输入 — 点击麦克风并讲话;您的话会为您输入。

访客(未登录)则保留原始主页聊天弹出窗口。

在您的手机上(移动)

  • 面板 停靠在屏幕底部,从不溢出边缘,无论方向如何 — 旋转手机会自动重新适配。
  • 它尊重 缺口和主页指示器(安全区域),并充分利用实时屏幕高度,因此浏览器的地址栏无法遮挡发送按钮。
  • 在您 讲话并发送 后,框会为您的下一个问题 清空 — 再次点击麦克风以开始下一轮讲话。

对于开发者

流式传输需要一个 异步视图在 ASGI 下(同步生成器在第一个字节之前缓冲)。orbitpilot.views.orbitpilot_ask_stream 是一个 async def,返回 StreamingHttpResponse,通过一个异步生成器发出服务器发送的事件(meta → token… → done)。所有 ORM/门控在两个 SYNC 帮助程序中运行(_prepare_ask_stream / _finalize_ask_stream),通过 sync_to_async(thread_sensitive=True)。 停止 = 客户端中止抓取 → 异步生成器被取消 → 部分答案被保存,并且配额行不被写入。前端在 templates/_orbitpilot_widget.html + static/css/orbitpilot-widget.css + static/js/orbitpilot-widget.js 中,仅供经过身份验证的用户使用的 base.html 中包含。

移动响应性(工作流 E): 整个小部件是 box-sizing: border-box 因此 1px 边框计算在宽度内(旧 iPhone 溢出是 width:100vw + border)。@media (max-width:575px) 规则在 left/right: env(safe-area-inset-*) + width:auto 下丢弃 100vw,使用 dvh(配有 vh 替代),并用 env(safe-area-inset-bottom) 填充作曲器。在 JS 中,保存的桌面拖动位置在移动视口上 不 应用,resize/orientationchange 监听器通过 applyPos() 重新夹紧位置。 语音清晰: 语音模块保持一个与输入分开的已完成 saved 缓冲区;send() 现在在清空 input.value 时调用一个共享的 resetVoice()(停止识别,清除静音计时器,清空 saved),因此下一轮以空白开始。

聊天字体大小 + 移动发送修复(2026-07-27)

  • A− / A+ 在小部件标题中 会缩小/增大聊天文本。您的选择将在页面和会话之间记住(通过 localStorage 键 op_widget_font 保存)。大小限制在 12−22px 之间。
  • 手机上的发送按钮: 作曲器行现在在狭窄屏幕上保持发送(和麦克风)按钮与文本框可见 — 之前文本框可能会把发送按钮推到右边缘之外。

对于开发者: 标记 templates/_orbitpilot_widget.html,行为 static/js/orbitpilot-widget.js(applyFont()/bumpFont(),在初始化时恢复),样式 static/css/orbitpilot-widget.css。按钮增大 --op-chat-font CSS 变量,由消息正文 + 输入读取;作曲器在文本区域上使用 min-width:0,在按钮上使用 flex:0 0 auto,因此发送永远不会被推出屏幕。

汉堡菜单 + 全屏模式(2026-07-27)

聊天小部件标题现在有一个 ☰ 菜单 和一个 ⧉ 全屏 按钮:

  • 您的说明 — AI 始终考虑的常设笔记(像 ChatGPT 自定义说明)。通过 orbitpilot_custom_instructions 保存至 OrbitPilotSettings.custom_user_prompt;由 custom_prompt 特性限制(如果计划不允许,将出现一个锁定的消息 + 升级链接;服务器也用 403 强制执行)。
  • 下载 — 现在明确有两个选项:“仅此对话” (orbitpilot_conversation_download) 与 “我所有的聊天历史” (新的 orbitpilot_history_download)。工具栏按钮重新标记为 “⬇️ 此聊天”。
  • 记忆 → 现在重建我的记忆 — 完全重建(orbitpilot_rebuild_memory)在确认费用警告后(它重新读取所有内容并重新嵌入,这使用 AI 学分);它不会在 真正 已经在运行的重建时堆叠重建。 (BL-404,2026-09-07) 如果该“正在运行”的构建实际上崩溃或被服务器重启终止 — 被卡在 计划中 或 运行中 超过安全窗口(有后台工作者时 10 分钟,没有时 3 分钟)— 按下按钮现在会自动清除并启动全新的重建,使用 Booklet Inspector 一直使用的相同清除工具(orbitpilot.services.reap_stuck_builds)。响应将表明清除了一次被卡住的构建,而不是假装什么都没发生。在此修复之前,处于该状态的死构建将无限期阻止刷新,没有办法在管理员打开检查器之前解锁它。

全屏模式 (⧉) 在新标签页中打开 /orbitpilot/chat/,类似 ChatGPT/Gemini 样式的全屏聊天,重用相同的小部件(通过 body 类 op-fullpage) — 因此在小部件和全页之间切换保持相同的对话(共享 op_widget_conv localStorage + 一个 storage 事件监听器)。此外:A− / A+ 更改聊天字体(记住),在手机上发送按钮保持在麦克风旁边可见。

对于开发者: 标记 templates/_orbitpilot_widget.html,行为 static/js/orbitpilot-widget.js,样式 static/css/orbitpilot-widget.css;全屏视图 orbitpilot.views.orbitpilot_chat → orbitpilot/templates/orbitpilot/chat_full.html。

快速更新与完全重建(软/硬记忆,2026-07-27)

小部件的 🧠 记忆 菜单现在提供两个重建选项:

  • ⚡ 快速更新(软) — 仅重新读取和重新嵌入自上次构建后您所更改的 项目;未更改的项目保留其现有嵌入,移除的项目被删除。成本更低,因为 OpenAI 嵌入费用与增加量相关,而不是整个语料库。
  • 🔄 完全重建(硬) — 从头开始重新读取和重新嵌入 所有内容(使用更多的 AI 学分)。仅在某些内容看起来不对的情况下使用。

对于开发者: run_memory_build(user, settings, build, incremental=True) 将新的块与存储的块进行比较,通过 (source_key, source_id, chunk_index, content_hash) 键 在 调用 embed_chunks 之前,因此只有新的/更改的块会被嵌入;过期的行在同一原子块中被删除;未更改的行保持不变。模式在 OrbitPilotMemoryBuild.incremental 中携带(迁移 orbitpilot/0025),并通过 orbitpilot_rebuild_memory 设置为 mode=soft|hard。如果省略 incremental,run_memory_build 从构建记录中读取。完全/硬路径保持确切的先前原子删除 + 重新嵌入行为。

聊天驱动的修复(2026-07-28)

分析真实的(已去标识化)OrbitPilot 对话揭示了四个修复:

  • 损坏的 AI 链接 (your-app-link):模型在得到来自过期小册子的相对路径时发明了一个域。现在 (a) 系统健康检查在生产时警告 SITE_URL 是 localhost,以及 (b) orbitpilot.services.heal_links() 会在每个回答中将任何占位符/localhost 链接基础重写为实际网站主机(流式/阻塞/访客) — 所以链接即使在重建之前也能正常工作。永久修复(设置 SITE_URL + 重建)在 管理员设置检查清单 上。
  • “列出我的 Blinks” 现在有效:pipeline/retrieve.py add_list_intent_sources() 在查询为枚举请求时插入源的所有块(“列出/显示/我的所有 blinks/tasks/events”),并且工作区快照采样 Blink 标题 — 使 AI 列出实际项目,而不仅仅是数量。
  • 可点击的下一步操作:操作现在是 {label, url}。一个真实的导航链接呈现为可点击的按钮(在新标签中打开);否则是一个预填充芯片。修复了整个小部件、访客主页模态(之前丢弃了操作)和全页结果。内联答案链接现在也在新标签中打开。
  • 提示优化:核心答案提示停止过度重复用户的标题目标,并优雅地处理“自昨天以来发生了什么变化”(它根据当前快照工作,而不是逐日历史)。

对于开发者: orbitpilot/services.py(heal_links,request_base,split_answer_actions 现在返回字典,访客 next_actions 图层),pipeline/retrieve.py(add_list_intent_sources),adminapp/diagnostics.py(_check_site_url),小部件 JS + home.html(操作呈现 + DOMPurify target=_blank 钩子),aihub/prompt_registry.py(核心 + next_actions 默认值;通过 aihub/0007 在未触动的种子默认值上刷新)。

一个工具栏,而不是两个(2026-08-28)

改变了什么。 小部件曾经绘制同一行按钮 — 新 · 历史 · 复制 · 此聊天 — 两次:一次直接在紫色标题下方,再一次在消息框下方。现在只保留一行,位于消息框下方。

为什么。 报告 #136,来自手机。两个行 chrome 在一个已经短的窗口内使对话显得拥挤。报告是关于对话空间过小的问题。

为什么底部行是保留的。 它是一个拇指在手机上能碰到的行,坐落在您输入的框旁 — 这是“开始新聊天”和“复制此聊天”的位置 — 并且它已经携带了其他行的每个按钮。顶部行的工具提示措辞更清晰,因此它们一并被移动。

没有东西变得无法接触。 标题保留它自己的 ×,因此即使折叠小部件仍然可以关闭;而且关闭保持在登录门之外,因此访客仍然可以关闭小部件。由 orbitpilot/test_widget_toolbar.py 保护。

麦克风:一个意图,一个会话(BL-447,2026-09-09)

所有者报告了聊天麦克风为 “第一次工作,然后第二次不工作,有时会卡住”。生产已经承载了之前的修复,当他说这个时,所以这仍然是其下的内容,不是错过的部署。有三件事是错的,它们解释了三种不同的症状。

1. 按钮可能表示其显示内容的相反意思

点击处理程序通过读取一个变量(wantListening,用户的请求)来决定该做什么,而红色脉动状态是从另一个变量(listening,引擎的实际状态)绘制的。浏览器的 stop() 调用是 异步 的,所以在六秒静默超时后以及每次发送后,存在一个窗口,用户请求已关闭而引擎仍在运行 — 按钮仍然看起来是活动的。一个本意为 停止 的按压因此被读取为 开始,而之前的修复(在其自身的情况下正确)保持那个按压活动,因此引擎重新启动。 按下停止让麦克风重新打开。 同样的间隙的镜像使得第二次按压取消用户的第一次按压,因此麦克风根本没有启动 — 那是“第二次不工作”的原因。

现在有一个变量。micOn 是用户要求的;按钮是从中绘制的,点击读取它,因此它们不能相违。

2. 一个识别对象服务于整个页面

在页面加载时构建了一个 SpeechRecognition 并永远重用。这是唯一的原因,启动可能会失败并出现“无效状态”错误,网络短暂中断或由另一个应用程序占用的麦克风导致的对象仍会卡住,直到页面被重新加载 — “工作一次,然后再也不工作”。网站上的每个其他麦克风(主页捕获框、错误报告者、管理人员口述)已经在每次按压时构建一个新的。聊天小部件现在也这样做,因此每次按压都获得一个干净的引擎。

3. 关闭窗口未释放麦克风

close() 从未停止识别,且当页面被离开时没有任何东西停止它,因此在中间口述时关闭聊天会导致引擎在隐藏面板后继续运行:浏览器的录音指示器保持点亮,重启循环不断重置,单词不断落入一个无人可见的框中。这就是“卡住”的原因。现在关闭窗口和离开页面都会释放麦克风。

您能看到的其他变化

  • 故障说明发生了什么。 阻止许可、未找到麦克风,以及 “该按压未开始任何东西” 看起来曾经是一样的 — 一个灰色按钮和普通的占位符。现在每个都会在消息框中写入自己简短的消息。
  • 损坏的引擎放弃而不是旋转。 口述仍然通过思考暂停自行重启,这是所有麦克风共享的行为,但一直掉落而从未听到语音的会话在尝试几次后停止,并说明了这一点。真正的语音会重新填写那个预算,因此普通的口述永远不会耗尽。
  • 聊天框仅在屏幕上时接收键盘。 口述结束曾经无条件专注输入,这可能会将键盘拉到刚关闭的窗口上。

对于开发者。 消失的会话是 孤立的 — 当前会话引用设置为 null,所有处理程序在接触任何东西之前检查自己的身份 — 因此在发送后晚期的最终结果被忽略,因为它属于一个没人再拥有的会话。这确保了前两个修复试图达到的保证,而不需要一个可能会被保持的标志。逻辑存在于 static/js/orbitpilot-widget.js(initVoice 块)中,其形状被 adminapp/test_widget_mic.py 和 adminapp/test_voice_parity.py 锁定。浏览器语音无法在测试套件中运行;一个真实的 Chromium 冒烟测试是一个另提议的项目。

This guide was translated automatically. Read the English original.

🪐 OrbitPilot

Create a free account and I'll remember your conversations — sign up

🧠 Memory status