import gradio as gr from transformers import pipeline import time # ========================================== # MODEL CONFIGURATION # ========================================== MODEL_NAME = "ENTUM-AI/FinBERT-Multi" print(f"Loading model: {MODEL_NAME}...") try: classifier = pipeline("text-classification", model=MODEL_NAME, top_k=3) print("Model loaded successfully!") except Exception as e: print(f"Error loading model: {e}") classifier = None # ========================================== # PREDICTION LOGIC # ========================================== SENTIMENT_CONFIG = { "Positive": {"color": "#16a34a", "bg": "#f0fdf4", "icon": "📈", "bar": "#22c55e"}, "Negative": {"color": "#dc2626", "bg": "#fef2f2", "icon": "📉", "bar": "#ef4444"}, "Neutral": {"color": "#2563eb", "bg": "#eff6ff", "icon": "➖", "bar": "#3b82f6"}, } def predict_single(text): """Classify a single financial text.""" if not text or not text.strip(): return create_empty_result() if classifier is None: return create_error_result() start = time.time() results = classifier(text.strip())[0] elapsed = (time.time() - start) * 1000 top = results[0] return create_result_html(text.strip(), top["label"], results, elapsed) def predict_batch(texts): """Classify multiple financial texts (one per line).""" if not texts or not texts.strip(): return "

Enter financial texts, one per line.

" if classifier is None: return create_error_result() lines = [line.strip() for line in texts.strip().split("\n") if line.strip()] if not lines: return "

No valid texts found.

" start = time.time() all_results = classifier(lines) elapsed = (time.time() - start) * 1000 counts = {"Positive": 0, "Negative": 0, "Neutral": 0} html_parts = [] for text, results in zip(lines, all_results): top = results[0] label = top["label"] score = top["score"] counts[label] = counts.get(label, 0) + 1 cfg = SENTIMENT_CONFIG.get(label, SENTIMENT_CONFIG["Neutral"]) bar_width = int(score * 100) html_parts.append(f"""
{cfg['icon']} {text} {label.upper()} {score:.0%}
""") total = len(lines) summary = f"""
Batch Sentiment Analysis
📈 {counts.get('Positive', 0)}
Positive
➖ {counts.get('Neutral', 0)}
Neutral
📉 {counts.get('Negative', 0)}
Negative
{total} texts analyzed in {elapsed:.0f}ms
""" return summary + "\n".join(html_parts) # ========================================== # HTML RESULT BUILDERS # ========================================== def create_result_html(text, top_label, all_scores, elapsed_ms): cfg = SENTIMENT_CONFIG.get(top_label, SENTIMENT_CONFIG["Neutral"]) bars_html = "" for item in all_scores: lbl = item["label"] sc = item["score"] c = SENTIMENT_CONFIG.get(lbl, SENTIMENT_CONFIG["Neutral"]) pct = int(sc * 100) bars_html += f"""
{c['icon']} {lbl} {sc:.1%}
""" if top_label == "Positive": gradient = "linear-gradient(135deg, #dcfce7, #bbf7d0, #86efac)" text_color = "#166534" elif top_label == "Negative": gradient = "linear-gradient(135deg, #fee2e2, #fecaca, #fca5a5)" text_color = "#991b1b" else: gradient = "linear-gradient(135deg, #dbeafe, #bfdbfe, #93c5fd)" text_color = "#1e40af" top_score = all_scores[0]["score"] return f"""
{cfg['icon']}
{top_label.upper()} SENTIMENT
Confidence: {top_score:.1%}
Analyzed Text
"{text}"
Score Breakdown {bars_html}
Model
FinBERT-Multi
Latency
{elapsed_ms:.0f}ms
Training Data
143K+
""" def create_empty_result(): return """
💹
Awaiting Input
Enter a financial text above and click Analyze
""" def create_error_result(): return """
âš ī¸
Model Not Available
Please wait while the model loads or try refreshing.
""" # ========================================== # CUSTOM CSS # ========================================== CUSTOM_CSS = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'); * { font-family: 'Inter', 'Segoe UI', sans-serif !important; } .gradio-container { max-width: 960px !important; margin: 0 auto !important; background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 50%, #e2e8f0 100%) !important; } .main-header { text-align: center; padding: 40px 20px 20px; } .main-header h1 { background: linear-gradient(135deg, #059669, #0891b2, #2563eb); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 2.5rem !important; font-weight: 800 !important; margin-bottom: 8px !important; letter-spacing: -0.5px; } .main-header p { color: #64748b !important; font-size: 15px !important; } .model-badge { display: inline-block; background: linear-gradient(135deg, #ecfdf5, #e0f2fe); border: 1px solid #a7f3d0; color: #047857 !important; padding: 6px 16px; border-radius: 24px; font-size: 13px !important; font-weight: 600; letter-spacing: 0.5px; margin-top: 12px; } .data-badge { display: inline-block; background: linear-gradient(135deg, #fef3c7, #fde68a); border: 1px solid #fbbf24; color: #92400e !important; padding: 4px 12px; border-radius: 16px; font-size: 12px !important; font-weight: 600; margin-left: 8px; } footer { display: none !important; } .tab-nav button { color: #64748b !important; font-weight: 600 !important; font-size: 14px !important; } .tab-nav button.selected { color: #059669 !important; border-color: #059669 !important; } """ # ========================================== # GRADIO UI # ========================================== with gr.Blocks( css=CUSTOM_CSS, title="FinBERT-Multi — Financial Sentiment Analyzer", theme=gr.themes.Soft( primary_hue="emerald", secondary_hue="cyan", neutral_hue="slate", ), ) as demo: # Header gr.HTML("""

