@lobehub/chat 1.91.3 → 1.92.1
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 +69 -0
- package/changelog/v1.json +24 -0
- package/locales/ar/setting.json +1 -1
- package/locales/bg-BG/setting.json +1 -1
- package/locales/de-DE/setting.json +1 -1
- package/locales/en-US/setting.json +1 -1
- package/locales/es-ES/setting.json +1 -1
- package/locales/fa-IR/setting.json +1 -1
- package/locales/fr-FR/setting.json +1 -1
- package/locales/it-IT/setting.json +1 -1
- package/locales/ja-JP/setting.json +1 -1
- package/locales/ko-KR/setting.json +1 -1
- package/locales/nl-NL/setting.json +1 -1
- package/locales/pl-PL/setting.json +1 -1
- package/locales/pt-BR/setting.json +1 -1
- package/locales/ru-RU/setting.json +1 -1
- package/locales/tr-TR/setting.json +1 -1
- package/locales/vi-VN/setting.json +1 -1
- package/locales/zh-CN/setting.json +1 -1
- package/locales/zh-TW/setting.json +1 -1
- package/package.json +1 -1
- package/src/components/ModelSelect/index.tsx +6 -3
- package/src/config/aiModels/google.ts +25 -0
- package/src/config/aiModels/hunyuan.ts +44 -0
- package/src/config/aiModels/novita.ts +39 -3
- package/src/config/aiModels/openrouter.ts +0 -1
- package/src/config/aiModels/qwen.ts +48 -6
- package/src/config/aiModels/siliconcloud.ts +0 -106
- package/src/features/AgentSetting/AgentModal/index.tsx +3 -2
- package/src/features/ChatInput/ActionBar/Search/Controls.tsx +6 -2
- package/src/libs/model-runtime/utils/streams/vertex-ai.ts +12 -0
- package/src/locales/default/setting.ts +1 -1
- package/src/services/chat.ts +17 -9
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +23 -31
- package/src/store/user/slices/auth/selectors.test.ts +94 -0
- package/src/store/user/slices/auth/selectors.ts +3 -0
- package/src/utils/client/parserPlaceholder.test.ts +315 -0
- package/src/utils/client/parserPlaceholder.ts +192 -0
@@ -0,0 +1,315 @@
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
2
|
+
|
3
|
+
import { VARIABLE_GENERATORS, parsePlaceholderVariablesMessages } from './parserPlaceholder';
|
4
|
+
|
5
|
+
// Mock dependencies
|
6
|
+
vi.mock('@/utils/uuid', () => ({
|
7
|
+
uuid: () => 'mocked-uuid-12345',
|
8
|
+
}));
|
9
|
+
|
10
|
+
vi.mock('@/store/user', () => ({
|
11
|
+
useUserStore: {
|
12
|
+
getState: () => ({}),
|
13
|
+
},
|
14
|
+
}));
|
15
|
+
|
16
|
+
vi.mock('@/store/user/selectors', () => ({
|
17
|
+
userProfileSelectors: {
|
18
|
+
displayUserName: () => 'testuser',
|
19
|
+
nickName: () => 'Test User',
|
20
|
+
fullName: () => 'Test Full Name',
|
21
|
+
},
|
22
|
+
}));
|
23
|
+
|
24
|
+
vi.mock('@/store/agent/store', () => ({
|
25
|
+
getAgentStoreState: () => ({}),
|
26
|
+
}));
|
27
|
+
|
28
|
+
vi.mock('@/store/agent/selectors', () => ({
|
29
|
+
agentChatConfigSelectors: {
|
30
|
+
currentChatConfig: () => ({
|
31
|
+
inputTemplate: 'Hello {{username}}!',
|
32
|
+
}),
|
33
|
+
},
|
34
|
+
}));
|
35
|
+
|
36
|
+
describe('parsePlaceholderVariablesMessages', () => {
|
37
|
+
beforeEach(() => {
|
38
|
+
// Mock Date for consistent testing
|
39
|
+
vi.useFakeTimers();
|
40
|
+
vi.setSystemTime(new Date('2025-06-06T06:06:06.666Z'));
|
41
|
+
|
42
|
+
// Mock Math.random for consistent random values
|
43
|
+
vi.spyOn(Math, 'random').mockReturnValue(0.5);
|
44
|
+
});
|
45
|
+
|
46
|
+
afterEach(() => {
|
47
|
+
vi.useRealTimers();
|
48
|
+
vi.restoreAllMocks();
|
49
|
+
});
|
50
|
+
|
51
|
+
describe('string content messages', () => {
|
52
|
+
it('should replace template variables in string content', () => {
|
53
|
+
const messages = [
|
54
|
+
{
|
55
|
+
id: '1',
|
56
|
+
content: 'Hello {{username}}, today is {{date}}',
|
57
|
+
},
|
58
|
+
];
|
59
|
+
|
60
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
61
|
+
|
62
|
+
expect(result[0].content).toContain('testuser');
|
63
|
+
expect(result[0].content).toContain(new Date().toLocaleDateString());
|
64
|
+
});
|
65
|
+
|
66
|
+
it('should handle multiple variables in one message', () => {
|
67
|
+
const messages = [
|
68
|
+
{
|
69
|
+
id: '1',
|
70
|
+
content: 'Time: {{time}}, Date: {{date}}, User: {{nickname}}',
|
71
|
+
},
|
72
|
+
];
|
73
|
+
|
74
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
75
|
+
|
76
|
+
expect(result[0].content).toContain('Test User');
|
77
|
+
expect(result[0].content).toMatch(/Time: .+, Date: .+, User: Test User/);
|
78
|
+
});
|
79
|
+
|
80
|
+
it('should preserve message structure when replacing variables', () => {
|
81
|
+
const messages = [
|
82
|
+
{
|
83
|
+
id: '1',
|
84
|
+
role: 'user',
|
85
|
+
content: 'Hello {{username}}',
|
86
|
+
},
|
87
|
+
];
|
88
|
+
|
89
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
90
|
+
|
91
|
+
expect(result[0]).toEqual({
|
92
|
+
id: '1',
|
93
|
+
role: 'user',
|
94
|
+
content: 'Hello testuser',
|
95
|
+
});
|
96
|
+
});
|
97
|
+
});
|
98
|
+
|
99
|
+
describe('array content messages', () => {
|
100
|
+
it('should replace variables in text type array elements', () => {
|
101
|
+
const messages = [
|
102
|
+
{
|
103
|
+
id: '1',
|
104
|
+
content: [
|
105
|
+
{
|
106
|
+
type: 'text',
|
107
|
+
text: 'Hello {{username}}',
|
108
|
+
},
|
109
|
+
{
|
110
|
+
type: 'image_url',
|
111
|
+
image_url: 'image.jpg',
|
112
|
+
},
|
113
|
+
],
|
114
|
+
},
|
115
|
+
];
|
116
|
+
|
117
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
118
|
+
|
119
|
+
expect(result[0].content[0].text).toBe('Hello testuser');
|
120
|
+
expect(result[0].content[1]).toEqual({
|
121
|
+
type: 'image_url',
|
122
|
+
image_url: 'image.jpg',
|
123
|
+
});
|
124
|
+
});
|
125
|
+
|
126
|
+
it('should handle multiple text elements with variables', () => {
|
127
|
+
const messages = [
|
128
|
+
{
|
129
|
+
id: '1',
|
130
|
+
content: [
|
131
|
+
{
|
132
|
+
type: 'text',
|
133
|
+
text: 'Date: {{date}}',
|
134
|
+
},
|
135
|
+
{
|
136
|
+
type: 'text',
|
137
|
+
text: 'Time: {{time}}',
|
138
|
+
},
|
139
|
+
{
|
140
|
+
type: 'image_url',
|
141
|
+
image_url: 'test.jpg',
|
142
|
+
},
|
143
|
+
],
|
144
|
+
},
|
145
|
+
];
|
146
|
+
|
147
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
148
|
+
|
149
|
+
expect(result[0].content[0].text).toContain(new Date().toLocaleDateString());
|
150
|
+
expect(result[0].content[1].text).toContain(new Date().toLocaleTimeString());
|
151
|
+
expect(result[0].content[2]).toEqual({
|
152
|
+
type: 'image_url',
|
153
|
+
image_url: 'test.jpg',
|
154
|
+
});
|
155
|
+
});
|
156
|
+
|
157
|
+
it('should preserve non-text array elements unchanged', () => {
|
158
|
+
const messages = [
|
159
|
+
{
|
160
|
+
id: '1',
|
161
|
+
content: [
|
162
|
+
{
|
163
|
+
type: 'image_url',
|
164
|
+
image_url: 'image.jpg',
|
165
|
+
},
|
166
|
+
{
|
167
|
+
type: 'image_url',
|
168
|
+
name: 'image2.jpg',
|
169
|
+
},
|
170
|
+
],
|
171
|
+
},
|
172
|
+
];
|
173
|
+
|
174
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
175
|
+
|
176
|
+
expect(result[0].content).toEqual([
|
177
|
+
{
|
178
|
+
type: 'image_url',
|
179
|
+
image_url: 'image.jpg',
|
180
|
+
},
|
181
|
+
{
|
182
|
+
type: 'image_url',
|
183
|
+
name: 'image2.jpg',
|
184
|
+
},
|
185
|
+
]);
|
186
|
+
});
|
187
|
+
});
|
188
|
+
|
189
|
+
describe('edge cases', () => {
|
190
|
+
it('should handle empty messages array', () => {
|
191
|
+
const result = parsePlaceholderVariablesMessages([]);
|
192
|
+
expect(result).toEqual([]);
|
193
|
+
});
|
194
|
+
|
195
|
+
it('should handle messages without content', () => {
|
196
|
+
const messages = [{ id: '1' }, { id: '2', content: null }, { id: '3', content: undefined }];
|
197
|
+
|
198
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
199
|
+
|
200
|
+
expect(result).toEqual([
|
201
|
+
{ id: '1' },
|
202
|
+
{ id: '2', content: null },
|
203
|
+
{ id: '3', content: undefined },
|
204
|
+
]);
|
205
|
+
});
|
206
|
+
|
207
|
+
it('should handle empty string content', () => {
|
208
|
+
const messages = [{ id: '1', content: '' }];
|
209
|
+
|
210
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
211
|
+
|
212
|
+
expect(result[0].content).toBe('');
|
213
|
+
});
|
214
|
+
|
215
|
+
it('should handle content without variables', () => {
|
216
|
+
const messages = [
|
217
|
+
{ id: '1', content: 'Hello world!' },
|
218
|
+
{
|
219
|
+
id: '2',
|
220
|
+
content: [
|
221
|
+
{ type: 'text', text: 'No variables here' },
|
222
|
+
{ type: 'image_url', image_url: 'test.jpg' },
|
223
|
+
],
|
224
|
+
},
|
225
|
+
];
|
226
|
+
|
227
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
228
|
+
|
229
|
+
expect(result[0].content).toBe('Hello world!');
|
230
|
+
expect(result[1].content[0].text).toBe('No variables here');
|
231
|
+
});
|
232
|
+
|
233
|
+
it('should handle unknown variable types', () => {
|
234
|
+
const messages = [{ id: '1', content: 'Hello {{unknown_variable}}!' }];
|
235
|
+
|
236
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
237
|
+
|
238
|
+
// Unknown variables should remain unchanged
|
239
|
+
expect(result[0].content).toBe('Hello {{unknown_variable}}!');
|
240
|
+
});
|
241
|
+
|
242
|
+
it('should handle nested variables (input_template)', () => {
|
243
|
+
const messages = [{ id: '1', content: 'Template: {{input_template}}' }];
|
244
|
+
|
245
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
246
|
+
|
247
|
+
// Should resolve nested variables in input_template
|
248
|
+
expect(result[0].content).toBe('Template: Hello testuser!');
|
249
|
+
});
|
250
|
+
});
|
251
|
+
|
252
|
+
describe('specific variable types', () => {
|
253
|
+
it('should handle time variables', () => {
|
254
|
+
const messages = [
|
255
|
+
{
|
256
|
+
id: '1',
|
257
|
+
content: 'Year: {{year}}, Month: {{month}}, Day: {{day}}',
|
258
|
+
},
|
259
|
+
];
|
260
|
+
|
261
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
262
|
+
|
263
|
+
expect(result[0].content).toContain('Year: 2025');
|
264
|
+
expect(result[0].content).toContain('Month: 06');
|
265
|
+
expect(result[0].content).toContain('Day: 06');
|
266
|
+
});
|
267
|
+
|
268
|
+
it('should handle random variables', () => {
|
269
|
+
const messages = [
|
270
|
+
{
|
271
|
+
id: '1',
|
272
|
+
content: 'Random: {{random}}, Bool: {{random_bool}}, UUID: {{uuid}}',
|
273
|
+
},
|
274
|
+
];
|
275
|
+
|
276
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
277
|
+
|
278
|
+
expect(result[0].content).toContain('Random: 500001'); // Math.random() * 1000000 + 1 with 0.5
|
279
|
+
expect(result[0].content).toContain('Bool: false'); // Math.random() > 0.5 with 0.5
|
280
|
+
expect(result[0].content).toContain('UUID: mocked-uuid-12345');
|
281
|
+
});
|
282
|
+
|
283
|
+
it('should handle user variables', () => {
|
284
|
+
const messages = [
|
285
|
+
{
|
286
|
+
id: '1',
|
287
|
+
content: 'User: {{username}}, Nickname: {{nickname}}',
|
288
|
+
},
|
289
|
+
];
|
290
|
+
|
291
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
292
|
+
|
293
|
+
expect(result[0].content).toBe('User: testuser, Nickname: Test User');
|
294
|
+
});
|
295
|
+
});
|
296
|
+
|
297
|
+
describe('multiple messages', () => {
|
298
|
+
it('should process multiple messages correctly', () => {
|
299
|
+
const messages = [
|
300
|
+
{ id: '1', content: 'Hello {{username}}' },
|
301
|
+
{
|
302
|
+
id: '2',
|
303
|
+
content: [{ type: 'text', text: 'Today is {{date}}' }],
|
304
|
+
},
|
305
|
+
{ id: '3', content: 'Time: {{time}}' },
|
306
|
+
];
|
307
|
+
|
308
|
+
const result = parsePlaceholderVariablesMessages(messages);
|
309
|
+
|
310
|
+
expect(result[0].content).toBe('Hello testuser');
|
311
|
+
expect(result[1].content[0].text).toContain(new Date().toLocaleDateString());
|
312
|
+
expect(result[2].content).toContain(new Date().toLocaleTimeString());
|
313
|
+
});
|
314
|
+
});
|
315
|
+
});
|
@@ -0,0 +1,192 @@
|
|
1
|
+
import { template } from 'lodash-es';
|
2
|
+
|
3
|
+
import { uuid } from '@/utils/uuid';
|
4
|
+
|
5
|
+
import { useUserStore } from '@/store/user';
|
6
|
+
import { userProfileSelectors } from '@/store/user/selectors';
|
7
|
+
|
8
|
+
import { getAgentStoreState } from '@/store/agent/store';
|
9
|
+
import { agentChatConfigSelectors } from '@/store/agent/selectors';
|
10
|
+
|
11
|
+
const placeholderVariablesRegex = /{{(.*?)}}/g;
|
12
|
+
|
13
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
14
|
+
export const VARIABLE_GENERATORS = {
|
15
|
+
/**
|
16
|
+
* 时间类模板变量
|
17
|
+
*
|
18
|
+
* | Value | Example |
|
19
|
+
* |-------|---------|
|
20
|
+
* | `{{date}}` | 12/25/2023 |
|
21
|
+
* | `{{datetime}}` | 12/25/2023, 2:30:45 PM |
|
22
|
+
* | `{{day}}` | 25 |
|
23
|
+
* | `{{hour}}` | 14 |
|
24
|
+
* | `{{iso}}` | 2023-12-25T14:30:45.123Z |
|
25
|
+
* | `{{locale}}` | zh-CN |
|
26
|
+
* | `{{minute}}` | 30 |
|
27
|
+
* | `{{month}}` | 12 |
|
28
|
+
* | `{{second}}` | 45 |
|
29
|
+
* | `{{time}}` | 2:30:45 PM |
|
30
|
+
* | `{{timestamp}}` | 1703538645123 |
|
31
|
+
* | `{{timezone}}` | America/New_York |
|
32
|
+
* | `{{weekday}}` | Monday |
|
33
|
+
* | `{{year}}` | 2023 |
|
34
|
+
*
|
35
|
+
*/
|
36
|
+
date: () => new Date().toLocaleDateString(),
|
37
|
+
datetime: () => new Date().toLocaleString(),
|
38
|
+
day: () => new Date().getDate().toString().padStart(2, '0'),
|
39
|
+
hour: () => new Date().getHours().toString().padStart(2, '0'),
|
40
|
+
iso: () => new Date().toISOString(),
|
41
|
+
locale: () => Intl.DateTimeFormat().resolvedOptions().locale,
|
42
|
+
minute: () => new Date().getMinutes().toString().padStart(2, '0'),
|
43
|
+
month: () => (new Date().getMonth() + 1).toString().padStart(2, '0'),
|
44
|
+
second: () => new Date().getSeconds().toString().padStart(2, '0'),
|
45
|
+
time: () => new Date().toLocaleTimeString(),
|
46
|
+
timestamp: () => Date.now().toString(),
|
47
|
+
timezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone,
|
48
|
+
weekday: () => new Date().toLocaleDateString('en-US', { weekday: 'long' }),
|
49
|
+
year: () => new Date().getFullYear().toString(),
|
50
|
+
|
51
|
+
/**
|
52
|
+
* 用户信息类模板变量
|
53
|
+
*
|
54
|
+
* | Value | Example |
|
55
|
+
* |-------|---------|
|
56
|
+
* | `{{email}}` | demo@lobehub.com |
|
57
|
+
* | `{{nickname}}` | 社区版用户 |
|
58
|
+
* | `{{username}}` | LobeChat |
|
59
|
+
*
|
60
|
+
*/
|
61
|
+
email: () => userProfileSelectors.email(useUserStore.getState()) ?? '',
|
62
|
+
nickname: () => userProfileSelectors.nickName(useUserStore.getState()) ?? '',
|
63
|
+
username: () => userProfileSelectors.displayUserName(useUserStore.getState()) ?? userProfileSelectors.fullName(useUserStore.getState()) ?? '',
|
64
|
+
|
65
|
+
/**
|
66
|
+
* 随机值类模板变量
|
67
|
+
*
|
68
|
+
* | Value | Example |
|
69
|
+
* |-------|---------|
|
70
|
+
* | `{{random}}` | 100041 |
|
71
|
+
* | `{{random_bool}}` | true |
|
72
|
+
* | `{{random_float}}` | 76.02 |
|
73
|
+
* | `{{random_hex}}` | de0dbd |
|
74
|
+
* | `{{random_int}}` | 68 |
|
75
|
+
* | `{{random_string}}` | wqn9zfrqe7h |
|
76
|
+
*
|
77
|
+
*/
|
78
|
+
random: () => Math.floor(Math.random() * 1_000_000 + 1).toString(),
|
79
|
+
random_bool: () => (Math.random() > 0.5 ? 'true' : 'false'),
|
80
|
+
random_float: () => (Math.random() * 100).toFixed(2),
|
81
|
+
random_hex: () => Math.floor(Math.random() * 16_777_215).toString(16).padStart(6, '0'),
|
82
|
+
random_int: () => Math.floor(Math.random() * 100 + 1).toString(),
|
83
|
+
random_string: () => Math.random().toString(36).slice(2, 15),
|
84
|
+
random_digit: () => Math.floor(Math.random() * 10).toString(),
|
85
|
+
|
86
|
+
/**
|
87
|
+
* UUID 类模板变量
|
88
|
+
*
|
89
|
+
* | Value | Example |
|
90
|
+
* |-------|---------|
|
91
|
+
* | `{{uuid}}` | dd90b35-669f-4e87-beb8-ac6877f6995d |
|
92
|
+
* | `{{uuid_short}}` | dd90b35 |
|
93
|
+
*
|
94
|
+
*/
|
95
|
+
uuid: () => uuid(),
|
96
|
+
uuid_short: () => uuid().split('-')[0],
|
97
|
+
|
98
|
+
/**
|
99
|
+
* 平台类模板变量
|
100
|
+
*
|
101
|
+
* | Value | Example |
|
102
|
+
* |-------|---------|
|
103
|
+
* | `{{language}}` | zh-CN |
|
104
|
+
* | `{{platform}}` | MacIntel |
|
105
|
+
* | `{{user_agent}}` | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0 |
|
106
|
+
*
|
107
|
+
*/
|
108
|
+
language: () => typeof navigator !== 'undefined' ? navigator.language : '',
|
109
|
+
platform: () => typeof navigator !== 'undefined' ? navigator.platform : '',
|
110
|
+
user_agent: () => typeof navigator !== 'undefined' ? navigator.userAgent : '',
|
111
|
+
|
112
|
+
/**
|
113
|
+
* LobeChat 模板变量
|
114
|
+
*
|
115
|
+
* | Value | Example |
|
116
|
+
* |-------|---------|
|
117
|
+
* | `{{input_template}}` | Some contents |
|
118
|
+
*
|
119
|
+
*/
|
120
|
+
input_template: () => agentChatConfigSelectors.currentChatConfig(getAgentStoreState()).inputTemplate || '',
|
121
|
+
} as Record<string, () => string>;
|
122
|
+
|
123
|
+
/**
|
124
|
+
* 从文本中提取所有 {{variable}} 占位符的变量名
|
125
|
+
* @param text 包含模板变量的字符串
|
126
|
+
* @returns 变量名数组,如 ['date', 'nickname']
|
127
|
+
*/
|
128
|
+
const extractPlaceholderVariables = (text: string): string[] => {
|
129
|
+
const matches = [...text.matchAll(placeholderVariablesRegex)];
|
130
|
+
return matches.map(m => m[1].trim());
|
131
|
+
};
|
132
|
+
|
133
|
+
/**
|
134
|
+
* 将模板变量替换为实际值,并支持递归解析嵌套变量
|
135
|
+
* @param text - 含变量的原始文本
|
136
|
+
* @param depth - 递归深度,默认 1,设置更高可支持 {{input_template}} 中的 {{date}} 等
|
137
|
+
* @returns 替换后的文本
|
138
|
+
*/
|
139
|
+
export const parsePlaceholderVariables = (text: string, depth = 2): string => {
|
140
|
+
let result = text;
|
141
|
+
|
142
|
+
// 递归解析,用于处理如 {{input_template}} 存在额外预设变量
|
143
|
+
for (let i = 0; i < depth; i++) {
|
144
|
+
try {
|
145
|
+
const variables = Object.fromEntries(
|
146
|
+
extractPlaceholderVariables(result)
|
147
|
+
.map((key) => [key, VARIABLE_GENERATORS[key]?.()])
|
148
|
+
.filter(([, value]) => value !== undefined)
|
149
|
+
);
|
150
|
+
|
151
|
+
const replaced = template(result, { interpolate: placeholderVariablesRegex })(variables);
|
152
|
+
if (replaced === result) break;
|
153
|
+
|
154
|
+
result = replaced;
|
155
|
+
} catch {
|
156
|
+
break;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
return result;
|
161
|
+
};
|
162
|
+
|
163
|
+
/**
|
164
|
+
* 解析消息内容,替换占位符变量
|
165
|
+
* @param messages 原始消息数组
|
166
|
+
* @returns 处理后的消息数组
|
167
|
+
*/
|
168
|
+
export const parsePlaceholderVariablesMessages = (messages: any[]): any[] =>
|
169
|
+
messages.map(message => {
|
170
|
+
if (!message?.content) return message;
|
171
|
+
|
172
|
+
const { content } = message;
|
173
|
+
|
174
|
+
// 字符串类型直接处理
|
175
|
+
if (typeof content === 'string') {
|
176
|
+
return { ...message, content: parsePlaceholderVariables(content) };
|
177
|
+
}
|
178
|
+
|
179
|
+
// 数组类型处理其中的 text 元素
|
180
|
+
if (Array.isArray(content)) {
|
181
|
+
return {
|
182
|
+
...message,
|
183
|
+
content: content.map(item =>
|
184
|
+
item?.type === 'text'
|
185
|
+
? { ...item, text: parsePlaceholderVariables(item.text) }
|
186
|
+
: item
|
187
|
+
)
|
188
|
+
};
|
189
|
+
}
|
190
|
+
|
191
|
+
return message;
|
192
|
+
});
|