mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
- 新增 `how-to-use-messageBlock.md`,详细介绍 `messageBlock.ts` 的 Redux Slice 及其状态管理、actions 和 selectors。 - 新增 `how-to-use-messageThunk.md`,概述 `messageThunk.ts` 的核心功能和主要 Thunks 的使用。 - 新增 `how-to-use-useMessageOperations.md`,提供 `useMessageOperations` Hook 的使用示例和功能说明,简化组件与消息数据的交互。
106 lines
7.4 KiB
Markdown
106 lines
7.4 KiB
Markdown
# messageThunk.ts 使用指南
|
||
|
||
该文件包含用于管理应用程序中消息流、处理助手交互以及同步 Redux 状态与 IndexedDB 数据库的核心 Thunk Action Creators。主要围绕 `Message` 和 `MessageBlock` 对象进行操作。
|
||
|
||
## 核心功能
|
||
|
||
1. **发送/接收消息**: 处理用户消息的发送,触发助手响应,并流式处理返回的数据,将其解析为不同的 `MessageBlock`。
|
||
2. **状态管理**: 确保 Redux store 中的消息和消息块状态与 IndexedDB 中的持久化数据保持一致。
|
||
3. **消息操作**: 提供删除、重发、重新生成、编辑后重发、追加响应、克隆等消息生命周期管理功能。
|
||
4. **Block 处理**: 动态创建、更新和保存各种类型的 `MessageBlock`(文本、思考过程、工具调用、引用、图片、错误、翻译等)。
|
||
|
||
## 主要 Thunks
|
||
|
||
以下是一些关键的 Thunk 函数及其用途:
|
||
|
||
1. **`sendMessage(userMessage, userMessageBlocks, assistant, topicId)`**
|
||
|
||
- **用途**: 发送一条新的用户消息。
|
||
- **流程**:
|
||
- 保存用户消息 (`userMessage`) 及其块 (`userMessageBlocks`) 到 Redux 和 DB。
|
||
- 检查 `@mentions` 以确定是单模型响应还是多模型响应。
|
||
- 创建助手消息(们)的存根 (Stub)。
|
||
- 将存根添加到 Redux 和 DB。
|
||
- 将核心处理逻辑 `fetchAndProcessAssistantResponseImpl` 添加到该 `topicId` 的队列中以获取实际响应。
|
||
- **Block 相关**: 主要处理用户消息的初始 `MessageBlock` 保存。
|
||
|
||
2. **`fetchAndProcessAssistantResponseImpl(dispatch, getState, topicId, assistant, assistantMessage)`**
|
||
|
||
- **用途**: (内部函数) 获取并处理单个助手响应的核心逻辑,被 `sendMessage`, `resend...`, `regenerate...`, `append...` 等调用。
|
||
- **流程**:
|
||
- 设置 Topic 加载状态。
|
||
- 准备上下文消息。
|
||
- 调用 `fetchChatCompletion` API 服务。
|
||
- 使用 `createStreamProcessor` 处理流式响应。
|
||
- 通过各种回调 (`onTextChunk`, `onThinkingChunk`, `onToolCallComplete`, `onImageGenerated`, `onError`, `onComplete` 等) 处理不同类型的事件。
|
||
- **Block 相关**:
|
||
- 根据流事件创建初始 `UNKNOWN` 块。
|
||
- 实时创建和更新 `MAIN_TEXT` 和 `THINKING` 块,使用 `throttledBlockUpdate` 和 `throttledBlockDbUpdate` 进行节流更新。
|
||
- 创建 `TOOL`, `CITATION`, `IMAGE`, `ERROR` 等类型的块。
|
||
- 在事件完成时(如 `onTextComplete`, `onToolCallComplete`)将块状态标记为 `SUCCESS` 或 `ERROR`,并使用 `saveUpdatedBlockToDB` 保存最终状态。
|
||
- 使用 `handleBlockTransition` 管理非流式块(如 `TOOL`, `CITATION`)的添加和状态更新。
|
||
|
||
3. **`loadTopicMessagesThunk(topicId, forceReload)`**
|
||
|
||
- **用途**: 从数据库加载指定主题的所有消息及其关联的 `MessageBlock`。
|
||
- **流程**:
|
||
- 从 DB 获取 `Topic` 及其 `messages` 列表。
|
||
- 根据消息 ID 列表从 DB 获取所有相关的 `MessageBlock`。
|
||
- 使用 `upsertManyBlocks` 将块更新到 Redux。
|
||
- 将消息更新到 Redux。
|
||
- **Block 相关**: 负责将持久化的 `MessageBlock` 加载到 Redux 状态。
|
||
|
||
4. **删除 Thunks**
|
||
|
||
- `deleteSingleMessageThunk(topicId, messageId)`: 删除单个消息及其所有 `MessageBlock`。
|
||
- `deleteMessageGroupThunk(topicId, askId)`: 删除一个用户消息及其所有相关的助手响应消息和它们的所有 `MessageBlock`。
|
||
- `clearTopicMessagesThunk(topicId)`: 清空主题下的所有消息及其所有 `MessageBlock`。
|
||
- **Block 相关**: 从 Redux 和 DB 中移除指定的 `MessageBlock`。
|
||
|
||
5. **重发/重新生成 Thunks**
|
||
|
||
- `resendMessageThunk(topicId, userMessageToResend, assistant)`: 重发用户消息。会重置(清空 Block 并标记为 PENDING)所有与该用户消息关联的助手响应,然后重新请求生成。
|
||
- `resendUserMessageWithEditThunk(topicId, originalMessage, mainTextBlockId, editedContent, assistant)`: 用户编辑消息内容后重发。先更新用户消息的 `MAIN_TEXT` 块内容,然后调用 `resendMessageThunk`。
|
||
- `regenerateAssistantResponseThunk(topicId, assistantMessageToRegenerate, assistant)`: 重新生成单个助手响应。重置该助手消息(清空 Block 并标记为 PENDING),然后重新请求生成。
|
||
- **Block 相关**: 删除旧的 `MessageBlock`,并在重新生成过程中创建新的 `MessageBlock`。
|
||
|
||
6. **`appendAssistantResponseThunk(topicId, existingAssistantMessageId, newModel, assistant)`**
|
||
|
||
- **用途**: 在已有的对话上下文中,针对同一个用户问题,使用新选择的模型追加一个新的助手响应。
|
||
- **流程**:
|
||
- 找到现有助手消息以获取原始 `askId`。
|
||
- 创建使用 `newModel` 的新助手消息存根(使用相同的 `askId`)。
|
||
- 添加新存根到 Redux 和 DB。
|
||
- 将 `fetchAndProcessAssistantResponseImpl` 添加到队列以生成新响应。
|
||
- **Block 相关**: 为新的助手响应创建全新的 `MessageBlock`。
|
||
|
||
7. **`cloneMessagesToNewTopicThunk(sourceTopicId, branchPointIndex, newTopic)`**
|
||
|
||
- **用途**: 将源主题的部分消息(及其 Block)克隆到一个**已存在**的新主题中。
|
||
- **流程**:
|
||
- 复制指定索引前的消息。
|
||
- 为所有克隆的消息和 Block 生成新的 UUID。
|
||
- 正确映射克隆消息之间的 `askId` 关系。
|
||
- 复制 `MessageBlock` 内容,更新其 `messageId` 指向新的消息 ID。
|
||
- 更新文件引用计数(如果 Block 是文件或图片)。
|
||
- 将克隆的消息和 Block 保存到新主题的 Redux 状态和 DB 中。
|
||
- **Block 相关**: 创建 `MessageBlock` 的副本,并更新其 ID 和 `messageId`。
|
||
|
||
8. **`initiateTranslationThunk(messageId, topicId, targetLanguage, sourceBlockId?, sourceLanguage?)`**
|
||
- **用途**: 为指定消息启动翻译流程,创建一个初始的 `TRANSLATION` 类型的 `MessageBlock`。
|
||
- **流程**:
|
||
- 创建一个状态为 `STREAMING` 的 `TranslationMessageBlock`。
|
||
- 将其添加到 Redux 和 DB。
|
||
- 更新原消息的 `blocks` 列表以包含新的翻译块 ID。
|
||
- **Block 相关**: 创建并保存一个占位的 `TranslationMessageBlock`。实际翻译内容的获取和填充需要后续步骤。
|
||
|
||
## 内部机制和注意事项
|
||
|
||
- **数据库交互**: 通过 `saveMessageAndBlocksToDB`, `updateExistingMessageAndBlocksInDB`, `saveUpdatesToDB`, `saveUpdatedBlockToDB`, `throttledBlockDbUpdate` 等辅助函数与 IndexedDB (`db`) 交互,确保数据持久化。
|
||
- **状态同步**: Thunks 负责协调 Redux Store 和 IndexedDB 之间的数据一致性。
|
||
- **队列 (`getTopicQueue`)**: 使用 `AsyncQueue` 确保对同一主题的操作(尤其是 API 请求)按顺序执行,避免竞态条件。
|
||
- **节流 (`throttle`)**: 对流式响应中频繁的 Block 更新(文本、思考)使用 `lodash.throttle` 优化性能,减少 Redux dispatch 和 DB 写入次数。
|
||
- **错误处理**: `fetchAndProcessAssistantResponseImpl` 内的回调函数(特别是 `onError`)处理流处理和 API 调用中可能出现的错误,并创建 `ERROR` 类型的 `MessageBlock`。
|
||
|
||
开发者在使用这些 Thunks 时,通常需要提供 `dispatch`, `getState` (由 Redux Thunk 中间件注入),以及如 `topicId`, `assistant` 配置对象, 相关的 `Message` 或 `MessageBlock` 对象/ID 等参数。理解每个 Thunk 的职责和它如何影响消息及块的状态至关重要。
|