Spaces:
Running
Running
File size: 8,555 Bytes
d3914e5 |
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 |
# handlers/dashboard_sync_handlers.py
import gradio as gr
import logging
# Assuming these functions are in the specified paths and are importable
from services.state_manager import process_and_store_bubble_token
from services.sync_logic import sync_all_linkedin_data_orchestrator
from ui.ui_generators import display_main_dashboard
class DashboardSyncHandlers:
def __init__(self, dashboard_components, token_state_ref, url_user_token_display_ref, org_urn_display_ref, status_box_ref):
self.components = dashboard_components
self.token_state = token_state_ref # gr.State object
self.url_user_token_display = url_user_token_display_ref # gr.Textbox object
self.org_urn_display = org_urn_display_ref # gr.Textbox object
self.status_box = status_box_ref # gr.Textbox object
logging.info("DashboardSyncHandlers initialized.")
def initial_load_sequence(self, url_token, org_urn_val, current_token_state_value):
"""
Handles the initial loading sequence after URL parameters are fetched.
This is called by app.load().then() or org_urn_display.change().
"""
logging.info(f"Initial load sequence triggered. URL Token: {'Set' if url_token else 'Not Set'}, Org URN: {org_urn_val}")
# process_and_store_bubble_token is expected to return:
# status_msg, new_state_dict, btn_update_dict (for sync_data_btn)
status_msg, new_state_dict, btn_update_dict = process_and_store_bubble_token(
url_token,
org_urn_val,
current_token_state_value # Pass the current value of the state
)
# display_main_dashboard expects the new state dictionary
dashboard_content_html = display_main_dashboard(new_state_dict)
# Returns:
# 1. Update for status_box (value)
# 2. New value for token_state (this will update the gr.State object)
# 3. Update for sync_data_btn (e.g., gr.update(visible=True, interactive=True))
# 4. Update for dashboard_display_html (value)
return status_msg, new_state_dict, btn_update_dict, dashboard_content_html
async def trigger_sync_and_refresh(self, current_token_state_value, url_token, org_urn_val):
"""
Orchestrates the full sync process when the sync button is clicked.
This combines sync_all_linkedin_data_orchestrator and subsequent updates.
Yields updates for a chained sequence.
"""
logging.info("Sync data button clicked. Starting sync process.")
# Part 1: sync_all_linkedin_data_orchestrator
# Expected to return: html_status_update_str, updated_token_state_dict
sync_status_html, updated_token_state_after_sync = await sync_all_linkedin_data_orchestrator(current_token_state_value)
yield sync_status_html, updated_token_state_after_sync # Updates sync_status_html_output, token_state
# Part 2: process_and_store_bubble_token again with potentially updated token_state
# This ensures the state is consistent after sync and reflects any new data fetched by sync_all_linkedin_data_orchestrator
# It might also re-evaluate if sync button should be visible/interactive
status_msg_after_sync, final_token_state_dict, sync_btn_update_after_sync = process_and_store_bubble_token(
url_token, # url_token and org_urn_val might be stale if not re-fetched, but usually static for a session
org_urn_val,
updated_token_state_after_sync # Use the state updated by sync_all_linkedin_data_orchestrator
)
yield status_msg_after_sync, final_token_state_dict, sync_btn_update_after_sync # Updates status_box, token_state, sync_data_btn
# Part 3: Refresh dashboard display
dashboard_html_after_sync = display_main_dashboard(final_token_state_dict)
yield dashboard_html_after_sync # Updates dashboard_display_html
# The subsequent calls to refresh_analytics_graphs_ui and run_agentic_pipeline_autonomously
# will be chained in app.py using .then() on this sync event, using the updated token_state.
def setup_event_handlers(self, initial_load_trigger_component, agentic_handlers_ref, analytics_handlers_ref):
"""
Sets up event handlers for the dashboard and sync tab.
initial_load_trigger_component is typically org_urn_display.
"""
logging.info("Setting up dashboard/sync event handlers.")
# Initial load sequence
# This is more complex due to the chained .then() calls for analytics and agentic pipeline
# The main app.py will handle the .then() chaining. This handler provides the core functions.
# The initial_load_sequence method itself will be the 'fn' for the first .change() or .load().
# Sync button click
# The sync_data_btn.click event will also have .then() chains in app.py
# We define the primary function here.
self.components['sync_data_btn'].click(
fn=self.trigger_sync_and_refresh,
inputs=[
self.token_state,
self.url_user_token_display, # Pass the component to get its current value
self.org_urn_display # Pass the component to get its current value
],
outputs=[
self.components['sync_status_html_output'], # Output 1 from sync_all_linkedin_data
self.token_state, # Output 2 from sync_all_linkedin_data
self.status_box, # Output 1 from process_and_store (after sync)
self.token_state, # Output 2 from process_and_store (after sync)
self.components['sync_data_btn'], # Output 3 from process_and_store (after sync)
self.components['dashboard_display_html'] # Output from display_main_dashboard (after sync)
],
show_progress="full",
api_name="sync_linkedin_data_full_flow"
# Note: The number of outputs here must match the total number of yields in trigger_sync_and_refresh
# trigger_sync_and_refresh yields:
# 1. sync_status_html (for sync_status_html_output)
# 2. updated_token_state_after_sync (for token_state)
# --- then ---
# 3. status_msg_after_sync (for status_box)
# 4. final_token_state_dict (for token_state)
# 5. sync_btn_update_after_sync (for sync_data_btn)
# --- then ---
# 6. dashboard_html_after_sync (for dashboard_display_html)
# This means the Gradio event needs to be structured to handle these yields if they are separate updates.
# However, Gradio's .click typically expects a single function that returns all outputs or a generator
# that yields tuples of updates for all outputs at each step.
# For simplicity, trigger_sync_and_refresh should be an async generator yielding tuples for all outputs.
# Let's refine trigger_sync_and_refresh to yield tuples.
)
logging.info("Dashboard/sync event handlers setup complete.")
async def refined_trigger_sync_and_refresh(self, current_token_state_value, url_token, org_urn_val):
"""
Refined orchestrator for sync process, yielding tuples for all outputs at each step.
Outputs:
1. self.components['sync_status_html_output']
2. self.token_state
3. self.status_box
4. self.components['sync_data_btn'] (this is tricky, might need to be separate or handled by token_state change)
5. self.components['dashboard_display_html']
Let's simplify the outputs for the direct click and handle subsequent updates via .then() in app.py
The click will call sync_all_linkedin_data_orchestrator.
Then, .then() will call process_and_store_bubble_token.
Then, .then() will call display_main_dashboard.
And further .then() for agentic and analytics.
So, this handler will provide the individual functions.
"""
pass # The original structure in app.py with chained .then() is better.
# This class will hold the functions called by those .then() chains.
# sync_all_linkedin_data_orchestrator
# process_and_store_bubble_token (already imported)
# display_main_dashboard (already imported)
|