@lobehub/chat 0.105.2 → 0.107.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.
- package/CHANGELOG.md +50 -0
- package/README.md +18 -0
- package/README.zh-CN.md +18 -0
- package/docs/Environment-Variable.md +4 -2
- package/docs/Environment-Variable.zh-CN.md +4 -2
- package/locales/en_US/common.json +19 -0
- package/locales/en_US/migration.json +45 -0
- package/locales/en_US/setting.json +7 -7
- package/locales/ja_JP/common.json +19 -0
- package/locales/ja_JP/migration.json +45 -0
- package/locales/ja_JP/setting.json +2 -2
- package/locales/ko_KR/common.json +19 -0
- package/locales/ko_KR/migration.json +45 -0
- package/locales/ko_KR/setting.json +2 -2
- package/locales/ru_RU/common.json +19 -0
- package/locales/ru_RU/migration.json +45 -0
- package/locales/ru_RU/setting.json +2 -2
- package/locales/zh_CN/common.json +19 -0
- package/locales/zh_CN/migration.json +45 -0
- package/locales/zh_CN/setting.json +1 -1
- package/locales/zh_TW/common.json +19 -0
- package/locales/zh_TW/migration.json +45 -0
- package/locales/zh_TW/setting.json +2 -2
- package/package.json +2 -1
- package/src/app/api/openai/chat/createChatCompletion.test.ts +4 -4
- package/src/app/api/openai/chat/createChatCompletion.ts +4 -10
- package/src/app/api/openai/createBizOpenAI/index.ts +1 -1
- package/src/app/api/openai/errorResponse.test.ts +1 -1
- package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +2 -1
- package/src/app/chat/(mobile)/features/ChatInput/SendButton.tsx +2 -2
- package/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx +2 -5
- package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/ActionBar/Clear.tsx +2 -2
- package/src/app/chat/features/ChatInput/ActionBar/ModelSwitch.tsx +1 -1
- package/src/app/chat/features/ChatInput/ActionBar/Token/TokenTag.tsx +8 -2
- package/src/app/chat/features/ChatInput/InputAreaInner/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/STT/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/Topic/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/useSend.ts +3 -3
- package/src/app/chat/features/Conversation/ChatList/Actions/index.ts +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/Assistant.test.tsx +4 -4
- package/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx +30 -31
- package/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/User.tsx +8 -5
- package/src/app/chat/features/Conversation/ChatList/Extras/index.ts +3 -3
- package/src/app/chat/features/Conversation/ChatList/Extras/type.ts +5 -0
- package/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx +10 -6
- package/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx +7 -3
- package/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +7 -6
- package/src/app/chat/features/Conversation/ChatList/Messages/index.ts +7 -7
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +6 -6
- package/src/app/chat/features/Conversation/ChatList/index.tsx +16 -24
- package/src/app/chat/features/Conversation/ScrollAnchor/index.tsx +2 -2
- package/src/app/chat/features/Conversation/index.tsx +3 -3
- package/src/app/chat/features/Conversation/useInitConversation.ts +43 -0
- package/src/app/chat/features/Migration/ExportConfigButton.tsx +33 -0
- package/src/app/chat/features/Migration/Failed.tsx +115 -0
- package/src/app/chat/features/Migration/Modal.tsx +80 -0
- package/src/app/chat/features/Migration/Start.tsx +106 -0
- package/src/app/chat/features/Migration/UpgradeButton.tsx +74 -0
- package/src/app/chat/features/Migration/const.ts +15 -0
- package/src/app/chat/features/Migration/index.tsx +44 -0
- package/src/app/chat/features/SessionListContent/DefaultMode.tsx +54 -0
- package/src/app/chat/features/SessionListContent/List/Item/Actions.tsx +5 -4
- package/src/app/chat/features/SessionListContent/List/Item/index.tsx +22 -28
- package/src/app/chat/features/SessionListContent/SearchMode.tsx +15 -0
- package/src/app/chat/features/SessionListContent/index.tsx +4 -44
- package/src/app/chat/features/SessionSearchBar/index.tsx +11 -3
- package/src/app/chat/features/TopicListContent/Header.tsx +4 -4
- package/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +11 -9
- package/src/app/chat/features/TopicListContent/Topic/TopicItem.tsx +15 -13
- package/src/app/chat/features/TopicListContent/Topic/index.tsx +9 -16
- package/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx +13 -4
- package/src/app/chat/features/TopicListContent/index.tsx +1 -2
- package/src/app/chat/page.tsx +6 -1
- package/src/app/chat/settings/features/HeaderContent.tsx +3 -3
- package/src/app/home/Redirect.tsx +13 -7
- package/src/app/settings/(mobile)/features/ExtraList.tsx +12 -4
- package/src/app/settings/common/Common.tsx +16 -4
- package/src/app/welcome/features/Banner/index.tsx +9 -10
- package/src/chains/summaryTitle.ts +5 -2
- package/src/components/DataStyleModal/index.tsx +64 -0
- package/src/config/client.ts +5 -0
- package/src/const/session.ts +21 -0
- package/src/const/settings.ts +1 -1
- package/src/database/core/__tests__/db.test.ts +8 -5
- package/src/database/core/__tests__/model.test.ts +3 -3
- package/src/database/core/db.ts +38 -10
- package/src/database/core/index.ts +1 -0
- package/src/database/core/model.ts +121 -10
- package/src/database/core/schemas.ts +22 -0
- package/src/database/core/types/db.ts +13 -0
- package/src/database/models/__DEBUG.ts +119 -0
- package/src/database/models/{file.test.ts → __tests__/file.test.ts} +19 -6
- package/src/database/models/__tests__/message.test.ts +314 -0
- package/src/database/models/__tests__/session.test.ts +117 -0
- package/src/database/models/__tests__/topic.test.ts +250 -0
- package/src/database/models/file.ts +9 -5
- package/src/database/models/message.ts +186 -0
- package/src/database/models/session.ts +160 -0
- package/src/database/models/topic.ts +196 -0
- package/src/{types/database → database/schemas}/files.ts +2 -2
- package/src/database/schemas/message.ts +37 -0
- package/src/database/schemas/session.ts +56 -0
- package/src/database/schemas/topic.ts +12 -0
- package/src/features/AgentSetting/AgentConfig/index.tsx +8 -1
- package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +1 -1
- package/src/features/AgentSetting/store/action.ts +1 -1
- package/src/features/AgentSetting/store/initialState.ts +1 -1
- package/src/features/AgentSetting/store/reducers/config.ts +1 -1
- package/src/features/DataImporter/index.tsx +240 -0
- package/src/features/DebugUI/index.tsx +34 -0
- package/src/features/SideBar/BottomActions.tsx +8 -14
- package/src/hooks/useImportConfig.ts +13 -30
- package/src/hooks/useTTS.ts +1 -1
- package/src/layout/GlobalLayout/index.tsx +16 -1
- package/src/locales/default/common.ts +19 -0
- package/src/locales/default/migration.ts +47 -0
- package/src/locales/default/setting.ts +1 -1
- package/src/locales/resources/en_US.ts +2 -0
- package/src/locales/resources/ja_JP.ts +2 -0
- package/src/locales/resources/ko_KR.ts +2 -0
- package/src/locales/resources/ru_RU.ts +2 -0
- package/src/locales/resources/zh_CN.ts +2 -0
- package/src/locales/resources/zh_TW.ts +2 -0
- package/src/migrations/FromV0ToV1.ts +2 -4
- package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +191 -0
- package/src/migrations/FromV1ToV2/fixtures/output-v2.json +202 -0
- package/src/migrations/FromV1ToV2/index.ts +82 -0
- package/src/migrations/FromV1ToV2/migrations.test.ts +224 -0
- package/src/migrations/FromV1ToV2/types/v1.ts +78 -0
- package/src/migrations/FromV1ToV2/types/v2.ts +52 -0
- package/src/{utils → migrations}/VersionController.test.ts +1 -3
- package/src/{utils → migrations}/VersionController.ts +5 -2
- package/src/migrations/index.ts +17 -3
- package/src/services/__tests__/file.test.ts +3 -3
- package/src/services/chat.ts +66 -5
- package/src/services/config.ts +184 -0
- package/src/services/debug.ts +13 -0
- package/src/services/file.ts +6 -2
- package/src/services/github.ts +25 -0
- package/src/services/message.ts +79 -0
- package/src/services/session.ts +63 -0
- package/src/services/topic.ts +56 -0
- package/src/store/chat/actions/enhance.ts +95 -0
- package/src/store/{session/slices/chat → chat}/actions/message.ts +225 -247
- package/src/store/{session/slices/chat → chat}/actions/plugin.ts +29 -34
- package/src/store/{session/slices/chat → chat}/actions/share.ts +9 -13
- package/src/store/chat/actions/topic.ts +197 -0
- package/src/store/chat/helpers.ts +23 -0
- package/src/store/chat/index.ts +3 -0
- package/src/store/chat/initialState.ts +48 -0
- package/src/store/chat/reducers/message.test.ts +83 -0
- package/src/store/chat/reducers/message.ts +83 -0
- package/src/store/chat/selectors/__tests__/topic.test.ts +43 -0
- package/src/store/chat/selectors/chat.ts +119 -0
- package/src/store/chat/selectors/index.ts +2 -0
- package/src/store/chat/selectors/topic.ts +28 -0
- package/src/store/chat/store.ts +63 -0
- package/src/store/files/slices/images/action.ts +6 -4
- package/src/store/global/selectors/__snapshots__/settings.test.ts.snap +99 -0
- package/src/store/global/selectors/settings.test.ts +51 -0
- package/src/store/global/selectors/settings.ts +36 -5
- package/src/store/global/store.ts +1 -1
- package/src/store/middleware/createHyperStorage/index.ts +40 -24
- package/src/store/middleware/createHyperStorage/keyMapper.ts +8 -2
- package/src/store/middleware/createHyperStorage/type.ts +10 -8
- package/src/store/plugin/slices/plugin/action.ts +1 -1
- package/src/store/plugin/store.ts +2 -4
- package/src/store/session/helpers.ts +1 -1
- package/src/store/session/hooks/useSessionHydrated.ts +6 -10
- package/src/store/session/initialState.ts +26 -7
- package/src/store/session/selectors.ts +1 -2
- package/src/store/session/slices/agent/action.ts +26 -35
- package/src/store/session/slices/agent/selectors.ts +32 -37
- package/src/store/session/slices/session/action.ts +81 -88
- package/src/store/session/slices/session/helpers.ts +19 -0
- package/src/store/session/slices/session/initialState.ts +7 -10
- package/src/store/session/slices/session/selectors/export.ts +12 -9
- package/src/store/session/slices/session/selectors/index.ts +2 -35
- package/src/store/session/slices/session/selectors/list.test.ts +25 -203
- package/src/store/session/slices/session/selectors/list.ts +40 -78
- package/src/store/session/store.ts +11 -17
- package/src/types/agent/index.ts +61 -0
- package/src/types/chatMessage.ts +11 -20
- package/src/types/exportConfig.ts +7 -2
- package/src/types/files.ts +2 -2
- package/src/types/llm.ts +1 -1
- package/src/types/meta.ts +24 -12
- package/src/types/openai/chat.ts +9 -1
- package/src/types/openai/functionCall.ts +4 -0
- package/src/types/session.ts +10 -94
- package/src/types/settings.ts +2 -0
- package/src/types/translate.ts +2 -1
- package/src/utils/config.ts +5 -11
- package/src/utils/fetch.ts +8 -2
- package/src/app/chat/features/Conversation/usePluginsInit.ts +0 -14
- package/src/database/core/schema.ts +0 -9
- package/src/helpers/export.ts +0 -69
- package/src/hooks/useExportConfig.ts +0 -6
- package/src/store/session/slices/chat/actions/index.ts +0 -32
- package/src/store/session/slices/chat/actions/topic.ts +0 -171
- package/src/store/session/slices/chat/actions/translate.ts +0 -113
- package/src/store/session/slices/chat/helpers.ts +0 -9
- package/src/store/session/slices/chat/initialState.ts +0 -13
- package/src/store/session/slices/chat/reducers/message.test.ts +0 -319
- package/src/store/session/slices/chat/reducers/message.ts +0 -156
- package/src/store/session/slices/chat/reducers/topic.test.ts +0 -179
- package/src/store/session/slices/chat/reducers/topic.ts +0 -81
- package/src/store/session/slices/chat/selectors/chat.ts +0 -111
- package/src/store/session/slices/chat/selectors/index.ts +0 -26
- package/src/store/session/slices/chat/selectors/topic.ts +0 -30
- package/src/store/session/slices/chat/selectors/utils.test.ts +0 -385
- package/src/store/session/slices/chat/selectors/utils.ts +0 -91
- package/src/store/session/slices/chat/utils.ts +0 -13
- package/src/store/session/slices/session/reducers/session.test.ts +0 -577
- package/src/store/session/slices/session/reducers/session.ts +0 -182
- package/src/types/database/db.ts +0 -4
- /package/src/store/{session/slices/chat → chat}/reducers/files.test.ts +0 -0
- /package/src/store/{session/slices/chat → chat}/reducers/files.ts +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// This file is for debugging purposes only.
|
|
2
|
+
// DON'T USE IT IN PRODUCTION.
|
|
3
|
+
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
4
|
+
import { DBModel } from '@/database/core/types/db';
|
|
5
|
+
import { DB_Message } from '@/database/schemas/message';
|
|
6
|
+
import { DB_Topic } from '@/database/schemas/topic';
|
|
7
|
+
|
|
8
|
+
import { BaseModel } from '../core';
|
|
9
|
+
import { DB_Session, DB_SessionSchema } from '../schemas/session';
|
|
10
|
+
|
|
11
|
+
class _DEBUG_MODEL extends BaseModel<'sessions'> {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('sessions', DB_SessionSchema);
|
|
14
|
+
}
|
|
15
|
+
private getRandomInt(min: number, max: number) {
|
|
16
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private randomString(length: number) {
|
|
20
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
21
|
+
let result = '';
|
|
22
|
+
for (let i = 0; i < length; i++) {
|
|
23
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private randomDate(start: Date, end: Date) {
|
|
29
|
+
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).getTime();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private randomPick<T>(array: T[]): T {
|
|
33
|
+
const randomIndex = this.getRandomInt(0, array.length - 1);
|
|
34
|
+
return array[randomIndex];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
createRandomData = async ({ sessionCount = 10, topicCount = 2000, messageCount = 10_000 }) => {
|
|
38
|
+
const numberOfSessions = sessionCount;
|
|
39
|
+
const numberOfTopics = topicCount;
|
|
40
|
+
const numberOfMessages = messageCount;
|
|
41
|
+
|
|
42
|
+
// Prepare data for batch inserts
|
|
43
|
+
const sessionsData: DBModel<DB_Session>[] = [];
|
|
44
|
+
const topicsData: DBModel<DB_Topic>[] = [];
|
|
45
|
+
const messagesData: DBModel<DB_Message>[] = [];
|
|
46
|
+
|
|
47
|
+
// Prepare sessions
|
|
48
|
+
for (let i = 1; i <= numberOfSessions; i++) {
|
|
49
|
+
sessionsData.push({
|
|
50
|
+
config: DEFAULT_AGENT_CONFIG,
|
|
51
|
+
createdAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
52
|
+
group: 'default',
|
|
53
|
+
id: `sess_${i}`,
|
|
54
|
+
meta: {
|
|
55
|
+
description: `Session Description ${i}`,
|
|
56
|
+
title: `Session Title ${i}`,
|
|
57
|
+
},
|
|
58
|
+
type: 'agent',
|
|
59
|
+
updatedAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Prepare topics
|
|
64
|
+
for (let i = 1; i <= numberOfTopics; i++) {
|
|
65
|
+
topicsData.push({
|
|
66
|
+
createdAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
67
|
+
favorite: this.getRandomInt(0, 1),
|
|
68
|
+
id: `topic_${i}`,
|
|
69
|
+
sessionId: `sess_${this.getRandomInt(1, numberOfSessions)}`,
|
|
70
|
+
title: `Topic Title ${i}`,
|
|
71
|
+
updatedAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Prepare messages
|
|
76
|
+
for (let i = 1; i <= numberOfMessages; i++) {
|
|
77
|
+
messagesData.push({
|
|
78
|
+
content: this.randomString(300),
|
|
79
|
+
createdAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
80
|
+
favorite: this.getRandomInt(0, 1),
|
|
81
|
+
fromModel: 'model',
|
|
82
|
+
id: `msg_${i}`,
|
|
83
|
+
parentId: `msg_${this.getRandomInt(1, numberOfMessages)}`,
|
|
84
|
+
quotaId: `msg_${this.getRandomInt(1, numberOfMessages)}`,
|
|
85
|
+
role: this.randomPick(['user', 'assistant']),
|
|
86
|
+
sessionId: `sess_${this.getRandomInt(1, numberOfSessions)}`,
|
|
87
|
+
topicId: `topic_${this.getRandomInt(1, numberOfTopics)}`,
|
|
88
|
+
updatedAt: this.randomDate(new Date(2020, 0, 1), new Date()),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Start a transaction for batch inserts
|
|
93
|
+
await this.db.transaction(
|
|
94
|
+
'rw',
|
|
95
|
+
this.db.sessions,
|
|
96
|
+
this.db.topics,
|
|
97
|
+
this.db.messages,
|
|
98
|
+
async () => {
|
|
99
|
+
// Batch insert sessions, topics, and messages
|
|
100
|
+
console.log('开始插入 sessions');
|
|
101
|
+
console.time('插入sessions');
|
|
102
|
+
await this.db.sessions.bulkAdd(sessionsData);
|
|
103
|
+
console.timeEnd('插入sessions');
|
|
104
|
+
|
|
105
|
+
console.log('开始插入 topics');
|
|
106
|
+
console.time('插入topics');
|
|
107
|
+
await this.db.topics.bulkAdd(topicsData);
|
|
108
|
+
console.timeEnd('插入topics');
|
|
109
|
+
|
|
110
|
+
console.log('开始插入 messages');
|
|
111
|
+
console.time('插入messages');
|
|
112
|
+
await this.db.messages.bulkAdd(messagesData);
|
|
113
|
+
console.timeEnd('插入messages');
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const DEBUG_MODEL = new _DEBUG_MODEL();
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { DB_File } from '@/database/schemas/files';
|
|
4
4
|
|
|
5
|
-
import { LocalDB } from '
|
|
6
|
-
import { FileModel } from '
|
|
5
|
+
import { LocalDB } from '../../core/db';
|
|
6
|
+
import { FileModel } from '../file';
|
|
7
7
|
|
|
8
8
|
// Assuming LocalDB is already mocked or using an in-memory database
|
|
9
9
|
// and LocalFileSchema has been imported correctly.
|
|
10
10
|
|
|
11
11
|
describe('_FileModel', () => {
|
|
12
|
-
let fileData:
|
|
12
|
+
let fileData: DB_File;
|
|
13
13
|
|
|
14
14
|
beforeEach(() => {
|
|
15
15
|
// Set up file data with the correct structure according to LocalFileSchema
|
|
@@ -32,7 +32,7 @@ describe('_FileModel', () => {
|
|
|
32
32
|
|
|
33
33
|
it('should create a file record', async () => {
|
|
34
34
|
// First, create a file to test the create method
|
|
35
|
-
const fileData:
|
|
35
|
+
const fileData: DB_File = {
|
|
36
36
|
data: new ArrayBuffer(10),
|
|
37
37
|
fileType: 'image/png',
|
|
38
38
|
name: 'test.png',
|
|
@@ -68,4 +68,17 @@ describe('_FileModel', () => {
|
|
|
68
68
|
const fileInDb = await FileModel.findById(createdFile.id);
|
|
69
69
|
expect(fileInDb).toBeUndefined();
|
|
70
70
|
});
|
|
71
|
+
|
|
72
|
+
it('should clear all files', async () => {
|
|
73
|
+
// First, create a file to test the delete method
|
|
74
|
+
const createdFile = await FileModel.create(fileData);
|
|
75
|
+
const createdFile2 = await FileModel.create(fileData);
|
|
76
|
+
await FileModel.clear();
|
|
77
|
+
|
|
78
|
+
// Verify that the file has been removed from the database
|
|
79
|
+
const fileInDb = await FileModel.findById(createdFile.id);
|
|
80
|
+
expect(fileInDb).toBeUndefined();
|
|
81
|
+
const fileInDb2 = await FileModel.findById(createdFile2.id);
|
|
82
|
+
expect(fileInDb2).toBeUndefined();
|
|
83
|
+
});
|
|
71
84
|
});
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { ChatMessage } from '@/types/chatMessage';
|
|
4
|
+
|
|
5
|
+
import { CreateMessageParams, MessageModel } from '../message';
|
|
6
|
+
|
|
7
|
+
describe('MessageModel', () => {
|
|
8
|
+
let messageData: CreateMessageParams;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
// 设置正确结构的消息数据
|
|
12
|
+
messageData = {
|
|
13
|
+
content: 'Test message content',
|
|
14
|
+
role: 'user',
|
|
15
|
+
sessionId: 'session1',
|
|
16
|
+
topicId: 'topic1',
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
// 每次测试后清理数据库
|
|
22
|
+
await MessageModel.clearTable();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('create', () => {
|
|
26
|
+
it('should create a message record', async () => {
|
|
27
|
+
const result = await MessageModel.create(messageData);
|
|
28
|
+
|
|
29
|
+
expect(result).toHaveProperty('id');
|
|
30
|
+
// 验证消息是否已添加到数据库
|
|
31
|
+
const messageInDb = await MessageModel.findById(result.id);
|
|
32
|
+
|
|
33
|
+
expect(messageInDb).toEqual(
|
|
34
|
+
expect.objectContaining({
|
|
35
|
+
content: messageData.content,
|
|
36
|
+
role: messageData.role,
|
|
37
|
+
sessionId: messageData.sessionId,
|
|
38
|
+
topicId: messageData.topicId,
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should create with tts', async () => {
|
|
44
|
+
const result = await MessageModel.create({
|
|
45
|
+
content: 'abc',
|
|
46
|
+
role: 'assistant',
|
|
47
|
+
extra: { translate: { content: 'avc', from: 'a', to: 'f' } },
|
|
48
|
+
sessionId: 'a',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 验证消息是否已添加到数据库
|
|
52
|
+
const messageInDb = await MessageModel.findById(result.id);
|
|
53
|
+
|
|
54
|
+
expect(messageInDb).toEqual(
|
|
55
|
+
expect.objectContaining({
|
|
56
|
+
content: 'abc',
|
|
57
|
+
role: 'assistant',
|
|
58
|
+
translate: { content: 'avc', from: 'a', to: 'f' },
|
|
59
|
+
sessionId: 'a',
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('batchCreate', () => {
|
|
66
|
+
it('should batch create message records', async () => {
|
|
67
|
+
const messagesToCreate = [messageData, messageData] as ChatMessage[];
|
|
68
|
+
const results = await MessageModel.batchCreate(messagesToCreate);
|
|
69
|
+
|
|
70
|
+
expect(results.success).toBeTruthy();
|
|
71
|
+
expect(results.errors).toBeUndefined();
|
|
72
|
+
|
|
73
|
+
// 验证消息是否已添加到数据库
|
|
74
|
+
for (const message of results.ids!) {
|
|
75
|
+
const messageInDb = await MessageModel.findById(message);
|
|
76
|
+
expect(messageInDb).toEqual(
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
content: messageData.content,
|
|
79
|
+
role: messageData.role,
|
|
80
|
+
sessionId: messageData.sessionId,
|
|
81
|
+
topicId: messageData.topicId,
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('query', () => {
|
|
89
|
+
it('should query messages with pagination', async () => {
|
|
90
|
+
// 创建多条消息以测试查询方法
|
|
91
|
+
await MessageModel.batchCreate([messageData, messageData] as ChatMessage[]);
|
|
92
|
+
|
|
93
|
+
const queriedMessages = await MessageModel.query({
|
|
94
|
+
pageSize: 1,
|
|
95
|
+
current: 0,
|
|
96
|
+
sessionId: messageData.sessionId,
|
|
97
|
+
topicId: messageData.topicId,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(queriedMessages).toHaveLength(1);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should query correctly without topic id', async () => {
|
|
104
|
+
// 创建多条消息以测试查询方法
|
|
105
|
+
await MessageModel.batchCreate([messageData, messageData] as ChatMessage[]);
|
|
106
|
+
|
|
107
|
+
const queriedMessages = await MessageModel.query({ sessionId: messageData.sessionId });
|
|
108
|
+
|
|
109
|
+
expect(queriedMessages).toHaveLength(0);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should query correctly with exactly topic id', async () => {
|
|
113
|
+
// 创建多条消息以测试查询方法
|
|
114
|
+
await MessageModel.batchCreate([
|
|
115
|
+
messageData,
|
|
116
|
+
{ ...messageData, topicId: undefined },
|
|
117
|
+
] as ChatMessage[]);
|
|
118
|
+
|
|
119
|
+
const queriedMessages = await MessageModel.query({ sessionId: messageData.sessionId });
|
|
120
|
+
|
|
121
|
+
expect(queriedMessages).toHaveLength(1);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should should have correct order', async () => {
|
|
125
|
+
const data: ChatMessage[] = [
|
|
126
|
+
{
|
|
127
|
+
role: 'user',
|
|
128
|
+
content: '1',
|
|
129
|
+
createdAt: 1697120044345,
|
|
130
|
+
id: 'NQ7RscYx',
|
|
131
|
+
updatedAt: 1697120181827,
|
|
132
|
+
extra: {},
|
|
133
|
+
meta: {},
|
|
134
|
+
sessionId: '1',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
role: 'assistant',
|
|
138
|
+
content: '2',
|
|
139
|
+
parentId: 'NQ7RscYx',
|
|
140
|
+
createdAt: 1697120130973,
|
|
141
|
+
id: '9tDAumEx',
|
|
142
|
+
updatedAt: 1697120181827,
|
|
143
|
+
meta: {},
|
|
144
|
+
extra: {
|
|
145
|
+
fromModel: 'gpt-3.5-turbo-16k',
|
|
146
|
+
},
|
|
147
|
+
sessionId: '1',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
role: 'assistant',
|
|
151
|
+
content: '3',
|
|
152
|
+
parentId: 'tOMH7c5R',
|
|
153
|
+
meta: {},
|
|
154
|
+
createdAt: 1697120163272,
|
|
155
|
+
id: '5Ie5hClg',
|
|
156
|
+
updatedAt: 1697120181827,
|
|
157
|
+
extra: {
|
|
158
|
+
fromModel: 'gpt-3.5-turbo-16k',
|
|
159
|
+
},
|
|
160
|
+
sessionId: '1',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
role: 'user',
|
|
164
|
+
content: '4',
|
|
165
|
+
meta: {},
|
|
166
|
+
createdAt: 1697120163272,
|
|
167
|
+
id: 'tOMH7c5R',
|
|
168
|
+
updatedAt: 1697120181827,
|
|
169
|
+
extra: {},
|
|
170
|
+
sessionId: '1',
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
await MessageModel.batchCreate(data);
|
|
175
|
+
|
|
176
|
+
const queriedMessages = await MessageModel.query({ sessionId: '1' });
|
|
177
|
+
|
|
178
|
+
expect(queriedMessages).toEqual([
|
|
179
|
+
{
|
|
180
|
+
role: 'user',
|
|
181
|
+
content: '1',
|
|
182
|
+
createdAt: 1697120044345,
|
|
183
|
+
id: 'NQ7RscYx',
|
|
184
|
+
updatedAt: 1697120181827,
|
|
185
|
+
sessionId: '1',
|
|
186
|
+
extra: {},
|
|
187
|
+
meta: {},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
role: 'assistant',
|
|
191
|
+
content: '2',
|
|
192
|
+
parentId: 'NQ7RscYx',
|
|
193
|
+
createdAt: 1697120130973,
|
|
194
|
+
id: '9tDAumEx',
|
|
195
|
+
sessionId: '1',
|
|
196
|
+
updatedAt: 1697120181827,
|
|
197
|
+
meta: {},
|
|
198
|
+
extra: {
|
|
199
|
+
fromModel: 'gpt-3.5-turbo-16k',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
role: 'user',
|
|
204
|
+
content: '4',
|
|
205
|
+
sessionId: '1',
|
|
206
|
+
createdAt: 1697120163272,
|
|
207
|
+
id: 'tOMH7c5R',
|
|
208
|
+
updatedAt: 1697120181827,
|
|
209
|
+
meta: {},
|
|
210
|
+
extra: {},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
role: 'assistant',
|
|
214
|
+
content: '3',
|
|
215
|
+
parentId: 'tOMH7c5R',
|
|
216
|
+
meta: {},
|
|
217
|
+
createdAt: 1697120163272,
|
|
218
|
+
sessionId: '1',
|
|
219
|
+
id: '5Ie5hClg',
|
|
220
|
+
updatedAt: 1697120181827,
|
|
221
|
+
extra: {
|
|
222
|
+
fromModel: 'gpt-3.5-turbo-16k',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
]);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('findById', () => {
|
|
230
|
+
it('should find a message by id', async () => {
|
|
231
|
+
const createdMessage = await MessageModel.create(messageData);
|
|
232
|
+
const messageInDb = await MessageModel.findById(createdMessage.id);
|
|
233
|
+
|
|
234
|
+
expect(messageInDb).toEqual(
|
|
235
|
+
expect.objectContaining({
|
|
236
|
+
id: createdMessage.id,
|
|
237
|
+
content: messageData.content,
|
|
238
|
+
}),
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('delete', () => {
|
|
244
|
+
it('should delete a message', async () => {
|
|
245
|
+
const createdMessage = await MessageModel.create(messageData);
|
|
246
|
+
await MessageModel.delete(createdMessage.id);
|
|
247
|
+
|
|
248
|
+
const messageInDb = await MessageModel.findById(createdMessage.id);
|
|
249
|
+
expect(messageInDb).toBeUndefined();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('update', () => {
|
|
254
|
+
it('should update a message', async () => {
|
|
255
|
+
const createdMessage = await MessageModel.create(messageData);
|
|
256
|
+
const updateData = { content: 'Updated content' };
|
|
257
|
+
|
|
258
|
+
await MessageModel.update(createdMessage.id, updateData);
|
|
259
|
+
const updatedMessage = await MessageModel.findById(createdMessage.id);
|
|
260
|
+
|
|
261
|
+
expect(updatedMessage).toHaveProperty('content', 'Updated content');
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('batchUpdate', () => {
|
|
266
|
+
it('should batch update messages', async () => {
|
|
267
|
+
const createdMessage1 = await MessageModel.create(messageData);
|
|
268
|
+
const createdMessage2 = await MessageModel.create(messageData);
|
|
269
|
+
const updateData = { content: 'Batch updated content' };
|
|
270
|
+
|
|
271
|
+
const numUpdated = await MessageModel.batchUpdate(
|
|
272
|
+
[createdMessage1.id, createdMessage2.id],
|
|
273
|
+
updateData,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
expect(numUpdated).toBe(2);
|
|
277
|
+
|
|
278
|
+
const updatedMessage1 = await MessageModel.findById(createdMessage1.id);
|
|
279
|
+
const updatedMessage2 = await MessageModel.findById(createdMessage2.id);
|
|
280
|
+
|
|
281
|
+
expect(updatedMessage1).toHaveProperty('content', 'Batch updated content');
|
|
282
|
+
expect(updatedMessage2).toHaveProperty('content', 'Batch updated content');
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe('batchDelete', () => {
|
|
287
|
+
it('should batch delete messages by session id', async () => {
|
|
288
|
+
// 创建多条消息以测试批量删除方法
|
|
289
|
+
const createdMessage1 = await MessageModel.create(messageData);
|
|
290
|
+
const createdMessage2 = await MessageModel.create(messageData);
|
|
291
|
+
|
|
292
|
+
await MessageModel.batchDelete(messageData.sessionId, undefined);
|
|
293
|
+
|
|
294
|
+
// 验证所有具有给定会话 ID 的消息是否已删除
|
|
295
|
+
const messagesInDb = await MessageModel.query({ sessionId: messageData.sessionId });
|
|
296
|
+
expect(messagesInDb).toHaveLength(0);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should batch delete messages by session id and topic id', async () => {
|
|
300
|
+
// 创建多条消息以测试批量删除方法
|
|
301
|
+
const createdMessage1 = await MessageModel.create(messageData);
|
|
302
|
+
const createdMessage2 = await MessageModel.create(messageData);
|
|
303
|
+
|
|
304
|
+
await MessageModel.batchDelete(messageData.sessionId, messageData.topicId);
|
|
305
|
+
|
|
306
|
+
// 验证所有具有给定会话 ID 和话题 ID 的消息是否已删除
|
|
307
|
+
const messagesInDb = await MessageModel.query({
|
|
308
|
+
sessionId: messageData.sessionId,
|
|
309
|
+
topicId: messageData.topicId,
|
|
310
|
+
});
|
|
311
|
+
expect(messagesInDb).toHaveLength(0);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
4
|
+
import { CreateMessageParams, MessageModel } from '@/database/models/message';
|
|
5
|
+
import { TopicModel } from '@/database/models/topic';
|
|
6
|
+
import { LobeAgentSession, LobeSessionType, SessionGroupKey } from '@/types/session';
|
|
7
|
+
|
|
8
|
+
import { SessionModel } from '../session';
|
|
9
|
+
|
|
10
|
+
describe('SessionModel', () => {
|
|
11
|
+
let sessionData: Partial<LobeAgentSession>;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
// Set up session data with the correct structure
|
|
15
|
+
sessionData = {
|
|
16
|
+
type: LobeSessionType.Agent,
|
|
17
|
+
group: 'testGroup',
|
|
18
|
+
meta: {},
|
|
19
|
+
config: DEFAULT_AGENT_CONFIG,
|
|
20
|
+
// ... other properties based on LobeAgentSession
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
// Clean up the database after each test
|
|
26
|
+
await SessionModel.clearTable();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should create a session record', async () => {
|
|
30
|
+
const result = await SessionModel.create('agent', sessionData);
|
|
31
|
+
|
|
32
|
+
expect(result).toHaveProperty('id');
|
|
33
|
+
// Verify that the session has been added to the database
|
|
34
|
+
// Assuming findById is a method that retrieves a session by ID
|
|
35
|
+
const sessionInDb = await SessionModel.findById(result.id);
|
|
36
|
+
|
|
37
|
+
expect(sessionInDb).toEqual(expect.objectContaining(sessionData));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should batch create session records', async () => {
|
|
41
|
+
const sessionsToCreate = [sessionData, sessionData];
|
|
42
|
+
const results = await SessionModel.batchCreate(sessionsToCreate as LobeAgentSession[]);
|
|
43
|
+
|
|
44
|
+
expect(results.ids).toHaveLength(sessionsToCreate.length);
|
|
45
|
+
// Verify that the sessions have been added to the database
|
|
46
|
+
for (const result of results.ids!) {
|
|
47
|
+
const sessionInDb = await SessionModel.findById(result);
|
|
48
|
+
expect(sessionInDb).toEqual(expect.objectContaining(sessionData));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should query sessions with pagination', async () => {
|
|
53
|
+
// Create multiple sessions to test the query method
|
|
54
|
+
await SessionModel.batchCreate([sessionData, sessionData] as LobeAgentSession[]);
|
|
55
|
+
|
|
56
|
+
const queriedSessions = await SessionModel.query({ pageSize: 1, current: 0 });
|
|
57
|
+
|
|
58
|
+
expect(queriedSessions).toHaveLength(1);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should query sessions by group', async () => {
|
|
62
|
+
// Create multiple sessions to test the queryByGroup method
|
|
63
|
+
const group: SessionGroupKey = 'testGroup';
|
|
64
|
+
await SessionModel.batchCreate([sessionData, sessionData] as LobeAgentSession[]);
|
|
65
|
+
|
|
66
|
+
const sessionsByGroup = await SessionModel.queryByGroup(group);
|
|
67
|
+
|
|
68
|
+
// Assuming all created sessions belong to the same group
|
|
69
|
+
expect(sessionsByGroup).toHaveLength(2);
|
|
70
|
+
expect(sessionsByGroup.every((i) => i.group === group)).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should update a session', async () => {
|
|
74
|
+
const createdSession = await SessionModel.create('agent', sessionData);
|
|
75
|
+
const updateData = { group: 'newGroup' };
|
|
76
|
+
|
|
77
|
+
await SessionModel.update(createdSession.id, updateData);
|
|
78
|
+
const updatedSession = await SessionModel.findById(createdSession.id);
|
|
79
|
+
|
|
80
|
+
expect(updatedSession).toHaveProperty('group', 'newGroup');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// 删除一个 session 时,也需要同步删除具有 sessionId 的 topic 和 message
|
|
84
|
+
it('should delete a session and its associated data', async () => {
|
|
85
|
+
// create session , topic and message test data
|
|
86
|
+
const { id: sessionId } = await SessionModel.create('agent', sessionData);
|
|
87
|
+
|
|
88
|
+
const topicData = {
|
|
89
|
+
title: 'Test Topic',
|
|
90
|
+
sessionId: sessionId,
|
|
91
|
+
favorite: false,
|
|
92
|
+
};
|
|
93
|
+
const createdTopic = await TopicModel.create(topicData);
|
|
94
|
+
|
|
95
|
+
const messageData: CreateMessageParams = {
|
|
96
|
+
content: 'Test Message',
|
|
97
|
+
sessionId: sessionId,
|
|
98
|
+
topicId: createdTopic.id,
|
|
99
|
+
role: 'user',
|
|
100
|
+
};
|
|
101
|
+
await MessageModel.create(messageData);
|
|
102
|
+
|
|
103
|
+
await SessionModel.delete(sessionId);
|
|
104
|
+
|
|
105
|
+
// Verify the session and its related data (topics, messages) are deleted
|
|
106
|
+
const sessionInDb = await SessionModel.findById(sessionId);
|
|
107
|
+
expect(sessionInDb).toBeUndefined();
|
|
108
|
+
|
|
109
|
+
// You need to verify that topics and messages related to the session are also deleted
|
|
110
|
+
const topicsInDb = await TopicModel.findBySessionId(sessionId);
|
|
111
|
+
expect(topicsInDb).toHaveLength(0);
|
|
112
|
+
|
|
113
|
+
// Verify all associated messages are deleted
|
|
114
|
+
const messagesInDb = await MessageModel.query({ sessionId });
|
|
115
|
+
expect(messagesInDb).toHaveLength(0);
|
|
116
|
+
});
|
|
117
|
+
});
|