@lobehub/chat 1.36.46 → 1.37.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.ja-JP.md +8 -8
  3. package/README.md +8 -8
  4. package/README.zh-CN.md +8 -8
  5. package/changelog/v1.json +18 -0
  6. package/next.config.mjs +4 -1
  7. package/package.json +5 -3
  8. package/scripts/migrateClientDB/compile-migrations.ts +14 -0
  9. package/src/app/(main)/(mobile)/me/(home)/layout.tsx +2 -0
  10. package/src/app/(main)/chat/_layout/Desktop/index.tsx +3 -2
  11. package/src/app/(main)/chat/_layout/Mobile.tsx +5 -3
  12. package/src/app/(main)/chat/features/Migration/DBReader.ts +290 -0
  13. package/src/app/(main)/chat/features/Migration/UpgradeButton.tsx +4 -8
  14. package/src/app/(main)/chat/features/Migration/index.tsx +26 -15
  15. package/src/app/(main)/settings/_layout/Desktop/index.tsx +2 -0
  16. package/src/app/loading/Client/Content.tsx +11 -1
  17. package/src/app/loading/Client/Error.tsx +27 -0
  18. package/src/app/loading/stage.ts +8 -0
  19. package/src/components/FullscreenLoading/index.tsx +4 -3
  20. package/src/const/version.ts +1 -0
  21. package/src/database/client/db.test.ts +172 -0
  22. package/src/database/client/db.ts +246 -0
  23. package/src/database/client/migrations.json +289 -0
  24. package/src/features/InitClientDB/EnableModal.tsx +111 -0
  25. package/src/features/InitClientDB/ErrorResult.tsx +125 -0
  26. package/src/features/InitClientDB/InitIndicator.tsx +124 -0
  27. package/src/features/InitClientDB/PGliteSVG.tsx +22 -0
  28. package/src/features/InitClientDB/index.tsx +37 -0
  29. package/src/hooks/useCheckPluginsIsInstalled.ts +2 -2
  30. package/src/hooks/useFetchInstalledPlugins.ts +2 -2
  31. package/src/hooks/useFetchMessages.ts +2 -2
  32. package/src/hooks/useFetchSessions.ts +2 -2
  33. package/src/hooks/useFetchThreads.ts +2 -2
  34. package/src/hooks/useFetchTopics.ts +2 -2
  35. package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -2
  36. package/src/services/baseClientService/index.ts +9 -0
  37. package/src/services/debug.ts +32 -34
  38. package/src/services/file/{client.test.ts → _deprecated.test.ts} +1 -1
  39. package/src/services/file/index.ts +6 -2
  40. package/src/services/file/pglite.test.ts +198 -0
  41. package/src/services/file/pglite.ts +84 -0
  42. package/src/services/file/type.ts +4 -3
  43. package/src/services/github.ts +17 -0
  44. package/src/services/import/index.ts +6 -2
  45. package/src/services/import/pglite.test.ts +997 -0
  46. package/src/services/import/pglite.ts +34 -0
  47. package/src/services/message/{client.test.ts → _deprecated.test.ts} +1 -1
  48. package/src/services/message/{client.ts → _deprecated.ts} +2 -0
  49. package/src/services/message/index.ts +6 -2
  50. package/src/services/message/pglite.test.ts +430 -0
  51. package/src/services/message/pglite.ts +118 -0
  52. package/src/services/message/server.ts +9 -9
  53. package/src/services/message/type.ts +3 -4
  54. package/src/services/plugin/{client.test.ts → _deprecated.test.ts} +1 -1
  55. package/src/services/plugin/index.ts +6 -2
  56. package/src/services/plugin/pglite.test.ts +175 -0
  57. package/src/services/plugin/pglite.ts +51 -0
  58. package/src/services/session/{client.test.ts → _deprecated.test.ts} +1 -1
  59. package/src/services/session/{client.ts → _deprecated.ts} +1 -1
  60. package/src/services/session/index.ts +6 -2
  61. package/src/services/session/pglite.test.ts +411 -0
  62. package/src/services/session/pglite.ts +184 -0
  63. package/src/services/session/type.ts +14 -1
  64. package/src/services/topic/client.test.ts +1 -1
  65. package/src/services/topic/index.ts +6 -3
  66. package/src/services/topic/pglite.test.ts +212 -0
  67. package/src/services/topic/pglite.ts +85 -0
  68. package/src/services/user/{client.test.ts → _deprecated.test.ts} +1 -2
  69. package/src/services/user/index.ts +8 -2
  70. package/src/services/user/pglite.test.ts +98 -0
  71. package/src/services/user/pglite.ts +92 -0
  72. package/src/store/chat/slices/builtinTool/action.test.ts +4 -5
  73. package/src/store/global/actions/clientDb.ts +51 -0
  74. package/src/store/global/initialState.ts +13 -0
  75. package/src/store/global/selectors.ts +24 -3
  76. package/src/store/global/store.ts +3 -1
  77. package/src/store/session/slices/sessionGroup/reducer.test.ts +6 -6
  78. package/src/store/user/slices/common/action.test.ts +1 -1
  79. package/src/store/user/slices/common/action.ts +2 -4
  80. package/src/types/clientDB.ts +29 -0
  81. package/src/types/importer.ts +17 -5
  82. package/src/types/meta.ts +0 -9
  83. package/src/types/session/sessionGroup.ts +3 -3
  84. package/src/services/message/index.test.ts +0 -48
  85. /package/src/services/file/{client.ts → _deprecated.ts} +0 -0
  86. /package/src/services/import/{client.ts → _deprecated.ts} +0 -0
  87. /package/src/services/plugin/{client.ts → _deprecated.ts} +0 -0
  88. /package/src/services/topic/{client.ts → _deprecated.ts} +0 -0
  89. /package/src/services/user/{client.ts → _deprecated.ts} +0 -0
