Update app.py
Browse files
app.py
CHANGED
@@ -14,8 +14,7 @@ from contextlib import redirect_stdout
|
|
14 |
# --- Configuration ---
|
15 |
warnings.filterwarnings('ignore')
|
16 |
|
17 |
-
# ---
|
18 |
-
# This CSS is designed to work with a dark theme, ensuring all elements are visible and stylish.
|
19 |
CSS = """
|
20 |
/* --- Phoenix UI Custom Dark CSS --- */
|
21 |
/* Stat Card Styling */
|
@@ -104,13 +103,11 @@ def load_and_process_file(file_obj, state_dict):
|
|
104 |
|
105 |
status_msg = f"β
**{state_dict['filename']}** loaded successfully."
|
106 |
|
107 |
-
# Update UI elements with new data context
|
108 |
cockpit_update = gr.update(visible=True)
|
109 |
deep_dive_update = gr.update(visible=False)
|
110 |
copilot_update = gr.update(visible=False)
|
111 |
welcome_update = gr.update(visible=False)
|
112 |
|
113 |
-
# Stat cards
|
114 |
rows, cols = metadata['shape']
|
115 |
quality = metadata['data_quality']
|
116 |
|
@@ -136,7 +133,6 @@ def extract_dataset_metadata(df: pd.DataFrame):
|
|
136 |
|
137 |
# --- Page Navigation ---
|
138 |
def switch_page(page_name):
|
139 |
-
"""Controls visibility of main content pages."""
|
140 |
if page_name == "cockpit":
|
141 |
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
|
142 |
elif page_name == "deep_dive":
|
@@ -147,7 +143,6 @@ def switch_page(page_name):
|
|
147 |
|
148 |
# --- Page 1: Data Cockpit ---
|
149 |
def get_ai_suggestions(state_dict, api_key):
|
150 |
-
"""Generates proactive analytical suggestions from the AI."""
|
151 |
if not api_key: return "Enter your Gemini API key to get suggestions.", *[gr.update(visible=False)]*5
|
152 |
if not state_dict: return "Upload data first.", *[gr.update(visible=False)]*5
|
153 |
|
@@ -176,17 +171,13 @@ def get_ai_suggestions(state_dict, api_key):
|
|
176 |
return f"Could not generate suggestions: {e}", *[gr.update(visible=False)]*5
|
177 |
|
178 |
def handle_suggestion_click(question_text):
|
179 |
-
"""When a suggestion button is clicked, switch to the co-pilot page and populate the input."""
|
180 |
return (
|
181 |
-
gr.update(visible=False),
|
182 |
-
gr.update(visible=
|
183 |
-
gr.update(visible=True), # Show co-pilot
|
184 |
-
question_text # Populate the chat input
|
185 |
)
|
186 |
|
187 |
# --- Page 2: Deep Dive Dashboard ---
|
188 |
def add_plot_to_dashboard(state_dict, x_col, y_col, plot_type):
|
189 |
-
"""Generates a plot and adds it to the state-managed dashboard."""
|
190 |
if not x_col: return state_dict, gr.update()
|
191 |
|
192 |
df = state_dict['df']
|
@@ -213,13 +204,11 @@ def add_plot_to_dashboard(state_dict, x_col, y_col, plot_type):
|
|
213 |
return state_dict, gr.update()
|
214 |
|
215 |
def clear_dashboard(state_dict):
|
216 |
-
"""Clears all plots from the dashboard."""
|
217 |
state_dict['dashboard_plots'] = []
|
218 |
return state_dict, gr.Accordion(label="Your Dashboard Plots", children=[])
|
219 |
|
220 |
# --- Page 3: AI Co-pilot ---
|
221 |
def respond_to_chat(user_message, history, state_dict, api_key):
|
222 |
-
"""Handles the advanced chat interaction with the AI Co-pilot."""
|
223 |
if not api_key:
|
224 |
history.append((user_message, "I need a Gemini API key to function. Please provide it in the sidebar."))
|
225 |
return history, *[gr.update(visible=False)] * 4
|
@@ -292,20 +281,19 @@ def respond_to_chat(user_message, history, state_dict, api_key):
|
|
292 |
|
293 |
# --- Gradio UI Definition ---
|
294 |
def create_gradio_interface():
|
295 |
-
# --- CORRECTED
|
296 |
-
|
|
|
|
|
297 |
global_state = gr.State({})
|
298 |
|
299 |
with gr.Row():
|
300 |
-
#
|
301 |
with gr.Column(scale=1, elem_classes="sidebar"):
|
302 |
gr.Markdown("## π Phoenix UI")
|
303 |
-
|
304 |
-
# Navigation buttons
|
305 |
cockpit_btn = gr.Button("π Data Cockpit", elem_classes="selected")
|
306 |
deep_dive_btn = gr.Button("π Deep Dive Builder")
|
307 |
copilot_btn = gr.Button("π€ AI Co-pilot")
|
308 |
-
|
309 |
gr.Markdown("---")
|
310 |
file_input = gr.File(label="π Upload New CSV", file_types=[".csv"])
|
311 |
status_output = gr.Markdown("Status: Awaiting data...")
|
@@ -313,16 +301,13 @@ def create_gradio_interface():
|
|
313 |
api_key_input = gr.Textbox(label="π Gemini API Key", type="password", placeholder="Enter key here...")
|
314 |
suggestion_btn = gr.Button("Get Smart Suggestions", variant="secondary")
|
315 |
|
316 |
-
#
|
317 |
with gr.Column(scale=4):
|
318 |
-
|
319 |
-
# Welcome Page (Visible initially)
|
320 |
with gr.Column(visible=True) as welcome_page:
|
321 |
-
gr.Markdown("# Welcome to the AI Data Explorer (Phoenix UI)"
|
322 |
gr.Markdown("Please **upload a CSV file** and **enter your Gemini API key** in the sidebar to begin.")
|
323 |
gr.Image(value="workflow.png", label="Workflow", show_label=False, show_download_button=False, container=False)
|
324 |
|
325 |
-
# Page 1: Data Cockpit (Hidden initially)
|
326 |
with gr.Column(visible=False) as cockpit_page:
|
327 |
gr.Markdown("## π Data Cockpit")
|
328 |
with gr.Row():
|
@@ -338,15 +323,12 @@ def create_gradio_interface():
|
|
338 |
with gr.Column(elem_classes="stat-card"):
|
339 |
gr.Markdown("<div class='stat-card-title'>Date/Time Cols</div>")
|
340 |
time_cols_stat = gr.Textbox("0", show_label=False, elem_classes="stat-card-value")
|
341 |
-
|
342 |
suggestion_status = gr.Markdown(visible=True)
|
343 |
with gr.Accordion(label="β¨ AI Smart Suggestions", open=True):
|
344 |
suggestion_buttons = [gr.Button(visible=False) for _ in range(5)]
|
345 |
|
346 |
-
# Page 2: Deep Dive Dashboard Builder (Hidden initially)
|
347 |
with gr.Column(visible=False) as deep_dive_page:
|
348 |
gr.Markdown("## π Deep Dive Dashboard Builder")
|
349 |
-
gr.Markdown("Create a custom dashboard by adding multiple plots to investigate your data.")
|
350 |
with gr.Row():
|
351 |
plot_type_dd = gr.Dropdown(['histogram', 'bar', 'scatter', 'box'], label="Plot Type", value='histogram')
|
352 |
x_col_dd = gr.Dropdown([], label="X-Axis / Column")
|
@@ -356,23 +338,19 @@ def create_gradio_interface():
|
|
356 |
clear_plots_btn = gr.Button("Clear Dashboard")
|
357 |
dashboard_accordion = gr.Accordion(label="Your Dashboard Plots", open=True)
|
358 |
|
359 |
-
# Page 3: AI Co-pilot (Hidden initially)
|
360 |
with gr.Column(visible=False) as copilot_page:
|
361 |
gr.Markdown("## π€ AI Co-pilot")
|
362 |
-
gr.Markdown("Ask complex questions in natural language. The Co-pilot will write and execute code to find the answer.")
|
363 |
chatbot = gr.Chatbot(height=400, label="Conversation with Co-pilot", show_copy_button=True)
|
364 |
-
|
365 |
with gr.Accordion("Co-pilot's Response Details", open=True):
|
366 |
copilot_explanation = gr.Markdown(visible=False, elem_classes="explanation-block")
|
367 |
-
copilot_code = gr.Code(language="python", visible=False, label="Executed Python Code"
|
368 |
copilot_plot = gr.Plot(visible=False, label="Generated Visualization")
|
369 |
copilot_table = gr.Dataframe(visible=False, label="Generated Table", wrap=True)
|
370 |
-
|
371 |
with gr.Row():
|
372 |
chat_input = gr.Textbox(label="Your Question", placeholder="e.g., 'What is the correlation between age and salary?'", scale=4)
|
373 |
chat_submit_btn = gr.Button("Submit", variant="primary")
|
374 |
|
375 |
-
#
|
376 |
pages = [cockpit_page, deep_dive_page, copilot_page]
|
377 |
nav_buttons = [cockpit_btn, deep_dive_btn, copilot_btn]
|
378 |
|
|
|
14 |
# --- Configuration ---
|
15 |
warnings.filterwarnings('ignore')
|
16 |
|
17 |
+
# --- Expert-Crafted Dark Theme CSS ---
|
|
|
18 |
CSS = """
|
19 |
/* --- Phoenix UI Custom Dark CSS --- */
|
20 |
/* Stat Card Styling */
|
|
|
103 |
|
104 |
status_msg = f"β
**{state_dict['filename']}** loaded successfully."
|
105 |
|
|
|
106 |
cockpit_update = gr.update(visible=True)
|
107 |
deep_dive_update = gr.update(visible=False)
|
108 |
copilot_update = gr.update(visible=False)
|
109 |
welcome_update = gr.update(visible=False)
|
110 |
|
|
|
111 |
rows, cols = metadata['shape']
|
112 |
quality = metadata['data_quality']
|
113 |
|
|
|
133 |
|
134 |
# --- Page Navigation ---
|
135 |
def switch_page(page_name):
|
|
|
136 |
if page_name == "cockpit":
|
137 |
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
|
138 |
elif page_name == "deep_dive":
|
|
|
143 |
|
144 |
# --- Page 1: Data Cockpit ---
|
145 |
def get_ai_suggestions(state_dict, api_key):
|
|
|
146 |
if not api_key: return "Enter your Gemini API key to get suggestions.", *[gr.update(visible=False)]*5
|
147 |
if not state_dict: return "Upload data first.", *[gr.update(visible=False)]*5
|
148 |
|
|
|
171 |
return f"Could not generate suggestions: {e}", *[gr.update(visible=False)]*5
|
172 |
|
173 |
def handle_suggestion_click(question_text):
|
|
|
174 |
return (
|
175 |
+
gr.update(visible=False), gr.update(visible=False),
|
176 |
+
gr.update(visible=True), question_text
|
|
|
|
|
177 |
)
|
178 |
|
179 |
# --- Page 2: Deep Dive Dashboard ---
|
180 |
def add_plot_to_dashboard(state_dict, x_col, y_col, plot_type):
|
|
|
181 |
if not x_col: return state_dict, gr.update()
|
182 |
|
183 |
df = state_dict['df']
|
|
|
204 |
return state_dict, gr.update()
|
205 |
|
206 |
def clear_dashboard(state_dict):
|
|
|
207 |
state_dict['dashboard_plots'] = []
|
208 |
return state_dict, gr.Accordion(label="Your Dashboard Plots", children=[])
|
209 |
|
210 |
# --- Page 3: AI Co-pilot ---
|
211 |
def respond_to_chat(user_message, history, state_dict, api_key):
|
|
|
212 |
if not api_key:
|
213 |
history.append((user_message, "I need a Gemini API key to function. Please provide it in the sidebar."))
|
214 |
return history, *[gr.update(visible=False)] * 4
|
|
|
281 |
|
282 |
# --- Gradio UI Definition ---
|
283 |
def create_gradio_interface():
|
284 |
+
# --- CORRECTED THEME DEFINITION ---
|
285 |
+
# We use gr.themes.Glass which is dark by default and allows hue customization.
|
286 |
+
# This is the syntactically correct and visually appropriate way to create the theme.
|
287 |
+
with gr.Blocks(theme=gr.themes.Glass(primary_hue="indigo", secondary_hue="blue"), css=CSS, title="Phoenix AI Data Explorer") as demo:
|
288 |
global_state = gr.State({})
|
289 |
|
290 |
with gr.Row():
|
291 |
+
# Sidebar
|
292 |
with gr.Column(scale=1, elem_classes="sidebar"):
|
293 |
gr.Markdown("## π Phoenix UI")
|
|
|
|
|
294 |
cockpit_btn = gr.Button("π Data Cockpit", elem_classes="selected")
|
295 |
deep_dive_btn = gr.Button("π Deep Dive Builder")
|
296 |
copilot_btn = gr.Button("π€ AI Co-pilot")
|
|
|
297 |
gr.Markdown("---")
|
298 |
file_input = gr.File(label="π Upload New CSV", file_types=[".csv"])
|
299 |
status_output = gr.Markdown("Status: Awaiting data...")
|
|
|
301 |
api_key_input = gr.Textbox(label="π Gemini API Key", type="password", placeholder="Enter key here...")
|
302 |
suggestion_btn = gr.Button("Get Smart Suggestions", variant="secondary")
|
303 |
|
304 |
+
# Main Content Area
|
305 |
with gr.Column(scale=4):
|
|
|
|
|
306 |
with gr.Column(visible=True) as welcome_page:
|
307 |
+
gr.Markdown("# Welcome to the AI Data Explorer (Phoenix UI)")
|
308 |
gr.Markdown("Please **upload a CSV file** and **enter your Gemini API key** in the sidebar to begin.")
|
309 |
gr.Image(value="workflow.png", label="Workflow", show_label=False, show_download_button=False, container=False)
|
310 |
|
|
|
311 |
with gr.Column(visible=False) as cockpit_page:
|
312 |
gr.Markdown("## π Data Cockpit")
|
313 |
with gr.Row():
|
|
|
323 |
with gr.Column(elem_classes="stat-card"):
|
324 |
gr.Markdown("<div class='stat-card-title'>Date/Time Cols</div>")
|
325 |
time_cols_stat = gr.Textbox("0", show_label=False, elem_classes="stat-card-value")
|
|
|
326 |
suggestion_status = gr.Markdown(visible=True)
|
327 |
with gr.Accordion(label="β¨ AI Smart Suggestions", open=True):
|
328 |
suggestion_buttons = [gr.Button(visible=False) for _ in range(5)]
|
329 |
|
|
|
330 |
with gr.Column(visible=False) as deep_dive_page:
|
331 |
gr.Markdown("## π Deep Dive Dashboard Builder")
|
|
|
332 |
with gr.Row():
|
333 |
plot_type_dd = gr.Dropdown(['histogram', 'bar', 'scatter', 'box'], label="Plot Type", value='histogram')
|
334 |
x_col_dd = gr.Dropdown([], label="X-Axis / Column")
|
|
|
338 |
clear_plots_btn = gr.Button("Clear Dashboard")
|
339 |
dashboard_accordion = gr.Accordion(label="Your Dashboard Plots", open=True)
|
340 |
|
|
|
341 |
with gr.Column(visible=False) as copilot_page:
|
342 |
gr.Markdown("## π€ AI Co-pilot")
|
|
|
343 |
chatbot = gr.Chatbot(height=400, label="Conversation with Co-pilot", show_copy_button=True)
|
|
|
344 |
with gr.Accordion("Co-pilot's Response Details", open=True):
|
345 |
copilot_explanation = gr.Markdown(visible=False, elem_classes="explanation-block")
|
346 |
+
copilot_code = gr.Code(language="python", visible=False, label="Executed Python Code")
|
347 |
copilot_plot = gr.Plot(visible=False, label="Generated Visualization")
|
348 |
copilot_table = gr.Dataframe(visible=False, label="Generated Table", wrap=True)
|
|
|
349 |
with gr.Row():
|
350 |
chat_input = gr.Textbox(label="Your Question", placeholder="e.g., 'What is the correlation between age and salary?'", scale=4)
|
351 |
chat_submit_btn = gr.Button("Submit", variant="primary")
|
352 |
|
353 |
+
# Event Handlers
|
354 |
pages = [cockpit_page, deep_dive_page, copilot_page]
|
355 |
nav_buttons = [cockpit_btn, deep_dive_btn, copilot_btn]
|
356 |
|