liuhua liuhua commited on
Commit
40a1db3
·
1 Parent(s): 7b36ea6

Refactor Chat API (#2804)

Browse files

### What problem does this PR solve?

Refactor Chat API

### Type of change

- [x] Refactoring

---------

Co-authored-by: liuhua <10215101452@stu.ecun.edu.cn>

api/apps/sdk/{assistant.py → chat.py} RENAMED
@@ -1,304 +1,287 @@
1
- #
2
- # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
- #
16
- from flask import request
17
-
18
- from api.db import StatusEnum
19
- from api.db.db_models import TenantLLM
20
- from api.db.services.dialog_service import DialogService
21
- from api.db.services.knowledgebase_service import KnowledgebaseService
22
- from api.db.services.llm_service import LLMService, TenantLLMService
23
- from api.db.services.user_service import TenantService
24
- from api.settings import RetCode
25
- from api.utils import get_uuid
26
- from api.utils.api_utils import get_data_error_result, token_required
27
- from api.utils.api_utils import get_json_result
28
-
29
-
30
- @manager.route('/save', methods=['POST'])
31
- @token_required
32
- def save(tenant_id):
33
- req = request.json
34
- # dataset
35
- if req.get("knowledgebases") == []:
36
- return get_data_error_result(retmsg="knowledgebases can not be empty list")
37
- kb_list = []
38
- if req.get("knowledgebases"):
39
- for kb in req.get("knowledgebases"):
40
- if not kb["id"]:
41
- return get_data_error_result(retmsg="knowledgebase needs id")
42
- if not KnowledgebaseService.query(id=kb["id"], tenant_id=tenant_id):
43
- return get_data_error_result(retmsg="you do not own the knowledgebase")
44
- # if not DocumentService.query(kb_id=kb["id"]):
45
- # return get_data_error_result(retmsg="There is a invalid knowledgebase")
46
- kb_list.append(kb["id"])
47
- req["kb_ids"] = kb_list
48
- # llm
49
- llm = req.get("llm")
50
- if llm:
51
- if "model_name" in llm:
52
- req["llm_id"] = llm.pop("model_name")
53
- req["llm_setting"] = req.pop("llm")
54
- e, tenant = TenantService.get_by_id(tenant_id)
55
- if not e:
56
- return get_data_error_result(retmsg="Tenant not found!")
57
- # prompt
58
- prompt = req.get("prompt")
59
- key_mapping = {"parameters": "variables",
60
- "prologue": "opener",
61
- "quote": "show_quote",
62
- "system": "prompt",
63
- "rerank_id": "rerank_model",
64
- "vector_similarity_weight": "keywords_similarity_weight"}
65
- key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
66
- if prompt:
67
- for new_key, old_key in key_mapping.items():
68
- if old_key in prompt:
69
- prompt[new_key] = prompt.pop(old_key)
70
- for key in key_list:
71
- if key in prompt:
72
- req[key] = prompt.pop(key)
73
- req["prompt_config"] = req.pop("prompt")
74
- # create
75
- if "id" not in req:
76
- # dataset
77
- if not kb_list:
78
- return get_data_error_result(retmsg="knowledgebases are required!")
79
- # init
80
- req["id"] = get_uuid()
81
- req["description"] = req.get("description", "A helpful Assistant")
82
- req["icon"] = req.get("avatar", "")
83
- req["top_n"] = req.get("top_n", 6)
84
- req["top_k"] = req.get("top_k", 1024)
85
- req["rerank_id"] = req.get("rerank_id", "")
86
- if req.get("llm_id"):
87
- if not TenantLLMService.query(llm_name=req["llm_id"]):
88
- return get_data_error_result(retmsg="the model_name does not exist.")
89
- else:
90
- req["llm_id"] = tenant.llm_id
91
- if not req.get("name"):
92
- return get_data_error_result(retmsg="name is required.")
93
- if DialogService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value):
94
- return get_data_error_result(retmsg="Duplicated assistant name in creating dataset.")
95
- # tenant_id
96
- if req.get("tenant_id"):
97
- return get_data_error_result(retmsg="tenant_id must not be provided.")
98
- req["tenant_id"] = tenant_id
99
- # prompt more parameter
100
- default_prompt = {
101
- "system": """你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
102
- 以下是知识库:
103
- {knowledge}
104
- 以上是知识库。""",
105
- "prologue": "您好,我是您的助手小樱,长得可爱又善良,can I help you?",
106
- "parameters": [
107
- {"key": "knowledge", "optional": False}
108
- ],
109
- "empty_response": "Sorry! 知识库中未找到相关内容!"
110
- }
111
- key_list_2 = ["system", "prologue", "parameters", "empty_response"]
112
- if "prompt_config" not in req:
113
- req['prompt_config'] = {}
114
- for key in key_list_2:
115
- temp = req['prompt_config'].get(key)
116
- if not temp:
117
- req['prompt_config'][key] = default_prompt[key]
118
- for p in req['prompt_config']["parameters"]:
119
- if p["optional"]:
120
- continue
121
- if req['prompt_config']["system"].find("{%s}" % p["key"]) < 0:
122
- return get_data_error_result(
123
- retmsg="Parameter '{}' is not used".format(p["key"]))
124
- # save
125
- if not DialogService.save(**req):
126
- return get_data_error_result(retmsg="Fail to new an assistant!")
127
- # response
128
- e, res = DialogService.get_by_id(req["id"])
129
- if not e:
130
- return get_data_error_result(retmsg="Fail to new an assistant!")
131
- res = res.to_json()
132
- renamed_dict = {}
133
- for key, value in res["prompt_config"].items():
134
- new_key = key_mapping.get(key, key)
135
- renamed_dict[new_key] = value
136
- res["prompt"] = renamed_dict
137
- del res["prompt_config"]
138
- new_dict = {"similarity_threshold": res["similarity_threshold"],
139
- "keywords_similarity_weight": res["vector_similarity_weight"],
140
- "top_n": res["top_n"],
141
- "rerank_model": res['rerank_id']}
142
- res["prompt"].update(new_dict)
143
- for key in key_list:
144
- del res[key]
145
- res["llm"] = res.pop("llm_setting")
146
- res["llm"]["model_name"] = res.pop("llm_id")
147
- del res["kb_ids"]
148
- res["knowledgebases"] = req["knowledgebases"]
149
- res["avatar"] = res.pop("icon")
150
- return get_json_result(data=res)
151
- else:
152
- # authorization
153
- if not DialogService.query(tenant_id=tenant_id, id=req["id"], status=StatusEnum.VALID.value):
154
- return get_json_result(data=False, retmsg='You do not own the assistant', retcode=RetCode.OPERATING_ERROR)
155
- # prompt
156
- if not req["id"]:
157
- return get_data_error_result(retmsg="id can not be empty")
158
- e, res = DialogService.get_by_id(req["id"])
159
- res = res.to_json()
160
- if "llm_id" in req:
161
- if not TenantLLMService.query(llm_name=req["llm_id"]):
162
- return get_data_error_result(retmsg="the model_name does not exist.")
163
- if "name" in req:
164
- if not req.get("name"):
165
- return get_data_error_result(retmsg="name is not empty.")
166
- if req["name"].lower() != res["name"].lower() \
167
- and len(
168
- DialogService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value)) > 0:
169
- return get_data_error_result(retmsg="Duplicated assistant name in updating dataset.")
170
- if "prompt_config" in req:
171
- res["prompt_config"].update(req["prompt_config"])
172
- for p in res["prompt_config"]["parameters"]:
173
- if p["optional"]:
174
- continue
175
- if res["prompt_config"]["system"].find("{%s}" % p["key"]) < 0:
176
- return get_data_error_result(retmsg="Parameter '{}' is not used".format(p["key"]))
177
- if "llm_setting" in req:
178
- res["llm_setting"].update(req["llm_setting"])
179
- req["prompt_config"] = res["prompt_config"]
180
- req["llm_setting"] = res["llm_setting"]
181
- # avatar
182
- if "avatar" in req:
183
- req["icon"] = req.pop("avatar")
184
- assistant_id = req.pop("id")
185
- if "knowledgebases" in req:
186
- req.pop("knowledgebases")
187
- if not DialogService.update_by_id(assistant_id, req):
188
- return get_data_error_result(retmsg="Assistant not found!")
189
- return get_json_result(data=True)
190
-
191
-
192
- @manager.route('/delete', methods=['DELETE'])
193
- @token_required
194
- def delete(tenant_id):
195
- req = request.args
196
- if "id" not in req:
197
- return get_data_error_result(retmsg="id is required")
198
- id = req['id']
199
- if not DialogService.query(tenant_id=tenant_id, id=id, status=StatusEnum.VALID.value):
200
- return get_json_result(data=False, retmsg='you do not own the assistant.', retcode=RetCode.OPERATING_ERROR)
201
-
202
- temp_dict = {"status": StatusEnum.INVALID.value}
203
- DialogService.update_by_id(req["id"], temp_dict)
204
- return get_json_result(data=True)
205
-
206
-
207
- @manager.route('/get', methods=['GET'])
208
- @token_required
209
- def get(tenant_id):
210
- req = request.args
211
- if "id" in req:
212
- id = req["id"]
213
- ass = DialogService.query(tenant_id=tenant_id, id=id, status=StatusEnum.VALID.value)
214
- if not ass:
215
- return get_json_result(data=False, retmsg='You do not own the assistant.', retcode=RetCode.OPERATING_ERROR)
216
- if "name" in req:
217
- name = req["name"]
218
- if ass[0].name != name:
219
- return get_json_result(data=False, retmsg='name does not match id.', retcode=RetCode.OPERATING_ERROR)
220
- res = ass[0].to_json()
221
- else:
222
- if "name" in req:
223
- name = req["name"]
224
- ass = DialogService.query(name=name, tenant_id=tenant_id, status=StatusEnum.VALID.value)
225
- if not ass:
226
- return get_json_result(data=False, retmsg='You do not own the assistant.',
227
- retcode=RetCode.OPERATING_ERROR)
228
- res = ass[0].to_json()
229
- else:
230
- return get_data_error_result(retmsg="At least one of `id` or `name` must be provided.")
231
- renamed_dict = {}
232
- key_mapping = {"parameters": "variables",
233
- "prologue": "opener",
234
- "quote": "show_quote",
235
- "system": "prompt",
236
- "rerank_id": "rerank_model",
237
- "vector_similarity_weight": "keywords_similarity_weight"}
238
- key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
239
- for key, value in res["prompt_config"].items():
240
- new_key = key_mapping.get(key, key)
241
- renamed_dict[new_key] = value
242
- res["prompt"] = renamed_dict
243
- del res["prompt_config"]
244
- new_dict = {"similarity_threshold": res["similarity_threshold"],
245
- "keywords_similarity_weight": res["vector_similarity_weight"],
246
- "top_n": res["top_n"],
247
- "rerank_model": res['rerank_id']}
248
- res["prompt"].update(new_dict)
249
- for key in key_list:
250
- del res[key]
251
- res["llm"] = res.pop("llm_setting")
252
- res["llm"]["model_name"] = res.pop("llm_id")
253
- kb_list = []
254
- for kb_id in res["kb_ids"]:
255
- kb = KnowledgebaseService.query(id=kb_id)
256
- kb_list.append(kb[0].to_json())
257
- del res["kb_ids"]
258
- res["knowledgebases"] = kb_list
259
- res["avatar"] = res.pop("icon")
260
- return get_json_result(data=res)
261
-
262
-
263
- @manager.route('/list', methods=['GET'])
264
- @token_required
265
- def list_assistants(tenant_id):
266
- assts = DialogService.query(
267
- tenant_id=tenant_id,
268
- status=StatusEnum.VALID.value,
269
- reverse=True,
270
- order_by=DialogService.model.create_time)
271
- assts = [d.to_dict() for d in assts]
272
- list_assts = []
273
- renamed_dict = {}
274
- key_mapping = {"parameters": "variables",
275
- "prologue": "opener",
276
- "quote": "show_quote",
277
- "system": "prompt",
278
- "rerank_id": "rerank_model",
279
- "vector_similarity_weight": "keywords_similarity_weight"}
280
- key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
281
- for res in assts:
282
- for key, value in res["prompt_config"].items():
283
- new_key = key_mapping.get(key, key)
284
- renamed_dict[new_key] = value
285
- res["prompt"] = renamed_dict
286
- del res["prompt_config"]
287
- new_dict = {"similarity_threshold": res["similarity_threshold"],
288
- "keywords_similarity_weight": res["vector_similarity_weight"],
289
- "top_n": res["top_n"],
290
- "rerank_model": res['rerank_id']}
291
- res["prompt"].update(new_dict)
292
- for key in key_list:
293
- del res[key]
294
- res["llm"] = res.pop("llm_setting")
295
- res["llm"]["model_name"] = res.pop("llm_id")
296
- kb_list = []
297
- for kb_id in res["kb_ids"]:
298
- kb = KnowledgebaseService.query(id=kb_id)
299
- kb_list.append(kb[0].to_json())
300
- del res["kb_ids"]
301
- res["knowledgebases"] = kb_list
302
- res["avatar"] = res.pop("icon")
303
- list_assts.append(res)
304
- return get_json_result(data=list_assts)
 
