🎨 Modernizar interfaz Gradio: diseño profesional, eliminar referencias específicas, CSS avanzado
42886e3 | #!/usr/bin/env python3 | |
| """ | |
| Gradio app for Hugging Face Spaces deployment | |
| Advanced sentiment analysis demo with modern UI | |
| """ | |
| import gradio as gr | |
| import torch | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| import numpy as np | |
| import plotly.express as px | |
| import pandas as pd | |
| from typing import Dict, List, Tuple | |
| import logging | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| class SentimentAnalyzer: | |
| """Professional sentiment analyzer for demo""" | |
| def __init__(self): | |
| self.model_name = "distilbert-base-uncased-finetuned-sst-2-english" | |
| self.tokenizer = None | |
| self.model = None | |
| self.load_model() | |
| def load_model(self): | |
| """Load the pre-trained model""" | |
| try: | |
| logger.info(f"Loading model: {self.model_name}") | |
| self.tokenizer = AutoTokenizer.from_pretrained(self.model_name) | |
| self.model = AutoModelForSequenceClassification.from_pretrained(self.model_name) | |
| logger.info("Model loaded successfully!") | |
| except Exception as e: | |
| logger.error(f"Error loading model: {e}") | |
| raise | |
| def analyze_single(self, text: str) -> Dict: | |
| """Analyze sentiment of a single text""" | |
| if not text.strip(): | |
| return { | |
| "sentiment": "Please enter some text", | |
| "confidence": 0.0, | |
| "probabilities": None | |
| } | |
| try: | |
| # Tokenize | |
| inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=512) | |
| # Predict | |
| with torch.no_grad(): | |
| outputs = self.model(**inputs) | |
| predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) | |
| # Process results | |
| probs = predictions[0].numpy() | |
| predicted_class = np.argmax(probs) | |
| confidence = float(probs[predicted_class]) | |
| sentiment = "POSITIVE" if predicted_class == 1 else "NEGATIVE" | |
| return { | |
| "sentiment": sentiment, | |
| "confidence": confidence, | |
| "probabilities": { | |
| "Negative": float(probs[0]), | |
| "Positive": float(probs[1]) | |
| } | |
| } | |
| except Exception as e: | |
| logger.error(f"Error in analysis: {e}") | |
| return { | |
| "sentiment": f"Error: {str(e)}", | |
| "confidence": 0.0, | |
| "probabilities": None | |
| } | |
| def analyze_batch(self, texts: List[str]) -> List[Dict]: | |
| """Analyze multiple texts""" | |
| results = [] | |
| for text in texts: | |
| if text.strip(): | |
| results.append(self.analyze_single(text)) | |
| return results | |
| # Initialize analyzer | |
| analyzer = SentimentAnalyzer() | |
| def analyze_sentiment(text: str) -> Tuple[str, float, dict]: | |
| """Main analysis function for Gradio""" | |
| result = analyzer.analyze_single(text) | |
| # Create confidence plot | |
| if result["probabilities"]: | |
| df = pd.DataFrame([ | |
| {"Sentiment": "Negative", "Probability": result["probabilities"]["Negative"]}, | |
| {"Sentiment": "Positive", "Probability": result["probabilities"]["Positive"]} | |
| ]) | |
| fig = px.bar( | |
| df, | |
| x="Sentiment", | |
| y="Probability", | |
| color="Sentiment", | |
| color_discrete_map={"Negative": "#ff4444", "Positive": "#44ff44"}, | |
| title="Sentiment Probability Distribution" | |
| ) | |
| fig.update_layout(showlegend=False, height=300) | |
| return ( | |
| f"**{result['sentiment']}** (Confidence: {result['confidence']:.1%})", | |
| result['confidence'], | |
| fig | |
| ) | |
| return result['sentiment'], result['confidence'], None | |
| def analyze_batch_texts(text_input: str) -> Tuple[str, dict]: | |
| """Analyze multiple texts separated by newlines""" | |
| if not text_input.strip(): | |
| return "Please enter some texts (one per line)", None | |
| texts = [line.strip() for line in text_input.split('\n') if line.strip()] | |
| if not texts: | |
| return "No valid texts found", None | |
| results = analyzer.analyze_batch(texts) | |
| # Create summary | |
| summary_lines = [] | |
| plot_data = [] | |
| for i, (text, result) in enumerate(zip(texts, results)): | |
| sentiment = result['sentiment'] | |
| confidence = result['confidence'] | |
| summary_lines.append(f"{i+1}. **{sentiment}** ({confidence:.1%}) - {text[:50]}{'...' if len(text) > 50 else ''}") | |
| plot_data.append({ | |
| "Text": f"Text {i+1}", | |
| "Sentiment": sentiment, | |
| "Confidence": confidence | |
| }) | |
| summary = "\n".join(summary_lines) | |
| # Create plot | |
| if plot_data: | |
| df = pd.DataFrame(plot_data) | |
| fig = px.bar( | |
| df, | |
| x="Text", | |
| y="Confidence", | |
| color="Sentiment", | |
| color_discrete_map={"NEGATIVE": "#ff4444", "POSITIVE": "#44ff44"}, | |
| title="Batch Analysis Results" | |
| ) | |
| fig.update_layout(height=400) | |
| return summary, fig | |
| return summary, None | |
| # Demo examples | |
| EXAMPLES = [ | |
| "🎬 This movie absolutely blew my mind! Best film I've seen this year - incredible cinematography and acting!", | |
| "😞 Worst customer service ever. They ignored my calls and the product arrived completely broken. Total waste of money.", | |
| "🤔 The restaurant was decent, nothing extraordinary but the food was acceptable and staff was polite.", | |
| "🚀 Revolutionary AI technology! This transformer model shows incredible understanding of human language nuances.", | |
| "❌ I regret this purchase deeply. Poor quality materials and misleading advertising. Avoid at all costs!", | |
| "✈️ Amazing travel experience! The hotel exceeded expectations and the local tours were absolutely spectacular.", | |
| "📚 Mixed feelings about this book - great storyline but the ending felt rushed and unsatisfying.", | |
| "🎵 Concert was phenomenal! The energy, the music, the atmosphere - everything was absolutely perfect!" | |
| ] | |
| BATCH_EXAMPLE = """🛍️ This online store has amazing customer service! Fast shipping and quality products. | |
| 😡 Terrible experience with their support team. Rude staff and no solutions offered. | |
| 🍕 Pizza was okay, nothing special but not bad either. Average taste and decent price. | |
| ⭐ Outstanding quality! Exceeded all my expectations. Highly recommend to everyone! | |
| 💸 Disappointed with this expensive purchase. Not worth the money at all. | |
| 🎯 Perfect for my needs! Exactly what I was looking for. Great value for money. | |
| 🏨 Hotel was clean and comfortable. Staff was friendly and location was convenient.""" | |
| # Create Gradio interface with modern styling | |
| with gr.Blocks( | |
| title="🤖 Transformer Sentiment Analysis", | |
| theme=gr.themes.Soft( | |
| primary_hue="blue", | |
| secondary_hue="purple", | |
| neutral_hue="slate", | |
| font=["Inter", "ui-sans-serif", "system-ui", "sans-serif"] | |
| ), | |
| css=""" | |
| /* Global styling */ | |
| .gradio-container { | |
| max-width: 1200px; | |
| margin: auto; | |
| font-family: 'Inter', 'SF Pro Display', system-ui, sans-serif; | |
| } | |
| /* Custom button styling */ | |
| #analyze-btn, #batch-btn { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border: none; | |
| color: white; | |
| font-weight: 600; | |
| font-size: 16px; | |
| padding: 12px 24px; | |
| border-radius: 10px; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); | |
| } | |
| #analyze-btn:hover, #batch-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); | |
| } | |
| /* Input field styling */ | |
| #single-input textarea, #batch-input textarea { | |
| border-radius: 10px; | |
| border: 2px solid #e2e8f0; | |
| transition: border-color 0.3s ease; | |
| font-size: 15px; | |
| } | |
| #single-input textarea:focus, #batch-input textarea:focus { | |
| border-color: #667eea; | |
| box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); | |
| } | |
| /* Tab styling */ | |
| .tab-nav button { | |
| border-radius: 8px 8px 0 0; | |
| font-weight: 500; | |
| font-size: 15px; | |
| } | |
| /* Confidence score styling */ | |
| #confidence input { | |
| font-size: 18px; | |
| font-weight: 600; | |
| color: #2E86AB; | |
| text-align: center; | |
| } | |
| /* Cards and panels */ | |
| .gr-panel { | |
| border-radius: 12px; | |
| border: 1px solid #e2e8f0; | |
| } | |
| /* Modern shadows */ | |
| .gr-box { | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06); | |
| } | |
| """ | |
| ) as demo: | |
| gr.Markdown(""" | |
| <div style="text-align: center; margin-bottom: 30px;"> | |
| <h1 style="color: #2E86AB; margin-bottom: 10px;">🤖 Transformer Sentiment Analysis</h1> | |
| <p style="font-size: 18px; color: #555; font-weight: 300; margin-bottom: 20px;"> | |
| Advanced AI-powered sentiment analysis with state-of-the-art transformer models | |
| </p> | |
| <div style="background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); height: 3px; width: 80%; margin: 0 auto; border-radius: 2px;"></div> | |
| </div> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 30px 0;"> | |
| <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; border-left: 4px solid #667eea;"> | |
| <h3 style="color: #2E86AB; margin: 0 0 10px 0;">🧠 Model</h3> | |
| <p style="margin: 0; color: #666;">DistilBERT (66M parameters)</p> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; border-left: 4px solid #52b788;"> | |
| <h3 style="color: #2E86AB; margin: 0 0 10px 0;">⚡ Speed</h3> | |
| <p style="margin: 0; color: #666;">~100ms inference</p> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; border-left: 4px solid #f72585;"> | |
| <h3 style="color: #2E86AB; margin: 0 0 10px 0;">🎯 Accuracy</h3> | |
| <p style="margin: 0; color: #666;">74% on IMDB dataset</p> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; border-left: 4px solid #f77f00;"> | |
| <h3 style="color: #2E86AB; margin: 0 0 10px 0;">📊 Features</h3> | |
| <p style="margin: 0; color: #666;">Confidence & batch processing</p> | |
| </div> | |
| </div> | |
| """) | |
| with gr.Tabs(): | |
| # Single Text Analysis Tab | |
| with gr.TabItem("🔍 Single Analysis", elem_id="single-tab"): | |
| gr.Markdown(""" | |
| <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 15px; border-radius: 10px; margin-bottom: 20px;"> | |
| <h3 style="color: white; margin: 0; text-align: center;"> | |
| Analyze individual texts with detailed confidence metrics | |
| </h3> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| single_input = gr.Textbox( | |
| label="💬 Enter your text", | |
| placeholder="Type or paste your text here for sentiment analysis...", | |
| lines=4, | |
| elem_id="single-input" | |
| ) | |
| single_btn = gr.Button( | |
| "🚀 Analyze Sentiment", | |
| variant="primary", | |
| elem_id="analyze-btn", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=2): | |
| single_output = gr.Markdown(label="📋 Analysis Result") | |
| confidence_score = gr.Number( | |
| label="🎯 Confidence Score", | |
| precision=3, | |
| elem_id="confidence" | |
| ) | |
| probability_plot = gr.Plot(label="📊 Probability Distribution") | |
| # Examples with better styling | |
| gr.Markdown(""" | |
| <div style="margin-top: 30px;"> | |
| <h4 style="color: #2E86AB; margin-bottom: 15px;">💡 Try these examples:</h4> | |
| </div> | |
| """) | |
| examples_single = gr.Examples( | |
| examples=EXAMPLES, | |
| inputs=single_input, | |
| label="" | |
| ) | |
| # Batch Analysis Tab | |
| with gr.TabItem("📊 Batch Processing", elem_id="batch-tab"): | |
| gr.Markdown(""" | |
| <div style="background: linear-gradient(135deg, #52b788 0%, #2d6a4f 100%); | |
| padding: 15px; border-radius: 10px; margin-bottom: 20px;"> | |
| <h3 style="color: white; margin: 0; text-align: center;"> | |
| Process multiple texts simultaneously with advanced analytics | |
| </h3> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| batch_input = gr.Textbox( | |
| label="📝 Multiple texts (one per line)", | |
| placeholder="Enter multiple texts here, one per line...", | |
| lines=8, | |
| value=BATCH_EXAMPLE, | |
| elem_id="batch-input" | |
| ) | |
| batch_btn = gr.Button( | |
| "🚀 Process Batch", | |
| variant="primary", | |
| elem_id="batch-btn", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=2): | |
| batch_output = gr.Markdown(label="📈 Batch Results") | |
| batch_plot = gr.Plot(label="📊 Visual Analytics") | |
| # Technical Details Tab | |
| with gr.TabItem("🛠️ Technical Details", elem_id="tech-tab"): | |
| gr.Markdown(""" | |
| <div style="background: linear-gradient(135deg, #f72585 0%, #b5179e 100%); | |
| padding: 15px; border-radius: 10px; margin-bottom: 20px;"> | |
| <h3 style="color: white; margin: 0; text-align: center;"> | |
| Deep dive into architecture, performance, and capabilities | |
| </h3> | |
| </div> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin: 20px 0;"> | |
| <div style="background: #f8f9fa; padding: 25px; border-radius: 12px; border-top: 4px solid #667eea;"> | |
| <h4 style="color: #2E86AB; margin: 0 0 15px 0;">🏗️ Architecture</h4> | |
| <ul style="color: #666; line-height: 1.6;"> | |
| <li><strong>Model:</strong> DistilBERT (Distilled BERT)</li> | |
| <li><strong>Parameters:</strong> 66 million</li> | |
| <li><strong>Training:</strong> Fine-tuned on SST-2</li> | |
| <li><strong>Accuracy:</strong> 74% on IMDB dataset</li> | |
| </ul> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 25px; border-radius: 12px; border-top: 4px solid #52b788;"> | |
| <h4 style="color: #2E86AB; margin: 0 0 15px 0;">⚡ Performance</h4> | |
| <ul style="color: #666; line-height: 1.6;"> | |
| <li><strong>Speed:</strong> ~100ms per prediction</li> | |
| <li><strong>Batch Processing:</strong> Supported</li> | |
| <li><strong>Memory:</strong> Optimized for production</li> | |
| <li><strong>Scalability:</strong> Cloud-ready</li> | |
| </ul> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 25px; border-radius: 12px; border-top: 4px solid #f72585;"> | |
| <h4 style="color: #2E86AB; margin: 0 0 15px 0;">🔧 Features</h4> | |
| <ul style="color: #666; line-height: 1.6;"> | |
| <li>Real-time sentiment classification</li> | |
| <li>Confidence scoring & probabilities</li> | |
| <li>RESTful API with async support</li> | |
| <li>Model interpretability tools</li> | |
| </ul> | |
| </div> | |
| <div style="background: #f8f9fa; padding: 25px; border-radius: 12px; border-top: 4px solid #f77f00;"> | |
| <h4 style="color: #2E86AB; margin: 0 0 15px 0;">🚀 Tech Stack</h4> | |
| <ul style="color: #666; line-height: 1.6;"> | |
| <li><strong>Framework:</strong> PyTorch + Transformers</li> | |
| <li><strong>API:</strong> FastAPI with async</li> | |
| <li><strong>Deployment:</strong> Docker + Cloud</li> | |
| <li><strong>Testing:</strong> Comprehensive suite</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div style="background: #e3f2fd; padding: 20px; border-radius: 10px; margin: 30px 0;"> | |
| <h4 style="color: #1976d2; margin: 0 0 15px 0;">🎯 Use Cases</h4> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;"> | |
| <div style="color: #666;">📱 Social media monitoring</div> | |
| <div style="color: #666;">📧 Customer feedback analysis</div> | |
| <div style="color: #666;">📊 Market research insights</div> | |
| <div style="color: #666;">🛒 Product review classification</div> | |
| </div> | |
| </div> | |
| <div style="text-align: center; padding: 20px; background: #f5f5f5; border-radius: 10px;"> | |
| <h4 style="color: #2E86AB; margin: 0 0 10px 0;">🔗 Open Source Project</h4> | |
| <p style="color: #666; margin: 0;">Complete source code, training scripts, and deployment guides available on GitHub</p> | |
| </div> | |
| """) | |
| # Event handlers | |
| single_btn.click( | |
| fn=analyze_sentiment, | |
| inputs=single_input, | |
| outputs=[single_output, confidence_score, probability_plot] | |
| ) | |
| batch_btn.click( | |
| fn=analyze_batch_texts, | |
| inputs=batch_input, | |
| outputs=[batch_output, batch_plot] | |
| ) | |
| # Footer with modern styling | |
| gr.Markdown(""" | |
| <div style="margin-top: 40px; padding: 30px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 15px; text-align: center;"> | |
| <h3 style="color: white; margin: 0 0 15px 0;">🚀 Advanced ML Engineering</h3> | |
| <p style="color: rgba(255,255,255,0.9); margin: 0 0 20px 0; font-size: 16px;"> | |
| This demo showcases production-ready machine learning engineering including model training, | |
| API development, comprehensive testing, and scalable deployment solutions. | |
| </p> | |
| <div style="display: flex; justify-content: center; gap: 20px; flex-wrap: wrap;"> | |
| <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; color: white;">PyTorch</span> | |
| <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; color: white;">Transformers</span> | |
| <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; color: white;">FastAPI</span> | |
| <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; color: white;">Docker</span> | |
| <span style="background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 20px; color: white;">Gradio</span> | |
| </div> | |
| </div> | |
| """) | |
| # Launch configuration | |
| if __name__ == "__main__": | |
| demo.launch( | |
| share=False, | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| show_error=True | |
| ) |