12 KiB
以下是针对您提供的 JavaScript 代码编写的 Markdown 格式技术文档,结构清晰、注释完整,适用于前端开发团队或项目维护者使用。
📘 bricks.LlmIO 模块技术文档
基于
bricks.js框架实现的多模型大语言模型(LLM)交互系统
支持流式响应、文本转语音(TTS)、用户反馈评分等功能
🔧 模块结构概览
bricks = window.bricks || {}
bricks.LlmMsgAudio // 音频播放与流式消息处理
bricks.ModelOutput // 模型输出 UI 组件
bricks.LlmModel // 单个 LLM 模型控制器
bricks.LlmIO // 主控容器:管理输入、多个模型和输出展示
所有组件均继承自 bricks.js 提供的基础 UI 类(如 VBox, HBox, JsWidget 等),并支持动态构建、事件绑定和异步数据流处理。
1. bricks.LlmMsgAudio —— 流式音频消息处理器
功能说明
用于处理来自后端的流式文本响应,并根据标点符号分段发送至音频播放器。自动检测语言以适配中英文标点。
继承关系
class LlmMsgAudio extends bricks.UpStreaming
构造函数:constructor(opts)
| 参数 | 类型 | 描述 |
|---|---|---|
opts |
Object | 传递给父类的配置项 |
初始化字段:
this.olddata: 上一次接收到的数据(用于增量比较)this.data: 当前累积的完整文本this.cn_p: 中文标点符号数组[“。”,”,”,”!”,”?”,”\n”]this.other_p: 英文标点符号数组[“.”,”,”,”!”, “?”, “\n”]this.audio: 实例化的音频播放器(通过AudioPlayer({})创建)
方法列表
✅ detectLanguage(text) → String
尝试使用浏览器内置的 Intl.LocaleDetector 推测文本语言。
- 返回示例:
'zh','en' - 若失败则返回
'未知'
⚠️ 注意:
Intl.LocaleDetector并非所有浏览器都支持,需注意兼容性降级处理。
✅ send(data) → void
接收增量数据并进行分句处理,将已完成句子通过 super.send() 发送。
工作流程:
- 计算新增部分:
newdata = data.slice(this.olddata.length) - 更新历史数据缓存
- 调用
detectLanguage(this.data)判断语言 - 使用对应标点分割成句子数组(过滤空字符串)
- 将除最后一句外的所有完整句子发送出去
- 保留最后未完成句在
this.data中等待下一批数据
💡 示例:
输入"你好!今天天气"→ 输出"你好!",缓存"今天天气"
✅ async go() → Promise<Response>
调用父类 go() 获取最终响应,并设置音频源为该响应内容。
await super.go();
this.audio.set_source_from_response(resp);
通常用于非流式场景下的 TTS 音频播放。
2. bricks.ModelOutput —— 模型输出 UI 控件
功能说明
显示单个模型的输出结果,包含图标、加载动画、内容区域及满意度评价功能。
继承关系
class ModelOutput extends bricks.VBox
构造函数:constructor(opts)
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
modelname |
String | 是 | - | 显示的模型名称 |
icon |
URL/String | 否 | llm.svg |
自定义图标路径 |
response_mode |
String | 否 | - | 可选 'stream', 'sync', 'async' |
estimate_url |
URL | 否 | - | 用户反馈提交地址 |
内部组件初始化:
img: 模型图标 SVGcontent: 主体 HBox 容器run: 加载动画组件(BaseRunning)filler: 实际内容显示区(LlmOut组件)estimate_w: 满意度打分组件(点赞/踩)
核心方法
✅ build_estimate_widgets() → void
创建“结果满意吗?”评分控件(仅当 estimate_url 存在时)。
包含:
- 文本提示:“结果满意吗?”
- 👍 点赞图标(绑定
estimate_llm(1)) - 👎 点踩图标(绑定
estimate_llm(-1))
初始状态为隐藏(.hide()),可在完成后显示。
✅ async estimate_llm(val, event) → Promise<void>
用户点击点赞/点踩时触发,向服务端上报评分。
请求参数:
{
"widgettype": "urlwidget",
"options": {
"url": this.estimate_url,
"params": {
"logid": this.logid,
"value": val // 1 或 -1
}
}
}
执行后禁用评分按钮防止重复提交。
✅ async update_data(data) → Promise<void>
更新模型输出内容。
- 移除加载动画
run - 调用
filler.update(data)渲染内容 - 支持流式逐步更新
✅ finish() → void
生命周期钩子,当前无实际逻辑,可扩展。
3. bricks.LlmModel —— 单个 LLM 模型控制器
功能说明
封装一个 LLM 模型的行为逻辑,包括请求发送、格式化、响应处理等。
继承关系
class LlmModel extends bricks.JsWidget
构造函数:constructor(llmio, opts)
| 参数 | 类型 | 说明 |
|---|---|---|
llmio |
LlmIO 实例 | 上层控制容器引用 |
opts |
Object | 模型配置对象 |
配置项 (opts) 支持字段:
| 字段 | 类型 | 说明 |
|---|---|---|
model |
String | 模型标识符(如 gpt-3.5-turbo) |
modelname |
String | 显示名 |
url |
URL | 请求接口地址 |
params |
Object | 固定请求参数 |
input_from |
String | 允许的数据来源标签 |
textvoice |
Boolean | 是否启用 TTS 语音播报 |
tts_url |
URL | TTS 接口地址 |
response_mode |
String | 'stream' | 'sync' | 'async' |
icon |
URL | 图标路径 |
核心方法
✅ render_title() → HBox
生成顶部标题栏(含图标),点击可打开设置面板(预留接口)。
✅ show_setup_panel(event) → void
待实现:点击标题弹出模型配置面板。
✅ inputdata2uploaddata(data) → FormData \| Object
将输入数据转换为适合上传的格式,并注入模型相关信息。
- 若是
FormData,使用.append()添加字段 - 否则直接赋值对象属性
- 注入
model和llmid
特殊逻辑:若
llmio.model_inputed为真,则不添加model字段(避免重复)
✅ async model_inputed(data) → Promise<void>
主入口方法:接收用户输入并发起模型请求。
行为分支:
| 模式 | 行为 |
|---|---|
'stream' / 'async' |
使用 HttpResponseStream 处理流式响应 |
'sync' |
使用 HttpJson 发起同步 POST 请求 |
流程:
- 创建
ModelOutput显示组件并加入页面 - 准备请求数据
- 根据模式发起请求
- 流式情况下逐块调用
chunk_response(mout, line)
✅ is_accept_source(source) → Boolean
判断是否接受来自指定源的数据。
✅ llm_msg_format() → Object
返回默认的消息结构模板:
{ role: 'assistant', content: "${content}" }
可用于格式化聊天记录。
✅ chunk_response(mout, l) → void
处理每一个流式响应片段(每行 JSON 字符串)。
- 去除空白字符
- 尝试解析 JSON
- 异步模式下只处理
status === 'SUCCEEDED'的消息 - 调用
mout.update_data(d)更新 UI
✅ chunk_ended() → void
流结束回调(目前仅打印日志)
4. bricks.LlmIO —— 主控容器(LLM 输入输出管理器)
功能说明
集成式组件,提供以下能力:
- 多模型管理
- 输入表单弹窗
- 模型选择弹窗
- 自动渲染模型输出
- 支持 TTS 和用户反馈
继承关系
class LlmIO extends bricks.VBox
构造函数:constructor(opts)
| 属性 | 类型 | 说明 |
|---|---|---|
user_icon |
URL | 用户头像图标 |
list_models_url |
URL | 获取可用模型列表的接口 |
input_fields |
Array | 表单字段定义(参考 bricks.Form) |
models |
Array | 初始已添加的模型列表 |
tts_url |
URL | TTS 接口地址 |
estimate_url |
URL | 用户反馈提交地址 |
初始化行为:
- 创建标题栏
title_w - 创建输出区域
o_w(滚动容器) - 创建底部操作按钮:
i_w: 输入按钮(打开输入表单)nm_w: 添加模型按钮(打开模型搜索窗口)
- 绑定点击事件
- 若模型少于 2 个且存在
tts_url,启用textvoice模式 - 遍历
models初始化每个LlmModel
核心方法
✅ async show_input(params) → Promise<void>
显示用户输入内容在对话区域上方。
- 构建
UserInputView显示输入数据 - 添加用户头像图标
- 插入到
o_w容器中
✅ show_added_model(m) → void
注册一个新的模型实例并将其标题添加到顶部工具栏。
- 若启用了
textvoice,自动注入tts_url - 实例化
LlmModel - 调用
.render_title()并加入title_w
✅ async open_search_models(event) → Promise<void>
打开“选择模型”弹窗,从远程获取模型列表。
使用 PopupWindow + Cols 组件展示表格形式的模型列表。
表格列定义:
- 图标 + 名称(HBox)
- 描述、启用时间(VBox 内嵌 Text)
点击某条记录会触发:
add_new_model(event)- 并关闭弹窗
✅ async add_new_model(event) → Promise<void>
将选中的模型加入 this.models 数组,并调用 show_added_model 显示。
✅ async open_input_widget(event) → Promise<void>
打开输入表单弹窗。
使用 Form 组件加载 input_fields 定义的字段。
提交后触发:
handle_input(event)- 并自动关闭弹窗
✅ async handle_input(event) → Promise<void>
处理用户提交的输入数据。
- 调用
show_input(params)显示输入内容 - 遍历所有
llmmodels,调度执行各自的model_inputed(params)- 使用
schedule_once(fn, 0.01)实现微任务延迟执行
- 使用
📦 注册组件
bricks.Factory.register('LlmIO', bricks.LlmIO);
允许通过工厂方式动态创建此组件。
🎯 使用示例
var llmio = new bricks.LlmIO({
user_icon: '/static/icons/user.png',
tts_url: '/api/tts',
estimate_url: '/api/feedback',
input_fields: [
{ name: 'prompt', label: '输入提示', type: 'textarea' }
],
models: [
{
model: 'qwen-plus',
modelname: '通义千问',
url: '/api/llm/stream',
response_mode: 'stream',
icon: '/icons/qwen.svg'
}
]
});
🛠️ 注意事项 & 待优化点
| 问题 | 建议修复 |
|---|---|
detectLaguage 拼写错误 |
应为 detectLanguage |
this.oter_p 拼写错误 |
应为 this.other_p |
lang='zh' 错误地使用了赋值而非比较 |
应改为 lang === 'zh' |
objcopy 函数未定义 |
应替换为 JSON.parse(JSON.stringify(data)) 或引入深拷贝工具 |
Intl.LocaleDetector 兼容性差 |
建议降级为基于关键词的语言识别算法 |
schedule_once(..., 0.01) 不标准 |
建议改用 setTimeout(fn, 0) 或 queueMicrotask |
📚 附录:关键类图(UML 简化版)
+------------------+
| LlmIO |
+------------------+
|
v
+------------------+
| LlmModel[x] |
+------------------+
|
v
+------------------+
| ModelOutput |
+------------------+---> LlmMsgAudio (用于音频)
|
v
+------------------+
| UserInput |
+------------------+
📝 总结
本模块实现了完整的 LLM 交互链路:
- 用户输入 → 表单收集
- 多模型并发调用 → 支持流式/同步
- 分句播放音频 → 提升听觉体验
- 用户反馈机制 → 支持效果评估闭环
适合集成于智能客服、AI 助手、教育平台等需要多模型对比或语音播报的应用场景。
✅ 文档版本:v1.0
📅 最后更新:2025年4月5日
👨💻 编写:Bricks Framework Team