@lobehub/chat 1.77.16 → 1.77.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/contributing/Basic/Architecture.md +1 -1
- package/contributing/Basic/Architecture.zh-CN.md +1 -1
- package/contributing/Basic/Chat-API.md +326 -108
- package/contributing/Basic/Chat-API.zh-CN.md +313 -133
- package/contributing/Basic/Contributing-Guidelines.md +7 -4
- package/contributing/Basic/Contributing-Guidelines.zh-CN.md +7 -6
- package/contributing/Home.md +5 -5
- package/contributing/State-Management/State-Management-Intro.md +1 -1
- package/contributing/State-Management/State-Management-Intro.zh-CN.md +1 -1
- package/docker-compose/local/docker-compose.yml +2 -1
- package/locales/ar/components.json +4 -0
- package/locales/ar/modelProvider.json +1 -0
- package/locales/ar/models.json +8 -5
- package/locales/ar/tool.json +21 -1
- package/locales/bg-BG/components.json +4 -0
- package/locales/bg-BG/modelProvider.json +1 -0
- package/locales/bg-BG/models.json +8 -5
- package/locales/bg-BG/tool.json +21 -1
- package/locales/de-DE/components.json +4 -0
- package/locales/de-DE/modelProvider.json +1 -0
- package/locales/de-DE/models.json +8 -5
- package/locales/de-DE/tool.json +21 -1
- package/locales/en-US/components.json +4 -0
- package/locales/en-US/modelProvider.json +1 -0
- package/locales/en-US/models.json +8 -5
- package/locales/en-US/tool.json +21 -1
- package/locales/es-ES/components.json +4 -0
- package/locales/es-ES/modelProvider.json +1 -0
- package/locales/es-ES/models.json +7 -4
- package/locales/es-ES/tool.json +21 -1
- package/locales/fa-IR/components.json +4 -0
- package/locales/fa-IR/modelProvider.json +1 -0
- package/locales/fa-IR/models.json +7 -4
- package/locales/fa-IR/tool.json +21 -1
- package/locales/fr-FR/components.json +4 -0
- package/locales/fr-FR/modelProvider.json +1 -0
- package/locales/fr-FR/models.json +8 -5
- package/locales/fr-FR/tool.json +21 -1
- package/locales/it-IT/components.json +4 -0
- package/locales/it-IT/modelProvider.json +1 -0
- package/locales/it-IT/models.json +7 -4
- package/locales/it-IT/tool.json +21 -1
- package/locales/ja-JP/components.json +4 -0
- package/locales/ja-JP/modelProvider.json +1 -0
- package/locales/ja-JP/models.json +8 -5
- package/locales/ja-JP/tool.json +21 -1
- package/locales/ko-KR/components.json +4 -0
- package/locales/ko-KR/modelProvider.json +1 -0
- package/locales/ko-KR/models.json +8 -5
- package/locales/ko-KR/tool.json +21 -1
- package/locales/nl-NL/components.json +4 -0
- package/locales/nl-NL/modelProvider.json +1 -0
- package/locales/nl-NL/models.json +8 -5
- package/locales/nl-NL/tool.json +21 -1
- package/locales/pl-PL/components.json +4 -0
- package/locales/pl-PL/modelProvider.json +1 -0
- package/locales/pl-PL/models.json +8 -5
- package/locales/pl-PL/tool.json +21 -1
- package/locales/pt-BR/components.json +4 -0
- package/locales/pt-BR/modelProvider.json +1 -0
- package/locales/pt-BR/models.json +7 -4
- package/locales/pt-BR/tool.json +21 -1
- package/locales/ru-RU/components.json +4 -0
- package/locales/ru-RU/modelProvider.json +1 -0
- package/locales/ru-RU/models.json +7 -4
- package/locales/ru-RU/tool.json +21 -1
- package/locales/tr-TR/components.json +4 -0
- package/locales/tr-TR/modelProvider.json +1 -0
- package/locales/tr-TR/models.json +8 -5
- package/locales/tr-TR/tool.json +21 -1
- package/locales/vi-VN/components.json +4 -0
- package/locales/vi-VN/modelProvider.json +1 -0
- package/locales/vi-VN/models.json +8 -5
- package/locales/vi-VN/tool.json +21 -1
- package/locales/zh-CN/components.json +4 -0
- package/locales/zh-CN/modelProvider.json +1 -0
- package/locales/zh-CN/models.json +9 -6
- package/locales/zh-CN/tool.json +30 -1
- package/locales/zh-TW/components.json +4 -0
- package/locales/zh-TW/modelProvider.json +1 -0
- package/locales/zh-TW/models.json +7 -4
- package/locales/zh-TW/tool.json +21 -1
- package/package.json +1 -1
- package/src/app/(backend)/webapi/models/[provider]/pull/route.ts +34 -0
- package/src/app/(backend)/webapi/{chat/models → models}/[provider]/route.ts +1 -2
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Ollama/index.tsx +0 -7
- package/src/app/[variants]/(main)/settings/provider/(detail)/ollama/CheckError.tsx +1 -1
- package/src/components/FormAction/index.tsx +1 -1
- package/src/database/models/__tests__/aiProvider.test.ts +100 -0
- package/src/database/models/aiProvider.ts +11 -1
- package/src/features/Conversation/Error/OllamaBizError/InvalidOllamaModel.tsx +43 -0
- package/src/features/Conversation/Error/OllamaDesktopSetupGuide/index.tsx +61 -0
- package/src/features/Conversation/Error/index.tsx +7 -0
- package/src/features/DevPanel/SystemInspector/ServerConfig.tsx +18 -2
- package/src/features/DevPanel/SystemInspector/index.tsx +25 -6
- package/src/features/OllamaModelDownloader/index.tsx +149 -0
- package/src/libs/agent-runtime/AgentRuntime.ts +6 -0
- package/src/libs/agent-runtime/BaseAI.ts +7 -0
- package/src/libs/agent-runtime/ollama/index.ts +84 -2
- package/src/libs/agent-runtime/openrouter/__snapshots__/index.test.ts.snap +24 -3263
- package/src/libs/agent-runtime/openrouter/fixtures/frontendModels.json +25 -0
- package/src/libs/agent-runtime/openrouter/fixtures/models.json +0 -3353
- package/src/libs/agent-runtime/openrouter/index.test.ts +56 -1
- package/src/libs/agent-runtime/openrouter/index.ts +9 -4
- package/src/libs/agent-runtime/types/index.ts +1 -0
- package/src/libs/agent-runtime/types/model.ts +44 -0
- package/src/libs/agent-runtime/utils/streams/index.ts +1 -0
- package/src/libs/agent-runtime/utils/streams/model.ts +110 -0
- package/src/locales/default/components.ts +4 -0
- package/src/locales/default/modelProvider.ts +1 -0
- package/src/locales/default/tool.ts +30 -1
- package/src/server/modules/SearXNG.ts +10 -2
- package/src/server/routers/tools/__test__/search.test.ts +3 -1
- package/src/server/routers/tools/search.ts +10 -2
- package/src/services/__tests__/models.test.ts +21 -0
- package/src/services/_url.ts +4 -1
- package/src/services/chat.ts +1 -1
- package/src/services/models.ts +153 -7
- package/src/services/search.ts +2 -2
- package/src/store/aiInfra/slices/aiModel/action.ts +1 -1
- package/src/store/aiInfra/slices/aiProvider/action.ts +2 -1
- package/src/store/chat/slices/builtinTool/actions/searXNG.test.ts +28 -8
- package/src/store/chat/slices/builtinTool/actions/searXNG.ts +22 -5
- package/src/store/user/slices/modelList/action.test.ts +2 -2
- package/src/store/user/slices/modelList/action.ts +1 -1
- package/src/tools/web-browsing/Portal/Search/index.tsx +1 -1
- package/src/tools/web-browsing/Render/Search/SearchQuery/SearchView.tsx +1 -1
- package/src/tools/web-browsing/Render/Search/SearchQuery/index.tsx +1 -1
- package/src/tools/web-browsing/Render/Search/SearchResult/index.tsx +1 -1
- package/src/tools/web-browsing/components/CategoryAvatar.tsx +27 -0
- package/src/tools/web-browsing/components/SearchBar.tsx +84 -4
- package/src/tools/web-browsing/const.ts +26 -0
- package/src/tools/web-browsing/index.ts +58 -28
- package/src/tools/web-browsing/systemRole.ts +62 -1
- package/src/types/tool/search.ts +10 -1
- package/src/app/[variants]/(main)/settings/llm/ProviderList/Ollama/Checker.tsx +0 -73
- package/src/app/[variants]/(main)/settings/provider/(detail)/ollama/OllamaModelDownloader/index.tsx +0 -127
- package/src/features/Conversation/Error/OllamaBizError/InvalidOllamaModel/index.tsx +0 -154
- package/src/features/Conversation/Error/OllamaBizError/InvalidOllamaModel/useDownloadMonitor.ts +0 -29
- package/src/helpers/url.ts +0 -17
- package/src/services/__tests__/ollama.test.ts +0 -28
- package/src/services/ollama.ts +0 -83
- /package/src/{app/[variants]/(main)/settings/provider/(detail)/ollama → features}/OllamaModelDownloader/useDownloadMonitor.ts +0 -0
@@ -1,174 +1,354 @@
|
|
1
|
-
#
|
1
|
+
# Lobe Chat API 前后端交互逻辑
|
2
2
|
|
3
|
-
|
3
|
+
本文档说明了 Lobe Chat API 在前后端交互中的实现逻辑,包括事件序列和涉及的核心组件。
|
4
4
|
|
5
5
|
#### TOC
|
6
6
|
|
7
|
-
- [
|
8
|
-
|
9
|
-
|
10
|
-
- [前端实现](#前端实现)
|
11
|
-
- [前端集成](#前端集成)
|
12
|
-
- [使用流式获取结果](#使用流式获取结果)
|
7
|
+
- [交互时序图](#交互时序图)
|
8
|
+
- [主要步骤说明](#主要步骤说明)
|
9
|
+
- [AgentRuntime 说明](#agentruntime-说明)
|
13
10
|
|
14
|
-
##
|
11
|
+
## 交互时序图
|
15
12
|
|
16
|
-
|
13
|
+
```mermaid
|
14
|
+
sequenceDiagram
|
15
|
+
participant Client as 前端客户端
|
16
|
+
participant ChatService as 前端 ChatService
|
17
|
+
participant ChatAPI as 后端 Chat API
|
18
|
+
participant AgentRuntime as AgentRuntime
|
19
|
+
participant ModelProvider as 模型提供商 API
|
20
|
+
participant PluginGateway as 插件网关
|
17
21
|
|
18
|
-
|
22
|
+
Client->>ChatService: 调用 createAssistantMessage
|
23
|
+
Note over ChatService: 处理消息、工具和参数
|
19
24
|
|
20
|
-
|
25
|
+
ChatService->>ChatService: 调用 getChatCompletion
|
26
|
+
Note over ChatService: 准备请求参数
|
21
27
|
|
22
|
-
|
23
|
-
export const POST = async (req: Request) => {
|
24
|
-
const payload = (await req.json()) as OpenAIChatStreamPayload;
|
28
|
+
ChatService->>ChatAPI: 发送 POST 请求到 /webapi/chat/[provider]
|
25
29
|
|
26
|
-
|
30
|
+
ChatAPI->>AgentRuntime: 初始化 AgentRuntime
|
31
|
+
Note over AgentRuntime: 通过 provider 和 用户配置创建运行时
|
27
32
|
|
28
|
-
|
29
|
-
|
33
|
+
ChatAPI->>AgentRuntime: 调用 chat 方法
|
34
|
+
AgentRuntime->>ModelProvider: 发送 chat completion 请求
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
```
|
36
|
+
ModelProvider-->>AgentRuntime: 返回流式响应
|
37
|
+
AgentRuntime-->>ChatAPI: 处理响应并返回 stream
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
if (error.error) {
|
63
|
-
errorResult = error.error;
|
64
|
-
} else if (error.cause) {
|
65
|
-
errorResult = error.cause;
|
66
|
-
}
|
67
|
-
// 如果没有其他请求错误,错误对象是一个类似 Response 的对象
|
68
|
-
else {
|
69
|
-
errorResult = { headers: error.headers, stack: error.stack, status: error.status };
|
70
|
-
}
|
71
|
-
console.error(errorResult);
|
72
|
-
// 返回错误响应
|
73
|
-
return createErrorResponse(ChatErrorType.OpenAIBizError, {
|
74
|
-
endpoint: openai.baseURL,
|
75
|
-
error: errorResult,
|
76
|
-
});
|
77
|
-
}
|
78
|
-
console.error(error);
|
79
|
-
return createErrorResponse(ChatErrorType.InternalServerError, {
|
80
|
-
endpoint: openai.baseURL,
|
81
|
-
error: JSON.stringify(error),
|
82
|
-
});
|
83
|
-
}
|
84
|
-
};
|
39
|
+
ChatAPI-->>ChatService: 流式返回 SSE 响应
|
40
|
+
|
41
|
+
ChatService->>ChatService: 使用 fetchSSE 处理流式响应
|
42
|
+
Note over ChatService: 通过 fetchEventSource 处理事件流
|
43
|
+
|
44
|
+
loop 对于每个数据块
|
45
|
+
ChatService->>ChatService: 处理不同类型的事件 (text, tool_calls, reasoning 等)
|
46
|
+
ChatService-->>Client: 通过 onMessageHandle 回调返回当前块
|
47
|
+
end
|
48
|
+
|
49
|
+
ChatService-->>Client: 通过 onFinish 回调返回完整结果
|
50
|
+
|
51
|
+
Note over ChatService,ModelProvider: 插件调用场景
|
52
|
+
ModelProvider-->>ChatService: 返回包含 tool_calls 的响应
|
53
|
+
ChatService->>ChatService: 解析工具调用
|
54
|
+
ChatService->>ChatService: 调用 runPluginApi
|
55
|
+
ChatService->>PluginGateway: 发送插件请求到网关
|
56
|
+
PluginGateway-->>ChatService: 返回插件执行结果
|
57
|
+
ChatService->>ModelProvider: 将插件结果返回给模型
|
58
|
+
ModelProvider-->>ChatService: 基于插件结果生成最终响应
|
59
|
+
|
60
|
+
Note over ChatService,ModelProvider: 预设任务场景
|
61
|
+
Client->>ChatService: 触发预设任务(如自动翻译、搜索等)
|
62
|
+
ChatService->>ChatService: 调用 fetchPresetTaskResult
|
63
|
+
ChatService->>ChatAPI: 发送预设任务请求
|
64
|
+
ChatAPI-->>ChatService: 返回任务结果
|
65
|
+
ChatService-->>Client: 通过回调函数返回结果
|
85
66
|
```
|
86
67
|
|
87
|
-
##
|
68
|
+
## 主要步骤说明
|
88
69
|
|
89
|
-
|
70
|
+
1. **客户端发起请求**:客户端调用前端 ChatService 的 createAssistantMessage 方法。
|
90
71
|
|
91
|
-
|
72
|
+
2. **前端处理请求**:
|
92
73
|
|
93
|
-
|
74
|
+
- `src/services/chat.ts` 对消息、工具和参数进行预处理
|
75
|
+
- 调用 getChatCompletion 准备请求参数
|
76
|
+
- 使用 `src/utils/fetch/fetchSSE.ts` 发送请求到后端 API
|
94
77
|
|
95
|
-
|
78
|
+
3. **后端处理请求**:
|
96
79
|
|
97
|
-
|
80
|
+
- `src/app/(backend)/webapi/chat/[provider]/route.ts` 接收请求
|
81
|
+
- 初始化 AgentRuntime
|
82
|
+
- 根据用户配置和提供商创建相应的模型实例
|
98
83
|
|
99
|
-
|
84
|
+
4. **模型调用**:
|
100
85
|
|
101
|
-
|
86
|
+
- `src/libs/agent-runtime/AgentRuntime.ts` 调用相应模型提供商的 API
|
87
|
+
- 返回流式响应
|
102
88
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
89
|
+
5. **处理响应**:
|
90
|
+
|
91
|
+
- 后端将模型响应转换为 Stream 返回
|
92
|
+
- 前端通过 fetchSSE 和 [fetchEventSource](https://github.com/Azure/fetch-event-source) 处理流式响应
|
93
|
+
- 对不同类型的事件(文本、工具调用、推理等)进行处理
|
94
|
+
- 通过回调函数将结果传递回客户端
|
109
95
|
|
110
|
-
|
111
|
-
getChatCompletion(payload: OpenAIChatStreamPayload, fetchOptions?: FetchOptions) {
|
112
|
-
// 实现细节...
|
113
|
-
}
|
96
|
+
6. **插件调用场景**:
|
114
97
|
|
115
|
-
|
116
|
-
runPluginApi(payload: PluginRequestPayload, fetchOptions?: FetchOptions) {
|
117
|
-
// 实现细节...
|
118
|
-
}
|
98
|
+
当 AI 模型在响应中返回 `tool_calls` 字段时,会触发插件调用流程:
|
119
99
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
100
|
+
- AI 模型返回包含 `tool_calls` 的响应,表明需要调用工具
|
101
|
+
- 前端通过 `internal_callPluginApi` 方法处理工具调用
|
102
|
+
- 调用 `runPluginApi` 方法执行插件功能,包括获取插件设置和清单、创建认证请求头、发送请求到插件网关
|
103
|
+
- 插件执行完成后,结果返回给 AI 模型,模型基于结果生成最终响应
|
124
104
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
```
|
105
|
+
**实际应用示例**:
|
106
|
+
|
107
|
+
- **搜索插件**:当用户需要获取实时信息时,AI 会调用网页搜索插件来获取最新数据
|
108
|
+
- **DALL-E 插件**:用户要求生成图片时,AI 调用 DALL-E 插件创建图像
|
109
|
+
- **Midjourney 插件**:提供更高质量的图像生成能力,通过 API 调用 Midjourney 服务
|
131
110
|
|
132
|
-
|
111
|
+
7. **预设任务处理**:
|
133
112
|
|
134
|
-
|
113
|
+
预设任务是指系统预定义的特定功能任务,通常在用户执行特定操作时触发(而非常规聊天流程的一部分)。这些任务使用 `fetchPresetTaskResult` 方法执行,该方法与正常聊天流程类似,但会使用专门设计的提示词(prompt chain)。
|
135
114
|
|
136
|
-
|
137
|
-
export const fetchSSE = async (fetchFn: () => Promise<Response>, options: FetchSSEOptions = {}) => {
|
138
|
-
const response = await fetchFn();
|
115
|
+
**执行时机**:预设任务主要在以下场景被触发:
|
139
116
|
|
140
|
-
|
141
|
-
if (!response.ok) {
|
142
|
-
const chatMessageError = await getMessageError(response);
|
117
|
+
1. **角色信息自动生成**:当用户创建或编辑角色时触发
|
143
118
|
|
144
|
-
|
145
|
-
|
146
|
-
|
119
|
+
- 角色头像生成(通过 `autoPickEmoji` 方法)
|
120
|
+
- 角色描述生成(通过 `autocompleteAgentDescription` 方法)
|
121
|
+
- 角色标签生成(通过 `autocompleteAgentTags` 方法)
|
122
|
+
- 角色标题生成(通过 `autocompleteAgentTitle` 方法)
|
147
123
|
|
148
|
-
|
124
|
+
2. **消息翻译**:用户手动点击翻译按钮时触发(通过 `translateMessage` 方法)
|
149
125
|
|
150
|
-
|
126
|
+
3. **网页搜索**:当启用搜索但模型不支持工具调用时,通过 `fetchPresetTaskResult` 实现搜索功能
|
151
127
|
|
152
|
-
|
153
|
-
let output = '';
|
154
|
-
const reader = data.getReader();
|
155
|
-
const decoder = new TextDecoder();
|
128
|
+
**实际代码示例**:
|
156
129
|
|
157
|
-
|
130
|
+
角色头像自动生成实现:
|
158
131
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
132
|
+
```typescript
|
133
|
+
// src/features/AgentSetting/store/action.ts
|
134
|
+
autoPickEmoji: async () => {
|
135
|
+
const { config, meta, dispatchMeta } = get();
|
136
|
+
const systemRole = config.systemRole;
|
137
|
+
|
138
|
+
chatService.fetchPresetTaskResult({
|
139
|
+
onFinish: async (emoji) => {
|
140
|
+
dispatchMeta({ type: 'update', value: { avatar: emoji } });
|
141
|
+
},
|
142
|
+
onLoadingChange: (loading) => {
|
143
|
+
get().updateLoadingState('avatar', loading);
|
144
|
+
},
|
145
|
+
params: merge(
|
146
|
+
get().internal_getSystemAgentForMeta(),
|
147
|
+
chainPickEmoji([meta.title, meta.description, systemRole].filter(Boolean).join(',')),
|
148
|
+
),
|
149
|
+
trace: get().getCurrentTracePayload({ traceName: TraceNameMap.EmojiPicker }),
|
150
|
+
});
|
151
|
+
};
|
152
|
+
```
|
153
|
+
|
154
|
+
翻译功能实现:
|
155
|
+
|
156
|
+
```typescript
|
157
|
+
// src/store/chat/slices/translate/action.ts
|
158
|
+
translateMessage: async (id, targetLang) => {
|
159
|
+
// ...省略部分代码...
|
160
|
+
|
161
|
+
// 检测语言
|
162
|
+
chatService.fetchPresetTaskResult({
|
163
|
+
onFinish: async (data) => {
|
164
|
+
if (data && supportLocales.includes(data)) from = data;
|
165
|
+
await updateMessageTranslate(id, { content, from, to: targetLang });
|
166
|
+
},
|
167
|
+
params: merge(translationSetting, chainLangDetect(message.content)),
|
168
|
+
trace: get().getCurrentTracePayload({ traceName: TraceNameMap.LanguageDetect }),
|
169
|
+
});
|
170
|
+
|
171
|
+
// 执行翻译
|
172
|
+
chatService.fetchPresetTaskResult({
|
173
|
+
onMessageHandle: (chunk) => {
|
174
|
+
if (chunk.type === 'text') {
|
175
|
+
content = chunk.text;
|
176
|
+
internal_dispatchMessage({
|
177
|
+
id,
|
178
|
+
type: 'updateMessageTranslate',
|
179
|
+
value: { content, from, to: targetLang },
|
180
|
+
});
|
181
|
+
}
|
182
|
+
},
|
183
|
+
onFinish: async () => {
|
184
|
+
await updateMessageTranslate(id, { content, from, to: targetLang });
|
185
|
+
internal_toggleChatLoading(false, id, n('translateMessage(end)', { id }) as string);
|
186
|
+
},
|
187
|
+
params: merge(translationSetting, chainTranslate(message.content, targetLang)),
|
188
|
+
trace: get().getCurrentTracePayload({ traceName: TraceNameMap.Translation }),
|
189
|
+
});
|
190
|
+
};
|
191
|
+
```
|
192
|
+
|
193
|
+
8. **完成**:
|
194
|
+
- 当流结束时,调用 onFinish 回调,提供完整的响应结果
|
195
|
+
|
196
|
+
## AgentRuntime 说明
|
197
|
+
|
198
|
+
AgentRuntime 是 Lobe Chat 中的一个核心抽象层,它封装了与不同 AI 模型提供商交互的统一接口。其主要职责和特点包括:
|
199
|
+
|
200
|
+
1. **统一抽象层**:AgentRuntime 提供了一个统一的接口,隐藏了不同 AI 提供商 API 的实现细节差异(如 OpenAI、Anthropic、Bedrock 等)。
|
201
|
+
|
202
|
+
2. **模型初始化**:通过 `initializeWithProvider` 静态方法,根据指定的提供商和配置参数初始化对应的运行时实例。
|
203
|
+
|
204
|
+
3. **能力封装**:
|
205
|
+
|
206
|
+
- `chat` 方法:处理聊天流式请求
|
207
|
+
- `models` 方法:获取模型列表
|
208
|
+
- 支持文本嵌入、文本到图像、文本到语音等功能(如果模型提供商支持)
|
209
|
+
|
210
|
+
4. **插件化架构**:通过 `src/libs/agent-runtime/runtimeMap.ts` 映射表,实现了可扩展的插件化架构,方便添加新的模型提供商。目前支持超过 40 个不同的模型提供商:
|
211
|
+
|
212
|
+
```typescript
|
213
|
+
export const providerRuntimeMap = {
|
214
|
+
openai: LobeOpenAI,
|
215
|
+
anthropic: LobeAnthropicAI,
|
216
|
+
google: LobeGoogleAI,
|
217
|
+
azure: LobeAzureOpenAI,
|
218
|
+
bedrock: LobeBedrockAI,
|
219
|
+
ollama: LobeOllamaAI,
|
220
|
+
// ...其他40多个模型提供商
|
221
|
+
};
|
222
|
+
```
|
223
|
+
|
224
|
+
5. **适配器模式**:在内部使用适配器模式,将不同提供商的 API 适配到统一的 `src/libs/agent-runtime/BaseAI.ts` 接口:
|
225
|
+
|
226
|
+
```typescript
|
227
|
+
export interface LobeRuntimeAI {
|
228
|
+
baseURL?: string;
|
229
|
+
chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions): Promise<Response>;
|
230
|
+
embeddings?(payload: EmbeddingsPayload, options?: EmbeddingsOptions): Promise<Embeddings[]>;
|
231
|
+
models?(): Promise<any>;
|
232
|
+
textToImage?: (payload: TextToImagePayload) => Promise<string[]>;
|
233
|
+
textToSpeech?: (
|
234
|
+
payload: TextToSpeechPayload,
|
235
|
+
options?: TextToSpeechOptions,
|
236
|
+
) => Promise<ArrayBuffer>;
|
237
|
+
}
|
238
|
+
```
|
239
|
+
|
240
|
+
**适配器实现示例**:
|
241
|
+
|
242
|
+
1. **OpenRouter 适配器**:
|
243
|
+
OpenRouter 是一个统一 API,可以通过它访问多个模型提供商的 AI 模型。Lobe Chat 通过适配器实现对 OpenRouter 的支持:
|
244
|
+
|
245
|
+
```typescript
|
246
|
+
// OpenRouter 适配器实现
|
247
|
+
class LobeOpenRouterAI implements LobeRuntimeAI {
|
248
|
+
client: OpenAI;
|
249
|
+
baseURL: string;
|
250
|
+
|
251
|
+
constructor(options: OpenAICompatibleOptions) {
|
252
|
+
// 初始化 OpenRouter 客户端,使用 OpenAI 兼容的 API
|
253
|
+
this.client = new OpenAI({
|
254
|
+
apiKey: options.apiKey,
|
255
|
+
baseURL: OPENROUTER_BASE_URL,
|
256
|
+
defaultHeaders: {
|
257
|
+
'HTTP-Referer': 'https://github.com/lobehub/lobe-chat',
|
258
|
+
'X-Title': 'LobeChat',
|
259
|
+
},
|
260
|
+
});
|
261
|
+
this.baseURL = OPENROUTER_BASE_URL;
|
262
|
+
}
|
263
|
+
|
264
|
+
// 实现聊天功能
|
265
|
+
async chat(payload: ChatCompletionCreateParamsBase, options?: RequestOptions) {
|
266
|
+
// 将 Lobe Chat 的请求格式转换为 OpenRouter 格式
|
267
|
+
// 处理模型映射、消息格式等
|
268
|
+
return this.client.chat.completions.create(
|
269
|
+
{
|
270
|
+
...payload,
|
271
|
+
model: payload.model || 'openai/gpt-4-turbo', // 默认模型
|
272
|
+
},
|
273
|
+
options,
|
274
|
+
);
|
275
|
+
}
|
276
|
+
|
277
|
+
// 实现其他 LobeRuntimeAI 接口方法
|
278
|
+
}
|
279
|
+
```
|
280
|
+
|
281
|
+
2. **Google Gemini 适配器**:
|
282
|
+
Gemini 是 Google 的大语言模型,Lobe Chat 通过专门的适配器支持 Gemini 系列模型:
|
283
|
+
|
284
|
+
```typescript
|
285
|
+
import { GoogleGenerativeAI } from '@google/generative-ai';
|
286
|
+
|
287
|
+
// Gemini 适配器实现
|
288
|
+
class LobeGoogleAI implements LobeRuntimeAI {
|
289
|
+
client: GoogleGenerativeAI;
|
290
|
+
baseURL: string;
|
291
|
+
apiKey: string;
|
292
|
+
|
293
|
+
constructor(options: GoogleAIOptions) {
|
294
|
+
// 初始化 Google Generative AI 客户端
|
295
|
+
this.client = new GoogleGenerativeAI(options.apiKey);
|
296
|
+
this.apiKey = options.apiKey;
|
297
|
+
this.baseURL = options.baseURL || GOOGLE_AI_BASE_URL;
|
298
|
+
}
|
299
|
+
|
300
|
+
// 实现聊天功能
|
301
|
+
async chat(payload: ChatCompletionCreateParamsBase, options?: RequestOptions) {
|
302
|
+
// 选择合适的模型(支持 Gemini Pro、Gemini Flash 等)
|
303
|
+
const modelName = payload.model || 'gemini-pro';
|
304
|
+
const model = this.client.getGenerativeModel({ model: modelName });
|
305
|
+
|
306
|
+
// 处理多模态输入(如图像)
|
307
|
+
const contents = this.processMessages(payload.messages);
|
308
|
+
|
309
|
+
// 设置生成参数
|
310
|
+
const generationConfig = {
|
311
|
+
temperature: payload.temperature,
|
312
|
+
topK: payload.top_k,
|
313
|
+
topP: payload.top_p,
|
314
|
+
maxOutputTokens: payload.max_tokens,
|
315
|
+
};
|
316
|
+
|
317
|
+
// 创建聊天会话并获取响应
|
318
|
+
const chat = model.startChat({
|
319
|
+
generationConfig,
|
320
|
+
history: contents.slice(0, -1),
|
321
|
+
safetySettings: this.getSafetySettings(payload),
|
322
|
+
});
|
323
|
+
|
324
|
+
// 处理流式响应
|
325
|
+
return this.handleStreamResponse(chat, contents, options?.signal);
|
326
|
+
}
|
327
|
+
|
328
|
+
// 实现其他处理方法
|
329
|
+
private processMessages(messages) {
|
330
|
+
/* ... */
|
331
|
+
}
|
332
|
+
private getSafetySettings(payload) {
|
333
|
+
/* ... */
|
334
|
+
}
|
335
|
+
private handleStreamResponse(chat, contents, signal) {
|
336
|
+
/* ... */
|
337
|
+
}
|
338
|
+
}
|
339
|
+
```
|
163
340
|
|
164
|
-
|
165
|
-
options.onMessageHandle?.(chunkValue);
|
166
|
-
}
|
341
|
+
**不同模型的适配实现**:
|
167
342
|
|
168
|
-
|
343
|
+
- `src/libs/agent-runtime/openai/index.ts` - OpenAI 实现
|
344
|
+
- `src/libs/agent-runtime/anthropic/index.ts` - Anthropic 实现
|
345
|
+
- `src/libs/agent-runtime/google/index.ts` - Google 实现
|
346
|
+
- `src/libs/agent-runtime/openrouter/index.ts` - OpenRouter 实现
|
169
347
|
|
170
|
-
|
171
|
-
};
|
172
|
-
```
|
348
|
+
详细实现可以查看:
|
173
349
|
|
174
|
-
|
350
|
+
- `src/libs/agent-runtime/AgentRuntime.ts` - 核心运行时类
|
351
|
+
- `src/libs/agent-runtime/BaseAI.ts` - 定义基础接口
|
352
|
+
- `src/libs/agent-runtime/runtimeMap.ts` - 提供商映射表
|
353
|
+
- `src/libs/agent-runtime/UniformRuntime/index.ts` - 处理多模型统一运行时
|
354
|
+
- `src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts` - OpenAI 兼容适配器工厂
|
@@ -9,6 +9,7 @@ Welcome to the Code Style and Contribution Guidelines for LobeChat. This guide w
|
|
9
9
|
- [Prettier](#prettier)
|
10
10
|
- [remarklint](#remarklint)
|
11
11
|
- [stylelint](#stylelint)
|
12
|
+
- [Style Checking](#style-checking)
|
12
13
|
- [Contribution Process](#contribution-process)
|
13
14
|
- [Gitmoji](#gitmoji)
|
14
15
|
- [Semantic Release](#semantic-release)
|
@@ -17,7 +18,7 @@ Welcome to the Code Style and Contribution Guidelines for LobeChat. This guide w
|
|
17
18
|
|
18
19
|
## Code Style
|
19
20
|
|
20
|
-
In LobeChat, we use the
|
21
|
+
In LobeChat, we use the [@lobehub/lint](https://github.com/lobehub/lobe-lint) package to maintain a unified code style. This package incorporates configurations for `ESLint`, `Prettier`, `remarklint`, and `stylelint` to ensure that our JavaScript, Markdown, and CSS files adhere to the same coding standards.
|
21
22
|
|
22
23
|
### ESLint
|
23
24
|
|
@@ -29,7 +30,7 @@ To ensure your code aligns with the project's standards, run ESLint before commi
|
|
29
30
|
|
30
31
|
Prettier is responsible for code formatting to maintain consistency. Our Prettier configuration can be found in `.prettierrc.js`, imported from `@lobehub/lint`.
|
31
32
|
|
32
|
-
It's recommended to configure your editor to run Prettier automatically
|
33
|
+
It's recommended to configure your editor to run Prettier automatically when saving files.
|
33
34
|
|
34
35
|
### remarklint
|
35
36
|
|
@@ -39,7 +40,9 @@ For Markdown files, we use remarklint to ensure consistent document formatting.
|
|
39
40
|
|
40
41
|
We utilize stylelint to standardize the style of our CSS code. In the configuration file for stylelint, we have made some custom rule adjustments based on `@lobehub/lint` configuration.
|
41
42
|
|
42
|
-
|
43
|
+
### Style Checking
|
44
|
+
|
45
|
+
You don't need to manually run these checks. The project is configured with husky to automatically run lint-staged when you commit code, which will check if your committed files comply with the above standards.
|
43
46
|
|
44
47
|
## Contribution Process
|
45
48
|
|
@@ -51,7 +54,7 @@ When committing code, please use gitmoji to label your commit messages. This hel
|
|
51
54
|
|
52
55
|
Gitmoji commit messages use specific emojis to represent the type or intent of the commit. Here's an example:
|
53
56
|
|
54
|
-
```
|
57
|
+
```markdown
|
55
58
|
📝 Update README with contribution guidelines
|
56
59
|
|
57
60
|
- Added section about code style preferences
|
@@ -9,6 +9,7 @@
|
|
9
9
|
- [Prettier](#prettier)
|
10
10
|
- [remarklint](#remarklint)
|
11
11
|
- [stylelint](#stylelint)
|
12
|
+
- [风格检查](#风格检查)
|
12
13
|
- [贡献流程](#贡献流程)
|
13
14
|
- [Gitmoji](#gitmoji)
|
14
15
|
- [Semantic Release](#semantic-release)
|
@@ -17,7 +18,7 @@
|
|
17
18
|
|
18
19
|
## 代码风格
|
19
20
|
|
20
|
-
在 LobeChat 中,我们使用
|
21
|
+
在 LobeChat 中,我们使用 [@lobehub/lint](https://github.com/lobehub/lobe-lint) 程序包来统一代码风格。该程序包内置了 `ESLint`、`Prettier`、`remarklint` 和 `stylelint` 的配置,以确保我们的 JavaScript、Markdown 和 CSS 文件遵循相同的编码标准。
|
21
22
|
|
22
23
|
### ESLint
|
23
24
|
|
@@ -25,13 +26,11 @@
|
|
25
26
|
|
26
27
|
为了与 Next.js 框架兼容,我们在配置中添加了 `plugin:@next/next/recommended`。此外,我们禁用了一些规则,以适应我们项目的特定需求。
|
27
28
|
|
28
|
-
请在提交代码前运行 ESLint,以确保您的代码符合项目规范。
|
29
|
-
|
30
29
|
### Prettier
|
31
30
|
|
32
31
|
Prettier 负责代码格式化,以保证代码的一致性。您可以在 `.prettierrc.js` 中找到我们的 Prettier 配置,它是从 `@lobehub/lint` 导入的。
|
33
32
|
|
34
|
-
在保存文件时,建议您配置您的编辑器以自动运行 Prettier
|
33
|
+
在保存文件时,建议您配置您的编辑器以自动运行 Prettier。
|
35
34
|
|
36
35
|
### remarklint
|
37
36
|
|
@@ -41,7 +40,9 @@ Prettier 负责代码格式化,以保证代码的一致性。您可以在 `.pr
|
|
41
40
|
|
42
41
|
我们使用 stylelint 来规范 CSS 代码的风格。在 `stylelint` 的配置文件中,我们基于 `@lobehub/lint` 的配置进行了一些自定义规则的调整。
|
43
42
|
|
44
|
-
|
43
|
+
### 风格检查
|
44
|
+
|
45
|
+
你不需要手动运行这些检查,项目配置了 husky 会在您提交代码时自动运行 lint-staged 检查你提交的文件是否符合以上规范。
|
45
46
|
|
46
47
|
## 贡献流程
|
47
48
|
|
@@ -53,7 +54,7 @@ LobeChat 采用 gitmoji 和 semantic release 作为我们的代码提交和发
|
|
53
54
|
|
54
55
|
Gitmoji commit messages 使用特定的 emoji 来表示提交的类型或意图。以下是一个示例:
|
55
56
|
|
56
|
-
```
|
57
|
+
```markdown
|
57
58
|
📝 Update README with contribution guidelines
|
58
59
|
|
59
60
|
- Added section about code style preferences
|
package/contributing/Home.md
CHANGED
@@ -19,16 +19,16 @@ LobeChat is an open-source, extensible ([Function Calling][fc-url]), high-perfor
|
|
19
19
|
### 🤯 Basic
|
20
20
|
|
21
21
|
- [Architecture Design](https://github.com/lobehub/lobe-chat/wiki/Architecture) | [架构设计](https://github.com/lobehub/lobe-chat/wiki/Architecture.zh-CN)
|
22
|
+
- [Development Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [配置开发环境指南](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
|
23
|
+
- [Project Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [项目目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
|
24
|
+
- [Technical Development Getting Started Guide](https://github.com/lobehub/lobe-chat/wiki/Intro) | [技术开发上手指南](https://github.com/lobehub/lobe-chat/wiki/Intro.zh-CN)
|
22
25
|
- [Code Style and Contribution Guidelines](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines) | [代码风格与贡献指南](https://github.com/lobehub/lobe-chat/wiki/Contributing-Guidelines.zh-CN)
|
26
|
+
- [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend) | [如何开发一个新功能:前端实现](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend.zh-CN)
|
23
27
|
- [Complete Guide to LobeChat Feature Development](https://github.com/lobehub/lobe-chat/wiki/Feature-Development) | [LobeChat 功能开发完全指南](https://github.com/lobehub/lobe-chat/wiki/Feature-Development.zh-CN)
|
24
28
|
- [Conversation API Implementation Logic](https://github.com/lobehub/lobe-chat/wiki/Chat-API) | [会话 API 实现逻辑](https://github.com/lobehub/lobe-chat/wiki/Chat-API.zh-CN)
|
25
|
-
- [Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
|
26
|
-
- [Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [环境设置指南](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
|
27
|
-
- [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend) | [如何开发一个新功能:前端实现](https://github.com/lobehub/lobe-chat/wiki/Feature-Development-Frontend.zh-CN)
|
28
29
|
- [New Authentication Provider Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers) | [新身份验证方式开发指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Authentication-Providers.zh-CN)
|
29
|
-
- [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
|
30
|
-
- [Technical Development Getting Started Guide](https://github.com/lobehub/lobe-chat/wiki/Intro) | [技术开发上手指南](https://github.com/lobehub/lobe-chat/wiki/Intro.zh-CN)
|
31
30
|
- [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [测试指南](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
|
31
|
+
- [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
|
32
32
|
|
33
33
|
<br/>
|
34
34
|
|
@@ -190,7 +190,7 @@ export const useSessionStore = createWithEqualityFn<SessionStore>()(
|
|
190
190
|
|
191
191
|
```
|
192
192
|
|
193
|
-
In this `store.ts` file, we create a `useSessionStore` hook that uses the `zustand` library to create a global state manager. We merge the initialState
|
193
|
+
In this `store.ts` file, we create a `useSessionStore` hook that uses the `zustand` library to create a global state manager. We merge the initialState with the actions from each Slice to create a complete SessionStore.
|
194
194
|
|
195
195
|
#### slices/session/action.ts
|
196
196
|
|
@@ -182,7 +182,7 @@ export const useSessionStore = createWithEqualityFn<SessionStore>()(
|
|
182
182
|
|
183
183
|
```
|
184
184
|
|
185
|
-
在这个 `store.ts` 文件中,我们创建了一个 `useSessionStore` 钩子,它使用 `zustand` 库来创建一个全局状态管理器。我们将 initialState 和每个 Slice
|
185
|
+
在这个 `store.ts` 文件中,我们创建了一个 `useSessionStore` 钩子,它使用 `zustand` 库来创建一个全局状态管理器。我们将 initialState 和每个 Slice 的动作合并,以创建完整的 SessionStore。
|
186
186
|
|
187
187
|
#### slices/session/action.ts
|
188
188
|
|
@@ -58,8 +58,9 @@ services:
|
|
58
58
|
wait \$MINIO_PID
|
59
59
|
"
|
60
60
|
|
61
|
+
# version lock ref: https://github.com/lobehub/lobe-chat/pull/7331
|
61
62
|
casdoor:
|
62
|
-
image: casbin/casdoor
|
63
|
+
image: casbin/casdoor:v1.843.0
|
63
64
|
container_name: lobe-casdoor
|
64
65
|
entrypoint: /bin/sh -c './server --createDatabase=true'
|
65
66
|
network_mode: 'service:network-service'
|
@@ -91,6 +91,10 @@
|
|
91
91
|
"provider": "مزود"
|
92
92
|
},
|
93
93
|
"OllamaSetupGuide": {
|
94
|
+
"action": {
|
95
|
+
"close": "إغلاق الإشعار",
|
96
|
+
"start": "تم التثبيت والتشغيل، ابدأ المحادثة"
|
97
|
+
},
|
94
98
|
"cors": {
|
95
99
|
"description": "بسبب قيود أمان المتصفح، تحتاج إلى تكوين CORS لـ Ollama لاستخدامه بشكل صحيح.",
|
96
100
|
"linux": {
|