fin-sent-v1 / app.py
kidwaiaun's picture
Update app.py
c18e9a0 verified
# Import necessary libraries
import gradio as gr
from datasets import load_dataset, Dataset # Explicitly import Dataset class
import pandas as pd
import numpy as np
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
import torch
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
import os
import shutil
# Load dataset once at startup
ds = load_dataset("ashraq/financial-news-articles")
df = pd.DataFrame(ds['train'])
# Simulate labels (replace with real labels in practice)
np.random.seed(42)
df['label'] = np.random.randint(0, 3, size=len(df)) # 0=neg, 1=neu, 2=pos
df['input_text'] = df['title'] + " " + df['text']
# Global variables for model and tokenizer
model = None
tokenizer = None
sentiment_map = {0: "Negative", 1: "Neutral", 2: "Positive"}
# Function to tokenize dataset
def tokenize_function(examples, tokenizer):
return tokenizer(examples['input_text'], padding="max_length", truncation=True, max_length=512)
# Function to compute metrics
def compute_metrics(pred):
labels = pred.label_ids
preds = np.argmax(pred.predictions, axis=1)
precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='weighted')
acc = accuracy_score(labels, preds)
return {'accuracy': acc, 'f1': f1, 'precision': precision, 'recall': recall}
# Train the model with user-defined parameters
def train_model(learning_rate, epochs, batch_size, save_path):
global model, tokenizer
# Split dataset
train_df, test_df = train_test_split(df, test_size=0.2, random_state=42)
# Load tokenizer and model
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=3)
# Prepare datasets
train_dataset = Dataset.from_pandas(train_df[['input_text', 'label']])
test_dataset = Dataset.from_pandas(test_df[['input_text', 'label']])
train_dataset = train_dataset.map(lambda x: tokenize_function(x, tokenizer), batched=True)
test_dataset = test_dataset.map(lambda x: tokenize_function(x, tokenizer), batched=True)
train_dataset.set_format('torch', columns=['input_ids', 'attention_mask', 'label'])
test_dataset.set_format('torch', columns=['input_ids', 'attention_mask', 'label'])
# Training arguments
training_args = TrainingArguments(
output_dir="./temp_model",
evaluation_strategy="epoch",
learning_rate=learning_rate,
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
num_train_epochs=epochs,
weight_decay=0.01,
logging_dir='./logs',
logging_steps=10,
save_strategy="epoch",
load_best_model_at_end=True,
)
# Initialize trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=test_dataset,
compute_metrics=compute_metrics,
)
# Train and evaluate
trainer.train()
eval_results = trainer.evaluate()
# Save the model if path provided
if save_path:
trainer.save_model(save_path)
tokenizer.save_pretrained(save_path)
output = f"Model saved to {save_path}\nEvaluation results: {eval_results}"
else:
output = f"Model trained but not saved.\nEvaluation results: {eval_results}"
# Clean up temp directory
if os.path.exists("./temp_model"):
shutil.rmtree("./temp_model")
if os.path.exists("./logs"):
shutil.rmtree("./logs")
return output
# Load a pre-trained model for inference
def load_model(model_path):
global model, tokenizer
if not os.path.exists(model_path):
return "Error: Model path does not exist."
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForSequenceClassification.from_pretrained(model_path)
return "Model loaded successfully from " + model_path
# Predict sentiment for new input
def predict_sentiment(title, text):
global model, tokenizer
if model is None or tokenizer is None:
return "Error: Please train or load a model first."
input_text = title + " " + text
inputs = tokenizer(input_text, return_tensors="pt", padding=True, truncation=True, max_length=512)
with torch.no_grad():
outputs = model(**inputs)
pred_label = np.argmax(outputs.logits.numpy(), axis=1)[0]
return f"Predicted Sentiment: {sentiment_map[pred_label]}"
# Gradio interface
with gr.Blocks(title="Financial News Sentiment Analyzer") as demo:
gr.Markdown("# Financial News Sentiment Analyzer")
gr.Markdown("Train a sentiment model on financial news articles, save it, and predict sentiments.")
with gr.Tab("Train Model"):
gr.Markdown("### Train a New Sentiment Model")
learning_rate = gr.Slider(1e-5, 5e-5, value=2e-5, label="Learning Rate")
epochs = gr.Slider(1, 5, value=3, step=1, label="Number of Epochs")
batch_size = gr.Slider(4, 16, value=8, step=4, label="Batch Size")
save_path = gr.Textbox(label="Save Model Path (optional)", placeholder="e.g., ./my_sentiment_model")
train_button = gr.Button("Train Model")
output = gr.Textbox(label="Training Output")
train_button.click(
fn=train_model,
inputs=[learning_rate, epochs, batch_size, save_path],
outputs=output
)
with gr.Tab("Load Model"):
gr.Markdown("### Load an Existing Model")
model_path = gr.Textbox(label="Model Path", placeholder="e.g., ./my_sentiment_model")
load_button = gr.Button("Load Model")
load_output = gr.Textbox(label="Load Status")
load_button.click(
fn=load_model,
inputs=model_path,
outputs=load_output
)
with gr.Tab("Predict Sentiment"):
gr.Markdown("### Predict Sentiment for New Input")
title_input = gr.Textbox(label="Article Title")
text_input = gr.Textbox(label="Article Text", lines=5)
predict_button = gr.Button("Predict")
pred_output = gr.Textbox(label="Prediction")
predict_button.click(
fn=predict_sentiment,
inputs=[title_input, text_input],
outputs=pred_output
)
# Launch the app
demo.launch()