1
+ #
2
+ # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from flask import request
17
+
18
+ from api.db import StatusEnum
19
+ from api.db.db_models import TenantLLM
20
+ from api.db.services.dialog_service import DialogService
21
+ from api.db.services.knowledgebase_service import KnowledgebaseService
22
+ from api.db.services.llm_service import LLMService, TenantLLMService
23
+ from api.db.services.user_service import TenantService
24
+ from api.settings import RetCode
25
+ from api.utils import get_uuid
26
+ from api.utils.api_utils import get_error_data_result, token_required
27
+ from api.utils.api_utils import get_result
28
+
29
+ @manager.route('/chat', methods=['POST'])
30
+ @token_required
31
+ def create(tenant_id):
32
+ req=request.json
33
+ if not req.get("knowledgebases"):
34
+ return get_error_data_result(retmsg="knowledgebases are required")
35
+ kb_list = []
36
+ for kb in req.get("knowledgebases"):
37
+ if not kb["id"]:
38
+ return get_error_data_result(retmsg="knowledgebase needs id")
39
+ if not KnowledgebaseService.query(id=kb["id"], tenant_id=tenant_id):
40
+ return get_error_data_result(retmsg="you do not own the knowledgebase")
41
+ # if not DocumentService.query(kb_id=kb["id"]):
42
+ # return get_error_data_result(retmsg="There is a invalid knowledgebase")
43
+ kb_list.append(kb["id"])
44
+ req["kb_ids"] = kb_list
45
+ # llm
46
+ llm = req.get("llm")
47
+ if llm:
48
+ if "model_name" in llm:
49
+ req["llm_id"] = llm.pop("model_name")
50
+ req["llm_setting"] = req.pop("llm")
51
+ e, tenant = TenantService.get_by_id(tenant_id)
52
+ if not e:
53
+ return get_error_data_result(retmsg="Tenant not found!")
54
+ # prompt
55
+ prompt = req.get("prompt")
56
+ key_mapping = {"parameters": "variables",
57
+ "prologue": "opener",
58
+ "quote": "show_quote",
59
+ "system": "prompt",
60
+ "rerank_id": "rerank_model",
61
+ "vector_similarity_weight": "keywords_similarity_weight"}
62
+ key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
63
+ if prompt:
64
+ for new_key, old_key in key_mapping.items():
65
+ if old_key in prompt:
66
+ prompt[new_key] = prompt.pop(old_key)
67
+ for key in key_list:
68
+ if key in prompt:
69
+ req[key] = prompt.pop(key)
70
+ req["prompt_config"] = req.pop("prompt")
71
+ # init
72
+ req["id"] = get_uuid()
73
+ req["description"] = req.get("description", "A helpful Assistant")
74
+ req["icon"] = req.get("avatar", "")
75
+ req["top_n"] = req.get("top_n", 6)
76
+ req["top_k"] = req.get("top_k", 1024)
77
+ req["rerank_id"] = req.get("rerank_id", "")
78
+ if req.get("llm_id"):
79
+ if not TenantLLMService.query(llm_name=req["llm_id"]):
80
+ return get_error_data_result(retmsg="the model_name does not exist.")
81
+ else:
82
+ req["llm_id"] = tenant.llm_id
83
+ if not req.get("name"):
84
+ return get_error_data_result(retmsg="name is required.")
85
+ if DialogService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value):
86
+ return get_error_data_result(retmsg="Duplicated chat name in creating dataset.")
87
+ # tenant_id
88
+ if req.get("tenant_id"):
89
+ return get_error_data_result(retmsg="tenant_id must not be provided.")
90
+ req["tenant_id"] = tenant_id
91
+ # prompt more parameter
92
+ default_prompt = {
93
+ "system": """你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
94
+ 以下是知识库:
95
+ {knowledge}
96
+ 以上是知识库。""",
97
+ "prologue": "您好,我是您的助手小樱,长得可爱又善良,can I help you?",
98
+ "parameters": [
99
+ {"key": "knowledge", "optional": False}
100
+ ],
101
+ "empty_response": "Sorry! 知识库中未找到相关内容!"
102
+ }
103
+ key_list_2 = ["system", "prologue", "parameters", "empty_response"]
104
+ if "prompt_config" not in req:
105
+ req['prompt_config'] = {}
106
+ for key in key_list_2:
107
+ temp = req['prompt_config'].get(key)
108
+ if not temp:
109
+ req['prompt_config'][key] = default_prompt[key]
110
+ for p in req['prompt_config']["parameters"]:
111
+ if p["optional"]:
112
+ continue
113
+ if req['prompt_config']["system"].find("{%s}" % p["key"]) < 0:
114
+ return get_error_data_result(
115
+ retmsg="Parameter '{}' is not used".format(p["key"]))
116
+ # save
117
+ if not DialogService.save(**req):
118
+ return get_error_data_result(retmsg="Fail to new a chat!")
119
+ # response
120
+ e, res = DialogService.get_by_id(req["id"])
121
+ if not e:
122
+ return get_error_data_result(retmsg="Fail to new a chat!")
123
+ res = res.to_json()
124
+ renamed_dict = {}
125
+ for key, value in res["prompt_config"].items():
126
+ new_key = key_mapping.get(key, key)
127
+ renamed_dict[new_key] = value
128
+ res["prompt"] = renamed_dict
129
+ del res["prompt_config"]
130
+ new_dict = {"similarity_threshold": res["similarity_threshold"],
131
+ "keywords_similarity_weight": res["vector_similarity_weight"],
132
+ "top_n": res["top_n"],
133
+ "rerank_model": res['rerank_id']}
134
+ res["prompt"].update(new_dict)
135
+ for key in key_list:
136
+ del res[key]
137
+ res["llm"] = res.pop("llm_setting")
138
+ res["llm"]["model_name"] = res.pop("llm_id")
139
+ del res["kb_ids"]
140
+ res["knowledgebases"] = req["knowledgebases"]
141
+ res["avatar"] = res.pop("icon")
142
+ return get_result(data=res)
143
+
144
+ @manager.route('/chat/<chat_id>', methods=['PUT'])
145
+ @token_required
146
+ def update(tenant_id,chat_id):
147
+ if not DialogService.query(tenant_id=tenant_id, id=chat_id, status=StatusEnum.VALID.value):
148
+ return get_error_data_result(retmsg='You do not own the chat')
149
+ req =request.json
150
+ if "knowledgebases" in req:
151
+ if not req.get("knowledgebases"):
152
+ return get_error_data_result(retmsg="knowledgebases can't be empty value")
153
+ kb_list = []
154
+ for kb in req.get("knowledgebases"):
155
+ if not kb["id"]:
156
+ return get_error_data_result(retmsg="knowledgebase needs id")
157
+ if not KnowledgebaseService.query(id=kb["id"], tenant_id=tenant_id):
158
+ return get_error_data_result(retmsg="you do not own the knowledgebase")
159
+ # if not DocumentService.query(kb_id=kb["id"]):
160
+ # return get_error_data_result(retmsg="There is a invalid knowledgebase")
161
+ kb_list.append(kb["id"])
162
+ req["kb_ids"] = kb_list
163
+ llm = req.get("llm")
164
+ if llm:
165
+ if "model_name" in llm:
166
+ req["llm_id"] = llm.pop("model_name")
167
+ req["llm_setting"] = req.pop("llm")
168
+ e, tenant = TenantService.get_by_id(tenant_id)
169
+ if not e:
170
+ return get_error_data_result(retmsg="Tenant not found!")
171
+ # prompt
172
+ prompt = req.get("prompt")
173
+ key_mapping = {"parameters": "variables",
174
+ "prologue": "opener",
175
+ "quote": "show_quote",
176
+ "system": "prompt",
177
+ "rerank_id": "rerank_model",
178
+ "vector_similarity_weight": "keywords_similarity_weight"}
179
+ key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
180
+ if prompt:
181
+ for new_key, old_key in key_mapping.items():
182
+ if old_key in prompt:
183
+ prompt[new_key] = prompt.pop(old_key)
184
+ for key in key_list:
185
+ if key in prompt:
186
+ req[key] = prompt.pop(key)
187
+ req["prompt_config"] = req.pop("prompt")
188
+ e, res = DialogService.get_by_id(chat_id)
189
+ res = res.to_json()
190
+ if "llm_id" in req:
191
+ if not TenantLLMService.query(llm_name=req["llm_id"]):
192
+ return get_error_data_result(retmsg="the model_name does not exist.")
193
+ if "name" in req:
194
+ if not req.get("name"):
195
+ return get_error_data_result(retmsg="name is not empty.")
196
+ if req["name"].lower() != res["name"].lower() \
197
+ and len(
198
+ DialogService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value)) > 0:
199
+ return get_error_data_result(retmsg="Duplicated chat name in updating dataset.")
200
+ if "prompt_config" in req:
201
+ res["prompt_config"].update(req["prompt_config"])
202
+ for p in res["prompt_config"]["parameters"]:
203
+ if p["optional"]:
204
+ continue
205
+ if res["prompt_config"]["system"].find("{%s}" % p["key"]) < 0:
206
+ return get_error_data_result(retmsg="Parameter '{}' is not used".format(p["key"]))
207
+ if "llm_setting" in req:
208
+ res["llm_setting"].update(req["llm_setting"])
209
+ req["prompt_config"] = res["prompt_config"]
210
+ req["llm_setting"] = res["llm_setting"]
211
+ # avatar
212
+ if "avatar" in req:
213
+ req["icon"] = req.pop("avatar")
214
+ if "knowledgebases" in req:
215
+ req.pop("knowledgebases")
216
+ if not DialogService.update_by_id(chat_id, req):
217
+ return get_error_data_result(retmsg="Chat not found!")
218
+ return get_result()
219
+
220
+
221
+ @manager.route('/chat', methods=['DELETE'])
222
+ @token_required
223
+ def delete(tenant_id):
224
+ req = request.json
225
+ ids = req.get("ids")
226
+ if not ids:
227
+ return get_error_data_result(retmsg="ids are required")
228
+ for id in ids:
229
+ if not DialogService.query(tenant_id=tenant_id, id=id, status=StatusEnum.VALID.value):
230
+ return get_error_data_result(retmsg=f"You don't own the chat {id}")
231
+ temp_dict = {"status": StatusEnum.INVALID.value}
232
+ DialogService.update_by_id(id, temp_dict)
233
+ return get_result()
234
+
235
+ @manager.route('/chat', methods=['GET'])
236
+ @token_required
237
+ def list(tenant_id):
238
+ id = request.args.get("id")
239
+ name = request.args.get("name")
240
+ chat = DialogService.query(id=id,name=name,status=StatusEnum.VALID.value)
241
+ if not chat:
242
+ return get_error_data_result(retmsg="The chat doesn't exist")
243
+ page_number = int(request.args.get("page", 1))
244
+ items_per_page = int(request.args.get("page_size", 1024))
245
+ orderby = request.args.get("orderby", "create_time")
246
+ if request.args.get("desc") == "False":
247
+ desc = False
248
+ else:
249
+ desc = True
250
+ chats = DialogService.get_list(tenant_id,page_number,items_per_page,orderby,desc,id,name)
251
+ if not chats:
252
+ return get_result(data=[])
253
+ list_assts = []
254
+ renamed_dict = {}
255
+ key_mapping = {"parameters": "variables",
256
+ "prologue": "opener",
257
+ "quote": "show_quote",
258
+ "system": "prompt",
259
+ "rerank_id": "rerank_model",
260
+ "vector_similarity_weight": "keywords_similarity_weight"}
261
+ key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
262
+ for res in chats:
263
+ for key, value in res["prompt_config"].items():
264
+ new_key = key_mapping.get(key, key)
265
+ renamed_dict[new_key] = value
266
+ res["prompt"] = renamed_dict
267
+ del res["prompt_config"]
268
+ new_dict = {"similarity_threshold": res["similarity_threshold"],
269
+ "keywords_similarity_weight": res["vector_similarity_weight"],
270
+ "top_n": res["top_n"],
271
+ "rerank_model": res['rerank_id']}
272
+ res["prompt"].update(new_dict)
273
+ for key in key_list:
274
+ del res[key]
275
+ res["llm"] = res.pop("llm_setting")
276
+ res["llm"]["model_name"] = res.pop("llm_id")
277
+ kb_list = []
278
+ for kb_id in res["kb_ids"]:
279
+ kb = KnowledgebaseService.query(id=kb_id)
280
+ if not kb :
281
+ return get_error_data_result(retmsg=f"Don't exist the kb {kb_id}")
282
+ kb_list.append(kb[0].to_json())
283
+ del res["kb_ids"]
284
+ res["knowledgebases"] = kb_list
285
+ res["avatar"] = res.pop("icon")
286
+ list_assts.append(res)
287
+ return get_result(data=list_assts)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
api/apps/sdk/dataset.py CHANGED
@@ -73,35 +73,24 @@ def create(tenant_id):
73
  @token_required
