ragflow-sdk-myfbee-test 1.0.1.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,39 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ # Keep runtime validation when beartype is installed, while allowing slim
18
+ # SDK installs to import without the optional checker.
19
+ try:
20
+ from beartype.claw import beartype_this_package
21
+
22
+ beartype_this_package()
23
+ except ImportError:
24
+ pass
25
+
26
+ import importlib.metadata
27
+
28
+ from .ragflow import RAGFlow
29
+ from .modules.dataset import DataSet
30
+ from .modules.chat import Chat
31
+ from .modules.session import Session
32
+ from .modules.document import Document
33
+ from .modules.chunk import Chunk
34
+ from .modules.agent import Agent
35
+ from .modules.memory import Memory
36
+
37
+ __version__ = importlib.metadata.version("ragflow_sdk")
38
+
39
+ __all__ = ["RAGFlow", "DataSet", "Chat", "Session", "Document", "Chunk", "Agent", "Memory"]
@@ -0,0 +1,15 @@
1
+ #
2
+ # Copyright 2025 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
+ #
@@ -0,0 +1,69 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ from .base import Base
18
+ from .session import Session
19
+
20
+
21
+ class Agent(Base):
22
+ def __init__(self, rag, res_dict):
23
+ self.id = None
24
+ self.avatar = None
25
+ self.canvas_type = None
26
+ self.description = None
27
+ self.dsl = None
28
+ super().__init__(rag, res_dict)
29
+
30
+ class Dsl(Base):
31
+ def __init__(self, rag, res_dict):
32
+ self.answer = []
33
+ self.components = {"begin": {"downstream": ["Answer:China"], "obj": {"component_name": "Begin", "params": {}}, "upstream": []}}
34
+ self.graph = {
35
+ "edges": [],
36
+ "nodes": [{"data": {"label": "Begin", "name": "begin"}, "id": "begin", "position": {"x": 50, "y": 200}, "sourcePosition": "left", "targetPosition": "right", "type": "beginNode"}],
37
+ }
38
+ self.history = []
39
+ self.messages = []
40
+ self.path = []
41
+ self.reference = []
42
+ super().__init__(rag, res_dict)
43
+
44
+ def create_session(self, **kwargs) -> Session:
45
+ res = self.post(f"/agents/{self.id}/sessions", json=kwargs)
46
+ res = res.json()
47
+ if res.get("code") == 0:
48
+ return Session(self.rag, res.get("data"))
49
+ raise Exception(res.get("message"))
50
+
51
+ def list_sessions(self, page: int = 1, page_size: int = 30, orderby: str = "create_time", desc: bool = True, id: str = None) -> list[Session]:
52
+ res = self.get(f"/agents/{self.id}/sessions", {"page": page, "page_size": page_size, "orderby": orderby, "desc": desc, "id": id})
53
+ res = res.json()
54
+ if res.get("code") == 0:
55
+ result_list = []
56
+ for data in res.get("data"):
57
+ temp_agent = Session(self.rag, data)
58
+ result_list.append(temp_agent)
59
+ return result_list
60
+ raise Exception(res.get("message"))
61
+
62
+ def delete_sessions(self, ids: list[str] | None = None, delete_all: bool = False):
63
+ payload = {"ids": ids}
64
+ if delete_all:
65
+ payload["delete_all"] = True
66
+ res = self.rm(f"/agents/{self.id}/sessions", payload)
67
+ res = res.json()
68
+ if res.get("code") != 0:
69
+ raise Exception(res.get("message"))
@@ -0,0 +1,62 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+
18
+ class Base:
19
+ def __init__(self, rag, res_dict):
20
+ self.rag = rag
21
+ self._update_from_dict(rag, res_dict)
22
+
23
+ def _update_from_dict(self, rag, res_dict):
24
+ for k, v in res_dict.items():
25
+ if isinstance(v, dict):
26
+ self.__dict__[k] = Base(rag, v)
27
+ else:
28
+ self.__dict__[k] = v
29
+
30
+ def to_json(self):
31
+ pr = {}
32
+ for name in dir(self):
33
+ value = getattr(self, name)
34
+ if not name.startswith("__") and not callable(value) and name != "rag":
35
+ if isinstance(value, Base):
36
+ pr[name] = value.to_json()
37
+ else:
38
+ pr[name] = value
39
+ return pr
40
+
41
+ def post(self, path, json=None, stream=False, files=None):
42
+ res = self.rag.post(path, json, stream=stream, files=files)
43
+ return res
44
+
45
+ def get(self, path, params=None):
46
+ res = self.rag.get(path, params)
47
+ return res
48
+
49
+ def rm(self, path, json):
50
+ res = self.rag.delete(path, json)
51
+ return res
52
+
53
+ def put(self, path, json):
54
+ res = self.rag.put(path, json)
55
+ return res
56
+
57
+ def patch(self, path, json):
58
+ res = self.rag.patch(path, json)
59
+ return res
60
+
61
+ def __str__(self):
62
+ return str(self.to_json())
@@ -0,0 +1,67 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+
18
+ from .base import Base
19
+ from .session import Session
20
+
21
+
22
+ class Chat(Base):
23
+ def __init__(self, rag, res_dict):
24
+ self.id = ""
25
+ self.name = "assistant"
26
+ self.icon = ""
27
+ self.dataset_ids = []
28
+ self.llm_id = None
29
+ self.llm_setting = {}
30
+ self.prompt_config = {}
31
+ self.similarity_threshold = 0.2
32
+ self.vector_similarity_weight = 0.3
33
+ self.top_n = 6
34
+ self.top_k = 1024
35
+ self.rerank_id = ""
36
+ super().__init__(rag, res_dict)
37
+
38
+ def update(self, update_message: dict):
39
+ if not isinstance(update_message, dict):
40
+ raise Exception("ValueError('`update_message` must be a dict')")
41
+ res = self.patch(f"/chats/{self.id}", update_message)
42
+ res = res.json()
43
+ if res.get("code") != 0:
44
+ raise Exception(res["message"])
45
+
46
+ def create_session(self, name: str = "New session") -> Session:
47
+ res = self.post(f"/chats/{self.id}/sessions", {"name": name})
48
+ res = res.json()
49
+ if res.get("code") == 0:
50
+ return Session(self.rag, res["data"])
51
+ raise Exception(res.get("message"))
52
+
53
+ def list_sessions(self, page: int = 1, page_size: int = 30, orderby: str = "create_time", desc: bool = True, id: str = None, name: str = None, user_id: str = None) -> list[Session]:
54
+ res = self.get(f"/chats/{self.id}/sessions", {"page": page, "page_size": page_size, "orderby": orderby, "desc": desc, "id": id, "name": name, "user_id": user_id})
55
+ res = res.json()
56
+ if res.get("code") == 0:
57
+ result_list = []
58
+ for data in res["data"]:
59
+ result_list.append(Session(self.rag, data))
60
+ return result_list
61
+ raise Exception(res["message"])
62
+
63
+ def delete_sessions(self, ids: list[str] | None = None, delete_all: bool = False):
64
+ res = self.rm(f"/chats/{self.id}/sessions", {"ids": ids, "delete_all": delete_all})
65
+ res = res.json()
66
+ if res.get("code") != 0:
67
+ raise Exception(res.get("message"))
@@ -0,0 +1,62 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ from .base import Base
18
+
19
+
20
+ class ChunkUpdateError(Exception):
21
+ def __init__(self, code=None, message=None, details=None):
22
+ self.code = code
23
+ self.message = message
24
+ self.details = details
25
+ super().__init__(message)
26
+
27
+
28
+ class Chunk(Base):
29
+ def __init__(self, rag, res_dict):
30
+ self.id = ""
31
+ self.content = ""
32
+ self.image_id = ""
33
+ self.important_keywords = []
34
+ self.tag_kwd = []
35
+ self.questions = []
36
+ self.create_time = ""
37
+ self.create_timestamp = 0.0
38
+ self.dataset_id = None
39
+ self.document_name = ""
40
+ self.document_keyword = ""
41
+ self.document_id = ""
42
+ self.available = True
43
+ # Additional fields for retrieval results
44
+ self.similarity = 0.0
45
+ self.vector_similarity = 0.0
46
+ self.term_similarity = 0.0
47
+ self.positions = []
48
+ self.doc_type = ""
49
+ for k in list(res_dict.keys()):
50
+ if k not in self.__dict__:
51
+ res_dict.pop(k)
52
+ super().__init__(rag, res_dict)
53
+
54
+ # for backward compatibility
55
+ if not self.document_name:
56
+ self.document_name = self.document_keyword
57
+
58
+ def update(self, update_message: dict):
59
+ res = self.patch(f"/datasets/{self.dataset_id}/documents/{self.document_id}/chunks/{self.id}", update_message)
60
+ res = res.json()
61
+ if res.get("code") != 0:
62
+ raise ChunkUpdateError(code=res.get("code"), message=res.get("message"), details=res.get("details"))
@@ -0,0 +1,182 @@
1
+ #
2
+ # Copyright 2025 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 typing import Any
17
+
18
+ from .base import Base
19
+ from .document import Document
20
+
21
+
22
+ class DataSet(Base):
23
+ class ParserConfig(Base):
24
+ def __init__(self, rag, res_dict):
25
+ super().__init__(rag, res_dict)
26
+
27
+ def __init__(self, rag, res_dict):
28
+ self.id = ""
29
+ self.name = ""
30
+ self.avatar = ""
31
+ self.tenant_id = None
32
+ self.description = ""
33
+ self.embedding_model = ""
34
+ self.permission = "me"
35
+ self.document_count = 0
36
+ self.chunk_count = 0
37
+ self.chunk_method = "naive"
38
+ self.parser_config = None
39
+ self.pagerank = 0
40
+ for k in list(res_dict.keys()):
41
+ if k not in self.__dict__:
42
+ res_dict.pop(k)
43
+ super().__init__(rag, res_dict)
44
+
45
+ def update(self, update_message: dict):
46
+ res = self.put(f"/datasets/{self.id}", update_message)
47
+ res = res.json()
48
+ if res.get("code") != 0:
49
+ raise Exception(res["message"])
50
+
51
+ self._update_from_dict(self.rag, res.get("data", {}))
52
+ return self
53
+
54
+ def upload_documents(self, document_list: list[dict]):
55
+ url = f"/datasets/{self.id}/documents"
56
+ files = [("file", (ele["display_name"], ele["blob"])) for ele in document_list]
57
+ res = self.post(path=url, json=None, files=files)
58
+ res = res.json()
59
+ if res.get("code") == 0:
60
+ doc_list = []
61
+ for doc in res["data"]:
62
+ document = Document(self.rag, doc)
63
+ doc_list.append(document)
64
+ return doc_list
65
+ raise Exception(res.get("message"))
66
+
67
+ def list_documents(
68
+ self,
69
+ id: str | None = None,
70
+ ids: list[str] | None = None,
71
+ name: str | None = None,
72
+ keywords: str | None = None,
73
+ page: int = 1,
74
+ page_size: int = 30,
75
+ orderby: str = "create_time",
76
+ desc: bool = True,
77
+ create_time_from: int = 0,
78
+ create_time_to: int = 0,
79
+ ):
80
+ # Validate that id and ids are not used together
81
+ if id and ids:
82
+ raise ValueError("Cannot use both 'id' and 'ids' parameters at the same time.")
83
+
84
+ params = {
85
+ "id": id,
86
+ "name": name,
87
+ "keywords": keywords,
88
+ "page": page,
89
+ "page_size": page_size,
90
+ "orderby": orderby,
91
+ "desc": desc,
92
+ "create_time_from": create_time_from,
93
+ "create_time_to": create_time_to,
94
+ }
95
+ # Handle ids parameter - requests expands list values into multiple query params
96
+ if ids:
97
+ params["ids"] = ids
98
+ res = self.get(f"/datasets/{self.id}/documents", params=params)
99
+ res = res.json()
100
+ documents = []
101
+ if res.get("code") == 0:
102
+ for document in res["data"].get("docs"):
103
+ documents.append(Document(self.rag, document))
104
+ return documents
105
+ raise Exception(res["message"])
106
+
107
+ def delete_documents(self, ids: list[str] | None = None, delete_all: bool = False):
108
+ res = self.rm(f"/datasets/{self.id}/documents", {"ids": ids, "delete_all": delete_all})
109
+ res = res.json()
110
+ if res.get("code") != 0:
111
+ raise Exception(res["message"])
112
+
113
+ def _get_documents_status(self, document_ids):
114
+ import time
115
+
116
+ terminal_states = {"DONE", "FAIL", "CANCEL"}
117
+ interval_sec = 1
118
+ pending = set(document_ids)
119
+ finished = []
120
+ while pending:
121
+ for doc_id in list(pending):
122
+
123
+ def fetch_doc(doc_id: str) -> Document | None:
124
+ try:
125
+ docs = self.list_documents(id=doc_id)
126
+ return docs[0] if docs else None
127
+ except Exception:
128
+ return None
129
+
130
+ doc = fetch_doc(doc_id)
131
+ if doc is None:
132
+ continue
133
+ if isinstance(doc.run, str) and doc.run.upper() in terminal_states:
134
+ finished.append((doc_id, doc.run, doc.chunk_count, doc.token_count))
135
+ pending.discard(doc_id)
136
+ elif float(doc.progress or 0.0) >= 1.0:
137
+ finished.append((doc_id, "DONE", doc.chunk_count, doc.token_count))
138
+ pending.discard(doc_id)
139
+ if pending:
140
+ time.sleep(interval_sec)
141
+ return finished
142
+
143
+ def async_parse_documents(self, document_ids):
144
+ res = self.post(f"/datasets/{self.id}/chunks", {"document_ids": document_ids})
145
+ res = res.json()
146
+ if res.get("code") != 0:
147
+ raise Exception(res.get("message"))
148
+
149
+ def parse_documents(self, document_ids):
150
+ try:
151
+ self.async_parse_documents(document_ids)
152
+ self._get_documents_status(document_ids)
153
+ except KeyboardInterrupt:
154
+ self.async_cancel_parse_documents(document_ids)
155
+
156
+ return self._get_documents_status(document_ids)
157
+
158
+ def async_cancel_parse_documents(self, document_ids):
159
+ res = self.rm(f"/datasets/{self.id}/chunks", {"document_ids": document_ids})
160
+ res = res.json()
161
+ if res.get("code") != 0:
162
+ raise Exception(res.get("message"))
163
+
164
+ def get_auto_metadata(self) -> dict[str, Any]:
165
+ """
166
+ Retrieve auto-metadata configuration for a dataset via SDK.
167
+ """
168
+ res = self.get(f"/datasets/{self.id}/metadata/config")
169
+ res = res.json()
170
+ if res.get("code") == 0:
171
+ return res["data"]
172
+ raise Exception(res["message"])
173
+
174
+ def update_auto_metadata(self, **config: Any) -> dict[str, Any]:
175
+ """
176
+ Update auto-metadata configuration for a dataset via SDK.
177
+ """
178
+ res = self.put(f"/datasets/{self.id}/metadata/config", config)
179
+ res = res.json()
180
+ if res.get("code") == 0:
181
+ return res["data"]
182
+ raise Exception(res["message"])
@@ -0,0 +1,109 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ import logging
18
+
19
+ from .base import Base
20
+ from .chunk import Chunk
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class Document(Base):
26
+ class ParserConfig(Base):
27
+ def __init__(self, rag, res_dict):
28
+ super().__init__(rag, res_dict)
29
+
30
+ def __init__(self, rag, res_dict):
31
+ self.id = ""
32
+ self.name = ""
33
+ self.thumbnail = None
34
+ self.dataset_id = None
35
+ self.chunk_method = "naive"
36
+ self.parser_config = {"pages": [[1, 1000000]]}
37
+ self.source_type = "local"
38
+ self.type = ""
39
+ self.created_by = ""
40
+ self.size = 0
41
+ self.token_count = 0
42
+ self.chunk_count = 0
43
+ self.progress = 0.0
44
+ self.progress_msg = ""
45
+ self.process_begin_at = None
46
+ self.process_duration = 0.0
47
+ self.run = "0"
48
+ self.status = "1"
49
+ self.meta_fields = {}
50
+ for k in list(res_dict.keys()):
51
+ if k not in self.__dict__:
52
+ res_dict.pop(k)
53
+ super().__init__(rag, res_dict)
54
+
55
+ def update(self, update_message: dict):
56
+ if "meta_fields" in update_message:
57
+ if not isinstance(update_message["meta_fields"], dict):
58
+ raise Exception("meta_fields must be a dictionary")
59
+ res = self.patch(f"/datasets/{self.dataset_id}/documents/{self.id}", update_message)
60
+ res = res.json()
61
+ if res.get("code") != 0:
62
+ raise Exception(res["message"])
63
+
64
+ self._update_from_dict(self.rag, res.get("data", {}))
65
+ return self
66
+
67
+ def download(self):
68
+ res = self.get(f"/datasets/{self.dataset_id}/documents/{self.id}")
69
+ content_disposition = res.headers.get("Content-Disposition", "")
70
+ if content_disposition.lstrip().lower().startswith("attachment"):
71
+ logger.debug("Document.download returning attachment content dataset_id=%s document_id=%s", self.dataset_id, self.id)
72
+ return res.content
73
+
74
+ try:
75
+ response = res.json()
76
+ if isinstance(response, dict) and "code" in response and response["code"] != 0:
77
+ raise Exception(response.get("message"))
78
+ except ValueError:
79
+ pass
80
+ logger.debug("Document.download returning non-attachment content dataset_id=%s document_id=%s", self.dataset_id, self.id)
81
+ return res.content
82
+
83
+ def list_chunks(self, page=1, page_size=30, keywords="", id=""):
84
+ data = {"keywords": keywords, "page": page, "page_size": page_size, "id": id}
85
+ res = self.get(f"/datasets/{self.dataset_id}/documents/{self.id}/chunks", data)
86
+ res = res.json()
87
+ if res.get("code") == 0:
88
+ chunks = []
89
+ for data in res["data"].get("chunks"):
90
+ chunk = Chunk(self.rag, data)
91
+ chunks.append(chunk)
92
+ return chunks
93
+ raise Exception(res.get("message"))
94
+
95
+ def add_chunk(self, content: str, important_keywords: list[str] = [], questions: list[str] = [], image_base64: str | None = None, *, tag_kwd: list[str] = []):
96
+ body = {"content": content, "important_keywords": important_keywords, "tag_kwd": tag_kwd, "questions": questions}
97
+ if image_base64 is not None:
98
+ body["image_base64"] = image_base64
99
+ res = self.post(f"/datasets/{self.dataset_id}/documents/{self.id}/chunks", body)
100
+ res = res.json()
101
+ if res.get("code") == 0:
102
+ return Chunk(self.rag, res["data"].get("chunk"))
103
+ raise Exception(res.get("message"))
104
+
105
+ def delete_chunks(self, ids: list[str] | None = None, delete_all: bool = False):
106
+ res = self.rm(f"/datasets/{self.dataset_id}/documents/{self.id}/chunks", {"chunk_ids": ids, "delete_all": delete_all})
107
+ res = res.json()
108
+ if res.get("code") != 0:
109
+ raise Exception(res.get("message"))
@@ -0,0 +1,87 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ from .base import Base
18
+
19
+
20
+ class Memory(Base):
21
+ def __init__(self, rag, res_dict):
22
+ self.id = ""
23
+ self.name = ""
24
+ self.avatar = None
25
+ self.tenant_id = None
26
+ self.owner_name = ""
27
+ self.memory_type = ["raw"]
28
+ self.storage_type = "table"
29
+ self.embd_id = ""
30
+ self.llm_id = ""
31
+ self.permissions = "me"
32
+ self.description = ""
33
+ self.memory_size = 5 * 1024 * 1024
34
+ self.forgetting_policy = "FIFO"
35
+ self.temperature = 0.5
36
+ self.system_prompt = ""
37
+ self.user_prompt = ""
38
+ for k in list(res_dict.keys()):
39
+ if k not in self.__dict__:
40
+ res_dict.pop(k)
41
+ super().__init__(rag, res_dict)
42
+
43
+ def update(self, update_dict: dict):
44
+ res = self.put(f"/memories/{self.id}", update_dict)
45
+ res = res.json()
46
+ if res.get("code") != 0:
47
+ raise Exception(res["message"])
48
+ self._update_from_dict(self.rag, res.get("data", {}))
49
+ return self
50
+
51
+ def get_config(self):
52
+ res = self.get(f"/memories/{self.id}/config")
53
+ res = res.json()
54
+ if res.get("code") != 0:
55
+ raise Exception(res["message"])
56
+ self._update_from_dict(self.rag, res.get("data", {}))
57
+ return self
58
+
59
+ def list_memory_messages(self, agent_id: str | list[str] = None, keywords: str = None, page: int = 1, page_size: int = 50):
60
+ params = {"agent_id": agent_id, "keywords": keywords, "page": page, "page_size": page_size}
61
+ res = self.get(f"/memories/{self.id}", params)
62
+ res = res.json()
63
+ if res.get("code") != 0:
64
+ raise Exception(res["message"])
65
+ return res["data"]
66
+
67
+ def forget_message(self, message_id: int):
68
+ res = self.rm(f"/messages/{self.id}:{message_id}", {})
69
+ res = res.json()
70
+ if res.get("code") != 0:
71
+ raise Exception(res["message"])
72
+ return True
73
+
74
+ def update_message_status(self, message_id: int, status: bool):
75
+ update_message = {"status": status}
76
+ res = self.put(f"/messages/{self.id}:{message_id}", update_message)
77
+ res = res.json()
78
+ if res.get("code") != 0:
79
+ raise Exception(res["message"])
80
+ return True
81
+
82
+ def get_message_content(self, message_id: int) -> dict:
83
+ res = self.get(f"/messages/{self.id}:{message_id}/content")
84
+ res = res.json()
85
+ if res.get("code") != 0:
86
+ raise Exception(res["message"])
87
+ return res["data"]
@@ -0,0 +1,203 @@
1
+ #
2
+ # Copyright 2025 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
+
17
+ import json
18
+ import logging
19
+
20
+ from .base import Base
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class Session(Base):
26
+ def __init__(self, rag, res_dict):
27
+ self.id = None
28
+ self.name = "New session"
29
+ self.messages = [{"role": "assistant", "content": "Hi! I am your assistant, can I help you?"}]
30
+ for key, value in res_dict.items():
31
+ if key == "chat_id" and value is not None:
32
+ self.chat_id = None
33
+ self.__session_type = "chat"
34
+ if key == "agent_id" and value is not None:
35
+ self.agent_id = None
36
+ self.__session_type = "agent"
37
+ super().__init__(rag, res_dict)
38
+
39
+ def ask(
40
+ self,
41
+ question="",
42
+ stream=False,
43
+ inputs=None,
44
+ release=None,
45
+ return_trace=None,
46
+ **kwargs,
47
+ ):
48
+ """
49
+ Ask a question to the session.
50
+
51
+ Parameters
52
+ ----------
53
+ question : str
54
+ The user's question. May be empty when the agent is driven solely by
55
+ Begin component inputs.
56
+ stream : bool
57
+ If ``True``, yields ``Message`` objects as they arrive (SSE streaming).
58
+ If ``False``, yields a single ``Message`` with the final answer.
59
+ inputs : dict, optional
60
+ Values for variables declared on the agent's **Begin** component. Each
61
+ value must be a dict containing at least a ``"value"`` key, and may
62
+ include ``"type"``. Example::
63
+
64
+ session.ask(
65
+ "",
66
+ stream=False,
67
+ inputs={"key1": {"type": "line", "value": "hello"}},
68
+ )
69
+
70
+ Only meaningful for agent sessions; ignored for chat sessions.
71
+ release : bool, optional
72
+ If ``True``, run against the latest published agent version instead of
73
+ the editable draft. Only meaningful for agent sessions.
74
+ return_trace : bool, optional
75
+ If ``True``, include execution trace information in the response.
76
+ Only meaningful for agent sessions.
77
+ **kwargs
78
+ Additional fields forwarded verbatim to the completion endpoint
79
+ (e.g. ``session_id``, ``files``, ``user_id``, ``custom_header``).
80
+ See the HTTP API reference for the full list.
81
+ """
82
+ if inputs is not None:
83
+ kwargs["inputs"] = inputs
84
+ if release is not None:
85
+ kwargs["release"] = release
86
+ if return_trace is not None:
87
+ kwargs["return_trace"] = return_trace
88
+
89
+ if inputs is not None or release is not None or return_trace is not None:
90
+ logger.debug(
91
+ "Session.ask explicit-params session_type=%s session_id=%s input_keys=%s release=%s return_trace=%s",
92
+ self.__session_type,
93
+ getattr(self, "id", None),
94
+ list(inputs.keys()) if isinstance(inputs, dict) else None,
95
+ release,
96
+ return_trace,
97
+ )
98
+
99
+ if self.__session_type == "agent":
100
+ res = self._ask_agent(question, stream, **kwargs)
101
+ elif self.__session_type == "chat":
102
+ res = self._ask_chat(question, stream, **kwargs)
103
+ else:
104
+ raise Exception(f"Unknown session type: {self.__session_type}")
105
+
106
+ if stream:
107
+ for line in res.iter_lines(decode_unicode=True):
108
+ if not line:
109
+ continue # Skip empty lines
110
+ line = line.strip()
111
+ if line.startswith("data:"):
112
+ content = line[len("data:") :].strip()
113
+ if content == "[DONE]":
114
+ break # End of stream
115
+ else:
116
+ content = line
117
+
118
+ try:
119
+ json_data = json.loads(content)
120
+ except json.JSONDecodeError:
121
+ continue # Skip lines that are not valid JSON
122
+
123
+ event = json_data.get("event", None)
124
+ if event:
125
+ if self.__session_type == "agent" and event not in {"message", "message_end"}:
126
+ continue
127
+ if self.__session_type == "chat" and event != "message":
128
+ continue
129
+
130
+ if self.__session_type == "chat" and json_data.get("data") is True:
131
+ return
132
+ if self.__session_type == "agent":
133
+ message = self._structure_answer(json_data)
134
+ if event == "message_end":
135
+ message.content = ""
136
+ if message.reference:
137
+ yield message
138
+ continue
139
+ yield message
140
+ else:
141
+ yield self._structure_answer(json_data["data"])
142
+ else:
143
+ try:
144
+ json_data = res.json()
145
+ except ValueError:
146
+ raise Exception(f"Invalid response {res}")
147
+ yield self._structure_answer(json_data["data"])
148
+
149
+ def _structure_answer(self, json_data):
150
+ answer = ""
151
+ event = None
152
+ if self.__session_type == "agent":
153
+ event = json_data.get("event")
154
+ json_data = json_data["data"]
155
+ answer = json_data.get("content", "")
156
+ elif self.__session_type == "chat":
157
+ answer = json_data["answer"]
158
+ reference = json_data.get("reference", {})
159
+ temp_dict = {"content": answer, "role": "assistant"}
160
+ if reference and "chunks" in reference:
161
+ chunks = reference["chunks"]
162
+ if isinstance(chunks, dict):
163
+ chunks = list(chunks.values())
164
+ temp_dict["reference"] = chunks
165
+ if self.__session_type == "agent":
166
+ reference_count = len(chunks) if isinstance(chunks, list) else 0
167
+ logger.debug("Session.ask parsed agent references session_id=%s event=%s reference_count=%s", self.id, event, reference_count)
168
+ message = Message(self.rag, temp_dict)
169
+ return message
170
+
171
+ def _ask_chat(self, question: str, stream: bool, **kwargs):
172
+ json_data = {"question": question, "stream": stream, "session_id": self.id}
173
+ json_data.update(kwargs)
174
+ res = self.post(f"/chats/{self.chat_id}/completions", json_data, stream=stream)
175
+ return res
176
+
177
+ def _ask_agent(self, question: str, stream: bool, **kwargs):
178
+ json_data = {
179
+ "agent_id": self.agent_id,
180
+ "query": question,
181
+ "stream": stream,
182
+ "session_id": self.id,
183
+ "openai-compatible": False,
184
+ }
185
+ json_data.update(kwargs)
186
+ res = self.post("/agents/chat/completions", json_data, stream=stream)
187
+ return res
188
+
189
+ def update(self, update_message):
190
+ res = self.patch(f"/chats/{self.chat_id}/sessions/{self.id}", update_message)
191
+ res = res.json()
192
+ if res.get("code") != 0:
193
+ raise Exception(res.get("message"))
194
+
195
+
196
+ class Message(Base):
197
+ def __init__(self, rag, res_dict):
198
+ self.content = "Hi! I am your assistant, can I help you?"
199
+ self.reference = None
200
+ self.role = "assistant"
201
+ self.prompt = None
202
+ self.id = None
203
+ super().__init__(rag, res_dict)
ragflow_sdk/ragflow.py ADDED
@@ -0,0 +1,398 @@
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 typing import Optional, Any
17
+
18
+ import requests
19
+
20
+ from .modules.agent import Agent
21
+ from .modules.chat import Chat
22
+ from .modules.chunk import Chunk
23
+ from .modules.dataset import DataSet
24
+ from .modules.memory import Memory
25
+
26
+
27
+ class RAGFlow:
28
+ def __init__(self, api_key, base_url, version="v1"):
29
+ """
30
+ api_url: http://<host_address>/api/v1
31
+ """
32
+ self.user_key = api_key
33
+ self.api_url = f"{base_url}/api/{version}"
34
+ self.authorization_header = {"Authorization": "{} {}".format("Bearer", self.user_key)}
35
+
36
+ def post(self, path, json=None, stream=False, files=None):
37
+ res = requests.post(url=self.api_url + path, json=json, headers=self.authorization_header, stream=stream, files=files)
38
+ return res
39
+
40
+ def get(self, path, params=None, json=None):
41
+ res = requests.get(url=self.api_url + path, params=params, headers=self.authorization_header, json=json)
42
+ return res
43
+
44
+ def delete(self, path, json):
45
+ res = requests.delete(url=self.api_url + path, json=json, headers=self.authorization_header)
46
+ return res
47
+
48
+ def put(self, path, json):
49
+ res = requests.put(url=self.api_url + path, json=json, headers=self.authorization_header)
50
+ return res
51
+
52
+ def patch(self, path, json):
53
+ res = requests.patch(url=self.api_url + path, json=json, headers=self.authorization_header)
54
+ return res
55
+
56
+ def create_dataset(
57
+ self,
58
+ name: str,
59
+ avatar: Optional[str] = None,
60
+ description: Optional[str] = None,
61
+ embedding_model: Optional[str] = None,
62
+ permission: str = "me",
63
+ chunk_method: str = "naive",
64
+ parser_config: Optional[DataSet.ParserConfig] = None,
65
+ auto_metadata_config: Optional[dict[str, Any]] = None,
66
+ ) -> DataSet:
67
+ payload = {
68
+ "name": name,
69
+ "avatar": avatar,
70
+ "description": description,
71
+ "embedding_model": embedding_model,
72
+ "permission": permission,
73
+ "chunk_method": chunk_method,
74
+ }
75
+ if parser_config is not None:
76
+ payload["parser_config"] = parser_config.to_json()
77
+ if auto_metadata_config is not None:
78
+ payload["auto_metadata_config"] = auto_metadata_config
79
+
80
+ res = self.post("/datasets", payload)
81
+ res = res.json()
82
+ if res.get("code") == 0:
83
+ return DataSet(self, res["data"])
84
+ raise Exception(res["message"])
85
+
86
+ def delete_datasets(self, ids: list[str] | None = None, delete_all: bool = False):
87
+ res = self.delete("/datasets", {"ids": ids, "delete_all": delete_all})
88
+ res = res.json()
89
+ if res.get("code") != 0:
90
+ raise Exception(res["message"])
91
+
92
+ def get_dataset(self, name: str):
93
+ _list = self.list_datasets(name=name)
94
+ if len(_list) > 0:
95
+ return _list[0]
96
+ raise Exception("Dataset %s not found" % name)
97
+
98
+ def list_datasets(
99
+ self, page: int = 1, page_size: int = 30, orderby: str = "create_time", desc: bool = True, id: str | None = None, ids: list[str] | None = None, name: str | None = None
100
+ ) -> list[DataSet]:
101
+ if id and ids:
102
+ raise ValueError("Cannot use both 'id' and 'ids' parameters at the same time.")
103
+
104
+ res = self.get(
105
+ "/datasets",
106
+ {
107
+ "page": page,
108
+ "page_size": page_size,
109
+ "orderby": orderby,
110
+ "desc": desc,
111
+ "id": id,
112
+ "ids": ids,
113
+ "name": name,
114
+ },
115
+ )
116
+ res = res.json()
117
+ result_list = []
118
+ if res.get("code") == 0:
119
+ for data in res["data"]:
120
+ result_list.append(DataSet(self, data))
121
+ return result_list
122
+ raise Exception(res["message"])
123
+
124
+ def create_chat(
125
+ self,
126
+ name: str,
127
+ icon: str = "",
128
+ dataset_ids: list[str] | None = None,
129
+ llm_id: str | None = None,
130
+ llm_setting: dict | None = None,
131
+ prompt_config: dict | None = None,
132
+ **kwargs,
133
+ ) -> Chat:
134
+ payload = {"name": name, "icon": icon, "dataset_ids": dataset_ids or []}
135
+ if llm_id is not None:
136
+ payload["llm_id"] = llm_id
137
+ if llm_setting is not None:
138
+ payload["llm_setting"] = llm_setting
139
+ if prompt_config is not None:
140
+ payload["prompt_config"] = prompt_config
141
+ payload.update(kwargs)
142
+ res = self.post("/chats", payload)
143
+ res = res.json()
144
+ if res.get("code") == 0:
145
+ return Chat(self, res["data"])
146
+ raise Exception(res["message"])
147
+
148
+ def delete_chats(self, ids: list[str] | None = None, delete_all: bool = False):
149
+ res = self.delete("/chats", {"ids": ids, "delete_all": delete_all})
150
+ res = res.json()
151
+ if res.get("code") != 0:
152
+ raise Exception(res["message"])
153
+
154
+ def get_chat(self, chat_id: str) -> Chat:
155
+ res = self.get(f"/chats/{chat_id}")
156
+ res = res.json()
157
+ if res.get("code") == 0:
158
+ return Chat(self, res["data"])
159
+ raise Exception(res["message"])
160
+
161
+ def list_chats(
162
+ self,
163
+ page: int = 1,
164
+ page_size: int = 30,
165
+ orderby: str = "create_time",
166
+ desc: bool = True,
167
+ id: str | None = None,
168
+ name: str | None = None,
169
+ keywords: str | None = None,
170
+ owner_ids: str | list[str] | None = None,
171
+ ) -> list[Chat]:
172
+ res = self.get(
173
+ "/chats",
174
+ {
175
+ "page": page,
176
+ "page_size": page_size,
177
+ "orderby": orderby,
178
+ "desc": desc,
179
+ "id": id,
180
+ "name": name,
181
+ "keywords": keywords,
182
+ "owner_ids": owner_ids,
183
+ },
184
+ )
185
+ res = res.json()
186
+ result_list = []
187
+ if res.get("code") == 0:
188
+ for data in res["data"]["chats"]:
189
+ result_list.append(Chat(self, data))
190
+ return result_list
191
+ raise Exception(res["message"])
192
+
193
+ def retrieve(
194
+ self,
195
+ dataset_ids,
196
+ document_ids=None,
197
+ question="",
198
+ page=1,
199
+ page_size=30,
200
+ similarity_threshold=0.2,
201
+ vector_similarity_weight=0.3,
202
+ top_k=1024,
203
+ rerank_id: str | None = None,
204
+ keyword: bool = False,
205
+ cross_languages: list[str] | None = None,
206
+ metadata_condition: dict | None = None,
207
+ use_kg: bool = False,
208
+ toc_enhance: bool = False,
209
+ ):
210
+ if document_ids is None:
211
+ document_ids = []
212
+ data_json = {
213
+ "page": page,
214
+ "page_size": page_size,
215
+ "similarity_threshold": similarity_threshold,
216
+ "vector_similarity_weight": vector_similarity_weight,
217
+ "top_k": top_k,
218
+ "rerank_id": rerank_id,
219
+ "keyword": keyword,
220
+ "question": question,
221
+ "dataset_ids": dataset_ids,
222
+ "document_ids": document_ids,
223
+ "cross_languages": cross_languages,
224
+ "metadata_condition": metadata_condition,
225
+ "use_kg": use_kg,
226
+ "toc_enhance": toc_enhance,
227
+ }
228
+ # Send a POST request to the backend service (using requests library as an example, actual implementation may vary)
229
+ res = self.post("/retrieval", json=data_json)
230
+ res = res.json()
231
+ if res.get("code") == 0:
232
+ chunks = []
233
+ for chunk_data in res["data"].get("chunks"):
234
+ chunk = Chunk(self, chunk_data)
235
+ chunks.append(chunk)
236
+ return chunks
237
+ raise Exception(res.get("message"))
238
+
239
+ def list_agents(self, page: int = 1, page_size: int = 30, orderby: str = "update_time", desc: bool = True) -> list[Agent]:
240
+ res = self.get(
241
+ "/agents",
242
+ {
243
+ "page": page,
244
+ "page_size": page_size,
245
+ "orderby": orderby,
246
+ "desc": desc,
247
+ },
248
+ )
249
+ res = res.json()
250
+ result_list = []
251
+ if res.get("code") == 0:
252
+ data = res.get("data") or {}
253
+ data_list = data.get("canvas", [])
254
+ for data in data_list:
255
+ result_list.append(Agent(self, data))
256
+ return result_list
257
+ raise Exception(res["message"])
258
+
259
+ def get_agent(self, agent_id: str) -> Agent:
260
+ res = self.get(f"/agents/{agent_id}")
261
+ res = res.json()
262
+ if res.get("code") == 0:
263
+ return Agent(self, res["data"])
264
+ raise Exception(res["message"])
265
+
266
+ def create_agent(
267
+ self,
268
+ title: str,
269
+ dsl: dict,
270
+ description: str | None = None,
271
+ canvas_type: str | None = None,
272
+ ) -> None:
273
+ req = {"title": title, "dsl": dsl}
274
+
275
+ if description is not None:
276
+ req["description"] = description
277
+
278
+ if canvas_type is not None:
279
+ req["canvas_type"] = canvas_type
280
+
281
+ res = self.post("/agents", req)
282
+ res = res.json()
283
+
284
+ if res.get("code") != 0:
285
+ raise Exception(res["message"])
286
+
287
+ def update_agent(
288
+ self,
289
+ agent_id: str,
290
+ title: str | None = None,
291
+ description: str | None = None,
292
+ dsl: dict | None = None,
293
+ canvas_type: str | None = None,
294
+ ) -> None:
295
+ req = {}
296
+
297
+ if title is not None:
298
+ req["title"] = title
299
+
300
+ if description is not None:
301
+ req["description"] = description
302
+
303
+ if dsl is not None:
304
+ req["dsl"] = dsl
305
+
306
+ if canvas_type is not None:
307
+ req["canvas_type"] = canvas_type
308
+
309
+ res = self.put(f"/agents/{agent_id}", req)
310
+ res = res.json()
311
+
312
+ if res.get("code") != 0:
313
+ raise Exception(res["message"])
314
+
315
+ def delete_agent(self, agent_id: str) -> None:
316
+ res = self.delete(f"/agents/{agent_id}", {})
317
+ res = res.json()
318
+
319
+ if res.get("code") != 0:
320
+ raise Exception(res["message"])
321
+
322
+ def create_memory(self, name: str, memory_type: list[str], embd_id: str, llm_id: str):
323
+ payload = {"name": name, "memory_type": memory_type, "embd_id": embd_id, "llm_id": llm_id}
324
+ res = self.post("/memories", payload)
325
+ res = res.json()
326
+ if res.get("code") != 0:
327
+ raise Exception(res["message"])
328
+ return Memory(self, res["data"])
329
+
330
+ def list_memory(self, page: int = 1, page_size: int = 50, tenant_id: str | list[str] = None, memory_type: str | list[str] = None, storage_type: str = None, keywords: str = None) -> dict:
331
+ res = self.get(
332
+ "/memories",
333
+ {
334
+ "page": page,
335
+ "page_size": page_size,
336
+ "tenant_id": tenant_id,
337
+ "memory_type": memory_type,
338
+ "storage_type": storage_type,
339
+ "keywords": keywords,
340
+ },
341
+ )
342
+ res = res.json()
343
+ if res.get("code") != 0:
344
+ raise Exception(res["message"])
345
+ result_list = []
346
+ for data in res["data"]["memory_list"]:
347
+ result_list.append(Memory(self, data))
348
+ return {"code": res.get("code", 0), "message": res.get("message"), "memory_list": result_list, "total_count": res["data"]["total_count"]}
349
+
350
+ def delete_memory(self, memory_id: str):
351
+ res = self.delete(f"/memories/{memory_id}", {})
352
+ res = res.json()
353
+ if res.get("code") != 0:
354
+ raise Exception(res["message"])
355
+
356
+ def add_message(self, memory_id: list[str], agent_id: str, session_id: str, user_input: str, agent_response: str, user_id: str = "") -> str:
357
+ """Append messages to memories; ``user_id`` is forwarded only for API-key auth (external subject)."""
358
+ payload = {"memory_id": memory_id, "agent_id": agent_id, "session_id": session_id, "user_input": user_input, "agent_response": agent_response, "user_id": user_id}
359
+ res = self.post("/messages", payload)
360
+ res = res.json()
361
+ if res.get("code") != 0:
362
+ raise Exception(res["message"])
363
+ return res["message"]
364
+
365
+ def search_message(
366
+ self,
367
+ query: str,
368
+ memory_id: list[str],
369
+ agent_id: str = None,
370
+ session_id: str = None,
371
+ user_id: str = None,
372
+ similarity_threshold: float = 0.2,
373
+ keywords_similarity_weight: float = 0.7,
374
+ top_n: int = 10,
375
+ ) -> list[dict]:
376
+ params = {
377
+ "query": query,
378
+ "memory_id": memory_id,
379
+ "agent_id": agent_id,
380
+ "session_id": session_id,
381
+ "user_id": user_id,
382
+ "similarity_threshold": similarity_threshold,
383
+ "keywords_similarity_weight": keywords_similarity_weight,
384
+ "top_n": top_n,
385
+ }
386
+ res = self.get("/messages/search", params)
387
+ res = res.json()
388
+ if res.get("code") != 0:
389
+ raise Exception(res["message"])
390
+ return res["data"]
391
+
392
+ def get_recent_messages(self, memory_id: list[str], agent_id: str = None, session_id: str = None, limit: int = 10) -> list[dict]:
393
+ params = {"memory_id": memory_id, "agent_id": agent_id, "session_id": session_id, "limit": limit}
394
+ res = self.get("/messages", params)
395
+ res = res.json()
396
+ if res.get("code") != 0:
397
+ raise Exception(res["message"])
398
+ return res["data"]
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: ragflow-sdk-myfbee-test
3
+ Version: 1.0.1.dev0
4
+ Summary: Python client sdk of [RAGFlow](https://github.com/infiniflow/ragflow). RAGFlow is an open-source RAG (Retrieval-Augmented Generation) engine based on deep document understanding.
5
+ Author-email: Zhichang Yu <yuzhichang@gmail.com>
6
+ License: Apache License, Version 2.0
7
+ Requires-Python: <3.14,>=3.13
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests<3.0.0,>=2.30.0
10
+ Requires-Dist: beartype<1.0.0,>=0.20.0
@@ -0,0 +1,15 @@
1
+ ragflow_sdk/__init__.py,sha256=ql_QJdp4vDpQ82flx5mdaQVX-Jn1ExmN_lYfPKGuaS4,1319
2
+ ragflow_sdk/ragflow.py,sha256=lVbpO1JHr8KNB9aDpkdfq967tbuXkIG-N7x4dPJo0oQ,13954
3
+ ragflow_sdk/modules/__init__.py,sha256=UQpEQcTBGyFrQsFf8jsVbreWSQA39-TPtgjjtoOpyQY,622
4
+ ragflow_sdk/modules/agent.py,sha256=ocygkPNRm44GKVozpSCe6eOvkXhMao6axpFMmZPd92E,2793
5
+ ragflow_sdk/modules/base.py,sha256=uBGd7yUFqfobmdhsWmP-nqNFmYwvcW_juT1Gu3-Qw-4,1918
6
+ ragflow_sdk/modules/chat.py,sha256=v7hljH8DVBNmhJjKw7F9y-lhtu-CzZkTGuCiMpXaeak,2656
7
+ ragflow_sdk/modules/chunk.py,sha256=HAj7uRkaVTOow9Ozc_BlbLH-2p1zel-ucBsZs1T2VXc,2137
8
+ ragflow_sdk/modules/dataset.py,sha256=3JN_HWEu7h-IK9lUdSLkIWEw9ZyHgbUo86BugxlroUI,6503
9
+ ragflow_sdk/modules/document.py,sha256=tVk1bCuoOEOAPKHD_ULx0smZ04A52pmY2OGSF_6WAkU,4412
10
+ ragflow_sdk/modules/memory.py,sha256=6Gp140KJPd8mB0hdkIf0rCc_RjRqoA7S6d4glYu4pcE,3114
11
+ ragflow_sdk/modules/session.py,sha256=pRpIFuIX6TuF-EZcaYLzZLFDA1QmVkIClavXhER_EUY,7898
12
+ ragflow_sdk_myfbee_test-1.0.1.dev0.dist-info/METADATA,sha256=l0i24q3_1VVOzqOMFVLvEAEAqz3951lOnOcKSy6o4Hk,494
13
+ ragflow_sdk_myfbee_test-1.0.1.dev0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
14
+ ragflow_sdk_myfbee_test-1.0.1.dev0.dist-info/top_level.txt,sha256=ep9RG2ggpS-qOwUXbtEbjfVyi6mVgQ407otRgO-xNdA,12
15
+ ragflow_sdk_myfbee_test-1.0.1.dev0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ ragflow_sdk