codexautomationkey commited on
Commit
6a16f17
·
verified ·
1 Parent(s): 171d009

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +112 -0
  2. requirements.txt +5 -0
  3. sentiment_model.pkl +3 -0
app.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import joblib
3
+ import gradio as gr
4
+
5
+
6
+ model = joblib.load("sentiment_model.pkl")
7
+
8
+
9
+ def clean_text(text):
10
+ text = str(text).lower()
11
+ text = re.sub(r"http\S+|www\S+", "", text)
12
+ text = re.sub(r"@\w+", "", text)
13
+ text = re.sub(r"#", "", text)
14
+ text = re.sub(r"[^a-z0-9\s!?.,']", " ", text)
15
+ text = re.sub(r"\s+", " ", text).strip()
16
+ return text
17
+
18
+
19
+ positive_words = {
20
+ "good", "great", "excellent", "useful", "helpful", "fast", "reliable",
21
+ "better", "smooth", "valuable", "enjoyable", "improves", "solved", "clear"
22
+ }
23
+
24
+ negative_words = {
25
+ "bad", "terrible", "poor", "slow", "weak", "worse", "crashing",
26
+ "disappointing", "confusing", "rude", "ignored", "harmful", "bugs", "wrong"
27
+ }
28
+
29
+ mixed_markers = {
30
+ "but", "however", "although", "though", "while"
31
+ }
32
+
33
+
34
+ def explain_sentiment(text):
35
+ cleaned = clean_text(text)
36
+ tokens = cleaned.split()
37
+
38
+ positive_clues = [word for word in tokens if word in positive_words]
39
+ negative_clues = [word for word in tokens if word in negative_words]
40
+ mixed_clues = [word for word in tokens if word in mixed_markers]
41
+
42
+ explanation = []
43
+
44
+ if positive_clues:
45
+ explanation.append(f"Positive clues found: {positive_clues}")
46
+
47
+ if negative_clues:
48
+ explanation.append(f"Negative clues found: {negative_clues}")
49
+
50
+ if mixed_clues:
51
+ explanation.append(f"Mixed-sentiment marker found: {mixed_clues}")
52
+
53
+ if not explanation:
54
+ explanation.append("No strong sentiment clue was found using the simple explanation layer.")
55
+
56
+ return explanation
57
+
58
+
59
+ def analyze_sentiment(text):
60
+ cleaned = clean_text(text)
61
+
62
+ prediction = model.predict([cleaned])[0]
63
+
64
+ output = f"Predicted Sentiment: {prediction}\n\n"
65
+
66
+ if hasattr(model, "predict_proba"):
67
+ probabilities = model.predict_proba([cleaned])[0]
68
+ prob_table = sorted(
69
+ zip(model.classes_, probabilities),
70
+ key=lambda x: x[1],
71
+ reverse=True
72
+ )
73
+
74
+ confidence = max(probabilities)
75
+
76
+ output += f"Confidence: {confidence:.3f}\n\n"
77
+ output += "Probability Table:\n"
78
+
79
+ for label, prob in prob_table:
80
+ output += f"{label}: {prob:.3f}\n"
81
+
82
+ if confidence < 0.45:
83
+ output += "\nResearch Note: Low confidence. Human review may be needed.\n"
84
+ else:
85
+ output += "\nResearch Note: The model found a reasonably clear pattern.\n"
86
+
87
+ else:
88
+ output += "Confidence: This model does not provide probabilities.\n\n"
89
+
90
+ explanation = explain_sentiment(text)
91
+
92
+ output += "\nExplanation:\n"
93
+ for item in explanation:
94
+ output += f"- {item}\n"
95
+
96
+ return output
97
+
98
+
99
+ demo = gr.Interface(
100
+ fn=analyze_sentiment,
101
+ inputs=gr.Textbox(
102
+ lines=6,
103
+ placeholder="Paste a social media post, review, news sentence, or public comment here..."
104
+ ),
105
+ outputs=gr.Textbox(lines=18),
106
+ title="ToneLens AI — Sentiment Analyzer",
107
+ description="A student-built NLP product that analyzes sentiment in text using a trained machine learning model."
108
+ )
109
+
110
+
111
+ if __name__ == "__main__":
112
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ scikit-learn
3
+ pandas
4
+ numpy
5
+ joblib
sentiment_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:973ae96c1a5bce9168ef21c9b328f683098bad974db7c3e3a3d8640cef904ebf
3
+ size 209472