| import gradio as gr |
| import pandas as pd |
| import numpy as np |
| import json |
| import pickle |
| import re |
|
|
| |
| def load_model_components(): |
| """Load all saved model components""" |
| try: |
| from tensorflow.keras.models import load_model |
| from tensorflow.keras.preprocessing.text import Tokenizer |
| from tensorflow.keras.preprocessing.sequence import pad_sequences |
| |
| model = load_model('best_emotion_model.h5') |
| |
| with open('tokenizer.pickle', 'rb') as handle: |
| tokenizer = pickle.load(handle) |
| |
| with open('label_encoder.pickle', 'rb') as handle: |
| label_encoder = pickle.load(handle) |
| |
| with open('model_config.json', 'r') as f: |
| config = json.load(f) |
| |
| return model, tokenizer, label_encoder, config |
| |
| except Exception as e: |
| raise ImportError(f"Error loading model components: {str(e)}") |
|
|
| |
| def clean_text(text, labels_to_remove=[]): |
| """Clean and normalize text""" |
| if pd.isna(text) or not isinstance(text, str): |
| return "" |
| |
| text = str(text) |
| text = text.lower() |
|
|
| |
| text = re.sub(r'http\S+|www\S+|https\S+', '', text, flags=re.MULTILINE) |
|
|
| |
| text = re.sub(r'[^a-zA-Z\s.,!?;:]', ' ', text) |
|
|
| |
| if labels_to_remove: |
| for label in labels_to_remove: |
| pattern = r'\b' + re.escape(label.lower()) + r'\b' |
| text = re.sub(pattern, ' ', text, flags=re.IGNORECASE) |
|
|
| |
| text = re.sub(r'\s+', ' ', text).strip() |
|
|
| return text |
|
|
| |
| def predict_emotion(text, top_k=5): |
| """Predict emotion from text with top-k confidence scores""" |
| try: |
| model, tokenizer, label_encoder, config = load_model_components() |
| MAX_LEN = config['MAX_LEN'] |
| |
| |
| EMOTION_LABELS = list(label_encoder.classes_) |
| cleaned = clean_text(text, labels_to_remove=EMOTION_LABELS) |
| |
| if not cleaned: |
| return [("No valid text", 0.0)] |
| |
| |
| sequence = tokenizer.texts_to_sequences([cleaned]) |
| padded = pad_sequences(sequence, maxlen=MAX_LEN, padding='post', truncating='post') |
| |
| |
| prediction = model.predict(padded, verbose=0)[0] |
| |
| |
| top_indices = np.argsort(prediction)[-top_k:][::-1] |
| |
| results = [] |
| for idx in top_indices: |
| emotion = label_encoder.classes_[idx] |
| confidence = prediction[idx] * 100 |
| results.append((emotion, confidence)) |
| |
| return results |
| |
| except Exception as e: |
| return [("Error", 0.0)] |
|
|
| |
| def emotion_classifier(text, top_k): |
| """Main function for Gradio interface""" |
| if not text or not text.strip(): |
| return "β Please enter some text to analyze emotions." |
| |
| try: |
| predictions = predict_emotion(text, int(top_k)) |
| |
| if not predictions or len(predictions) == 0: |
| return "β No predictions generated. Please try different text." |
| |
| |
| result_text = f"**Emotion Predictions for:** {text}\n\n" |
| result_text += "| Emotion | Confidence (%) |\n" |
| result_text += "|---------|----------------|\n" |
| |
| for emotion, confidence in predictions: |
| if confidence > 0: |
| result_text += f"| {emotion} | {confidence:.2f} |\n" |
| else: |
| result_text += f"| {emotion} | Not available |\n" |
| |
| return result_text |
| |
| except Exception as e: |
| return f"β Error during analysis: {str(e)}" |
|
|
| |
| with gr.Blocks(title="Emotion Classification App", theme=gr.themes.Soft()) as demo: |
| gr.Markdown(""" |
| # π§ Emotion Classification from Text |
| This application uses a bidirectional LSTM model to classify emotions from text input. |
| The model was trained on 287,000 AI-generated question-answer pairs covering 75 different emotions. |
| """) |
| |
| with gr.Row(): |
| with gr.Column(): |
| input_text = gr.Textbox( |
| label="Enter Text for Emotion Analysis", |
| placeholder="Type your text here (e.g., 'I feel so happy about my achievements!')", |
| lines=5, |
| value="I made the mistake, but I'm determined to fix it immediately and ensure it never happens again" |
| ) |
| |
| top_k_slider = gr.Slider( |
| minimum=3, |
| maximum=10, |
| value=5, |
| step=1, |
| label="Number of Emotions to Show" |
| ) |
| |
| submit_btn = gr.Button("π Analyze Emotions", variant="primary") |
| |
| |
| gr.Markdown("### Example Texts:") |
| examples = gr.Examples( |
| examples=[ |
| ["I made the mistake, but I'm determined to fix it immediately and ensure it never happens again"], |
| ["I heard that rumor about my colleague, and honestly, I feel a rush of competitive schadenfreude."], |
| ["The beauty of the mountain view left me speechless; I felt incredibly small and insignificant."], |
| ["I'm just exhausted and drained. I don't feel anything anymore, not even stress."], |
| ["Seeing my childhood home again brought back a wave of deep melancholy and sweet sadness."] |
| ], |
| inputs=[input_text], |
| label="Try these examples" |
| ) |
| |
| with gr.Column(): |
| output = gr.Markdown( |
| label="Emotion Predictions", |
| value="Enter text and click 'Analyze Emotions' to see predictions." |
| ) |
| |
| submit_btn.click( |
| fn=emotion_classifier, |
| inputs=[input_text, top_k_slider], |
| outputs=output |
| ) |
| |
| |
| with gr.Accordion("Model Information", open=False): |
| gr.Markdown(""" |
| ### Model Architecture |
| - **Embedding Layer**: Pre-trained Word2Vec embeddings (128 dimensions) |
| - **Bidirectional LSTM**: Two layers (128 and 64 units) for sequence processing |
| - **Dense Layers**: 256 and 128 units with dropout for regularization |
| - **Output Layer**: 75 neurons (one per emotion) with softmax activation |
| |
| ### Training Details |
| - **Dataset**: 287,280 AI-generated question-answer pairs |
| - **Emotions**: 75 different emotion categories |
| - **Validation Accuracy**: 87.62% |
| - **Test Accuracy**: 87.84% |
| |
| ### Features |
| - Real-time emotion classification |
| - Confidence scoring for predictions |
| - Support for complex emotional contexts |
| - Robust text preprocessing pipeline |
| """) |
|
|
| |
| if __name__ == "__main__": |
| demo.launch() |