File size: 3,203 Bytes
6a16f17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import re
import joblib
import gradio as gr


model = joblib.load("sentiment_model.pkl")


def clean_text(text):
    text = str(text).lower()
    text = re.sub(r"http\S+|www\S+", "", text)
    text = re.sub(r"@\w+", "", text)
    text = re.sub(r"#", "", text)
    text = re.sub(r"[^a-z0-9\s!?.,']", " ", text)
    text = re.sub(r"\s+", " ", text).strip()
    return text


positive_words = {
    "good", "great", "excellent", "useful", "helpful", "fast", "reliable",
    "better", "smooth", "valuable", "enjoyable", "improves", "solved", "clear"
}

negative_words = {
    "bad", "terrible", "poor", "slow", "weak", "worse", "crashing",
    "disappointing", "confusing", "rude", "ignored", "harmful", "bugs", "wrong"
}

mixed_markers = {
    "but", "however", "although", "though", "while"
}


def explain_sentiment(text):
    cleaned = clean_text(text)
    tokens = cleaned.split()

    positive_clues = [word for word in tokens if word in positive_words]
    negative_clues = [word for word in tokens if word in negative_words]
    mixed_clues = [word for word in tokens if word in mixed_markers]

    explanation = []

    if positive_clues:
        explanation.append(f"Positive clues found: {positive_clues}")

    if negative_clues:
        explanation.append(f"Negative clues found: {negative_clues}")

    if mixed_clues:
        explanation.append(f"Mixed-sentiment marker found: {mixed_clues}")

    if not explanation:
        explanation.append("No strong sentiment clue was found using the simple explanation layer.")

    return explanation


def analyze_sentiment(text):
    cleaned = clean_text(text)

    prediction = model.predict([cleaned])[0]

    output = f"Predicted Sentiment: {prediction}\n\n"

    if hasattr(model, "predict_proba"):
        probabilities = model.predict_proba([cleaned])[0]
        prob_table = sorted(
            zip(model.classes_, probabilities),
            key=lambda x: x[1],
            reverse=True
        )

        confidence = max(probabilities)

        output += f"Confidence: {confidence:.3f}\n\n"
        output += "Probability Table:\n"

        for label, prob in prob_table:
            output += f"{label}: {prob:.3f}\n"

        if confidence < 0.45:
            output += "\nResearch Note: Low confidence. Human review may be needed.\n"
        else:
            output += "\nResearch Note: The model found a reasonably clear pattern.\n"

    else:
        output += "Confidence: This model does not provide probabilities.\n\n"

    explanation = explain_sentiment(text)

    output += "\nExplanation:\n"
    for item in explanation:
        output += f"- {item}\n"

    return output


demo = gr.Interface(
    fn=analyze_sentiment,
    inputs=gr.Textbox(
        lines=6,
        placeholder="Paste a social media post, review, news sentence, or public comment here..."
    ),
    outputs=gr.Textbox(lines=18),
    title="ToneLens AI — Sentiment Analyzer",
    description="A student-built NLP product that analyzes sentiment in text using a trained machine learning model."
)


if __name__ == "__main__":
    demo.launch()