- AI Agent
- 人工智能
- 代码智能体
- 交互助手
【免费下载链接】openchamber
Agentic Development Environment based on OpenCode AI agent
导读
OpenChamber 的packages/web/server/lib/text模块是服务端共享的文本变换工具箱,为 TTS 朗读、通知正文、项目记忆笔记等多个产品面提供统一的文本清洗与摘要能力。本文将带你完整掌握该模块的公开 API、三种处理模式(tts/notification/note)的差异与底层实现,并结合源码与测试用例,说明摘要服务在模型提供商不可用时的本地回退机制,以及如何通过 HTTP 端点正确调用它。
模块定位:不属于任何单一产品面的共享文本管线
在 OpenChamber 服务端,text模块的设计原则是中立——它不被 TTS、通知或笔记任何一个产品面独占,而是为所有需要"把一段文本变成更干净、更简短、适合特定出口的文本"的场景提供共享能力。
值得特别说明的是该模块的历史沿革:它此前通过 opencode.ai 的 Zen 提供商代理模型驱动的摘要能力;由于该提供商不再适用于此用途,摘要功能现已完全本地化——只返回经过清洗/蒸馏的本地回退文本,不再发起任何外部模型调用。这一点在模块文档的 Purpose 一节中有明确交代,也是理解整个模块设计的关键背景。
模块唯一的入口文件为 summarization.js,它同时包含摘要桩函数与全部清洗辅助函数,文件头部注释即声明了三种模式的语义:
/** * Shared text summarization service. * * Modes: * - tts: concise speakable text * - notification: concise notification text * - note: distilled project note */公共导出 API
模块对外暴露以下四个函数:
| 导出函数 | 签名 | 用途 |
|---|---|---|
summarizeText | ({ text, threshold, maxLength, zenModel, mode }) | 摘要入口,API 兼容桩,zenModel被忽略 |
sanitizeForTTS | sanitizeForTTS(text) | 为语音输出清洗文本 |
sanitizeForNotification | sanitizeForNotification(text) | 为紧凑通知正文清洗文本 |
sanitizeForNote | sanitizeForNote(text) | 为短笔记/蒸馏输出清洗文本 |
其中summarizeText的完整签名与默认值如下(见 summarization.js#L119):
export async function summarizeText({ text, threshold = 200, maxLength = 500, zenModel, mode = 'tts' })参数含义:
text:待处理的原始文本,必需。threshold:默认200。当text长度不超过该阈值时,直接判定为"无需摘要"并原样返回清洗结果。maxLength:默认500。蒸馏算法尝试将结果控制在的目标长度。zenModel:历史遗留参数,代码中以void zenModel;显式忽略(见 summarization.js#L120)。mode:默认'tts',决定走哪条清洗/蒸馏管线。
三种模式:tts / notification / note
三个模式对应三条不同的文本出口,清洗策略差异显著。从源码的sanitizeByMode分发逻辑(summarization.js#L65-L69)可以看出:
function sanitizeByMode(text, mode) { if (mode === 'note') return sanitizeForNote(text); if (mode === 'notification') return sanitizeForNotification(text); return sanitizeForTTS(text); }tts:可朗读的语音摘要
sanitizeForTTS是三种清洗器中最激进的一个,目标是让文本读起来自然(见 summarization.js#L10-L26):
- 代码块(```` ```
围栏)与行内代码(` ``)整体替换为空格——避免 TTS 把代码读出来; - 删除 Markdown 强调符号
* _ ~ #,删除行首的$ # >引用符; - 将
| & ; < >等符号替换为空格,移除反斜杠、括号、引号; - 把 URL 替换为可朗读的占位短语
' a link '(例如https://example.com会变成 "a link"); - 移除路径类片段,最终把连续空白折叠为单个空格并
trim()。
典型输入输出对照:
| 输入 | 输出 |
|---|---|
Read \const value = 1` aloud|Read aloud` | |
Before\n```js\nconst value = 1\n```\nAfter | Before After |
notification:紧凑的通知正文
sanitizeForNotification(summarization.js#L28-L44)更注重保真度:
- 行内代码保留内容本身(
`code`→code),仅移除反引号; - 删除列表符号
- * +与标题符号#; - 剥离加粗/斜体的 Markdown 包裹符(
**、__、*、_); - 把 Markdown 链接
text收敛为纯文本text; - 将换行折叠为单个空格,压缩连续空白。
note:蒸馏后的项目记忆笔记
sanitizeForNote(summarization.js#L46-L63)在 notification 的基础上更近一步:额外移除 URL与引号,适合把一段对话内容沉淀为简短的项目记忆条目。
本地回退:摘要的"蒸馏"实现
由于模型提供商不可用,summarizeText的摘要能力由两个本地蒸馏函数承担(见 summarization.js#L71-L111):
distillNoteFallback(text, maxLength)(note 模式):
- 先经
sanitizeForNote清洗; - 剥离常见的 AI 风格前缀,如
In summary:、Here is a note:; - 按句子切分,取第一句作为候选;
- 再按
;:()-与逗号逐级截断到更短的片段; - 理想上限取
min(maxLength, max(32, 原文长度 × 0.65));若候选超长,则截取到idealLimit - 1并追加省略号…。
distillNotificationFallback(text, maxLength)(notification 模式):
- 清洗后按句子切分;
- 优先选取长度 ≥ 20 的第一句话(避免选出残缺碎片),否则回退到第一句或全文;
- 长度上限为
max(20, maxLength)(maxLength非有限数值时取 100); - 超出时截断并追加省略号。
而tts模式走的是纯清洗路径sanitizeByMode,不做句子级蒸馏——因为语音场景优先保证完整性,由上层自行控制篇幅。
响应契约
summarizeText始终返回一个对象(summarization.js#L122-L137):
| 字段 | 说明 |
|---|---|
summary | 本地清洗/蒸馏后的回退文本 |
summarized | 恒为false(模型提供商不可用期间) |
reason | 跳过原因;文本超过阈值时通常为Model summarization provider unavailable |
originalLength | 可选,仅文本超阈值时返回的原始长度 |
summaryLength | 可选,仅文本超阈值时返回的摘要长度 |
注意两条边界分支:
- 文本为空:返回
{ summary: '', summarized: false, reason: 'No text provided' }; - 文本长度 ≤
threshold:返回{ summary: 清洗结果, summarized: false, reason: 'Text under threshold' },此时不附带长度字段。
HTTP 集成:POST /api/text/summarize
该模块通过 TTS 路由注册了一个公开端点(tts/routes.js#L108-L131):
app.post('/api/text/summarize', async (req, res) => { const { text, threshold = 200, maxLength = 500, mode } = req.body || {}; if (!text || typeof text !== 'string' || !text.trim()) { return res.status(400).json({ error: 'Text is required' }); } const result = await summarizeText({ text, threshold, maxLength, mode: typeof mode === 'string' ? mode : 'tts', }); return res.json(result); });实际调用示例(curl):
curl -X POST http://localhost:PORT/api/text/summarize \ -H 'Content-Type: application/json' \ -d '{ "text": "First sentence. Second sentence with the useful insight.", "threshold": 0, "maxLength": 100, "mode": "note" }'预期响应:
{ "summary": "First sentence.", "summarized": false, "reason": "Model summarization provider unavailable" }要点:
text缺失或非字符串时返回400;mode缺省时回退为tts;- 路由的 catch 分支(tts/routes.js#L126-L129)在异常时按
mode选用sanitizeForNote或sanitizeForTTS兜底,保证接口始终能返回一个干净的summary字段。
通知模块中的兼容桩
除了 HTTP 端点,通知模块也直接复用了该管线。template-runtime.js 内部定义了一个同名的summarizeText兼容桩:以threshold: 0、mode: 'notification'调用共享的summarizeText,把targetLength映射为maxLength,并在结果为空时回退返回原文,确保通知正文渲染不因摘要失败而中断。这正是模块文档所说"Add new mode semantics here when multiple product surfaces need the same text pipeline"的实例——多个产品面共享同一条文本管线,而不是各自复制实现。
测试验证:回退行为有据可查
模块的行为由 summarization.test.js 覆盖,三组测试直接印证了核心契约:
- TTS 清洗:验证代码块在剥离 Markdown 标点前被移除,
Read \const value = 1` aloud→Read aloud`; - 不再调用 Zen 提供商:传入
zenModel: 'gpt-5-nano'后断言summarized === false且reason === 'Model summarization provider unavailable',同时校验 notification 蒸馏在 80 字符上限下的省略号截断结果; - note 本地回退:两句话的输入在
maxLength: 100下仅保留第一句,验证"取首句"的蒸馏策略。
这些测试同时是贡献者的行为规范:任何对清洗规则的调整都应在该测试文件中同步补充用例。
给贡献者的维护约定
模块文档在 Notes for contributors 一节给出了三条边界,源码中也一一对应:
- 保持模块中立:不要将本模块重新耦合到 TTS 专属的命名或路由(例如不要在清洗器里加入语音相关的分支);
- 共享模式优先:当多个产品面需要相同的文本管线时,在此处新增模式语义(扩展
sanitizeByMode与fallbackByMode的分发),而不是在其他模块里复制粘贴一套新的清洗器; - 模式化清洗:倾向于为每个模式提供专属的 prompt 与清洗行为,避免在无关模块中重复实现。
小结
packages/web/server/lib/text是 OpenChamber 服务端一条轻量但职责清晰的共享文本管线:对外提供summarizeText这一 API 兼容的摘要入口,内部以三种模式分别驱动 TTS、通知与笔记三种出口的清洗与蒸馏回退;在模型提供商不可用期间,它以完全本地、可测试、行为明确的方式保证了所有调用方的文本输出质量。理解这个模块,有助于你在接入 TTS、通知或记忆笔记功能时,正确选择清洗模式并准确解读summarized: false与reason字段所表达的回退语义。
- AI Agent
- 人工智能
- 代码智能体
- 交互助手
【免费下载链接】openchamber
Agentic Development Environment based on OpenCode AI agent
相关推荐
用 PocketFlow Node 构建带重试与回退机制的 LLM 文本摘要工具
用 PocketFlow Node 构建带重试与回退机制的 LLM 文本摘要工具 本文围绕 Pocket Flow 仓库中 cookbook/pocketflo
人工智能大模型AI Agent工作流自动化RAGLangchain-Chatchat 文档块摘要机制深度解析:SummaryAdapter 与 MapReduce 摘要流水线实战
Langchain Chatchat 文档块摘要机制深度解析:SummaryAdapter 与 MapReduce 摘要流水线实战 在基于 Langchain
桌面应用跨平台workerd 模块回退机制实战指南:用 moduleFallback 动态解析 Worker 模块
workerd 模块回退机制实战指南:用 moduleFallback 动态解析 Worker 模块 导读 workerd 是支撑 Cloudflare Wor
后端语言运行时WebAssembly
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考