@lobehub/chat 1.91.2 → 1.92.0

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.
Files changed (41) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +74 -0
  3. package/changelog/v1.json +27 -0
  4. package/locales/ar/setting.json +1 -1
  5. package/locales/bg-BG/setting.json +1 -1
  6. package/locales/de-DE/setting.json +1 -1
  7. package/locales/en-US/setting.json +1 -1
  8. package/locales/es-ES/setting.json +1 -1
  9. package/locales/fa-IR/setting.json +1 -1
  10. package/locales/fr-FR/setting.json +1 -1
  11. package/locales/it-IT/setting.json +1 -1
  12. package/locales/ja-JP/setting.json +1 -1
  13. package/locales/ko-KR/setting.json +1 -1
  14. package/locales/nl-NL/setting.json +1 -1
  15. package/locales/pl-PL/setting.json +1 -1
  16. package/locales/pt-BR/setting.json +1 -1
  17. package/locales/ru-RU/setting.json +1 -1
  18. package/locales/tr-TR/setting.json +1 -1
  19. package/locales/vi-VN/setting.json +1 -1
  20. package/locales/zh-CN/setting.json +1 -1
  21. package/locales/zh-TW/setting.json +1 -1
  22. package/package.json +1 -1
  23. package/src/app/[variants]/(main)/profile/features/ClerkProfile.tsx +1 -4
  24. package/src/config/aiModels/modelscope.ts +4 -1
  25. package/src/config/aiModels/novita.ts +2 -0
  26. package/src/config/aiModels/openrouter.ts +2 -0
  27. package/src/config/aiModels/siliconcloud.ts +1 -0
  28. package/src/config/modelProviders/anthropic.ts +30 -11
  29. package/src/config/modelProviders/openai.ts +14 -0
  30. package/src/features/AgentSetting/AgentModal/index.tsx +3 -2
  31. package/src/features/ChatInput/ActionBar/Search/Controls.tsx +6 -2
  32. package/src/layout/AuthProvider/Clerk/useAppearance.ts +1 -4
  33. package/src/libs/model-runtime/utils/streams/vertex-ai.ts +12 -0
  34. package/src/locales/default/setting.ts +1 -1
  35. package/src/services/chat.ts +17 -9
  36. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +23 -31
  37. package/src/store/user/slices/auth/selectors.test.ts +18 -0
  38. package/src/store/user/slices/auth/selectors.ts +1 -0
  39. package/src/utils/client/parserPlaceholder.test.ts +326 -0
  40. package/src/utils/client/parserPlaceholder.ts +190 -0
  41. package/src/app/[variants]/(main)/settings/provider/(detail)/ollama/OllamaModelDownloader/index.tsx +0 -0
