@lobehub/chat 0.135.0 → 0.135.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +8 -8
- package/README.zh-CN.md +8 -8
- package/package.json +2 -2
- package/src/app/api/plugin/store/route.ts +1 -1
- package/src/database/models/message.ts +88 -77
- package/src/database/models/plugin.ts +9 -4
- package/src/database/models/session.ts +93 -83
- package/src/database/models/sessionGroup.ts +38 -30
- package/src/database/models/topic.ts +104 -97
- package/src/database/models/user.ts +12 -3
- package/src/libs/swr/index.ts +18 -0
- package/src/store/chat/slices/message/action.test.ts +1 -1
- package/src/store/chat/slices/message/action.ts +8 -9
- package/src/store/session/slices/session/action.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.135.1](https://github.com/lobehub/lobe-chat/compare/v0.135.0...v0.135.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-03-14**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor the db model.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor the db model, closes [#1567](https://github.com/lobehub/lobe-chat/issues/1567) ([3d56dd6](https://github.com/lobehub/lobe-chat/commit/3d56dd6))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 0.135.0](https://github.com/lobehub/lobe-chat/compare/v0.134.1...v0.135.0)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2024-03-14**</sup>
|
package/README.md
CHANGED
|
@@ -216,14 +216,14 @@ In addition, these plugins are not limited to news aggregation, but can also ext
|
|
|
216
216
|
|
|
217
217
|
<!-- PLUGIN LIST -->
|
|
218
218
|
|
|
219
|
-
| Recent Submits | Description
|
|
220
|
-
| ----------------------------------------------------------------------------------------------------------------- |
|
|
221
|
-
| [
|
|
222
|
-
| [
|
|
223
|
-
| [
|
|
224
|
-
| [
|
|
225
|
-
|
|
226
|
-
> 📊 Total plugins: [<kbd>**
|
|
219
|
+
| Recent Submits | Description |
|
|
220
|
+
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
221
|
+
| [Calendar Assistant](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **cc** on **2024-03-13**</sup> | A plugin to manage your calendar events # will auto generate i18n in workflow<br/>`calendar` `schedule` `will-auto-generate-i-18-n-in-workflow` |
|
|
222
|
+
| [Charts & Diagrams](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | Mermaid Diagrams, Schemes for Presentations, Analysis, research websites, pie charts.<br/>`chart` `diagram` |
|
|
223
|
+
| [Social Search](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | The Social Search provides access to tweets, users, followers, images, media and more.<br/>`social` `twitter` `x` `search` |
|
|
224
|
+
| [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | Get realtime crypto price, BTC, ETH, BNB, and the latest insights.The latest coin news and airdrop opportunities.<br/>`crypto` `btc` `eth` `bnb` |
|
|
225
|
+
|
|
226
|
+
> 📊 Total plugins: [<kbd>**59**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
|
|
227
227
|
|
|
228
228
|
<!-- PLUGIN LIST -->
|
|
229
229
|
|
package/README.zh-CN.md
CHANGED
|
@@ -208,14 +208,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
208
208
|
|
|
209
209
|
<!-- PLUGIN LIST -->
|
|
210
210
|
|
|
211
|
-
| 最近新增 | 插件描述
|
|
212
|
-
| ----------------------------------------------------------------------------------------------------------------- |
|
|
213
|
-
| [
|
|
214
|
-
| [
|
|
215
|
-
| [
|
|
216
|
-
| [
|
|
217
|
-
|
|
218
|
-
> 📊 Total plugins: [<kbd>**
|
|
211
|
+
| 最近新增 | 插件描述 |
|
|
212
|
+
| ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
213
|
+
| [日历助手](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **cc** on **2024-03-13**</sup> | 一个用于管理日历事件的插件 # 将自动生成工作流程中的 i18n<br/>`日历` `日程安排` `将自动生成工作流程中的-i-18-n` |
|
|
214
|
+
| [图表和图示](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | 美人鱼图表,演示文稿方案,分析,研究网站,饼图。<br/>`图表` `图示` |
|
|
215
|
+
| [社交搜索](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | 社交搜索提供访问推文、用户、关注者、图片、媒体等功能。<br/>`社交` `推特` `x` `搜索` |
|
|
216
|
+
| [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | 获取实时加密货币价格,BTC,ETH,BNB 和最新见解。最新的币新闻和空投机会。<br/>`加密货币` `btc` `eth` `bnb` |
|
|
217
|
+
|
|
218
|
+
> 📊 Total plugins: [<kbd>**59**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
|
|
219
219
|
|
|
220
220
|
<!-- PLUGIN LIST -->
|
|
221
221
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.135.
|
|
3
|
+
"version": "0.135.1",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
"uuid": "^9",
|
|
149
149
|
"yaml": "^2",
|
|
150
150
|
"zod": "^3",
|
|
151
|
-
"zustand": "^4.
|
|
151
|
+
"zustand": "^4.5.2",
|
|
152
152
|
"zustand-utils": "^1.3.2"
|
|
153
153
|
},
|
|
154
154
|
"devDependencies": {
|
|
@@ -11,7 +11,7 @@ export const GET = async (req: Request) => {
|
|
|
11
11
|
|
|
12
12
|
let res: Response;
|
|
13
13
|
|
|
14
|
-
res = await fetch(pluginStore.getPluginIndexUrl(locale as any));
|
|
14
|
+
res = await fetch(pluginStore.getPluginIndexUrl(locale as any), { next: { revalidate: 3600 } });
|
|
15
15
|
|
|
16
16
|
if (res.status === 404) {
|
|
17
17
|
res = await fetch(pluginStore.getPluginIndexUrl(DEFAULT_LANG));
|
|
@@ -26,19 +26,8 @@ class _MessageModel extends BaseModel {
|
|
|
26
26
|
constructor() {
|
|
27
27
|
super('messages', DB_MessageSchema);
|
|
28
28
|
}
|
|
29
|
-
async create(data: CreateMessageParams) {
|
|
30
|
-
const id = nanoid();
|
|
31
|
-
|
|
32
|
-
const messageData: DB_Message = this.mapChatMessageToDBMessage(data as ChatMessage);
|
|
33
|
-
|
|
34
|
-
return this._add(messageData, id);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async batchCreate(messages: ChatMessage[]) {
|
|
38
|
-
const data: DB_Message[] = messages.map((m) => this.mapChatMessageToDBMessage(m));
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
}
|
|
30
|
+
// **************** Query *************** //
|
|
42
31
|
|
|
43
32
|
async query({
|
|
44
33
|
sessionId,
|
|
@@ -91,45 +80,79 @@ class _MessageModel extends BaseModel {
|
|
|
91
80
|
return this.table.get(id);
|
|
92
81
|
}
|
|
93
82
|
|
|
94
|
-
async
|
|
95
|
-
|
|
83
|
+
async queryAll() {
|
|
84
|
+
const data: DBModel<DB_Message>[] = await this.table.orderBy('updatedAt').toArray();
|
|
85
|
+
|
|
86
|
+
return data.map((element) => this.mapToChatMessage(element));
|
|
96
87
|
}
|
|
97
88
|
|
|
98
|
-
async
|
|
99
|
-
return this.table.
|
|
89
|
+
async queryBySessionId(sessionId: string) {
|
|
90
|
+
return this.table.where('sessionId').equals(sessionId).toArray();
|
|
100
91
|
}
|
|
101
92
|
|
|
102
|
-
async
|
|
103
|
-
|
|
93
|
+
queryByTopicId = async (topicId: string) => {
|
|
94
|
+
const dbMessages = await this.table.where('topicId').equals(topicId).toArray();
|
|
95
|
+
|
|
96
|
+
return dbMessages.map((message) => this.mapToChatMessage(message));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
async count() {
|
|
100
|
+
return this.table.count();
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
|
|
107
|
-
const item = await this.findById(id);
|
|
103
|
+
// **************** Create *************** //
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
async create(data: CreateMessageParams) {
|
|
106
|
+
const id = nanoid();
|
|
107
|
+
|
|
108
|
+
const messageData: DB_Message = this.mapChatMessageToDBMessage(data as ChatMessage);
|
|
109
|
+
|
|
110
|
+
return this._add(messageData, id);
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
*
|
|
115
|
-
* @param {string[]} messageIds - The identifiers of the messages to be updated.
|
|
116
|
-
* @param {Partial<DB_Message>} updateFields - An object containing the fields to update and their new values.
|
|
117
|
-
* @returns {Promise<number>} - The number of updated messages.
|
|
118
|
-
*/
|
|
119
|
-
async batchUpdate(messageIds: string[], updateFields: Partial<DB_Message>): Promise<number> {
|
|
120
|
-
// Retrieve the messages by their IDs
|
|
121
|
-
const messagesToUpdate = await this.table.where(':id').anyOf(messageIds).toArray();
|
|
113
|
+
async batchCreate(messages: ChatMessage[]) {
|
|
114
|
+
const data: DB_Message[] = messages.map((m) => this.mapChatMessageToDBMessage(m));
|
|
122
115
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
...message,
|
|
126
|
-
...updateFields,
|
|
127
|
-
}));
|
|
116
|
+
return this._batchAdd(data);
|
|
117
|
+
}
|
|
128
118
|
|
|
129
|
-
|
|
130
|
-
await this.
|
|
119
|
+
async duplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
|
|
120
|
+
const duplicatedMessages = await this.createDuplicateMessages(messages);
|
|
121
|
+
// 批量添加复制后的消息到数据库
|
|
122
|
+
await this.batchCreate(duplicatedMessages);
|
|
123
|
+
return duplicatedMessages;
|
|
124
|
+
}
|
|
131
125
|
|
|
132
|
-
|
|
126
|
+
async createDuplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
|
|
127
|
+
// 创建一个映射来存储原始消息ID和复制消息ID之间的关系
|
|
128
|
+
const idMapping = new Map<string, string>();
|
|
129
|
+
|
|
130
|
+
// 首先复制所有消息,并为每个复制的消息生成新的ID
|
|
131
|
+
const duplicatedMessages = messages.map((originalMessage) => {
|
|
132
|
+
const newId = nanoid();
|
|
133
|
+
idMapping.set(originalMessage.id, newId);
|
|
134
|
+
|
|
135
|
+
return { ...originalMessage, id: newId };
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// 更新 parentId 为复制后的新ID
|
|
139
|
+
for (const duplicatedMessage of duplicatedMessages) {
|
|
140
|
+
if (duplicatedMessage.parentId && idMapping.has(duplicatedMessage.parentId)) {
|
|
141
|
+
duplicatedMessage.parentId = idMapping.get(duplicatedMessage.parentId);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return duplicatedMessages;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// **************** Delete *************** //
|
|
149
|
+
|
|
150
|
+
async delete(id: string) {
|
|
151
|
+
return this.table.delete(id);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async clearTable() {
|
|
155
|
+
return this.table.clear();
|
|
133
156
|
}
|
|
134
157
|
|
|
135
158
|
/**
|
|
@@ -158,55 +181,43 @@ class _MessageModel extends BaseModel {
|
|
|
158
181
|
return this.table.bulkDelete(messageIds);
|
|
159
182
|
}
|
|
160
183
|
|
|
161
|
-
|
|
162
|
-
const data: DBModel<DB_Message>[] = await this.table.orderBy('updatedAt').toArray();
|
|
163
|
-
|
|
164
|
-
return data.map((element) => this.mapToChatMessage(element));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async count() {
|
|
168
|
-
return this.table.count();
|
|
169
|
-
}
|
|
184
|
+
// **************** Update *************** //
|
|
170
185
|
|
|
171
|
-
async
|
|
172
|
-
return this.
|
|
186
|
+
async update(id: string, data: DeepPartial<DB_Message>) {
|
|
187
|
+
return this._update(id, data);
|
|
173
188
|
}
|
|
174
189
|
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
return dbMessages.map((message) => this.mapToChatMessage(message));
|
|
179
|
-
};
|
|
190
|
+
async updatePluginState(id: string, key: string, value: any) {
|
|
191
|
+
const item = await this.findById(id);
|
|
180
192
|
|
|
181
|
-
|
|
182
|
-
const duplicatedMessages = await this.createDuplicateMessages(messages);
|
|
183
|
-
// 批量添加复制后的消息到数据库
|
|
184
|
-
await this.batchCreate(duplicatedMessages);
|
|
185
|
-
return duplicatedMessages;
|
|
193
|
+
return this.update(id, { pluginState: { ...item.pluginState, [key]: value } });
|
|
186
194
|
}
|
|
187
195
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Batch updates multiple fields of the specified messages.
|
|
198
|
+
*
|
|
199
|
+
* @param {string[]} messageIds - The identifiers of the messages to be updated.
|
|
200
|
+
* @param {Partial<DB_Message>} updateFields - An object containing the fields to update and their new values.
|
|
201
|
+
* @returns {Promise<number>} - The number of updated messages.
|
|
202
|
+
*/
|
|
203
|
+
async batchUpdate(messageIds: string[], updateFields: Partial<DB_Message>): Promise<number> {
|
|
204
|
+
// Retrieve the messages by their IDs
|
|
205
|
+
const messagesToUpdate = await this.table.where(':id').anyOf(messageIds).toArray();
|
|
196
206
|
|
|
197
|
-
|
|
198
|
-
|
|
207
|
+
// Update the specified fields of each message
|
|
208
|
+
const updatedMessages = messagesToUpdate.map((message) => ({
|
|
209
|
+
...message,
|
|
210
|
+
...updateFields,
|
|
211
|
+
}));
|
|
199
212
|
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
if (duplicatedMessage.parentId && idMapping.has(duplicatedMessage.parentId)) {
|
|
203
|
-
duplicatedMessage.parentId = idMapping.get(duplicatedMessage.parentId);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
213
|
+
// Use the bulkPut method to update the messages in bulk
|
|
214
|
+
await this.table.bulkPut(updatedMessages);
|
|
206
215
|
|
|
207
|
-
return
|
|
216
|
+
return updatedMessages.length;
|
|
208
217
|
}
|
|
209
218
|
|
|
219
|
+
// **************** Helper *************** //
|
|
220
|
+
|
|
210
221
|
private mapChatMessageToDBMessage(message: ChatMessage): DB_Message {
|
|
211
222
|
const { extra, ...messageData } = message;
|
|
212
223
|
|
|
@@ -7,11 +7,14 @@ class _PluginModel extends BaseModel {
|
|
|
7
7
|
constructor() {
|
|
8
8
|
super('plugins', DB_PluginSchema);
|
|
9
9
|
}
|
|
10
|
+
// **************** Query *************** //
|
|
10
11
|
|
|
11
12
|
getList = async (): Promise<DB_Plugin[]> => {
|
|
12
13
|
return this.table.toArray();
|
|
13
14
|
};
|
|
14
15
|
|
|
16
|
+
// **************** Create *************** //
|
|
17
|
+
|
|
15
18
|
create = async (plugin: DB_Plugin) => {
|
|
16
19
|
const old = await this.table.get(plugin.identifier);
|
|
17
20
|
|
|
@@ -21,18 +24,20 @@ class _PluginModel extends BaseModel {
|
|
|
21
24
|
batchCreate = async (plugins: DB_Plugin[]) => {
|
|
22
25
|
return this._batchAdd(plugins);
|
|
23
26
|
};
|
|
27
|
+
// **************** Delete *************** //
|
|
24
28
|
|
|
25
29
|
delete(id: string) {
|
|
26
30
|
return this.table.delete(id);
|
|
27
31
|
}
|
|
32
|
+
clear() {
|
|
33
|
+
return this.table.clear();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// **************** Update *************** //
|
|
28
37
|
|
|
29
38
|
update: (id: string, value: Partial<DB_Plugin>) => Promise<number> = async (id, value) => {
|
|
30
39
|
return this.table.update(id, value);
|
|
31
40
|
};
|
|
32
|
-
|
|
33
|
-
clear() {
|
|
34
|
-
return this.table.clear();
|
|
35
|
-
}
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export const PluginModel = new _PluginModel();
|
|
@@ -21,29 +21,7 @@ class _SessionModel extends BaseModel {
|
|
|
21
21
|
super('sessions', DB_SessionSchema);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
const data = merge(DEFAULT_AGENT_LOBE_SESSION, { type, ...defaultValue });
|
|
26
|
-
const dataDB = this.mapToDB_Session(data);
|
|
27
|
-
return this._add(dataDB, id);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async batchCreate(sessions: LobeAgentSession[]) {
|
|
31
|
-
const DB_Sessions = await Promise.all(
|
|
32
|
-
sessions.map(async (s) => {
|
|
33
|
-
if (s.group && s.group !== SessionDefaultGroup.Default) {
|
|
34
|
-
// Check if the group exists in the SessionGroup table
|
|
35
|
-
const groupExists = await SessionGroupModel.findById(s.group);
|
|
36
|
-
// If the group does not exist, set it to default
|
|
37
|
-
if (!groupExists) {
|
|
38
|
-
s.group = SessionDefaultGroup.Default;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return this.mapToDB_Session(s);
|
|
42
|
-
}),
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
return this._batchAdd<DB_Session>(DB_Sessions, { idGenerator: uuid });
|
|
46
|
-
}
|
|
24
|
+
// **************** Query *************** //
|
|
47
25
|
|
|
48
26
|
async query({
|
|
49
27
|
pageSize = 9999,
|
|
@@ -103,59 +81,6 @@ class _SessionModel extends BaseModel {
|
|
|
103
81
|
return Object.fromEntries(groupItems);
|
|
104
82
|
}
|
|
105
83
|
|
|
106
|
-
async update(id: string, data: Partial<DB_Session>) {
|
|
107
|
-
return super._update(id, data);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async updatePinned(id: string, pinned: boolean) {
|
|
111
|
-
return this.update(id, { pinned: pinned ? 1 : 0 });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
|
|
115
|
-
const session = await this.findById(id);
|
|
116
|
-
if (!session) return;
|
|
117
|
-
|
|
118
|
-
const config = merge(session.config, data);
|
|
119
|
-
|
|
120
|
-
return this.update(id, { config });
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Delete a session , also delete all messages and topic associated with it.
|
|
125
|
-
*/
|
|
126
|
-
async delete(id: string) {
|
|
127
|
-
return this.db.transaction('rw', [this.table, this.db.topics, this.db.messages], async () => {
|
|
128
|
-
// Delete all topics associated with the session
|
|
129
|
-
const topics = await this.db.topics.where('sessionId').equals(id).toArray();
|
|
130
|
-
const topicIds = topics.map((topic) => topic.id);
|
|
131
|
-
if (topicIds.length > 0) {
|
|
132
|
-
await this.db.topics.bulkDelete(topicIds);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Delete all messages associated with the session
|
|
136
|
-
const messages = await this.db.messages.where('sessionId').equals(id).toArray();
|
|
137
|
-
const messageIds = messages.map((message) => message.id);
|
|
138
|
-
if (messageIds.length > 0) {
|
|
139
|
-
await this.db.messages.bulkDelete(messageIds);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Finally, delete the session itself
|
|
143
|
-
await this.table.delete(id);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async clearTable() {
|
|
148
|
-
return this.table.clear();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async findById(id: string): Promise<DBModel<DB_Session>> {
|
|
152
|
-
return this.table.get(id);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async isEmpty() {
|
|
156
|
-
return (await this.table.count()) === 0;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
84
|
/**
|
|
160
85
|
* Query sessions by keyword in title, description, content, or translated content
|
|
161
86
|
* @param keyword The keyword to search for
|
|
@@ -225,6 +150,50 @@ class _SessionModel extends BaseModel {
|
|
|
225
150
|
return this.mapToAgentSessions(items);
|
|
226
151
|
}
|
|
227
152
|
|
|
153
|
+
async getPinnedSessions(): Promise<LobeSessions> {
|
|
154
|
+
const items: DBModel<DB_Session>[] = await this.table
|
|
155
|
+
.where('pinned')
|
|
156
|
+
.equals(1)
|
|
157
|
+
.reverse()
|
|
158
|
+
.sortBy('updatedAt');
|
|
159
|
+
|
|
160
|
+
return this.mapToAgentSessions(items);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async findById(id: string): Promise<DBModel<DB_Session>> {
|
|
164
|
+
return this.table.get(id);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async isEmpty() {
|
|
168
|
+
return (await this.table.count()) === 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// **************** Create *************** //
|
|
172
|
+
|
|
173
|
+
async create(type: 'agent' | 'group', defaultValue: Partial<LobeAgentSession>, id = uuid()) {
|
|
174
|
+
const data = merge(DEFAULT_AGENT_LOBE_SESSION, { type, ...defaultValue });
|
|
175
|
+
const dataDB = this.mapToDB_Session(data);
|
|
176
|
+
return this._add(dataDB, id);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async batchCreate(sessions: LobeAgentSession[]) {
|
|
180
|
+
const DB_Sessions = await Promise.all(
|
|
181
|
+
sessions.map(async (s) => {
|
|
182
|
+
if (s.group && s.group !== SessionDefaultGroup.Default) {
|
|
183
|
+
// Check if the group exists in the SessionGroup table
|
|
184
|
+
const groupExists = await SessionGroupModel.findById(s.group);
|
|
185
|
+
// If the group does not exist, set it to default
|
|
186
|
+
if (!groupExists) {
|
|
187
|
+
s.group = SessionDefaultGroup.Default;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return this.mapToDB_Session(s);
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return this._batchAdd<DB_Session>(DB_Sessions, { idGenerator: uuid });
|
|
195
|
+
}
|
|
196
|
+
|
|
228
197
|
async duplicate(id: string, newTitle?: string) {
|
|
229
198
|
const session = await this.findById(id);
|
|
230
199
|
if (!session) return;
|
|
@@ -234,16 +203,57 @@ class _SessionModel extends BaseModel {
|
|
|
234
203
|
return this._add(newSession, uuid());
|
|
235
204
|
}
|
|
236
205
|
|
|
237
|
-
|
|
238
|
-
const items: DBModel<DB_Session>[] = await this.table
|
|
239
|
-
.where('pinned')
|
|
240
|
-
.equals(1)
|
|
241
|
-
.reverse()
|
|
242
|
-
.sortBy('updatedAt');
|
|
206
|
+
// **************** Delete *************** //
|
|
243
207
|
|
|
244
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Delete a session , also delete all messages and topic associated with it.
|
|
210
|
+
*/
|
|
211
|
+
async delete(id: string) {
|
|
212
|
+
return this.db.transaction('rw', [this.table, this.db.topics, this.db.messages], async () => {
|
|
213
|
+
// Delete all topics associated with the session
|
|
214
|
+
const topics = await this.db.topics.where('sessionId').equals(id).toArray();
|
|
215
|
+
const topicIds = topics.map((topic) => topic.id);
|
|
216
|
+
if (topicIds.length > 0) {
|
|
217
|
+
await this.db.topics.bulkDelete(topicIds);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Delete all messages associated with the session
|
|
221
|
+
const messages = await this.db.messages.where('sessionId').equals(id).toArray();
|
|
222
|
+
const messageIds = messages.map((message) => message.id);
|
|
223
|
+
if (messageIds.length > 0) {
|
|
224
|
+
await this.db.messages.bulkDelete(messageIds);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Finally, delete the session itself
|
|
228
|
+
await this.table.delete(id);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async clearTable() {
|
|
233
|
+
return this.table.clear();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// **************** Update *************** //
|
|
237
|
+
|
|
238
|
+
async update(id: string, data: Partial<DB_Session>) {
|
|
239
|
+
return this._update(id, data);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async updatePinned(id: string, pinned: boolean) {
|
|
243
|
+
return this.update(id, { pinned: pinned ? 1 : 0 });
|
|
245
244
|
}
|
|
246
245
|
|
|
246
|
+
async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
|
|
247
|
+
const session = await this.findById(id);
|
|
248
|
+
if (!session) return;
|
|
249
|
+
|
|
250
|
+
const config = merge(session.config, data);
|
|
251
|
+
|
|
252
|
+
return this.update(id, { config });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// **************** Helper *************** //
|
|
256
|
+
|
|
247
257
|
private mapToDB_Session(session: LobeAgentSession): DBModel<DB_Session> {
|
|
248
258
|
return {
|
|
249
259
|
...session,
|
|
@@ -8,32 +8,7 @@ class _SessionGroupModel extends BaseModel {
|
|
|
8
8
|
super('sessionGroups', DB_SessionGroupSchema);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
return this._add({ name, sort }, id);
|
|
13
|
-
}
|
|
14
|
-
async batchCreate(groups: SessionGroups) {
|
|
15
|
-
return this._batchAdd(groups, { idGenerator: nanoid });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async findById(id: string): Promise<DB_SessionGroup> {
|
|
19
|
-
return this.table.get(id);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async update(id: string, data: Partial<DB_SessionGroup>) {
|
|
23
|
-
return super._update(id, data);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async delete(id: string, removeGroupItem: boolean = false) {
|
|
27
|
-
this.db.sessions.toCollection().modify((session) => {
|
|
28
|
-
// update all session associated with the sessionGroup to default
|
|
29
|
-
if (session.group === id) session.group = 'default';
|
|
30
|
-
});
|
|
31
|
-
if (!removeGroupItem) {
|
|
32
|
-
return this.table.delete(id);
|
|
33
|
-
} else {
|
|
34
|
-
return this.db.sessions.where('group').equals(id).delete();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
11
|
+
// **************** Query *************** //
|
|
37
12
|
|
|
38
13
|
async query(): Promise<SessionGroups> {
|
|
39
14
|
const allGroups = await this.table.toArray();
|
|
@@ -60,6 +35,43 @@ class _SessionGroupModel extends BaseModel {
|
|
|
60
35
|
});
|
|
61
36
|
}
|
|
62
37
|
|
|
38
|
+
async findById(id: string): Promise<DB_SessionGroup> {
|
|
39
|
+
return this.table.get(id);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// **************** Create *************** //
|
|
43
|
+
|
|
44
|
+
async create(name: string, sort?: number, id = nanoid()) {
|
|
45
|
+
return this._add({ name, sort }, id);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async batchCreate(groups: SessionGroups) {
|
|
49
|
+
return this._batchAdd(groups, { idGenerator: nanoid });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// **************** Delete *************** //
|
|
53
|
+
async delete(id: string, removeGroupItem: boolean = false) {
|
|
54
|
+
this.db.sessions.toCollection().modify((session) => {
|
|
55
|
+
// update all session associated with the sessionGroup to default
|
|
56
|
+
if (session.group === id) session.group = 'default';
|
|
57
|
+
});
|
|
58
|
+
if (!removeGroupItem) {
|
|
59
|
+
return this.table.delete(id);
|
|
60
|
+
} else {
|
|
61
|
+
return this.db.sessions.where('group').equals(id).delete();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async clear() {
|
|
66
|
+
this.table.clear();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// **************** Update *************** //
|
|
70
|
+
|
|
71
|
+
async update(id: string, data: Partial<DB_SessionGroup>) {
|
|
72
|
+
return super._update(id, data);
|
|
73
|
+
}
|
|
74
|
+
|
|
63
75
|
async updateOrder(sortMap: { id: string; sort: number }[]) {
|
|
64
76
|
return this.db.transaction('rw', this.table, async () => {
|
|
65
77
|
for (const { id, sort } of sortMap) {
|
|
@@ -67,10 +79,6 @@ class _SessionGroupModel extends BaseModel {
|
|
|
67
79
|
}
|
|
68
80
|
});
|
|
69
81
|
}
|
|
70
|
-
|
|
71
|
-
async clear() {
|
|
72
|
-
this.table.clear();
|
|
73
|
-
}
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
export const SessionGroupModel = new _SessionGroupModel();
|
|
@@ -23,19 +23,7 @@ class _TopicModel extends BaseModel {
|
|
|
23
23
|
super('topics', DB_TopicSchema);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const topic = await this._add({ favorite: favorite ? 1 : 0, sessionId, title: title }, id);
|
|
28
|
-
|
|
29
|
-
// add topicId to these messages
|
|
30
|
-
if (messages) {
|
|
31
|
-
await this.db.messages.where('id').anyOf(messages).modify({ topicId: topic.id });
|
|
32
|
-
}
|
|
33
|
-
return topic;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async batchCreate(topics: CreateTopicParams[]) {
|
|
37
|
-
return this._batchAdd(topics.map((t) => ({ ...t, favorite: t.favorite ? 1 : 0 })));
|
|
38
|
-
}
|
|
26
|
+
// **************** Query *************** //
|
|
39
27
|
|
|
40
28
|
async query({ pageSize = 9999, current = 0, sessionId }: QueryTopicParams): Promise<ChatTopic[]> {
|
|
41
29
|
const offset = current * pageSize;
|
|
@@ -58,90 +46,6 @@ class _TopicModel extends BaseModel {
|
|
|
58
46
|
return pagedTopics.map((i) => this.mapToChatTopic(i));
|
|
59
47
|
}
|
|
60
48
|
|
|
61
|
-
async findBySessionId(sessionId: string) {
|
|
62
|
-
return this.table.where({ sessionId }).toArray();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async findById(id: string): Promise<DBModel<DB_Topic>> {
|
|
66
|
-
return this.table.get(id);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Deletes a topic and all messages associated with it.
|
|
71
|
-
*/
|
|
72
|
-
async delete(id: string) {
|
|
73
|
-
return this.db.transaction('rw', [this.table, this.db.messages], async () => {
|
|
74
|
-
// Delete all messages associated with the topic
|
|
75
|
-
const messages = await this.db.messages.where('topicId').equals(id).toArray();
|
|
76
|
-
|
|
77
|
-
if (messages.length > 0) {
|
|
78
|
-
const messageIds = messages.map((msg) => msg.id);
|
|
79
|
-
await this.db.messages.bulkDelete(messageIds);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
await this.table.delete(id);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Deletes multiple topic based on the sessionId.
|
|
88
|
-
*
|
|
89
|
-
* @param {string} sessionId - The identifier of the assistant associated with the messages.
|
|
90
|
-
* @returns {Promise<void>}
|
|
91
|
-
*/
|
|
92
|
-
async batchDeleteBySessionId(sessionId: string): Promise<void> {
|
|
93
|
-
// use sessionId as the filter criteria in the query.
|
|
94
|
-
const query = this.table.where('sessionId').equals(sessionId);
|
|
95
|
-
|
|
96
|
-
// Retrieve a collection of message IDs that satisfy the criteria
|
|
97
|
-
const topicIds = await query.primaryKeys();
|
|
98
|
-
|
|
99
|
-
// Use the bulkDelete method to delete all selected messages in bulk
|
|
100
|
-
return this.table.bulkDelete(topicIds);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async clearTable() {
|
|
104
|
-
return this.table.clear();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async update(id: string, data: Partial<DB_Topic>) {
|
|
108
|
-
return super._update(id, { ...data, updatedAt: Date.now() });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async toggleFavorite(id: string, newState?: boolean) {
|
|
112
|
-
const topic = await this.findById(id);
|
|
113
|
-
if (!topic) {
|
|
114
|
-
throw new Error(`Topic with id ${id} not found`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Toggle the 'favorite' status
|
|
118
|
-
const nextState = typeof newState !== 'undefined' ? newState : !topic.favorite;
|
|
119
|
-
|
|
120
|
-
await this.update(id, { favorite: nextState ? 1 : 0 });
|
|
121
|
-
|
|
122
|
-
return nextState;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Deletes multiple topics and all messages associated with them in a transaction.
|
|
127
|
-
*/
|
|
128
|
-
async batchDelete(topicIds: string[]) {
|
|
129
|
-
return this.db.transaction('rw', [this.table, this.db.messages], async () => {
|
|
130
|
-
// Iterate over each topicId and delete related messages, then delete the topic itself
|
|
131
|
-
for (const topicId of topicIds) {
|
|
132
|
-
// Delete all messages associated with the topic
|
|
133
|
-
const messages = await this.db.messages.where('topicId').equals(topicId).toArray();
|
|
134
|
-
if (messages.length > 0) {
|
|
135
|
-
const messageIds = messages.map((msg) => msg.id);
|
|
136
|
-
await this.db.messages.bulkDelete(messageIds);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Delete the topic
|
|
140
|
-
await this.table.delete(topicId);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
49
|
queryAll() {
|
|
146
50
|
return this.table.orderBy('updatedAt').toArray();
|
|
147
51
|
}
|
|
@@ -201,6 +105,29 @@ class _TopicModel extends BaseModel {
|
|
|
201
105
|
return uniqueTopics.map((i) => ({ ...i, favorite: !!i.favorite }));
|
|
202
106
|
}
|
|
203
107
|
|
|
108
|
+
async findBySessionId(sessionId: string) {
|
|
109
|
+
return this.table.where({ sessionId }).toArray();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async findById(id: string): Promise<DBModel<DB_Topic>> {
|
|
113
|
+
return this.table.get(id);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// **************** Create *************** //
|
|
117
|
+
|
|
118
|
+
async create({ title, favorite, sessionId, messages }: CreateTopicParams, id = nanoid()) {
|
|
119
|
+
const topic = await this._add({ favorite: favorite ? 1 : 0, sessionId, title: title }, id);
|
|
120
|
+
|
|
121
|
+
// add topicId to these messages
|
|
122
|
+
if (messages) {
|
|
123
|
+
await this.db.messages.where('id').anyOf(messages).modify({ topicId: topic.id });
|
|
124
|
+
}
|
|
125
|
+
return topic;
|
|
126
|
+
}
|
|
127
|
+
async batchCreate(topics: CreateTopicParams[]) {
|
|
128
|
+
return this._batchAdd(topics.map((t) => ({ ...t, favorite: t.favorite ? 1 : 0 })));
|
|
129
|
+
}
|
|
130
|
+
|
|
204
131
|
async duplicateTopic(topicId: string, newTitle?: string) {
|
|
205
132
|
return this.db.transaction('rw', this.db.topics, this.db.messages, async () => {
|
|
206
133
|
// Step 1: get DB_Topic
|
|
@@ -226,6 +153,86 @@ class _TopicModel extends BaseModel {
|
|
|
226
153
|
});
|
|
227
154
|
}
|
|
228
155
|
|
|
156
|
+
// **************** Delete *************** //
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Deletes a topic and all messages associated with it.
|
|
160
|
+
*/
|
|
161
|
+
async delete(id: string) {
|
|
162
|
+
return this.db.transaction('rw', [this.table, this.db.messages], async () => {
|
|
163
|
+
// Delete all messages associated with the topic
|
|
164
|
+
const messages = await this.db.messages.where('topicId').equals(id).toArray();
|
|
165
|
+
|
|
166
|
+
if (messages.length > 0) {
|
|
167
|
+
const messageIds = messages.map((msg) => msg.id);
|
|
168
|
+
await this.db.messages.bulkDelete(messageIds);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await this.table.delete(id);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Deletes multiple topic based on the sessionId.
|
|
177
|
+
*
|
|
178
|
+
* @param {string} sessionId - The identifier of the assistant associated with the messages.
|
|
179
|
+
* @returns {Promise<void>}
|
|
180
|
+
*/
|
|
181
|
+
async batchDeleteBySessionId(sessionId: string): Promise<void> {
|
|
182
|
+
// use sessionId as the filter criteria in the query.
|
|
183
|
+
const query = this.table.where('sessionId').equals(sessionId);
|
|
184
|
+
|
|
185
|
+
// Retrieve a collection of message IDs that satisfy the criteria
|
|
186
|
+
const topicIds = await query.primaryKeys();
|
|
187
|
+
|
|
188
|
+
// Use the bulkDelete method to delete all selected messages in bulk
|
|
189
|
+
return this.table.bulkDelete(topicIds);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Deletes multiple topics and all messages associated with them in a transaction.
|
|
193
|
+
*/
|
|
194
|
+
async batchDelete(topicIds: string[]) {
|
|
195
|
+
return this.db.transaction('rw', [this.table, this.db.messages], async () => {
|
|
196
|
+
// Iterate over each topicId and delete related messages, then delete the topic itself
|
|
197
|
+
for (const topicId of topicIds) {
|
|
198
|
+
// Delete all messages associated with the topic
|
|
199
|
+
const messages = await this.db.messages.where('topicId').equals(topicId).toArray();
|
|
200
|
+
if (messages.length > 0) {
|
|
201
|
+
const messageIds = messages.map((msg) => msg.id);
|
|
202
|
+
await this.db.messages.bulkDelete(messageIds);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Delete the topic
|
|
206
|
+
await this.table.delete(topicId);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async clearTable() {
|
|
212
|
+
return this.table.clear();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// **************** Update *************** //
|
|
216
|
+
async update(id: string, data: Partial<DB_Topic>) {
|
|
217
|
+
return this._update(id, data);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async toggleFavorite(id: string, newState?: boolean) {
|
|
221
|
+
const topic = await this.findById(id);
|
|
222
|
+
if (!topic) {
|
|
223
|
+
throw new Error(`Topic with id ${id} not found`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Toggle the 'favorite' status
|
|
227
|
+
const nextState = typeof newState !== 'undefined' ? newState : !topic.favorite;
|
|
228
|
+
|
|
229
|
+
await this.update(id, { favorite: nextState ? 1 : 0 });
|
|
230
|
+
|
|
231
|
+
return nextState;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// **************** Helper *************** //
|
|
235
|
+
|
|
229
236
|
private mapToChatTopic = (dbTopic: DBModel<DB_Topic>): ChatTopic => ({
|
|
230
237
|
...dbTopic,
|
|
231
238
|
favorite: !!dbTopic.favorite,
|
|
@@ -10,6 +10,7 @@ class _UserModel extends BaseModel {
|
|
|
10
10
|
constructor() {
|
|
11
11
|
super('users', DB_UserSchema);
|
|
12
12
|
}
|
|
13
|
+
// **************** Query *************** //
|
|
13
14
|
|
|
14
15
|
getUser = async (): Promise<DB_User & { id: number }> => {
|
|
15
16
|
const noUser = !(await this.table.count());
|
|
@@ -21,18 +22,20 @@ class _UserModel extends BaseModel {
|
|
|
21
22
|
return list[0];
|
|
22
23
|
};
|
|
23
24
|
|
|
25
|
+
// **************** Create *************** //
|
|
26
|
+
|
|
24
27
|
create = async (user: DB_User) => {
|
|
25
28
|
return this.table.put(user);
|
|
26
29
|
};
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
return this.table.update(id, value);
|
|
30
|
-
};
|
|
31
|
+
// **************** Delete *************** //
|
|
31
32
|
|
|
32
33
|
clear() {
|
|
33
34
|
return this.table.clear();
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
// **************** Update *************** //
|
|
38
|
+
|
|
36
39
|
async updateSettings(settings: DeepPartial<GlobalSettings>) {
|
|
37
40
|
const user = await this.getUser();
|
|
38
41
|
|
|
@@ -50,6 +53,12 @@ class _UserModel extends BaseModel {
|
|
|
50
53
|
|
|
51
54
|
return this.update(user.id, { avatar });
|
|
52
55
|
}
|
|
56
|
+
|
|
57
|
+
// **************** Helper *************** //
|
|
58
|
+
|
|
59
|
+
private update = async (id: number, value: DeepPartial<DB_User>) => {
|
|
60
|
+
return this.table.update(id, value);
|
|
61
|
+
};
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
export const UserModel = new _UserModel();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import useSWR, { SWRHook } from 'swr';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 这一类请求方法是比较「死」的请求模式,只会在第一次请求时触发。不会自动刷新,刷新需要搭配 refreshXXX 这样的方法实现,
|
|
5
|
+
* 适用于 messages、topics、sessions 等由用户在客户端交互产生的数据。
|
|
6
|
+
*/
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
export const useClientDataSWR: SWRHook = (key, fetch, config) =>
|
|
9
|
+
useSWR(key, fetch, {
|
|
10
|
+
// default is 2000ms ,it makes the user's quick switch don't work correctly.
|
|
11
|
+
// Cause issue like this: https://github.com/lobehub/lobe-chat/issues/532
|
|
12
|
+
// we need to set it to 0.
|
|
13
|
+
dedupingInterval: 0,
|
|
14
|
+
refreshWhenOffline: false,
|
|
15
|
+
revalidateOnFocus: false,
|
|
16
|
+
revalidateOnReconnect: false,
|
|
17
|
+
...config,
|
|
18
|
+
});
|
|
@@ -559,7 +559,7 @@ describe('chatMessage actions', () => {
|
|
|
559
559
|
});
|
|
560
560
|
|
|
561
561
|
// 确保 mutate 调用了正确的参数
|
|
562
|
-
expect(mutate).toHaveBeenCalledWith([activeId, activeTopicId]);
|
|
562
|
+
expect(mutate).toHaveBeenCalledWith(['SWR_USE_FETCH_MESSAGES', activeId, activeTopicId]);
|
|
563
563
|
});
|
|
564
564
|
it('should handle errors during refreshing messages', async () => {
|
|
565
565
|
useChatStore.setState({ refreshMessages: realRefreshMessages });
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// Disable the auto sort key eslint rule to make the code more logic and readable
|
|
3
3
|
import { copyToClipboard } from '@lobehub/ui';
|
|
4
4
|
import { template } from 'lodash-es';
|
|
5
|
-
import
|
|
5
|
+
import { SWRResponse, mutate } from 'swr';
|
|
6
6
|
import { StateCreator } from 'zustand/vanilla';
|
|
7
7
|
|
|
8
8
|
import { LOADING_FLAT, isFunctionMessageAtStart, testFunctionMessageAtEnd } from '@/const/message';
|
|
9
9
|
import { TraceEventType, TraceNameMap } from '@/const/trace';
|
|
10
10
|
import { CreateMessageParams } from '@/database/models/message';
|
|
11
|
+
import { useClientDataSWR } from '@/libs/swr';
|
|
11
12
|
import { chatService } from '@/services/chat';
|
|
12
13
|
import { messageService } from '@/services/message';
|
|
13
14
|
import { topicService } from '@/services/topic';
|
|
@@ -25,6 +26,8 @@ import { MessageDispatch, messagesReducer } from './reducer';
|
|
|
25
26
|
|
|
26
27
|
const n = setNamespace('message');
|
|
27
28
|
|
|
29
|
+
const SWR_USE_FETCH_MESSAGES = 'SWR_USE_FETCH_MESSAGES';
|
|
30
|
+
|
|
28
31
|
interface SendMessageParams {
|
|
29
32
|
message: string;
|
|
30
33
|
files?: { id: string; url: string }[];
|
|
@@ -274,9 +277,9 @@ export const chatMessage: StateCreator<
|
|
|
274
277
|
await get().internalUpdateMessageContent(id, content);
|
|
275
278
|
},
|
|
276
279
|
useFetchMessages: (sessionId, activeTopicId) =>
|
|
277
|
-
|
|
278
|
-
[sessionId, activeTopicId],
|
|
279
|
-
async ([sessionId, topicId]: [string, string | undefined]) =>
|
|
280
|
+
useClientDataSWR<ChatMessage[]>(
|
|
281
|
+
[SWR_USE_FETCH_MESSAGES, sessionId, activeTopicId],
|
|
282
|
+
async ([, sessionId, topicId]: [string, string, string | undefined]) =>
|
|
280
283
|
messageService.getMessages(sessionId, topicId),
|
|
281
284
|
{
|
|
282
285
|
onSuccess: (messages, key) => {
|
|
@@ -289,14 +292,10 @@ export const chatMessage: StateCreator<
|
|
|
289
292
|
}),
|
|
290
293
|
);
|
|
291
294
|
},
|
|
292
|
-
// default is 2000ms ,it makes the user's quick switch don't work correctly.
|
|
293
|
-
// Cause issue like this: https://github.com/lobehub/lobe-chat/issues/532
|
|
294
|
-
// we need to set it to 0.
|
|
295
|
-
dedupingInterval: 0,
|
|
296
295
|
},
|
|
297
296
|
),
|
|
298
297
|
refreshMessages: async () => {
|
|
299
|
-
await mutate([get().activeId, get().activeTopicId]);
|
|
298
|
+
await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId]);
|
|
300
299
|
},
|
|
301
300
|
|
|
302
301
|
// the internal process method of the AI message
|
|
@@ -6,6 +6,7 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
6
6
|
|
|
7
7
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
8
8
|
import { SESSION_CHAT_URL } from '@/const/url';
|
|
9
|
+
import { useClientDataSWR } from '@/libs/swr';
|
|
9
10
|
import { sessionService } from '@/services/session';
|
|
10
11
|
import { useGlobalStore } from '@/store/global';
|
|
11
12
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
@@ -154,7 +155,7 @@ export const createSessionSlice: StateCreator<
|
|
|
154
155
|
},
|
|
155
156
|
|
|
156
157
|
useFetchSessions: () =>
|
|
157
|
-
|
|
158
|
+
useClientDataSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getSessionsWithGroup, {
|
|
158
159
|
onSuccess: (data) => {
|
|
159
160
|
// 由于 https://github.com/lobehub/lobe-chat/pull/541 的关系
|
|
160
161
|
// 只有触发了 refreshSessions 才会更新 sessions,进而触发页面 rerender
|