@lobehub/chat 1.15.13 → 1.15.14

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 CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.15.14](https://github.com/lobehub/lobe-chat/compare/v1.15.13...v1.15.14)
6
+
7
+ <sup>Released on **2024-09-06**</sup>
8
+
9
+ <br/>
10
+
11
+ <details>
12
+ <summary><kbd>Improvements and Fixes</kbd></summary>
13
+
14
+ </details>
15
+
16
+ <div align="right">
17
+
18
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
19
+
20
+ </div>
21
+
5
22
  ### [Version 1.15.13](https://github.com/lobehub/lobe-chat/compare/v1.15.12...v1.15.13)
6
23
 
7
24
  <sup>Released on **2024-09-06**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.15.13",
3
+ "version": "1.15.14",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -112,6 +112,10 @@ const Google: ModelProviderCard = {
112
112
  proxyUrl: {
113
113
  placeholder: 'https://generativelanguage.googleapis.com',
114
114
  },
115
+ smoothing: {
116
+ speed: 2,
117
+ text: true,
118
+ },
115
119
  };
116
120
 
117
121
  export default Google;
@@ -3,6 +3,7 @@ import { produce } from 'immer';
3
3
  import { merge } from 'lodash-es';
4
4
 
5
5
  import { createErrorResponse } from '@/app/api/errorResponse';
6
+ import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
6
7
  import { INBOX_GUIDE_SYSTEMROLE } from '@/const/guide';
7
8
  import { INBOX_SESSION_ID } from '@/const/session';
8
9
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
@@ -304,6 +305,8 @@ class ChatService {
304
305
  provider,
305
306
  });
306
307
 
308
+ const providerConfig = DEFAULT_MODEL_PROVIDER_LIST.find((item) => item.id === provider);
309
+
307
310
  return fetchSSE(API_ENDPOINTS.chat(provider), {
308
311
  body: JSON.stringify(payload),
309
312
  fetcher: fetcher,
@@ -314,6 +317,7 @@ class ChatService {
314
317
  onFinish: options?.onFinish,
315
318
  onMessageHandle: options?.onMessageHandle,
316
319
  signal,
320
+ smoothing: providerConfig?.smoothing,
317
321
  });
318
322
  };
319
323
 
package/src/types/llm.ts CHANGED
@@ -43,6 +43,12 @@ export interface ChatModelCard {
43
43
  vision?: boolean;
44
44
  }
45
45
 
46
+ export interface SmoothingParams {
47
+ speed?: number;
48
+ text?: boolean;
49
+ toolsCalling?: boolean;
50
+ }
51
+
46
52
  export interface ModelProviderCard {
47
53
  chatModels: ChatModelCard[];
48
54
  /**
@@ -89,6 +95,11 @@ export interface ModelProviderCard {
89
95
  * so provider like ollama don't need api key field
90
96
  */
91
97
  showApiKey?: boolean;
98
+
99
+ /**
100
+ * whether to smoothing the output
101
+ */
102
+ smoothing?: SmoothingParams;
92
103
  }
93
104
 
94
105
  // 语言模型的设置参数