@@ -0,0 +1,34 @@
1
+ import { clientDB } from '@/database/client/db';
2
+ import { DataImporterRepos } from '@/database/repositories/dataImporter';
3
+ import { BaseClientService } from '@/services/baseClientService';
4
+ import { useUserStore } from '@/store/user';
5
+ import { ImportStage, ImporterEntryData, OnImportCallbacks } from '@/types/importer';
6
+ import { UserSettings } from '@/types/user/settings';
7
+
8
+ export class ClientService extends BaseClientService {
9
+ private get dataImporter(): DataImporterRepos {
10
+ return new DataImporterRepos(clientDB as any, this.userId);
11
+ }
12
+
13
+ importSettings = async (settings: UserSettings) => {
14
+ await useUserStore.getState().importAppSettings(settings);
15
+ };
16
+
17
+ importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks) => {
18
+ callbacks?.onStageChange?.(ImportStage.Importing);
19
+ const time = Date.now();
20
+ try {
21
+ const result = await this.dataImporter.importData(data);
22
+ const duration = Date.now() - time;
23
+
24
+ callbacks?.onStageChange?.(ImportStage.Success);
25
+ callbacks?.onSuccess?.(result, duration);
26
+ } catch (e) {
27
+ console.error(e);
28
+ callbacks?.onStageChange?.(ImportStage.Error);
29
+ const error = e as Error;
30
+
31
+ callbacks?.onError?.({ code: 'ImportError', httpStatus: 0, message: error.message });
32
+ }
33
+ };
34
+ }
@@ -10,7 +10,7 @@ import {
10
10
  ChatTranslate,
11
11
  } from '@/types/message';
12
12
 
13
- import { ClientService } from './client';
13
+ import { ClientService } from './_deprecated';
14
14
 
15
15
  const messageService = new ClientService();
16
16
 
@@ -21,6 +21,7 @@ export class ClientService implements IMessageService {
21
21
  return id;
22
22
  }
23
23
 
24
+ // @ts-ignore
24
25
  async batchCreateMessages(messages: ChatMessage[]) {
25
26
  return MessageModel.batchCreate(messages);
26
27
  }
@@ -70,6 +71,7 @@ export class ClientService implements IMessageService {
70
71
  return MessageModel.update(id, { error });
71
72
  }
72
73
 
74
+ // @ts-ignore
73
75
  async updateMessage(id: string, message: Partial<DB_Message>) {
74
76
  return MessageModel.update(id, message);
75
77
  }
@@ -1,5 +1,9 @@
1
- import { ClientService } from './client';
1
+ import { ClientService as DeprecatedService } from './_deprecated';
2
+ import { ClientService } from './pglite';
2
3
  import { ServerService } from './server';
3
4
 
5
+ const clientService =
6
+ process.env.NEXT_PUBLIC_CLIENT_DB === 'pglite' ? new ClientService() : new DeprecatedService();
7
+
4
8
  export const messageService =
