File size: 12,186 Bytes
1cbff0c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# ui/agentic_module.py
import gradio as gr
import logging
from collections import defaultdict

# --- Module Imports ---
try:
    from run_agentic_pipeline import run_full_analytics_orchestration
    from ui.insights_ui_generator import (
        format_report_to_markdown,
        extract_key_results_for_selection,
        format_single_okr_for_display
    )
    AGENTIC_MODULES_LOADED = True
except ImportError as e:
    logging.error(f"Could not import agentic pipeline modules in agentic_module.py: {e}.")
    AGENTIC_MODULES_LOADED = False
    async def run_full_analytics_orchestration(*args, **kwargs): return None
    def format_report_to_markdown(report_string): return "Agentic modules not loaded. Report unavailable."
    def extract_key_results_for_selection(okrs_dict): return []
    def format_single_okr_for_display(okr_data, **kwargs): return "Agentic modules not loaded. OKR display unavailable."

logger = logging.getLogger(__name__)

# Store references to UI components that handlers need to update
_agentic_report_display_md = None
_key_results_cbg = None
_okr_detail_display_md = None
_agentic_pipeline_status_md = None


def handle_update_okr_display(selected_kr_unique_ids: list, raw_orchestration_results: dict, all_krs_for_selection: list):
    if not raw_orchestration_results or not AGENTIC_MODULES_LOADED:
        return gr.update(value="Nessun dato dalla pipeline AI o moduli non caricati.")
    
    actionable_okrs_dict = raw_orchestration_results.get("actionable_okrs_and_tasks")
    if not actionable_okrs_dict or not isinstance(actionable_okrs_dict.get("okrs"), list):
        return gr.update(value="Nessun OKR trovato nei risultati della pipeline.")
    
    okrs_list = actionable_okrs_dict["okrs"]
    # Rebuild kr_id_to_indices based on the structure of all_krs_for_selection
    # all_krs_for_selection is: [{'okr_index': int, 'kr_index': int, 'unique_kr_id': str, ...}]
    kr_id_to_indices = {kr_info['unique_kr_id']: (kr_info['okr_index'], kr_info['kr_index']) 
                        for kr_info in all_krs_for_selection if isinstance(kr_info, dict) and 'unique_kr_id' in kr_info}

    selected_krs_by_okr_idx = defaultdict(list)
    if selected_kr_unique_ids:
        for kr_unique_id in selected_kr_unique_ids:
            if kr_unique_id in kr_id_to_indices:
                okr_idx, kr_idx = kr_id_to_indices[kr_unique_id]
                selected_krs_by_okr_idx[okr_idx].append(kr_idx)
            else:
                logger.warning(f"Selected KR ID '{kr_unique_id}' not found in kr_id_to_indices map.")


    output_md_parts = []
    if not okrs_list:
        output_md_parts.append("Nessun OKR generato.")
    else:
        for okr_idx, okr_data in enumerate(okrs_list):
            accepted_indices_for_this_okr = selected_krs_by_okr_idx.get(okr_idx)
            # If specific KRs are selected, only show OKRs that have at least one of those selected KRs
            if selected_kr_unique_ids: # User has made a selection
                if accepted_indices_for_this_okr is not None: # This OKR has some selected KRs
                     output_md_parts.append(format_single_okr_for_display(okr_data, accepted_kr_indices=accepted_indices_for_this_okr, okr_main_index=okr_idx))
            else: # No KRs selected, show all OKRs with all their KRs
                output_md_parts.append(format_single_okr_for_display(okr_data, accepted_kr_indices=None, okr_main_index=okr_idx))
    
    if not output_md_parts and selected_kr_unique_ids:
        final_md = "Nessun OKR corrisponde alla selezione corrente o i KR selezionati non hanno task dettagliati."
    elif not output_md_parts and not selected_kr_unique_ids and okrs_list : # OKRs exist but somehow didn't format
        final_md = "Nessun OKR da visualizzare in base alla selezione (o tutti OKR visualizzati)."
    elif not output_md_parts and not okrs_list:
         final_md = "Nessun OKR generato."
    else:
        final_md = "\n\n---\n\n".join(output_md_parts)
        
    return gr.update(value=final_md)


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):
    logger.info(f"Agentic pipeline check triggered. Current token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")

    if not current_token_state_val or not current_token_state_val.get("token"):
        logger.info("Agentic pipeline: Token not available in token_state. Skipping.")
        yield (
            gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # report_display
            gr.update(choices=[], value=[], interactive=False), # key_results_cbg
            gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # okr_detail_display
            None, # orchestration_raw_results_st
            [],   # selected_key_result_ids_st
            [],   # key_results_for_selection_st
            "Pipeline AI: In attesa dei dati..." # agentic_pipeline_status_md
        )
        return

    logger.info("Agentic pipeline starting autonomously with 'Sempre' filter.")
    yield (
        gr.update(value="Analisi AI (Sempre) in corso..."),
        gr.update(choices=[], value=[], interactive=False),
        gr.update(value="Dettagli OKR (Sempre) in corso di generazione..."),
        orchestration_raw_results_st_val, # Preserve existing results
        selected_key_result_ids_st_val,
        key_results_for_selection_st_val,
        "Esecuzione pipeline AI (Sempre)..."
    )

    if not AGENTIC_MODULES_LOADED:
        logger.warning("Agentic modules not loaded. Skipping autonomous pipeline.")
        yield (
            gr.update(value="Moduli AI non caricati. Report non disponibile."),
            gr.update(choices=[], value=[], interactive=False),
            gr.update(value="Moduli AI non caricati. OKR non disponibili."),
            None, [], [], "Pipeline AI: Moduli non caricati."
        )
        return

    try:
        date_filter_val_agentic = "Sempre"
        custom_start_val_agentic = None
        custom_end_val_agentic = None
        
        orchestration_output = await run_full_analytics_orchestration(
            current_token_state_val, date_filter_val_agentic, 
            custom_start_val_agentic, custom_end_val_agentic
        )
        agentic_status_text = "Pipeline AI (Sempre) completata."
        logger.info(f"Autonomous agentic pipeline finished. Output keys: {orchestration_output.keys() if orchestration_output else 'None'}")

        if orchestration_output:
            orchestration_results_update = orchestration_output
            report_str = orchestration_output.get('comprehensive_analysis_report')
            agentic_report_md_update = gr.update(value=format_report_to_markdown(report_str))
            
            actionable_okrs = orchestration_output.get('actionable_okrs_and_tasks')
            krs_for_ui_selection_list = extract_key_results_for_selection(actionable_okrs)
            krs_for_selection_update = krs_for_ui_selection_list # This is the list of dicts for the state
            
            kr_choices_for_cbg = [(kr['kr_description'], kr['unique_kr_id']) for kr in krs_for_ui_selection_list if isinstance(kr, dict)]
            key_results_cbg_update = gr.update(choices=kr_choices_for_cbg, value=[], interactive=True)
            
            # Default display for OKRs: show all, as if no KR is selected yet.
            all_okrs_md_parts = []
            if actionable_okrs and isinstance(actionable_okrs.get("okrs"), list):
                for okr_idx, okr_item in enumerate(actionable_okrs["okrs"]):
                    all_okrs_md_parts.append(format_single_okr_for_display(okr_item, accepted_kr_indices=None, okr_main_index=okr_idx))
            
            if not all_okrs_md_parts:
                okr_detail_display_md_update = gr.update(value="Nessun OKR generato o trovato (Sempre).")
            else:
                okr_detail_display_md_update = gr.update(value="\n\n---\n\n".join(all_okrs_md_parts))
            
            selected_krs_update = [] # Reset selection
        else:
            agentic_report_md_update = gr.update(value="Nessun report generato dalla pipeline AI (Sempre).")
            key_results_cbg_update = gr.update(choices=[], value=[], interactive=False)
            okr_detail_display_md_update = gr.update(value="Nessun OKR generato o errore nella pipeline AI (Sempre).")
            orchestration_results_update = None
            selected_krs_update = []
            krs_for_selection_update = []
            
        yield (agentic_report_md_update, key_results_cbg_update, okr_detail_display_md_update, 
               orchestration_results_update, selected_krs_update, krs_for_selection_update, agentic_status_text)

    except Exception as e:
        logger.error(f"Error during autonomous agentic pipeline execution: {e}", exc_info=True)
        agentic_status_text = f"Errore pipeline AI (Sempre): {str(e)}"
        yield (
            gr.update(value=f"Errore generazione report AI (Sempre): {str(e)}"),
            gr.update(choices=[], value=[], interactive=False),
            gr.update(value=f"Errore generazione OKR AI (Sempre): {str(e)}"),
            None, [], [], agentic_status_text
        )


