File size: 14,125 Bytes
c0a4e63
0cfca76
 
 
8ed7829
6faec7c
fed5558
 
 
055c98e
 
0cfca76
5cb07dc
 
055c98e
5cb07dc
 
 
055c98e
 
5f0b7f9
055c98e
5cb07dc
 
708a26e
5cb07dc
 
 
 
5f0b7f9
6faec7c
5cb07dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
055c98e
0cfca76
 
6faec7c
8ed7829
6faec7c
 
0cfca76
 
6faec7c
 
0cfca76
 
5cb07dc
 
8ed7829
5cb07dc
708a26e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5cb07dc
0cfca76
708a26e
 
5cb07dc
 
708a26e
5cb07dc
 
708a26e
5cb07dc
 
 
6086ed3
 
 
708a26e
5cb07dc
708a26e
 
 
 
 
 
 
 
 
 
 
 
5cb07dc
 
708a26e
5f0b7f9
0cfca76
5f0b7f9
0cfca76
6faec7c
0cfca76
5f0b7f9
0cfca76
 
6faec7c
5cb07dc
0cfca76
 
5cb07dc
6faec7c
 
5cb07dc
0cfca76
 
5f0b7f9
d40cdca
708a26e
 
 
 
 
 
0cfca76
5cb07dc
708a26e
 
 
 
 
0cfca76
5f0b7f9
6faec7c
 
5cb07dc
708a26e
5cb07dc
 
0cfca76
 
5cb07dc
fed5558
 
 
 
5cb07dc
 
 
 
 
 
 
 
 
 
 
 
 
708a26e
5cb07dc
 
0cfca76
6faec7c
fed5558
5cb07dc
5f0b7f9
6faec7c
5cb07dc
0cfca76
5cb07dc
 
 
 
 
 
 
 
 
 
 
0cfca76
6086ed3
0cfca76
 
5cb07dc
708a26e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5cb07dc
 
708a26e
5cb07dc
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import gradio as gr
import pandas as pd
import logging
from typing import Dict, Any, List, Optional

# Import the reconstruction function that now expects a cache dictionary
from services.report_data_handler import fetch_and_reconstruct_data_from_bubble

# UI formatting functions
try:
    from ui.insights_ui_generator import (
        format_report_for_display,
        # REMOVED: extract_key_results_for_selection, - No longer directly used here for display
        # REMOVED: format_single_okr_for_display - No longer directly used here for display
    )
    # NEW: Import the enhanced OKR display functions
    from ui.okr_ui_generator import format_okrs_for_enhanced_display, get_initial_okr_display

    AGENTIC_MODULES_LOADED = True
except ImportError as e:
    logging.error(f"Could not import agentic pipeline display modules: {e}. Tabs 3 and 4 will be disabled.")
    AGENTIC_MODULES_LOADED = False
    # Placeholder functions for when modules are not loaded, ensuring return signatures match
    def format_report_for_display(report_data):
        return {'header_html': '<h1>Agentic modules not loaded.</h1>', 'body_markdown': 'Report display unavailable.'}
    # These functions are now used by app.py directly for placeholder returns if modules are not loaded,
    # but their definitions might still be expected in some contexts, so providing minimal ones.
    # We still need placeholders for the *return values* if the import fails, even if they're not called
    # directly within this file, to maintain the correct function signature for load_and_display_agentic_results.
    def extract_key_results_for_selection(okrs_dict): return []
    def format_single_okr_for_display(okr_data, **kwargs): return "Agentic modules not loaded."
    # Placeholder for the new OKR UI display
    def format_okrs_for_enhanced_display(raw_results): return get_initial_okr_display()
    def get_initial_okr_display(): return """
        <div class="okr-container">
            <div class="okr-header">
                <div class="okr-title">🎯 AI-Generated OKRs & Strategic Tasks</div>
                <div class="okr-subtitle">Intelligent objectives and key results based on your LinkedIn analytics</div>
            </div>
            <div class="okr-stats-bar">
                <div class="stat-card"><div class="stat-number">0</div><div class="stat-label">Objectives</div></div>
                <div class="stat-card"><div class="stat-number">0</div><div class="stat-label">Key Results</div></div>
                <div class="stat-card"><div class="stat-number">0</div><div class="stat-label">Tasks</div></div>
                <div class="stat-card"><div class="stat-number">0</div><div class="stat-label">High Priority</div></div>
            </div>
            <div class="okr-content">
                <div class="empty-state">
                    <div class="empty-state-icon">⚠️</div>
                    <div class="empty-state-title">Modules Not Loaded</div>
                    <div class="empty-state-description">
                        Agentic analysis modules could not be loaded. OKR display unavailable.
                    </div>
                </div>
            </div>
        </div>
    """


logger = logging.getLogger(__name__)

