@lobehub/chat 1.79.10 → 1.80.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 (52) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/changelog/v1.json +15 -0
  3. package/docs/development/basic/feature-development-new.mdx +465 -0
  4. package/docs/development/basic/feature-development-new.zh-CN.mdx +465 -0
  5. package/docs/development/database-schema.dbml +2 -0
  6. package/locales/ar/setting.json +16 -0
  7. package/locales/bg-BG/setting.json +16 -0
  8. package/locales/de-DE/setting.json +16 -0
  9. package/locales/en-US/setting.json +16 -0
  10. package/locales/es-ES/setting.json +16 -0
  11. package/locales/fa-IR/setting.json +16 -0
  12. package/locales/fr-FR/setting.json +16 -0
  13. package/locales/it-IT/setting.json +16 -0
  14. package/locales/ja-JP/setting.json +16 -0
  15. package/locales/ko-KR/setting.json +16 -0
  16. package/locales/nl-NL/setting.json +16 -0
  17. package/locales/pl-PL/setting.json +16 -0
  18. package/locales/pt-BR/setting.json +16 -0
  19. package/locales/ru-RU/setting.json +16 -0
  20. package/locales/tr-TR/setting.json +16 -0
  21. package/locales/vi-VN/setting.json +16 -0
  22. package/locales/zh-CN/setting.json +16 -0
  23. package/locales/zh-TW/setting.json +16 -0
  24. package/package.json +1 -1
  25. package/scripts/generate-oidc-jwk.mjs +2 -1
  26. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/OpeningQuestions.tsx +78 -0
  27. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx +24 -4
  28. package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/CategoryContent/useCategory.tsx +6 -1
  29. package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/index.tsx +2 -0
  30. package/src/const/settings/agent.ts +1 -0
  31. package/src/database/_deprecated/schemas/session.ts +2 -0
  32. package/src/database/client/migrations.json +9 -0
  33. package/src/database/migrations/0021_add_agent_opening_settings.sql +2 -0
  34. package/src/database/migrations/meta/0021_snapshot.json +4988 -0
  35. package/src/database/migrations/meta/_journal.json +7 -0
  36. package/src/database/repositories/dataImporter/deprecated/__tests__/fixtures/messages.json +2 -0
  37. package/src/database/repositories/dataImporter/deprecated/__tests__/index.test.ts +19 -0
  38. package/src/database/schemas/agent.ts +3 -0
  39. package/src/features/AgentSetting/AgentOpening/OpeningMessage.tsx +80 -0
  40. package/src/features/AgentSetting/AgentOpening/OpeningQuestions.tsx +144 -0
  41. package/src/features/AgentSetting/AgentOpening/index.tsx +52 -0
  42. package/src/features/AgentSetting/store/selectors.ts +3 -0
  43. package/src/locales/default/setting.ts +16 -0
  44. package/src/migrations/FromV5ToV6/types/v6.ts +2 -0
  45. package/src/server/routers/lambda/session.ts +8 -1
  46. package/src/services/import/client.test.ts +18 -0
  47. package/src/services/session/server.test.ts +2 -0
  48. package/src/store/agent/slices/chat/selectors/__snapshots__/agent.test.ts.snap +1 -0
  49. package/src/store/agent/slices/chat/selectors/agent.ts +7 -0
  50. package/src/store/global/initialState.ts +1 -0
  51. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +2 -0
  52. package/src/types/agent/index.ts +12 -0