74
  def delete(tenant_id):
75
  req = request.json
76
- names=req.get("names")
77
  ids = req.get("ids")
78
- if not ids and not names:
79
  return get_error_data_result(
80
- retmsg="ids or names is required")
81
- id_list=[]
82
- if names:
83
- for name in names:
84
- kbs=KnowledgebaseService.query(name=name,tenant_id=tenant_id)
85
- if not kbs:
86
- return get_error_data_result(retmsg=f"You don't own the dataset {name}")
87
- id_list.append(kbs[0].id)
88
- if ids:
89
- for id in ids:
90
- kbs=KnowledgebaseService.query(id=id,tenant_id=tenant_id)
91
- if not kbs:
92
- return get_error_data_result(retmsg=f"You don't own the dataset {id}")
93
- id_list.extend(ids)
94
- for id in id_list:
95
- for doc in DocumentService.query(kb_id=id):
96
- if not DocumentService.remove_document(doc, tenant_id):
97
- return get_error_data_result(
98
- retmsg="Remove document error.(Database error)")
99
- f2d = File2DocumentService.get_by_document_id(doc.id)
100
- FileService.filter_delete([File.source_type == FileSource.KNOWLEDGEBASE, File.id == f2d[0].file_id])
101
- File2DocumentService.delete_by_document_id(doc.id)
102
- if not KnowledgebaseService.delete_by_id(id):
103
  return get_error_data_result(
104
- retmsg="Delete dataset error.(Database serror)")
 
 
 
 
 
 
105
  return get_result(retcode=RetCode.SUCCESS)
106
 
107
  @manager.route('/dataset/<dataset_id>', methods=['PUT'])
@@ -161,7 +150,10 @@ def list(tenant_id):
161
  page_number = int(request.args.get("page", 1))
162
  items_per_page = int(request.args.get("page_size", 1024))
163
  orderby = request.args.get("orderby", "create_time")
164
- desc = bool(request.args.get("desc", True))
 
 
 
165
  tenants = TenantService.get_joined_tenants_by_user_id(tenant_id)
166
  kbs = KnowledgebaseService.get_list(
167
  [m["tenant_id"] for m in tenants], tenant_id, page_number, items_per_page, orderby, desc, id, name)
 
73
  @token_required
74
  def delete(tenant_id):
75
  req = request.json
 
76
  ids = req.get("ids")
77
+ if not ids:
78
  return get_error_data_result(
79
+ retmsg="ids are required")
80
+ for id in ids:
81
+ kbs = KnowledgebaseService.query(id=id, tenant_id=tenant_id)
82
+ if not kbs:
83
+ return get_error_data_result(retmsg=f"You don't own the dataset {id}")
84
+ for doc in DocumentService.query(kb_id=id):
85
+ if not DocumentService.remove_document(doc, tenant_id):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  return get_error_data_result(
87
+ retmsg="Remove document error.(Database error)")
88
+ f2d = File2DocumentService.get_by_document_id(doc.id)
89
+ FileService.filter_delete([File.source_type == FileSource.KNOWLEDGEBASE, File.id == f2d[0].file_id])
90
+ File2DocumentService.delete_by_document_id(doc.id)
91
+ if not KnowledgebaseService.delete_by_id(id):
92
+ return get_error_data_result(
93
+ retmsg="Delete dataset error.(Database serror)")
94
  return get_result(retcode=RetCode.SUCCESS)
95
 
96
  @manager.route('/dataset/<dataset_id>', methods=['PUT'])
 
150
  page_number = int(request.args.get("page", 1))
151
  items_per_page = int(request.args.get("page_size", 1024))
152
  orderby = request.args.get("orderby", "create_time")
153
+ if request.args.get("desc") == "False":
154
+ desc = False
155
+ else:
156
+ desc = True
157
  tenants = TenantService.get_joined_tenants_by_user_id(tenant_id)
158
  kbs = KnowledgebaseService.get_list(
159
  [m["tenant_id"] for m in tenants], tenant_id, page_number, items_per_page, orderby, desc, id, name)
api/db/services/dialog_service.py CHANGED
@@ -19,8 +19,8 @@ import json
19
  import re
20
  from copy import deepcopy
21
  from timeit import default_timer as timer
22
- from api.db import LLMType, ParserType
23
- from api.db.db_models import Dialog, Conversation
24
  from api.db.services.common_service import CommonService
25
  from api.db.services.knowledgebase_service import KnowledgebaseService
26
  from api.db.services.llm_service import LLMService, TenantLLMService, LLMBundle
@@ -35,6 +35,28 @@ from api.utils.file_utils import get_project_base_directory
35
  class DialogService(CommonService):
36
  model = Dialog
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  class ConversationService(CommonService):
40
  model = Conversation
@@ -85,7 +107,7 @@ def llm_id2llm_type(llm_id):
85
  for llm in llm_factory["llm"]:
86
  if llm_id == llm["llm_name"]:
87
  return llm["model_type"].strip(",")[-1]
88
-
89
 
90
  def chat(dialog, messages, stream=True, **kwargs):
91
  assert messages[-1]["role"] == "user", "The last content of this conversation is not from user."
 
19
  import re
20
  from copy import deepcopy
21
  from timeit import default_timer as timer
22
+ from api.db import LLMType, ParserType,StatusEnum
23
+ from api.db.db_models import Dialog, Conversation,DB
24
  from api.db.services.common_service import CommonService
25
  from api.db.services.knowledgebase_service import KnowledgebaseService
26
  from api.db.services.llm_service import LLMService, TenantLLMService, LLMBundle
 
35
  class DialogService(CommonService):
36
  model = Dialog
37
 
38
+ @classmethod
39
+ @DB.connection_context()
40
+ def get_list(cls, tenant_id,
41
+ page_number, items_per_page, orderby, desc, id , name):
42
+ chats = cls.model.select()
43
+ if id:
44
+ chats = chats.where(cls.model.id == id)
45
+ if name:
46
+ chats = chats.where(cls.model.name == name)
47
+ chats = chats.where(
48
+ (cls.model.tenant_id == tenant_id)
49
+ & (cls.model.status == StatusEnum.VALID.value)
50
+ )
51
+ if desc:
52
+ chats = chats.order_by(cls.model.getter_by(orderby).desc())
53
+ else:
54
+ chats = chats.order_by(cls.model.getter_by(orderby).asc())
55
+
56
+ chats = chats.paginate(page_number, items_per_page)
57
+
58
+ return list(chats.dicts())
59
+
60
 
61
  class ConversationService(CommonService):
62
  model = Conversation
 
107
  for llm in llm_factory["llm"]:
108
  if llm_id == llm["llm_name"]:
109
  return llm["model_type"].strip(",")[-1]
110
+
111
 
112
  def chat(dialog, messages, stream=True, **kwargs):
113
  assert messages[-1]["role"] == "user", "The last content of this conversation is not from user."
