ragflow-cli 0.25.0.dev6__tar.gz → 0.25.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragflow-cli
3
- Version: 0.25.0.dev6
3
+ Version: 0.25.2
4
4
  Summary: Admin Service's client of [RAGFlow](https://github.com/infiniflow/ragflow). The Admin Service provides user management and system monitoring.
5
5
  Author-email: Lynn <lynn_inf@hotmail.com>
6
6
  License: Apache License, Version 2.0
@@ -62,7 +62,7 @@ It consists of a server-side Service and a command-line client (CLI), both imple
62
62
  1. Ensure the Admin Service is running.
63
63
  2. Install ragflow-cli.
64
64
  ```bash
65
- pip install ragflow-cli==0.24.0
65
+ pip install ragflow-cli==0.25.2
66
66
  ```
67
67
  3. Launch the CLI client:
68
68
  ```bash
@@ -48,7 +48,7 @@ It consists of a server-side Service and a command-line client (CLI), both imple
48
48
  1. Ensure the Admin Service is running.
49
49
  2. Install ragflow-cli.
50
50
  ```bash
51
- pip install ragflow-cli==0.24.0
51
+ pip install ragflow-cli==0.25.2
52
52
  ```
53
53
  3. Launch the CLI client:
54
54
  ```bash
@@ -77,10 +77,17 @@ sql_command: login_user
77
77
  | drop_user_dataset
78
78
  | list_user_datasets
79
79
  | list_user_dataset_files
80
+ | list_user_dataset_documents
81
+ | list_user_datasets_metadata
82
+ | list_user_documents_metadata_summary
80
83
  | list_user_agents
81
84
  | list_user_chats
82
85
  | create_user_chat
83
86
  | drop_user_chat
87
+ | create_dataset_table
88
+ | drop_dataset_table
89
+ | create_metadata_table
90
+ | drop_metadata_table
84
91
  | list_user_model_providers
85
92
  | list_user_default_models
86
93
  | parse_dataset_docs
@@ -88,6 +95,14 @@ sql_command: login_user
88
95
  | parse_dataset_async
89
96
  | import_docs_into_dataset
90
97
  | search_on_datasets
98
+ | get_chunk
99
+ | list_chunks
100
+ | insert_dataset_from_file
101
+ | insert_metadata_from_file
102
+ | update_chunk
103
+ | set_metadata
104
+ | remove_tags
105
+ | remove_chunks
91
106
  | create_chat_session
92
107
  | drop_chat_session
93
108
  | list_chat_sessions
@@ -103,10 +118,12 @@ sql_command: login_user
103
118
  // meta command definition
104
119
  meta_command: "\\" meta_command_name [meta_args]
105
120
 
121
+ COMMA: ","
122
+
106
123
  meta_command_name: /[a-zA-Z?]+/
107
124
  meta_args: (meta_arg)+
108
125
 
