LiuHua Feiue commited on
Commit
633d85b
·
1 Parent(s): 99bbd67

SDK for Assistant (#2266)

Browse files

### What problem does this PR solve?

SDK for Assistant
#1102

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

Co-authored-by: Feiue <[email protected]>

api/apps/sdk/assistant.py ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.services.dialog_service import DialogService
20
+ from api.db.services.document_service import DocumentService
21
+ from api.db.services.knowledgebase_service import KnowledgebaseService
22
+ from api.db.services.user_service import TenantService
23
+ from api.settings import RetCode
24
+ from api.utils import get_uuid
25
+ from api.utils.api_utils import get_data_error_result, token_required
26
+ from api.utils.api_utils import get_json_result
27
+
28
+
29
+ @manager.route('/save', methods=['POST'])
30
+ @token_required
31
+ def save(tenant_id):
32
+ req = request.json
33
+ id = req.get("id")
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 not id:
76
+ # dataset
77
+ if not kb_list:
78
+ return get_data_error_result(retmsg="knowledgebase is 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
+ req["llm_id"] = req.get("llm_id", tenant.llm_id)
87
+ if not req.get("name"):
88
+ return get_data_error_result(retmsg="name is required.")
89
+ if DialogService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value):
90
+ return get_data_error_result(retmsg="Duplicated assistant name in creating dataset.")
91
+ # tenant_id
92
+ if req.get("tenant_id"):
93
+ return get_data_error_result(retmsg="tenant_id must not be provided.")
94
+ req["tenant_id"] = tenant_id
95
+ # prompt more parameter
96
+ default_prompt = {
97
+ "system": """你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。
98
+ 以下是知识库:
99
+ {knowledge}
100
+ 以上是知识库。""",
101
+ "prologue": "您好,我是您的助手小樱,长得可爱又善良,can I help you?",
102
+ "parameters": [
103
+ {"key": "knowledge", "optional": False}
104
+ ],
105
+ "empty_response": "Sorry! 知识库中未找到相关内容!"
106
+ }
107
+ key_list_2 = ["system", "prologue", "parameters", "empty_response"]
108
+ if "prompt_config" not in req:
109
+ req['prompt_config'] = {}
110
+ for key in key_list_2:
111
+ temp = req['prompt_config'].get(key)
112
+ if not temp:
113
+ req['prompt_config'][key] = default_prompt[key]
114
+ for p in req['prompt_config']["parameters"]:
115
+ if p["optional"]:
116
+ continue
117
+ if req['prompt_config']["system"].find("{%s}" % p["key"]) < 0:
118
+ return get_data_error_result(
119
+ retmsg="Parameter '{}' is not used".format(p["key"]))
120
+ # save
121
+ if not DialogService.save(**req):
122
+ return get_data_error_result(retmsg="Fail to new an assistant!")
123
+ # response
124
+ e, res = DialogService.get_by_id(req["id"])
125
+ if not e:
126
+ return get_data_error_result(retmsg="Fail to new an assistant!")
127
+ res = res.to_json()
128
+ renamed_dict = {}
129
+ for key, value in res["prompt_config"].items():
130
+ new_key = key_mapping.get(key, key)
131
+ renamed_dict[new_key] = value
132
+ res["prompt"] = renamed_dict
133
+ del res["prompt_config"]
134
+ new_dict = {"similarity_threshold": res["similarity_threshold"],
135
+ "keywords_similarity_weight": res["vector_similarity_weight"],
136
+ "top_n": res["top_n"],
137
+ "rerank_model": res['rerank_id']}
138
+ res["prompt"].update(new_dict)
139
+ for key in key_list:
140
+ del res[key]
141
+ res["llm"] = res.pop("llm_setting")
142
+ res["llm"]["model_name"] = res.pop("llm_id")
143
+ del res["kb_ids"]
144
+ res["knowledgebases"] = req["knowledgebases"]
145
+ res["avatar"] = res.pop("icon")
146
+ return get_json_result(data=res)
147
+ else:
148
+ # authorization
149
+ if not DialogService.query(tenant_id=tenant_id, id=req["id"], status=StatusEnum.VALID.value):
150
+ return get_json_result(data=False, retmsg='You do not own the assistant', retcode=RetCode.OPERATING_ERROR)
151
+ # prompt
152
+ e, res = DialogService.get_by_id(req["id"])
153
+ res = res.to_json()
154
+ if "name" in req:
155
+ if not req.get("name"):
156
+ return get_data_error_result(retmsg="name is not empty.")
157
+ if req["name"].lower() != res["name"].lower() \
158
+ and len(DialogService.query(name=req["name"], tenant_id=tenant_id,status=StatusEnum.VALID.value)) > 0:
159
+ return get_data_error_result(retmsg="Duplicated knowledgebase name in updating dataset.")
160
+ if "prompt_config" in req:
161
+ res["prompt_config"].update(req["prompt_config"])
162
+ for p in res["prompt_config"]["parameters"]:
163
+ if p["optional"]:
164
+ continue
165
+ if res["prompt_config"]["system"].find("{%s}" % p["key"]) < 0:
166
+ return get_data_error_result(retmsg="Parameter '{}' is not used".format(p["key"]))
167
+ if "llm_setting" in req:
168
+ res["llm_setting"].update(req["llm_setting"])
169
+ req["prompt_config"] = res["prompt_config"]
170
+ req["llm_setting"] = res["llm_setting"]
171
+ # avatar
172
+ if "avatar" in req:
173
+ req["icon"] = req.pop("avatar")
174
+ assistant_id = req.pop("id")
175
+ if "knowledgebases" in req:
176
+ req.pop("knowledgebases")
177
+ if not DialogService.update_by_id(assistant_id, req):
178
+ return get_data_error_result(retmsg="Assistant not found!")
179
+ return get_json_result(data=True)
180
+
181
+
182
+ @manager.route('/delete', methods=['DELETE'])
183
+ @token_required
184
+ def delete(tenant_id):
185
+ req = request.args
186
+ if "id" not in req:
187
+ return get_data_error_result(retmsg="id is required")
188
+ id = req['id']
189
+ if not DialogService.query(tenant_id=tenant_id, id=id,status=StatusEnum.VALID.value):
190
+ return get_json_result(data=False, retmsg='you do not own the assistant.', retcode=RetCode.OPERATING_ERROR)
191
+
192
+ temp_dict = {"status": StatusEnum.INVALID.value}
193
+ DialogService.update_by_id(req["id"], temp_dict)
194
+ return get_json_result(data=True)
195
+
196
+
197
+ @manager.route('/get', methods=['GET'])
198
+ @token_required
199
+ def get(tenant_id):
200
+ req = request.args
201
+ if "id" in req:
202
+ id = req["id"]
203
+ ass = DialogService.query(tenant_id=tenant_id, id=id,status=StatusEnum.VALID.value)
204
+ if not ass:
205
+ return get_json_result(data=False, retmsg='You do not own the assistant.', retcode=RetCode.OPERATING_ERROR)
206
+ if "name" in req:
207
+ name = req["name"]
208
+ if ass[0].name != name:
209
+ return get_json_result(data=False, retmsg='name does not match id.', retcode=RetCode.OPERATING_ERROR)
210
+ res=ass[0].to_json()
211
+ else:
212
+ if "name" in req:
213
+ name = req["name"]
214
+ ass = DialogService.query(name=name, tenant_id=tenant_id,status=StatusEnum.VALID.value)
215
+ if not ass:
216
+ return get_json_result(data=False, retmsg='You do not own the dataset.',retcode=RetCode.OPERATING_ERROR)
217
+ res=ass[0].to_json()
218
+ else:
219
+ return get_data_error_result(retmsg="At least one of `id` or `name` must be provided.")
220
+ renamed_dict = {}
221
+ key_mapping = {"parameters": "variables",
222
+ "prologue": "opener",
223
+ "quote": "show_quote",
224
+ "system": "prompt",
225
+ "rerank_id": "rerank_model",
226
+ "vector_similarity_weight": "keywords_similarity_weight"}
227
+ key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
228
+ for key, value in res["prompt_config"].items():
229
+ new_key = key_mapping.get(key, key)
230
+ renamed_dict[new_key] = value
231
+ res["prompt"] = renamed_dict
232
+ del res["prompt_config"]
233
+ new_dict = {"similarity_threshold": res["similarity_threshold"],
234
+ "keywords_similarity_weight": res["vector_similarity_weight"],
235
+ "top_n": res["top_n"],
236
+ "rerank_model": res['rerank_id']}
237
+ res["prompt"].update(new_dict)
238
+ for key in key_list:
239
+ del res[key]
240
+ res["llm"] = res.pop("llm_setting")
241
+ res["llm"]["model_name"] = res.pop("llm_id")
242
+ kb_list = []
243
+ for kb_id in res["kb_ids"]:
244
+ kb = KnowledgebaseService.query(id=kb_id)
245
+ kb_list.append(kb[0].to_json())
246
+ del res["kb_ids"]
247
+ res["knowledgebases"] = kb_list
248
+ res["avatar"] = res.pop("icon")
249
+ return get_json_result(data=res)
250
+
251
+
252
+ @manager.route('/list', methods=['GET'])
253
+ @token_required
254
+ def list_assistants(tenant_id):
255
+ assts = DialogService.query(
256
+ tenant_id=tenant_id,
257
+ status=StatusEnum.VALID.value,
258
+ reverse=True,
259
+ order_by=DialogService.model.create_time)
260
+ assts = [d.to_dict() for d in assts]
261
+ list_assts=[]
262
+ renamed_dict = {}
263
+ key_mapping = {"parameters": "variables",
264
+ "prologue": "opener",
265
+ "quote": "show_quote",
266
+ "system": "prompt",
267
+ "rerank_id": "rerank_model",
268
+ "vector_similarity_weight": "keywords_similarity_weight"}
269
+ key_list = ["similarity_threshold", "vector_similarity_weight", "top_n", "rerank_id"]
270
+ for res in assts:
271
+ for key, value in res["prompt_config"].items():
272
+ new_key = key_mapping.get(key, key)
273
+ renamed_dict[new_key] = value
274
+ res["prompt"] = renamed_dict
275
+ del res["prompt_config"]
276
+ new_dict = {"similarity_threshold": res["similarity_threshold"],
277
+ "keywords_similarity_weight": res["vector_similarity_weight"],
278
+ "top_n": res["top_n"],
279
+ "rerank_model": res['rerank_id']}
280
+ res["prompt"].update(new_dict)
281
+ for key in key_list:
282
+ del res[key]
283
+ res["llm"] = res.pop("llm_setting")
284
+ res["llm"]["model_name"] = res.pop("llm_id")
285
+ kb_list = []
286
+ for kb_id in res["kb_ids"]:
287
+ kb = KnowledgebaseService.query(id=kb_id)
288
+ kb_list.append(kb[0].to_json())
289
+ del res["kb_ids"]
290
+ res["knowledgebases"] = kb_list
291
+ res["avatar"] = res.pop("icon")
292
+ list_assts.append(res)
293
+ return get_json_result(data=list_assts)
sdk/python/ragflow/__init__.py CHANGED
@@ -3,4 +3,5 @@ import importlib.metadata
3
  __version__ = importlib.metadata.version("ragflow")
4
 
5
  from .ragflow import RAGFlow
6
- from .modules.dataset import DataSet
 
 
3
  __version__ = importlib.metadata.version("ragflow")
4
 
5
  from .ragflow import RAGFlow
6
+ from .modules.dataset import DataSet
7
+ from .modules.chat_assistant import Assistant
sdk/python/ragflow/modules/chat_assistant.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .base import Base
2
+
3
+
4
+ class Assistant(Base):
5
+ def __init__(self, rag, res_dict):
6
+ self.id=""
7
+ self.name = "assistant"
8
+ self.avatar = "path/to/avatar"
9
+ self.knowledgebases = ["kb1"]
10
+ self.llm = Assistant.LLM(rag, {})
11
+ self.prompt = Assistant.Prompt(rag, {})
12
+ super().__init__(rag, res_dict)
13
+
14
+ class LLM(Base):
15
+ def __init__(self, rag, res_dict):
16
+ self.model_name = "deepseek-chat"
17
+ self.temperature = 0.1
18
+ self.top_p = 0.3
19
+ self.presence_penalty = 0.4
20
+ self.frequency_penalty = 0.7
21
+ self.max_tokens = 512
22
+ super().__init__(rag, res_dict)
23
+
24
+ class Prompt(Base):
25
+ def __init__(self, rag, res_dict):
26
+ self.similarity_threshold = 0.2
27
+ self.keywords_similarity_weight = 0.7
28
+ self.top_n = 8
29
+ self.variables = [{"key": "knowledge", "optional": True}]
30
+ self.rerank_model = None
31
+ self.empty_response = None
32
+ self.opener = "Hi! I'm your assistant, what can I do for you?"
33
+ self.show_quote = True
34
+ self.prompt = (
35
+ "You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. "
36
+ "Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, "
37
+ "your answer must include the sentence 'The answer you are looking for is not found in the knowledge base!' "
38
+ "Answers need to consider chat history.\nHere is the knowledge base:\n{knowledge}\nThe above is the knowledge base."
39
+ )
40
+ super().__init__(rag, res_dict)
41
+
42
+ def save(self) -> bool:
43
+ res = self.post('/assistant/save',
44
+ {"id": self.id, "name": self.name, "avatar": self.avatar, "knowledgebases":self.knowledgebases,
45
+ "llm":self.llm.to_json(),"prompt":self.prompt.to_json()
46
+ })
47
+ res = res.json()
48
+ if res.get("retmsg") == "success": return True
49
+ raise Exception(res["retmsg"])
50
+
51
+ def delete(self) -> bool:
52
+ res = self.rm('/assistant/delete',
53
+ {"id": self.id})
54
+ res = res.json()
55
+ if res.get("retmsg") == "success": return True
56
+ raise Exception(res["retmsg"])
sdk/python/ragflow/ragflow.py CHANGED
@@ -17,6 +17,8 @@ from typing import List
17
 
18
  import requests
19
 
 
 
20
  from .modules.dataset import DataSet
21
 
22
 
@@ -78,3 +80,66 @@ class RAGFlow:
78
  if res.get("retmsg") == "success":
79
  return DataSet(self, res['data'])
80
  raise Exception(res["retmsg"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  import requests
19
 
20
+
21
+ from .modules.chat_assistant import Assistant
22
  from .modules.dataset import DataSet
23
 
24
 
 
80
  if res.get("retmsg") == "success":
81
  return DataSet(self, res['data'])
82
  raise Exception(res["retmsg"])
83
+
84
+ def create_assistant(self, name: str = "assistant", avatar: str = "path", knowledgebases: List[DataSet] = [],
85
+ llm: Assistant.LLM = None, prompt: Assistant.Prompt = None) -> Assistant:
86
+ datasets = []
87
+ for dataset in knowledgebases:
88
+ datasets.append(dataset.to_json())
89
+
90
+ if llm is None:
91
+ llm = Assistant.LLM(self, {"model_name": "deepseek-chat",
92
+ "temperature": 0.1,
93
+ "top_p": 0.3,
94
+ "presence_penalty": 0.4,
95
+ "frequency_penalty": 0.7,
96
+ "max_tokens": 512, })
97
+ if prompt is None:
98
+ prompt = Assistant.Prompt(self, {"similarity_threshold": 0.2,
99
+ "keywords_similarity_weight": 0.7,
100
+ "top_n": 8,
101
+ "variables": [{
102
+ "key": "knowledge",
103
+ "optional": True
104
+ }], "rerank_model": "",
105
+ "empty_response": None,
106
+ "opener": None,
107
+ "show_quote": True,
108
+ "prompt": None})
109
+ if prompt.opener is None:
110
+ prompt.opener = "Hi! I'm your assistant, what can I do for you?"
111
+ if prompt.prompt is None:
112
+ prompt.prompt = (
113
+ "You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. "
114
+ "Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, "
115
+ "your answer must include the sentence 'The answer you are looking for is not found in the knowledge base!' "
116
+ "Answers need to consider chat history.\nHere is the knowledge base:\n{knowledge}\nThe above is the knowledge base."
117
+ )
118
+
119
+ temp_dict = {"name": name,
120
+ "avatar": avatar,
121
+ "knowledgebases": datasets,
122
+ "llm": llm.to_json(),
123
+ "prompt": prompt.to_json()}
124
+ res = self.post("/assistant/save", temp_dict)
125
+ res = res.json()
126
+ if res.get("retmsg") == "success":
127
+ return Assistant(self, res["data"])
128
+ raise Exception(res["retmsg"])
129
+
130
+ def get_assistant(self, id: str = None, name: str = None) -> Assistant:
131
+ res = self.get("/assistant/get", {"id": id, "name": name})
132
+ res = res.json()
133
+ if res.get("retmsg") == "success":
134
+ return Assistant(self, res['data'])
135
+ raise Exception(res["retmsg"])
136
+
137
+ def list_assistants(self) -> List[Assistant]:
138
+ res = self.get("/assistant/list")
139
+ res = res.json()
140
+ result_list = []
141
+ if res.get("retmsg") == "success":
142
+ for data in res['data']:
143
+ result_list.append(Assistant(self, data))
144
+ return result_list
145
+ raise Exception(res["retmsg"])
sdk/python/test/common.py CHANGED
@@ -1,4 +1,4 @@
1
 
2
 
3
- API_KEY = 'ragflow-k0N2I1MzQwNjNhMzExZWY5ODg1MDI0Mm'
4
  HOST_ADDRESS = 'http://127.0.0.1:9380'
 
1
 
2
 
3
+ API_KEY = 'ragflow-k0YzUxMGY4NjY5YTExZWY5MjI5MDI0Mm'
4
  HOST_ADDRESS = 'http://127.0.0.1:9380'
sdk/python/test/t_assistant.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.get_dataset(name="God")
14
+ assistant = rag.create_assistant("God",knowledgebases=[kb])
15
+ if isinstance(assistant, Assistant):
16
+ assert assistant.name == "God", "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.get_dataset(name="God")
26
+ assistant = rag.create_assistant("ABC",knowledgebases=[kb])
27
+ if isinstance(assistant, Assistant):
28
+ assert assistant.name == "ABC", "Name does not match."
29
+ assistant.name = 'DEF'
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.get_dataset(name="God")
41
+ assistant = rag.create_assistant("MA",knowledgebases=[kb])
42
+ if isinstance(assistant, Assistant):
43
+ assert assistant.name == "MA", "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
+ assistant = rag.get_assistant(name="God")
65
+ assert isinstance(assistant, Assistant), f"Failed to get assistant, error: {assistant}."
66
+ assert assistant.name == "God", "Name does not match"