5
- process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : new ClientService();
9
+ process.env.NEXT_PUBLIC_SERVICE_MODE === 'server' ? new ServerService() : clientService;
@@ -0,0 +1,430 @@
1
+ import dayjs from 'dayjs';
2
+ import { and, eq } from 'drizzle-orm';
3
+ import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
+
5
+ import { MessageModel } from '@/database/_deprecated/models/message';
6
+ import { clientDB, initializeDB } from '@/database/client/db';
7
+ import {
8
+ MessageItem,
9
+ files,
10
+ messagePlugins,
11
+ messageTTS,
12
+ messageTranslates,
13
+ messages,
14
+ sessions,
15
+ topics,
16
+ users,
17
+ } from '@/database/schemas';
18
+ import {
19
+ ChatMessage,
20
+ ChatMessageError,
21
+ ChatTTS,
22
+ ChatTranslate,
23
+ CreateMessageParams,
24
+ } from '@/types/message';
25
+
26
+ import { ClientService } from './pglite';
27
+
28
+ const userId = 'message-db';
29
+ const sessionId = '1';
30
+ const topicId = 'topic-id';
31
+
32
+ // Mock data
33
+ const mockMessageId = 'mock-message-id';
34
+ const mockMessage = {
35
+ id: mockMessageId,
36
+ content: 'Mock message content',
37
+ sessionId,
38
+ role: 'user',
39
+ } as ChatMessage;
40
+
41
+ const mockMessages = [mockMessage];
42
+
43
+ beforeEach(async () => {
44
+ await initializeDB();
45
+
46
+ // 在每个测试用例之前,清空表
47
+ await clientDB.transaction(async (trx) => {
48
+ await trx.delete(users);
49
+ await trx.insert(users).values([{ id: userId }, { id: '456' }]);
50
+
51
+ await trx.insert(sessions).values([{ id: sessionId, userId }]);
52
+ await trx.insert(topics).values([{ id: topicId, sessionId, userId }]);
53
+ await trx.insert(files).values({
54
+ id: 'f1',
55
+ userId: userId,
56
+ url: 'abc',
57
+ name: 'file-1',
58
+ fileType: 'image/png',
59
+ size: 1000,
60
+ });
61
+ });
62
+ });
63
+
64
+ afterEach(async () => {
65
+ // 在每个测试用例之后,清空表
66
+ await clientDB.delete(users);
67
+ });
68
+
69
+ const messageService = new ClientService(userId);
70
+
71
+ describe('MessageClientService', () => {
72
+ describe('create', () => {
73
+ it('should create a message and return its id', async () => {
74
+ // Setup
75
+ const createParams: CreateMessageParams = {
76
+ content: 'New message content',
77
+ sessionId,
78
+ role: 'user',
79
+ };
80
+
81
+ // Execute
82
+ const messageId = await messageService.createMessage(createParams);
83
+
84
+ // Assert
85
+ expect(messageId).toMatch(/^msg_/);
86
+ });
87
+ });
88
+
89
+ describe('batchCreate', () => {
90
+ it('should batch create messages', async () => {
91
+ // Execute
92
+ await messageService.batchCreateMessages([
93
+ {
94
+ content: 'Mock message content',
95
+ sessionId,
96
+ role: 'user',
97
+ },
98
+ {
99
+ content: 'Mock message content',
100
+ sessionId,
101
+ role: 'user',
102
+ },
103
+ ] as MessageItem[]);
104
+ const count = await clientDB.$count(messages);
105
+
106
+ // Assert
107
+ expect(count).toBe(2);
108
+ });
109
+ });
110
+
111
+ describe('removeMessage', () => {
112
+ it('should remove a message by id', async () => {
113
+ // Execute
114
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
115
+ await messageService.removeMessage(mockMessageId);
116
+
117
+ // Assert
118
+ const count = await clientDB.$count(messages);
119
+
120
+ expect(count).toBe(0);
121
+ });
122
+ });
123
+ describe('removeMessages', () => {
124
+ it('should remove a message by id', async () => {
125
+ // Setup
126
+ await clientDB.insert(messages).values([
127
+ { id: mockMessageId, role: 'user', userId },
128
+ { role: 'assistant', userId },
129
+ ]);
130
+
131
+ // Execute
132
+ await messageService.removeMessages([mockMessageId]);
133
+
134
+ // Assert
135
+ const count = await clientDB.$count(messages);
136
+
137
+ expect(count).toBe(1);
138
+ });
139
+ });
140
+
141
+ describe('getMessages', () => {
142
+ it('should retrieve messages by sessionId and topicId', async () => {
143
+ // Setup
144
+ await clientDB
145
+ .insert(messages)
146
+ .values({ id: mockMessageId, sessionId, topicId, role: 'user', userId });
147
+
148
+ // Execute
149
+ const data = await messageService.getMessages(sessionId, topicId);
150
+
151
+ // Assert
152
+ expect(data[0]).toMatchObject({ id: mockMessageId, role: 'user' });
153
+ });
154
+ });
155
+
156
+ describe('getAllMessagesInSession', () => {
157
+ it('should retrieve all messages in a session', async () => {
158
+ // Setup
159
+ const sessionId = 'session-id';
160
+ await clientDB.insert(sessions).values([
161
+ { id: 'bbb', userId },
162
+ { id: sessionId, userId },
163
+ ]);
164
+ await clientDB.insert(messages).values([
165
+ { sessionId, topicId, role: 'user', userId },
166
+ { sessionId, topicId, role: 'assistant', userId },
167
+ { sessionId: 'bbb', topicId, role: 'assistant', userId },
168
+ ]);
169
+
170
+ // Execute
171
+ const data = await messageService.getAllMessagesInSession(sessionId);
172
+
173
+ // Assert
174
+ expect(data.length).toBe(2);
175
+ });
176
+ });
177
+
178
+ describe('removeMessagesByAssistant', () => {
179
+ it('should batch remove messages by assistantId and topicId', async () => {
180
+ // Setup
181
+ const assistantId = 'assistant-id';
182
+ const sessionId = 'session-id';
183
+ await clientDB.insert(sessions).values([
184
+ { id: 'bbb', userId },
185
+ { id: sessionId, userId },
186
+ ]);
187
+ await clientDB.insert(messages).values([
188
+ { sessionId, topicId, role: 'user', userId },
189
+ { sessionId, topicId, role: 'assistant', userId },
190
+ { sessionId: 'bbb', topicId, role: 'assistant', userId },
191
+ ]);
192
+
193
+ // Execute
194
+ await messageService.removeMessagesByAssistant(sessionId, topicId);
195
+
196
+ // Assert
197
+ const result = await clientDB.query.messages.findMany({
198
+ where: and(eq(messages.sessionId, sessionId), eq(messages.topicId, topicId)),
199
+ });
200
+
201
+ expect(result.length).toBe(0);
202
+ });
203
+ });
204
+
205
+ describe('clearAllMessage', () => {
206
+ it('should clear all messages from the table', async () => {
207
+ // Setup
208
+ await clientDB.insert(users).values({ id: 'another' });
209
+ await clientDB.insert(messages).values([
210
+ { id: mockMessageId, role: 'user', userId },
211
+ { role: 'user', userId: 'another' },
212
+ ]);
213
+
214
+ // Execute
215
+ await messageService.removeAllMessages();
216
+
217
+ // Assert
218
+ const result = await clientDB.query.messages.findMany({
219
+ where: eq(messages.userId, userId),
220
+ });
221
+ expect(result.length).toBe(0);
222
+ });
223
+ });
224
+
225
+ describe('getAllMessages', () => {
226
+ it('should retrieve all messages', async () => {
227
+ await clientDB.insert(messages).values([
228
+ { sessionId, topicId, content: '1', role: 'user', userId },
229
+ { sessionId, topicId, content: '2', role: 'assistant', userId },
230
+ ]);
231
+
232
+ // Execute
233
+ const data = await messageService.getAllMessages();
234
+
235
+ // Assert
236
+ expect(data).toMatchObject([
237
+ { sessionId, topicId, content: '1', role: 'user', userId },
238
+ { sessionId, topicId, content: '2', role: 'assistant', userId },
239
+ ]);
240
+ });
241
+ });
242
+
243
+ describe('updateMessageError', () => {
244
+ it('should update the error field of a message', async () => {
245
+ // Setup
246
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
247
+ const newError = {
248
+ type: 'InvalidProviderAPIKey',
249
+ message: 'Error occurred',
250
+ } as ChatMessageError;
251
+
252
+ // Execute
253
+ await messageService.updateMessageError(mockMessageId, newError);
254
+
255
+ // Assert
256
+ const result = await clientDB.query.messages.findFirst({
257
+ where: eq(messages.id, mockMessageId),
258
+ });
259
+
260
+ expect(result!.error).toEqual(newError);
261
+ });
262
+ });
263
+
264
+ // describe('updateMessagePlugin', () => {
265
+ // it('should update the plugin payload of a message', async () => {
266
+ // // Setup
267
+ // const newPlugin = {
268
+ // type: 'default',
269
+ // apiName: 'abc',
270
+ // arguments: '',
271
+ // identifier: 'plugin1',
272
+ // } as ChatPluginPayload;
273
+ //
274
+ // (MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, plugin: newPlugin });
275
+ //
276
+ // // Execute
277
+ // const result = await messageService.updateMessagePlugin(mockMessageId, newPlugin);
278
+ //
279
+ // // Assert
280
+ // expect(MessageModel.update).toHaveBeenCalledWith(mockMessageId, { plugin: newPlugin });
281
+ // expect(result).toEqual({ ...mockMessage, plugin: newPlugin });
282
+ // });
283
+ // });
284
+
285
+ describe('updateMessagePluginState', () => {
286
+ it('should update the plugin state of a message', async () => {
287
+ // Setup
288
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
289
+ await clientDB.insert(messagePlugins).values({ id: mockMessageId });
290
+ const key = 'stateKey';
291
+ const value = 'stateValue';
292
+ const newPluginState = { [key]: value };
293
+
294
+ // Execute
295
+ await messageService.updateMessagePluginState(mockMessageId, { stateKey: value });
296
+
297
+ // Assert
298
+ const result = await clientDB.query.messagePlugins.findFirst({
299
+ where: eq(messagePlugins.id, mockMessageId),
300
+ });
301
+ expect(result!.state).toEqual(newPluginState);
302
+ });
303
+ });
304
+
305
+ describe('updateMessagePluginArguments', () => {
306
+ it('should update the plugin arguments object of a message', async () => {
307
+ // Setup
308
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
309
+ await clientDB.insert(messagePlugins).values({ id: mockMessageId });
310
+ const value = 'stateValue';
311
+
312
+ // Execute
313
+ await messageService.updateMessagePluginArguments(mockMessageId, { key: value });
314
+
315
+ // Assert
316
+ const result = await clientDB.query.messagePlugins.findFirst({
317
+ where: eq(messageTTS.id, mockMessageId),
318
+ });
319
+ expect(result).toMatchObject({ arguments: '{"key":"stateValue"}' });
320
+ });
321
+ it('should update the plugin arguments string of a message', async () => {
322
+ // Setup
323
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
324
+ await clientDB.insert(messagePlugins).values({ id: mockMessageId });
325
+ const value = 'stateValue';
326
+ // Execute
327
+ await messageService.updateMessagePluginArguments(
328
+ mockMessageId,
329
+ JSON.stringify({ abc: value }),
330
+ );
331
+
332
+ // Assert
333
+ const result = await clientDB.query.messagePlugins.findFirst({
334
+ where: eq(messageTTS.id, mockMessageId),
335
+ });
336
+ expect(result).toMatchObject({ arguments: '{"abc":"stateValue"}' });
337
+ });
338
+ });
339
+
340
+ describe('countMessages', () => {
341
+ it('should count the total number of messages', async () => {
342
+ // Setup
343
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
344
+
345
+ // Execute
346
+ const count = await messageService.countMessages();
347
+
348
+ // Assert
349
+ expect(count).toBe(1);
350
+ });
351
+ });
352
+
353
+ describe('countTodayMessages', () => {
354
+ it('should count the number of messages created today', async () => {
355
+ // Setup
356
+ const mockMessages = [
357
+ { ...mockMessage, id: undefined, createdAt: new Date(), userId },
358
+ { ...mockMessage, id: undefined, createdAt: new Date(), userId },
359
+ { ...mockMessage, id: undefined, createdAt: new Date('2023-01-01'), userId },
360
+ ];
361
+ await clientDB.insert(messages).values(mockMessages);
362
+
363
+ // Execute
364
+ const count = await messageService.countTodayMessages();
365
+
366
+ // Assert
367
+ expect(count).toBe(2);
368
+ });
369
+ });
370
+
371
+ describe('updateMessageTTS', () => {
372
+ it('should update the TTS field of a message', async () => {
373
+ // Setup
374
+ await clientDB
375
+ .insert(files)
376
+ .values({ id: 'file-abc', fileType: 'text', name: 'abc', url: 'abc', size: 100, userId });
377
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
378
+ const newTTS: ChatTTS = { contentMd5: 'abc', file: 'file-abc' };
379
+
380
+ // Execute
381
+ await messageService.updateMessageTTS(mockMessageId, newTTS);
382
+
383
+ // Assert
384
+ const result = await clientDB.query.messageTTS.findFirst({
385
+ where: eq(messageTTS.id, mockMessageId),
386
+ });
387
+
388
+ expect(result).toMatchObject({ contentMd5: 'abc', fileId: 'file-abc', id: mockMessageId });
389
+ });
390
+ });
391
+
392
+ describe('updateMessageTranslate', () => {
393
+ it('should update the translate field of a message', async () => {
394
+ // Setup
395
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
396
+ const newTranslate: ChatTranslate = { content: 'Translated text', to: 'es' };
397
+
398
+ // Execute
399
+ await messageService.updateMessageTranslate(mockMessageId, newTranslate);
400
+
401
+ // Assert
402
+ const result = await clientDB.query.messageTranslates.findFirst({
403
+ where: eq(messageTranslates.id, mockMessageId),
404
+ });
405
+
406
+ expect(result).toMatchObject(newTranslate);
407
+ });
408
+ });
409
+
410
+ describe('hasMessages', () => {
411
+ it('should return true if there are messages', async () => {
412
+ // Setup
413
+ await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
414
+
415
+ // Execute
416
+ const result = await messageService.hasMessages();
417
+
418
+ // Assert
419
+ expect(result).toBe(true);
420
+ });
421
+
422
+ it('should return false if there are no messages', async () => {
423
+ // Execute
424
+ const result = await messageService.hasMessages();
425
+
426
+ // Assert
427
+ expect(result).toBe(false);
428
+ });
429
+ });
430
+ });
@@ -0,0 +1,118 @@
1
+ import dayjs from 'dayjs';
2
+
3
+ import { INBOX_SESSION_ID } from '@/const/session';
4
+ import { clientDB } from '@/database/client/db';
5
+ import { MessageItem } from '@/database/schemas';
6
+ import { MessageModel } from '@/database/server/models/message';
7
+ import { BaseClientService } from '@/services/baseClientService';
8
+ import {
9
+ ChatMessage,
10
+ ChatMessageError,
11
+ ChatTTS,
12
+ ChatTranslate,
13
+ CreateMessageParams,
14
+ } from '@/types/message';
15
+
16
+ import { IMessageService } from './type';
17
+
18
+ export class ClientService extends BaseClientService implements IMessageService {
19
+ private get messageModel(): MessageModel {
20
+ return new MessageModel(clientDB as any, this.userId);
21
+ }
22
+
23
+ async createMessage({ sessionId, ...params }: CreateMessageParams) {
24
+ const { id } = await this.messageModel.create({
25
+ ...params,
26
+ sessionId: this.toDbSessionId(sessionId) as string,
27
+ });
28
+
29
+ return id;
30
+ }
31
+
32
+ async batchCreateMessages(messages: MessageItem[]) {
33
+ return this.messageModel.batchCreate(messages);
34
+ }
35
+
36
+ async getMessages(sessionId: string, topicId?: string) {
37
+ const data = await this.messageModel.query({
38
+ sessionId: this.toDbSessionId(sessionId),
39
+ topicId,
40
+ });
41
+
42
+ return data as unknown as ChatMessage[];
43
+ }
44
+
45
+ async getAllMessages() {
46
+ const data = await this.messageModel.queryAll();
47
+
48
+ return data as unknown as ChatMessage[];
49
+ }
50
+
51
+ async countMessages() {
52
+ return this.messageModel.count();
53
+ }
54
+
55
+ async countTodayMessages() {
56
+ const topics = await this.messageModel.queryAll();
57
+ return topics.filter(
58
+ (item) => dayjs(item.createdAt).format('YYYY-MM-DD') === dayjs().format('YYYY-MM-DD'),
59
+ ).length;
60
+ }
61
+
62
+ async getAllMessagesInSession(sessionId: string) {
63
+ const data = this.messageModel.queryBySessionId(this.toDbSessionId(sessionId));
64
+
65
+ return data as unknown as ChatMessage[];
66
+ }
67
+
68
+ async updateMessageError(id: string, error: ChatMessageError) {
69
+ return this.messageModel.update(id, { error });
70
+ }
71
+
72
+ async updateMessage(id: string, message: Partial<MessageItem>) {
73
+ return this.messageModel.update(id, message);
74
+ }
75
+
76
+ async updateMessageTTS(id: string, tts: Partial<ChatTTS> | false) {
77
+ return this.messageModel.updateTTS(id, tts as any);
78
+ }
79
+
80
+ async updateMessageTranslate(id: string, translate: Partial<ChatTranslate> | false) {
81
+ return this.messageModel.updateTranslate(id, translate as any);
82
+ }
83
+
84
+ async updateMessagePluginState(id: string, value: Record<string, any>) {
85
+ return this.messageModel.updatePluginState(id, value);
86
+ }
87
+
88
+ async updateMessagePluginArguments(id: string, value: string | Record<string, any>) {
89
+ const args = typeof value === 'string' ? value : JSON.stringify(value);
90
+
91
+ return this.messageModel.updateMessagePlugin(id, { arguments: args });
92
+ }
93
+
94
+ async removeMessage(id: string) {
95
+ return this.messageModel.deleteMessage(id);
96
+ }
97
+
98
+ async removeMessages(ids: string[]) {
99
+ return this.messageModel.deleteMessages(ids);
100
+ }
101
+
102
+ async removeMessagesByAssistant(sessionId: string, topicId?: string) {
103
+ return this.messageModel.deleteMessagesBySession(this.toDbSessionId(sessionId), topicId);
104
+ }
105
+
106
+ async removeAllMessages() {
107
+ return this.messageModel.deleteAllMessages();
108
+ }
109
+
110
+ async hasMessages() {
111
+ const number = await this.countMessages();
112
+ return number > 0;
113
+ }
114
+
115
+ private toDbSessionId(sessionId: string | undefined) {
116
+ return sessionId === INBOX_SESSION_ID ? undefined : sessionId;
117
+ }
118
+ }
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { INBOX_SESSION_ID } from '@/const/session';
3
+ import { MessageItem } from '@/database/schemas';
3
4
  import { lambdaClient } from '@/libs/trpc/client';
