logasanjeev commited on
Commit
0901236
·
verified ·
1 Parent(s): 8272578

Add Gradio app

Browse files
Files changed (1) hide show
  1. app.py +190 -0
app.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import gradio as gr
3
+ import tensorflow as tf
4
+ from tensorflow.keras.models import load_model
5
+ from tensorflow.keras.preprocessing.sequence import pad_sequences
6
+ import numpy as np
7
+ import json
8
+ import pickle
9
+ import nltk
10
+ from nltk.tokenize import word_tokenize
11
+ from nltk.stem import WordNetLemmatizer
12
+ import re
13
+ import string
14
+ from huggingface_hub import hf_hub_download
15
+
16
+ # Download NLTK resources
17
+ nltk.download('punkt', quiet=True)
18
+ nltk.download('wordnet', quiet=True)
19
+ nltk.download('omw-1.4', quiet=True)
20
+
21
+ # Initialize lemmatizer
22
+ lemmatizer = WordNetLemmatizer()
23
+
24
+ # Define LuongAttention (placeholder for loading)
25
+ class LuongAttention(tf.keras.layers.Layer):
26
+ def __init__(self, **kwargs):
27
+ super(LuongAttention, self).__init__(**kwargs)
28
+
29
+ def build(self, input_shape):
30
+ self.W = self.add_weight(
31
+ name='attention_weight',
32
+ shape=(input_shape[-1], input_shape[-1]),
33
+ initializer='glorot_uniform',
34
+ trainable=True
35
+ )
36
+ self.b = self.add_weight(
37
+ name='attention_bias',
38
+ shape=(input_shape[-1],),
39
+ initializer='zeros',
40
+ trainable=True
41
+ )
42
+ super(LuongAttention, self).build(input_shape)
43
+
44
+ def call(self, inputs):
45
+ lstm_output = inputs
46
+ score = tf.matmul(lstm_output, self.W) + self.b
47
+ score = tf.tanh(score)
48
+ attention_weights = tf.nn.softmax(score, axis=1)
49
+ context = lstm_output * attention_weights
50
+ context = tf.reduce_sum(context, axis=1)
51
+ return context, attention_weights
52
+
53
+ def get_config(self):
54
+ config = super(LuongAttention, self).get_config()
55
+ return config
56
+
57
+ # Load model, tokenizer, label encoder from Hugging Face Hub
58
+ model_path = hf_hub_download(repo_id="logasanjeev/sentiment-analysis-bilstm-luong", filename="sentiment_model.h5")
59
+ tokenizer_path = hf_hub_download(repo_id="logasanjeev/sentiment-analysis-bilstm-luong", filename="tokenizer.json")
60
+ encoder_path = hf_hub_download(repo_id="logasanjeev/sentiment-analysis-bilstm-luong", filename="label_encoder.pkl")
61
+ model = load_model(model_path, custom_objects={"LuongAttention": LuongAttention})
62
+ with open(tokenizer_path, "r") as f:
63
+ tokenizer = tf.keras.preprocessing.text.tokenizer_from_json(json.load(f))
64
+ with open(encoder_path, "rb") as f:
65
+ label_encoder = pickle.load(f)
66
+
67
+ # Text cleaning function
68
+ def clean_text(text):
69
+ if not isinstance(text, str):
70
+ text = str(text)
71
+ text = text.lower()
72
+ text = re.sub(r'http\S+|www\S+|https\S+', '', text, flags=re.MULTILINE)
73
+ text = re.sub(r'@\w+|\#\w+', '', text)
74
+ text = text.translate(str.maketrans('', '', string.punctuation))
75
+ text = re.sub(r'\d+', '', text)
76
+ tokens = word_tokenize(text)
77
+ tokens = [lemmatizer.lemmatize(token) for token in tokens]
78
+ return ' '.join(tokens).strip()
79
+
80
+ # Prediction function
81
+ def predict_sentiment(text):
82
+ if not text or not isinstance(text, str) or len(text.strip()) < 3:
83
+ return "Please enter a valid sentence.", None, None
84
+
85
+ # Clean and preprocess
86
+ cleaned = clean_text(text)
87
+ seq = tokenizer.texts_to_sequences([cleaned])
88
+ if not seq or not any(x > 1 for x in seq[0]):
89
+ return "Text too short or invalid.", None, None
90
+
91
+ # Pad sequence
92
+ max_len = 35
93
+ pad = pad_sequences(seq, maxlen=max_len, padding='post', truncating='post')
94
+
95
+ # Predict
96
+ with tf.device('/CPU:0'):
97
+ pred = model.predict(pad, verbose=0)[0]
98
+ sentiment = label_encoder.inverse_transform([np.argmax(pred)])[0]
99
+ probs = pred.tolist()
100
+
101
+ # Format output
102
+ emoji = {"negative": "😣", "neutral": "😐", "positive": "😊"}
103
+ probs_dict = {
104
+ "Negative": probs[0],
105
+ "Neutral": probs[1],
106
+ "Positive": probs[2]
107
+ }
108
+
109
+ return (
110
+ f"**Sentiment**: {sentiment.capitalize()} {emoji[sentiment]}",
111
+ probs_dict,
112
+ cleaned
113
+ )
114
+
115
+ # Custom CSS for slick UI
116
+ css = """
117
+ body { font-family: 'Arial', sans-serif; }
118
+ .gradio-container { max-width: 800px; margin: auto; }
119
+ h1 { color: #1a73e8; text-align: center; }
120
+ .textbox { border-radius: 8px; }
121
+ .output-text { font-size: 1.2em; font-weight: bold; }
122
+ .footer { text-align: center; color: #666; }
123
+ .prob-bar { margin-top: 10px; }
124
+ button { border-radius: 6px; }
125
+ .dark { background: #1e1e1e; color: #ffffff; }
126
+ .dark h1 { color: #4a90e2; }
127
+ .dark .footer { color: #aaa; }
128
+ """
129
+
130
+ # Gradio interface
131
+ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
132
+ gr.Markdown(
133
+ """
134
+ # Sentiment Analysis App
135
+ Predict the sentiment of your text (negative, neutral, positive) using a Bi-LSTM model with Luong attention. Try it out!
136
+ """
137
+ )
138
+
139
+ with gr.Row():
140
+ with gr.Column(scale=3):
141
+ text_input = gr.Textbox(
142
+ label="Your Text",
143
+ placeholder="e.g., The food service is not good at all",
144
+ lines=2
145
+ )
146
+ predict_btn = gr.Button("Analyze Sentiment", variant="primary")
147
+ with gr.Column(scale=1):
148
+ theme_toggle = gr.Button("Toggle Theme")
149
+
150
+ output_text = gr.Markdown()
151
+ prob_plot = gr.Label(label="Probability Distribution")
152
+ cleaned_text = gr.Textbox(label="Cleaned Text", interactive=False)
153
+
154
+ examples = gr.Examples(
155
+ examples=[
156
+ "the food service is not good at all",
157
+ "this is not recommended at all",
158
+ "This place sucks!",
159
+ "I’m so happy with this!",
160
+ "It’s alright, I guess."
161
+ ],
162
+ inputs=text_input
163
+ )
164
+
165
+ # Theme toggle logic
166
+ def toggle_theme():
167
+ return gr.themes.Dark() if demo.theme.name == "soft" else gr.themes.Soft()
168
+
169
+ # Bind functions
170
+ predict_btn.click(
171
+ fn=predict_sentiment,
172
+ inputs=text_input,
173
+ outputs=[output_text, prob_plot, cleaned_text]
174
+ )
175
+ theme_toggle.click(
176
+ fn=toggle_theme,
177
+ outputs=None,
178
+ _js="() => { document.body.classList.toggle('dark'); }"
179
+ )
180
+
181
+ gr.Markdown(
182
+ """
183
+ <div class='footer'>
184
+ Created by logasanjeev | Powered by Hugging Face & Gradio
185
+ </div>
186
+ """
187
+ )
188
+
189
+ # Launch app
190
+ demo.launch()