对话输入框 Sender
Sender 对齐 Ant Design X 的输入框结构与交互:输入区默认在 Enter 时提交,加载态切换为停止操作,并提供头部、前缀、后缀和底部扩展区域。普通文本模式使用 Textarea;结构化词槽模式直接使用 RichTextEditor,选区、输入法、粘贴、组件节点和光标操作不再由 Sender 单独实现。
- 构建聊天、智能助手或提示词输入区域。
- 输入框需要发送、停止生成、语音输入或粘贴文件等操作。
- 需要把参数、标签和可编辑内容组合为结构化词槽。
通过 v-model 绑定内容,按 Enter 或点击发送按钮触发 submit。Shift + Enter 保留为换行。
把 SenderHeader 放入 header 插槽,可展示引用、附件或上下文信息。展开与收起动画沿用 Ant Design X 的高度和边框过渡。
设置 slot-config 后进入词槽模式。Sender 会把配置转换为 RichTextEditor 的文本和组件节点:input、select、tag 直接使用其内置节点,content 复用输入节点,custom 使用 node-senderCustom 动态插槽。formatResult 只改变最终拼接结果,不改变控件中显示的原始值。词槽模式请从 change、submit 或 getValue() 读取结果。
自定义操作区
Section titled “自定义操作区”prefix、suffix、footer 都是 Vue 插槽。suffix 插槽会替换默认操作按钮,并提供与默认行为一致的 actions。默认情况下 suffix 位于输入区右侧;设置 suffix-placement="footer" 后,suffix 会移动到 .sd-sender-footer 右侧,footer 插槽只负责左侧内容。
SenderSwitch 用于展示与输入框关联的功能开关。
语音采集与流式事件
Section titled “语音采集与流式事件”allow-speech 设为 true 或配置对象后,Sender 使用 getUserMedia + AudioWorklet 采集单声道 Float32 PCM。组件本身不调用浏览器语音识别,也不会把识别文本写入输入框;业务可以通过 speech-start、speech-data、speech-end 和 speech-error 把音频交给任意第三方 SDK。
每个 speech-data 都包含可直接传输的 ArrayBuffer、当前 sampleRate、从 0 开始的 sequence 和高精度 timestamp。默认每 4096 个采样点抛出一块数据,可用 bufferSize 调整。
直接连接后端时,在 allow-speech 配置中传入 ws:// 或 wss:// 地址即可:
<sd-sender :allow-speech="{ url: 'wss://api.example.com/asr/stream', protocols: 'pcm-f32', bufferSize: 4096, }" @speech-transport-message="handleRecognitionResult" @speech-error="handleSpeechError"/>连接建立后,Sender 先发送一条 JSON 元数据:
{ "type": "start", "format": "pcm-f32", "channels": 1, "sampleRate": 48000, "bufferSize": 4096 }随后连续发送 AudioWorklet 产生的二进制 ArrayBuffer;结束时发送 {"type":"end","reason":"manual"} 并正常关闭连接。后端不需要元数据帧时可设置 sendMetadata: false。服务端返回的流式识别结果通过 speech-transport-message 原样透出。
Agent 工作流
Section titled “Agent 工作流”根据当前 Agent 切换 skill 和 slot-config,并组合 SenderSwitch、自适应高度、加载与停止操作,构成完整的 AI 输入工作流。
通过组件实例调用 insert()、focus()、clear() 和 getValue()。插入操作支持开头、末尾和当前光标位置。
默认使用 Enter 发送、Shift + Enter 换行;设置 submit-type="shiftEnter" 后两者行为互换。
自适应高度与状态
Section titled “自适应高度与状态”auto-size 可限制自适应输入区的最小和最大行数。只读状态保留内容查看能力,hover、点击或尝试修改时都会显示 Tooltip;readonly 传入字符串可自定义提示文案。禁用状态同时关闭输入和操作。
剪贴板只包含文件时触发 paste-file,可配合 SenderHeader 展示待发送文件;普通文本粘贴仍写入输入框。
<sender> Props
Section titled “<sender> Props”| 参数名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| v-model | 输入内容;词槽模式下不作为结构化内容的状态源 | string |
- |
| default-value | 非受控模式默认内容 | string |
'' |
| loading | 加载中,默认发送按钮切换为停止按钮 | boolean |
false |
| readonly | 是否只读;传入字符串时作为只读提示文案 | boolean | string |
false |
| disabled | 是否禁用 | boolean |
false |
| submit-type | 提交快捷键模式 | 'enter' | 'shiftEnter' |
'enter' |
| slot-config | 结构化词槽配置 | SenderSlotConfig[] |
- |
| skill | 技能标签配置 | SenderSkill |
- |
| allow-speech | AudioWorklet 语音采集、WebSocket 传输或受控录音配置 | boolean | SenderSpeechConfig |
false |
| auto-size | 输入区自适应高度 | boolean | { minRows?: number; maxRows?: number } |
{ maxRows: 8 } |
| placeholder | 占位文本 | string |
- |
| show-actions | 是否显示后缀操作区 | boolean |
true |
| suffix-placement | 后缀操作区位置;footer 时位于 footer 右侧 |
'content' | 'footer' |
'content' |
| components | 替换内部输入组件 | { input?: Component } |
- |
| class-names | 语义化节点类名 | Partial<Record<SenderSemanticType, string>> |
- |
| styles | 语义化节点样式 | Partial<Record<SenderSemanticType, CSSProperties>> |
- |
<sender> Events
Section titled “<sender> Events”| 事件名 | 描述 | 参数 |
|---|---|---|
| update:model-value | 输入内容变化 | value: string |
| change | 普通输入或结构化词槽变化 | value, event, slotConfig, skill |
| submit | 点击发送或使用提交快捷键 | value, slotConfig, skill |
| cancel | 加载态点击停止按钮 | - |
| paste | 粘贴内容 | event: ClipboardEvent |
| paste-file | 剪贴板仅包含文件时 | files: FileList |
| focus | 输入区获取焦点 | event: FocusEvent |
| blur | 输入区失去焦点 | event: FocusEvent |
| speech-start | 开始采集;受控模式下表示开始意图 | SenderSpeechStartEvent |
| speech-data | AudioWorklet 产生一块 PCM 流数据 | SenderSpeechDataEvent |
| speech-end | 采集结束并完成资源释放 | SenderSpeechEndEvent |
| speech-error | 麦克风、音频上下文、Worklet 或传输失败 | SenderSpeechErrorEvent |
| speech-transport-open | WebSocket 连接已建立 | { event, socket } |
| speech-transport-message | 收到后端流式消息 | { event, socket } |
| speech-transport-close | WebSocket 连接已关闭 | { event, socket } |
<sender> Slots
Section titled “<sender> Slots”| 插槽名 | 描述 | 参数 |
|---|---|---|
| header | 输入区上方的头部面板 | { actions } |
| prefix | 输入区左侧内容 | { actions } |
| suffix | 输入区右侧操作区;使用后替换默认操作 | { actions } |
| footer | Footer 左侧内容;不再独立控制整个 footer 是否显示 | { actions } |
| skill-title | 自定义技能标题 | { skill } |
| skill-close-icon | 自定义技能关闭图标 | { skill } |
| slot-key | 自定义 custom 词槽 |
{ value, item, disabled, readonly, onChange } |
actions 包含 send、clear、cancel、speech 以及对应的禁用状态、recording 和 loading。
SenderSpeechConfig
Section titled “SenderSpeechConfig”| 参数名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| recording | 受控录音状态;与 onRecordingChange 同时提供时,Sender 不采集音频 |
boolean |
- |
| onRecordingChange | 受控状态回调,或监听内部采集状态 | (recording: boolean) => void |
- |
| audioConstraints | 传给 getUserMedia 的音频约束 |
MediaTrackConstraints |
true |
| bufferSize | 每个 speech-data 的 Float32 采样点数量 |
number |
4096 |
| workletUrl | 自定义 AudioWorklet 模块地址 | string |
内置模块 |
| processorName | 自定义 Worklet processor 名称 | string |
'sd-sender-audio-processor' |
| processorOptions | 额外的 Worklet processorOptions |
Record<string, unknown> |
- |
| url | 自动流式发送 buffer 的 WebSocket 地址 | string |
- |
| protocols | WebSocket 子协议 | string | string[] |
- |
| sendMetadata | 是否在音频二进制流前后发送 start/end 元数据 | boolean |
true |
如果同时传入 recording 与 onRecordingChange,Sender 保持受控模式兼容:点击按钮只回调期望状态,并抛出 speech-start / speech-end 意图事件,不会申请麦克风。第三方 SDK 可以据此完全接管录音生命周期。
<sender> Methods
Section titled “<sender> Methods”| 方法名 | 描述 |
|---|---|
| focus(options?) | 聚焦输入区,可指定 start、end、all 或 slot |
| blur() | 取消焦点 |
| insert(value, position?, replaceCharacters?, preventScroll?) | 在开头、结尾或光标处插入文本/词槽 |
| clear() | 清空输入;保留传入的 skill 配置 |
| getValue() | 返回 { value, slotConfig, skill } |
SenderSlotConfig
Section titled “SenderSlotConfig”| type | 关键配置 | 说明 |
|---|---|---|
| text | value |
RichTextEditor 文本节点 |
| input | key、props.defaultValue、props.placeholder |
内联输入框 |
| select | key、props.options、props.defaultValue |
内联选择器 |
| tag | key、props.label、props.value |
不可编辑标签 |
| content | key、props.defaultValue、props.placeholder |
复用 RichTextEditor 输入节点 |
| custom | key、customRender 或 slot-key |
自定义控件 |
所有非 text 词槽都需要唯一 key;所有类型都可以通过 formatResult(value) 格式化最终结果。词槽配置是 Sender 的兼容适配层,编辑状态与 DOM 行为以 RichTextEditor 为唯一实现。
<sender-header> Props / Events
Section titled “<sender-header> Props / Events”| 参数名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| v-model:open | 是否展开 | boolean |
false |
| title | 标题 | VNodeChild |
- |
| closable | 是否显示关闭按钮 | boolean |
true |
| force-render | 关闭后是否保留内容 DOM | boolean |
false |
关闭按钮触发 update:open 和 open-change。
<sender-switch> Props / Events / Slots
Section titled “<sender-switch> Props / Events / Slots”| 参数名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| v-model | 是否选中 | boolean |
- |
| default-value | 非受控默认值 | boolean |
false |
| disabled | 是否禁用 | boolean |
false |
| loading | 是否加载中 | boolean |
false |
状态变化触发 change(checked);checked、unchecked、icon 和默认插槽可定制内容。