api/http_api.md CHANGED
@@ -149,11 +149,11 @@ The error response includes a JSON object like the following:
149
  }
150
  ```
151
 
152
- ## Delete dataset
153
 
154
  **DELETE** `/api/v1/dataset`
155
 
156
- Deletes datasets by ids or names.
157
 
158
  ### Request
159
 
@@ -163,7 +163,6 @@ Deletes datasets by ids or names.
163
  - `content-Type: application/json`
164
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
165
  - Body:
166
- - `"names"`: `List[string]`
167
  - `"ids"`: `List[string]`
168
 
169
 
@@ -176,18 +175,15 @@ curl --request DELETE \
176
  --header 'Content-Type: application/json' \
177
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' \
178
  --data '{
179
- "names": ["test_1", "test_2"]
180
  }'
181
  ```
182
 
183
  #### Request parameters
184
 
185
- - `"names"`: (*Body parameter*)
186
- Dataset names to delete.
187
  - `"ids"`: (*Body parameter*)
188
  Dataset IDs to delete.
189
 
190
- `"names"` and `"ids"` are exclusive.
191
 
192
  ### Response
193
 
@@ -318,7 +314,7 @@ curl --request GET \
318
  A boolean flag indicating whether the sorting should be in descending order.
319
  - `name`: (*Path parameter*)
320
  Dataset name
321
- - - `"id"`: (*Path parameter*)
322
  The ID of the dataset to be retrieved.
323
  - `"name"`: (*Path parameter*)
324
  The name of the dataset to be retrieved.
@@ -996,10 +992,18 @@ Create a chat
996
  ### Request
997
 
998
  - Method: POST
999
- - URL: `/api/v1/chat`
1000
  - Headers:
1001
  - `content-Type: application/json`
1002
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
 
 
 
 
 
 
 
 
1003
 
1004
  #### Request example
1005
 
@@ -1009,135 +1013,424 @@ curl --request POST \
1009
  --header 'Content-Type: application/json' \
1010
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1011
  --data-binary '{
1012
- "avatar": "path",
1013
- "create_date": "Wed, 04 Sep 2024 10:08:01 GMT",
1014
- "create_time": 1725444481128,
1015
- "description": "A helpful Assistant",
1016
- "do_refer": "",
1017
- "knowledgebases": [
1018
- {
1019
- "avatar": null,
1020
- "chunk_count": 0,
1021
- "description": null,
1022
- "document_count": 0,
1023
- "embedding_model": "",
1024
- "id": "d6d0e8e868cd11ef92250242ac120006",
1025
- "language": "English",
1026
- "name": "Test_assistant",
1027
- "parse_method": "naive",
1028
- "parser_config": {
1029
- "pages": [
1030
- [
1031
- 1,
1032
- 1000000
1033
- ]
1034
- ]
1035
- },
1036
- "permission": "me",
1037
- "tenant_id": "4fb0cd625f9311efba4a0242ac120006"
1038
- }
1039
- ],
1040
- "language": "English",
1041
- "llm": {
1042
- "frequency_penalty": 0.7,
1043
- "max_tokens": 512,
1044
- "model_name": "deepseek-chat",
1045
- "presence_penalty": 0.4,
1046
- "temperature": 0.1,
1047
- "top_p": 0.3
1048
- },
1049
- "name": "Miss R",
1050
- "prompt": {
1051
- "empty_response": "Sorry! Can't find the context!",
1052
- "keywords_similarity_weight": 0.7,
1053
- "opener": "Hi! I am your assistant, what can I do for you?",
1054
- "prompt": "You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence 'The answer you are looking for is not found in the knowledge base!' Answers need to consider chat history.\nHere is the knowledge base:\n{knowledge}\nThe above is the knowledge base.",
1055
- "rerank_model": "",
1056
- "show_quote": true,
1057
- "similarity_threshold": 0.2,
1058
- "top_n": 8,
1059
- "variables": [
1060
- {
1061
- "key": "knowledge",
1062
- "optional": true
1063
- }
1064
- ]
1065
- },
1066
- "prompt_type": "simple",
1067
- "status": "1",
1068
- "top_k": 1024,
1069
- "update_date": "Wed, 04 Sep 2024 10:08:01 GMT",
1070
- "update_time": 1725444481128
1071
  }'
1072
  ```
1073
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1074
  ## Update chat
1075
 
1076
- **PUT** `/api/v1/chat`
1077
 
1078
  Update a chat
1079
 
1080
  ### Request
1081
 
1082
  - Method: PUT
1083
- - URL: `/api/v1/chat`
1084
  - Headers:
1085
  - `content-Type: application/json`
1086
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1087
-
 
1088
  #### Request example
1089
-
1090
  curl --request PUT \
1091
- --url http://{address}/api/v1/chat \
1092
  --header 'Content-Type: application/json' \
1093
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' \
1094
- --data-binary '{
1095
- "id":"554e96746aaa11efb06b0242ac120005",
1096
  "name":"Test"
1097
  }'
 
 
 
1098
 
1099
- ## Delete chat
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
 
1101
- **DELETE** `/api/v1/chat/{chat_id}`
1102
 
1103
- Delete a chat
1104
 
1105
  ### Request
1106
 
1107
- - Method: PUT
1108
- - URL: `/api/v1/chat/{chat_id}`
1109
  - Headers:
1110
  - `content-Type: application/json`
1111
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1112
-
 
1113
  #### Request example
1114
-
1115
- curl --request PUT \
1116
- --url http://{address}/api/v1/chat/554e96746aaa11efb06b0242ac120005 \
 
1117
  --header 'Content-Type: application/json' \
1118
- --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
 
 
 
1119
  }'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1120
 
1121
- ## List chat
1122
 
1123
- **GET** `/api/v1/chat`
1124
 
1125
- List all chat assistants
1126
 
1127
  ### Request
1128
 
1129
  - Method: GET
1130
- - URL: `/api/v1/chat`
1131
  - Headers:
1132
- - `content-Type: application/json`
1133
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1134
 
1135
  #### Request example
1136
 
 
1137
  curl --request GET \
1138
- --url http://{address}/api/v1/chat \
1139
- --header 'Content-Type: application/json' \
1140
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1141
 
1142
  ## Create a chat session
1143
 
 
149
  }
150
  ```
151
 
152
+ ## Delete datasets
153
 
154
  **DELETE** `/api/v1/dataset`
155
 
156
+ Deletes datasets by ids.
157
 
158
  ### Request
159
 
 
163
  - `content-Type: application/json`
164
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
165
  - Body:
 
166
  - `"ids"`: `List[string]`
167
 
168
 
 
175
  --header 'Content-Type: application/json' \
176
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' \
177
  --data '{
178
+ "ids": ["test_1", "test_2"]
179
  }'
180
  ```
181
 
182
  #### Request parameters
183
 
 
 
184
  - `"ids"`: (*Body parameter*)
185
  Dataset IDs to delete.
186
 
 
187
 
188
  ### Response
189
 
 
314
  A boolean flag indicating whether the sorting should be in descending order.
315
  - `name`: (*Path parameter*)
316
  Dataset name
317
+ - `"id"`: (*Path parameter*)
318
  The ID of the dataset to be retrieved.
319
  - `"name"`: (*Path parameter*)
320
  The name of the dataset to be retrieved.
 
992
  ### Request
993
 
994
  - Method: POST
995
+ - URL: `http://{address}/api/v1/chat`
996
  - Headers:
997
  - `content-Type: application/json`
998
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
999
+ - Body:
1000
+ - `"name"`: `string`
1001
+ - `"avatar"`: `string`
1002
+ - `"knowledgebases"`: `List[DataSet]`
1003
+ - `"id"`: `string`
1004
+ - `"llm"`: `LLM`
1005
+ - `"prompt"`: `Prompt`
1006
+
1007
 
1008
  #### Request example
1009
 
 
1013
  --header 'Content-Type: application/json' \
1014
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1015
  --data-binary '{
