File size: 4,455 Bytes
0a8cbc3
d9ea3f9
60da408
c9ba3ae
0a8cbc3
c9ba3ae
0a8cbc3
 
 
 
 
 
 
 
60da408
0a8cbc3
 
51dfd28
0a8cbc3
 
 
 
51dfd28
0d6622c
0a8cbc3
 
 
 
 
 
 
60da408
0d6622c
0a8cbc3
 
 
d9ea3f9
0a8cbc3
 
 
 
 
 
 
 
 
51dfd28
0a8cbc3
 
51dfd28
0a8cbc3
 
 
 
 
 
 
51dfd28
0a8cbc3
 
 
 
 
 
 
0d6622c
0a8cbc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c9ba3ae
60da408
0a8cbc3
 
 
 
 
 
 
 
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
# app.py

# -*- coding: utf-8 -*-
#
# PROJECT:      CognitiveEDA v5.3 - The QuantumLeap Intelligence Platform
#
# DESCRIPTION:  Main application entry point. This definitive version correctly
#               orchestrates UI layout, callback registration, and server launch.
#
# SETUP:        $ pip install -r requirements.txt
#
# AUTHOR:       An MCP & PhD Expert in Data & AI Solutions
# VERSION:      5.3 (Definitive Launch Edition)
# LAST-UPDATE:  2023-10-30 (Ensured main execution block and all callbacks are wired)

import warnings
import logging
import gradio as gr

# Import the UI layout and the callback LOGIC functions
from ui.layout import create_main_layout
from ui import callbacks
from core.config import settings

# --- Configuration & Setup ---
# This setup MUST be in the global scope to be configured before any functions run.
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - [%(levelname)s] - (%(filename)s:%(lineno)d) - %(message)s'
)
warnings.filterwarnings('ignore', category=FutureWarning)


def main():
    """
    Primary function to build, wire up, and launch the Gradio application.
    """
    logging.info(f"Starting {settings.APP_TITLE}")
    
    # The 'with' block creates the Gradio context. All UI and event listeners
    # MUST be defined within this block.
    with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="indigo"), title=settings.APP_TITLE) as demo:
        
        # 1. Build the UI from the layout module.
        # This returns a dictionary of all named components.
        components = create_main_layout()

        # 2. Register all event handlers (callbacks) within the same context.
        # This is the correct, robust pattern for a modular Gradio app.

        # --- Primary Analysis Chain ---
        # Event 1: User clicks "Generate". This triggers the fast, initial analysis.
        analysis_complete_event = components["analyze_button"].click(
            fn=callbacks.run_initial_analysis,
            inputs=[components["upload_button"]],
            outputs=[components["state_analyzer"]]
        )

        # Event 2: Chained to the success of Event 1. This triggers the slower,
        #          asynchronous report and visual generation.
        analysis_complete_event.then(
            fn=callbacks.generate_reports_and_visuals,
            inputs=[components["state_analyzer"]],
            outputs=components  # Maps the returned dict to the components dict
        )

        # --- Interactive Explorer Callbacks ---
        components["dd_hist_col"].change(
            fn=callbacks.create_histogram,
            inputs=[components["state_analyzer"], components["dd_hist_col"]],
            outputs=[components["plot_histogram"]]
        )

        # For the scatter plot, we need to listen to changes on all three dropdowns.
        scatter_inputs = [
            components["state_analyzer"],
            components["dd_scatter_x"],
            components["dd_scatter_y"],
            components["dd_scatter_color"]
        ]
        for dropdown in [components["dd_scatter_x"], components["dd_scatter_y"], components["dd_scatter_color"]]:
            dropdown.change(
                fn=callbacks.create_scatterplot,
                inputs=scatter_inputs,
                outputs=[components["plot_scatter"]]
            )

        # --- Specialized Module Callbacks ---
        components["num_clusters"].change(
            fn=callbacks.update_clustering,
            inputs=[components["state_analyzer"], components["num_clusters"]],
            outputs=[
                components["plot_cluster"],
                components["plot_elbow"],
                components["md_cluster_summary"]
            ]
        )
    
    # 3. Launch the application server. This line is outside the 'with' block
    #    but is called on the 'demo' object that was defined by it. The server
    #    will now run indefinitely, listening for requests.
    demo.launch(debug=False, server_name="0.0.0.0")


# --- Application Entry Point ---
# This is the most critical part for a runnable script. The `if __name__ == "__main__":`
# check ensures that the `main()` function is called only when the script is
# executed directly (not when it's imported by another script). Without this
# block, the application will define the 'main' function but never run it,
# leading to the "application not initialized" error.
if __name__ == "__main__":
    main()