import os import gradio as gr from transformers import pipeline # 1. Thread Optimization & GPU/CPU Configuration # Force PyTorch to use 1 thread for CPU inference to avoid excessive context switching in constrained envs import torch torch.set_num_threads(1) # Global lazy-loaded pipelines to minimize startup latency _sentiment_pipeline = None _zero_shot_pipeline = None def get_sentiment_pipeline(): global _sentiment_pipeline if _sentiment_pipeline is None: # Using distilbert-base-uncased-finetuned-sst-2-english # Extremely fast, highly accurate (~92% on SST-2), and highly efficient for production CPUs _sentiment_pipeline = pipeline( "sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english", revision="714eb0f" ) return _sentiment_pipeline def get_zero_shot_pipeline(): global _zero_shot_pipeline if _zero_shot_pipeline is None: # Using typeform/distilbert-base-uncased-mnli # Extremely lightweight (~268MB), offering BART-like zero-shot capability at a fraction of the memory footprint _zero_shot_pipeline = pipeline( "zero-shot-classification", model="typeform/distilbert-base-uncased-mnli" ) return _zero_shot_pipeline # 2. Main Logic Handlers def analyze_sentiment(text): if not text or not text.strip(): return {"Error": 1.0}, "Please enter valid text." try: classifier = get_sentiment_pipeline() results = classifier(text) # Format the output beautifully for Gradio's gr.Label # e.g., {"POSITIVE": 0.999, "NEGATIVE": 0.001} label = results[0]['label'] score = results[0]['score'] other_label = "NEGATIVE" if label == "POSITIVE" else "POSITIVE" output_data = { label: score, other_label: 1.0 - score } emoji = "✨" if label == "POSITIVE" else "⚠️" explanation = f"The model is **{score:.2%}** confident that this text has a **{label.lower()}** sentiment {emoji}." return output_data, explanation except Exception as e: return {"Error": 1.0}, f"Inference Error: {str(e)}" def classify_zero_shot(text, candidate_labels): if not text or not text.strip(): return {"Error": 1.0}, "Please enter valid text." if not candidate_labels or not candidate_labels.strip(): return {"Error": 1.0}, "Please enter at least one candidate label." try: # Clean and split the candidate labels labels_list = [label.strip() for label in candidate_labels.split(",") if label.strip()] if len(labels_list) == 0: return {"Error": 1.0}, "Please provide valid comma-separated labels." classifier = get_zero_shot_pipeline() results = classifier(text, candidate_labels=labels_list) # Gradio Label component expects a dict of {label_name: float_probability} output_data = {label: score for label, score in zip(results['labels'], results['scores'])} top_label = results['labels'][0] top_score = results['scores'][0] explanation = f"**Top Match**: classified as **'{top_label}'** with **{top_score:.1%}** confidence." return output_data, explanation except Exception as e: return {"Error": 1.0}, f"Inference Error: {str(e)}" # 3. Custom Theming & Premium Visual Layout # Sleek, enterprise-grade Slate and Sapphire design with clean edges theme = gr.themes.Soft( primary_hue="indigo", secondary_hue="blue", neutral_hue="slate", font=[gr.themes.GoogleFont("Inter"), "Helvetica Neue", "Arial", "sans-serif"] ).set( body_background_fill="*neutral_50", body_background_fill_dark="*neutral_950", button_primary_background_fill="linear-gradient(135deg, #4f46e5 0%, #3b82f6 100%)", button_primary_background_fill_hover="linear-gradient(135deg, #4338ca 0%, #2563eb 100%)", button_primary_text_color="white", block_title_text_weight="600", block_border_width="1px", block_shadow="rgba(0, 0, 0, 0.05) 0px 4px 12px" ) # Custom CSS for glassmorphism headers and beautiful margins custom_css = """ .header-container { background: linear-gradient(135deg, #1e1b4b 0%, #0f172a 100%); padding: 2.5rem; border-radius: 12px; margin-bottom: 2rem; color: white; box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15), 0 8px 10px -6px rgba(0, 0, 0, 0.15); } .header-title { font-size: 2.5rem; font-weight: 800; letter-spacing: -0.025em; margin: 0; background: linear-gradient(to right, #a5b4fc, #818cf8, #60a5fa); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .header-subtitle { font-size: 1.1rem; opacity: 0.85; margin-top: 0.5rem; } .footer-text { text-align: center; font-size: 0.85rem; color: #64748b; margin-top: 3rem; } """ with gr.Blocks(title="NexusCorp AI Suite") as demo: # 4. Premium Header Section gr.HTML( """

