Download app.py from JatinAutonomousLabs/Excel_AI_Assistant: direct link, hf CLI and curl.
- Browser
- Download file 15.8 kB
-
https://huggingface.co/spaces/JatinAutonomousLabs/Excel_AI_Assistant/resolve/main/app.py
- Command line
-
hf download hf://spaces/JatinAutonomousLabs/Excel_AI_Assistant/app.py
-
curl -L -o app.py https://huggingface.co/spaces/JatinAutonomousLabs/Excel_AI_Assistant/resolve/main/app.py
15.8 kB
| #!/usr/bin/env python3 | |
| """ | |
| Universal Multi-Agent Platform - Core Application (Production Ready) | |
| Auto-generated with Gradio 4.x compatibility | |
| """ | |
| import gradio as gr | |
| import pandas as pd | |
| from typing import Dict, Any, List, Optional, Tuple | |
| from pathlib import Path | |
| import json | |
| import os | |
| # ============================================================================ | |
| # IMPORT ENABLED PLUGINS | |
| # ============================================================================ | |
| from plugins.processors.schema_detector import * | |
| from plugins.processors.text_processor import * | |
| from plugins.outputs.table_formatter import * | |
| from plugins.processors.date_normalizer import * | |
| from plugins.file_handlers.csv_handler import * | |
| from plugins.outputs.report_generator import * | |
| from plugins.file_handlers.excel_handler import * | |
| from plugins.memory.document_memory import * | |
| from plugins.processors.data_cleaner import * | |
| from plugins.analyzers.statistical_analyzer import * | |
| from plugins.analyzers.time_series_analyzer import * | |
| from plugins.outputs.chart_generator import * | |
| from plugins.memory.conversation_memory import * | |
| # ============================================================================ | |
| # PLUGIN MANAGER (Handles all plugin interactions) | |
| # ============================================================================ | |
| class PluginManager: | |
| """Manage all plugins and application state.""" | |
| def __init__(self): | |
| # Initialize file handlers | |
| self.file_handlers = [] | |
| self.file_handlers.append(CSVHandler()) | |
| self.file_handlers.append(ExcelHandler()) | |
| # Initialize processors/analyzers | |
| self.data_cleaner = DataCleaner() if True else None | |
| self.time_series_analyzer = TimeSeriesAnalyzer() if True else None | |
| self.statistical_analyzer = StatisticalAnalyzer() if True else None | |
| # Initialize memory/outputs | |
| self.conversation_memory = ConversationMemory() if True else None | |
| self.table_formatter = TableFormatter() if True else None | |
| self.chart_generator = ChartGenerator() if True else None | |
| # Data storage | |
| self.loaded_data: Optional[Dict[str, Any]] = None | |
| self.cleaned_df: Optional[pd.DataFrame] = None | |
| self.last_chart_json: Optional[str] = None | |
| def load_file(self, file_path: str) -> Dict[str, Any]: | |
| """Load file using appropriate handler and automatically clean data.""" | |
| self.loaded_data = None | |
| self.cleaned_df = None | |
| self.last_chart_json = None | |
| if not os.path.exists(file_path): | |
| return {"success": False, "error": "File not found on server"} | |
| for handler in self.file_handlers: | |
| if handler.can_handle(file_path): | |
| result = handler.load(file_path) | |
| if result.get("success"): | |
| self.loaded_data = result | |
| # Auto-clean tabular data | |
| df = self._get_raw_df() | |
| if df is not None and self.data_cleaner: | |
| df = self.data_cleaner.clean_dataframe(df) | |
| self.cleaned_df = self.data_cleaner.enforce_schema(df) | |
| if "metadata" not in result: | |
| result["metadata"] = {} | |
| result["metadata"]["cleaned_shape"] = list(self.cleaned_df.shape) | |
| result["metadata"]["cleaned_cols"] = list(self.cleaned_df.columns) | |
| return result | |
| return {"success": False, "error": "No handler found for this file type"} | |
| def _get_raw_df(self) -> Optional[pd.DataFrame]: | |
| """Internal method to extract a DataFrame from loaded_data.""" | |
| if not self.loaded_data: | |
| return None | |
| if "combined" in self.loaded_data and isinstance(self.loaded_data["combined"], pd.DataFrame): | |
| return self.loaded_data["combined"] | |
| elif "data" in self.loaded_data and isinstance(self.loaded_data["data"], pd.DataFrame): | |
| return self.loaded_data["data"] | |
| return None | |
| # Initialize plugin manager | |
| pm = PluginManager() | |
| # ============================================================================ | |
| # GRADIO INTERFACE LOGIC | |
| # ============================================================================ | |
| def upload_file(file): | |
| """Handle file upload.""" | |
| if file is None: | |
| return "β No file uploaded", None | |
| try: | |
| result = pm.load_file(file.name) | |
| if result.get("success"): | |
| # Get appropriate handler for preview | |
| preview_html = "Data loaded successfully" | |
| for handler in pm.file_handlers: | |
| if handler.can_handle(file.name) and hasattr(handler, 'preview'): | |
| preview_html = handler.preview(result) | |
| break | |
| shape_info = f"Shape: {pm.cleaned_df.shape}" if pm.cleaned_df is not None else "Non-tabular data" | |
| summary = "β File loaded and processed successfully\n" | |
| summary += f"Type: {result.get('file_type', 'unknown')}\n" | |
| summary += f"Data: {shape_info}\n\n" | |
| summary += "Ready for conversational analysis!" | |
| return summary, preview_html | |
| return f"β Error: {result.get('error')}", None | |
| except Exception as e: | |
| return f"β Critical Error: {str(e)}", None | |
| def process_query(query: str, history: List) -> Tuple[List, str, Optional[str]]: | |
| """ | |
| Executes conversational analytics. | |
| Returns: updated history, empty query text, and chart JSON. | |
| """ | |
| if not query or not query.strip(): | |
| return history + [("", "β Please enter a question")], "", None | |
| if pm.conversation_memory: | |
| pm.conversation_memory.add_message("user", query) | |
| df = pm.cleaned_df | |
| pm.last_chart_json = None | |
| # Handle No Data Case | |
| if df is None or df.empty: | |
| # Check if non-tabular data was loaded | |
| if pm.loaded_data and pm.loaded_data.get('file_type') in ['pdf', 'docx']: | |
| document_text = pm.loaded_data.get('text', '') or str(pm.loaded_data.get('text_data', [{}])[0].get('text', 'No text')) | |
| response = "π **Document Content Loaded**\n\n" | |
| response += "The system has loaded a document. Advanced NLP analysis would be applied here.\n" | |
| response += f"Text Sample: {document_text[:200]}..." | |
| else: | |
| response = "β No **data** loaded for analysis. Please upload a file first." | |
| if pm.conversation_memory: | |
| pm.conversation_memory.add_message("assistant", response) | |
| return history + [(query, response)], "", None | |
| try: | |
| # Execute Analytics | |
| if pm.time_series_analyzer: | |
| description, result_df = pm.time_series_analyzer.analyze_query(df, query) | |
| elif pm.statistical_analyzer: | |
| stats = pm.statistical_analyzer.analyze(df) | |
| description = "π Statistical Analysis Results" | |
| result_df = pd.DataFrame(stats.get('columns', {})).T | |
| else: | |
| description = "β οΈ No analyzer available. Upload data and try basic queries." | |
| result_df = None | |
| final_response = f"**Query:** {query}\n\n{description}\n\n" | |
| chart_json = None | |
| if result_df is not None and not result_df.empty: | |
| # Format Table Output | |
| if pm.table_formatter: | |
| table_markdown = pm.table_formatter.format_to_markdown(result_df.head(10)) | |
| final_response += "### Results (Top 10 Rows):\n" | |
| final_response += table_markdown | |
| final_response += f"\n\n*Total Rows: {len(result_df):,}*" | |
| # Generate Chart Output | |
| if pm.chart_generator and len(result_df.columns) >= 2: | |
| try: | |
| x_col = result_df.columns[0] | |
| y_col = result_df.columns[1] | |
| chart_json = pm.chart_generator.create_chart_html( | |
| result_df.head(20), | |
| 'bar', | |
| x=x_col, | |
| y=y_col, | |
| title=description.split('\n')[0][:50] | |
| ) | |
| except Exception as chart_err: | |
| print(f"Chart generation failed: {chart_err}") | |
| else: | |
| final_response = f"**Query:** {query}\n\n{description}" | |
| if pm.conversation_memory: | |
| pm.conversation_memory.add_message("assistant", final_response) | |
| return history + [(query, final_response)], "", chart_json | |
| except Exception as e: | |
| import traceback | |
| error_trace = traceback.format_exc() | |
| response = f"β Analysis Error: {str(e)}\n\nDebug Info:\n```\n{error_trace[:500]}\n```" | |
| return history + [(query, response)], "", None | |
| def create_ui(): | |
| """Create Gradio interface (Gradio 4.x compatible).""" | |
| with gr.Blocks(title="Universal AI Platform", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# π€ Universal Multi-Agent Platform") | |
| gr.Markdown("## AI-Powered Analysis & Conversational Intelligence") | |
| with gr.Tabs(): | |
| # ================================================================ | |
| # FILE UPLOAD TAB | |
| # ================================================================ | |
| with gr.Tab("π Upload & Process"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| file_upload = gr.File( | |
| label="Upload Your File", | |
| file_types=[".xlsx", ".xls", ".csv", ".pdf", ".docx", ".json", ".xml"], | |
| interactive=True | |
| ) | |
| upload_btn = gr.Button("π€ Process File", variant="primary", size="lg") | |
| upload_status = gr.Textbox( | |
| label="Status", | |
| lines=8, | |
| value="Ready to process files. Supported: Excel, CSV, PDF, Word, JSON, XML", | |
| interactive=False | |
| ) | |
| with gr.Column(scale=2): | |
| data_preview = gr.HTML(label="Data Preview") | |
| upload_btn.click( | |
| fn=upload_file, | |
| inputs=[file_upload], | |
| outputs=[upload_status, data_preview] | |
| ) | |
| # ================================================================ | |
| # CHAT INTERFACE TAB | |
| # ================================================================ | |
| with gr.Tab("π¬ Ask Questions"): | |
| chatbot = gr.Chatbot( | |
| height=450, | |
| label="Conversational AI Assistant", | |
| type='tuples', | |
| show_copy_button=True | |
| ) | |
| gr.Markdown(""" | |
| ### π Example Queries: | |
| - "Summarize the data" | |
| - "Show me aggregated statistics" | |
| - "Group by [column name]" | |
| - "Segment the data into categories" | |
| - "Analyze trends over time" | |
| - "Show correlation between columns" | |
| """) | |
| with gr.Row(): | |
| msg = gr.Textbox( | |
| label="Your Query", | |
| placeholder="Ask anything about your data...", | |
| scale=4, | |
| lines=2 | |
| ) | |
| submit_btn = gr.Button("Send", variant="primary", scale=1, size="lg") | |
| # Chart display area | |
| chart_display = gr.HTML( | |
| label="Visualization", | |
| value="" | |
| ) | |
| # Clear button | |
| with gr.Row(): | |
| clear_btn = gr.Button("ποΈ Clear Chat", variant="secondary") | |
| def process_and_display(query: str, history: List) -> Tuple[List, str, str]: | |
| """Process query and return chart HTML.""" | |
| updated_history, empty_msg, chart_json_str = process_query(query, history) | |
| # Convert chart JSON to HTML with embedded Plotly | |
| # KEY FIX: Use string concatenation instead of f-string substitution | |
| chart_html = "" | |
| if chart_json_str: | |
| # Build the HTML string using concatenation to avoid f-string issues | |
| chart_html = ( | |
| '<div style="width: 100%; height: 500px; margin-top: 20px;">' + | |
| '<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>' + | |
| '<div id="plotly-chart-container"></div>' + | |
| '<script>' + | |
| '(function() {' + | |
| 'try {' + | |
| 'const chartData = ' + chart_json_str + ';' + | |
| "Plotly.newPlot('plotly-chart-container', chartData.data, chartData.layout, {responsive: true, displayModeBar: true});" + | |
| '} catch (e) {' + | |
| "console.error('Chart rendering error:', e);" + | |
| "document.getElementById('plotly-chart-container').innerHTML = '<p style=\"color: red; padding: 20px;\">Chart rendering failed: ' + e.message + '</p>';" + | |
| '}' + | |
| '})();' + | |
| '</script>' + | |
| '</div>' | |
| ) | |
| return updated_history, empty_msg, chart_html | |
| # Wire up the chat interface | |
| msg.submit( | |
| process_and_display, | |
| inputs=[msg, chatbot], | |
| outputs=[chatbot, msg, chart_display] | |
| ) | |
| submit_btn.click( | |
| process_and_display, | |
| inputs=[msg, chatbot], | |
| outputs=[chatbot, msg, chart_display] | |
| ) | |
| clear_btn.click( | |
| lambda: ([], ""), | |
| outputs=[chatbot, chart_display] | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown(f"**Enabled Plugins:** Schema Detector, Text Processor, Table Formatter, Date Normalizer, CSV Handler, Report Generator, Excel Handler, Document Memory, Data Cleaner, Statistical Analyzer, Time Series Analyzer, Chart Generator, Conversation Memory") | |
| gr.Markdown("*Powered by Universal AI Agent Development Platform*") | |
| return demo | |
| # ============================================================================ | |
| # MAIN ENTRY POINT | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| # Check for environment variables | |
| if not os.getenv("OPENAI_API_KEY"): | |
| print("β οΈ Warning: OPENAI_API_KEY not set (not required for basic analytics)") | |
| # Launch application | |
| print("π Launching Universal AI Platform...") | |
| demo = create_ui() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) | |