💹 FinBERT-Multi

Financial sentiment analysis powered by FinBERT, fine-tuned on 143K+ samples from 5 expert datasets

🧠 ENTUM-AI / FinBERT-Multi 📊 143K+ training samples
""") with gr.Tabs(): # --- Tab 1: Single Analysis --- with gr.Tab("🔍 Single Analysis"): with gr.Row(): with gr.Column(scale=3): single_input = gr.Textbox( label="Financial Text", placeholder="e.g. Stock price soars on record-breaking earnings report", lines=2, max_lines=4, ) single_btn = gr.Button("⚡ Analyze Sentiment", variant="primary", size="lg") with gr.Column(scale=4): single_output = gr.HTML(value=create_empty_result()) gr.Examples( examples=[ ["Stock price soars on record-breaking earnings report"], ["Revenue decline signals weakening market position"], ["Company announces quarterly earnings results"], ["Shares surge 15% after strong Q3 revenue growth"], ["Major layoffs expected as company restructures operations"], ["The board of directors met to discuss routine operations"], ["Bankruptcy filing raises concerns about long-term viability"], ["Profit margins improved significantly driven by cost optimization"], ], inputs=single_input, label="📋 Try these examples", ) single_btn.click(fn=predict_single, inputs=single_input, outputs=single_output) single_input.submit(fn=predict_single, inputs=single_input, outputs=single_output) # --- Tab 2: Batch Analysis --- with gr.Tab("📊 Batch Analysis"): gr.Markdown("Paste multiple financial texts — **one per line** — for batch sentiment classification.") with gr.Row(): with gr.Column(scale=2): batch_input = gr.Textbox( label="Financial Texts (one per line)", placeholder="Headline 1\nHeadline 2\nHeadline 3", lines=8, max_lines=20, ) batch_btn = gr.Button("⚡ Analyze All", variant="primary", size="lg") with gr.Column(scale=3): batch_output = gr.HTML( value="

Results will appear here.

" ) batch_btn.click(fn=predict_batch, inputs=batch_input, outputs=batch_output) # --- Tab 3: About --- with gr.Tab("â„šī¸ About"): gr.HTML("""

About FinBERT-Multi

A financial sentiment model built on ProsusAI/FinBERT. Fine-tuned on 143K+ samples from 5 combined financial datasets for maximum coverage and robustness.

Base Model ProsusAI/FinBERT (BERT-based)
Task 3-Class Sentiment (Positive / Negative / Neutral)
Training Data 143K+ samples from 5 datasets
Language English
License Apache 2.0

📊 Training Datasets

Dataset Samples
FinanceInc/auditor_sentiment~4.8K
nickmuchi/financial-classification~5K
warwickai/financial_phrasebank_mirror~4.8K
NOSIBLE/financial-sentiment~100K
TimKoornstra/financial-tweets-sentiment~38K

🐍 Python API

from transformers import pipeline

classifier = pipeline("text-classification",
                       model="ENTUM-AI/FinBERT-Multi")

result = classifier("Stock price soars on earnings")
# [{'label': 'Positive', 'score': 0.99}]
""") # Launch demo.launch()