Update app.py
Browse files
app.py
CHANGED
@@ -29,6 +29,7 @@ class ProgressTracker:
|
|
29 |
self.is_processing = False
|
30 |
self.lock = threading.Lock()
|
31 |
self.gradio_progress = None # Store Gradio progress object
|
|
|
32 |
|
33 |
def update(self, progress, message="Processing..."):
|
34 |
with self.lock:
|
@@ -40,24 +41,73 @@ class ProgressTracker:
|
|
40 |
self.gradio_progress(progress / 100, desc=message)
|
41 |
except:
|
42 |
pass # Ignore errors if progress object is not valid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
def get_status(self):
|
45 |
with self.lock:
|
46 |
return f"{self.message} ({self.progress:.1f}%)"
|
47 |
|
48 |
-
def start_processing(self, gradio_progress=None):
|
49 |
with self.lock:
|
50 |
self.is_processing = True
|
51 |
self.progress = 0
|
52 |
self.message = "Starting..."
|
53 |
self.gradio_progress = gradio_progress
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
|
55 |
def end_processing(self):
|
56 |
with self.lock:
|
57 |
self.is_processing = False
|
58 |
self.progress = 100
|
59 |
self.message = "Complete"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
self.gradio_progress = None
|
|
|
61 |
|
62 |
# Create a global instance
|
63 |
progress_tracker = ProgressTracker()
|
@@ -757,8 +807,17 @@ def process_multiple_dashboards(api_key, files, language_code="it", goal_descrip
|
|
757 |
# FIXED: Improved wrapper function for Gradio interface with progress bar integration
|
758 |
def process_dashboard(api_key, files, language_name, goal_description=None, num_sections=4, model_name=DEFAULT_MODEL, custom_model=None, progress=gr.Progress()):
|
759 |
"""Process dashboard files (PDF/images) and generate reports (wrapper function for Gradio interface)."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
760 |
# Start progress tracking with Gradio progress integration
|
761 |
-
progress_tracker.start_processing(progress)
|
762 |
|
763 |
# Start a thread to update text-based progress
|
764 |
progress_thread = threading.Thread(target=update_progress)
|
@@ -777,13 +836,29 @@ def process_dashboard(api_key, files, language_name, goal_description=None, num_
|
|
777 |
error_message = "API key is required."
|
778 |
progress_tracker.update(100, f"β {error_message}")
|
779 |
progress_tracker.end_processing()
|
780 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
781 |
|
782 |
if not files or len(files) == 0:
|
783 |
error_message = "No files uploaded."
|
784 |
progress_tracker.update(100, f"β {error_message}")
|
785 |
progress_tracker.end_processing()
|
786 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
787 |
|
788 |
# Process the uploaded files with improved handling
|
789 |
processed_files = []
|
@@ -848,7 +923,15 @@ def process_dashboard(api_key, files, language_name, goal_description=None, num_
|
|
848 |
error_message = "No valid files were uploaded or processed."
|
849 |
progress_tracker.update(100, f"β {error_message}")
|
850 |
progress_tracker.end_processing()
|
851 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
852 |
|
853 |
print(f"Successfully processed {len(processed_files)} files for analysis")
|
854 |
|
@@ -875,18 +958,50 @@ def process_dashboard(api_key, files, language_name, goal_description=None, num_
|
|
875 |
|
876 |
if valid_files:
|
877 |
print(f"β
Returning {len(valid_files)} valid output files")
|
878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
879 |
else:
|
880 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
881 |
|
882 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
883 |
|
884 |
except Exception as e:
|
885 |
error_message = f"Error processing dashboards: {str(e)}"
|
886 |
print(f"β {error_message}")
|
887 |
progress_tracker.update(100, f"β {error_message}")
|
888 |
progress_tracker.end_processing()
|
889 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
890 |
|
891 |
# Gradio Interface Functions
|
892 |
def toggle_custom_model(choice):
|
@@ -928,6 +1043,16 @@ with gr.Blocks(title="Dashboard Narrator - Powered by OpenRouter.ai", theme=gr.t
|
|
928 |
5. Optionally specify analysis goals
|
929 |
6. Click "Analyze Dashboards" to begin
|
930 |
""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
931 |
with gr.Row():
|
932 |
with gr.Column(scale=1):
|
933 |
api_key = gr.Textbox(
|
@@ -990,6 +1115,9 @@ with gr.Blocks(title="Dashboard Narrator - Powered by OpenRouter.ai", theme=gr.t
|
|
990 |
interactive=False
|
991 |
)
|
992 |
|
|
|
|
|
|
|
993 |
# Handle model dropdown change
|
994 |
model_choice.change(
|
995 |
fn=toggle_custom_model,
|
@@ -1008,7 +1136,7 @@ with gr.Blocks(title="Dashboard Narrator - Powered by OpenRouter.ai", theme=gr.t
|
|
1008 |
analyze_btn.click(
|
1009 |
fn=process_dashboard,
|
1010 |
inputs=[api_key, files, language, goal, num_sections, model_choice, custom_model],
|
1011 |
-
outputs=[output_md, output_files, output_status],
|
1012 |
show_progress=True
|
1013 |
)
|
1014 |
|
|
|
29 |
self.is_processing = False
|
30 |
self.lock = threading.Lock()
|
31 |
self.gradio_progress = None # Store Gradio progress object
|
32 |
+
self.progress_bar = None # Store Gradio progress bar component
|
33 |
|
34 |
def update(self, progress, message="Processing..."):
|
35 |
with self.lock:
|
|
|
41 |
self.gradio_progress(progress / 100, desc=message)
|
42 |
except:
|
43 |
pass # Ignore errors if progress object is not valid
|
44 |
+
|
45 |
+
# Update visible progress bar component if available
|
46 |
+
if self.progress_bar is not None:
|
47 |
+
try:
|
48 |
+
# Create HTML progress bar
|
49 |
+
progress_html = f"""
|
50 |
+
<div style="background-color: #f0f0f0; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ddd;">
|
51 |
+
<div style="background: linear-gradient(90deg, #4CAF50 0%, #45a049 100%); width: {progress}%; height: 25px; border-radius: 8px; transition: width 0.3s ease;"></div>
|
52 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #333;">
|
53 |
+
{message} - {progress:.1f}%
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
"""
|
57 |
+
self.progress_bar.update(value=progress_html, visible=True)
|
58 |
+
except Exception as e:
|
59 |
+
print(f"Error updating progress bar: {e}")
|
60 |
+
pass
|
61 |
|
62 |
def get_status(self):
|
63 |
with self.lock:
|
64 |
return f"{self.message} ({self.progress:.1f}%)"
|
65 |
|
66 |
+
def start_processing(self, gradio_progress=None, progress_bar=None):
|
67 |
with self.lock:
|
68 |
self.is_processing = True
|
69 |
self.progress = 0
|
70 |
self.message = "Starting..."
|
71 |
self.gradio_progress = gradio_progress
|
72 |
+
self.progress_bar = progress_bar
|
73 |
+
# Show progress bar
|
74 |
+
if self.progress_bar is not None:
|
75 |
+
try:
|
76 |
+
start_html = """
|
77 |
+
<div style="background-color: #f0f0f0; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ddd;">
|
78 |
+
<div style="background: linear-gradient(90deg, #4CAF50 0%, #45a049 100%); width: 0%; height: 25px; border-radius: 8px; transition: width 0.3s ease;"></div>
|
79 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #333;">
|
80 |
+
Starting... - 0.0%
|
81 |
+
</div>
|
82 |
+
</div>
|
83 |
+
"""
|
84 |
+
self.progress_bar.update(value=start_html, visible=True)
|
85 |
+
except Exception as e:
|
86 |
+
print(f"Error starting progress bar: {e}")
|
87 |
+
pass
|
88 |
|
89 |
def end_processing(self):
|
90 |
with self.lock:
|
91 |
self.is_processing = False
|
92 |
self.progress = 100
|
93 |
self.message = "Complete"
|
94 |
+
# Show completion progress bar
|
95 |
+
if self.progress_bar is not None:
|
96 |
+
try:
|
97 |
+
complete_html = """
|
98 |
+
<div style="background-color: #f0f0f0; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ddd;">
|
99 |
+
<div style="background: linear-gradient(90deg, #4CAF50 0%, #45a049 100%); width: 100%; height: 25px; border-radius: 8px; transition: width 0.3s ease;"></div>
|
100 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #333;">
|
101 |
+
β
Analysis Complete - 100.0%
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
"""
|
105 |
+
self.progress_bar.update(value=complete_html, visible=True)
|
106 |
+
except Exception as e:
|
107 |
+
print(f"Error ending progress bar: {e}")
|
108 |
+
pass
|
109 |
self.gradio_progress = None
|
110 |
+
# Don't reset progress_bar here so it shows the completion state
|
111 |
|
112 |
# Create a global instance
|
113 |
progress_tracker = ProgressTracker()
|
|
|
807 |
# FIXED: Improved wrapper function for Gradio interface with progress bar integration
|
808 |
def process_dashboard(api_key, files, language_name, goal_description=None, num_sections=4, model_name=DEFAULT_MODEL, custom_model=None, progress=gr.Progress()):
|
809 |
"""Process dashboard files (PDF/images) and generate reports (wrapper function for Gradio interface)."""
|
810 |
+
|
811 |
+
# Get reference to the progress bar component
|
812 |
+
progress_bar = None
|
813 |
+
try:
|
814 |
+
# We'll pass this via the global progress_tracker
|
815 |
+
progress_bar = progress_tracker.progress_bar
|
816 |
+
except:
|
817 |
+
pass
|
818 |
+
|
819 |
# Start progress tracking with Gradio progress integration
|
820 |
+
progress_tracker.start_processing(progress, progress_bar)
|
821 |
|
822 |
# Start a thread to update text-based progress
|
823 |
progress_thread = threading.Thread(target=update_progress)
|
|
|
836 |
error_message = "API key is required."
|
837 |
progress_tracker.update(100, f"β {error_message}")
|
838 |
progress_tracker.end_processing()
|
839 |
+
error_html = """
|
840 |
+
<div style="background-color: #ffebee; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #f44336;">
|
841 |
+
<div style="background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%); width: 100%; height: 25px; border-radius: 8px;"></div>
|
842 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #d32f2f;">
|
843 |
+
β Error: API key is required
|
844 |
+
</div>
|
845 |
+
</div>
|
846 |
+
"""
|
847 |
+
return None, None, error_message, error_html
|
848 |
|
849 |
if not files or len(files) == 0:
|
850 |
error_message = "No files uploaded."
|
851 |
progress_tracker.update(100, f"β {error_message}")
|
852 |
progress_tracker.end_processing()
|
853 |
+
error_html = """
|
854 |
+
<div style="background-color: #ffebee; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #f44336;">
|
855 |
+
<div style="background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%); width: 100%; height: 25px; border-radius: 8px;"></div>
|
856 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #d32f2f;">
|
857 |
+
β Error: No files uploaded
|
858 |
+
</div>
|
859 |
+
</div>
|
860 |
+
"""
|
861 |
+
return None, None, error_message, error_html
|
862 |
|
863 |
# Process the uploaded files with improved handling
|
864 |
processed_files = []
|
|
|
923 |
error_message = "No valid files were uploaded or processed."
|
924 |
progress_tracker.update(100, f"β {error_message}")
|
925 |
progress_tracker.end_processing()
|
926 |
+
error_html = """
|
927 |
+
<div style="background-color: #ffebee; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #f44336;">
|
928 |
+
<div style="background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%); width: 100%; height: 25px; border-radius: 8px;"></div>
|
929 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #d32f2f;">
|
930 |
+
β Error: No valid files processed
|
931 |
+
</div>
|
932 |
+
</div>
|
933 |
+
"""
|
934 |
+
return None, None, error_message, error_html
|
935 |
|
936 |
print(f"Successfully processed {len(processed_files)} files for analysis")
|
937 |
|
|
|
958 |
|
959 |
if valid_files:
|
960 |
print(f"β
Returning {len(valid_files)} valid output files")
|
961 |
+
success_html = """
|
962 |
+
<div style="background-color: #f0f0f0; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ddd;">
|
963 |
+
<div style="background: linear-gradient(90deg, #4CAF50 0%, #45a049 100%); width: 100%; height: 25px; border-radius: 8px; transition: width 0.3s ease;"></div>
|
964 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #333;">
|
965 |
+
β
Analysis Complete - 100.0%
|
966 |
+
</div>
|
967 |
+
</div>
|
968 |
+
"""
|
969 |
+
return combined_content, valid_files, status, success_html
|
970 |
else:
|
971 |
+
success_html = """
|
972 |
+
<div style="background-color: #fff3cd; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ffc107;">
|
973 |
+
<div style="background: linear-gradient(90deg, #ffc107 0%, #ffb300 100%); width: 100%; height: 25px; border-radius: 8px;"></div>
|
974 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #856404;">
|
975 |
+
β οΈ Analysis completed but no files created
|
976 |
+
</div>
|
977 |
+
</div>
|
978 |
+
"""
|
979 |
+
return combined_content, None, "Analysis completed but no downloadable files were created.", success_html
|
980 |
|
981 |
+
success_html = """
|
982 |
+
<div style="background-color: #f0f0f0; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #ddd;">
|
983 |
+
<div style="background: linear-gradient(90deg, #4CAF50 0%, #45a049 100%); width: 100%; height: 25px; border-radius: 8px; transition: width 0.3s ease;"></div>
|
984 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #333;">
|
985 |
+
β
Analysis Complete - 100.0%
|
986 |
+
</div>
|
987 |
+
</div>
|
988 |
+
"""
|
989 |
+
return combined_content, output_files, status, success_html
|
990 |
|
991 |
except Exception as e:
|
992 |
error_message = f"Error processing dashboards: {str(e)}"
|
993 |
print(f"β {error_message}")
|
994 |
progress_tracker.update(100, f"β {error_message}")
|
995 |
progress_tracker.end_processing()
|
996 |
+
error_html = """
|
997 |
+
<div style="background-color: #ffebee; border-radius: 10px; padding: 5px; margin: 10px 0; border: 1px solid #f44336;">
|
998 |
+
<div style="background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%); width: 100%; height: 25px; border-radius: 8px;"></div>
|
999 |
+
<div style="text-align: center; margin-top: 5px; font-weight: bold; color: #d32f2f;">
|
1000 |
+
β Error processing dashboards
|
1001 |
+
</div>
|
1002 |
+
</div>
|
1003 |
+
"""
|
1004 |
+
return None, None, error_message, error_html
|
1005 |
|
1006 |
# Gradio Interface Functions
|
1007 |
def toggle_custom_model(choice):
|
|
|
1043 |
5. Optionally specify analysis goals
|
1044 |
6. Click "Analyze Dashboards" to begin
|
1045 |
""")
|
1046 |
+
|
1047 |
+
# Add a visible progress bar component
|
1048 |
+
with gr.Row():
|
1049 |
+
with gr.Column():
|
1050 |
+
progress_bar = gr.HTML(
|
1051 |
+
value="",
|
1052 |
+
visible=False,
|
1053 |
+
label="Analysis Progress"
|
1054 |
+
)
|
1055 |
+
|
1056 |
with gr.Row():
|
1057 |
with gr.Column(scale=1):
|
1058 |
api_key = gr.Textbox(
|
|
|
1115 |
interactive=False
|
1116 |
)
|
1117 |
|
1118 |
+
# Store progress bar reference in global tracker
|
1119 |
+
progress_tracker.progress_bar = progress_bar
|
1120 |
+
|
1121 |
# Handle model dropdown change
|
1122 |
model_choice.change(
|
1123 |
fn=toggle_custom_model,
|
|
|
1136 |
analyze_btn.click(
|
1137 |
fn=process_dashboard,
|
1138 |
inputs=[api_key, files, language, goal, num_sections, model_choice, custom_model],
|
1139 |
+
outputs=[output_md, output_files, output_status, progress_bar],
|
1140 |
show_progress=True
|
1141 |
)
|
1142 |
|