""" š MissionControlMCP - Gradio Web Interface Beautiful GUI demo for all 8 tools! Run: python demo_gui.py Then share the public URL on LinkedIn! """ import gradio as gr import sys import os import json import base64 from io import BytesIO from PIL import Image # Setup paths SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.append(SCRIPT_DIR) EXAMPLES_DIR = os.path.join(SCRIPT_DIR, "examples") # Import tools from tools.pdf_reader import read_pdf from tools.text_extractor import extract_text from tools.web_fetcher import fetch_web_content from tools.rag_search import search_documents from tools.data_visualizer import visualize_data from tools.file_converter import convert_file from tools.email_intent_classifier import classify_email_intent from tools.kpi_generator import generate_kpis # ============================================================================ # TOOL FUNCTIONS # ============================================================================ def tool_pdf_reader(pdf_file): """PDF Reader tool""" try: if pdf_file is None: return "ā Please upload a PDF file!", None result = read_pdf(pdf_file.name) output = f"""ā **PDF Analysis Complete!** š **Metadata:** - Pages: {result['pages']} - Characters: {len(result['text']):,} - Author: {result['metadata'].get('author', 'N/A')} - Title: {result['metadata'].get('title', 'N/A')} š **Extracted Text (first 1000 chars):** {result['text'][:1000]}... """ # Extract keywords keywords = extract_text(result['text'], operation="keywords") output += f"\n\nš **Keywords:** {keywords['result']}" return output, None except Exception as e: return f"ā Error: {str(e)}", None def tool_text_extractor(text, operation, max_length): """Text Extractor tool""" try: if not text.strip(): return "ā Please enter some text!" result = extract_text(text, operation=operation, max_length=max_length) output = f"""ā **Text Processing Complete!** š **Operation:** {operation.upper()} š **Word Count:** {result['word_count']} š **Result:** {result['result']} """ return output except Exception as e: return f"ā Error: {str(e)}" def tool_web_fetcher(url): """Web Fetcher tool""" try: if not url.strip(): return "ā Please enter a URL!" result = fetch_web_content(url) if result['status_code'] == 999: return f"""ā ļø **Status 999 - Bot Detection** The website is blocking automated requests. This is common for LinkedIn, Facebook, etc. Try a different website!""" output = f"""ā **Website Fetched Successfully!** š **URL:** {url} š **Status:** {result['status_code']} š **Title:** {result.get('title', 'N/A')} š **Content Length:** {len(result['content']):,} characters š **Links Found:** {len(result.get('links', []))} š **Content Preview (first 1000 chars):** {result['content'][:1000]}... """ # Extract keywords if len(result['content']) > 50: keywords = extract_text(result['content'], operation="keywords") output += f"\n\nš **Keywords:** {keywords['result']}" return output except Exception as e: return f"ā Error: {str(e)}" def tool_rag_search(query): """RAG Search tool""" try: if not query.strip(): return "ā Please enter a search query!" # Load sample documents docs_file = os.path.join(EXAMPLES_DIR, "sample_documents.txt") with open(docs_file, "r", encoding="utf-8") as f: content = f.read() documents = [doc.strip() for doc in content.split("##") if doc.strip()] result = search_documents(query, documents, top_k=3) output = f"""ā **Search Complete!** š **Query:** "{query}" š **Documents Searched:** {len(documents)} š **Results Found:** {len(result['results'])} šÆ **Top Results:** """ for i, res in enumerate(result['results'], 1): preview = res['document'][:200].replace('\n', ' ') output += f""" **Result {i}** (Score: {res['score']:.4f}) {preview}... """ return output except Exception as e: return f"ā Error: {str(e)}" def tool_data_visualizer(csv_data, chart_type, x_col, y_col, title): """Data Visualizer tool""" try: if not csv_data.strip(): return "ā Please enter CSV data!", None result = visualize_data( data=csv_data, chart_type=chart_type, x_column=x_col, y_column=y_col, title=title ) # Convert base64 to image img_data = base64.b64decode(result['image_base64']) image = Image.open(BytesIO(img_data)) output = f"""ā **Chart Created!** š **Chart Type:** {chart_type.upper()} š **Dimensions:** {result['dimensions']} š **Title:** {title} """ return output, image except Exception as e: return f"ā Error: {str(e)}", None def tool_email_classifier(email_text): """Email Intent Classifier tool""" try: if not email_text.strip(): return "ā Please enter email text!" result = classify_email_intent(email_text) output = f"""ā **Email Classified!** šÆ **Primary Intent:** {result['intent'].upper()} š **Confidence:** {result['confidence']:.2%} š¬ **Explanation:** {result['explanation']} """ if result['secondary_intents']: output += "\n\nš **Secondary Intents:**\n" for intent in result['secondary_intents'][:3]: output += f"- {intent['intent']}: {intent['confidence']:.2%}\n" return output except Exception as e: return f"ā Error: {str(e)}" def tool_kpi_generator(business_json, metrics): """KPI Generator tool""" try: if not business_json.strip(): return "ā Please enter business data!" # Validate JSON json.loads(business_json) result = generate_kpis(business_json, metrics=metrics) output = f"""ā **KPIs Generated!** š **Total KPIs Calculated:** {len(result['kpis'])} š **Key Metrics:** """ # Display top 15 KPIs for i, (name, value) in enumerate(list(result['kpis'].items())[:15], 1): # Format based on metric type if 'percent' in name or 'rate' in name or 'margin' in name: formatted = f"{value:.1f}%" elif 'revenue' in name or 'profit' in name or 'cost' in name: formatted = f"${value:,.0f}" else: formatted = f"{value:,.2f}" display_name = name.replace('_', ' ').title() output += f"{i}. **{display_name}:** {formatted}\n" output += f"\n\nš **Executive Summary:**\n{result['summary']}" if result.get('trends'): output += "\n\nš **Key Trends:**\n" for trend in result['trends'][:5]: output += f"- {trend}\n" return output except json.JSONDecodeError: return "ā Invalid JSON format! Please check your data." except Exception as e: return f"ā Error: {str(e)}" # ============================================================================ # LOAD SAMPLE DATA # ============================================================================ def load_sample_csv(): csv_file = os.path.join(EXAMPLES_DIR, "business_data.csv") with open(csv_file, "r") as f: return f.read() def load_sample_email(): email_file = os.path.join(EXAMPLES_DIR, "sample_email_complaint.txt") with open(email_file, "r", encoding="utf-8") as f: return f.read() def load_sample_json(): return """{ "revenue": 5500000, "costs": 3400000, "customers": 2700, "current_revenue": 5500000, "previous_revenue": 5400000, "current_customers": 2700, "previous_customers": 2650, "employees": 50, "marketing_spend": 500000, "sales": 5500000, "cogs": 2000000 }""" # ============================================================================ # GRADIO INTERFACE # ============================================================================ # Custom CSS for beautiful UI custom_css = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); /* Global mobile-first settings */ * { box-sizing: border-box !important; } html, body { overflow-x: hidden !important; width: 100% !important; } .gradio-container { font-family: 'Inter', sans-serif !important; max-width: 1400px !important; margin: 0 auto !important; padding: 10px !important; width: 100% !important; overflow-x: hidden !important; } /* Header styling */ .gradio-container h1 { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 3em !important; font-weight: 700 !important; text-align: center; margin-bottom: 0.5em; } /* Mobile responsive header */ @media (max-width: 768px) { .gradio-container h1 { font-size: 2em !important; } .gradio-container h3 { font-size: 1.2em !important; } .gradio-container p { font-size: 0.9em !important; } } /* Tab styling */ .tab-nav { border-radius: 12px !important; background: linear-gradient(to right, #f8f9fa, #e9ecef) !important; padding: 8px !important; margin-bottom: 20px !important; } button.selected { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; color: white !important; border-radius: 8px !important; font-weight: 600 !important; box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4) !important; } /* Mobile tab styling */ @media (max-width: 768px) { .tab-nav button { font-size: 0.85em !important; padding: 8px 12px !important; } } /* Button styling */ .primary-btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border: none !important; color: white !important; font-weight: 600 !important; border-radius: 10px !important; padding: 12px 24px !important; font-size: 16px !important; transition: all 0.3s ease !important; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4) !important; } .primary-btn:hover { transform: translateY(-2px) !important; box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6) !important; } /* Mobile button styling */ @media (max-width: 768px) { .primary-btn { width: 100% !important; padding: 14px 20px !important; font-size: 15px !important; } } /* Input fields */ textarea, input[type="text"] { border-radius: 10px !important; border: 2px solid #e9ecef !important; padding: 12px !important; font-size: 15px !important; transition: border-color 0.3s ease !important; } textarea:focus, input[type="text"]:focus { border-color: #667eea !important; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important; } /* Mobile input fields */ @media (max-width: 768px) { textarea, input[type="text"] { font-size: 16px !important; padding: 10px !important; } } /* Output boxes */ .output-class { background: linear-gradient(to bottom, #ffffff, #f8f9fa) !important; border-radius: 12px !important; padding: 20px !important; border: 2px solid #e9ecef !important; } /* Cards and containers */ .gr-box { border-radius: 12px !important; border: 1px solid #e9ecef !important; box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important; } /* Labels */ label { font-weight: 600 !important; color: #495057 !important; font-size: 14px !important; margin-bottom: 8px !important; } /* Examples */ .gr-samples-table { border-radius: 10px !important; overflow: hidden !important; } /* Footer */ .footer { text-align: center; padding: 30px; background: linear-gradient(to right, #f8f9fa, #e9ecef); border-radius: 12px; margin-top: 30px; } /* Image display */ .gr-image { border-radius: 12px !important; border: 2px solid #e9ecef !important; box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important; } /* Radio buttons and checkboxes */ .gr-radio, .gr-checkbox { padding: 10px !important; border-radius: 8px !important; } /* File upload */ .gr-file { border: 2px dashed #667eea !important; border-radius: 12px !important; background: linear-gradient(to bottom, #ffffff, #f8f9fa) !important; padding: 30px !important; } .gr-file:hover { border-color: #764ba2 !important; background: #f8f9fa !important; } /* Mobile responsive layout */ @media (max-width: 768px) { .gr-row { flex-direction: column !important; gap: 15px !important; } .gr-column { width: 100% !important; max-width: 100% !important; min-width: 0 !important; flex: 0 0 100% !important; } .gr-file { padding: 20px !important; } /* Stack columns vertically on mobile */ .gradio-container .gr-form { display: flex !important; flex-direction: column !important; } /* Prevent text overflow */ .gradio-container { word-wrap: break-word !important; overflow-wrap: break-word !important; } /* Better spacing on mobile */ .gr-box { margin: 10px 0 !important; } /* Tabs scrollable on mobile */ .tab-nav { overflow-x: auto !important; -webkit-overflow-scrolling: touch !important; white-space: nowrap !important; } } /* Improve touch targets for mobile */ @media (max-width: 768px) { button, a, input, textarea, select { min-height: 44px !important; -webkit-tap-highlight-color: rgba(102, 126, 234, 0.2) !important; } label { font-size: 15px !important; margin-bottom: 10px !important; } /* Better radio and checkbox sizing */ .gr-radio label, .gr-checkbox label { padding: 12px !important; min-height: 44px !important; display: flex !important; align-items: center !important; } /* Mobile-friendly sliders */ input[type="range"] { height: 44px !important; padding: 10px 0 !important; } /* Examples section */ .gr-samples-table { overflow-x: auto !important; -webkit-overflow-scrolling: touch !important; } } /* Footer responsive */ @media (max-width: 768px) { .footer { padding: 20px 10px !important; } .footer h2 { font-size: 1.5em !important; } .footer p { font-size: 0.9em !important; } } /* Smaller screens (phones in portrait) */ @media (max-width: 480px) { .gradio-container h1 { font-size: 1.5em !important; } .tab-nav button { font-size: 0.75em !important; padding: 6px 10px !important; } .primary-btn { font-size: 14px !important; padding: 12px 16px !important; } /* Reduce line count for better mobile UX */ textarea { min-height: 100px !important; } } /* Landscape mobile */ @media (max-width: 768px) and (orientation: landscape) { .gradio-container h1 { font-size: 1.8em !important; margin-bottom: 0.3em !important; } } """ # Create Gradio interface with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="MissionControlMCP Demo") as demo: # Add viewport meta tag for proper mobile rendering gr.HTML("""""") gr.Markdown("# š MissionControlMCP") gr.Markdown("### Enterprise Automation Tools - Powered by AI") gr.HTML("""
Built for HuggingFace Gradio Hackathon | Claude MCP Integration