def build_and_wire_tabs(orchestration_raw_results_st, key_results_for_selection_st, selected_key_result_ids_st):
    """Builds the UI for Agentic Tabs and wires up internal event handlers."""
    global _agentic_report_display_md, _key_results_cbg, _okr_detail_display_md, _agentic_pipeline_status_md

    with gr.TabItem("3️⃣ Agentic Analysis Report", id="tab_agentic_report", visible=AGENTIC_MODULES_LOADED):
        gr.Markdown("## 🤖 Comprehensive Analysis Report (AI Generated)")
        _agentic_pipeline_status_md = gr.Markdown("Stato Pipeline AI (filtro 'Sempre'): In attesa...", visible=True)
        gr.Markdown("Questo report è generato da un agente AI con filtro 'Sempre' sui dati disponibili. Rivedi criticamente.")
        _agentic_report_display_md = gr.Markdown("La pipeline AI si avvierà automaticamente dopo il caricamento iniziale dei dati o dopo una sincronizzazione.")
        if not AGENTIC_MODULES_LOADED:
            gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")

    with gr.TabItem("4️⃣ Agentic OKRs & Tasks", id="tab_agentic_okrs", visible=AGENTIC_MODULES_LOADED):
        gr.Markdown("## 🎯 AI Generated OKRs and Actionable Tasks (filtro 'Sempre')")
        gr.Markdown("Basato sull'analisi AI (filtro 'Sempre'), l'agente ha proposto i seguenti OKR e task. Seleziona i Key Results per dettagli.")
        if not AGENTIC_MODULES_LOADED:
            gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
        
        with gr.Row():
            with gr.Column(scale=1):
                gr.Markdown("### Suggested Key Results (da analisi 'Sempre')")
                _key_results_cbg = gr.CheckboxGroup(label="Select Key Results", choices=[], value=[], interactive=True)
            with gr.Column(scale=3):
                gr.Markdown("### Detailed OKRs and Tasks for Selected Key Results")
                _okr_detail_display_md = gr.Markdown("I dettagli OKR appariranno qui dopo l'esecuzione della pipeline AI.")
        
        if AGENTIC_MODULES_LOADED:
            _key_results_cbg.change(
                fn=handle_update_okr_display, # This handler now correctly returns gr.update()
                inputs=[_key_results_cbg, orchestration_raw_results_st, key_results_for_selection_st],
                outputs=[_okr_detail_display_md]
            )

    # Components to be updated by handle_run_agentic_pipeline
    # Order must match the yield tuple in handle_run_agentic_pipeline
    agentic_pipeline_outputs_components = [
        _agentic_report_display_md, 
        _key_results_cbg, 
        _okr_detail_display_md,
        # orchestration_raw_results_st, # State
        # selected_key_result_ids_st,   # State
        # key_results_for_selection_st, # State
        _agentic_pipeline_status_md
    ]
    
    return agentic_pipeline_outputs_components