1016
+ "knowledgebases": [
1017
+ {
1018
+ "avatar": null,
1019
+ "chunk_count": 0,
1020
+ "description": null,
1021
+ "document_count": 0,
1022
+ "embedding_model": "",
1023
+ "id": "0b2cbc8c877f11ef89070242ac120005",
1024
+ "language": "English",
1025
+ "name": "Test_assistant",
1026
+ "parse_method": "naive",
1027
+ "parser_config": {
1028
+ "pages": [
1029
+ [
1030
+ 1,
1031
+ 1000000
1032
+ ]
1033
+ ]
1034
+ },
1035
+ "permission": "me",
1036
+ "tenant_id": "4fb0cd625f9311efba4a0242ac120006"
1037
+ }
1038
+ ],
1039
+ "name":"new_chat_1"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  }'
1041
  ```
1042
 
1043
+ #### Request parameters
1044
+
1045
+ - `"name"`: (*Body parameter*)
1046
+ The name of the created chat.
1047
+ - `"assistant"`
1048
+
1049
+ - `"avatar"`: (*Body parameter*)
1050
+ The icon of the created chat.
1051
+ - `"path"`
1052
+
1053
+ - `"knowledgebases"`: (*Body parameter*)
1054
+ Select knowledgebases associated.
1055
+ - `["kb1"]`
1056
+
1057
+ - `"id"`: (*Body parameter*)
1058
+ The id of the created chat.
1059
+ - `""`
1060
+
1061
+ - `"llm"`: (*Body parameter*)
1062
+ The LLM of the created chat.
1063
+ - If the value is `None`, a dictionary with default values will be generated.
1064
+
1065
+ - `"prompt"`: (*Body parameter*)
1066
+ The prompt of the created chat.
1067
+ - If the value is `None`, a dictionary with default values will be generated.
1068
+
1069
+ ---
1070
+
1071
+ ##### Chat.LLM parameters:
1072
+
1073
+ - `"model_name"`: (*Body parameter*)
1074
+ Large language chat model.
1075
+ - If it is `None`, it will return the user's default model.
1076
+
1077
+ - `"temperature"`: (*Body parameter*)
1078
+ Controls the randomness of predictions by the model. A lower temperature makes the model more confident, while a higher temperature makes it more creative and diverse.
1079
+ - `0.1`
1080
+
1081
+ - `"top_p"`: (*Body parameter*)
1082
+ Also known as "nucleus sampling," it focuses on the most likely words, cutting off the less probable ones.
1083
+ - `0.3`
1084
+
1085
+ - `"presence_penalty"`: (*Body parameter*)
1086
+ Discourages the model from repeating the same information by penalizing repeated content.
1087
+ - `0.4`
1088
+
1089
+ - `"frequency_penalty"`: (*Body parameter*)
1090
+ Reduces the model’s tendency to repeat words frequently.
1091
+ - `0.7`
1092
+
1093
+ - `"max_tokens"`: (*Body parameter*)
1094
+ Sets the maximum length of the model’s output, measured in tokens (words or pieces of words).
1095
+ - `512`
1096
+
1097
+ ---
1098
+
1099
+ ##### Chat.Prompt parameters:
1100
+
1101
+ - `"similarity_threshold"`: (*Body parameter*)
1102
+ Filters out chunks with similarity below this threshold.
1103
+ - `0.2`
1104
+
1105
+ - `"keywords_similarity_weight"`: (*Body parameter*)
1106
+ Weighted keywords similarity and vector cosine similarity; the sum of weights is 1.0.
1107
+ - `0.7`
1108
+
1109
+ - `"top_n"`: (*Body parameter*)
1110
+ Only the top N chunks above the similarity threshold will be fed to LLMs.
1111
+ - `8`
1112
+
1113
+ - `"variables"`: (*Body parameter*)
1114
+ Variables help with different chat strategies by filling in the 'System' part of the prompt.
1115
+ - `[{"key": "knowledge", "optional": True}]`
1116
+
1117
+ - `"rerank_model"`: (*Body parameter*)
1118
+ If empty, it uses vector cosine similarity; otherwise, it uses rerank score.
1119
+ - `""`
1120
+
1121
+ - `"empty_response"`: (*Body parameter*)
1122
+ If nothing is retrieved, this will be used as the response. Leave blank if LLM should provide its own opinion.
1123
+ - `None`
1124
+
1125
+ - `"opener"`: (*Body parameter*)
1126
+ The welcome message for clients.
1127
+ - `"Hi! I'm your assistant, what can I do for you?"`
1128
+
1129
+ - `"show_quote"`: (*Body parameter*)
1130
+ Indicates whether the source of the original text should be displayed.
1131
+ - `True`
1132
+
1133
+ - `"prompt"`: (*Body parameter*)
1134
+ Instructions for LLM to follow when answering questions, such as character design or answer length.
1135
+ - `"You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence 'The answer you are looking for is not found in the knowledge base!' Answers need to consider chat history. Here is the knowledge base: {knowledge} The above is the knowledge base."`
1136
+ ### Response
1137
+ Success:
1138
+ ```json
1139
+ {
1140
+ "code": 0,
1141
+ "data": {
1142
+ "avatar": "",
1143
+ "create_date": "Fri, 11 Oct 2024 03:23:24 GMT",
1144
+ "create_time": 1728617004635,
1145
+ "description": "A helpful Assistant",
1146
+ "do_refer": "1",
1147
+ "id": "2ca4b22e878011ef88fe0242ac120005",
1148
+ "knowledgebases": [
1149
+ {
1150
+ "avatar": null,
1151
+ "chunk_count": 0,
1152
+ "description": null,
1153
+ "document_count": 0,
1154
+ "embedding_model": "",
1155
+ "id": "0b2cbc8c877f11ef89070242ac120005",
1156
+ "language": "English",
1157
+ "name": "Test_assistant",
1158
+ "parse_method": "naive",
1159
+ "parser_config": {
1160
+ "pages": [
1161
+ [
1162
+ 1,
1163
+ 1000000
1164
+ ]
1165
+ ]
1166
+ },
1167
+ "permission": "me",
1168
+ "tenant_id": "4fb0cd625f9311efba4a0242ac120006"
1169
+ }
1170
+ ],
1171
+ "language": "English",
1172
+ "llm": {
1173
+ "frequency_penalty": 0.7,
1174
+ "max_tokens": 512,
1175
+ "model_name": "deepseek-chat___OpenAI-API@OpenAI-API-Compatible",
1176
+ "presence_penalty": 0.4,
1177
+ "temperature": 0.1,
1178
+ "top_p": 0.3
1179
+ },
1180
+ "name": "new_chat_1",
1181
+ "prompt": {
1182
+ "empty_response": "Sorry! 知识库中未找到相关内容!",
1183
+ "keywords_similarity_weight": 0.3,
1184
+ "opener": "您好,我是您的助手小樱,长得可爱又善良,can I help you?",
1185
+ "prompt": "你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。\n 以下是知识库:\n {knowledge}\n 以上是知识库。",
1186
+ "rerank_model": "",
1187
+ "similarity_threshold": 0.2,
1188
+ "top_n": 6,
1189
+ "variables": [
1190
+ {
1191
+ "key": "knowledge",
1192
+ "optional": false
1193
+ }
1194
+ ]
1195
+ },
1196
+ "prompt_type": "simple",
1197
+ "status": "1",
1198
+ "tenant_id": "69736c5e723611efb51b0242ac120007",
1199
+ "top_k": 1024,
1200
+ "update_date": "Fri, 11 Oct 2024 03:23:24 GMT",
1201
+ "update_time": 1728617004635
1202
+ }
1203
+ }
1204
+ ```
1205
+ Error:
1206
+ ```json
1207
+ {
1208
+ "code": 102,
1209
+ "message": "Duplicated chat name in creating dataset."
1210
+ }
1211
+ ```
1212
+
1213
  ## Update chat
1214
 
1215
+ **PUT** `/api/v1/chat/{chat_id}`
1216
 
1217
  Update a chat
1218
 
1219
  ### Request
1220
 
1221
  - Method: PUT
1222
+ - URL: `http://{address}/api/v1/chat/{chat_id}`
1223
  - Headers:
1224
  - `content-Type: application/json`
1225
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1226
+ - Body: (Refer to the "Create chat" for the complete structure of the request body.)
1227
+
1228
  #### Request example
1229
+ ```bash
1230
  curl --request PUT \
1231
+ --url http://{address}/api/v1/chat/{chat_id} \
1232
  --header 'Content-Type: application/json' \
1233
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' \
1234
+ --data '{
 
1235
  "name":"Test"
1236
  }'
1237
+ ```
1238
+ #### Parameters
1239
+ (Refer to the "Create chat" for the complete structure of the request parameters.)
1240
 
1241
+ ### Response
1242
+ Success
1243
+ ```json
1244
+ {
1245
+ "code": 0
1246
+ }
1247
+ ```
1248
+ Error
1249
+ ```json
1250
+ {
1251
+ "code": 102,
1252
+ "message": "Duplicated chat name in updating dataset."
1253
+ }
1254
+ ```
1255
+
1256
+ ## Delete chats
1257
 
1258
+ **DELETE** `/api/v1/chat`
1259
 
1260
+ Delete chats
1261
 
1262
  ### Request
1263
 
1264
+ - Method: DELETE
1265
+ - URL: `http://{address}/api/v1/chat`
1266
  - Headers:
1267
  - `content-Type: application/json`
1268
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1269
+ - Body:
1270
+ - `ids`: List[string]
1271
  #### Request example
1272
+ ```bash
1273
+ # Either id or name must be provided, but not both.
1274
+ curl --request DELETE \
1275
+ --url http://{address}/api/v1/chat \
1276
  --header 'Content-Type: application/json' \
1277
+ --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' \
1278
+ --data '{
1279
+ "ids": ["test_1", "test_2"]
1280
+ }'
1281
  }'
1282
+ ```
1283
+ #### Request parameters:
1284
+
1285
+ - `"ids"`: (*Body parameter*)
1286
+ IDs of the chats to be deleted.
1287
+ - `None`
1288
+ ### Response
1289
+ Success
1290
+ ```json
1291
+ {
1292
+ "code": 0
1293
+ }
1294
+ ```
1295
+ Error
1296
+ ```json
1297
+ {
1298
+ "code": 102,
1299
+ "message": "ids are required"
1300
+ }
1301
+ ```
1302
 
1303
+ ## List chats
1304
 
1305
+ **GET** `/api/v1/chat?page={page}&page_size={page_size}&orderby={orderby}&desc={desc}&name={dataset_name}&id={dataset_id}`
1306
 
1307
+ List chats based on filter criteria.
1308
 
1309
  ### Request
1310
 
1311
  - Method: GET
1312
+ - URL: `http://{address}/api/v1/chat?page={page}&page_size={page_size}&orderby={orderby}&desc={desc}&name={dataset_name}&id={dataset_id}`
1313
  - Headers:
 
1314
  - 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1315
 
1316
  #### Request example
1317
 
1318
+ ```bash
1319
  curl --request GET \
1320
+ --url http://{address}/api/v1/chat?page={page}&page_size={page_size}&orderby={orderby}&desc={desc}&name={dataset_name}&id={dataset_id} \
 
1321
  --header 'Authorization: Bearer {YOUR_ACCESS_TOKEN}'
1322
+ ```
1323
+
1324
+ #### Request parameters
1325
+ - `"page"`: (*Path parameter*)
1326
+ The current page number to retrieve from the paginated data. This parameter determines which set of records will be fetched.
1327
+ - `1`
1328
+
1329
+ - `"page_size"`: (*Path parameter*)
1330
+ The number of records to retrieve per page. This controls how many records will be included in each page.
1331
+ - `1024`
1332
+
1333
+ - `"orderby"`: (*Path parameter*)
1334
+ The field by which the records should be sorted. This specifies the attribute or column used to order the results.
1335
+ - `"create_time"`
1336
+
1337
+ - `"desc"`: (*Path parameter*)
1338
+ A boolean flag indicating whether the sorting should be in descending order.
1339
+ - `True`
1340
+
1341
+ - `"id"`: (*Path parameter*)
1342
+ The ID of the chat to be retrieved.
1343
+ - `None`
1344
+
1345
+ - `"name"`: (*Path parameter*)
1346
+ The name of the chat to be retrieved.
1347
+ - `None`
1348
+
1349
+ ### Response
1350
+ Success
1351
+ ```json
1352
+ {
1353
+ "code": 0,
1354
+ "data": [
1355
+ {
1356
+ "avatar": "",
1357
+ "create_date": "Fri, 11 Oct 2024 03:23:24 GMT",
1358
+ "create_time": 1728617004635,
1359
+ "description": "A helpful Assistant",
1360
+ "do_refer": "1",
1361
+ "id": "2ca4b22e878011ef88fe0242ac120005",
1362
+ "knowledgebases": [
1363
+ {
1364
+ "avatar": "",
1365
+ "chunk_num": 0,
1366
+ "create_date": "Fri, 11 Oct 2024 03:15:18 GMT",
1367
+ "create_time": 1728616518986,
1368
+ "created_by": "69736c5e723611efb51b0242ac120007",
1369
+ "description": "",
1370
+ "doc_num": 0,
1371
+ "embd_id": "BAAI/bge-large-zh-v1.5",
1372
+ "id": "0b2cbc8c877f11ef89070242ac120005",
1373
+ "language": "English",
1374
+ "name": "test_delete_chat",
1375
+ "parser_config": {
1376
+ "chunk_token_count": 128,
1377
+ "delimiter": "\n!?。;!?",
1378
+ "layout_recognize": true,
1379
+ "task_page_size": 12
1380
+ },
1381
+ "parser_id": "naive",
1382
+ "permission": "me",
1383
+ "similarity_threshold": 0.2,
1384
+ "status": "1",
1385
+ "tenant_id": "69736c5e723611efb51b0242ac120007",
1386
+ "token_num": 0,
1387
+ "update_date": "Fri, 11 Oct 2024 04:01:31 GMT",
1388
+ "update_time": 1728619291228,
1389
+ "vector_similarity_weight": 0.3
1390
+ }
1391
+ ],
1392
+ "language": "English",
1393
+ "llm": {
1394
+ "frequency_penalty": 0.7,
1395
+ "max_tokens": 512,
1396
+ "model_name": "deepseek-chat___OpenAI-API@OpenAI-API-Compatible",
1397
+ "presence_penalty": 0.4,
1398
+ "temperature": 0.1,
1399
+ "top_p": 0.3
1400
+ },
1401
+ "name": "Test",
1402
+ "prompt": {
1403
+ "empty_response": "Sorry! 知识库中未找到相关内容!",
1404
+ "keywords_similarity_weight": 0.3,
1405
+ "opener": "您好,我是您的助手小樱,长得可爱又善良,can I help you?",
1406
+ "prompt": "你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。\n 以下是知识库:\n {knowledge}\n 以上是知识库。",
1407
+ "rerank_model": "",
1408
+ "similarity_threshold": 0.2,
1409
+ "top_n": 6,
1410
+ "variables": [
1411
+ {
1412
+ "key": "knowledge",
1413
+ "optional": false
1414
+ }
1415
+ ]
1416
+ },
1417
+ "prompt_type": "simple",
1418
+ "status": "1",
1419
+ "tenant_id": "69736c5e723611efb51b0242ac120007",
1420
+ "top_k": 1024,
1421
+ "update_date": "Fri, 11 Oct 2024 03:47:58 GMT",
1422
+ "update_time": 1728618478392
1423
+ }
1424
+ ]
1425
+ }
1426
+ ```
1427
+ Error
1428
+ ```json
1429
+ {
1430
+ "code": 102,
1431
+ "message": "The chat doesn't exist"
1432
+ }
1433
+ ```
1434
 