@@ -0,0 +1,190 @@
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
+ * | `{{nickname}}` | 社区版用户 |
57
+ * | `{{username}}` | LobeChat |
58
+ *
59
+ */
60
+ nickname: () => userProfileSelectors.nickName(useUserStore.getState()) ?? '',
61
+ username: () => userProfileSelectors.username(useUserStore.getState()) ?? userProfileSelectors.fullName(useUserStore.getState()) ?? '',
62
+
63
+ /**
64
+ * 随机值类模板变量
65
+ *
66
+ * | Value | Example |
67
+ * |-------|---------|
68
+ * | `{{random}}` | 100041 |
69
+ * | `{{random_bool}}` | true |
70
+ * | `{{random_float}}` | 76.02 |
71
+ * | `{{random_hex}}` | de0dbd |
72
+ * | `{{random_int}}` | 68 |
73
+ * | `{{random_string}}` | wqn9zfrqe7h |
74
+ *
75
+ */
76
+ random: () => Math.floor(Math.random() * 1_000_000 + 1).toString(),
77
+ random_bool: () => (Math.random() > 0.5 ? 'true' : 'false'),
78
+ random_float: () => (Math.random() * 100).toFixed(2),
79
+ random_hex: () => Math.floor(Math.random() * 16_777_215).toString(16).padStart(6, '0'),
80
+ random_int: () => Math.floor(Math.random() * 100 + 1).toString(),
81
+ random_string: () => Math.random().toString(36).slice(2, 15),
82
+ random_digit: () => Math.floor(Math.random() * 10).toString(),
83
+
84
+ /**
85
+ * UUID 类模板变量
86
+ *
87
+ * | Value | Example |
88
+ * |-------|---------|
89
+ * | `{{uuid}}` | dd90b35-669f-4e87-beb8-ac6877f6995d |
90
+ * | `{{uuid_short}}` | dd90b35 |
91
+ *
92
+ */
93
+ uuid: () => uuid(),
94
+ uuid_short: () => uuid().split('-')[0],
95
+
96
+ /**
97
+ * 平台类模板变量
98
+ *
99
+ * | Value | Example |
100
+ * |-------|---------|
101
+ * | `{{language}}` | zh-CN |
102
+ * | `{{platform}}` | MacIntel |
103
+ * | `{{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 |
104
+ *
105
+ */
106
+ language: () => typeof navigator !== 'undefined' ? navigator.language : '',
107
+ platform: () => typeof navigator !== 'undefined' ? navigator.platform : '',
108
+ user_agent: () => typeof navigator !== 'undefined' ? navigator.userAgent : '',
109
+
110
+ /**
111
+ * LobeChat 模板变量
112
+ *
113
+ * | Value | Example |
114
+ * |-------|---------|
115
+ * | `{{input_template}}` | Some contents |
116
+ *
117
+ */
118
+ input_template: () => agentChatConfigSelectors.currentChatConfig(getAgentStoreState()).inputTemplate || '',
119
+ } as Record<string, () => string>;
120
+
121
+ /**
122
+ * 从文本中提取所有 {{variable}} 占位符的变量名
123
+ * @param text 包含模板变量的字符串
124
+ * @returns 变量名数组,如 ['date', 'nickname']
125
+ */
126
+ const extractPlaceholderVariables = (text: string): string[] => {
127
+ const matches = [...text.matchAll(placeholderVariablesRegex)];
128
+ return matches.map(m => m[1].trim());
129
+ };
130
+
131
+ /**
132
+ * 将模板变量替换为实际值,并支持递归解析嵌套变量
133
+ * @param text - 含变量的原始文本
134
+ * @param depth - 递归深度,默认 1,设置更高可支持 {{input_template}} 中的 {{date}} 等
135
+ * @returns 替换后的文本
136
+ */
137
+ export const parsePlaceholderVariables = (text: string, depth = 2): string => {
138
+ let result = text;
139
+
140
+ // 递归解析,用于处理如 {{input_template}} 存在额外预设变量
141
+ for (let i = 0; i < depth; i++) {
142
+ try {
143
+ const variables = Object.fromEntries(
144
+ extractPlaceholderVariables(result)
145
+ .map((key) => [key, VARIABLE_GENERATORS[key]?.()])
146
+ .filter(([, value]) => value !== undefined)
147
+ );
148
+
149
+ const replaced = template(result, { interpolate: placeholderVariablesRegex })(variables);
150
+ if (replaced === result) break;
151
+
152
+ result = replaced;
153
+ } catch {
154
+ break;
155
+ }
156
+ }
157
+
158
+ return result;
159
+ };
160
+
161
+ /**
162
+ * 解析消息内容,替换占位符变量
163
+ * @param messages 原始消息数组
164
+ * @returns 处理后的消息数组
165
+ */
166
+ export const parsePlaceholderVariablesMessages = (messages: any[]): any[] =>
167
+ messages.map(message => {
168
+ if (!message?.content) return message;
169
+
170
+ const { content } = message;
171
+
172
+ // 字符串类型直接处理
173
+ if (typeof content === 'string') {
174
+ return { ...message, content: parsePlaceholderVariables(content) };
175
+ }
176
+
177
+ // 数组类型处理其中的 text 元素
178
+ if (Array.isArray(content)) {
179
+ return {
180
+ ...message,
181
+ content: content.map(item =>
182
+ item?.type === 'text'
183
+ ? { ...item, text: parsePlaceholderVariables(item.text) }
184
+ : item
185
+ )
186
+ };
187
+ }
188
+
189
+ return message;
190
+ });