109
- meta_arg: /[^\\s"']+/ | quoted_string
126
+ meta_arg: /[^\s"',]+/ | quoted_string
110
127
 
111
128
  // command definition
112
129
 
@@ -127,6 +144,7 @@ ALTER: "ALTER"i
127
144
  ACTIVE: "ACTIVE"i
128
145
  ADMIN: "ADMIN"i
129
146
  PASSWORD: "PASSWORD"i
147
+ DATASET_TABLE: "DATASET TABLE"i
130
148
  DATASET: "DATASET"i
131
149
  DATASETS: "DATASETS"i
132
150
  OF: "OF"i
@@ -161,11 +179,18 @@ DEFAULT: "DEFAULT"i
161
179
  CHATS: "CHATS"i
162
180
  CHAT: "CHAT"i
163
181
  FILES: "FILES"i
182
+ DOCUMENT: "DOCUMENT"i
183
+ DOCUMENTS: "DOCUMENTS"i
184
+ METADATA: "METADATA"i
185
+ SUMMARY: "SUMMARY"i
164
186
  AS: "AS"i
165
187
  PARSE: "PARSE"i
166
188
  IMPORT: "IMPORT"i
167
189
  INTO: "INTO"i
190
+ IN: "IN"i
168
191
  WITH: "WITH"i
192
+ VECTOR: "VECTOR"i
193
+ SIZE: "SIZE"i
169
194
  PARSER: "PARSER"i
170
195
  PIPELINE: "PIPELINE"i
171
196
  SEARCH: "SEARCH"i
@@ -187,8 +212,21 @@ FINGERPRINT: "FINGERPRINT"i
187
212
  LICENSE: "LICENSE"i
188
213
  CHECK: "CHECK"i
189
214
  CONFIG: "CONFIG"i
190
-
191
- login_user: LOGIN USER quoted_string ";"
215
+ INDEX: "INDEX"i
216
+ TABLE: "TABLE"i
217
+ CHUNK: "CHUNK"i
218
+ CHUNKS: "CHUNKS"i
219
+ GET: "GET"i
220
+ INSERT: "INSERT"i
221
+ PAGE: "PAGE"i
222
+ KEYWORDS: "KEYWORDS"i
223
+ AVAILABLE: "AVAILABLE"i
224
+ FILE: "FILE"i
225
+ UPDATE: "UPDATE"i
226
+ REMOVE: "REMOVE"i
227
+ TAGS: "TAGS"i
228
+
229
+ login_user: LOGIN USER quoted_string (PASSWORD quoted_string)? ";"
192
230
  list_services: LIST SERVICES ";"
193
231
  show_service: SHOW SERVICE NUMBER ";"
194
232
  startup_service: STARTUP SERVICE NUMBER ";"
@@ -271,6 +309,9 @@ user_statement: ping_server
271
309
  | list_user_default_models
272
310
  | import_docs_into_dataset
273
311
  | search_on_datasets
312
+ | update_chunk
313
+ | set_metadata
314
+ | remove_tags
274
315
  | create_chat_session
275
316
  | drop_chat_session
276
317
  | list_chat_sessions
@@ -299,6 +340,9 @@ create_user_dataset_with_parser: CREATE DATASET quoted_string WITH EMBEDDING quo
299
340
  create_user_dataset_with_pipeline: CREATE DATASET quoted_string WITH EMBEDDING quoted_string PIPELINE quoted_string ";"
300
341
  drop_user_dataset: DROP DATASET quoted_string ";"
301
342
  list_user_dataset_files: LIST FILES OF DATASET quoted_string ";"
343
+ list_user_dataset_documents: LIST DOCUMENTS OF DATASET quoted_string ";"
344
+ list_user_datasets_metadata: LIST METADATA OF DATASETS quoted_string (COMMA quoted_string)* ";"
345
+ list_user_documents_metadata_summary: LIST METADATA SUMMARY OF DATASET quoted_string (DOCUMENTS quoted_string (COMMA quoted_string)*)? ";"
302
346
  list_user_agents: LIST AGENTS ";"
303
347
  list_user_chats: LIST CHATS ";"
304
348
  create_user_chat: CREATE CHAT quoted_string ";"
@@ -311,12 +355,27 @@ list_user_model_providers: LIST MODEL PROVIDERS ";"
311
355
  list_user_default_models: LIST DEFAULT MODELS ";"
312
356
  import_docs_into_dataset: IMPORT quoted_string INTO DATASET quoted_string ";"
313
357
  search_on_datasets: SEARCH quoted_string ON DATASETS quoted_string ";"
358
+ get_chunk: GET CHUNK quoted_string ";"
359
+ list_chunks: LIST CHUNKS OF DOCUMENT quoted_string ("PAGE" NUMBER)? ("SIZE" NUMBER)? ("KEYWORDS" quoted_string)? ("AVAILABLE" NUMBER)? ";"
360
+ set_metadata: SET METADATA OF DOCUMENT quoted_string TO quoted_string ";"
361
+ remove_tags: REMOVE TAGS quoted_string (COMMA quoted_string)* FROM DATASET quoted_string ";"
362
+ remove_chunks: REMOVE CHUNKS quoted_string (COMMA quoted_string)* FROM DOCUMENT quoted_string ";"
363
+ | REMOVE ALL CHUNKS FROM DOCUMENT quoted_string ";"
314
364
 
315
365
  parse_dataset_docs: PARSE quoted_string OF DATASET quoted_string ";"
316
366
  parse_dataset_sync: PARSE DATASET quoted_string SYNC ";"
317
367
  parse_dataset_async: PARSE DATASET quoted_string ASYNC ";"
318
368
 
319
- identifier_list: identifier ("," identifier)*
369
+ // Internal CLI only for GO
370
+ create_dataset_table: CREATE DATASET TABLE quoted_string VECTOR SIZE NUMBER ";"
371
+ drop_dataset_table: DROP DATASET TABLE quoted_string ";"
372
+ create_metadata_table: CREATE METADATA TABLE ";"
373
+ drop_metadata_table: DROP METADATA TABLE ";"
374
+ insert_dataset_from_file: INSERT DATASET FROM FILE quoted_string ";"
375
+ insert_metadata_from_file: INSERT METADATA FROM FILE quoted_string ";"
376
+ update_chunk: UPDATE CHUNK quoted_string OF DATASET quoted_string SET quoted_string ";"
377
+
378
+ identifier_list: identifier (COMMA identifier)*
320
379
 
321
380
  identifier: WORD
322
381
  quoted_string: QUOTED_STRING
@@ -340,7 +399,13 @@ class RAGFlowCLITransformer(Transformer):
340
399
 
341
400
  def login_user(self, items):
342
401
  email = items[2].children[0].strip("'\"")
343
- return {"type": "login_user", "email": email}
402
+ if len(items) == 5:
403
+ # With password: LOGIN USER email PASSWORD password
404
+ password = items[4].children[0].strip("'\"")
405
+ return {"type": "login_user", "email": email, "password": password}
406
+ else:
407
+ # Without password: LOGIN USER email
408
+ return {"type": "login_user", "email": email}
344
409
 
345
410
  def ping_server(self, items):
346
411
  return {"type": "ping_server"}
@@ -592,6 +657,28 @@ class RAGFlowCLITransformer(Transformer):
592
657
  dataset_name = items[4].children[0].strip("'\"")
593
658
  return {"type": "list_user_dataset_files", "dataset_name": dataset_name}
594
659
 
660
+ def list_user_dataset_documents(self, items):
661
+ dataset_name = items[4].children[0].strip("'\"")
662
+ return {"type": "list_user_dataset_documents", "dataset_name": dataset_name}
663
+
664
+ def list_user_datasets_metadata(self, items):
665
+ dataset_names = []
666
+ dataset_names.append(items[4].children[0].strip("'\""))
667
+ for i in range(5, len(items)):
668
+ if items[i] and hasattr(items[i], 'children') and items[i].children:
669
+ dataset_names.append(items[i].children[0].strip("'\""))
670
+ return {"type": "list_user_datasets_metadata", "dataset_names": dataset_names}
671
+
672
+ def list_user_documents_metadata_summary(self, items):
673
+ dataset_name = items[5].children[0].strip("'\"")
674
+ doc_ids = []
675
+ if len(items) > 6 and items[6] == "DOCUMENTS":
676
+ for i in range(7, len(items)):
677
+ if items[i] and hasattr(items[i], 'children') and items[i].children:
678
+ doc_id = items[i].children[0].strip("'\"")
679
+ doc_ids.append(doc_id)
680
+ return {"type": "list_user_documents_metadata_summary", "dataset_name": dataset_name, "document_ids": doc_ids}
681
+
595
682
  def list_user_agents(self, items):
596
683
  return {"type": "list_user_agents"}
597
684
 
@@ -606,6 +693,30 @@ class RAGFlowCLITransformer(Transformer):
606
693
  chat_name = items[2].children[0].strip("'\"")
607
694
  return {"type": "drop_user_chat", "chat_name": chat_name}
608
695
 
696
+ def create_dataset_table(self, items):
697
+ dataset_name = None
698
+ vector_size = None
699
+ for i, item in enumerate(items):
700
+ if hasattr(item, 'data') and item.data == 'quoted_string':
701
+ dataset_name = item.children[0].strip("'\"")
702
+ if hasattr(item, 'type') and item.type == 'NUMBER':
703
+ if i > 0 and items[i-1].type == 'SIZE' and items[i-2].type == 'VECTOR':
704
+ vector_size = int(item)
705
+ return {"type": "create_dataset_table", "dataset_name": dataset_name, "vector_size": vector_size}
706
+
707
+ def drop_dataset_table(self, items):
708
+ dataset_name = None
709
+ for item in items:
710
+ if hasattr(item, 'data') and item.data == 'quoted_string':
711
+ dataset_name = item.children[0].strip("'\"")
712
+ return {"type": "drop_dataset_table", "dataset_name": dataset_name}
713
+
714
+ def create_metadata_table(self, items):
715
+ return {"type": "create_metadata_table"}
716
+
717
+ def drop_metadata_table(self, items):
718
+ return {"type": "drop_metadata_table"}
719
+
609
720
  def list_user_model_providers(self, items):
610
721
  return {"type": "list_user_model_providers"}
611
722
 
@@ -666,6 +777,103 @@ class RAGFlowCLITransformer(Transformer):
666
777
  datasets = datasets.split(" ")
667
778
  return {"type": "search_on_datasets", "datasets": datasets, "question": question}
668
779
 
780
+ def get_chunk(self, items):
781
+ chunk_id = items[2].children[0].strip("'\"")
782
+ return {"type": "get_chunk", "chunk_id": chunk_id}
783
+
784
+ def insert_dataset_from_file(self, items):
785
+ file_path = items[4].children[0].strip("'\"")
786
+ return {"type": "insert_dataset_from_file", "file_path": file_path}
787
+
788
+ def insert_metadata_from_file(self, items):
789
+ file_path = items[4].children[0].strip("'\"")
790
+ return {"type": "insert_metadata_from_file", "file_path": file_path}
791
+
792
+ def update_chunk(self, items):
793
+ def get_quoted_value(item):
794
+ if hasattr(item, 'children') and item.children:
795
+ return item.children[0].strip("'\"")
796
+ return str(item).strip("'\"")
797
+
798
+ chunk_id = get_quoted_value(items[2])
799
+ dataset_name = get_quoted_value(items[5])
800
+ json_body = get_quoted_value(items[7])
801
+ return {"type": "update_chunk", "chunk_id": chunk_id, "dataset_name": dataset_name, "json_body": json_body}
802
+
803
+ def set_metadata(self, items):
804
+ doc_id = items[4].children[0].strip("'\"")
805
+ meta_json = items[6].children[0].strip("'\"")
806
+ return {"type": "set_metadata", "doc_id": doc_id, "meta": meta_json}
807
+
808
+ def remove_tags(self, items):
809
+ # items: REMOVE, TAGS, quoted_string(tag1), quoted_string(tag2), ..., FROM, DATASET, quoted_string(dataset_name), ";"
810
+ tags = []
811
+ # Start from index 2 (after TAGS keyword) and parse quoted strings until FROM
812
+ for i in range(2, len(items)):
813
+ item = items[i]
814
+ # Check for FROM token to stop
815
+ if hasattr(item, 'type') and item.type == 'FROM':
816
+ break
817
+ if hasattr(item, 'children') and item.children:
818
+ tag = item.children[0].strip("'\"")
819
+ tags.append(tag)
820
+ # Find dataset_name: quoted_string after DATASET
821
+ dataset_name = None
822
+ for i, item in enumerate(items):
823
+ # Check if item is a DATASET token
824
+ if hasattr(item, 'type') and item.type == 'DATASET':
825
+ # Next item should be quoted_string
826
+ dataset_name = items[i + 1].children[0].strip("'\"")
827
+ break
828
+ return {"type": "remove_tags", "dataset_name": dataset_name, "tags": tags}
829
+
830
+ def remove_chunks(self, items):
831
+ # Handle two cases:
832
+ # 1. REMOVE CHUNKS quoted_string (COMMA quoted_string)* FROM DOCUMENT quoted_string ";"
833
+ # 2. REMOVE ALL CHUNKS FROM DOCUMENT quoted_string ";"
834
+
835
+ # Check if it's "REMOVE ALL CHUNKS"
836
+ for item in items:
837
+ if hasattr(item, 'type') and item.type == 'ALL':
838
+ # Find doc_id
839
+ for j, inner_item in enumerate(items):
840
+ if hasattr(inner_item, 'type') and inner_item.type == 'DOCUMENT':
841
+ doc_id = items[j + 1].children[0].strip("'\"")
842
+ return {"type": "remove_chunks", "doc_id": doc_id, "delete_all": True}
843
+
844
+ # Otherwise, we have chunk_ids
845
+ chunk_ids = []
846
+ doc_id = None
847
+ for i, item in enumerate(items):
848
+ if hasattr(item, 'type') and item.type == 'DOCUMENT':
849
+ doc_id = items[i + 1].children[0].strip("'\"")
850
+ elif hasattr(item, 'children') and item.children:
851
+ val = item.children[0].strip("'\"")
852
+ # Skip if it's "FROM" or "DOCUMENT"
853
+ if val.upper() in ['FROM', 'DOCUMENT']:
854
+ continue
855
+ chunk_ids.append(val)
856
+
857
+ return {"type": "remove_chunks", "doc_id": doc_id, "chunk_ids": chunk_ids}
858
+
859
+ def list_chunks(self, items):
860
+ doc_id = items[4].children[0].strip("'\"")
861
+ result = {"type": "list_chunks", "doc_id": doc_id}
862
+
863
+ # Parse optional parameters: PAGE, SIZE, KEYWORDS, AVAILABLE
864
+ # items structure varies based on which params are present
865
+ for i, item in enumerate(items):
866
+ if str(item) == "PAGE":
867
+ result["page"] = int(items[i + 1])
868
+ elif str(item) == "SIZE":
869
+ result["size"] = int(items[i + 1])
870
+ elif str(item) == "KEYWORDS":
871
+ result["keywords"] = items[i + 1].children[0].strip("'\"")
872
+ elif str(item) == "AVAILABLE":
873
+ result["available_int"] = int(items[i + 1])
874
+
875
+ return result
876
+
669
877
  def benchmark(self, items):
670
878
  concurrency: int = int(items[1])
671
879
  iterations: int = int(items[2])
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ragflow-cli"
3
- version = "0.25.0.dev6"
3
+ version = "0.25.2"
4
4
  description = "Admin Service's client of [RAGFlow](https://github.com/infiniflow/ragflow). The Admin Service provides user management and system monitoring. "
5
5
  authors = [{ name = "Lynn", email = "lynn_inf@hotmail.com" }]
6
6
  license = { text = "Apache License, Version 2.0" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragflow-cli
3
- Version: 0.25.0.dev6
3
+ Version: 0.25.2
4
4
  Summary: Admin Service's client of [RAGFlow](https://github.com/infiniflow/ragflow). The Admin Service provides user management and system monitoring.
5
5
  Author-email: Lynn <lynn_inf@hotmail.com>
6
6
  License: Apache License, Version 2.0
@@ -62,7 +62,7 @@ It consists of a server-side Service and a command-line client (CLI), both imple
62
62
  1. Ensure the Admin Service is running.
63
63
  2. Install ragflow-cli.
64
64
  ```bash
65
- pip install ragflow-cli==0.24.0
65
+ pip install ragflow-cli==0.25.2
66
66
  ```
67
67
  3. Launch the CLI client:
68
68
  ```bash
@@ -18,6 +18,9 @@ import sys
18
18
  import argparse
19
19
  import base64
20
20
  import getpass
21
+ import os
22
+ import atexit
23
+ import readline
21
24
  from cmd import Cmd
22
25
  from typing import Any, Dict, List
23
26
 
@@ -61,6 +64,12 @@ class RAGFlowCLI(Cmd):
61
64
  self.port: int = 0
62
65
  self.mode: str = "admin"
63
66
  self.ragflow_client = None
67
+ # History file for readline persistence
68
+ self.history_file = os.path.expanduser("~/.ragflow_cli_history")
69
+ # Load existing history
70
+ self._load_history()
71
+ # Register cleanup to save history on exit
72
+ atexit.register(self._save_history)
64
73
 
65
74
  intro = r"""Type "\h" for help."""
66
75
  prompt = "ragflow> "
@@ -99,6 +108,7 @@ class RAGFlowCLI(Cmd):
99
108
  return {"type": "empty"}
100
109
 
101
110
  self.command_history.append(command_str)
111
+ readline.add_history(command_str)
102
112
 
103
113
  try:
104
114
  result = self.parser.parse(command_str)
@@ -210,6 +220,21 @@ class RAGFlowCLI(Cmd):
210
220
 
211
221
  print(separator)
212
222
 
223
+ def _load_history(self):
224
+ """Load command history from file."""
225
+ try:
226
+ if os.path.exists(self.history_file):
227
+ readline.read_history_file(self.history_file)
228
+ except Exception:
229
+ pass # Ignore errors loading history
230
+
231
+ def _save_history(self):
232
+ """Save command history to file."""
233
+ try:
234
+ readline.write_history_file(self.history_file)
235
+ except Exception:
236
+ pass # Ignore errors saving history
237
+
213
238
  def run_interactive(self, args):
214
239
  if self.verify_auth(args, single_command=False, auth=args["auth"]):
215
240
  print(r"""