消息输入系统(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/open-webui/open-webui/4.2-message-input-system
翻译时间:2026-06-09T16:08:10.304Z
翻译模型:deepseek-chat
原文字符数:15467
项目:Open WebUI (open-webui)
---
消息输入系统
相关源文件
以下文件为本 Wiki 页面的上下文来源:
backend/open_webui/internal/db.pybackend/open_webui/migrations/env.pybackend/open_webui/models/oauth_sessions.pybackend/open_webui/retrieval/loaders/mistral.pybackend/open_webui/routers/configs.pybackend/open_webui/utils/webhook.pysrc/lib/apis/configs/index.tssrc/lib/apis/tools/index.tssrc/lib/apis/users/index.tssrc/lib/components/chat/Chat.sveltesrc/lib/components/chat/MessageInput.sveltesrc/lib/components/chat/MessageInput/Commands/Knowledge.sveltesrc/lib/components/chat/MessageInput/Commands/Models.sveltesrc/lib/components/chat/MessageInput/Commands/Prompts.sveltesrc/lib/components/chat/MessageInput/InputMenu.sveltesrc/lib/components/chat/MessageInput/IntegrationsMenu.sveltesrc/lib/components/chat/Messages.sveltesrc/lib/components/chat/Messages/Message.sveltesrc/lib/components/chat/Messages/MultiResponseMessages.sveltesrc/lib/components/chat/Messages/ResponseMessage.sveltesrc/lib/components/chat/Messages/UserMessage.sveltesrc/lib/components/common/FileItem.sveltesrc/lib/components/common/FileItemModal.sveltesrc/lib/components/common/PDFViewer.sveltesrc/lib/utils/index.tssrc/lib/utils/onedrive-file-picker.ts
本文档说明 MessageInput.svelte 组件在聊天界面中处理用户输入的角色。该组件管理文本输入、文件附件、语音录制、命令建议和输入变量处理,是用户与 AI 聊天系统之间的主要接口。
组件架构
MessageInput.svelte 组件 src/lib/components/chat/MessageInput.svelte:1-1271 是用户输入的主要界面。它通过 RichTextInput.svelte 协调文本编辑、支持拖放的文件处理、语音录制和命令建议。该组件向 Chat.svelte 暴露 setText() 方法(在 src/lib/components/chat/Chat.svelte:121 处绑定为 messageInput),并通过响应式绑定维护状态同步。
组件结构
图:MessageInput 组件架构
graph TB
ChatSvelte["Chat.svelte<br/>bind:this={messageInput}<br/>第 121 行"]
subgraph MessageInputSvelte["MessageInput.svelte"]
subgraph ExportedAPI["公开 API"]
setTextMethod["setText(text, cb)<br/>第 316-334 行"]
end
subgraph ExportedState["导出状态(双向绑定)"]
promptVar["prompt: string<br/>第 130 行"]
filesVar["files: array<br/>第 131 行"]
selectedToolIdsVar["selectedToolIds: string[]<br/>第 133 行"]
selectedFilterIdsVar["selectedFilterIds: string[]<br/>第 134 行"]
featuresVar["imageGenerationEnabled<br/>webSearchEnabled<br/>codeInterpreterEnabled<br/>第 136-138 行"]
end
subgraph ChildComponents["子组件"]
RichTextInputComp["RichTextInput.svelte<br/>bind:this={chatInputElement}<br/>id='chat-input'<br/>第 1157-1174 行"]
VoiceRecordingComp["VoiceRecording.svelte<br/>bind:recording<br/>第 1120-1145 行"]
InputMenuComp["InputMenu.svelte<br/>第 1054-1118 行"]
InputVariablesModalComp["InputVariablesModal.svelte<br/>bind:show={showInputVariablesModal}<br/>第 1007-1011 行"]
IntegrationsMenuComp["IntegrationsMenu.svelte<br/>第 1020-1051 行"]
end
subgraph CoreFunctions["核心处理函数"]
textVariableHandlerFunc["textVariableHandler(text)<br/>第 205-303 行"]
inputVariableHandlerFunc["inputVariableHandler(text)<br/>第 185-203 行"]
uploadFileHandlerFunc["uploadFileHandler(file, process)<br/>第 550-656 行"]
inputFilesHandlerFunc["inputFilesHandler(inputFiles)<br/>第 658-768 行"]
insertTextAtCursorFunc["insertTextAtCursor(text)<br/>第 354-389 行"]
screenCaptureHandlerFunc["screenCaptureHandler()<br/>第 512-548 行"]
end
onChangeReactive["$: onChange({...})<br/>第 167-183 行<br/>状态变化时触发"]
end
ChatSvelte -->|"messageInput.setText()"| setTextMethod
ChatSvelte -->|"bind: props"| ExportedState
ExportedState --> onChangeReactive
onChangeReactive -->|"回调"| ChatSvelte
setTextMethod --> textVariableHandlerFunc
setTextMethod --> inputVariableHandlerFunc
MessageInputSvelte --> RichTextInputComp
MessageInputSvelte --> VoiceRecordingComp
MessageInputSvelte --> InputMenuComp
MessageInputSvelte --> InputVariablesModalComp
MessageInputSvelte --> IntegrationsMenuComp
来源:src/lib/components/chat/MessageInput.svelte:115-183,src/lib/components/chat/Chat.svelte:121
状态同步
状态通过响应式绑定在 MessageInput 和 Chat 之间双向流动。onChange 回调 src/lib/components/chat/MessageInput.svelte:167-183 会在任何状态变化时响应式触发。
表:导出的状态变量
| 变量 | 类型 | 声明位置 | 用途 |
|---|---|---|---|
prompt | string | src/lib/components/chat/MessageInput.svelte:130 | RichTextInput 中的当前文本 |
files | FileItem[] | src/lib/components/chat/MessageInput.svelte:131 | 已上传文件及其状态 |
selectedToolIds | string[] | src/lib/components/chat/MessageInput.svelte:133 | 用于函数调用的活动工具 ID |
selectedFilterIds | string[] | src/lib/components/chat/MessageInput.svelte:134 | 用于管道处理的活跃过滤器 ID |
imageGenerationEnabled | boolean | src/lib/components/chat/MessageInput.svelte:136 | DALL-E/ComfyUI 图像生成开关 |
webSearchEnabled | boolean | src/lib/components/chat/MessageInput.svelte:137 | 网络搜索中间件开关 |
codeInterpreterEnabled | boolean | src/lib/components/chat/MessageInput.svelte:138 | Pyodide/Jupyter 执行开关 |
图:状态同步流程
graph TB
subgraph MessageInputState["MessageInput.svelte 状态"]
promptVar2["prompt<br/>第 130 行"]
filesVar2["files[]<br/>第 131 行"]
toolsVar["selectedToolIds[]<br/>第 133 行"]
filtersVar["selectedFilterIds[]<br/>第 134 行"]
featuresVar2["imageGenerationEnabled<br/>webSearchEnabled<br/>codeInterpreterEnabled<br/>第 136-138 行"]
end
subgraph ReactiveStatement["响应式语句"]
onChangeCall["$: onChange({<br/> prompt,<br/> files: files.filter(...),<br/> selectedToolIds,<br/> selectedFilterIds,<br/> imageGenerationEnabled,<br/> webSearchEnabled,<br/> codeInterpreterEnabled<br/>})<br/>第 167-183 行"]
end
subgraph ChatSvelte["Chat.svelte"]
chatStateVars["Chat 状态变量<br/>通过 bind:prompt={prompt}<br/>bind:files={files} 等绑定"]
processNextInQueue["processNextInQueue(chatIdProp)<br/>第 221 行"]
end
promptVar2 --> onChangeCall
filesVar2 --> onChangeCall
toolsVar --> onChangeCall
filtersVar --> onChangeCall
featuresVar2 --> onChangeCall
onChangeCall -->|"回调参数"| chatStateVars
chatStateVars --> processNextInQueue
onChange 函数是从 Chat.svelte 传入的属性,它接收状态对象,允许 Chat.svelte 管理消息提交和持久化的生命周期 src/lib/components/chat/Chat.svelte:106-107。
来源:src/lib/components/chat/MessageInput.svelte:130-183,src/lib/components/chat/Chat.svelte:174-243
文本输入与富文本编辑
文本输入使用绑定到 chatInputElement 的 RichTextInput.svelte(基于 TipTap 的编辑器)src/lib/components/chat/MessageInput.svelte:1158。该组件分两个顺序阶段处理变量:内置模板变量(例如 {{CLIPBOARD}})和自定义输入变量 {{var|description}}。
变量处理管道
图:变量替换流程
flowchart TD
setTextCall["setText(text, cb)<br/>第 316-334 行<br/>入口点"]
textVarHandler["textVariableHandler(text)<br/>第 205-303 行<br/>await"]
subgraph BuiltInVars["内置模板变量"]
CLIPBOARD["{{CLIPBOARD}}<br/>navigator.clipboard.readText()<br/>第 206-231 行"]
USER_LOCATION["{{USER_LOCATION}}<br/>getUserPosition()<br/>第 233-242 行"]
USER_NAME["{{USER_NAME}}<br/>sessionUser.name<br/>第 246-249 行"]
CURRENT_DATE["{{CURRENT_DATE}}<br/>getFormattedDate()<br/>第 290-293 行"]
end
chatInputSetText["chatInputElement.setText(text)<br/>第 324 行"]
inputVarHandler["inputVariableHandler(text)<br/>第 185-203 行<br/>await"]
extractInputVars["extractInputVariables(text)<br/>来自 $lib/utils<br/>第 186 行"]
showModal["showInputVariablesModal = true<br/>第 194 行<br/>返回 Promise"]
replaceVars["replaceVariables(variableValues)<br/>第 305-314 行"]
setTextCall --> textVarHandler
textVarHandler --> CLIPBOARD
textVarHandler --> USER_LOCATION
textVarHandler --> USER_NAME
textVarHandler --> CURRENT_DATE
textVarHandler --> chatInputSetText
chatInputSetText --> inputVarHandler
inputVarHandler --> extractInputVars
extractInputVars --> showModal
showModal --> replaceVars
支持的内置变量:
{{CLIPBOARD}}:从系统剪贴板读取,并处理剪贴板中的图像数据src/lib/components/chat/MessageInput.svelte:206-231。{{USER_LOCATION}}:通过getUserPosition()获取 GPS 坐标src/lib/components/chat/MessageInput.svelte:233-242。{{USER_NAME}}、{{USER_EMAIL}}、{{USER_BIO}}:从sessionUser获取src/lib/components/chat/MessageInput.svelte:246-263。{{CURRENT_DATE}}、{{CURRENT_TIME}}、{{CURRENT_WEEKDAY}}:动态日期/时间字符串src/lib/components/chat/MessageInput.svelte:290-301。
来源:src/lib/components/chat/MessageInput.svelte:185-334,src/lib/utils/index.ts:55-83
文件上传与处理
系统支持拖放 src/lib/components/chat/MessageInput.svelte:791-804、屏幕截图 src/lib/components/chat/MessageInput.svelte:512-548 以及通过 InputMenu.svelte 选择本地文件 src/lib/components/chat/MessageInput/InputMenu.svelte:70-76。
上传路由
图:文件上传处理流程
graph TB
subgraph InputSources["输入来源"]
DragDrop["onDrop(e)<br/>第 791-804 行"]
FileInputElem["filesInputElement<br/>第 1203-1220 行"]
ScreenCap["screenCaptureHandler()<br/>第 512-548 行"]
end
subgraph Validation["inputFilesHandler(inputFiles)<br/>第 658-768 行"]
MaxCount["检查 $config.file.max_count<br/>第 661-670 行"]
TypeCheck["file.type 检查<br/>第 697 行"]
end
subgraph ImagePath["图像处理路径"]
HeicConvert["convertHeicToJpeg(file)<br/>第 750 行"]
CompressHandler["compressImage(file)<br/>第 703 行"]
ImgFilesArray["files = [...files, {type: 'image', url}]<br/>第 736-741 行"]
end
subgraph DocumentPath["文档处理路径"]
UploadFileFunc["uploadFileHandler(file, process)<br/>第 550-656 行"]
UploadAPI["uploadFile(localStorage.token, file)<br/>第 597 行"]
end
DragDrop --> Validation
FileInputElem --> Validation
ScreenCap --> Validation
Validation -->|"image/*"| ImagePath
Validation -->|"其他"| DocumentPath
ImagePath --> ImgFilesArray
DocumentPath --> UploadAPI
- 图像:如果
temporaryChatEnabled为 true,则通过compressImage()和convertHeicToJpeg()在本地处理src/lib/components/chat/MessageInput.svelte:734-747。 - 文档:通过
uploadFile()API 上传到后端src/lib/components/chat/MessageInput.svelte:597。 - 验证:检查
$config中的max_count和max_sizesrc/lib/components/chat/MessageInput.svelte:661-695。
来源:src/lib/components/chat/MessageInput.svelte:512-804,src/lib/apis/files/index.ts,src/lib/components/chat/MessageInput/InputMenu.svelte:70-76
命令建议
自动补全使用 TipTap 的 Suggestion 插件,触发字符为 @、/ 和 # src/lib/components/chat/MessageInput.svelte:843-961。
触发字符配置:
| 触发字符 | 用途 | 组件 | 行为 |
|---|---|---|---|
@ | 模型覆盖 | Models.svelte | 设置 atSelectedModel src/lib/components/chat/MessageInput.svelte:844-877 |
/ | 命令/提示词 | Prompts.svelte | 插入提示文本或添加知识库 src/lib/components/chat/MessageInput.svelte:880-913 |
# | 知识库/标签 | Knowledge.svelte | 添加知识库或集合 src/lib/components/chat/MessageInput.svelte:915-948 |
每个触发字符使用 getSuggestionRenderer 显示下拉菜单 src/lib/components/chat/MessageInput.svelte:847。
来源:src/lib/components/chat/MessageInput.svelte:843-961,src/lib/components/common/RichTextInput/suggestions.ts
消息提交
表单包裹输入区域,通过 Chat.svelte 中的 createMessagePair() 处理提交。
图:表单提交处理
graph TB
FormElement["<form on:submit|preventDefault><br/>第 1147-1155 行"]
CheckEmpty["if (prompt === '' && files.length === 0)<br/>return<br/>第 1148-1150 行"]
GeneratingCheck["if (generating)<br/>stopResponse()<br/>第 1151-1154 行"]
NotGenerating["if (!generating)<br/>createMessagePair(prompt, files)<br/>第 1188 行"]
FormElement --> CheckEmpty
CheckEmpty --> GeneratingCheck
GeneratingCheck -->|"True"| StopResponse["stopResponse()"]
GeneratingCheck -->|"False"| NotGenerating
提交按钮 src/lib/components/chat/MessageInput.svelte:1221-1265 根据 generating 状态在"发送"和"停止"图标之间切换。
来源:src/lib/components/chat/MessageInput.svelte:1147-1190,src/lib/components/chat/Chat.svelte:1322-1491