Spaces:
Build error
Build error
| import gradio as gr | |
| import pandas as pd | |
| import os | |
| import base64 | |
| import json | |
| from data_engine import ( | |
| clean_numeric, run_analysis, create_visualization, handle_missing_data, | |
| undo_last_change, undo_all_changes, download_dataset, | |
| display_data_format, display_text_format | |
| ) | |
| try: | |
| from ai_agent import initialize_llm, analyze_question | |
| except (ImportError, RuntimeError) as e: | |
| print(f"Warning: Full AI agent not available: {e}") | |
| def initialize_llm(): | |
| return None | |
| def analyze_question(question, columns, df, llm): | |
| return "AI agent not available. Please check dependencies.", None, None | |
| from prompts import SAMPLE_QUESTIONS | |
| llm = None | |
| uploaded_df = None | |
| original_df = None | |
| dataset_name = None | |
| change_history = [] | |
| logo_path = os.path.join(os.getcwd(), "public/main-logo.png") | |
| def embed_image_base64(path): | |
| with open(path, "rb") as f: | |
| return "data:image/png;base64," + base64.b64encode(f.read()).decode() | |
| logo_b64 = embed_image_base64(logo_path) | |
| with open("public/style.css") as f: | |
| css = f.read() | |
| # Enhanced custom CSS for dropdown | |
| custom_css = css + """ | |
| .dropdown-wrapper { | |
| width: 100%; | |
| margin: 10px 0; | |
| } | |
| .dropdown-button { | |
| width: 100%; | |
| padding: 12px 16px; | |
| background: rgba(138, 43, 226, 0.15); | |
| border: 1px solid rgba(138, 43, 226, 0.3); | |
| border-radius: 8px; | |
| cursor: pointer; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| font-size: 14px; | |
| color: #e0e0e0; | |
| transition: all 0.3s; | |
| } | |
| .dropdown-button:hover { | |
| background: rgba(138, 43, 226, 0.25); | |
| border-color: rgba(138, 43, 226, 0.5); | |
| } | |
| .dropdown-menu { | |
| display: none; | |
| position: absolute; | |
| width: calc(100% - 32px); | |
| max-height: 300px; | |
| overflow-y: auto; | |
| background: #2a2a3e; | |
| border: 1px solid rgba(138, 43, 226, 0.3); | |
| border-radius: 8px; | |
| margin-top: 5px; | |
| z-index: 1000; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); | |
| } | |
| .dropdown-menu.show { | |
| display: block; | |
| } | |
| .dropdown-item { | |
| padding: 12px 16px; | |
| cursor: pointer; | |
| color: #e0e0e0; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .dropdown-item:hover { | |
| background: rgba(138, 43, 226, 0.2); | |
| } | |
| .dropdown-item.selected { | |
| background: rgba(138, 43, 226, 0.3); | |
| color: #fff; | |
| font-weight: 500; | |
| } | |
| .dropdown-item::before { | |
| content: '☐'; | |
| font-size: 18px; | |
| } | |
| .dropdown-item.selected::before { | |
| content: '☑'; | |
| color: #8a2be2; | |
| } | |
| .selected-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| margin-top: 10px; | |
| min-height: 20px; | |
| } | |
| .tag { | |
| background: rgba(138, 43, 226, 0.3); | |
| color: #fff; | |
| padding: 6px 12px; | |
| border-radius: 20px; | |
| font-size: 13px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .tag .remove { | |
| cursor: pointer; | |
| font-weight: bold; | |
| color: #ff6b6b; | |
| font-size: 16px; | |
| line-height: 1; | |
| } | |
| .tag .remove:hover { | |
| color: #ff4444; | |
| } | |
| .dropdown-arrow { | |
| transition: transform 0.3s; | |
| } | |
| .dropdown-arrow.open { | |
| transform: rotate(180deg); | |
| } | |
| """ | |
| def upload_dataset(file): | |
| global uploaded_df, original_df, dataset_name, change_history | |
| if file is None: | |
| return "No file uploaded", None, [], "" | |
| try: | |
| if file.name.endswith('.csv'): | |
| uploaded_df = pd.read_csv(file.name) | |
| elif file.name.endswith(('.xlsx', '.xls')): | |
| uploaded_df = pd.read_excel(file.name) | |
| else: | |
| return "Unsupported file format", None, [], "" | |
| original_df = uploaded_df.copy() | |
| dataset_name = os.path.basename(file.name) | |
| change_history = [] | |
| info = f"**Dataset:** {dataset_name}\n**Shape:** {uploaded_df.shape}\n**Columns:** {', '.join(uploaded_df.columns)}" | |
| columns = list(uploaded_df.columns) | |
| # Create the dropdown HTML with updated columns | |
| dropdown_html = create_dropdown_html(columns, []) | |
| return info, uploaded_df.head(), columns, dropdown_html | |
| except Exception as e: | |
| return f"Error uploading file: {str(e)}", None, [], "" | |
| def create_dropdown_html(available_columns, selected_columns): | |
| """Create the dropdown HTML structure""" | |
| if not available_columns: | |
| return """ | |
| <div class="dropdown-wrapper"> | |
| <div class="dropdown-button" style="opacity: 0.5; cursor: not-allowed;"> | |
| <span>No columns available</span> | |
| <span class="dropdown-arrow">▼</span> | |
| </div> | |
| </div> | |
| """ | |
| columns_json = json.dumps(available_columns) | |
| selected_json = json.dumps(selected_columns) | |
| dropdown_items = ''.join([ | |
| f'<div class="dropdown-item{" selected" if col in selected_columns else ""}" data-column="{col}">{col}</div>' | |
| for col in available_columns | |
| ]) | |
| selected_tags = ''.join([ | |
| f'<span class="tag" data-column="{col}">{col}<span class="remove">×</span></span>' | |
| for col in selected_columns | |
| ]) | |
| return f""" | |
| <div class="dropdown-wrapper"> | |
| <div class="dropdown-button" onclick="toggleDropdown()"> | |
| <span id="dropdown-text">{len(selected_columns)} column(s) selected" if selected_columns else "Choose columns to work with</span> | |
| <span class="dropdown-arrow" id="dropdown-arrow">▼</span> | |
| </div> | |
| <div class="dropdown-menu" id="dropdown-menu"> | |
| {dropdown_items} | |
| </div> | |
| <div class="selected-tags" id="selected-tags"> | |
| {selected_tags} | |
| </div> | |
| </div> | |
| <input type="hidden" id="available-columns" value='{columns_json}'> | |
| <input type="hidden" id="selected-columns-data" value='{selected_json}'> | |
| <script> | |
| (function() {{ | |
| let selectedColumns = {selected_json}; | |
| let availableColumns = {columns_json}; | |
| function updateHiddenInput() {{ | |
| const hiddenInput = document.getElementById('selected-columns-data'); | |
| if (hiddenInput) {{ | |
| hiddenInput.value = JSON.stringify(selectedColumns); | |
| // Trigger change event for Gradio | |
| hiddenInput.dispatchEvent(new Event('input', {{ bubbles: true }})); | |
| }} | |
| }} | |
| window.toggleDropdown = function() {{ | |
| const menu = document.getElementById('dropdown-menu'); | |
| const arrow = document.getElementById('dropdown-arrow'); | |
| if (menu && arrow) {{ | |
| menu.classList.toggle('show'); | |
| arrow.classList.toggle('open'); | |
| }} | |
| }} | |
| // Handle dropdown item clicks | |
| document.addEventListener('click', function(e) {{ | |
| if (e.target.classList.contains('dropdown-item')) {{ | |
| const column = e.target.getAttribute('data-column'); | |
| if (selectedColumns.includes(column)) {{ | |
| selectedColumns = selectedColumns.filter(c => c !== column); | |
| e.target.classList.remove('selected'); | |
| }} else {{ | |
| selectedColumns.push(column); | |
| e.target.classList.add('selected'); | |
| }} | |
| updateSelectedDisplay(); | |
| updateHiddenInput(); | |
| }} | |
| // Handle tag remove | |
| if (e.target.classList.contains('remove')) {{ | |
| const tag = e.target.parentElement; | |
| const column = tag.getAttribute('data-column'); | |
| selectedColumns = selectedColumns.filter(c => c !== column); | |
| // Update dropdown item | |
| const dropdownItem = document.querySelector(`.dropdown-item[data-column="${{column}}"]`); | |
| if (dropdownItem) {{ | |
| dropdownItem.classList.remove('selected'); | |
| }} | |
| updateSelectedDisplay(); | |
| updateHiddenInput(); | |
| }} | |
| // Close dropdown when clicking outside | |
| if (!e.target.closest('.dropdown-wrapper')) {{ | |
| const menu = document.getElementById('dropdown-menu'); | |
| const arrow = document.getElementById('dropdown-arrow'); | |
| if (menu && arrow) {{ | |
| menu.classList.remove('show'); | |
| arrow.classList.remove('open'); | |
| }} | |
| }} | |
| }}); | |
| function updateSelectedDisplay() {{ | |
| const tagsContainer = document.getElementById('selected-tags'); | |
| const dropdownText = document.getElementById('dropdown-text'); | |
| if (tagsContainer && dropdownText) {{ | |
| if (selectedColumns.length === 0) {{ | |
| dropdownText.textContent = 'Choose columns to work with'; | |
| tagsContainer.innerHTML = ''; | |
| }} else {{ | |
| dropdownText.textContent = selectedColumns.length + ' column(s) selected'; | |
| tagsContainer.innerHTML = selectedColumns.map(col => | |
| `<span class="tag" data-column="${{col}}">${{col}}<span class="remove">×</span></span>` | |
| ).join(''); | |
| }} | |
| }} | |
| }} | |
| }})(); | |
| </script> | |
| """ | |
| def get_selected_columns_from_html(): | |
| """This would normally extract from the hidden input, but we'll use State instead""" | |
| return [] | |
| def clear_dataset(): | |
| global uploaded_df, original_df, dataset_name, change_history | |
| uploaded_df = None | |
| original_df = None | |
| dataset_name = None | |
| change_history = [] | |
| return "", None, [], create_dropdown_html([], []) | |
| def update_preview(format_type, columns): | |
| global uploaded_df | |
| if uploaded_df is None or format_type == "None": | |
| return None, "", gr.update(visible=False), gr.update(visible=False) | |
| try: | |
| # Use selected columns or all columns if none selected | |
| selected_columns = columns if columns else list(uploaded_df.columns) | |
| selected_df = uploaded_df[selected_columns] | |
| if format_type == "DataFrame": | |
| return selected_df, "", gr.update(visible=True), gr.update(visible=False) | |
| elif format_type == "JSON": | |
| json_str = selected_df.to_json(indent=2) | |
| return None, json_str, gr.update(visible=False), gr.update(visible=True) | |
| elif format_type == "Dictionary": | |
| dict_str = str(selected_df.to_dict()) | |
| return None, dict_str, gr.update(visible=False), gr.update(visible=True) | |
| except Exception as e: | |
| return None, f"Error: {str(e)}", gr.update(visible=False), gr.update(visible=True) | |
| def handle_analysis_change(analysis_type, columns): | |
| global uploaded_df | |
| if uploaded_df is None or analysis_type == "None": | |
| return "", "", None | |
| try: | |
| result = run_analysis(uploaded_df, analysis_type, columns) | |
| if isinstance(result, tuple): | |
| text_result, data_result = result | |
| return text_result, "", data_result | |
| else: | |
| return str(result), "", None | |
| except Exception as e: | |
| return f"Error in analysis: {str(e)}", "", None | |
| def handle_viz_change(viz_type, columns): | |
| global uploaded_df | |
| if uploaded_df is None or viz_type == "None": | |
| return None, None, "", "" | |
| try: | |
| chart, explanation = create_visualization(uploaded_df, viz_type, columns) | |
| return chart, None, explanation, "" | |
| except Exception as e: | |
| return None, None, f"Error creating visualization: {str(e)}", "" | |
| def show_constant_input(handler_type): | |
| return gr.update(visible=(handler_type == "Constant Fill")) | |
| def handle_data_and_refresh(handler, columns, constant, analysis_type): | |
| global uploaded_df, change_history | |
| if uploaded_df is None or handler == "None": | |
| return "", "", [], "" | |
| try: | |
| result = handle_missing_data(uploaded_df, handler, columns, constant) | |
| change_history.append(uploaded_df.copy()) | |
| analysis_result = "" | |
| if analysis_type != "None": | |
| analysis_result = str(run_analysis(uploaded_df, analysis_type, columns)) | |
| new_columns = list(uploaded_df.columns) | |
| info = f"Applied {handler} to dataset\nShape: {uploaded_df.shape}" | |
| dropdown_html = create_dropdown_html(new_columns, new_columns) | |
| return result, analysis_result, new_columns, info, dropdown_html | |
| except Exception as e: | |
| return f"Error: {str(e)}", "", [], "", "" | |
| def handle_undo_and_refresh(analysis_type, undo_all): | |
| global uploaded_df, change_history | |
| if uploaded_df is None: | |
| return "", "", [], "", "" | |
| try: | |
| if undo_all: | |
| result = undo_all_changes() | |
| else: | |
| result = undo_last_change() | |
| analysis_result = "" | |
| if analysis_type != "None": | |
| analysis_result = str(run_analysis(uploaded_df, analysis_type, [])) | |
| new_columns = list(uploaded_df.columns) | |
| info = f"Dataset restored\nShape: {uploaded_df.shape}" | |
| dropdown_html = create_dropdown_html(new_columns, new_columns) | |
| return result, analysis_result, new_columns, info, dropdown_html | |
| except Exception as e: | |
| return f"Error: {str(e)}", "", [], "", "" | |
| def handle_question_analysis(question, columns): | |
| global llm, uploaded_df | |
| if llm is None: | |
| llm = initialize_llm() | |
| return analyze_question(question, columns, uploaded_df, llm) | |
| def sync_selected_columns(selected_json_str): | |
| """Sync selected columns from hidden input""" | |
| try: | |
| if selected_json_str: | |
| return json.loads(selected_json_str) | |
| except: | |
| pass | |
| return [] | |
| with gr.Blocks(theme=gr.themes.Soft(), css=custom_css) as demo: | |
| popup_visible = gr.State(False) | |
| selected_columns_state = gr.State([]) | |
| gr.HTML(f""" | |
| <!-- How to Use Section - Fixed Left Side --> | |
| <div class="how-to-use-sidebar"> | |
| <div class="how-to-use-content"> | |
| <h3>How to Use</h3> | |
| <ul> | |
| <li>• Use Display Format to preview or view summary of your data.</li> | |
| <li>• Select an Analysis Type to explore key insights and patterns.</li> | |
| <li>• Choose a Visualization Type to generate charts and graphical views.</li> | |
| <li>• Ask any question about your data in the text box and click Analyze to get AI-driven results.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="header-box"> | |
| <div style="flex:1; display:flex; justify-content:flex-start; width: 100px;"> | |
| <img src="{logo_b64}" width="120" style="margin-bottom:70px; margin-top: 30px; opacity:0.95;"> | |
| </div> | |
| <div style="flex:1; display:flex; justify-content:center;"> | |
| <h1 class="header-title">SparkNova</h1> | |
| </div> | |
| <div style="flex:1;"></div> | |
| </div> | |
| <div style="text-align: center; display: flex; justify-content: center;"> | |
| <p style="margin-top:20px; font-size:1.30em; opacity:0.92; color: white; max-width: 1450px; line-height: 1.45;"> | |
| SparkNova is a data analysis platform that allows users to upload datasets, explore insights, visualize patterns, and ask questions about their data. It simplifies data analytics by automating cleaning, visualization, and intelligent interpretation for quick decision-making. | |
| </p> | |
| </div> | |
| """) | |
| with gr.Row(elem_classes="first-row"): | |
| # Left Column - Upload Dataset | |
| with gr.Column(scale=1): | |
| with gr.Group(elem_id="upload-wrapper", elem_classes="upload-section"): | |
| gr.Markdown("### Upload Dataset", elem_classes="upload-title") | |
| file_input = gr.File( | |
| label="Choose File", | |
| file_types=[".csv", ".xlsx", ".xls"], | |
| elem_classes="upload-card", | |
| ) | |
| dataset_info = gr.Markdown(value="", elem_classes="upload-info") | |
| clear_btn = gr.Button("Clear Dataset", variant="secondary", size="sm") | |
| # Middle Column - Custom Dropdown Column Selector | |
| with gr.Column(scale=1): | |
| with gr.Group(): | |
| gr.Markdown("### 📋 Column Selector") | |
| column_dropdown_html = gr.HTML(create_dropdown_html([], [])) | |
| # Hidden textbox to capture selected columns from JavaScript | |
| selected_columns_json = gr.Textbox(visible=False, elem_id="selected-columns-data") | |
| # Right Column - Display Format | |
| with gr.Column(scale=1): | |
| with gr.Group(): | |
| gr.Markdown("### 🔍 Display Format") | |
| format_selector = gr.Dropdown( | |
| choices=["None", "DataFrame", "JSON", "Dictionary"], | |
| value="None", | |
| label="Format Type" | |
| ) | |
| # Hidden elements | |
| constant_input = gr.Textbox( | |
| label="Constant Value", | |
| placeholder="Enter value", | |
| visible=False | |
| ) | |
| data_handling_output = gr.Textbox(label="Results", lines=2, visible=False, interactive=False) | |
| download_file = gr.File(label="Download", visible=False) | |
| with gr.Row(elem_classes="second-row"): | |
| with gr.Group(elem_classes="overflow-class"): | |
| gr.Markdown("### 📊 Analysis Type") | |
| analysis_selector = gr.Dropdown( | |
| choices=["None", "Summary", "Describe", "Top 5 Rows", "Bottom 5 Rows", | |
| "Missing Values", "Group & Aggregate", "Calculate Expressions", "Highest Correlation"], | |
| value="None", | |
| label="Select Analysis" | |
| ) | |
| with gr.Group(): | |
| gr.Markdown("### 📈 Visualization") | |
| viz_selector = gr.Dropdown( | |
| choices=["None", "Bar Chart", "Line Chart", "Scatter Plot", "Pie Chart", | |
| "Histogram", "Box Plot", "Heat Map"], | |
| value="None", | |
| label="Chart Type" | |
| ) | |
| with gr.Group(): | |
| gr.Markdown("### 🔧 Data Handling") | |
| data_handler = gr.Dropdown( | |
| choices=["None", "Forward Fill", "Backward Fill", "Constant Fill", | |
| "Mean Fill", "Median Fill", "Mode Fill", "Drop Columns"], | |
| value="None", | |
| label="Method" | |
| ) | |
| with gr.Row(): | |
| apply_btn = gr.Button("Apply", variant="primary", size="sm") | |
| undo_last_btn = gr.Button("Undo", variant="secondary", size="sm") | |
| with gr.Row(): | |
| undo_all_btn = gr.Button("Undo All", variant="secondary", size="sm") | |
| download_btn = gr.Button("Download", variant="secondary", size="sm") | |
| with gr.Column(scale=2): | |
| preview_heading = gr.Markdown("", visible=False) | |
| dataset_preview = gr.Dataframe(visible=False) | |
| text_preview = gr.Textbox(label="Text Preview", lines=8, visible=False) | |
| analysis_heading = gr.Markdown("### Analysis Results", visible=False) | |
| analysis_output = gr.Textbox(label="Analysis Output", lines=6, visible=False, interactive=False) | |
| analysis_data_table = gr.Dataframe(label="Data Table", visible=False) | |
| chart_output_new = gr.Plot(label="Chart", visible=False) | |
| chart_explanation = gr.Textbox(label="Chart Analysis", lines=3, visible=False, interactive=False) | |
| with gr.Column(visible=False, elem_classes="chat-popup-box") as chat_popup: | |
| gr.HTML('<div class="chat-header"><h3>💬 Ask a Question</h3></div>') | |
| with gr.Column(elem_classes="chat-content-area"): | |
| gr.HTML(''' | |
| <div class="sample-questions-box"> | |
| <h4>Sample Questions</h4> | |
| <ul style="list-style: none; padding: 0; margin: 10px 0;"> | |
| <li style="margin: 8px 0; color: #555;">• What is the average of all numeric columns?</li> | |
| <li style="margin: 8px 0; color: #555;">• Show me the correlation between columns</li> | |
| <li style="margin: 8px 0; color: #555;">• What are the missing values in my dataset?</li> | |
| </ul> | |
| </div> | |
| ''') | |
| gr.HTML('<div style="margin: 20px 0 10px 0; font-weight: 600; color: #333; font-size: 15px;">✍️ Type Your Question Here</div>') | |
| question_input = gr.Textbox( | |
| placeholder="Ask anything about your dataset...", | |
| lines=2, | |
| elem_classes="question-input-field", | |
| show_label=False | |
| ) | |
| with gr.Row(): | |
| ask_btn = gr.Button("Ask Question", variant="primary", size="sm") | |
| close_chat_btn = gr.Button("Close", variant="secondary", size="sm") | |
| answer_output = gr.Textbox( | |
| label="Answer", | |
| lines=4, | |
| interactive=False, | |
| elem_id="answer-output" | |
| ) | |
| answer_chart = gr.Plot(label="Generated Chart", visible=False) | |
| answer_data = gr.Dataframe(label="Generated Data", visible=False) | |
| # Floating Chat Button | |
| floating_chat_button = gr.Button("💬", elem_classes="floating-chat-btn") | |
| # Event handlers | |
| file_input.upload( | |
| fn=upload_dataset, | |
| inputs=[file_input], | |
| outputs=[dataset_info, dataset_preview, selected_columns_state, column_dropdown_html] | |
| ) | |
| clear_btn.click( | |
| fn=clear_dataset, | |
| outputs=[dataset_info, dataset_preview, selected_columns_state, column_dropdown_html] | |
| ) | |
| # Sync selected columns from hidden input | |
| selected_columns_json.change( | |
| fn=sync_selected_columns, | |
| inputs=[selected_columns_json], | |
| outputs=[selected_columns_state] | |
| ) | |
| format_selector.change( | |
| fn=update_preview, | |
| inputs=[format_selector, selected_columns_state], | |
| outputs=[dataset_preview, text_preview, preview_heading, analysis_heading] | |
| ) | |
| analysis_selector.change( | |
| fn=handle_analysis_change, | |
| inputs=[analysis_selector, selected_columns_state], | |
| outputs=[analysis_output, chart_explanation, analysis_data_table] | |
| ) | |
| viz_selector.change( | |
| fn=handle_viz_change, | |
| inputs=[viz_selector, selected_columns_state], | |
| outputs=[chart_output_new, analysis_data_table, chart_explanation, analysis_output] | |
| ) | |
| data_handler.change( | |
| fn=show_constant_input, | |
| inputs=[data_handler], | |
| outputs=[constant_input] | |
| ) | |
| apply_btn.click( | |
| fn=handle_data_and_refresh, | |
| inputs=[data_handler, selected_columns_state, constant_input, analysis_selector], | |
| outputs=[data_handling_output, analysis_output, selected_columns_state, dataset_info, column_dropdown_html] | |
| ) | |
| undo_last_btn.click( | |
| fn=lambda analysis_type: handle_undo_and_refresh(analysis_type, False), | |
| inputs=[analysis_selector], | |
| outputs=[data_handling_output, analysis_output, selected_columns_state, dataset_info, column_dropdown_html] | |
| ) | |
| undo_all_btn.click( | |
| fn=lambda analysis_type: handle_undo_and_refresh(analysis_type, True), | |
| inputs=[analysis_selector], | |
| outputs=[data_handling_output, analysis_output, selected_columns_state, dataset_info, column_dropdown_html] | |
| ) | |
| # Toggle chat popup visibility | |
| def toggle_chat_popup(current_visible): | |
| new_visible = not current_visible | |
| return gr.update(visible=new_visible), new_visible | |
| floating_chat_button.click( | |
| toggle_chat_popup, | |
| inputs=[popup_visible], | |
| outputs=[chat_popup, popup_visible] | |
| ) | |
| close_chat_btn.click( | |
| fn=lambda: (gr.update(visible=False), False), | |
| outputs=[chat_popup, popup_visible] | |
| ) | |
| ask_btn.click( | |
| fn=handle_question_analysis, | |
| inputs=[question_input, selected_columns_state], | |
| outputs=[answer_output, answer_chart, answer_data] | |
| ) | |
| def handle_download(): | |
| if uploaded_df is not None: | |
| filepath = download_dataset(uploaded_df, dataset_name) | |
| return gr.update(value=filepath, visible=bool(filepath)) | |
| return gr.update(visible=False) | |
| download_btn.click(handle_download, outputs=[download_file]) | |
| if __name__ == "__main__": | |
| demo.launch(share=True, debug=True) |