Spaces:
Running
Running
Delete services/agentic_handlers.py
Browse files- services/agentic_handlers.py +0 -322
services/agentic_handlers.py
DELETED
@@ -1,322 +0,0 @@
|
|
1 |
-
# handlers/agentic_handlers.py
|
2 |
-
import gradio as gr
|
3 |
-
import logging
|
4 |
-
from collections import defaultdict
|
5 |
-
import json # Added for JSON serialization/deserialization
|
6 |
-
|
7 |
-
# Attempt to import agentic pipeline functions and UI formatters
|
8 |
-
try:
|
9 |
-
from run_agentic_pipeline import run_full_analytics_orchestration
|
10 |
-
from ui.insights_ui_generator import (
|
11 |
-
format_report_to_markdown,
|
12 |
-
extract_key_results_for_selection,
|
13 |
-
format_single_okr_for_display
|
14 |
-
)
|
15 |
-
AGENTIC_MODULES_LOADED = True
|
16 |
-
except ImportError as e:
|
17 |
-
logging.error(f"Could not import agentic pipeline modules for AgenticHandlers: {e}.")
|
18 |
-
AGENTIC_MODULES_LOADED = False
|
19 |
-
# Define placeholder functions if modules are not loaded to avoid NameErrors during class definition
|
20 |
-
async def run_full_analytics_orchestration(*args, **kwargs): return None
|
21 |
-
def format_report_to_markdown(report_string): return "Agentic modules not loaded. Report unavailable."
|
22 |
-
def extract_key_results_for_selection(okrs_dict): return []
|
23 |
-
def format_single_okr_for_display(okr_data, **kwargs): return "Agentic modules not loaded. OKR display unavailable."
|
24 |
-
|
25 |
-
|
26 |
-
class AgenticHandlers:
|
27 |
-
def __init__(self, agentic_report_components, agentic_okrs_components,
|
28 |
-
token_state_ref, orchestration_raw_results_st_ref,
|
29 |
-
key_results_for_selection_st_ref, selected_key_result_ids_st_ref):
|
30 |
-
|
31 |
-
self.report_components = agentic_report_components
|
32 |
-
self.okrs_components = agentic_okrs_components
|
33 |
-
|
34 |
-
# References to global states
|
35 |
-
self.token_state = token_state_ref
|
36 |
-
self.orchestration_raw_results_st = orchestration_raw_results_st_ref
|
37 |
-
self.key_results_for_selection_st = key_results_for_selection_st_ref
|
38 |
-
self.selected_key_result_ids_st = selected_key_result_ids_st_ref
|
39 |
-
|
40 |
-
self.agentic_modules_really_loaded = AGENTIC_MODULES_LOADED
|
41 |
-
logging.info(f"AgenticHandlers initialized. Modules loaded: {self.agentic_modules_really_loaded}")
|
42 |
-
|
43 |
-
async def run_agentic_pipeline_autonomously_on_update(self, current_token_state_val):
|
44 |
-
"""
|
45 |
-
This function is intended to be triggered by changes in token_state.
|
46 |
-
It yields updates for the agentic report and OKR tabs.
|
47 |
-
State values (5th, 6th, 7th) are serialized to JSON strings.
|
48 |
-
Updates for key_results_cbg are now simplified without choices/interactive.
|
49 |
-
"""
|
50 |
-
logging.info(f"Agentic pipeline auto-trigger. Token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")
|
51 |
-
|
52 |
-
initial_report_status = "Pipeline AI: In attesa dei dati necessari..."
|
53 |
-
initial_okr_details = "Pipeline AI: In attesa dei dati necessari..."
|
54 |
-
|
55 |
-
initial_orchestration_results = self.orchestration_raw_results_st.value
|
56 |
-
initial_selected_krs = self.selected_key_result_ids_st.value
|
57 |
-
initial_krs_for_selection = self.key_results_for_selection_st.value
|
58 |
-
|
59 |
-
report_status_md_update = gr.update(value=initial_report_status) if self.report_components.get("agentic_pipeline_status_md") else gr.update()
|
60 |
-
report_display_md_update = gr.update()
|
61 |
-
|
62 |
-
# Simple update for checkbox component - just reset value
|
63 |
-
okrs_cbg_update = gr.update(value=[]) if self.okrs_components.get("key_results_cbg") else gr.update()
|
64 |
-
|
65 |
-
okrs_detail_md_update = gr.update(value=initial_okr_details) if self.okrs_components.get("okr_detail_display_md") else gr.update()
|
66 |
-
|
67 |
-
if not current_token_state_val or not current_token_state_val.get("token"):
|
68 |
-
logging.info("Agentic pipeline: Token not available in token_state. Skipping actual run.")
|
69 |
-
yield (
|
70 |
-
report_status_md_update,
|
71 |
-
report_display_md_update,
|
72 |
-
okrs_cbg_update,
|
73 |
-
okrs_detail_md_update,
|
74 |
-
json.dumps(initial_orchestration_results), # Serialize to JSON
|
75 |
-
json.dumps(initial_selected_krs), # Serialize to JSON
|
76 |
-
json.dumps(initial_krs_for_selection) # Serialize to JSON
|
77 |
-
)
|
78 |
-
return
|
79 |
-
|
80 |
-
in_progress_status = "Analisi AI (Sempre) in corso..."
|
81 |
-
if self.report_components.get("agentic_pipeline_status_md"):
|
82 |
-
report_status_md_update = gr.update(value=in_progress_status)
|
83 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
84 |
-
okrs_detail_md_update = gr.update(value="Dettagli OKR (Sempre) in corso di generazione...")
|
85 |
-
|
86 |
-
yield (
|
87 |
-
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
88 |
-
json.dumps(initial_orchestration_results), # Serialize to JSON
|
89 |
-
json.dumps(initial_selected_krs), # Serialize to JSON
|
90 |
-
json.dumps(initial_krs_for_selection) # Serialize to JSON
|
91 |
-
)
|
92 |
-
|
93 |
-
if not self.agentic_modules_really_loaded:
|
94 |
-
logging.warning("Agentic modules not loaded. Skipping autonomous pipeline actual run.")
|
95 |
-
error_status = "Moduli AI non caricati. Operazione non disponibile."
|
96 |
-
if self.report_components.get("agentic_pipeline_status_md"):
|
97 |
-
report_status_md_update = gr.update(value=error_status)
|
98 |
-
if self.report_components.get("agentic_report_display_md"):
|
99 |
-
report_display_md_update = gr.update(value=error_status)
|
100 |
-
|
101 |
-
# Simple update for checkbox in error case
|
102 |
-
if self.okrs_components.get("key_results_cbg"):
|
103 |
-
okrs_cbg_update = gr.update(value=[])
|
104 |
-
|
105 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
106 |
-
okrs_detail_md_update = gr.update(value=error_status)
|
107 |
-
|
108 |
-
yield (
|
109 |
-
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
110 |
-
json.dumps(None), json.dumps([]), json.dumps([]) # Serialize to JSON
|
111 |
-
)
|
112 |
-
return
|
113 |
-
|
114 |
-
try:
|
115 |
-
date_filter_val_agentic = "Sempre"
|
116 |
-
custom_start_val_agentic = None
|
117 |
-
custom_end_val_agentic = None
|
118 |
-
|
119 |
-
logging.info("Agentic pipeline: Calling run_full_analytics_orchestration...")
|
120 |
-
orchestration_output = await run_full_analytics_orchestration(
|
121 |
-
current_token_state_val,
|
122 |
-
date_filter_val_agentic,
|
123 |
-
custom_start_val_agentic,
|
124 |
-
custom_end_val_agentic
|
125 |
-
)
|
126 |
-
|
127 |
-
final_status_text = "Pipeline AI (Sempre) completata."
|
128 |
-
logging.info(f"Autonomous agentic pipeline finished. Output keys: {orchestration_output.keys() if orchestration_output else 'None'}")
|
129 |
-
|
130 |
-
orchestration_results_update_val = None
|
131 |
-
selected_krs_update_val = [] # This will be the value for the CheckboxGroup, initially empty
|
132 |
-
krs_for_selection_update_val = []
|
133 |
-
|
134 |
-
if orchestration_output:
|
135 |
-
orchestration_results_update_val = orchestration_output
|
136 |
-
|
137 |
-
report_str = orchestration_output.get('comprehensive_analysis_report', "Nessun report testuale fornito.")
|
138 |
-
if self.report_components.get("agentic_report_display_md"):
|
139 |
-
formatted_report = format_report_to_markdown(report_str)
|
140 |
-
# Ensure we have a string, not a list
|
141 |
-
if isinstance(formatted_report, list):
|
142 |
-
formatted_report = "\n".join(formatted_report)
|
143 |
-
elif not isinstance(formatted_report, str):
|
144 |
-
formatted_report = str(formatted_report)
|
145 |
-
report_display_md_update = gr.update(value=formatted_report)
|
146 |
-
|
147 |
-
actionable_okrs = orchestration_output.get('actionable_okrs_and_tasks')
|
148 |
-
krs_for_ui_selection_list = extract_key_results_for_selection(actionable_okrs)
|
149 |
-
krs_for_selection_update_val = krs_for_ui_selection_list # This is the list of dicts
|
150 |
-
|
151 |
-
# For checkbox, just reset the value - don't update choices programmatically
|
152 |
-
if self.okrs_components.get("key_results_cbg"):
|
153 |
-
okrs_cbg_update = gr.update(value=[])
|
154 |
-
|
155 |
-
all_okrs_md_parts = []
|
156 |
-
if actionable_okrs and isinstance(actionable_okrs.get("okrs"), list):
|
157 |
-
for okr_idx, okr_item in enumerate(actionable_okrs["okrs"]):
|
158 |
-
all_okrs_md_parts.append(format_single_okr_for_display(okr_item, accepted_kr_indices=None, okr_main_index=okr_idx))
|
159 |
-
|
160 |
-
if not all_okrs_md_parts:
|
161 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
162 |
-
okrs_detail_md_update = gr.update(value="Nessun OKR generato o trovato (Sempre).")
|
163 |
-
else:
|
164 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
165 |
-
okrs_detail_md_update = gr.update(value="\n\n---\n\n".join(all_okrs_md_parts))
|
166 |
-
|
167 |
-
selected_krs_update_val = [] # Reset CheckboxGroup selection
|
168 |
-
else:
|
169 |
-
final_status_text = "Pipeline AI (Sempre): Nessun risultato prodotto."
|
170 |
-
if self.report_components.get("agentic_report_display_md"):
|
171 |
-
report_display_md_update = gr.update(value="Nessun report generato dalla pipeline AI (Sempre).")
|
172 |
-
|
173 |
-
# Simple update for checkbox if no output
|
174 |
-
if self.okrs_components.get("key_results_cbg"):
|
175 |
-
okrs_cbg_update = gr.update(value=[])
|
176 |
-
|
177 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
178 |
-
okrs_detail_md_update = gr.update(value="Nessun OKR generato o errore nella pipeline AI (Sempre).")
|
179 |
-
|
180 |
-
if self.report_components.get("agentic_pipeline_status_md"):
|
181 |
-
report_status_md_update = gr.update(value=final_status_text)
|
182 |
-
|
183 |
-
yield (
|
184 |
-
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
185 |
-
json.dumps(orchestration_results_update_val), # Serialize to JSON
|
186 |
-
json.dumps(selected_krs_update_val), # Serialize to JSON (value for selected_key_result_ids_st)
|
187 |
-
json.dumps(krs_for_selection_update_val) # Serialize to JSON (value for key_results_for_selection_st)
|
188 |
-
)
|
189 |
-
|
190 |
-
except Exception as e:
|
191 |
-
logging.error(f"Error during autonomous agentic pipeline execution: {e}", exc_info=True)
|
192 |
-
error_status_text = f"Errore pipeline AI (Sempre): {str(e)}"
|
193 |
-
if self.report_components.get("agentic_pipeline_status_md"):
|
194 |
-
report_status_md_update = gr.update(value=error_status_text)
|
195 |
-
if self.report_components.get("agentic_report_display_md"):
|
196 |
-
report_display_md_update = gr.update(value=f"Errore generazione report AI (Sempre): {str(e)}")
|
197 |
-
|
198 |
-
# Simple update for checkbox in case of exception
|
199 |
-
if self.okrs_components.get("key_results_cbg"):
|
200 |
-
okrs_cbg_update = gr.update(value=[])
|
201 |
-
|
202 |
-
if self.okrs_components.get("okr_detail_display_md"):
|
203 |
-
okrs_detail_md_update = gr.update(value=f"Errore generazione OKR AI (Sempre): {str(e)}")
|
204 |
-
|
205 |
-
yield (
|
206 |
-
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
207 |
-
json.dumps(None), json.dumps([]), json.dumps([]) # Serialize to JSON
|
208 |
-
)
|
209 |
-
|
210 |
-
def update_okr_display_on_kr_selection(self, selected_kr_unique_ids: list,
|
211 |
-
raw_orchestration_results_json: str,
|
212 |
-
all_krs_for_selection_list_json: str):
|
213 |
-
"""
|
214 |
-
Updates the OKR detail display when Key Results are selected in the CheckboxGroup.
|
215 |
-
raw_orchestration_results_json and all_krs_for_selection_list_json are expected
|
216 |
-
to be JSON strings from state.
|
217 |
-
"""
|
218 |
-
if not self.agentic_modules_really_loaded:
|
219 |
-
return gr.update(value="Moduli AI non caricati. Impossibile visualizzare i dettagli OKR.")
|
220 |
-
|
221 |
-
# Handle case where selected_kr_unique_ids might be None or not a list
|
222 |
-
if not isinstance(selected_kr_unique_ids, list):
|
223 |
-
selected_kr_unique_ids = []
|
224 |
-
|
225 |
-
parsed_orchestration_results = None
|
226 |
-
try:
|
227 |
-
if raw_orchestration_results_json: # Check if the string is not empty
|
228 |
-
parsed_orchestration_results = json.loads(raw_orchestration_results_json)
|
229 |
-
except (json.JSONDecodeError, TypeError) as e:
|
230 |
-
logging.error(f"Failed to parse raw_orchestration_results_json: {raw_orchestration_results_json}. Error: {e}")
|
231 |
-
return gr.update(value="Errore: Dati interni corrotti (orchestration results).")
|
232 |
-
|
233 |
-
if not parsed_orchestration_results: # This covers None or empty after parsing
|
234 |
-
return gr.update(value="Nessun dato dalla pipeline AI (orchestration results).")
|
235 |
-
|
236 |
-
parsed_krs_for_selection_list = []
|
237 |
-
try:
|
238 |
-
if all_krs_for_selection_list_json: # Check if the string is not empty
|
239 |
-
parsed_krs_for_selection_list = json.loads(all_krs_for_selection_list_json)
|
240 |
-
except (json.JSONDecodeError, TypeError) as e:
|
241 |
-
logging.error(f"Failed to parse all_krs_for_selection_list_json: {all_krs_for_selection_list_json}. Error: {e}")
|
242 |
-
return gr.update(value="Errore: Dati interni corrotti (krs for selection).")
|
243 |
-
|
244 |
-
# Ensure parsed_krs_for_selection_list is a list, even if JSON was 'null' or other non-list type
|
245 |
-
if not isinstance(parsed_krs_for_selection_list, list):
|
246 |
-
logging.warning(f"Parsed all_krs_for_selection_list is not a list: {type(parsed_krs_for_selection_list)}. Defaulting to empty list.")
|
247 |
-
parsed_krs_for_selection_list = []
|
248 |
-
|
249 |
-
actionable_okrs_dict = parsed_orchestration_results.get("actionable_okrs_and_tasks") if isinstance(parsed_orchestration_results, dict) else None
|
250 |
-
|
251 |
-
if not actionable_okrs_dict or not isinstance(actionable_okrs_dict.get("okrs"), list):
|
252 |
-
return gr.update(value="Nessun OKR trovato nei risultati della pipeline (o dati in formato imprevisto).")
|
253 |
-
|
254 |
-
okrs_list = actionable_okrs_dict["okrs"]
|
255 |
-
if not okrs_list:
|
256 |
-
return gr.update(value="Nessun OKR generato.")
|
257 |
-
|
258 |
-
kr_id_to_indices = {}
|
259 |
-
if isinstance(parsed_krs_for_selection_list, list): # Ensure it's a list before iterating
|
260 |
-
for kr_info in parsed_krs_for_selection_list:
|
261 |
-
if isinstance(kr_info, dict) and 'unique_kr_id' in kr_info and 'okr_index' in kr_info and 'kr_index' in kr_info:
|
262 |
-
kr_id_to_indices[kr_info['unique_kr_id']] = (kr_info['okr_index'], kr_info['kr_index'])
|
263 |
-
else:
|
264 |
-
logging.warning(f"Skipping invalid kr_info item: {kr_info}")
|
265 |
-
|
266 |
-
selected_krs_by_okr_idx = defaultdict(list)
|
267 |
-
# selected_kr_unique_ids comes directly from CheckboxGroup, should be a list of strings/values
|
268 |
-
if isinstance(selected_kr_unique_ids, list):
|
269 |
-
for kr_unique_id in selected_kr_unique_ids:
|
270 |
-
if kr_unique_id in kr_id_to_indices:
|
271 |
-
okr_idx, kr_idx_in_okr = kr_id_to_indices[kr_unique_id]
|
272 |
-
selected_krs_by_okr_idx[okr_idx].append(kr_idx_in_okr)
|
273 |
-
|
274 |
-
output_md_parts = []
|
275 |
-
for okr_idx, okr_data in enumerate(okrs_list):
|
276 |
-
accepted_indices_for_this_okr = selected_krs_by_okr_idx.get(okr_idx)
|
277 |
-
|
278 |
-
if selected_kr_unique_ids:
|
279 |
-
if accepted_indices_for_this_okr is not None:
|
280 |
-
formatted_okr_md = format_single_okr_for_display(
|
281 |
-
okr_data,
|
282 |
-
accepted_kr_indices=accepted_indices_for_this_okr,
|
283 |
-
okr_main_index=okr_idx
|
284 |
-
)
|
285 |
-
output_md_parts.append(formatted_okr_md)
|
286 |
-
else:
|
287 |
-
formatted_okr_md = format_single_okr_for_display(
|
288 |
-
okr_data,
|
289 |
-
accepted_kr_indices=None,
|
290 |
-
okr_main_index=okr_idx
|
291 |
-
)
|
292 |
-
output_md_parts.append(formatted_okr_md)
|
293 |
-
|
294 |
-
if not output_md_parts and selected_kr_unique_ids:
|
295 |
-
final_md = "Nessun OKR corrisponde alla selezione corrente o i KR selezionati non hanno task dettagliati."
|
296 |
-
elif not output_md_parts and not selected_kr_unique_ids:
|
297 |
-
final_md = "Nessun OKR generato."
|
298 |
-
else:
|
299 |
-
final_md = "\n\n---\n\n".join(output_md_parts)
|
300 |
-
|
301 |
-
return gr.update(value=final_md)
|
302 |
-
|
303 |
-
def setup_event_handlers(self):
|
304 |
-
"""Sets up event handlers for the agentic OKRs tab."""
|
305 |
-
if not self.agentic_modules_really_loaded:
|
306 |
-
logging.warning("Agentic modules not loaded. Skipping agentic event handler setup.")
|
307 |
-
return
|
308 |
-
|
309 |
-
if self.okrs_components.get("key_results_cbg"):
|
310 |
-
self.okrs_components['key_results_cbg'].change(
|
311 |
-
fn=self.update_okr_display_on_kr_selection,
|
312 |
-
inputs=[
|
313 |
-
self.okrs_components['key_results_cbg'],
|
314 |
-
self.orchestration_raw_results_st,
|
315 |
-
self.key_results_for_selection_st
|
316 |
-
],
|
317 |
-
outputs=[self.okrs_components['okr_detail_display_md']],
|
318 |
-
api_name="update_okr_display_on_kr_selection" # Keep api_name for Gradio
|
319 |
-
)
|
320 |
-
logging.info("Agentic OKR selection handler setup complete.")
|
321 |
-
else:
|
322 |
-
logging.warning("key_results_cbg component not found for agentic OKR handler setup.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|