Spaces:
Running
Running
Create agentic_module.py
Browse files- ui/agentic_module.py +222 -0
ui/agentic_module.py
ADDED
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ui/agentic_module.py
|
2 |
+
import gradio as gr
|
3 |
+
import logging
|
4 |
+
from collections import defaultdict
|
5 |
+
|
6 |
+
# --- Module Imports ---
|
7 |
+
try:
|
8 |
+
from run_agentic_pipeline import run_full_analytics_orchestration
|
9 |
+
from ui.insights_ui_generator import (
|
10 |
+
format_report_to_markdown,
|
11 |
+
extract_key_results_for_selection,
|
12 |
+
format_single_okr_for_display
|
13 |
+
)
|
14 |
+
AGENTIC_MODULES_LOADED = True
|
15 |
+
except ImportError as e:
|
16 |
+
logging.error(f"Could not import agentic pipeline modules in agentic_module.py: {e}.")
|
17 |
+
AGENTIC_MODULES_LOADED = False
|
18 |
+
async def run_full_analytics_orchestration(*args, **kwargs): return None
|
19 |
+
def format_report_to_markdown(report_string): return "Agentic modules not loaded. Report unavailable."
|
20 |
+
def extract_key_results_for_selection(okrs_dict): return []
|
21 |
+
def format_single_okr_for_display(okr_data, **kwargs): return "Agentic modules not loaded. OKR display unavailable."
|
22 |
+
|
23 |
+
logger = logging.getLogger(__name__)
|
24 |
+
|
25 |
+
# Store references to UI components that handlers need to update
|
26 |
+
_agentic_report_display_md = None
|
27 |
+
_key_results_cbg = None
|
28 |
+
_okr_detail_display_md = None
|
29 |
+
_agentic_pipeline_status_md = None
|
30 |
+
|
31 |
+
|
32 |
+
def handle_update_okr_display(selected_kr_unique_ids: list, raw_orchestration_results: dict, all_krs_for_selection: list):
|
33 |
+
if not raw_orchestration_results or not AGENTIC_MODULES_LOADED:
|
34 |
+
return gr.update(value="Nessun dato dalla pipeline AI o moduli non caricati.")
|
35 |
+
|
36 |
+
actionable_okrs_dict = raw_orchestration_results.get("actionable_okrs_and_tasks")
|
37 |
+
if not actionable_okrs_dict or not isinstance(actionable_okrs_dict.get("okrs"), list):
|
38 |
+
return gr.update(value="Nessun OKR trovato nei risultati della pipeline.")
|
39 |
+
|
40 |
+
okrs_list = actionable_okrs_dict["okrs"]
|
41 |
+
# Rebuild kr_id_to_indices based on the structure of all_krs_for_selection
|
42 |
+
# all_krs_for_selection is: [{'okr_index': int, 'kr_index': int, 'unique_kr_id': str, ...}]
|
43 |
+
kr_id_to_indices = {kr_info['unique_kr_id']: (kr_info['okr_index'], kr_info['kr_index'])
|
44 |
+
for kr_info in all_krs_for_selection if isinstance(kr_info, dict) and 'unique_kr_id' in kr_info}
|
45 |
+
|
46 |
+
selected_krs_by_okr_idx = defaultdict(list)
|
47 |
+
if selected_kr_unique_ids:
|
48 |
+
for kr_unique_id in selected_kr_unique_ids:
|
49 |
+
if kr_unique_id in kr_id_to_indices:
|
50 |
+
okr_idx, kr_idx = kr_id_to_indices[kr_unique_id]
|
51 |
+
selected_krs_by_okr_idx[okr_idx].append(kr_idx)
|
52 |
+
else:
|
53 |
+
logger.warning(f"Selected KR ID '{kr_unique_id}' not found in kr_id_to_indices map.")
|
54 |
+
|
55 |
+
|
56 |
+
output_md_parts = []
|
57 |
+
if not okrs_list:
|
58 |
+
output_md_parts.append("Nessun OKR generato.")
|
59 |
+
else:
|
60 |
+
for okr_idx, okr_data in enumerate(okrs_list):
|
61 |
+
accepted_indices_for_this_okr = selected_krs_by_okr_idx.get(okr_idx)
|
62 |
+
# If specific KRs are selected, only show OKRs that have at least one of those selected KRs
|
63 |
+
if selected_kr_unique_ids: # User has made a selection
|
64 |
+
if accepted_indices_for_this_okr is not None: # This OKR has some selected KRs
|
65 |
+
output_md_parts.append(format_single_okr_for_display(okr_data, accepted_kr_indices=accepted_indices_for_this_okr, okr_main_index=okr_idx))
|
66 |
+
else: # No KRs selected, show all OKRs with all their KRs
|
67 |
+
output_md_parts.append(format_single_okr_for_display(okr_data, accepted_kr_indices=None, okr_main_index=okr_idx))
|
68 |
+
|
69 |
+
if not output_md_parts and selected_kr_unique_ids:
|
70 |
+
final_md = "Nessun OKR corrisponde alla selezione corrente o i KR selezionati non hanno task dettagliati."
|
71 |
+
elif not output_md_parts and not selected_kr_unique_ids and okrs_list : # OKRs exist but somehow didn't format
|
72 |
+
final_md = "Nessun OKR da visualizzare in base alla selezione (o tutti OKR visualizzati)."
|
73 |
+
elif not output_md_parts and not okrs_list:
|
74 |
+
final_md = "Nessun OKR generato."
|
75 |
+
else:
|
76 |
+
final_md = "\n\n---\n\n".join(output_md_parts)
|
77 |
+
|
78 |
+
return gr.update(value=final_md)
|
79 |
+
|
80 |
+
|
81 |
+
async def handle_run_agentic_pipeline(current_token_state_val, orchestration_raw_results_st_val, key_results_for_selection_st_val, selected_key_result_ids_st_val):
|
82 |
+
logger.info(f"Agentic pipeline check triggered. Current token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")
|
83 |
+
|
84 |
+
if not current_token_state_val or not current_token_state_val.get("token"):
|
85 |
+
logger.info("Agentic pipeline: Token not available in token_state. Skipping.")
|
86 |
+
yield (
|
87 |
+
gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # report_display
|
88 |
+
gr.update(choices=[], value=[], interactive=False), # key_results_cbg
|
89 |
+
gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # okr_detail_display
|
90 |
+
None, # orchestration_raw_results_st
|
91 |
+
[], # selected_key_result_ids_st
|
92 |
+
[], # key_results_for_selection_st
|
93 |
+
"Pipeline AI: In attesa dei dati..." # agentic_pipeline_status_md
|
94 |
+
)
|
95 |
+
return
|
96 |
+
|
97 |
+
logger.info("Agentic pipeline starting autonomously with 'Sempre' filter.")
|
98 |
+
yield (
|
99 |
+
gr.update(value="Analisi AI (Sempre) in corso..."),
|
100 |
+
gr.update(choices=[], value=[], interactive=False),
|
101 |
+
gr.update(value="Dettagli OKR (Sempre) in corso di generazione..."),
|
102 |
+
orchestration_raw_results_st_val, # Preserve existing results
|
103 |
+
selected_key_result_ids_st_val,
|
104 |
+
key_results_for_selection_st_val,
|
105 |
+
"Esecuzione pipeline AI (Sempre)..."
|
106 |
+
)
|
107 |
+
|
108 |
+
if not AGENTIC_MODULES_LOADED:
|
109 |
+
logger.warning("Agentic modules not loaded. Skipping autonomous pipeline.")
|
110 |
+
yield (
|
111 |
+
gr.update(value="Moduli AI non caricati. Report non disponibile."),
|
112 |
+
gr.update(choices=[], value=[], interactive=False),
|
113 |
+
gr.update(value="Moduli AI non caricati. OKR non disponibili."),
|
114 |
+
None, [], [], "Pipeline AI: Moduli non caricati."
|
115 |
+
)
|
116 |
+
return
|
117 |
+
|
118 |
+
try:
|
119 |
+
date_filter_val_agentic = "Sempre"
|
120 |
+
custom_start_val_agentic = None
|
121 |
+
custom_end_val_agentic = None
|
122 |
+
|
123 |
+
orchestration_output = await run_full_analytics_orchestration(
|
124 |
+
current_token_state_val, date_filter_val_agentic,
|
125 |
+
custom_start_val_agentic, custom_end_val_agentic
|
126 |
+
)
|
127 |
+
agentic_status_text = "Pipeline AI (Sempre) completata."
|
128 |
+
logger.info(f"Autonomous agentic pipeline finished. Output keys: {orchestration_output.keys() if orchestration_output else 'None'}")
|
129 |
+
|
130 |
+
if orchestration_output:
|
131 |
+
orchestration_results_update = orchestration_output
|
132 |
+
report_str = orchestration_output.get('comprehensive_analysis_report')
|
133 |
+
agentic_report_md_update = gr.update(value=format_report_to_markdown(report_str))
|
134 |
+
|
135 |
+
actionable_okrs = orchestration_output.get('actionable_okrs_and_tasks')
|
136 |
+
krs_for_ui_selection_list = extract_key_results_for_selection(actionable_okrs)
|
137 |
+
krs_for_selection_update = krs_for_ui_selection_list # This is the list of dicts for the state
|
138 |
+
|
139 |
+
kr_choices_for_cbg = [(kr['kr_description'], kr['unique_kr_id']) for kr in krs_for_ui_selection_list if isinstance(kr, dict)]
|
140 |
+
key_results_cbg_update = gr.update(choices=kr_choices_for_cbg, value=[], interactive=True)
|
141 |
+
|
142 |
+
# Default display for OKRs: show all, as if no KR is selected yet.
|
143 |
+
all_okrs_md_parts = []
|
144 |
+
if actionable_okrs and isinstance(actionable_okrs.get("okrs"), list):
|
145 |
+
for okr_idx, okr_item in enumerate(actionable_okrs["okrs"]):
|
146 |
+
all_okrs_md_parts.append(format_single_okr_for_display(okr_item, accepted_kr_indices=None, okr_main_index=okr_idx))
|
147 |
+
|
148 |
+
if not all_okrs_md_parts:
|
149 |
+
okr_detail_display_md_update = gr.update(value="Nessun OKR generato o trovato (Sempre).")
|
150 |
+
else:
|
151 |
+
okr_detail_display_md_update = gr.update(value="\n\n---\n\n".join(all_okrs_md_parts))
|
152 |
+
|
153 |
+
selected_krs_update = [] # Reset selection
|
154 |
+
else:
|
155 |
+
agentic_report_md_update = gr.update(value="Nessun report generato dalla pipeline AI (Sempre).")
|
156 |
+
key_results_cbg_update = gr.update(choices=[], value=[], interactive=False)
|
157 |
+
okr_detail_display_md_update = gr.update(value="Nessun OKR generato o errore nella pipeline AI (Sempre).")
|
158 |
+
orchestration_results_update = None
|
159 |
+
selected_krs_update = []
|
160 |
+
krs_for_selection_update = []
|
161 |
+
|
162 |
+
yield (agentic_report_md_update, key_results_cbg_update, okr_detail_display_md_update,
|
163 |
+
orchestration_results_update, selected_krs_update, krs_for_selection_update, agentic_status_text)
|
164 |
+
|
165 |
+
except Exception as e:
|
166 |
+
logger.error(f"Error during autonomous agentic pipeline execution: {e}", exc_info=True)
|
167 |
+
agentic_status_text = f"Errore pipeline AI (Sempre): {str(e)}"
|
168 |
+
yield (
|
169 |
+
gr.update(value=f"Errore generazione report AI (Sempre): {str(e)}"),
|
170 |
+
gr.update(choices=[], value=[], interactive=False),
|
171 |
+
gr.update(value=f"Errore generazione OKR AI (Sempre): {str(e)}"),
|
172 |
+
None, [], [], agentic_status_text
|
173 |
+
)
|
174 |
+
|
175 |
+
|
176 |
+
def build_and_wire_tabs(orchestration_raw_results_st, key_results_for_selection_st, selected_key_result_ids_st):
|
177 |
+
"""Builds the UI for Agentic Tabs and wires up internal event handlers."""
|
178 |
+
global _agentic_report_display_md, _key_results_cbg, _okr_detail_display_md, _agentic_pipeline_status_md
|
179 |
+
|
180 |
+
with gr.TabItem("3️⃣ Agentic Analysis Report", id="tab_agentic_report", visible=AGENTIC_MODULES_LOADED):
|
181 |
+
gr.Markdown("## 🤖 Comprehensive Analysis Report (AI Generated)")
|
182 |
+
_agentic_pipeline_status_md = gr.Markdown("Stato Pipeline AI (filtro 'Sempre'): In attesa...", visible=True)
|
183 |
+
gr.Markdown("Questo report è generato da un agente AI con filtro 'Sempre' sui dati disponibili. Rivedi criticamente.")
|
184 |
+
_agentic_report_display_md = gr.Markdown("La pipeline AI si avvierà automaticamente dopo il caricamento iniziale dei dati o dopo una sincronizzazione.")
|
185 |
+
if not AGENTIC_MODULES_LOADED:
|
186 |
+
gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
|
187 |
+
|
188 |
+
with gr.TabItem("4️⃣ Agentic OKRs & Tasks", id="tab_agentic_okrs", visible=AGENTIC_MODULES_LOADED):
|
189 |
+
gr.Markdown("## 🎯 AI Generated OKRs and Actionable Tasks (filtro 'Sempre')")
|
190 |
+
gr.Markdown("Basato sull'analisi AI (filtro 'Sempre'), l'agente ha proposto i seguenti OKR e task. Seleziona i Key Results per dettagli.")
|
191 |
+
if not AGENTIC_MODULES_LOADED:
|
192 |
+
gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
|
193 |
+
|
194 |
+
with gr.Row():
|
195 |
+
with gr.Column(scale=1):
|
196 |
+
gr.Markdown("### Suggested Key Results (da analisi 'Sempre')")
|
197 |
+
_key_results_cbg = gr.CheckboxGroup(label="Select Key Results", choices=[], value=[], interactive=True)
|
198 |
+
with gr.Column(scale=3):
|
199 |
+
gr.Markdown("### Detailed OKRs and Tasks for Selected Key Results")
|
200 |
+
_okr_detail_display_md = gr.Markdown("I dettagli OKR appariranno qui dopo l'esecuzione della pipeline AI.")
|
201 |
+
|
202 |
+
if AGENTIC_MODULES_LOADED:
|
203 |
+
_key_results_cbg.change(
|
204 |
+
fn=handle_update_okr_display, # This handler now correctly returns gr.update()
|
205 |
+
inputs=[_key_results_cbg, orchestration_raw_results_st, key_results_for_selection_st],
|
206 |
+
outputs=[_okr_detail_display_md]
|
207 |
+
)
|
208 |
+
|
209 |
+
# Components to be updated by handle_run_agentic_pipeline
|
210 |
+
# Order must match the yield tuple in handle_run_agentic_pipeline
|
211 |
+
agentic_pipeline_outputs_components = [
|
212 |
+
_agentic_report_display_md,
|
213 |
+
_key_results_cbg,
|
214 |
+
_okr_detail_display_md,
|
215 |
+
# orchestration_raw_results_st, # State
|
216 |
+
# selected_key_result_ids_st, # State
|
217 |
+
# key_results_for_selection_st, # State
|
218 |
+
_agentic_pipeline_status_md
|
219 |
+
]
|
220 |
+
|
221 |
+
return agentic_pipeline_outputs_components
|
222 |
+
|