dwmk commited on
Commit
f04c010
ยท
verified ยท
1 Parent(s): 0360059

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -97
app.py CHANGED
@@ -5,29 +5,31 @@ import torch
5
  import torch.nn as nn
6
  import torch.nn.functional as F
7
  from sklearn.feature_extraction.text import TfidfVectorizer
8
- from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
9
  from sklearn.linear_model import LogisticRegression
10
  from sklearn.svm import SVC
11
  from sklearn.naive_bayes import MultinomialNB
12
  from sklearn.preprocessing import LabelEncoder
13
- from sklearn.utils import Bunch
14
  import kagglehub
15
  import time
16
  import random
17
- import threading
18
 
19
- # --- 1. CORE MODEL LOGIC (Ported from your script) ---
 
20
 
21
  class EpisodicMemory:
 
22
  def __init__(self, capacity=2000):
23
  self.memory_x, self.memory_y = [], []
24
  self.capacity = capacity
 
25
  def store(self, x, y):
26
  curr_x, curr_y = x.detach().cpu(), y.detach().cpu()
27
  for i in range(curr_x.size(0)):
28
  if len(self.memory_x) >= self.capacity:
29
  self.memory_x.pop(0); self.memory_y.pop(0)
30
  self.memory_x.append(curr_x[i]); self.memory_y.append(curr_y[i])
 
31
  def retrieve(self, query_x, k=5):
32
  if len(self.memory_x) < k: return None
33
  mem_tensor = torch.stack(self.memory_x).to(query_x.device)
@@ -39,7 +41,14 @@ class EpisodicMemory:
39
  class ExecutiveCore(nn.Module):
40
  def __init__(self, input_dim, hidden_dim):
41
  super().__init__()
42
- self.net = nn.Sequential(nn.Linear(input_dim, hidden_dim), nn.LayerNorm(hidden_dim), nn.GELU(), nn.Dropout(0.2), nn.Linear(hidden_dim, hidden_dim), nn.GELU())
 
 
 
 
 
 
 
43
  def forward(self, x): return self.net(x)
44
 
45
  class MotorPolicy(nn.Module):
@@ -49,34 +58,46 @@ class MotorPolicy(nn.Module):
49
  def forward(self, x): return self.fc(x)
50
 
51
  class H3MOS(nn.Module):
 
52
  def __init__(self, input_dim, hidden_dim, output_dim):
53
  super().__init__()
54
  self.executive = ExecutiveCore(input_dim, hidden_dim)
55
  self.motor = MotorPolicy(hidden_dim, output_dim)
56
  self.hippocampus = EpisodicMemory()
 
57
  def forward(self, x, training_mode=False):
58
  z = self.executive(x)
59
- if training_mode or len(self.hippocampus.memory_x) < 10: return self.motor(z)
 
 
60
  past_labels = self.hippocampus.retrieve(x, k=5)
61
  raw_logits = self.motor(z)
 
 
 
62
  mem_votes = torch.zeros_like(raw_logits)
63
  for i in range(x.size(0)):
64
  votes = torch.bincount(past_labels[i], minlength=raw_logits.size(1)).float()
65
  mem_votes[i] = votes
 
66
  return (0.8 * raw_logits) + (0.2 * F.softmax(mem_votes, dim=1) * 5.0)
67
 
68
- # --- 2. DATA & TRAINING SETUP ---
 
 
69
 
70
- print("Downloading dataset and training models...")
71
  path = kagglehub.dataset_download('dewanmukto/social-messages-and-emoji-reactions')
72
  df = pd.read_csv(path+"/messages_emojis.csv").dropna(subset=['content'])
73
 
 
74
  sent_map = {'โค๏ธ':'Pos', '๐Ÿ‘':'Pos', '๐Ÿ˜‚':'Pos', '๐Ÿ’ฏ':'Pos', '๐Ÿ˜ข':'Neg', '๐Ÿ˜ญ':'Neg', '๐Ÿ˜ฎ':'Neu'}