def load_and_display_agentic_results(token_state: dict, session_cache: dict):
    """
    Loads agentic results from state, populates the report library, and displays
    the LATEST report and its fully reconstructed OKRs by default, using a session-specific cache.

    Args:
        token_state: The main state dictionary with Bubble data.
        session_cache: The session-specific cache for reconstructed data.

    Returns:
        A tuple of Gradio updates, including the updated cache and the new enhanced OKR HTML.
        This function now returns 11 values to match the expected outputs in app.py.
    """
    # Define placeholder content for empty or error states to match 11 outputs
    empty_header_html = """
        <div class="report-title">πŸ“Š Comprehensive Analysis Report</div>
        <div class="report-subtitle">AI-Generated Insights from Your LinkedIn Data</div>
        <div class="status-badge">Generated from Bubble.io</div>
        """
    empty_body_markdown_no_selection = """
        <div class="empty-state">
            <div class="empty-state-icon">πŸ“„</div>
            <div class="empty-state-title">No Report Selected</div>
            <div class="empty-state-description">
                Please select a report from the library above to view its detailed analysis and insights.
            </div>
        </div>
        """

    # Default initial updates for 11 outputs
    initial_updates = (
        gr.update(value="Status: No agentic analysis data found."), # 0: agentic_pipeline_status_md
        gr.update(choices=[], value=None, interactive=False),       # 1: report_selector_dd
        gr.update(choices=[], value=[], interactive=False),         # 2: key_results_cbg (hidden in app.py)
        gr.update(value="No OKRs to display."),                     # 3: okr_detail_display_md (hidden in app.py)
        gr.update(value=None),                                      # 4: orchestration_raw_results_st
        gr.update(value=[]),                                        # 5: selected_key_result_ids_st (hidden in app.py)
        gr.update(value=[]),                                        # 6: key_results_for_selection_st (hidden in app.py)
        gr.update(value=empty_header_html),                         # 7: report_header_html_display
        gr.update(value=empty_body_markdown_no_selection),          # 8: report_body_markdown_display
        gr.update(value=session_cache),                             # 9: reconstruction_cache_st
        gr.update(value=get_initial_okr_display())                  # 10: enhanced_okr_display_html
    )

    if not AGENTIC_MODULES_LOADED:
        logger.error("Agentic modules not loaded, returning placeholder updates.")
        # Ensure error updates match the 11-item signature
        error_header_html = '<div class="report-title">Error Loading Report</div><div class="report-subtitle">Agentic modules not loaded.</div><div class="status-badge">Error</div>'
        error_body_markdown = '<div class="empty-state"><div class="empty-state-icon">❌</div><div class="empty-state-title">Module Error</div><div class="empty-state-description">Agentic analysis modules could not be loaded. Report display unavailable.</div></div>'
        return (
            gr.update(value="Status: Critical module import error."), # 0
            gr.update(choices=[], value=None, interactive=False), # 1
            gr.update(choices=[], value=[], interactive=False), # 2
            gr.update(value="Agentic modules not loaded. No OKRs to display."), # 3
            gr.update(value=None), # 4
            gr.update(value=[]), # 5
            gr.update(value=[]), # 6
            gr.update(value=error_header_html), # 7
            gr.update(value=error_body_markdown), # 8
            gr.update(value=session_cache), # 9
            gr.update(value=get_initial_okr_display()) # 10: Placeholder for enhanced OKR display
        )

    agentic_df = token_state.get("bubble_agentic_analysis_data")

    if agentic_df is None or agentic_df.empty:
        logger.warning("Agentic analysis DataFrame is missing or empty.")
        return initial_updates

    try:
        if 'Created Date' not in agentic_df.columns or '_id' not in agentic_df.columns:
            raise KeyError("Required columns ('Created Date', '_id') not found.")

        agentic_df['Created Date'] = pd.to_datetime(agentic_df['Created Date'])
        agentic_df = agentic_df.sort_values(by='Created Date', ascending=False).reset_index(drop=True)

        report_choices = [(f"{row.get('report_type', 'Report')} - {row['Created Date'].strftime('%Y-%m-%d %H:%M')}", row['_id'])
                          for _, row in agentic_df.iterrows()]

        if not report_choices:
            return initial_updates

        quarterly_reports_df = agentic_df[agentic_df['report_type'] == 'Quarter'].copy()
        if quarterly_reports_df.empty:
            logger.warning("No quarterly reports found, falling back to latest available report.")
            latest_report_series = agentic_df.iloc[0] # Use the absolute latest if no quarterly
        else:
            latest_report_series = quarterly_reports_df.iloc[0]

        latest_report_id = latest_report_series['_id']

        # Split the formatted report content into header and body
        formatted_report_parts = format_report_for_display(latest_report_series)
        report_header_content = formatted_report_parts['header_html']
        report_body_content = formatted_report_parts['body_markdown']

        report_selector_update = gr.update(choices=report_choices, value=latest_report_id, interactive=True)

        # --- MODIFIED: Use the session cache for data reconstruction ---
        reconstructed_data, updated_cache = fetch_and_reconstruct_data_from_bubble(latest_report_series, session_cache)

        raw_results_state = None
        okr_details_md = "No OKRs found in the latest report." # This is for the old, hidden component
        enhanced_okr_html_content = get_initial_okr_display() # Default to loading state or empty
        key_results_cbg_update = gr.update(choices=[], value=[], interactive=False)
        all_krs_state = []

        if reconstructed_data:
            raw_results_state = reconstructed_data
            actionable_okrs_dict = raw_results_state.get("actionable_okrs", {})
            if actionable_okrs_dict:
                # Format for the new enhanced HTML display
                enhanced_okr_html_content = format_okrs_for_enhanced_display(raw_results_state)

                # The following is for the old, hidden components. Keep for signature compatibility.
                # all_krs_state = extract_key_results_for_selection(actionable_okrs_dict) # REMOVED direct usage
                # if all_krs_state:
                #     kr_choices = [(kr['kr_description'], kr['unique_kr_id']) for kr in all_krs_state]
                #     key_results_cbg_update = gr.update(choices=kr_choices, value=[], interactive=True)
                #     okrs_list = actionable_okrs_dict.get("okrs", [])
                #     output_md_parts = [format_single_okr_for_display(okr, okr_main_index=i) for i, okr in enumerate(okrs_list)]
                #     okr_details_md = "\n\n---\n\n".join(output_md_parts) if output_md_parts else okr_details_md
                # else:
                #     logger.info(f"No actionable_okrs found in reconstructed data for report ID {latest_report_id}.")
            else:
                logger.info(f"No 'actionable_okrs' key found in reconstructed data for report ID {latest_report_id}.")
                enhanced_okr_html_content = get_initial_okr_display() # Show empty state if no OKRs
        else:
            logger.error(f"Failed to reconstruct data for latest report ID {latest_report_id}")
            okr_details_md = "Error: Could not reconstruct OKR data for this report."
            enhanced_okr_html_content = get_initial_okr_display() # Show empty state on reconstruction error

        status_update = f"Status: Loaded {len(agentic_df)} reports. Displaying latest from {latest_report_series['Created Date'].strftime('%Y-%m-%d')}."

        return (
            gr.update(value=status_update),              # 0: agentic_pipeline_status_md
            report_selector_update,                      # 1: report_selector_dd
            key_results_cbg_update,                      # 2: key_results_cbg (kept for compatibility)
            gr.update(value=okr_details_md),             # 3: okr_detail_display_md (kept for compatibility)
            gr.update(value=raw_results_state),          # 4: orchestration_raw_results_st
            gr.update(value=[]),                         # 5: selected_key_result_ids_st (kept for compatibility)
            gr.update(value=all_krs_state),              # 6: key_results_for_selection_st (kept for compatibility)
            gr.update(value=report_header_content),      # 7: report_header_html_display
            gr.update(value=report_body_content),        # 8: report_body_markdown_display
            gr.update(value=updated_cache),              # 9: reconstruction_cache_st
            gr.update(value=enhanced_okr_html_content)   # 10: NEW: The enhanced HTML display for OKRs
        )

    except Exception as e:
        logger.error(f"Failed to process and display agentic results: {e}", exc_info=True)
        # Ensure error returns match the 11-item signature
        error_header_html = """
            <div class="report-title">⚠️ Error Loading Report</div>
            <div class="report-subtitle">An error occurred during data processing.</div>
            <div class="status-badge" style="background: #e74c3c;">Error</div>
            """
        error_body_markdown = f"""
            <div class="empty-state">
                <div class="empty-state-icon">🚨</div>
                <div class="empty-state-title">Report Loading Failed</div>
                <div class="empty-state-description">
                    An error occurred while loading or processing the report data: {e}.
                    Please try again or contact support if the issue persists.
                </div>
            </div>
            """
        return (
            gr.update(value=f"Status: An error occurred: {e}"), # 0
            gr.update(choices=[], value=None, interactive=False), # 1
            gr.update(choices=[], value=[], interactive=False), # 2
            gr.update(value="Error: Could not display OKRs due to an error."), # 3
            gr.update(value=None), # 4
            gr.update(value=[]), # 5
            gr.update(value=[]), # 6
            gr.update(value=error_header_html), # 7
            gr.update(value=error_body_markdown), # 8
            gr.update(value=session_cache), # 9
            gr.update(value=get_initial_okr_display()) # 10: Placeholder for enhanced OKR display on error
        )