@@ -87,12 +87,47 @@ def run_command(command):
8787 except subprocess .CalledProcessError as e :
8888 return f"Error: { e .stderr } "
8989
90- def index_graph (root_dir ):
90+ def index_graph (root_dir , progress = gr . Progress () ):
9191 command = f"python -m graphrag.index --root { root_dir } "
9292 logging .info (f"Running indexing command: { command } " )
93- result = run_command (command )
93+
94+ # Create a queue to store the output
95+ output_queue = queue .Queue ()
96+
97+ def run_command_with_output ():
98+ process = subprocess .Popen (command , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , text = True )
99+ for line in iter (process .stdout .readline , '' ):
100+ output_queue .put (line )
101+ process .stdout .close ()
102+ process .wait ()
103+
104+ # Start the command in a separate thread
105+ thread = threading .Thread (target = run_command_with_output )
106+ thread .start ()
107+
108+ # Initialize progress
109+ progress (0 , desc = "Starting indexing..." )
110+
111+ # Process the output and update progress
112+ full_output = []
113+ while thread .is_alive () or not output_queue .empty ():
114+ try :
115+ line = output_queue .get_nowait ()
116+ full_output .append (line )
117+
118+ # Update progress based on the output
119+ if "Processing file" in line :
120+ progress ((0.5 , None ), desc = "Processing files..." )
121+ elif "Indexing completed" in line :
122+ progress (1 , desc = "Indexing completed" )
123+
124+ yield "\n " .join (full_output ), update_logs ()
125+ except queue .Empty :
126+ time .sleep (0.1 )
127+
128+ thread .join ()
94129 logging .info ("Indexing completed" )
95- return result , update_logs ()
130+ return " \n " . join ( full_output ) , update_logs ()
96131
97132def run_query (root_dir , method , query , history ):
98133 command = f"python -m graphrag.query --root { root_dir } --method { method } \" { query } \" "
@@ -121,7 +156,7 @@ def upload_file(file):
121156 # Get the updated file list
122157 updated_file_list = [f ["path" ] for f in list_input_files ()]
123158
124- return status , gr .Dropdown . update (choices = updated_file_list ), update_logs ()
159+ return status , gr .update (choices = updated_file_list ), update_logs ()
125160
126161def list_input_files ():
127162 input_dir = os .path .join ("ragtest" , "input" )
@@ -140,7 +175,7 @@ def delete_file(file_path):
140175 # Get the updated file list
141176 updated_file_list = [f ["path" ] for f in list_input_files ()]
142177
143- return status , gr .Dropdown . update (choices = updated_file_list ), update_logs ()
178+ return status , gr .update (choices = updated_file_list ), update_logs ()
144179
145180def read_file_content (file_path ):
146181 try :
@@ -208,7 +243,7 @@ def find_latest_graph_file(root_dir):
208243def update_visualization (root_dir , folder_name , file_name ):
209244 if not folder_name or not file_name :
210245 return None , "Please select a folder and a GraphML file."
211- file_name = file_name .split ("] " )[1 ] # Remove file type prefix
246+ file_name = file_name .split ("] " )[1 ] if "]" in file_name else file_name # Remove file type prefix
212247 graph_path = os .path .join (root_dir , "output" , folder_name , "artifacts" , file_name )
213248 if not graph_path .endswith ('.graphml' ):
214249 return None , "Please select a GraphML file for visualization."
@@ -275,9 +310,9 @@ def update_visualization(root_dir, folder_name, file_name):
275310 title = f'3D Graph Visualization: { os .path .basename (graph_path )} ' ,
276311 showlegend = False ,
277312 scene = dict (
278- xaxis = dict (showbackground = False ),
279- yaxis = dict (showbackground = False ),
280- zaxis = dict (showbackground = False )
313+ xaxis = dict (showbackground = False , showticklabels = False , title = '' ),
314+ yaxis = dict (showbackground = False , showticklabels = False , title = '' ),
315+ zaxis = dict (showbackground = False , showticklabels = False , title = '' )
281316 ),
282317 margin = dict (l = 0 , r = 0 , b = 0 , t = 40 ),
283318 annotations = [
@@ -289,11 +324,14 @@ def update_visualization(root_dir, folder_name, file_name):
289324 x = 0 ,
290325 y = 0
291326 )
292- ]
327+ ],
328+ autosize = True
293329 )
294330
295- # Return the Plotly figure instead of converting to image
296- return fig , f"Graph visualization generated successfully. Using file: { graph_path } "
331+ fig .update_layout (autosize = True )
332+ fig .update_layout (height = 600 ) # Set a fixed height
333+ config = {'responsive' : True }
334+ return fig , f"Graph visualization generated successfully. Using file: { graph_path } " , config
297335 except Exception as e :
298336 return None , f"Error visualizing graph: { str (e )} "
299337
@@ -335,7 +373,7 @@ def send_message(root_dir, query_type, query, history, system_message, temperatu
335373 else : # Direct chat
336374 result = chat_with_llm (query , history , system_message , temperature , max_tokens , model )
337375 history .append ((query , result ))
338- return history , gr .Textbox . update (value = "" ), update_logs ()
376+ return history , gr .update (value = "" ), update_logs ()
339377
340378def fetch_ollama_models ():
341379 try :
@@ -350,7 +388,7 @@ def fetch_ollama_models():
350388
351389def update_model_choices ():
352390 models = fetch_ollama_models ()
353- return gr .Dropdown . update (choices = models , value = models [0 ] if models else None )
391+ return gr .update (choices = models , value = models [0 ] if models else None )
354392
355393custom_css = """
356394html, body {
@@ -415,34 +453,26 @@ def update_model_choices():
415453 margin-top: 10px;
416454}
417455
418- #visualization-container {
419- height: 30%;
420- min-height: 200px;
421- display: flex;
422- flex-direction: column;
423- border: 2px solid var(--color-accent);
424- border-radius: 8px;
425- margin-top: 20px;
426- overflow: hidden;
427- }
428-
429456#visualization-plot {
430- flex: 1;
431- min-height: 0;
457+ width: 100%;
458+ aspect-ratio: 1 / 1;
459+ max-height: 600px; /* Adjust this value as needed */
432460}
433461
434- #vis-controls {
435- padding: 10px;
436- background-color: var(--color-foreground);
437- border-top: 1px solid var(--color-accent);
462+ #vis-controls-row {
463+ display: flex;
464+ justify-content: space-between;
465+ align-items: center;
466+ margin-top: 10px;
438467}
439468
440- #vis-controls .gr-button {
441- margin-bottom: 10px;
469+ #vis-controls-row > * {
470+ flex: 1;
471+ margin: 0 5px;
442472}
443473
444474#vis-status {
445- margin-top: 5px ;
475+ margin-top: 10px ;
446476}
447477
448478/* Chat input styling */
@@ -540,10 +570,35 @@ def update_model_choices():
540570}
541571
542572#visualization-container {
573+ display: flex;
574+ flex-direction: column;
543575 border: 2px solid var(--color-accent);
544576 border-radius: 8px;
545- padding: 10px;
546577 margin-top: 20px;
578+ padding: 10px;
579+ background-color: var(--color-foreground);
580+ height: calc(100vh - 300px); /* Adjust this value as needed */
581+ }
582+
583+ #visualization-plot {
584+ width: 100%;
585+ height: 100%;
586+ }
587+
588+ #vis-controls-row {
589+ display: flex;
590+ justify-content: space-between;
591+ align-items: center;
592+ margin-top: 10px;
593+ }
594+
595+ #vis-controls-row > * {
596+ flex: 1;
597+ margin: 0 5px;
598+ }
599+
600+ #vis-status {
601+ margin-top: 10px;
547602}
548603
549604#log-container {
@@ -590,7 +645,7 @@ def list_output_files(root_dir):
590645
591646def update_file_list ():
592647 files = list_input_files ()
593- return gr .Dropdown . update (choices = [f ["path" ] for f in files ])
648+ return gr .update (choices = [f ["path" ] for f in files ])
594649
595650def update_file_content (file_path ):
596651 if not file_path :
@@ -605,36 +660,41 @@ def update_file_content(file_path):
605660
606661def update_output_folder_list ():
607662 folders = list_output_folders (root_dir .value )
608- return gr .Dropdown . update (choices = folders , value = folders [0 ] if folders else None )
663+ return gr .update (choices = folders , value = folders [0 ] if folders else None )
609664
610665def update_folder_content_list (root_dir , folder_name ):
611666 if not folder_name :
612- return gr .Dropdown . update (choices = [])
667+ return gr .update (choices = [])
613668 contents = list_folder_contents (os .path .join (root_dir , "output" , folder_name ))
614- return gr .Dropdown . update (choices = contents )
669+ return gr .update (choices = contents )
615670
616671def handle_content_selection (root_dir , folder_name , selected_item ):
617- if selected_item .startswith ("[DIR]" ):
672+ if isinstance (selected_item , list ) and selected_item :
673+ selected_item = selected_item [0 ] # Take the first item if it's a list
674+
675+ if isinstance (selected_item , str ) and selected_item .startswith ("[DIR]" ):
618676 dir_name = selected_item [6 :] # Remove "[DIR] " prefix
619677 sub_contents = list_folder_contents (os .path .join (root_dir , "output" , folder_name , dir_name ))
620- return gr .Dropdown . update (choices = sub_contents ), "" , ""
621- else :
622- file_name = selected_item .split ("] " )[1 ] # Remove file type prefix
678+ return gr .update (choices = sub_contents ), "" , ""
679+ elif isinstance ( selected_item , str ) :
680+ file_name = selected_item .split ("] " )[1 ] if "]" in selected_item else selected_item # Remove file type prefix if present
623681 file_path = os .path .join (root_dir , "output" , folder_name , "artifacts" , file_name )
624682 file_size = os .path .getsize (file_path )
625683 file_type = os .path .splitext (file_name )[1 ]
626684 file_info = f"File: { file_name } \n Size: { file_size } bytes\n Type: { file_type } "
627685 content = read_file_content (file_path )
628- return gr .Dropdown .update (), file_info , content
686+ return gr .update (), file_info , content
687+ else :
688+ return gr .update (), "" , ""
629689
630690def initialize_selected_folder (root_dir , folder_name ):
631691 if not folder_name :
632- return "Please select a folder first." , gr .Dropdown . update (choices = [])
692+ return "Please select a folder first." , gr .update (choices = [])
633693 folder_path = os .path .join (root_dir , "output" , folder_name , "artifacts" )
634694 if not os .path .exists (folder_path ):
635- return f"Artifacts folder not found in '{ folder_name } '." , gr .Dropdown . update (choices = [])
695+ return f"Artifacts folder not found in '{ folder_name } '." , gr .update (choices = [])
636696 contents = list_folder_contents (folder_path )
637- return f"Folder '{ folder_name } /artifacts' initialized with { len (contents )} items." , gr .Dropdown . update (choices = contents )
697+ return f"Folder '{ folder_name } /artifacts' initialized with { len (contents )} items." , gr .update (choices = contents )
638698
639699def list_output_folders (root_dir ):
640700 output_dir = os .path .join (root_dir , "output" )
@@ -656,13 +716,13 @@ def list_folder_contents(folder_path):
656716default_model = settings ['llm' ]['model' ]
657717
658718with gr .Blocks (css = custom_css , theme = gr .themes .Base ()) as demo :
659- gr .Markdown ("# GraphRAG UI" , elem_id = "title" )
719+ gr .Markdown ("# GraphRAG Local UI" , elem_id = "title" )
660720
661721 with gr .Row (elem_id = "main-container" ):
662722 with gr .Column (scale = 1 , elem_id = "left-column" ):
663723 with gr .Tabs ():
664724 with gr .TabItem ("Data Management" ):
665- with gr .Accordion ("File Operations " , open = False ):
725+ with gr .Accordion ("File Upload (.txt) " , open = True ):
666726 file_upload = gr .File (label = "Upload .txt File" , file_types = [".txt" ])
667727 upload_btn = gr .Button ("Upload File" , variant = "primary" )
668728 upload_output = gr .Textbox (label = "Upload Status" , visible = False )
@@ -680,10 +740,11 @@ def list_folder_contents(folder_path):
680740 operation_status = gr .Textbox (label = "Operation Status" , visible = False )
681741
682742
683- with gr .Accordion ("Indexing" , open = False ):
684- root_dir = gr .Textbox (label = "Root Directory" , value = "./ragtest" )
743+ with gr .Accordion ("Indexing" , open = True ):
744+ root_dir = gr .Textbox (label = "Root Directory" , value = os . path . abspath ( "./ragtest" ) )
685745 index_btn = gr .Button ("Run Indexing" , variant = "primary" )
686- index_output = gr .Textbox (label = "Indexing Output" , lines = 5 , visible = False )
746+ index_output = gr .Textbox (label = "Indexing Output" , lines = 10 , visible = True )
747+ index_progress = gr .Textbox (label = "Indexing Progress" , visible = True )
687748
688749 with gr .TabItem ("Indexing Outputs" ):
689750 output_folder_list = gr .Dropdown (label = "Select Output Folder" , choices = [], interactive = True )
@@ -696,15 +757,15 @@ def list_folder_contents(folder_path):
696757
697758 with gr .TabItem ("Settings" ):
698759 settings = load_settings ()
699- with gr .Box ():
760+ with gr .Group ():
700761 for key , value in settings .items ():
701762 create_setting_component (key , value )
702763
703- with gr .Box (elem_id = "log-container" ):
764+ with gr .Group (elem_id = "log-container" ):
704765 log_output = gr .TextArea (label = "Logs" , elem_id = "log-output" )
705766
706767 with gr .Column (scale = 2 , elem_id = "right-column" ):
707- with gr .Box (elem_id = "chat-container" ):
768+ with gr .Group (elem_id = "chat-container" ):
708769 chatbot = gr .Chatbot (label = "Chat History" , elem_id = "chatbot" )
709770 with gr .Row (elem_id = "chat-input-row" ):
710771 query_type = gr .Radio (["global" , "local" , "direct" ], label = "Query Type" , value = "global" )
@@ -724,11 +785,11 @@ def list_folder_contents(folder_path):
724785 refresh_models_btn = gr .Button ("Refresh Models" , variant = "secondary" )
725786
726787
727- with gr .Row (elem_id = "visualization-container" ):
788+ with gr .Group (elem_id = "visualization-container" ):
728789 vis_output = gr .Plot (label = "Graph Visualization" , elem_id = "visualization-plot" )
729- with gr .Column (elem_id = "vis-controls" , scale = 1 ):
790+ with gr .Row (elem_id = "vis-controls-row" ):
730791 vis_btn = gr .Button ("Visualize Graph" , variant = "secondary" )
731- vis_status = gr .Textbox (label = "Visualization Status" , elem_id = "vis-status" , show_label = False )
792+ vis_status = gr .Textbox (label = "Visualization Status" , elem_id = "vis-status" , show_label = False )
732793
733794 # Event handlers
734795 upload_btn .click (fn = upload_file , inputs = [file_upload ], outputs = [upload_output , file_list , log_output ])
@@ -742,7 +803,12 @@ def list_folder_contents(folder_path):
742803 )
743804 delete_btn .click (fn = delete_file , inputs = [file_list ], outputs = [operation_status , file_list , log_output ])
744805 save_btn .click (fn = save_file_content , inputs = [file_list , file_content ], outputs = [operation_status , log_output ])
745- index_btn .click (fn = index_graph , inputs = [root_dir ], outputs = [index_output , log_output ])
806+ index_btn .click (
807+ fn = index_graph ,
808+ inputs = [root_dir ],
809+ outputs = [index_output , log_output ],
810+ show_progress = True
811+ )
746812 refresh_folder_btn .click (fn = update_output_folder_list , outputs = [output_folder_list ]).then (
747813 fn = update_logs ,
748814 outputs = [log_output ]
@@ -801,4 +867,4 @@ def list_folder_contents(folder_path):
801867 """ )
802868
803869if __name__ == "__main__" :
804- demo .launch (enable_queue = False )
870+ demo .launch ()
0 commit comments