Spaces:
Running
Running
Update services/agentic_handlers.py
Browse files- services/agentic_handlers.py +74 -56
services/agentic_handlers.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
import gradio as gr
|
3 |
import logging
|
4 |
from collections import defaultdict
|
|
|
5 |
|
6 |
# Attempt to import agentic pipeline functions and UI formatters
|
7 |
try:
|
@@ -34,25 +35,28 @@ class AgenticHandlers:
|
|
34 |
self.token_state = token_state_ref
|
35 |
self.orchestration_raw_results_st = orchestration_raw_results_st_ref
|
36 |
self.key_results_for_selection_st = key_results_for_selection_st_ref
|
37 |
-
self.selected_key_result_ids_st = selected_key_result_ids_st_ref
|
38 |
|
39 |
-
self.agentic_modules_really_loaded = AGENTIC_MODULES_LOADED
|
40 |
logging.info(f"AgenticHandlers initialized. Modules loaded: {self.agentic_modules_really_loaded}")
|
41 |
|
42 |
async def run_agentic_pipeline_autonomously_on_update(self, current_token_state_val):
|
43 |
"""
|
44 |
-
This function is intended to be triggered by changes in token_state
|
45 |
-
(e.g., after initial load or after sync).
|
46 |
It yields updates for the agentic report and OKR tabs.
|
47 |
-
|
48 |
-
|
49 |
"""
|
50 |
logging.info(f"Agentic pipeline auto-trigger. Token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")
|
51 |
|
52 |
-
# Initial "waiting" status updates
|
53 |
initial_report_status = "Pipeline AI: In attesa dei dati necessari..."
|
54 |
-
initial_okr_value_for_markdown = ""
|
55 |
initial_okr_details = "Pipeline AI: In attesa dei dati necessari..."
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
initial_orchestration_results = self.orchestration_raw_results_st.value
|
57 |
initial_selected_krs = self.selected_key_result_ids_st.value
|
58 |
initial_krs_for_selection = self.key_results_for_selection_st.value
|
@@ -60,7 +64,7 @@ class AgenticHandlers:
|
|
60 |
report_status_md_update = gr.update(value=initial_report_status) if self.report_components.get("agentic_pipeline_status_md") else gr.update()
|
61 |
report_display_md_update = gr.update()
|
62 |
|
63 |
-
okrs_cbg_update = gr.update(value=
|
64 |
okrs_detail_md_update = gr.update(value=initial_okr_details) if self.okrs_components.get("okr_detail_display_md") else gr.update()
|
65 |
|
66 |
if not current_token_state_val or not current_token_state_val.get("token"):
|
@@ -70,9 +74,9 @@ class AgenticHandlers:
|
|
70 |
report_display_md_update,
|
71 |
okrs_cbg_update,
|
72 |
okrs_detail_md_update,
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
)
|
77 |
return
|
78 |
|
@@ -82,11 +86,12 @@ class AgenticHandlers:
|
|
82 |
if self.okrs_components.get("okr_detail_display_md"):
|
83 |
okrs_detail_md_update = gr.update(value="Dettagli OKR (Sempre) in corso di generazione...")
|
84 |
|
|
|
85 |
yield (
|
86 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
)
|
91 |
|
92 |
if not self.agentic_modules_really_loaded:
|
@@ -97,15 +102,16 @@ class AgenticHandlers:
|
|
97 |
if self.report_components.get("agentic_report_display_md"):
|
98 |
report_display_md_update = gr.update(value=error_status)
|
99 |
|
|
|
100 |
if self.okrs_components.get("key_results_cbg"):
|
101 |
-
okrs_cbg_update = gr.update(value=
|
102 |
|
103 |
if self.okrs_components.get("okr_detail_display_md"):
|
104 |
okrs_detail_md_update = gr.update(value=error_status)
|
105 |
|
106 |
yield (
|
107 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
108 |
-
|
109 |
)
|
110 |
return
|
111 |
|
@@ -126,7 +132,7 @@ class AgenticHandlers:
|
|
126 |
logging.info(f"Autonomous agentic pipeline finished. Output keys: {orchestration_output.keys() if orchestration_output else 'None'}")
|
127 |
|
128 |
orchestration_results_update_val = None
|
129 |
-
selected_krs_update_val = []
|
130 |
krs_for_selection_update_val = []
|
131 |
|
132 |
if orchestration_output:
|
@@ -138,10 +144,12 @@ class AgenticHandlers:
|
|
138 |
|
139 |
actionable_okrs = orchestration_output.get('actionable_okrs_and_tasks')
|
140 |
krs_for_ui_selection_list = extract_key_results_for_selection(actionable_okrs)
|
141 |
-
krs_for_selection_update_val = krs_for_ui_selection_list
|
142 |
|
|
|
|
|
143 |
if self.okrs_components.get("key_results_cbg"):
|
144 |
-
okrs_cbg_update = gr.update(value=
|
145 |
|
146 |
all_okrs_md_parts = []
|
147 |
if actionable_okrs and isinstance(actionable_okrs.get("okrs"), list):
|
@@ -155,14 +163,15 @@ class AgenticHandlers:
|
|
155 |
if self.okrs_components.get("okr_detail_display_md"):
|
156 |
okrs_detail_md_update = gr.update(value="\n\n---\n\n".join(all_okrs_md_parts))
|
157 |
|
158 |
-
selected_krs_update_val = []
|
159 |
else:
|
160 |
final_status_text = "Pipeline AI (Sempre): Nessun risultato prodotto."
|
161 |
if self.report_components.get("agentic_report_display_md"):
|
162 |
report_display_md_update = gr.update(value="Nessun report generato dalla pipeline AI (Sempre).")
|
163 |
|
|
|
164 |
if self.okrs_components.get("key_results_cbg"):
|
165 |
-
okrs_cbg_update = gr.update(value=
|
166 |
|
167 |
if self.okrs_components.get("okr_detail_display_md"):
|
168 |
okrs_detail_md_update = gr.update(value="Nessun OKR generato o errore nella pipeline AI (Sempre).")
|
@@ -172,9 +181,9 @@ class AgenticHandlers:
|
|
172 |
|
173 |
yield (
|
174 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
)
|
179 |
|
180 |
except Exception as e:
|
@@ -185,48 +194,55 @@ class AgenticHandlers:
|
|
185 |
if self.report_components.get("agentic_report_display_md"):
|
186 |
report_display_md_update = gr.update(value=f"Errore generazione report AI (Sempre): {str(e)}")
|
187 |
|
|
|
188 |
if self.okrs_components.get("key_results_cbg"):
|
189 |
-
okrs_cbg_update = gr.update(value=
|
190 |
|
191 |
if self.okrs_components.get("okr_detail_display_md"):
|
192 |
okrs_detail_md_update = gr.update(value=f"Errore generazione OKR AI (Sempre): {str(e)}")
|
193 |
|
194 |
yield (
|
195 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
196 |
-
|
197 |
)
|
198 |
|
199 |
def update_okr_display_on_kr_selection(self, selected_kr_unique_ids: list,
|
200 |
-
|
201 |
-
|
202 |
"""
|
203 |
Updates the OKR detail display when Key Results are selected in the CheckboxGroup.
|
|
|
|
|
204 |
"""
|
205 |
-
# raw_orchestration_results, all_krs_for_selection_list now might be strings
|
206 |
-
# if they come from state that was stringified. This needs careful handling
|
207 |
-
# if this function is called with outputs from the stringified state.
|
208 |
-
# For now, assuming they are passed correctly as dict/list if not from stringified state.
|
209 |
-
|
210 |
if not self.agentic_modules_really_loaded:
|
211 |
return gr.update(value="Moduli AI non caricati. Impossibile visualizzare i dettagli OKR.")
|
212 |
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
# will be the string "'[]'", not the list [].
|
221 |
|
222 |
-
if not
|
223 |
-
return gr.update(value="Nessun dato dalla pipeline AI
|
224 |
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
|
231 |
if not actionable_okrs_dict or not isinstance(actionable_okrs_dict.get("okrs"), list):
|
232 |
return gr.update(value="Nessun OKR trovato nei risultati della pipeline (o dati in formato imprevisto).")
|
@@ -236,14 +252,16 @@ class AgenticHandlers:
|
|
236 |
return gr.update(value="Nessun OKR generato.")
|
237 |
|
238 |
kr_id_to_indices = {}
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
if isinstance(kr_info, dict): # defensive check
|
243 |
kr_id_to_indices[kr_info['unique_kr_id']] = (kr_info['okr_index'], kr_info['kr_index'])
|
244 |
-
|
|
|
|
|
245 |
selected_krs_by_okr_idx = defaultdict(list)
|
246 |
-
|
|
|
247 |
for kr_unique_id in selected_kr_unique_ids:
|
248 |
if kr_unique_id in kr_id_to_indices:
|
249 |
okr_idx, kr_idx_in_okr = kr_id_to_indices[kr_unique_id]
|
@@ -293,7 +311,7 @@ class AgenticHandlers:
|
|
293 |
self.key_results_for_selection_st
|
294 |
],
|
295 |
outputs=[self.okrs_components['okr_detail_display_md']],
|
296 |
-
api_name="update_okr_display_on_kr_selection"
|
297 |
)
|
298 |
logging.info("Agentic OKR selection handler setup complete.")
|
299 |
else:
|
|
|
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:
|
|
|
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 for a CheckboxGroup.
|
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 state for key_results_cbg (CheckboxGroup)
|
56 |
+
initial_okr_cbg_choices = []
|
57 |
+
initial_okr_cbg_value = []
|
58 |
+
initial_okr_cbg_interactive = False
|
59 |
+
|
60 |
initial_orchestration_results = self.orchestration_raw_results_st.value
|
61 |
initial_selected_krs = self.selected_key_result_ids_st.value
|
62 |
initial_krs_for_selection = self.key_results_for_selection_st.value
|
|
|
64 |
report_status_md_update = gr.update(value=initial_report_status) if self.report_components.get("agentic_pipeline_status_md") else gr.update()
|
65 |
report_display_md_update = gr.update()
|
66 |
|
67 |
+
okrs_cbg_update = gr.update(choices=initial_okr_cbg_choices, value=initial_okr_cbg_value, interactive=initial_okr_cbg_interactive) if self.okrs_components.get("key_results_cbg") else gr.update()
|
68 |
okrs_detail_md_update = gr.update(value=initial_okr_details) if self.okrs_components.get("okr_detail_display_md") else gr.update()
|
69 |
|
70 |
if not current_token_state_val or not current_token_state_val.get("token"):
|
|
|
74 |
report_display_md_update,
|
75 |
okrs_cbg_update,
|
76 |
okrs_detail_md_update,
|
77 |
+
json.dumps(initial_orchestration_results), # Serialize to JSON
|
78 |
+
json.dumps(initial_selected_krs), # Serialize to JSON
|
79 |
+
json.dumps(initial_krs_for_selection) # Serialize to JSON
|
80 |
)
|
81 |
return
|
82 |
|
|
|
86 |
if self.okrs_components.get("okr_detail_display_md"):
|
87 |
okrs_detail_md_update = gr.update(value="Dettagli OKR (Sempre) in corso di generazione...")
|
88 |
|
89 |
+
# okrs_cbg_update is already set to initial waiting state for CheckboxGroup
|
90 |
yield (
|
91 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
92 |
+
json.dumps(initial_orchestration_results), # Serialize to JSON
|
93 |
+
json.dumps(initial_selected_krs), # Serialize to JSON
|
94 |
+
json.dumps(initial_krs_for_selection) # Serialize to JSON
|
95 |
)
|
96 |
|
97 |
if not self.agentic_modules_really_loaded:
|
|
|
102 |
if self.report_components.get("agentic_report_display_md"):
|
103 |
report_display_md_update = gr.update(value=error_status)
|
104 |
|
105 |
+
# Update for key_results_cbg (CheckboxGroup) in error case
|
106 |
if self.okrs_components.get("key_results_cbg"):
|
107 |
+
okrs_cbg_update = gr.update(choices=[], value=[], interactive=False)
|
108 |
|
109 |
if self.okrs_components.get("okr_detail_display_md"):
|
110 |
okrs_detail_md_update = gr.update(value=error_status)
|
111 |
|
112 |
yield (
|
113 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
114 |
+
json.dumps(None), json.dumps([]), json.dumps([]) # Serialize to JSON
|
115 |
)
|
116 |
return
|
117 |
|
|
|
132 |
logging.info(f"Autonomous agentic pipeline finished. Output keys: {orchestration_output.keys() if orchestration_output else 'None'}")
|
133 |
|
134 |
orchestration_results_update_val = None
|
135 |
+
selected_krs_update_val = [] # This will be the value for the CheckboxGroup, initially empty
|
136 |
krs_for_selection_update_val = []
|
137 |
|
138 |
if orchestration_output:
|
|
|
144 |
|
145 |
actionable_okrs = orchestration_output.get('actionable_okrs_and_tasks')
|
146 |
krs_for_ui_selection_list = extract_key_results_for_selection(actionable_okrs)
|
147 |
+
krs_for_selection_update_val = krs_for_ui_selection_list # This is the list of dicts
|
148 |
|
149 |
+
# Prepare choices for key_results_cbg (CheckboxGroup)
|
150 |
+
kr_choices_for_cbg = [(kr['kr_description'], kr['unique_kr_id']) for kr in krs_for_ui_selection_list]
|
151 |
if self.okrs_components.get("key_results_cbg"):
|
152 |
+
okrs_cbg_update = gr.update(choices=kr_choices_for_cbg, value=[], interactive=True)
|
153 |
|
154 |
all_okrs_md_parts = []
|
155 |
if actionable_okrs and isinstance(actionable_okrs.get("okrs"), list):
|
|
|
163 |
if self.okrs_components.get("okr_detail_display_md"):
|
164 |
okrs_detail_md_update = gr.update(value="\n\n---\n\n".join(all_okrs_md_parts))
|
165 |
|
166 |
+
selected_krs_update_val = [] # Reset CheckboxGroup selection
|
167 |
else:
|
168 |
final_status_text = "Pipeline AI (Sempre): Nessun risultato prodotto."
|
169 |
if self.report_components.get("agentic_report_display_md"):
|
170 |
report_display_md_update = gr.update(value="Nessun report generato dalla pipeline AI (Sempre).")
|
171 |
|
172 |
+
# Update for key_results_cbg (CheckboxGroup) if no output
|
173 |
if self.okrs_components.get("key_results_cbg"):
|
174 |
+
okrs_cbg_update = gr.update(choices=[], value=[], interactive=False)
|
175 |
|
176 |
if self.okrs_components.get("okr_detail_display_md"):
|
177 |
okrs_detail_md_update = gr.update(value="Nessun OKR generato o errore nella pipeline AI (Sempre).")
|
|
|
181 |
|
182 |
yield (
|
183 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
184 |
+
json.dumps(orchestration_results_update_val), # Serialize to JSON
|
185 |
+
json.dumps(selected_krs_update_val), # Serialize to JSON (value for selected_key_result_ids_st)
|
186 |
+
json.dumps(krs_for_selection_update_val) # Serialize to JSON (value for key_results_for_selection_st)
|
187 |
)
|
188 |
|
189 |
except Exception as e:
|
|
|
194 |
if self.report_components.get("agentic_report_display_md"):
|
195 |
report_display_md_update = gr.update(value=f"Errore generazione report AI (Sempre): {str(e)}")
|
196 |
|
197 |
+
# Update for key_results_cbg (CheckboxGroup) in case of exception
|
198 |
if self.okrs_components.get("key_results_cbg"):
|
199 |
+
okrs_cbg_update = gr.update(choices=[], value=[], interactive=False)
|
200 |
|
201 |
if self.okrs_components.get("okr_detail_display_md"):
|
202 |
okrs_detail_md_update = gr.update(value=f"Errore generazione OKR AI (Sempre): {str(e)}")
|
203 |
|
204 |
yield (
|
205 |
report_status_md_update, report_display_md_update, okrs_cbg_update, okrs_detail_md_update,
|
206 |
+
json.dumps(None), json.dumps([]), json.dumps([]) # Serialize to JSON
|
207 |
)
|
208 |
|
209 |
def update_okr_display_on_kr_selection(self, selected_kr_unique_ids: list,
|
210 |
+
raw_orchestration_results_json: str,
|
211 |
+
all_krs_for_selection_list_json: str):
|
212 |
"""
|
213 |
Updates the OKR detail display when Key Results are selected in the CheckboxGroup.
|
214 |
+
raw_orchestration_results_json and all_krs_for_selection_list_json are expected
|
215 |
+
to be JSON strings from state.
|
216 |
"""
|
|
|
|
|
|
|
|
|
|
|
217 |
if not self.agentic_modules_really_loaded:
|
218 |
return gr.update(value="Moduli AI non caricati. Impossibile visualizzare i dettagli OKR.")
|
219 |
|
220 |
+
parsed_orchestration_results = None
|
221 |
+
try:
|
222 |
+
if raw_orchestration_results_json: # Check if the string is not empty
|
223 |
+
parsed_orchestration_results = json.loads(raw_orchestration_results_json)
|
224 |
+
except json.JSONDecodeError as e:
|
225 |
+
logging.error(f"Failed to parse raw_orchestration_results_json: {raw_orchestration_results_json}. Error: {e}")
|
226 |
+
return gr.update(value="Errore: Dati interni corrotti (orchestration results).")
|
|
|
227 |
|
228 |
+
if not parsed_orchestration_results: # This covers None or empty after parsing
|
229 |
+
return gr.update(value="Nessun dato dalla pipeline AI (orchestration results).")
|
230 |
|
231 |
+
parsed_krs_for_selection_list = []
|
232 |
+
try:
|
233 |
+
if all_krs_for_selection_list_json: # Check if the string is not empty
|
234 |
+
parsed_krs_for_selection_list = json.loads(all_krs_for_selection_list_json)
|
235 |
+
except json.JSONDecodeError as e:
|
236 |
+
logging.error(f"Failed to parse all_krs_for_selection_list_json: {all_krs_for_selection_list_json}. Error: {e}")
|
237 |
+
return gr.update(value="Errore: Dati interni corrotti (krs for selection).")
|
238 |
+
|
239 |
+
# Ensure parsed_krs_for_selection_list is a list, even if JSON was 'null' or other non-list type
|
240 |
+
if not isinstance(parsed_krs_for_selection_list, list):
|
241 |
+
logging.warning(f"Parsed all_krs_for_selection_list is not a list: {type(parsed_krs_for_selection_list)}. Defaulting to empty list.")
|
242 |
+
parsed_krs_for_selection_list = []
|
243 |
+
|
244 |
+
|
245 |
+
actionable_okrs_dict = parsed_orchestration_results.get("actionable_okrs_and_tasks") if isinstance(parsed_orchestration_results, dict) else None
|
246 |
|
247 |
if not actionable_okrs_dict or not isinstance(actionable_okrs_dict.get("okrs"), list):
|
248 |
return gr.update(value="Nessun OKR trovato nei risultati della pipeline (o dati in formato imprevisto).")
|
|
|
252 |
return gr.update(value="Nessun OKR generato.")
|
253 |
|
254 |
kr_id_to_indices = {}
|
255 |
+
if isinstance(parsed_krs_for_selection_list, list): # Ensure it's a list before iterating
|
256 |
+
for kr_info in parsed_krs_for_selection_list:
|
257 |
+
if isinstance(kr_info, dict) and 'unique_kr_id' in kr_info and 'okr_index' in kr_info and 'kr_index' in kr_info:
|
|
|
258 |
kr_id_to_indices[kr_info['unique_kr_id']] = (kr_info['okr_index'], kr_info['kr_index'])
|
259 |
+
else:
|
260 |
+
logging.warning(f"Skipping invalid kr_info item: {kr_info}")
|
261 |
+
|
262 |
selected_krs_by_okr_idx = defaultdict(list)
|
263 |
+
# selected_kr_unique_ids comes directly from CheckboxGroup, should be a list of strings/values
|
264 |
+
if isinstance(selected_kr_unique_ids, list):
|
265 |
for kr_unique_id in selected_kr_unique_ids:
|
266 |
if kr_unique_id in kr_id_to_indices:
|
267 |
okr_idx, kr_idx_in_okr = kr_id_to_indices[kr_unique_id]
|
|
|
311 |
self.key_results_for_selection_st
|
312 |
],
|
313 |
outputs=[self.okrs_components['okr_detail_display_md']],
|
314 |
+
api_name="update_okr_display_on_kr_selection" # Keep api_name for Gradio
|
315 |
)
|
316 |
logging.info("Agentic OKR selection handler setup complete.")
|
317 |
else:
|