1435
  ## Create a chat session
1436
 
api/python_api_reference.md CHANGED
@@ -107,7 +107,7 @@ ds = rag.create_dataset(name="kb_1")
107
  ## Delete knowledge bases
108
 
109
  ```python
110
- RAGFlow.delete_dataset(ids: List[str] = None, names: List[str] = None)
111
  ```
112
  Deletes knowledge bases.
113
  ### Parameters
@@ -116,11 +116,7 @@ Deletes knowledge bases.
116
 
117
  The ids of the datasets to be deleted.
118
 
119
- #### names: `List[str]`
120
 
121
- The names of the datasets to be deleted.
122
-
123
- Either `ids` or `names` must be provided, but not both.
124
  ### Returns
125
 
126
  ```python
@@ -133,8 +129,7 @@ no return
133
  from ragflow import RAGFlow
134
 
135
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
136
- rag.delete_dataset(names=["name_1","name_2"])
137
- rag.delete_dataset(ids=["id_1","id_2"])
138
  ```
139
 
140
  ---
@@ -711,32 +706,35 @@ for c in rag.retrieval(question="What's ragflow?",
711
  ---
712
 
713
  :::tip API GROUPING
714
- Chat assistant APIs
715
  :::
716
 
717
- ## Create assistant
718
 
719
  ```python
720
- RAGFlow.create_assistant(
721
  name: str = "assistant",
722
  avatar: str = "path",
723
  knowledgebases: List[DataSet] = ["kb1"],
724
- llm: Assistant.LLM = None,
725
- prompt: Assistant.Prompt = None
726
- ) -> Assistant
 
727
  ```
728
 
729
  ### Returns
730
 
731
- Assistant object.
 
 
732
 
733
  #### name: `str`
734
 
735
- The name of the created assistant. Defaults to `"assistant"`.
736
 
737
  #### avatar: `str`
738
 
739
- The icon of the created assistant. Defaults to `"path"`.
740
 
741
  #### knowledgebases: `List[DataSet]`
742
 
@@ -744,11 +742,11 @@ Select knowledgebases associated. Defaults to `["kb1"]`.
744
 
745
  #### id: `str`
746
 
747
- The id of the created assistant. Defaults to `""`.
748
 
749
  #### llm: `LLM`
750
 
751
- The llm of the created assistant. Defaults to `None`. When the value is `None`, a dictionary with the following values will be generated as the default.
752
 
753
  - **model_name**, `str`
754
  Large language chat model. If it is `None`, it will return the user's default model.
@@ -782,22 +780,21 @@ from ragflow import RAGFlow
782
 
783
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
784
  kb = rag.get_dataset(name="kb_1")
785
- assi = rag.create_assistant("Miss R", knowledgebases=[kb])
786
  ```
787
 
788
  ---
789
 
790
- ## Save updates to a chat assistant
791
 
792
  ```python
793
- Assistant.save() -> bool
794
  ```
795
 
796
  ### Returns
797
 
798
  ```python
799
- bool
800
- description:the case of updating an assistant, True or False.
801
  ```
802
 
803
  ### Examples
@@ -807,24 +804,28 @@ from ragflow import RAGFlow
807
 
808
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
809
  kb = rag.get_knowledgebase(name="kb_1")
810
- assi = rag.create_assistant("Miss R", knowledgebases=[kb])
811
- assi.llm.temperature = 0.8
812
- assi.save()
813
  ```
814
 
815
  ---
816
 
817
- ## Delete assistant
818
 
819
  ```python
820
- Assistant.delete() -> bool
821
  ```
 
 
 
 
 
 
822
 
823
  ### Returns
824
 
825
  ```python
826
- bool
827
- description:the case of deleting an assistant, True or False.
828
  ```
829
 
830
  ### Examples
@@ -833,98 +834,58 @@ description:the case of deleting an assistant, True or False.
833
  from ragflow import RAGFlow
834
 
835
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
836
- kb = rag.get_knowledgebase(name="kb_1")
837
- assi = rag.create_assistant("Miss R", knowledgebases=[kb])
838
- assi.delete()
839
  ```
840
 
841
  ---
842
 
843
- ## Retrieve assistant
844
 
845
  ```python
846
- RAGFlow.get_assistant(id: str = None, name: str = None) -> Assistant
 
 
 
 
 
 
 
847
  ```
848
 
849
  ### Parameters
850
 
851
- #### id: `str`
852
-
853
- ID of the assistant to retrieve. If `name` is not provided, `id` is required.
854
-
855
- #### name: `str`
856
-
857
- Name of the assistant to retrieve. If `id` is not provided, `name` is required.
858
-
859
- ### Returns
860
-
861
- Assistant object.
862
-
863
- #### name: `str`
864
-
865
- The name of the created assistant. Defaults to `"assistant"`.
866
-
867
- #### avatar: `str`
868
-
869
- The icon of the created assistant. Defaults to `"path"`.
870
-
871
- #### knowledgebases: `List[DataSet]`
872
-
873
- Select knowledgebases associated. Defaults to `["kb1"]`.
874
-
875
- #### id: `str`
876
-
877
- The id of the created assistant. Defaults to `""`.
878
-
879
- #### llm: `LLM`
880
 
881
- The llm of the created assistant. Defaults to `None`. When the value is `None`, a dictionary with the following values will be generated as the default.
882
-
883
- - **model_name**, `str`
884
- Large language chat model. If it is `None`, it will return the user's default model.
885
- - **temperature**, `float`
886
- This parameter controls the randomness of predictions by the model. A lower temperature makes the model more confident in its responses, while a higher temperature makes it more creative and diverse. Defaults to `0.1`.
887
- - **top_p**, `float`
888
- Also known as “nucleus sampling,” this parameter sets a threshold to select a smaller set of words to sample from. It focuses on the most likely words, cutting off the less probable ones. Defaults to `0.3`
889
- - **presence_penalty**, `float`
890
- This discourages the model from repeating the same information by penalizing words that have already appeared in the conversation. Defaults to `0.2`.
891
- - **frequency penalty**, `float`
892
- Similar to the presence penalty, this reduces the model’s tendency to repeat the same words frequently. Defaults to `0.7`.
893
- - **max_token**, `int`
894
- This sets the maximum length of the model’s output, measured in the number of tokens (words or pieces of words). Defaults to `512`.
895
 
896
- #### Prompt: `str`
897
 
898
- Instructions you need LLM to follow when LLM answers questions, like character design, answer length and answer language etc.
 
899
 
900
- Defaults:
901
- ```
902
- You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence "The answer you are looking for is not found in the knowledge base!" Answers need to consider chat history.
903
- Here is the knowledge base:
904
- {knowledge}
905
- The above is the knowledge base.
906
- ```
907
 
908
- ### Examples
 
909
 
910
- ```python
911
- from ragflow import RAGFlow
912
 
913
- rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
914
- assi = rag.get_assistant(name="Miss R")
915
- ```
916
 
917
- ---
918
 
919
- ## List assistants
 
920
 
921
- ```python
922
- RAGFlow.list_assistants() -> List[Assistant]
923
- ```
924
 
 
 
925
  ### Returns
926
 
927
- A list of assistant objects.
928
 
929
  ### Examples
930
 
@@ -932,7 +893,7 @@ A list of assistant objects.
932
  from ragflow import RAGFlow
933
 
934
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
935
- for assi in rag.list_assistants():
936
  print(assi)
937
  ```
938
 
 
107
  ## Delete knowledge bases
108
 
109
  ```python
110
+ RAGFlow.delete_datasets(ids: List[str] = None)
111
  ```
112
  Deletes knowledge bases.
113
  ### Parameters
 
116
 
117
  The ids of the datasets to be deleted.
118
 
 
119
 
 
 
 
120
  ### Returns
121
 
122
  ```python
 
129
  from ragflow import RAGFlow
130
 
131
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
132
+ rag.delete_datasets(ids=["id_1","id_2"])
 
133
  ```
134
 
135
  ---
 
706
  ---
707
 
708
  :::tip API GROUPING
709
+ Chat APIs
710
  :::
711
 
712
+ ## Create chat
713
 
714
  ```python
715
+ RAGFlow.create_chat(
716
  name: str = "assistant",
717
  avatar: str = "path",
718
  knowledgebases: List[DataSet] = ["kb1"],
719
+ llm: Chat.LLM = None,
720
+ prompt: Chat.Prompt = None
721
+ ) -> Chat
722
+
723
  ```
724
 
725
  ### Returns
726
 
727
+ Chat
728
+
729
+ description: assitant object.
730
 
731
  #### name: `str`
732
 
733
+ The name of the created chat. Defaults to `"assistant"`.
734
 
735
  #### avatar: `str`
736
 
737
+ The icon of the created chat. Defaults to `"path"`.
738
 
739
  #### knowledgebases: `List[DataSet]`
740
 
 
742
 
743
  #### id: `str`
744
 
745
+ The id of the created chat. Defaults to `""`.
746
 
747
  #### llm: `LLM`
748
 
749
+ The llm of the created chat. Defaults to `None`. When the value is `None`, a dictionary with the following values will be generated as the default.
750
 
751
  - **model_name**, `str`
752
  Large language chat model. If it is `None`, it will return the user's default model.
 
780
 
781
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
782
  kb = rag.get_dataset(name="kb_1")
783
+ assi = rag.create_chat("Miss R", knowledgebases=[kb])
784
  ```
785
 
786
  ---
787
 
788
+ ## Update chat
789
 
790
  ```python
791
+ Chat.update(update_message: dict)
792
  ```
793
 
794
  ### Returns
795
 
796
  ```python
797
+ no return
 
798
  ```
799
 
800
  ### Examples
 
804
 
805
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
806
  kb = rag.get_knowledgebase(name="kb_1")
807
+ assi = rag.create_chat("Miss R", knowledgebases=[kb])
808
+ assi.update({"temperature":0.8})
 
809
  ```
810
 
811
  ---
812
 
813
+ ## Delete chats
814
 
815
  ```python
816
+ RAGFlow.delete_chats(ids: List[str] = None)
817
  ```
818
+ ### Parameters
819
+
820
+ #### ids: `str`
821
+
822
+ IDs of the chats to be deleted.
823
+
824
 
825
  ### Returns
826
 
827
  ```python
828
+ no return
 
829
  ```
830
 
831
  ### Examples
 
834
  from ragflow import RAGFlow
835
 
836
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
837
+ rag.delete_chats(ids=["id_1","id_2"])
 
 
838
  ```
839
 
840
  ---
841
 
842
+ ## List chats
843
 
844
  ```python
845
+ RAGFlow.list_chats(
846
+ page: int = 1,
847
+ page_size: int = 1024,
848
+ orderby: str = "create_time",
849
+ desc: bool = True,
850
+ id: str = None,
851
+ name: str = None
852
+ ) -> List[Chat]
853
  ```
854
 
855
  ### Parameters
856
 
857
+ #### page: `int`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
858
 
859
+ The current page number to retrieve from the paginated data. This parameter determines which set of records will be fetched.
860
+ - `1`
 
 
 
 
 
 
 
 
 
 
 
 
861
 
862
+ #### page_size: `int`
863
 
864
+ The number of records to retrieve per page. This controls how many records will be included in each page.
865
+ - `1024`
866
 
867
+ #### orderby: `string`
 
 
 
 
 
 
868
 
869
+ The field by which the records should be sorted. This specifies the attribute or column used to order the results.
870
+ - `"create_time"`
871
 
872
+ #### desc: `bool`
 
873
 
874
+ A boolean flag indicating whether the sorting should be in descending order.
875
+ - `True`
 
876
 
877
+ #### id: `string`
878
 
879
+ The ID of the chat to be retrieved.
880
+ - `None`
881
 
882
+ #### name: `string`
 
 
883
 
884
+ The name of the chat to be retrieved.
885
+ - `None`
886
  ### Returns
887
 
888
+ A list of chat objects.
889
 
890
  ### Examples
891
 
 
893
  from ragflow import RAGFlow
894
 
895
  rag = RAGFlow(api_key="xxxxxx", base_url="http://xxx.xx.xx.xxx:9380")
896
+ for assi in rag.list_chats():
897
  print(assi)
898
  ```
899
 
api/utils/api_utils.py CHANGED
@@ -279,8 +279,8 @@ def get_result(retcode=RetCode.SUCCESS, retmsg='error', data=None):
279
  response = {"code": retcode, "message": retmsg}
280
  return jsonify(response)
281
 
282
- def get_error_data_result(retcode=RetCode.DATA_ERROR,
283
- retmsg='Sorry! Data missing!'):
284
  import re
285
  result_dict = {
286
  "code": retcode,
@@ -295,5 +295,4 @@ def get_error_data_result(retcode=RetCode.DATA_ERROR,
295
  continue
296
  else:
297
  response[key] = value
298
- return jsonify(response)
299
-
 
279
  response = {"code": retcode, "message": retmsg}
280
  return jsonify(response)
281
 
282
+ def get_error_data_result(retmsg='Sorry! Data missing!',retcode=RetCode.DATA_ERROR,
283
+ ):
284
  import re
285
  result_dict = {
286
  "code": retcode,
 
295
  continue
296
  else:
297
  response[key] = value
298
+ return jsonify(response)
 
sdk/python/ragflow/__init__.py CHANGED
@@ -4,7 +4,7 @@ __version__ = importlib.metadata.version("ragflow")
4
 
5
  from .ragflow import RAGFlow
6
  from .modules.dataset import DataSet
7
- from .modules.assistant import Assistant
8
  from .modules.session import Session
9
  from .modules.document import Document
10
  from .modules.chunk import Chunk
 
4
 
5
  from .ragflow import RAGFlow
6
  from .modules.dataset import DataSet
7
+ from .modules.chat import Chat
8
  from .modules.session import Session
9
  from .modules.document import Document
10
  from .modules.chunk import Chunk
sdk/python/ragflow/modules/base.py CHANGED
@@ -18,16 +18,16 @@ class Base(object):
18
  pr[name] = value
19
  return pr
20
 
21
- def post(self, path, param, stream=False):
22
- res = self.rag.post(path, param, stream=stream)
23
  return res
24
 
25
  def get(self, path, params):
26
  res = self.rag.get(path, params)
27
  return res
28
 
29
- def rm(self, path, params):
30
- res = self.rag.delete(path, params)
31
  return res
32
 
33
  def put(self,path, json):
 
18
  pr[name] = value
19
  return pr
20
 
21
+ def post(self, path, json, stream=False):
22
+ res = self.rag.post(path, json, stream=stream)
23
  return res
24
 
25
  def get(self, path, params):
26
  res = self.rag.get(path, params)
27
  return res
28
 
29
+ def rm(self, path, json):
30
+ res = self.rag.delete(path, json)
31
  return res
32
 
33
  def put(self,path, json):
sdk/python/ragflow/modules/{assistant.py → chat.py} RENAMED
@@ -4,14 +4,14 @@ from .base import Base
4
  from .session import Session
5
 
6
 
7
- class Assistant(Base):
8
  def __init__(self, rag, res_dict):
9
  self.id = ""
10
  self.name = "assistant"
11
  self.avatar = "path/to/avatar"
12
  self.knowledgebases = ["kb1"]
13
- self.llm = Assistant.LLM(rag, {})
14
- self.prompt = Assistant.Prompt(rag, {})
15
  super().__init__(rag, res_dict)
16
 
17
  class LLM(Base):
@@ -42,21 +42,13 @@ class Assistant(Base):
42
  )
43
  super().__init__(rag, res_dict)
44
 
45
- def save(self) -> bool:
46
- res = self.post('/assistant/save',
47
- {"id": self.id, "name": self.name, "avatar": self.avatar, "knowledgebases": self.knowledgebases,
48
- "llm": self.llm.to_json(), "prompt": self.prompt.to_json()
49
- })
50
  res = res.json()
51
- if res.get("retmsg") == "success": return True
52
- raise Exception(res["retmsg"])
53
 
54
- def delete(self) -> bool:
55
- res = self.rm('/assistant/delete',
56
- {"id": self.id})
57
- res = res.json()
58
- if res.get("retmsg") == "success": return True
59
- raise Exception(res["retmsg"])
60
 
61
  def create_session(self, name: str = "New session") -> Session:
62
  res = self.post("/session/save", {"name": name, "assistant_id": self.id})
 
4
  from .session import Session
5
 
6
 
7
+ class Chat(Base):
8
  def __init__(self, rag, res_dict):
9
  self.id = ""
10
  self.name = "assistant"
11
  self.avatar = "path/to/avatar"
12
  self.knowledgebases = ["kb1"]
13
+ self.llm = Chat.LLM(rag, {})
14
+ self.prompt = Chat.Prompt(rag, {})
15
  super().__init__(rag, res_dict)
16
 
17
  class LLM(Base):
 
42
  )
43
  super().__init__(rag, res_dict)
44
 
45
+ def update(self, update_message: dict):
46
+ res = self.put(f'/chat/{self.id}',
47
+ update_message)
 
 
48
  res = res.json()
49
+ if res.get("code") != 0:
50
+ raise Exception(res["message"])
51
 
 
 
 
 
 
 
52
 
53
  def create_session(self, name: str = "New session") -> Session:
54
  res = self.post("/session/save", {"name": name, "assistant_id": self.id})
sdk/python/ragflow/ragflow.py CHANGED
@@ -17,7 +17,7 @@ from typing import List
17
 
18
  import requests
19
 
20
- from .modules.assistant import Assistant
21
  from .modules.chunk import Chunk
22
  from .modules.dataset import DataSet
23
  from .modules.document import Document
@@ -32,16 +32,16 @@ class RAGFlow:
32
  self.api_url = f"{base_url}/api/{version}"
33
  self.authorization_header = {"Authorization": "{} {}".format("Bearer", self.user_key)}
34
 
35
- def post(self, path, param, stream=False):
36
- res = requests.post(url=self.api_url + path, json=param, headers=self.authorization_header, stream=stream)
37
  return res
38
 
39
  def get(self, path, params=None):
40
  res = requests.get(url=self.api_url + path, params=params, headers=self.authorization_header)
41
  return res
42
 
43
- def delete(self, path, params):
44
- res = requests.delete(url=self.api_url + path, json=params, headers=self.authorization_header)
45
  return res
46
 
47
  def put(self, path, json):
@@ -68,7 +68,7 @@ class RAGFlow:
68
  return DataSet(self, res["data"])
69
  raise Exception(res["message"])
70
 
71
- def delete_dataset(self, ids: List[str] = None, names: List[str] = None):
72
  res = self.delete("/dataset",{"ids": ids, "names": names})
73
  res=res.json()
74
  if res.get("code") != 0:
@@ -87,21 +87,21 @@ class RAGFlow:
87
  return result_list
88
  raise Exception(res["message"])
89
 
90
- def create_assistant(self, name: str = "assistant", avatar: str = "path", knowledgebases: List[DataSet] = [],
91
- llm: Assistant.LLM = None, prompt: Assistant.Prompt = None) -> Assistant:
92
  datasets = []
93
  for dataset in knowledgebases:
94
  datasets.append(dataset.to_json())
95
 
96
  if llm is None:
97
- llm = Assistant.LLM(self, {"model_name": None,
98
  "temperature": 0.1,
99
  "top_p": 0.3,
100
  "presence_penalty": 0.4,
101
  "frequency_penalty": 0.7,
102
  "max_tokens": 512, })
103
  if prompt is None:
104
- prompt = Assistant.Prompt(self, {"similarity_threshold": 0.2,
105
  "keywords_similarity_weight": 0.7,
106
  "top_n": 8,
107
  "variables": [{
@@ -127,28 +127,29 @@ class RAGFlow:
127
  "knowledgebases": datasets,
128
  "llm": llm.to_json(),
129
  "prompt": prompt.to_json()}
130
- res = self.post("/assistant/save", temp_dict)
131
  res = res.json()
132
- if res.get("retmsg") == "success":
133
- return Assistant(self, res["data"])
134
- raise Exception(res["retmsg"])
135
 
136
- def get_assistant(self, id: str = None, name: str = None) -> Assistant:
137
- res = self.get("/assistant/get", {"id": id, "name": name})
 
138
  res = res.json()
139
- if res.get("retmsg") == "success":
140
- return Assistant(self, res['data'])
141
- raise Exception(res["retmsg"])
142
 
143
- def list_assistants(self) -> List[Assistant]:
144
- res = self.get("/assistant/list")
 
145
  res = res.json()
146
  result_list = []
147
- if res.get("retmsg") == "success":
148
  for data in res['data']:
149
- result_list.append(Assistant(self, data))
150
  return result_list
151
- raise Exception(res["retmsg"])
152
 
153
  def create_document(self, ds: DataSet, name: str, blob: bytes) -> bool:
154
  url = f"/doc/dataset/{ds.id}/documents/upload"
 
17
 
18
  import requests
19
 
20
+ from .modules.chat import Chat
21
  from .modules.chunk import Chunk
22
  from .modules.dataset import DataSet
23
  from .modules.document import Document
 
32
  self.api_url = f"{base_url}/api/{version}"
33
  self.authorization_header = {"Authorization": "{} {}".format("Bearer", self.user_key)}
34
 
35
+ def post(self, path, json, stream=False):
36
+ res = requests.post(url=self.api_url + path, json=json, headers=self.authorization_header, stream=stream)
37
  return res
38
 
39
  def get(self, path, params=None):
40
  res = requests.get(url=self.api_url + path, params=params, headers=self.authorization_header)
41
  return res
42
 
43
+ def delete(self, path, json):
44
+ res = requests.delete(url=self.api_url + path, json=json, headers=self.authorization_header)
45
  return res
46
 
47
  def put(self, path, json):
 
68
  return DataSet(self, res["data"])
69
  raise Exception(res["message"])
70
 
71
+ def delete_datasets(self, ids: List[str] = None, names: List[str] = None):
72
  res = self.delete("/dataset",{"ids": ids, "names": names})
73
  res=res.json()
74
  if res.get("code") != 0:
 
87
  return result_list
88
  raise Exception(res["message"])
89
 
90
+ def create_chat(self, name: str = "assistant", avatar: str = "path", knowledgebases: List[DataSet] = [],
91
+ llm: Chat.LLM = None, prompt: Chat.Prompt = None) -> Chat:
92
  datasets = []
93
  for dataset in knowledgebases:
94
  datasets.append(dataset.to_json())
95
 
96
  if llm is None:
97
+ llm = Chat.LLM(self, {"model_name": None,
98
  "temperature": 0.1,
99
  "top_p": 0.3,
100
  "presence_penalty": 0.4,
101
  "frequency_penalty": 0.7,
102
  "max_tokens": 512, })
103
  if prompt is None:
104
+ prompt = Chat.Prompt(self, {"similarity_threshold": 0.2,
105
  "keywords_similarity_weight": 0.7,
106
  "top_n": 8,
107
  "variables": [{
 
127
  "knowledgebases": datasets,
128
  "llm": llm.to_json(),
129
  "prompt": prompt.to_json()}
130
+ res = self.post("/chat", temp_dict)
131
  res = res.json()
132
+ if res.get("code") == 0:
133
+ return Chat(self, res["data"])
134
+ raise Exception(res["message"])
135
 
136
+ def delete_chats(self,ids: List[str] = None,names: List[str] = None ) -> bool:
137
+ res = self.delete('/chat',
138
+ {"ids":ids, "names":names})
139
  res = res.json()
140
+ if res.get("code") != 0:
141
+ raise Exception(res["message"])
 
142
 
143
+ def list_chats(self, page: int = 1, page_size: int = 1024, orderby: str = "create_time", desc: bool = True,
144
+ id: str = None, name: str = None) -> List[Chat]:
145
+ res = self.get("/chat",{"page": page, "page_size": page_size, "orderby": orderby, "desc": desc, "id": id, "name": name})
146
  res = res.json()
147
  result_list = []
148
+ if res.get("code") == 0:
149
  for data in res['data']:
150
+ result_list.append(Chat(self, data))
151
  return result_list
152
+ raise Exception(res["message"])
153
 
154
  def create_document(self, ds: DataSet, name: str, blob: bytes) -> bool:
155
  url = f"/doc/dataset/{ds.id}/documents/upload"
sdk/python/test/t_assistant.py DELETED
@@ -1,68 +0,0 @@
1
- from ragflow import RAGFlow, Assistant
2
-
3
- from common import API_KEY, HOST_ADDRESS
4
- from test_sdkbase import TestSdk
5
-
6
-
7
- class TestAssistant(TestSdk):
8
- def test_create_assistant_with_success(self):
9
- """
10
- Test creating an assistant with success
11
- """
12
- rag = RAGFlow(API_KEY, HOST_ADDRESS)
13
- kb = rag.create_dataset(name="test_create_assistant")
14
- assistant = rag.create_assistant("test_create", knowledgebases=[kb])
15
- if isinstance(assistant, Assistant):
16
- assert assistant.name == "test_create", "Name does not match."
17
- else:
18
- assert False, f"Failed to create assistant, error: {assistant}"
19
-
20
- def test_update_assistant_with_success(self):
21
- """
22
- Test updating an assistant with success.
23
- """
24
- rag = RAGFlow(API_KEY, HOST_ADDRESS)
25
- kb = rag.create_dataset(name="test_update_assistant")
26
- assistant = rag.create_assistant("test_update", knowledgebases=[kb])
27
- if isinstance(assistant, Assistant):
28
- assert assistant.name == "test_update", "Name does not match."
29
- assistant.name = 'new_assistant'
30
- res = assistant.save()
31
- assert res is True, f"Failed to update assistant, error: {res}"
32
- else:
33
- assert False, f"Failed to create assistant, error: {assistant}"
34
-
35
- def test_delete_assistant_with_success(self):
36
- """
37
- Test deleting an assistant with success
38
- """
39
- rag = RAGFlow(API_KEY, HOST_ADDRESS)
40
- kb = rag.create_dataset(name="test_delete_assistant")
41
- assistant = rag.create_assistant("test_delete", knowledgebases=[kb])
42
- if isinstance(assistant, Assistant):
43
- assert assistant.name == "test_delete", "Name does not match."
44
- res = assistant.delete()
45
- assert res is True, f"Failed to delete assistant, error: {res}"
46
- else:
47
- assert False, f"Failed to create assistant, error: {assistant}"
48
-
49
- def test_list_assistants_with_success(self):
50
- """
51
- Test listing assistants with success
52
- """
53
- rag = RAGFlow(API_KEY, HOST_ADDRESS)
54
- list_assistants = rag.list_assistants()
55
- assert len(list_assistants) > 0, "Do not exist any assistant"
56
- for assistant in list_assistants:
57
- assert isinstance(assistant, Assistant), "Existence type is not assistant."
58
-
59
- def test_get_detail_assistant_with_success(self):
60
- """
61
- Test getting an assistant's detail with success
62
- """
63
- rag = RAGFlow(API_KEY, HOST_ADDRESS)
64
- kb = rag.create_dataset(name="test_get_assistant")
65
- rag.create_assistant("test_get_assistant", knowledgebases=[kb])
66
- assistant = rag.get_assistant(name="test_get_assistant")
67
- assert isinstance(assistant, Assistant), f"Failed to get assistant, error: {assistant}."
68
- assert assistant.name == "test_get_assistant", "Name does not match"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
sdk/python/test/t_chat.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ragflow import RAGFlow, Chat
2
+
3
+ from common import API_KEY, HOST_ADDRESS
4
+ from test_sdkbase import TestSdk
5
+
6
+
7
+ class TestChat(TestSdk):
8
+ def test_create_chat_with_success(self):
9
+ """
10
+ Test creating an chat with success
11
+ """
12
+ rag = RAGFlow(API_KEY, HOST_ADDRESS)
13
+ kb = rag.create_dataset(name="test_create_chat")
14
+ chat = rag.create_chat("test_create", knowledgebases=[kb])
15
+ if isinstance(chat, Chat):
16
+ assert chat.name == "test_create", "Name does not match."
17
+ else:
18
+ assert False, f"Failed to create chat, error: {chat}"
19
+
20
+ def test_update_chat_with_success(self):
21
+ """
22
+ Test updating an chat with success.
23
+ """
24
+ rag = RAGFlow(API_KEY, HOST_ADDRESS)
25
+ kb = rag.create_dataset(name="test_update_chat")
26
+ chat = rag.create_chat("test_update", knowledgebases=[kb])
27
+ if isinstance(chat, Chat):
28
+ assert chat.name == "test_update", "Name does not match."
29
+ res=chat.update({"name":"new_chat"})
30
+ assert res is None, f"Failed to update chat, error: {res}"
31
+ else:
32
+ assert False, f"Failed to create chat, error: {chat}"
33
+
34
+ def test_delete_chats_with_success(self):
35
+ """
36
+ Test deleting an chat with success
37
+ """
38
+ rag = RAGFlow(API_KEY, HOST_ADDRESS)
39
+ kb = rag.create_dataset(name="test_delete_chat")
40
+ chat = rag.create_chat("test_delete", knowledgebases=[kb])
41
+ if isinstance(chat, Chat):
42
+ assert chat.name == "test_delete", "Name does not match."
43
+ res = rag.delete_chats(ids=[chat.id])
44
+ assert res is None, f"Failed to delete chat, error: {res}"
45
+ else:
46
+ assert False, f"Failed to create chat, error: {chat}"
47
+
48
+ def test_list_chats_with_success(self):
49
+ """
50
+ Test listing chats with success
51
+ """
52
+ rag = RAGFlow(API_KEY, HOST_ADDRESS)
53
+ list_chats = rag.list_chats()
54
+ assert len(list_chats) > 0, "Do not exist any chat"
55
+ for chat in list_chats:
56
+ assert isinstance(chat, Chat), "Existence type is not chat."
sdk/python/test/t_dataset.py CHANGED
@@ -29,7 +29,7 @@ class TestDataset(TestSdk):
29
  else:
30
  assert False, f"Failed to create dataset, error: {ds}"
31
 
32
- def test_delete_dataset_with_success(self):
33
  """
34
  Test deleting a dataset with success
35
  """
@@ -37,7 +37,7 @@ class TestDataset(TestSdk):
37
  ds = rag.create_dataset("MA")
38
  if isinstance(ds, DataSet):
39
  assert ds.name == "MA", "Name does not match."
40
- res = rag.delete_dataset(names=["MA"])
41
  assert res is None, f"Failed to delete dataset, error: {res}"
42
  else:
43
  assert False, f"Failed to create dataset, error: {ds}"
 
29
  else:
30
  assert False, f"Failed to create dataset, error: {ds}"
31
 
32
+ def test_delete_datasets_with_success(self):
33
  """
34
  Test deleting a dataset with success
35
  """
 
37
  ds = rag.create_dataset("MA")
38
  if isinstance(ds, DataSet):
39
  assert ds.name == "MA", "Name does not match."
40
+ res = rag.delete_datasets(ids=[ds.id])
41
  assert res is None, f"Failed to delete dataset, error: {res}"
42
  else:
43
  assert False, f"Failed to create dataset, error: {ds}"