LinkedinMonitor / app.py
GuglielmoTor's picture
Update app.py
bb1bc48 verified
raw
history blame
10.6 kB
import gradio as gr
import pandas as pd
import os
import logging
from collections import defaultdict
import matplotlib
matplotlib.use('Agg') # Set backend for Matplotlib
# --- Module Imports ---
from utils.gradio_utils import get_url_user_token
# Functions from newly created/refactored modules
from config import (
PLOT_ID_TO_FORMULA_KEY_MAP,
LINKEDIN_CLIENT_ID_ENV_VAR,
BUBBLE_APP_NAME_ENV_VAR,
BUBBLE_API_KEY_PRIVATE_ENV_VAR,
BUBBLE_API_ENDPOINT_ENV_VAR
)
# analytics_tab_module is now imported locally inside ui/ui_enhancements.py's build_main_app_ui
# from services.analytics_tab_module import AnalyticsTab # REMOVED global import here
# UPDATED: Using the new data loading function from the refactored state manager
from services.state_manager import load_data_from_bubble
# Import UI generator functions (these are now passed to build_main_app_ui)
from ui.ui_generators import (
build_analytics_tab_plot_area,
build_home_tab_ui,
create_enhanced_report_tab,
BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON
)
# NEW: Import the new OKR UI functions
from ui.okr_ui_generator import create_enhanced_okr_tab, format_okrs_for_enhanced_display, get_initial_okr_display
from ui.analytics_plot_generator import update_analytics_plots_figures, create_placeholder_plot
from formulas import PLOT_FORMULAS
# NEW: Import UI enhancements from the new module
from ui.ui_main_page_enhancements import build_main_app_ui, update_report_display_enhanced
# --- CHATBOT MODULE IMPORTS ---
from features.chatbot.chatbot_prompts import get_initial_insight_prompt_and_suggestions
from features.chatbot.chatbot_handler import generate_llm_response
# --- AGENTIC PIPELINE (DISPLAY ONLY) IMPORTS ---
try:
# This is the main function called on initial load to populate the agentic tabs
from run_agentic_pipeline import load_and_display_agentic_results
# This function is now called when a new report is selected from the dropdown
from services.report_data_handler import fetch_and_reconstruct_data_from_bubble
# UI formatting functions
from ui.insights_ui_generator import (
format_report_for_display, # This will now return header HTML and body Markdown
)
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 to prevent app from crashing if imports fail
def load_and_display_agentic_results(*args, **kwargs):
# NOTE: This return signature MUST match agentic_display_outputs
# Adjusted return values for the new split report display components and the new OKR HTML
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 = """
<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>
"""
# The load_and_display_agentic_results function returns many values.
# Ensure the placeholder returns the correct number of gr.update components
# matching the `outputs` in the .then() call later.
return (
gr.update(value="Modules not loaded."), # agentic_pipeline_status_md (0)
gr.update(choices=[], value=None), # report_selector_dd (1)
gr.update(choices=[], value=[]), # key_results_cbg (2) - KEPT HIDDEN for compatibility
gr.update(value="Modules not loaded."), # okr_detail_display_md (3) - KEPT HIDDEN for compatibility
None, # orchestration_raw_results_st (4)
[], # selected_key_result_ids_st (5) - KEPT HIDDEN for compatibility
[], # key_results_for_selection_st (6) - KEPT HIDDEN for compatibility
gr.update(value=empty_header_html), # report_header_html_display (7)
gr.update(value=empty_body_markdown), # report_body_markdown_display (8)
{}, # reconstruction_cache_st (9)
gr.update(value=get_initial_okr_display()), # NEW: enhanced_okr_display_html (10)
gr.update(value={}) # NEW: actionable_okrs_data_st (11)
)
def fetch_and_reconstruct_data_from_bubble(*args, **kwargs):
return None, {}
def format_report_for_display(report_data):
# Placeholder for when modules are not loaded, returns structure matching the new design
return {'header_html': '<h1>Agentic modules not loaded.</h1>', 'body_markdown': 'Report display unavailable.'}
# --- Initial data load sequence function (remains in app.py as it uses service functions) ---
def initial_data_load_sequence(url_token, org_urn_val, current_state):
"""
Handles the initial data loading from Bubble.
No longer generates dashboard HTML as the Home tab is now static.
"""
status_msg, new_state = load_data_from_bubble(url_token, org_urn_val, current_state)
# Add status icons based on success/failure
if "successfully" in status_msg.lower() or "loaded" in status_msg.lower():
status_msg = f"βœ… {status_msg}"
elif "error" in status_msg.lower() or "failed" in status_msg.lower():
status_msg = f"❌ {status_msg}"
else:
status_msg = f"πŸ”„ {status_msg}"
return status_msg, new_state
# Build the main UI using the function from ui_enhancements
(app, url_user_token_display, org_urn_display, status_box,
token_state, reconstruction_cache_st, enhanced_okr_display_html,
tabs, report_selector_dd, agentic_display_outputs,
analytics_tab_instance, chat_histories_st_returned,
current_chat_plot_id_st_returned, plot_data_for_chatbot_st_returned, # Receive these returned states
format_report_for_display_func_passed) = \
build_main_app_ui(
PLOT_ID_TO_FORMULA_KEY_MAP=PLOT_ID_TO_FORMULA_KEY_MAP,
PLOT_FORMULAS=PLOT_FORMULAS,
BOMB_ICON=BOMB_ICON, EXPLORE_ICON=EXPLORE_ICON, FORMULA_ICON=FORMULA_ICON, ACTIVE_ICON=ACTIVE_ICON,
build_analytics_tab_plot_area_func=build_analytics_tab_plot_area,
update_analytics_plots_figures_func=update_analytics_plots_figures,
create_placeholder_plot_func=create_placeholder_plot,
get_initial_insight_prompt_and_suggestions_func=get_initial_insight_prompt_and_suggestions,
generate_llm_response_func=generate_llm_response,
build_home_tab_ui_func=build_home_tab_ui,
create_enhanced_report_tab_func=create_enhanced_report_tab,
create_enhanced_okr_tab_func=create_enhanced_okr_tab,
format_report_for_display_func=format_report_for_display # Pass the imported function
)
# Event handlers (re-establishing them now that components are defined)
app.load(fn=get_url_user_token, inputs=None, outputs=[url_user_token_display, org_urn_display], api_name="get_url_params", show_progress=False)
if AGENTIC_MODULES_LOADED:
report_selector_dd.change(
fn=lambda sr_id, c_state: update_report_display_enhanced(sr_id, c_state, format_report_for_display),
inputs=[report_selector_dd, token_state],
outputs=[agentic_display_outputs[7], agentic_display_outputs[8]], # report_header_html_display, report_body_markdown_display
show_progress="minimal"
)
# Initial load sequence with enhanced status updates
initial_load_event = org_urn_display.change(
fn=initial_data_load_sequence,
inputs=[url_user_token_display, org_urn_display, token_state],
outputs=[status_box, token_state],
show_progress="full"
)
# Chain the loading events
initial_load_event.then(
fn=analytics_tab_instance.refresh_analytics_graphs_ui,
inputs=[token_state, analytics_tab_instance.date_filter_selector, analytics_tab_instance.custom_start_date_picker,
analytics_tab_instance.custom_end_date_picker, chat_histories_st_returned],
outputs=analytics_tab_instance.graph_refresh_outputs_list,
show_progress="full"
).then(
fn=load_and_display_agentic_results,
inputs=[token_state, reconstruction_cache_st],
outputs=agentic_display_outputs,
show_progress="minimal"
).then(
fn=format_okrs_for_enhanced_display,
inputs=[reconstruction_cache_st],
outputs=[enhanced_okr_display_html],
show_progress="minimal"
)
if __name__ == "__main__":
# Enhanced startup logging
print("πŸš€ Starting LinkedIn Organization Dashboard...")
# Environment variable checks with better logging
missing_vars = []
if not os.environ.get(LINKEDIN_CLIENT_ID_ENV_VAR):
missing_vars.append(LINKEDIN_CLIENT_ID_ENV_VAR)
logging.warning(f"⚠️ WARNING: '{LINKEDIN_CLIENT_ID_ENV_VAR}' is not set.")
bubble_vars = [BUBBLE_APP_NAME_ENV_VAR, BUBBLE_API_KEY_PRIVATE_ENV_VAR, BUBBLE_API_ENDPOINT_ENV_VAR]
if not all(os.environ.get(var) for var in bubble_vars):
missing_vars.extend([var for var in bubble_vars if not os.environ.get(var)])
logging.warning("⚠️ WARNING: One or more Bubble environment variables are not set.")
if not os.environ.get("GEMINI_API_KEY"):
missing_vars.append("GEMINI_API_KEY")
logging.warning("⚠️ WARNING: 'GEMINI_API_KEY' is not set.")
if not AGENTIC_MODULES_LOADED:
logging.warning("πŸ”΄ CRITICAL: Agentic modules failed to load.")
if missing_vars:
print(f"⚠️ Missing environment variables: {', '.join(missing_vars)}")
print("πŸ”§ Please set these variables for full functionality.")
else:
print("βœ… All environment variables are properly configured.")
print("🌐 Launching dashboard on http://0.0.0.0:7860")
print("🎯 Dashboard features:")
print(" β€’ πŸ“Š Advanced LinkedIn Analytics")
print(" β€’ πŸ€– AI-Powered Insights")
print(" β€’ 🎯 OKR Generation & Tracking")
print(" β€’ ☁️ Bubble.io Integration")
app.launch(
server_name="0.0.0.0",
server_port=int(os.environ.get("PORT", 7860)),
debug=True,
show_error=True,
show_tips=True,
enable_queue=True
)