@@ -0,0 +1,465 @@
1
+ # LobeChat 功能开发完全指南 (新版)
2
+
3
+ 本文档旨在指导开发者了解如何在 LobeChat 中开发一块完整的功能需求。
4
+
5
+ 我们将以 [RFC 021 - 自定义助手开场引导](https://github.com/lobehub/lobe-chat/discussions/891) 为例,阐述完整的实现流程。
6
+
7
+ ## 一、更新 schema
8
+
9
+ lobe-chat 使用 postgres 数据库,浏览器端本地数据库使用 [pglite](https://pglite.dev/)(wasm 版本 postgres)。项目还使用了 [drizzle](https://orm.drizzle.team/) ORM 用来操作数据库。
10
+
11
+ 相比旧方案浏览器端使用 indexDB 来说,浏览器端和 server 端都使用 postgres 好处在于 model 层代码可以完全复用。
12
+
13
+ schemas 都统一放在 `src/database/schemas`,我们需要调整 `agents` 表增加两个配置项对应的字段:
14
+
15
+ ```diff
16
+ // src/database/schemas/agent.ts
17
+ export const agents = pgTable(
18
+ 'agents',
19
+ {
20
+ id: text('id')
21
+ .primaryKey()
22
+ .$defaultFn(() => idGenerator('agents'))
23
+ .notNull(),
24
+ avatar: text('avatar'),
25
+ backgroundColor: text('background_color'),
26
+ plugins: jsonb('plugins').$type<string[]>().default([]),
27
+ // ...
28
+ tts: jsonb('tts').$type<LobeAgentTTSConfig>(),
29
+
30
+ + openingMessage: text('opening_message'),
31
+ + openingQuestions: text('opening_questions').array().default([]),
32
+
33
+ ...timestamps,
34
+ },
35
+ (t) => ({
36
+ // ...
37
+ // !: update index here
38
+ }),
39
+ );
40
+
41
+ ```
42
+
43
+ 需要注意的是,有些时候我们可能还需要更新索引,但对于这个需求我们没有相关的性能瓶颈问题,所以不需要更新索引。
44
+
45
+ 调整完 schema 后我们需要运行 `npm run db:generate,` 使用 drizzle-kit 自带的数据库迁移能力生成对应的用于迁移到最新 schema 的 sql 代码。执行后会产生四个文件:
46
+
47
+ - src/database/migrations/meta/\_journal.json:保存每次迁移的相关信息
48
+ - src/database/migrations/0021\_add\_agent\_opening\_settings.sql:此次迁移的 sql 命令
49
+ - src/database/client/migrations.json:pglite 使用的此次迁移的 sql 命令
50
+ - src/database/migrations/meta/0021\_snapshot.json:当前最新的完整数据库快照
51
+
52
+ 注意脚本默认生成的迁移 sql 文件名不会像 `0021_add_agent_opening_settings.sql` 这样语义清晰,你需要自己手动对它重命名并且更新 `src/database/migrations/meta/_journal.json`。
53
+
54
+ 以前客户端存储使用 indexDB 数据迁移相对麻烦,现在本地端使用 pglite 之后数据库迁移就是一条命令的事,非常简单快捷,你也可以检查生成的迁移 sql 是否有什么优化空间,手动调整。
55
+
56
+ ## 二、更新数据模型
57
+
58
+ 在 `src/types` 下定义了我们项目中使用到的各种数据模型,我们并没有直接使用 drizzle schema 导出的类型,例如 `export type NewAgent = typeof agents.$inferInsert;`,而是根据前端需求和 db schema 定义中对应字段数据类型定义了对应的数据模型。
59
+
60
+ 数据模型定义都放在 `src/types` 文件夹下,更新 `src/types/agent/index.ts` 中 `LobeAgentConfig` 类型:
61
+
62
+ ```diff
63
+ export interface LobeAgentConfig {
64
+ // ...
65
+ chatConfig: LobeAgentChatConfig;
66
+ /**
67
+ * 角色所使用的语言模型
68
+ * @default gpt-4o-mini
69
+ */
70
+ model: string;
71
+
72
+ + /**
73
+ + * 开场白
74
+ + */
75
+ + openingMessage?: string;
76
+ + /**
77
+ + * 开场问题
78
+ + */
79
+ + openingQuestions?: string[];
80
+
81
+ /**
82
+ * 语言模型参数
83
+ */
84
+ params: LLMParams;
85
+ /**
86
+ * 启用的插件
87
+ */
88
+ plugins?: string[];
89
+
90
+ /**
91
+ * 模型供应商
92
+ */
93
+ provider?: string;
94
+
95
+ /**
96
+ * 系统角色
97
+ */
98
+ systemRole: string;
99
+
100
+ /**
101
+ * 语音服务
102
+ */
103
+ tts: LobeAgentTTSConfig;
104
+ }
105
+ ```
106
+
107
+ ## 三、Service 实现 / Model 实现
108
+
109
+ - `model` 层封装对 DB 的可复用操作
110
+ - `service` 层实现应用业务逻辑
111
+
112
+ 在 `src` 目录下都有对应的顶层文件夹。
113
+
114
+ 我们需要查看是否需要更新其实现,agent 配置在前端被抽象成 session 的配置,在 `src/services/session/server.ts` 中可以看到有个 service 函数 `updateSessionConfig`:
115
+
116
+ ```typescript
117
+ export class ServerService implements ISessionService {
118
+ // ...
119
+ updateSessionConfig: ISessionService['updateSessionConfig'] = (id, config, signal) => {
120
+ return lambdaClient.session.updateSessionConfig.mutate({ id, value: config }, { signal });
121
+ };
122
+ }
123
+ ```
124
+
125
+ 跳转 `lambdaClient.session.updateSessionConfig` 实现,发现它只是简单的 **merge** 了新的 config 和旧的 config。
126
+
127
+ ```typescript
128
+ export const sessionRouter = router({
129
+ // ..
130
+ updateSessionConfig: sessionProcedure
131
+ .input(
132
+ z.object({
133
+ id: z.string(),
134
+ value: z.object({}).passthrough().partial(),
135
+ }),
136
+ )
137
+ .mutation(async ({ input, ctx }) => {
138
+ const session = await ctx.sessionModel.findByIdOrSlug(input.id);
139
+ // ...
140
+ const mergedValue = merge(session.agent, input.value);
141
+ return ctx.sessionModel.updateConfig(session.agent.id, mergedValue);
142
+ }),
143
+ });
144
+ ```
145
+
146
+ 可以预想的到,我们前端会增加两个输入,用户修改的时候去调用这个 `updateSessionConfig`,我们只需要把新的字段 `openingMessage` 和 `openingQuestions` 传过来 merge 就好了。
147
+
148
+ 因此,service 层和 model 层不需要修改。
149
+
150
+ ## 四、前端实现
151
+
152
+ ### 数据流 store 实现
153
+
154
+ lobe-chat 使用 [zustand](https://zustand.docs.pmnd.rs/getting-started/introduction) 作为全局状态管理框架,对于状态管理的详细实践介绍,可以查阅 [📘 状态管理最佳实践](/zh/docs/development/state-management/state-management-intro)。
155
+
156
+ 和 agent 相关的 store 有两个:
157
+
158
+ - `src/features/AgentSetting/store` 服务于 agent 设置的局部 store
159
+ - `src/store/agent` 用于获取当前会话 agent 的 store
160
+
161
+ 后者通过 `src/features/AgentSetting/AgentSettings.tsx` 中 `AgentSettings` 组件的 `onConfigChange` 监听并更新当前会话的 agent 配置。
162
+
163
+ #### 更新 AgentSetting/store
164
+
165
+ 首先我们更新 initialState,阅读 `src/features/AgentSetting/store/initialState.ts` 后得知初始 agent 配置保存在 `src/const/settings/agent.ts` 中的 `DEFAULT_AGENT_CONFIG`:
166
+
167
+ ```diff
168
+ export const DEFAULT_AGENT_CONFIG: LobeAgentConfig = {
169
+ chatConfig: DEFAULT_AGENT_CHAT_CONFIG,
170
+ model: DEFAULT_MODEL,
171
+ + openingQuestions: [],
172
+ params: {
173
+ frequency_penalty: 0,
174
+ presence_penalty: 0,
175
+ temperature: 1,
176
+ top_p: 1,
177
+ },
178
+ plugins: [],
179
+ provider: DEFAULT_PROVIDER,
180
+ systemRole: '',
181
+ tts: DEFAUTT_AGENT_TTS_CONFIG,
182
+ };
183
+ ```
184
+
185
+ 其实你这里不更新都可以,因为 `openingQuestions` 类型本来就是可选的,`openingMessage` 我这里就不更新了。
186
+
187
+ 因为我们增加了两个新字段,为了方便在 `src/features/AgentSetting/AgentOpening` 文件夹中组件访问和性能优化,我们在 `src/features/AgentSetting/store/selectors.ts` 增加相关的 selectors:
188
+
189
+ ```diff
190
+ import { DEFAULT_AGENT_CHAT_CONFIG } from '@/const/settings';
191
+ import { LobeAgentChatConfig } from '@/types/agent';
192
+
193
+ import { Store } from './action';
194
+
195
+ const chatConfig = (s: Store): LobeAgentChatConfig =>
196
+ s.config.chatConfig || DEFAULT_AGENT_CHAT_CONFIG;
197
+
198
+ +export const DEFAULT_OPENING_QUESTIONS: string[] = [];
199
+ export const selectors = {
200
+ chatConfig,
201
+ + openingMessage: (s: Store) => s.config.openingMessage,
202
+ + openingQuestions: (s: Store) => s.config.openingQuestions || DEFAULT_OPENING_QUESTIONS,
203
+ };
204
+ ```
205
+
206
+ 这里我们就不增加额外的 action 用于更新 agent config 了,因为我观察到已有的其它代码也是直接使用现有代码中统一的 `setChatConfig`:
207
+
208
+ ```typescript
209
+ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, get) => ({
210
+ setAgentConfig: (config) => {
211
+ get().dispatchConfig({ config, type: 'update' });
212
+ },
213
+ });
214
+ ```
215
+
216
+ #### 更新 store/agent
217
+
218
+ 在组件 `src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx` 我们使用了这个 store 用于获取当前 agent 配置,用来渲染用户自定义的开场消息和引导性问题。
219
+
220
+ 这里因为只需要读取两个配置项,我们就简单的加两个 selectors 就好了:
221
+
222
+ 更新 `src/store/agent/slices/chat/selectors/agent.ts`:
223
+
224
+ ```diff
225
+ // ...
226
+ +const openingQuestions = (s: AgentStoreState) =>
227
+ + currentAgentConfig(s).openingQuestions || DEFAULT_OPENING_QUESTIONS;
228
+ +const openingMessage = (s: AgentStoreState) => currentAgentConfig(s).openingMessage || '';
229
+
230
+ export const agentSelectors = {
231
+ // ...
232
+ isInboxSession,
233
+ + openingMessage,
234
+ + openingQuestions,
235
+ };
236
+ ```
237
+
238
+ ### UI 实现和 action 绑定
239
+
240
+ 我们这次要新增一个类别的设置, 在 `src/features/AgentSetting` 中定义了 agent 的各种设置的 UI 组件,这次我们要增加一个设置类型:开场设置。增加一个文件夹 `AgentOpening` 存放开场设置相关的组件。项目使用了:
241
+
242
+ - [ant-design](https://ant.design/) 和 [lobe-ui:](https://github.com/lobehub/lobe-ui)组件库
243
+ - [antd-style](https://ant-design.github.io/antd-style) : css-in-js 方案
244
+ - [react-layout-kit](https://github.com/arvinxx/react-layout-kit):响应式布局组件
245
+ - [@ant-design/icons](https://ant.design/components/icon-cn) 和 [lucide](https://lucide.dev/icons/): 图标库
246
+ - [react-i18next](https://github.com/i18next/react-i18next) 和 [lobe-i18n](https://github.com/lobehub/lobe-cli-toolbox/tree/master/packages/lobe-i18n) :i18n 框架和多语言自动翻译工具
247
+
248
+ lobe-chat 是个国际化项目,新加的文案需要更新默认的 `locale` 文件: `src/locales/default/setting.ts` 。
249
+
250
+ 我们以子组件 `OpeningQuestion.tsx` 为例,组件实现:
251
+
252
+ ```typescript
253
+ // src/features/AgentSetting/AgentOpening/OpeningQuestions.tsx
254
+ 'use client';
255
+
256
+ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
257
+ import { SortableList } from '@lobehub/ui';
258
+ import { Button, Empty, Input } from 'antd';
259
+ import { createStyles } from 'antd-style';
260
+ import { memo, useCallback, useMemo, useState } from 'react';
261
+ import { useTranslation } from 'react-i18next';
262
+ import { Flexbox } from 'react-layout-kit';
263
+
264
+ import { useStore } from '../store';
265
+ import { selectors } from '../store/selectors';
266
+
267
+ const useStyles = createStyles(({ css, token }) => ({
268
+ empty: css`
269
+ margin-block: 24px;
270
+ margin-inline: 0;
271
+ `,
272
+ questionItemContainer: css`
273
+ margin-block-end: 8px;
274
+ padding-block: 2px;
275
+ padding-inline: 10px 0;
276
+ background: ${token.colorBgContainer};
277
+ `,
278
+ questionItemContent: css`
279
+ flex: 1;
280
+ `,
281
+ questionsList: css`
282
+ width: 100%;
283
+ margin-block-start: 16px;
284
+ `,
285
+ repeatError: css`
286
+ margin: 0;
287
+ color: ${token.colorErrorText};
288
+ `,
289
+ }));
290
+
291
+ interface QuestionItem {
292
+ content: string;
293
+ id: number;
294
+ }
295
+
296
+ const OpeningQuestions = memo(() => {
297
+ const { t } = useTranslation('setting');
298
+ const { styles } = useStyles();
299
+ const [questionInput, setQuestionInput] = useState('');
300
+
301
+ // 使用 selector 访问对应配置
302
+ const openingQuestions = useStore(selectors.openingQuestions);
303
+ // 使用 action 更新配置
304
+ const updateConfig = useStore((s) => s.setAgentConfig);
305
+ const setQuestions = useCallback(
306
+ (questions: string[]) => {
307
+ updateConfig({ openingQuestions: questions });
308
+ },
309
+ [updateConfig],
310
+ );
311
+
312
+ const addQuestion = useCallback(() => {
313
+ if (!questionInput.trim()) return;
314
+
315
+ setQuestions([...openingQuestions, questionInput.trim()]);
316
+ setQuestionInput('');
317
+ }, [openingQuestions, questionInput, setQuestions]);
318
+
319
+ const removeQuestion = useCallback(
320
+ (content: string) => {
321
+ const newQuestions = [...openingQuestions];
322
+ const index = newQuestions.indexOf(content);
323
+ newQuestions.splice(index, 1);
324
+ setQuestions(newQuestions);
325
+ },
326
+ [openingQuestions, setQuestions],
327
+ );
328
+
329
+ // 处理拖拽排序后的逻辑
330
+ const handleSortEnd = useCallback(
331
+ (items: QuestionItem[]) => {
332
+ setQuestions(items.map((item) => item.content));
333
+ },
334
+ [setQuestions],
335
+ );
336
+
337
+ const items: QuestionItem[] = useMemo(() => {
338
+ return openingQuestions.map((item, index) => ({
339
+ content: item,
340
+ id: index,
341
+ }));
342
+ }, [openingQuestions]);
343
+
344
+ const isRepeat = openingQuestions.includes(questionInput.trim());
345
+
346
+ return (
347
+ <Flexbox gap={8}>
348
+ <Flexbox gap={4}>
349
+ <Input
350
+ addonAfter={
351
+ <Button
352
+ // don't allow repeat
353
+ disabled={openingQuestions.includes(questionInput.trim())}
354
+ icon={<PlusOutlined />}
355
+ onClick={addQuestion}
356
+ size="small"
357
+ type="text"
358
+ />
359
+ }
360
+ onChange={(e) => setQuestionInput(e.target.value)}
361
+ onPressEnter={addQuestion}
362
+ placeholder={t('settingOpening.openingQuestions.placeholder')}
363
+ value={questionInput}
364
+ />
365
+
366
+ {isRepeat && (
367
+ <p className={styles.repeatError}>{t('settingOpening.openingQuestions.repeat')}</p>
368
+ )}
369
+ </Flexbox>
370
+
371
+ <div className={styles.questionsList}>
372
+ {openingQuestions.length > 0 ? (
373
+ <SortableList
374
+ items={items}
375
+ onChange={handleSortEnd}
376
+ renderItem={(item) => (
377
+ <SortableList.Item className={styles.questionItemContainer} id={item.id}>
378
+ <SortableList.DragHandle />
379
+ <div className={styles.questionItemContent}>{item.content}</div>
380
+ <Button
381
+ icon={<DeleteOutlined />}
382
+ onClick={() => removeQuestion(item.content)}
383
+ type="text"
384
+ />
385
+ </SortableList.Item>
386
+ )}
387
+ />
388
+ ) : (
389
+ <Empty
390
+ className={styles.empty}
391
+ description={t('settingOpening.openingQuestions.empty')}
392
+ />
393
+ )}
394
+ </div>
395
+ </Flexbox>
396
+ );
397
+ });
398
+
399
+ export default OpeningQuestions;
400
+ ```
401
+
402
+ 同时我们需要将用户设置的开场配置展示出来,这个是在 chat 页面,对应组件在 `src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx`:
403
+
404
+ ```typescript
405
+ const WelcomeMessage = () => {
406
+ const { t } = useTranslation('chat');
407
+
408
+ // 获取当前开场配置
409
+ const openingMessage = useAgentStore(agentSelectors.openingMessage);
410
+ const openingQuestions = useAgentStore(agentSelectors.openingQuestions);
411
+
412
+ const meta = useSessionStore(sessionMetaSelectors.currentAgentMeta, isEqual);
413
+ const { isAgentEditable } = useServerConfigStore(featureFlagsSelectors);
414
+ const activeId = useChatStore((s) => s.activeId);
415
+
416
+ const agentSystemRoleMsg = t('agentDefaultMessageWithSystemRole', {
417
+ name: meta.title || t('defaultAgent'),
418
+ systemRole: meta.description,
419
+ });
420
+
421
+ const agentMsg = t(isAgentEditable ? 'agentDefaultMessage' : 'agentDefaultMessageWithoutEdit', {
422
+ name: meta.title || t('defaultAgent'),
423
+ url: `/chat/settings?session=${activeId}`,
424
+ });
425
+
426
+ const message = useMemo(() => {
427
+ // 用户设置了就用用户设置的
428
+ if (openingMessage) return openingMessage;
429
+ return !!meta.description ? agentSystemRoleMsg : agentMsg;
430
+ }, [openingMessage, agentSystemRoleMsg, agentMsg, meta.description]);
431
+
432
+ const chatItem = (
433
+ <ChatItem
434
+ avatar={meta}
435
+ editing={false}
436
+ message={message}
437
+ placement={'left'}
438
+ type={type === 'chat' ? 'block' : 'pure'}
439
+ />
440
+ );
441
+
442
+ return openingQuestions.length > 0 ? (
443
+ <Flexbox>
444
+ {chatItem}
445
+ {/* 渲染引导性问题 */}
446
+ <OpeningQuestions mobile={mobile} questions={openingQuestions} />
447
+ </Flexbox>
448
+ ) : (
449
+ chatItem
450
+ );
451
+ };
452
+ export default WelcomeMessage;
453
+ ```
454
+
455
+ ## 五、测试
456
+
457
+ 项目使用 vitest 进行单元测试。
458
+
459
+ 由于我们目前两个新的配置字段都是可选的,所以理论上你不更新测试也能跑通,不过由于我们把前面提到的默认配置 `DEFAULT_AGENT_CONFIG` 增加了 `openingQuestions` 字段,这导致很多测试计算出的配置都是有这个字段的,因此我们还是需要更新一部分测试的快照。
460
+
461
+ 对于当前这个场景,我建议是本地直接跑下测试,看哪些测试失败了,针对需要更新,例如测试文件 `src/store/agent/slices/chat/selectors/agent.test.ts` 需要执行一下 `npx vitest -u src/store/agent/slices/chat/selectors/agent.test.ts` 更新快照。
462
+
463
+ ## 总结
464
+
465
+ 以上就是 LobeChat 开场设置功能的完整实现流程。开发者可以参考本文档进行相关功能的开发和测试。
@@ -16,6 +16,8 @@ table agents {
16
16
  provider text
17
17
  system_role text
18
18
  tts jsonb
19
+ opening_message text
20
+ opening_questions text[] [default: `[]`]
19
21
  accessed_at "timestamp with time zone" [not null, default: `now()`]
20
22
  created_at "timestamp with time zone" [not null, default: `now()`]
21
23
  updated_at "timestamp with time zone" [not null, default: `now()`]
@@ -6,6 +6,7 @@
6
6
  "chat": "تفضيلات الدردشة",
7
7
  "meta": "معلومات المساعد",
8
8
  "modal": "إعدادات النموذج",
9
+ "opening": "إعداد الافتتاح",
9
10
  "plugin": "إعدادات الإضافة",
10
11
  "prompt": "تعيين الشخصية",
11
12
  "tts": "خدمة النص إلى كلام"
@@ -253,6 +254,21 @@
253
254
  "title": "مستوى الانفتاح الفكري"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "رسالة الافتتاح عند بدء المحادثة، تستخدم لتعريف وظائف المساعد",
260
+ "placeholder": "مرحبًا، أنا المساعد المخصص، يمكنك بدء المحادثة معي على الفور، أو يمكنك الذهاب إلى إعدادات المساعد لإكمال معلوماتي.",
261
+ "title": "رسالة الافتتاح"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "الأسئلة الإرشادية المعروضة عند بدء المحادثة",
265
+ "empty": "لا توجد أسئلة حالياً",
266
+ "placeholder": "أدخل السؤال",
267
+ "repeat": "السؤال موجود بالفعل",
268
+ "title": "أسئلة الافتتاح"
269
+ },
270
+ "title": "إعداد الافتتاح"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "قائمة الإضافات"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "Предпочитания за чат",
7
7
  "meta": "Информация за асистента",
8
8
  "modal": "Настройки на модела",
9
+ "opening": "Настройка на откритие",
9
10
  "plugin": "Настройки на добавката",
10
11
  "prompt": "Настройки на ролята",
11
12
  "tts": "Гласова услуга"
@@ -253,6 +254,21 @@
253
254
  "title": "Отвореност на мисленето"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "Съобщение за откритие при стартиране на сесия, използвано за представяне на функциите на асистента",
260
+ "placeholder": "Здравей, аз съм Персонализиран асистент, можеш веднага да започнеш разговор с мен или да отидеш в Настройки на асистента, за да попълниш информацията ми.",
261
+ "title": "Съобщение за откритие"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "Водещи въпроси, показвани в началото на сесията",
265
+ "empty": "Няма въпроси",
266
+ "placeholder": "Въведете въпрос",
267
+ "repeat": "Въпросът вече съществува",
268
+ "title": "Въпроси за откритие"
269
+ },
270
+ "title": "Настройка на откритие"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "Списък с плъгини"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "Chat-Präferenz",
7
7
  "meta": "Assistenteninformation",
8
8
  "modal": "Modell-Einstellungen",
9
+ "opening": "Eröffnungs Einstellungen",
9
10
  "plugin": "Plugin-Einstellungen",
10
11
  "prompt": "Rollenkonfiguration",
11
12
  "tts": "Sprachdienst"
@@ -253,6 +254,21 @@
253
254
  "title": "Offenheit des Denkens"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "Die Eröffnungsnachricht beim Start des Gesprächs, um die Funktionen des Assistenten vorzustellen",
260
+ "placeholder": "Hallo, ich bin der benutzerdefinierte Assistent. Du kannst sofort mit mir sprechen oder zu den Assistenteneinstellungen gehen, um meine Informationen zu vervollständigen.",
261
+ "title": "Eröffnungsnachricht"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "Leitfragen, die zu Beginn des Gesprächs angezeigt werden",
265
+ "empty": "Keine Fragen vorhanden",
266
+ "placeholder": "Bitte Frage eingeben",
267
+ "repeat": "Frage existiert bereits",
268
+ "title": "Eröffnungsfragen"
269
+ },
270
+ "title": "Eröffnungs Einstellungen"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "Plugin-Liste"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "Chat Preferences",
7
7
  "meta": "Assistant Info",
8
8
  "modal": "Model Settings",
9
+ "opening": "Opening Settings",
9
10
  "plugin": "Plugin Settings",
10
11
  "prompt": "Role Configuration",
11
12
  "tts": "Voice Service"
@@ -253,6 +254,21 @@
253
254
  "title": "Openness to Ideas"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "The opening message displayed when the conversation starts, used to introduce the assistant's features",
260
+ "placeholder": "Hello, I am your Custom Assistant. You can start chatting with me right away, or go to Assistant Settings to complete my information.",
261
+ "title": "Opening Message"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "Guiding questions displayed at the beginning of the conversation",
265
+ "empty": "No questions available",
266
+ "placeholder": "Please enter a question",
267
+ "repeat": "Question already exists",
268
+ "title": "Opening Questions"
269
+ },
270
+ "title": "Opening Settings"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "Plugin List"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "Preferencias de chat",
7
7
  "meta": "Información del asistente",
8
8
  "modal": "Configuración del modelo",
9
+ "opening": "Configuración de apertura",
9
10
  "plugin": "Configuración de complementos",
10
11
  "prompt": "Configuración de roles",
11
12
  "tts": "Servicio de voz"
@@ -253,6 +254,21 @@
253
254
  "title": "Apertura mental"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "Mensaje de apertura al iniciar la conversación, utilizado para presentar las funciones del asistente",
260
+ "placeholder": "Hola, soy el asistente personalizado, puedes comenzar a hablar conmigo de inmediato o ir a la configuración del asistente para completar mi información.",
261
+ "title": "Mensaje de apertura"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "Preguntas orientativas que se muestran al inicio de la conversación",
265
+ "empty": "No hay preguntas disponibles",
266
+ "placeholder": "Introduce una pregunta",
267
+ "repeat": "La pregunta ya existe",
268
+ "title": "Preguntas de apertura"
269
+ },
270
+ "title": "Configuración de apertura"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "Lista de complementos"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "ترجیحات گفتگو",
7
7
  "meta": "اطلاعات دستیار",
8
8
  "modal": "تنظیمات مدل",
9
+ "opening": "تنظیمات آغازین",
9
10
  "plugin": "تنظیمات افزونه",
10
11
  "prompt": "تنظیمات شخصیت",
11
12
  "tts": "خدمات صوتی"
@@ -253,6 +254,21 @@
253
254
  "title": "باز بودن ذهن"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "پیام آغازین هنگام باز کردن گفتگو، برای معرفی قابلیت‌های دستیار",
260
+ "placeholder": "سلام، من دستیار سفارشی هستم، می‌توانید بلافاصله با من گفتگو کنید یا به تنظیمات دستیار بروید تا اطلاعات من را تکمیل کنید.",
261
+ "title": "پیام آغازین"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "سوالات راهنمایی که در ابتدای گفتگو نمایش داده می‌شوند",
265
+ "empty": "سوالی وجود ندارد",
266
+ "placeholder": "لطفاً سوال را وارد کنید",
267
+ "repeat": "سوال قبلاً وجود دارد",
268
+ "title": "سوالات آغازین"
269
+ },
270
+ "title": "تنظیمات آغازین"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "فهرست افزونه‌ها"
258
274
  },
@@ -6,6 +6,7 @@
6
6
  "chat": "Préférences de discussion",
7
7
  "meta": "Informations de l'agent",
8
8
  "modal": "Paramètres du modèle",
9
+ "opening": "Paramètres d'ouverture",
9
10
  "plugin": "Paramètres du plugin",
10
11
  "prompt": "Configuration du rôle",
11
12
  "tts": "Service vocal"
@@ -253,6 +254,21 @@
253
254
  "title": "Ouverture d'esprit"
254
255
  }
255
256
  },
257
+ "settingOpening": {
258
+ "openingMessage": {
259
+ "desc": "Message d'ouverture lors de l'initiation de la conversation, utilisé pour présenter les fonctionnalités de l'assistant",
260
+ "placeholder": "Bonjour, je suis l'assistant personnalisé, vous pouvez commencer à discuter avec moi immédiatement ou aller dans les paramètres de l'assistant pour compléter mes informations.",
261
+ "title": "Message d'ouverture"
262
+ },
263
+ "openingQuestions": {
264
+ "desc": "Questions d'orientation affichées au début de la conversation",
265
+ "empty": "Aucune question pour le moment",
266
+ "placeholder": "Veuillez entrer une question",
267
+ "repeat": "La question existe déjà",
268
+ "title": "Questions d'ouverture"
269
+ },
270
+ "title": "Paramètres d'ouverture"
271
+ },
256
272
  "settingPlugin": {
257
273
  "title": "Liste des plugins"
258
274
  },