@@ -139,6 +139,7 @@ describe('fetchSSE', () => {
139
139
  await fetchSSE('/', {
140
140
  onMessageHandle: mockOnMessageHandle,
141
141
  onFinish: mockOnFinish,
142
+ smoothing: true,
142
143
  });
143
144
 
144
145
  expect(mockOnMessageHandle).toHaveBeenNthCalledWith(1, { text: 'Hell', type: 'text' });
@@ -183,6 +184,7 @@ describe('fetchSSE', () => {
183
184
  await fetchSSE('/', {
184
185
  onMessageHandle: mockOnMessageHandle,
185
186
  onFinish: mockOnFinish,
187
+ smoothing: true,
186
188
  });
187
189
 
188
190
  // TODO: need to check whether the `aarg1` is correct
@@ -234,6 +236,7 @@ describe('fetchSSE', () => {
234
236
  onMessageHandle: mockOnMessageHandle,
235
237
  onFinish: mockOnFinish,
236
238
  signal: abortController.signal,
239
+ smoothing: true,
237
240
  });
238
241
 
239
242
  expect(mockOnMessageHandle).toHaveBeenNthCalledWith(1, { text: 'Hell', type: 'text' });
@@ -1,6 +1,7 @@
1
1
  import { MESSAGE_CANCEL_FLAT } from '@/const/message';
2
2
  import { LOBE_CHAT_OBSERVATION_ID, LOBE_CHAT_TRACE_ID } from '@/const/trace';
3
3
  import { ChatErrorType } from '@/types/fetch';
4
+ import { SmoothingParams } from '@/types/llm';
4
5
  import {
5
6
  ChatMessageError,
6
7
  MessageToolCall,
@@ -41,14 +42,19 @@ export interface FetchSSEOptions {
41
42
  onErrorHandle?: (error: ChatMessageError) => void;
42
43
  onFinish?: OnFinishHandler;
43
44
  onMessageHandle?: (chunk: MessageTextChunk | MessageToolCallsChunk) => void;
44
- smoothing?: boolean;
45
+ smoothing?: SmoothingParams | boolean;
45
46
  }
46
47
 
47
48
  const START_ANIMATION_SPEED = 4;
48
49
 
49
50
  const END_ANIMATION_SPEED = 15;
50
51
 
51
- const createSmoothMessage = (params: { onTextUpdate: (delta: string, text: string) => void }) => {
52
+ const createSmoothMessage = (params: {
53
+ onTextUpdate: (delta: string, text: string) => void;
54
+ startSpeed?: number;
55
+ }) => {
56
+ const { startSpeed = START_ANIMATION_SPEED } = params;
57
+
52
58
  let buffer = '';
53
59
  // why use queue: https://shareg.pt/GLBrjpK
54
60
  let outputQueue: string[] = [];
@@ -66,7 +72,7 @@ const createSmoothMessage = (params: { onTextUpdate: (delta: string, text: strin
66
72
 
67
73
  // define startAnimation function to display the text in buffer smooth
68
74
  // when you need to start the animation, call this function
69
- const startAnimation = (speed = START_ANIMATION_SPEED) =>
75
+ const startAnimation = (speed = startSpeed) =>
70
76
  new Promise<void>((resolve) => {
71
77
  if (isAnimationActive) {
72
78
  resolve();
@@ -122,7 +128,9 @@ const createSmoothMessage = (params: { onTextUpdate: (delta: string, text: strin
122
128
 
123
129
  const createSmoothToolCalls = (params: {
124
130
  onToolCallsUpdate: (toolCalls: MessageToolCall[], isAnimationActives: boolean[]) => void;
131
+ startSpeed?: number;
125
132
  }) => {
133
+ const { startSpeed = START_ANIMATION_SPEED } = params;
126
134
  let toolCallsBuffer: MessageToolCall[] = [];
127
135
 
128
136
  // 为每个 tool_call 维护一个输出队列和动画控制器
@@ -139,7 +147,7 @@ const createSmoothToolCalls = (params: {
139
147
  }
140
148
  };
141
149
 
142
- const startAnimation = (index: number, speed = START_ANIMATION_SPEED) =>
150
+ const startAnimation = (index: number, speed = startSpeed) =>
143
151
  new Promise<void>((resolve) => {
144
152
  if (isAnimationActives[index]) {
145
153
  resolve();
@@ -194,7 +202,7 @@ const createSmoothToolCalls = (params: {
194
202
  });
195
203
  };
196
204
 
197
- const startAnimations = async (speed = START_ANIMATION_SPEED) => {
205
+ const startAnimations = async (speed = startSpeed) => {
198
206
  const pools = toolCallsBuffer.map(async (_, index) => {
199
207
  if (outputQueues[index].length > 0 && !isAnimationActives[index]) {
200
208
  await startAnimation(index, speed);
@@ -230,19 +238,26 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
230
238
  let finishedType: SSEFinishType = 'done';
231
239
  let response!: Response;
232
240
 
233
- const { smoothing = true } = options;
241
+ const { smoothing } = options;
242
+
243
+ const textSmoothing = typeof smoothing === 'boolean' ? smoothing : smoothing?.text;
244
+ const toolsCallingSmoothing =
245
+ typeof smoothing === 'boolean' ? smoothing : (smoothing?.toolsCalling ?? true);
246
+ const smoothingSpeed = typeof smoothing === 'object' ? smoothing.speed : undefined;
234
247
 
235
248
  const textController = createSmoothMessage({
236
249
  onTextUpdate: (delta, text) => {
237
250
  output = text;
238
251
  options.onMessageHandle?.({ text: delta, type: 'text' });
239
252
  },
253
+ startSpeed: smoothingSpeed,
240
254
  });
241
255
 
242
256
  const toolCallsController = createSmoothToolCalls({
243
257
  onToolCallsUpdate: (toolCalls, isAnimationActives) => {
244
258
  options.onMessageHandle?.({ isAnimationActives, tool_calls: toolCalls, type: 'tool_calls' });
245
259
  },
260
+ startSpeed: smoothingSpeed,
246
261
  });
247
262
 
248
263
  await fetchEventSource(url, {
@@ -305,7 +320,7 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
305
320
  }
306
321
 
307
322
  case 'text': {
308
- if (smoothing) {
323
+ if (textSmoothing) {
309
324
  textController.pushToQueue(data);
310
325
 
311
326
  if (!textController.isAnimationActive) textController.startAnimation();
@@ -323,7 +338,7 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
323
338
  if (!toolCalls) toolCalls = [];
324
339
  toolCalls = parseToolCalls(toolCalls, data);
325
340
 
326
- if (smoothing) {
341
+ if (toolsCallingSmoothing) {
327
342
  // make the tool calls smooth
328
343
 
329
344
  // push the tool calls to the smooth queue
@@ -333,10 +348,7 @@ export const fetchSSE = async (url: string, options: RequestInit & FetchSSEOptio
333
348
  toolCallsController.startAnimations();
334
349
  }
335
350
  } else {
336
- options.onMessageHandle?.({
337
- tool_calls: toolCalls,
338
- type: 'tool_calls',
339
- });
351
+ options.onMessageHandle?.({ tool_calls: toolCalls, type: 'tool_calls' });
340
352
  }
341
353
  }
342
354
  }