4
5
  import {
5
6
  ChatMessage,
@@ -19,20 +20,23 @@ export class ServerService implements IMessageService {
19
20
  });
20
21
  }
21
22
 
22
- batchCreateMessages(messages: ChatMessage[]): Promise<any> {
23
+ batchCreateMessages(messages: MessageItem[]): Promise<any> {
23
24
  return lambdaClient.message.batchCreateMessages.mutate(messages);
24
25
  }
25
26
 
26
- getMessages(sessionId?: string, topicId?: string | undefined): Promise<ChatMessage[]> {
27
- return lambdaClient.message.getMessages.query({
27
+ getMessages = async (sessionId?: string, topicId?: string | undefined) => {
28
+ const data = await lambdaClient.message.getMessages.query({
28
29
  sessionId: this.toDbSessionId(sessionId),
29
30
  topicId,
30
31
  });
31
- }
32
+
33
+ return data as unknown as ChatMessage[];
34
+ };
32
35
 
33
36
  getAllMessages(): Promise<ChatMessage[]> {
34
37
  return lambdaClient.message.getAllMessages.query();
35
38
  }
39
+
36
40
  getAllMessagesInSession(sessionId: string): Promise<ChatMessage[]> {
37
41
  return lambdaClient.message.getAllMessagesInSession.query({
38
42
  sessionId: this.toDbSessionId(sessionId),
@@ -63,7 +67,7 @@ export class ServerService implements IMessageService {
63
67
  return lambdaClient.message.updateMessagePlugin.mutate({ id, value: { arguments: args } });
64
68
  }
65
69
 
66
- updateMessage(id: string, message: Partial<ChatMessage>): Promise<any> {
70
+ updateMessage(id: string, message: Partial<MessageItem>): Promise<any> {
67
71
  return lambdaClient.message.update.mutate({ id, value: message });
68
72
  }
69
73
 
@@ -79,10 +83,6 @@ export class ServerService implements IMessageService {
79
83
  return lambdaClient.message.updatePluginState.mutate({ id, value });
80
84
  }
81
85
 
82
- bindMessagesToTopic(_topicId: string, _messageIds: string[]): Promise<any> {
83
- throw new Error('Method not implemented.');
84
- }
85
-
86
86
  removeMessage(id: string): Promise<any> {
87
87
  return lambdaClient.message.removeMessage.mutate({ id });
88
88
  }