|
|
|
|
|
import os |
|
|
import sys |
|
|
import io |
|
|
os.environ['CUDA_VISIBLE_DEVICES'] = '-1' |
|
|
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' |
|
|
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' |
|
|
os.environ['GRADIO_HOT_RELOAD'] = 'false' |
|
|
os.environ['WRAPT_DISABLE_EXTENSIONS'] = 'true' |
|
|
os.environ['PYTHONWARNINGS'] = 'ignore' |
|
|
|
|
|
import re |
|
|
import nltk |
|
|
import pickle |
|
|
import string |
|
|
import warnings |
|
|
import numpy as np |
|
|
import gradio as gr |
|
|
from keras.models import load_model |
|
|
from keras.preprocessing.sequence import pad_sequences |
|
|
|
|
|
|
|
|
warnings.filterwarnings('ignore') |
|
|
warnings.simplefilter('ignore') |
|
|
|
|
|
|
|
|
MAX_LEN = 100 |
|
|
MODEL_PATH = "sentiment_analysis_best.keras" |
|
|
TOKENIZER_PATH = "tokenizer.pkl" |
|
|
|
|
|
nltk.download('stopwords', quiet=True) |
|
|
|
|
|
|
|
|
def expand_contractions(text): |
|
|
contractions = { |
|
|
"i'm": "i am", "you're": "you are", "he's": "he is", |
|
|
"she's": "she is", "it's": "it is", "we're": "we are", |
|
|
"they're": "they are", "i've": "i have", "you've": "you have", |
|
|
"we've": "we have", "they've": "they have", "i'll": "i will", |
|
|
"you'll": "you will", "he'll": "he will", "she'll": "she will", |
|
|
"we'll": "we will", "they'll": "they will", "i'd": "i would", |
|
|
"you'd": "you would", "he'd": "he would", "she'd": "she would", |
|
|
"we'd": "we would", "they'd": "they would", "don't": "do not", |
|
|
"doesn't": "does not", "didn't": "did not", "can't": "cannot", |
|
|
"couldn't": "could not", "won't": "will not", "wouldn't": "would not", |
|
|
"shouldn't": "should not", "isn't": "is not", "aren't": "are not", |
|
|
"wasn't": "was not", "weren't": "were not", "hasn't": "has not", |
|
|
"haven't": "have not", "hadn't": "had not", "mightn't": "might not", |
|
|
"mustn't": "must not", "needn't": "need not", "shan't": "shall not" |
|
|
} |
|
|
for contraction, expansion in contractions.items(): |
|
|
text = re.sub(r'\b' + contraction + r'\b', expansion, text, flags=re.IGNORECASE) |
|
|
return text |
|
|
|
|
|
|
|
|
def preprocess(text): |
|
|
negations = {"not", "no", "nor", "never", "n't", "nobody", "nothing", "neither", "nowhere", "none"} |
|
|
important_words = {"am", "is", "are", "was", "were", "be", "been", "being"} |
|
|
|
|
|
try: |
|
|
from nltk.corpus import stopwords |
|
|
stop_words = set(stopwords.words("english")) - negations - important_words |
|
|
except: |
|
|
stop_words = set() |
|
|
|
|
|
text = text.lower() |
|
|
text = expand_contractions(text) |
|
|
text = re.sub(r"\d+", "", text) |
|
|
text = text.translate(str.maketrans('', '', string.punctuation)) |
|
|
words = [w for w in text.split() if w not in stop_words or w in negations or w in important_words] |
|
|
|
|
|
return " ".join(words) |
|
|
|
|
|
|
|
|
def load_resources(): |
|
|
try: |
|
|
model = load_model(MODEL_PATH) |
|
|
print(f"β Model loaded successfully from {MODEL_PATH}") |
|
|
|
|
|
with open(TOKENIZER_PATH, "rb") as f: |
|
|
tokenizer = pickle.load(f) |
|
|
print(f"β Tokenizer loaded successfully from {TOKENIZER_PATH}") |
|
|
|
|
|
return model, tokenizer |
|
|
except FileNotFoundError as e: |
|
|
print(f"β Error: Model or Tokenizer file not found!") |
|
|
print(f" Make sure {MODEL_PATH} AND {TOKENIZER_PATH} are in the same directory.") |
|
|
raise e |
|
|
except Exception as e: |
|
|
print(f"β Error loading resources: {e}") |
|
|
raise e |
|
|
|
|
|
|
|
|
model, tokenizer = load_resources() |
|
|
|
|
|
|
|
|
def predict_sentiment(text): |
|
|
if not text or not text.strip(): |
|
|
return "β οΈ Neutral", "33.33%", "Please enter some text to analyze!" |
|
|
|
|
|
processed_text = preprocess(text) |
|
|
|
|
|
if not processed_text.strip(): |
|
|
return "β οΈ Neutral", "33.33%", "Text is empty after preprocessing. Try adding more words." |
|
|
|
|
|
seq = tokenizer.texts_to_sequences([processed_text]) |
|
|
padded = pad_sequences(seq, maxlen=MAX_LEN, padding='post') |
|
|
|
|
|
pred = model.predict(padded, verbose=0) |
|
|
label_idx = np.argmax(pred, axis=1)[0] |
|
|
confidence = pred[0][label_idx] |
|
|
|
|
|
labels = ["π Negative", "π Positive", "π Neutral"] |
|
|
sentiment = labels[label_idx] |
|
|
confidence_percentage = f"{confidence * 100:.2f}%" |
|
|
|
|
|
detailed_results = f""" |
|
|
### π Detailed Analysis: |
|
|
|
|
|
**Original Text:** {text} |
|
|
|
|
|
**Processed Text:** {processed_text} |
|
|
|
|
|
**Prediction Probabilities:** |
|
|
- π Negative: {pred[0][0] * 100:.2f}% |
|
|
- π Positive: {pred[0][1] * 100:.2f}% |
|
|
- π Neutral: {pred[0][2] * 100:.2f}% |
|
|
|
|
|
**Final Sentiment:** {sentiment} |
|
|
**Confidence:** {confidence_percentage} |
|
|
""" |
|
|
return sentiment, confidence_percentage, detailed_results |
|
|
|
|
|
|
|
|
def create_gradio_interface(): |
|
|
"""Create and configure Gradio interface""" |
|
|
|
|
|
examples = [ |
|
|
["I'm so happy with my purchase! Highly recommended!"], |
|
|
["I don't like this at all. Very disappointing."], |
|
|
["I absolutely love this product! It's amazing!"], |
|
|
["This is the worst experience I've ever had."], |
|
|
["Fantastic! Best decision I ever made!"], |
|
|
["I'm not sure how I feel about this."], |
|
|
["It's okay, nothing special really."], |
|
|
["Amazing work! Best I've ever seen!"], |
|
|
["This is the worst experience ever"], |
|
|
["This is terrible and I hate it"], |
|
|
["It works fine, no complaints."], |
|
|
["Not bad, but could be better."], |
|
|
["He is no good boy"], |
|
|
["I'm doing great"], |
|
|
["I'm not normal"], |
|
|
["Both of you"], |
|
|
["I am fine"], |
|
|
["I am good"], |
|
|
["I'm okay"] |
|
|
] |
|
|
|
|
|
with gr.Blocks(title="Sentiment Analysis") as interface: |
|
|
gr.Markdown(""" |
|
|
# π Sentiment Analysis - AI Powered |
|
|
### Analyze the sentiment of your text using Deep Learning (LSTM Model) |
|
|
|
|
|
**Instructions:** Enter any text in English and the model will predict whether it's Positive, Negative, or Neutral. |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
text_input = gr.Textbox( |
|
|
label="π Enter Your Text", |
|
|
placeholder="Type your text here... (e.g., 'I love this product!')", |
|
|
lines=5, |
|
|
max_lines=10 |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
analyze_btn = gr.Button("π Analyze Sentiment", variant="primary", size="lg") |
|
|
clear_btn = gr.ClearButton([text_input], value="ποΈ Clear", size="lg") |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
sentiment_output = gr.Textbox( |
|
|
label="π― Predicted Sentiment", |
|
|
interactive=False |
|
|
) |
|
|
confidence_output = gr.Textbox( |
|
|
label="π Confidence Score", |
|
|
interactive=False |
|
|
) |
|
|
|
|
|
detailed_output = gr.Markdown( |
|
|
label="π Detailed Analysis", |
|
|
value="Results will appear here after analysis..." |
|
|
) |
|
|
|
|
|
gr.Markdown("### π‘ Try These Examples:") |
|
|
gr.Examples( |
|
|
examples=examples, |
|
|
inputs=text_input, |
|
|
outputs=[sentiment_output, confidence_output, detailed_output], |
|
|
fn=predict_sentiment, |
|
|
cache_examples=False |
|
|
) |
|
|
|
|
|
gr.Markdown(""" |
|
|
--- |
|
|
**Model Information:** |
|
|
- Architecture: Bidirectional LSTM with Embedding Layer |
|
|
- Classes: Negative (0), Positive (1), Neutral (2) |
|
|
- Max Sequence Length: 100 tokens |
|
|
|
|
|
**Tips for Best Results:** |
|
|
- Use clear, complete sentences |
|
|
- The model works best with English text |
|
|
- Longer texts provide more context for accurate predictions |
|
|
""") |
|
|
|
|
|
analyze_btn.click( |
|
|
fn=predict_sentiment, |
|
|
inputs=text_input, |
|
|
outputs=[sentiment_output, confidence_output, detailed_output] |
|
|
) |
|
|
|
|
|
text_input.submit( |
|
|
fn=predict_sentiment, |
|
|
inputs=text_input, |
|
|
outputs=[sentiment_output, confidence_output, detailed_output] |
|
|
) |
|
|
|
|
|
return interface |
|
|
|
|
|
|
|
|
class SuppressStderr: |
|
|
def __enter__(self): |
|
|
self.original_stderr = sys.stderr |
|
|
sys.stderr = io.StringIO() |
|
|
return self |
|
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb): |
|
|
sys.stderr = self.original_stderr |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
print("\n" + "=" * 70) |
|
|
print("π Starting Sentiment Analysis Gradio Interface...") |
|
|
print("=" * 70 + "\n") |
|
|
|
|
|
|
|
|
interface = create_gradio_interface() |
|
|
|
|
|
|
|
|
print("β³ Launching server...") |
|
|
|
|
|
with SuppressStderr(): |
|
|
|
|
|
interface.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=False, |
|
|
show_error=True, |
|
|
ssr_mode=False, |
|
|
theme=gr.themes.Soft(), |
|
|
quiet=False, |
|
|
prevent_thread_lock=False |
|
|
) |
|
|
|
|
|
print("\n" + "=" * 70) |
|
|
print("β
Interface is LIVE and ready to use!") |
|
|
print(" π Local URL: http://localhost:7860") |
|
|
print(" β‘ Server is running smoothly") |
|
|
print(" π Press Ctrl+C to stop") |
|
|
print("=" * 70) |