NexusCorp NLP Engine

State-of-the-art NLP classification models optimized for instant pipeline inference

""" ) with gr.Tabs(): # Tab 1: Sentiment Analysis with gr.Tab("Sentiment Intelligence"): gr.Markdown( """ ### 🎭 Real-Time Sentiment & Polarity Analysis Detect emotional valence (Positive or Negative) in conversational copy, client feedback, or support tickets. """ ) with gr.Row(): with gr.Column(scale=5): sentiment_input = gr.Textbox( label="Analyze Copy", placeholder="Type or paste your text here (e.g., 'The new service launch was absolutely stellar, we got incredible feedback!')...", lines=5, max_lines=12 ) # Examples for users to interact with immediately gr.Examples( examples=[ ["The new update is absolute perfection! Visual design looks stunning and responsiveness is stellar."], ["I'm extremely disappointed with the delayed shipment, and the customer support was non-responsive."], ["The product works fine, although it has a few minor bugs that need to be patched in the next release."] ], inputs=sentiment_input, label="Pre-loaded Enterprise Scenarios" ) sentiment_btn = gr.Button("Execute Analysis", variant="primary") with gr.Column(scale=4): sentiment_label = gr.Label( label="Sentiment Distribution", num_top_classes=2 ) sentiment_explanation = gr.Markdown("*Awaiting analysis request...*") sentiment_btn.click( fn=analyze_sentiment, inputs=sentiment_input, outputs=[sentiment_label, sentiment_explanation] ) # Tab 2: Zero-Shot Classification with gr.Tab("Zero-Shot Classification"): gr.Markdown( """ ### 🏷️ Zero-Shot Dynamic Categorizer Classify any piece of copy into **custom labels** on the fly without any model re-training. """ ) with gr.Row(): with gr.Column(scale=5): zero_shot_text = gr.Textbox( label="Input Text", placeholder="Type text to classify here...", lines=4 ) zero_shot_labels = gr.Textbox( label="Candidate Labels (Comma-Separated)", placeholder="e.g. Finance, Technology, Health, Sports, Customer Support", value="Finance, Technology, Support, Marketing" ) gr.Examples( examples=[ [ "We need to schedule a software patch rollout tonight to resolve the high CPU consumption on the database server.", "Technology, Infrastructure, Finance, Urgent Operations" ], [ "Our marketing campaign saw a 25% lift in click-through rates after changing the call-to-action button color.", "Creative Design, Marketing Metrics, Legal, Engineering" ], [ "Can I get a refund for my order? The invoice was generated with double the tax rate.", "Billing Support, Bug Report, Sales Inquiries, Careers" ] ], inputs=[zero_shot_text, zero_shot_labels], label="Zero-Shot Use Cases" ) zero_shot_btn = gr.Button("Categorize Copy", variant="primary") with gr.Column(scale=4): zero_shot_label = gr.Label( label="Probability Distribution" ) zero_shot_explanation = gr.Markdown("*Awaiting categorization request...*") zero_shot_btn.click( fn=classify_zero_shot, inputs=[zero_shot_text, zero_shot_labels], outputs=[zero_shot_label, zero_shot_explanation] ) # Premium footer info gr.HTML( """ """ ) # 5. Local Running and Deployment Configuration if __name__ == "__main__": # Get port from environment variable (required for Hugging Face Spaces and other cloud runtimes) port = int(os.environ.get("PORT", 7860)) # Launch Gradio interface. # server_name="0.0.0.0" is critical for Docker/cloud environments to allow external requests demo.queue().launch( server_name="0.0.0.0", server_port=port, share=False, theme=theme, css=custom_css )