75
  intent_map = {'โค๏ธ':'Emotion', '๐Ÿ‘':'Agreement', '๐Ÿ˜‚':'Emotion', '๐Ÿ˜ฎ':'Surprise'}
 
76
  tfidf = TfidfVectorizer(max_features=1000, stop_words='english')
77
- X = tfidf.fit_transform(df['content'])
 
78
 
79
- targets = {
80
  'emoji': df['emoji'].values,
81
  'sentiment': df['emoji'].apply(lambda x: sent_map.get(x, 'Neutral')).values,
82
  'intent': df['emoji'].apply(lambda x: intent_map.get(x, 'Other')).values
@@ -84,126 +105,104 @@ targets = {
84
 
85
  model_zoo = {}
86
  encoders = {}
87
- algs = {
88
- "RandomForest": RandomForestClassifier(n_estimators=50),
89
- "SVM": SVC(kernel='linear', probability=True),
90
- "NaiveBayes": MultinomialNB(),
91
- "LogReg": LogisticRegression(max_iter=500),
92
- "DISTIL-H3MOS": "torch"
93
- }
94
 
95
- for task, y in targets.items():
96
  le = LabelEncoder()
97
- y_enc = le.fit_transform(y)
98
  encoders[task] = le
99
- for name, clf in algs.items():
100
- if name not in model_zoo: model_zoo[name] = {}
101
- if name == "DISTIL-H3MOS":
102
- model = H3MOS(X.shape[1], 64, len(le.classes_))
103
- # (Simplified training for demo speed)
104
- optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
105
- X_t = torch.FloatTensor(X.toarray())
106
- y_t = torch.LongTensor(y_enc)
107
- for _ in range(20):
108
- optimizer.zero_grad(); loss = F.cross_entropy(model(X_t, True), y_t); loss.backward(); optimizer.step()
109
- model_zoo[name][task] = model
110
- else:
111
- clf.fit(X, y)
112
- model_zoo[name][task] = clf
113
-
114
- # --- 3. GRADIO UI & CHAT LOGIC ---
115
-
116
- # Dicebear Avatars
117
  def get_avatar(seed):
118
  return f"https://api.dicebear.com/7.x/adventurer/svg?seed={seed}"
119
 
120
  CSS = """
121
  .reaction-pill {
122
- background: rgba(255, 255, 255, 0.8);
123
  border-radius: 12px;
124
- padding: 2px 8px;
125
- font-size: 14px;
126
- margin-top: 5px;
127
  display: inline-block;
128
  border: 1px solid #ddd;
129
- cursor: help;
130
  }
131
- .chat-window { border-radius: 15px; }
132
  """
133
 
134
- def chat_interface(message, history):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  if not message: return "", history
136
 
137
- # 1. Process Reactions for User Message
138
- vec = tfidf.transform([message])
139
- vec_t = torch.FloatTensor(vec.toarray())
140
 
141
- reactions = []
142
- reaction_details = "Models reacted: "
143
- for name in model_zoo.keys():
144
- if name == "DISTIL-H3MOS":
145
- with torch.no_grad():
146
- res = torch.argmax(model_zoo[name]['emoji'](vec_t)).item()
147
- emoji = encoders['emoji'].inverse_transform([res])[0]
148
- else:
149
- emoji = model_zoo[name]['emoji'].predict(vec)[0]
150
- reactions.append(emoji)
151
- reaction_details += f"{name} ({emoji}) "
152
-
153
- # Most frequent emoji as primary reaction
154
- primary_emoji = max(set(reactions), key=reactions.count)
155
- reaction_html = f"<div class='reaction-pill' title='{reaction_details}'>{primary_emoji} {len(reactions)}</div>"
156
 
157
- user_msg_formatted = f"{message}<br>{reaction_html}"
158
- history.append({"role": "user", "content": user_msg_formatted})
159
  yield history
160
 
161
- # 2. Simulate Bot Responses
162
- active_models = ["DISTIL-H3MOS", "RandomForest", "LogReg", "SVM"]
163
- random.shuffle(active_models)
164
-
165
- for bot in active_models:
166
- # Simulate typing delay
167
- time.sleep(random.uniform(0.5, 1.5))
168
 
169
- # Predict Sentiment/Intent
170
- if bot == "DISTIL-H3MOS":
171
- with torch.no_grad():
172
- s_idx = torch.argmax(model_zoo[bot]['sentiment'](vec_t)).item()
173
- i_idx = torch.argmax(model_zoo[bot]['intent'](vec_t)).item()
174
- sent = encoders['sentiment'].inverse_transform([s_idx])[0]
175
- intent = encoders['intent'].inverse_transform([i_idx])[0]
176
- else:
177
- sent = model_zoo[bot]['sentiment'].predict(vec)[0]
178
- intent = model_zoo[bot]['intent'].predict(vec)[0]
179
-
180
- bot_content = f"**Sentiment:** {sent} | **Intent:** {intent}"
181
  history.append({
182
  "role": "assistant",
183
- "content": bot_content,
184
- "metadata": {"title": f"{bot}", "avatar": get_avatar(bot)}
185
  })
186
  yield history
187
 
188
- with gr.Blocks(css=CSS) as demo:
189
- gr.Markdown("# ๐Ÿค– Multitask Model Group Chat\n*A benchmark-turned-chat app featuring H3MOS, RF, and SVM.*")
 
190
 
191
  chatbot = gr.Chatbot(
192
  elem_id="chat-window",
193
- type="messages",
194
  avatar_images=(None, "https://api.dicebear.com/7.x/bottts/svg?seed=User"),
195
  bubble_full_width=False
196
  )
197
 
198
  with gr.Row():
199
- txt = gr.Textbox(
200
- show_label=False,
201
- placeholder="Type a message to see how the models react...",
202
- scale=4
203
- )
204
- submit_btn = gr.Button("Send", variant="primary", scale=1)
205
 
206
- txt.submit(chat_interface, [txt, chatbot], [txt, chatbot])
207
- submit_btn.click(chat_interface, [txt, chatbot], [txt, chatbot])
208
 
209
- demo.launch()
 
 
5
  import torch.nn as nn
6
  import torch.nn.functional as F
7
  from sklearn.feature_extraction.text import TfidfVectorizer
8
+ from sklearn.ensemble import RandomForestClassifier
9
  from sklearn.linear_model import LogisticRegression
10
  from sklearn.svm import SVC
11
  from sklearn.naive_bayes import MultinomialNB
12
  from sklearn.preprocessing import LabelEncoder
 
13
  import kagglehub
14
  import time
15
  import random
 
16
 
17
+ # --- 1. CORE MODEL LOGIC ---
18
+ # Using the H3MOS and EpisodicMemory architecture provided in the benchmarks
19
 
20
  class EpisodicMemory:
21
+ """Mimics Hippocampal retention and retrieval"""
22
  def __init__(self, capacity=2000):
23
  self.memory_x, self.memory_y = [], []
24
  self.capacity = capacity
25
+
26
  def store(self, x, y):
27
  curr_x, curr_y = x.detach().cpu(), y.detach().cpu()
28
  for i in range(curr_x.size(0)):
29
  if len(self.memory_x) >= self.capacity:
30
  self.memory_x.pop(0); self.memory_y.pop(0)
31
  self.memory_x.append(curr_x[i]); self.memory_y.append(curr_y[i])
32
+
33
  def retrieve(self, query_x, k=5):
34
  if len(self.memory_x) < k: return None
35
  mem_tensor = torch.stack(self.memory_x).to(query_x.device)
 
41
  class ExecutiveCore(nn.Module):
42
  def __init__(self, input_dim, hidden_dim):
43
  super().__init__()
44
+ self.net = nn.Sequential(
45
+ nn.Linear(input_dim, hidden_dim),
46
+ nn.LayerNorm(hidden_dim),
47
+ nn.GELU(),
48
+ nn.Dropout(0.2),
49
+ nn.Linear(hidden_dim, hidden_dim),
50
+ nn.GELU()
51
+ )
52
  def forward(self, x): return self.net(x)
53
 
54
  class MotorPolicy(nn.Module):
 
58
  def forward(self, x): return self.fc(x)
59
 
60
  class H3MOS(nn.Module):
61
+ """The DISTIL-H3MOS model architecture"""
62
  def __init__(self, input_dim, hidden_dim, output_dim):
63
  super().__init__()
64
  self.executive = ExecutiveCore(input_dim, hidden_dim)
65
  self.motor = MotorPolicy(hidden_dim, output_dim)
66
  self.hippocampus = EpisodicMemory()
67
+
68
  def forward(self, x, training_mode=False):
69
  z = self.executive(x)
70
+ if training_mode or len(self.hippocampus.memory_x) < 10:
71
+ return self.motor(z)
72
+
73
  past_labels = self.hippocampus.retrieve(x, k=5)
74
  raw_logits = self.motor(z)
75
+
76
+ if past_labels is None: return raw_logits
77
+
78
  mem_votes = torch.zeros_like(raw_logits)
79
  for i in range(x.size(0)):
80
  votes = torch.bincount(past_labels[i], minlength=raw_logits.size(1)).float()
81
  mem_votes[i] = votes
82
+
83
  return (0.8 * raw_logits) + (0.2 * F.softmax(mem_votes, dim=1) * 5.0)
84
 
85
+ # --- 2. DATA & TRAINING ---
86
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
87
+ print(f"Loading data on {device}...")
88
 
 
89
  path = kagglehub.dataset_download('dewanmukto/social-messages-and-emoji-reactions')
90
  df = pd.read_csv(path+"/messages_emojis.csv").dropna(subset=['content'])
91
 
92
+ # Mapping logic from the original benchmark
93
  sent_map = {'โค๏ธ':'Pos', '๐Ÿ‘':'Pos', '๐Ÿ˜‚':'Pos', '๐Ÿ’ฏ':'Pos', '๐Ÿ˜ข':'Neg', '๐Ÿ˜ญ':'Neg', '๐Ÿ˜ฎ':'Neu'}
94
  intent_map = {'โค๏ธ':'Emotion', '๐Ÿ‘':'Agreement', '๐Ÿ˜‚':'Emotion', '๐Ÿ˜ฎ':'Surprise'}
95
+
96
  tfidf = TfidfVectorizer(max_features=1000, stop_words='english')
97
+ X_sparse = tfidf.fit_transform(df['content'])
98
+ X_dense = torch.FloatTensor(X_sparse.toarray()).to(device)
99
 
100
+ tasks = {
101
  'emoji': df['emoji'].values,
102
  'sentiment': df['emoji'].apply(lambda x: sent_map.get(x, 'Neutral')).values,
103
  'intent': df['emoji'].apply(lambda x: intent_map.get(x, 'Other')).values
 
105
 
106
  model_zoo = {}
107
  encoders = {}
 
 
 
 
 
 
 
108
 
109
+ for task, y_labels in tasks.items():
110
  le = LabelEncoder()
111
+ y_enc = torch.LongTensor(le.fit_transform(y_labels)).to(device)
112
  encoders[task] = le
113
+
114
+ # Train H3MOS
115
+ h3_model = H3MOS(X_dense.shape[1], 64, len(le.classes_)).to(device)
116
+ opt = torch.optim.Adam(h3_model.parameters(), lr=0.01)
117
+ for _ in range(30):
118
+ opt.zero_grad()
119
+ loss = F.cross_entropy(h3_model(X_dense, True), y_enc)
120
+ loss.backward(); opt.step()
121
+
122
+ # Store Sklearn models for comparison
123
+ rf = RandomForestClassifier(n_estimators=50).fit(X_sparse, y_labels)
124
+
125
+ model_zoo[task] = {"H3MOS": h3_model, "RandomForest": rf}
126
+
127
+ # --- 3. CHAT INTERFACE ---
128
+
 
 
129
  def get_avatar(seed):
130
  return f"https://api.dicebear.com/7.x/adventurer/svg?seed={seed}"
131
 
132
  CSS = """
133
  .reaction-pill {
134
+ background: rgba(0, 0, 0, 0.05);
135
  border-radius: 12px;
136
+ padding: 2px 10px;
137
+ font-size: 16px;
138
+ margin-top: 8px;
139
  display: inline-block;
140
  border: 1px solid #ddd;
 
141
  }
 
142
  """
143
 
144
+ def predict_all(text):
145
+ vec_s = tfidf.transform([text])
146
+ vec_t = torch.FloatTensor(vec_s.toarray()).to(device)
147
+
148
+ results = {}
149
+ for task in ['emoji', 'sentiment', 'intent']:
150
+ # H3MOS Inference
151
+ with torch.no_grad():
152
+ h3_out = model_zoo[task]["H3MOS"](vec_t)
153
+ h3_pred = encoders[task].inverse_transform([torch.argmax(h3_out).item()])[0]
154
+
155
+ # RF Inference
156
+ rf_pred = model_zoo[task]["RandomForest"].predict(vec_s)[0]
157
+ results[task] = {"H3MOS": h3_pred, "RandomForest": rf_pred}
158
+ return results
159
+
160
+ def chat_fn(message, history):
161
  if not message: return "", history
162
 
163
+ preds = predict_all(message)
 
 
164
 
165
+ # Create Reaction HTML (Hover shows model breakdown)
166
+ emoji_h3 = preds['emoji']['H3MOS']
167
+ emoji_rf = preds['emoji']['RandomForest']
168
+ reaction_html = f"<div class='reaction-pill' title='H3MOS: {emoji_h3} | RF: {emoji_rf}'>{emoji_h3} ๐Ÿค–</div>"
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ # 1. Add User Message
171
+ history.append({"role": "user", "content": f"{message}<br>{reaction_html}"})
172
  yield history
173
 
174
+ # 2. Sequential Bot Replies
175
+ bots = [("DISTIL-H3MOS", "H3MOS"), ("RandomForest", "RandomForest")]
176
+ for bot_name, key in bots:
177
+ time.sleep(random.uniform(0.8, 1.5)) # Simulation delay
 
 
 
178
 
179
+ sent = preds['sentiment'][key]
180
+ intent = preds['intent'][key]
181
+
182
+ bot_msg = f"**Sentiment:** {sent} \n**Intent:** {intent}"
 
 
 
 
 
 
 
 
183
  history.append({
184
  "role": "assistant",
185
+ "content": bot_msg,
186
+ "metadata": {"title": bot_name}
187
  })
188
  yield history
189
 
190
+ with gr.Blocks() as demo:
191
+ gr.Markdown("## ๐Ÿ’ฌ Social AI Group Chat")
192
+ gr.Markdown("Type a message. Models will react with emojis and reply with their analysis.")
193
 
194
  chatbot = gr.Chatbot(
195
  elem_id="chat-window",
 
196
  avatar_images=(None, "https://api.dicebear.com/7.x/bottts/svg?seed=User"),
197
  bubble_full_width=False
198
  )
199
 
200
  with gr.Row():
201
+ msg_input = gr.Textbox(placeholder="Say something...", show_label=False, scale=4)
202
+ submit = gr.Button("Send", variant="primary")
 
 
 
 
203
 
204
+ msg_input.submit(chat_fn, [msg_input, chatbot], [msg_input, chatbot])
205
+ submit.click(chat_fn, [msg_input, chatbot], [msg_input, chatbot])
206
 
207
+ # Corrected launch for Gradio 6.0 compatibility
208
+ demo.launch(css=CSS)