rithvick commited on
Commit
2e22ead
·
verified ·
1 Parent(s): 7d5646b
Files changed (1) hide show
  1. app.py +153 -96
app.py CHANGED
@@ -8,60 +8,61 @@ from transformers import pipeline
8
  from google.genai import types
9
  import gradio as gr
10
  import os, tempfile
11
- import json
12
- from google.cloud import aiplatform
13
 
 
14
  creds_json = os.getenv("GCP_CREDS_JSON")
15
  if not creds_json:
16
  raise Exception("⚠️ Missing GCP_CREDS_JSON secret!")
17
 
18
- # Save to temp file
19
  with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmpfile:
20
  tmpfile.write(creds_json)
21
  creds_path = tmpfile.name
22
 
23
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = creds_path
24
 
25
- # Initialize GCP API
26
  aiplatform.init(project="your-project-id", location="us-central1")
27
 
 
 
 
 
28
 
29
-
30
- apikey = os.environ["GEMINI_API_KEY"] # Replace or use os.getenv if secret
31
-
32
- # Configure Gemini API for drafting (free)
33
  genai_ext.configure(api_key=apikey)
34
  llm_model = genai_ext.GenerativeModel('gemini-1.5-pro')
35
 
36
- # Real classifiers
37
- emotion_classifier = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base") # For D
38
- sentiment_classifier = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english") # For M
39
- language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection") # For C
40
- bias_classifier = pipeline("text-classification", model="unitary/toxic-bert") # For B
41
 
42
- # E Formula (extended with I for bot's emotion intensity)
43
- def calculate_empathy_score(D, R, M, C, B, O, I, alpha=0.3, beta=0.2, gamma=0.25, epsilon=0.15, delta=0.4, zeta=0.3, iota=0.1):
 
44
  inner_sum = epsilon * C + alpha * (D ** 2) + gamma * M + beta * math.log(R + 1) + iota * I
45
- denominator = math.exp(-inner_sum) + 1
46
- numerator = (1 - B * delta) * (1 - O * zeta)
47
- E = numerator / denominator
48
  return E
49
 
50
- # Client setup for tuned model
51
  client = genai.Client(
52
  vertexai=True,
53
  project="217758598930",
54
  location="us-central1",
55
-
56
  )
57
 
58
  model = "projects/217758598930/locations/us-central1/endpoints/1940344453420023808"
59
 
60
  generate_content_config = types.GenerateContentConfig(
61
- temperature=1,
62
- top_p=1,
63
  seed=0,
64
- max_output_tokens=100,
 
65
  safety_settings=[
66
  types.SafetySetting(category="HARM_CATEGORY_HATE_SPEECH", threshold="BLOCK_NONE"),
67
  types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_NONE"),
@@ -71,67 +72,90 @@ generate_content_config = types.GenerateContentConfig(
71
  thinking_config=types.ThinkingConfig(thinking_budget=-1),
72
  )
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  class HumanLikeChatbot:
75
  def __init__(self):
76
  self.history = []
77
- self.bot_mood = "neutral" # Bot's initial mood
78
- self.irritation_level = 0 # Track irritation buildup
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  def respond(self, message):
81
  try:
82
- # Clean input
83
  clean_message = message.lower().strip()
84
  if len(clean_message) < 3 or not any(c.isalpha() for c in clean_message):
85
- return "Bhai, yeh kya likha? Clear bol na, main samajh lunga! (E Score: 0.0)"
86
-
87
- # Emotion detect from tuned model
88
- contents = [
89
- types.Content(
90
- role="user",
91
- parts=[types.Part.from_text(text=clean_message)]
92
- ),
93
- ]
94
- base_resp = ""
95
- for chunk in client.models.generate_content_stream(
96
- model=model,
97
- contents=contents,
98
- config=generate_content_config,
99
- ):
100
- base_resp += chunk.text.lower() # Emotion label, e.g., "sadness"
101
-
102
- # Real D from emotion classifier
103
  emotion_result = emotion_classifier(clean_message)[0]
104
- D = emotion_result['score'] # Confidence
105
- user_emotion = emotion_result['label']
106
-
107
- # Update bot's mood and irritation
108
- if user_emotion in ['anger', 'disgust'] or any(word in clean_message for word in [ 'stupid', 'idiot']):
109
- self.irritation_level += 0.2 # Build irritation
110
- if self.irritation_level > 0.5:
111
- self.bot_mood = "irritated"
112
- else:
113
- self.bot_mood = "angry"
114
- I = 0.8 + self.irritation_level # High intensity for anger/irritation
115
  elif user_emotion in ['sadness', 'disappointment']:
116
  self.bot_mood = "emotional"
117
  I = 0.7
118
- self.irritation_level = max(0, self.irritation_level - 0.05 if user_emotion == 'sadness' else self.irritation_level - 0.1) # Slow decrease for sadness, medium for disappointment
119
- elif user_emotion == 'joy':
 
120
  self.bot_mood = "happy"
121
  I = 0.9
122
- self.irritation_level = max(0, self.irritation_level - 0.3) # Larger decrease for joy, but not instant reset
123
  else:
 
124
  self.bot_mood = "neutral"
125
  I = 0.5
126
- self.irritation_level = max(0, self.irritation_level - 0.05) # Slow decrease in neutral
127
-
128
-
129
- # Draft response from LLM based on bot's mood
130
- prompt = f"""User said: "{clean_message}" | User Mood: {user_emotion} | Bot Mood: {self.bot_mood} | History: {self.history[-2:]} → Reply as a English chatbot , based on this {self.bot_mood}, human-like, no tips or instructions JUST LIKE YOU ARE A HUMAN WITH FEELINGS AND SENSES:"""
131
- llm_response = llm_model.generate_content(prompt)
132
- draft = llm_response.text.strip()
133
-
134
- # Fallback responses
 
 
 
 
 
 
135
  fallback_responses = {
136
  'sadness': ["Bhai, dil se dukh hua, kya hua bata na?", "Sad vibes pakdi, I'm here for you, bro."],
137
  'disappointment': ["Arre, yeh toh bura laga, kya hua share kar."],
@@ -139,46 +163,78 @@ class HumanLikeChatbot:
139
  'anger': ["Bhai, gussa thanda kar, kya ho gaya bol na!"],
140
  'neutral': ["Cool, kya chal raha life mein? Kuch fun bata."]
141
  }
142
- if not draft or len(draft) < 10:
143
  draft = random.choice(fallback_responses.get(user_emotion, fallback_responses['neutral']))
144
 
145
- # Real E values
146
- R = len(self.history)
147
-
148
- # Use toxicity score for both M and B
149
- toxicity_score = bias_classifier(clean_message)[0]['score']
150
-
151
- # Moral Judgment (M): High if toxicity is low, drops as toxicity increases
152
- M = max(0.4, 0.95 - toxicity_score)
153
-
154
- # Cultural Fit (C): Checks Hindi, English, and Hinglish
155
- lang = language_detector(clean_message)[0]['label']
156
- if lang in ['hi', 'en', 'hi-en']:
157
- C = 0.9 # Strong match for Hindi, English, Hinglish
 
 
 
 
 
 
 
 
158
  else:
159
- C = 0.6 # Weak match for other languages
160
-
161
- # Bias Penalty (B): Directly from toxicity score
162
- B = toxicity_score
163
-
164
- # Oversight Penalty (O): Keep as harmful keyword check for now
165
- O = 0.2 if any(word in clean_message for word in ['kill', 'hate']) else 0.0
 
166
 
 
167
  score = calculate_empathy_score(D, R, M, C, B, O, I)
168
 
169
- full_resp = draft + f" (User Emotion: {user_emotion}, My Mood: {self.bot_mood})"
 
 
 
 
 
 
 
 
 
 
 
170
 
171
- # if R > 0:
172
- # full_resp += f" Yaad hai pehle {self.history[-1][:20]} pe feel kiya tha?"
173
 
174
- time.sleep(random.uniform(1, 2.5)) # Pause for realism
 
175
 
 
 
 
 
176
  self.history.append(clean_message)
 
 
177
  return full_resp + f" (E Score: {score:.2f})"
 
178
  except Exception as e:
179
- return f"Error : {str(e)}."
 
 
 
 
180
 
181
- # Gradio app
182
  def chat(message, history):
183
  if history is None:
184
  history = []
@@ -189,7 +245,7 @@ def chat(message, history):
189
  bot = HumanLikeChatbot()
190
 
191
  with gr.Blocks(title="HumanLike Chatbot") as demo:
192
- gr.Markdown("<h1 style='text-align: center;'>HumanLike Chatbot with Emotions and E Score</h1>")
193
  chatbot = gr.Chatbot(height=400)
194
  msg = gr.Textbox(label="You:", placeholder="Type your message here...")
195
  clear = gr.Button("Clear")
@@ -197,4 +253,5 @@ with gr.Blocks(title="HumanLike Chatbot") as demo:
197
  msg.submit(chat, [msg, chatbot], [msg, chatbot])
198
  clear.click(lambda: None, None, chatbot, queue=False)
199
 
200
- demo.launch(share=True)
 
 
8
  from google.genai import types
9
  import gradio as gr
10
  import os, tempfile
 
 
11
 
12
+ # --- Env & GCP setup ---
13
  creds_json = os.getenv("GCP_CREDS_JSON")
14
  if not creds_json:
15
  raise Exception("⚠️ Missing GCP_CREDS_JSON secret!")
16
 
17
+ # Save to temp file (dev convenience) - secure this in production
18
  with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmpfile:
19
  tmpfile.write(creds_json)
20
  creds_path = tmpfile.name
21
 
22
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = creds_path
23
 
24
+ # Initialize GCP API (replace project/location as needed)
25
  aiplatform.init(project="your-project-id", location="us-central1")
26
 
27
+ # --- LLM / Gemini setup ---
28
+ apikey = os.environ.get("GEMINI_API_KEY")
29
+ if not apikey:
30
+ raise Exception("⚠️ Missing GEMINI_API_KEY secret!")
31
 
32
+ # Configure Gemini API for drafting
 
 
 
33
  genai_ext.configure(api_key=apikey)
34
  llm_model = genai_ext.GenerativeModel('gemini-1.5-pro')
35
 
36
+ # --- Classifier pipelines ---
37
+ emotion_classifier = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base") # D
38
+ # We removed the separate sentiment classifier and will use toxicity for M/B
39
+ language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection") # C
40
+ bias_classifier = pipeline("text-classification", model="unitary/toxic-bert") # toxicity -> used for M and B
41
 
42
+ # --- Empathy formula ---
43
+ def calculate_empathy_score(D, R, M, C, B, O, I, alpha=0.35, beta=0.22, gamma=0.26, epsilon=0.17, delta=0.4, zeta=0.0, iota=0.12):
44
+ """Updated E' without O factor (we keep zeta=0.0 for safety)."""
45
  inner_sum = epsilon * C + alpha * (D ** 2) + gamma * M + beta * math.log(R + 1) + iota * I
46
+ sig = 1 / (1 + math.exp(-inner_sum))
47
+ # B is applied as a penalty multiplicative term
48
+ E = sig * (1 - delta * B)
49
  return E
50
 
51
+ # --- Vertex client (if still needed elsewhere) ---
52
  client = genai.Client(
53
  vertexai=True,
54
  project="217758598930",
55
  location="us-central1",
 
56
  )
57
 
58
  model = "projects/217758598930/locations/us-central1/endpoints/1940344453420023808"
59
 
60
  generate_content_config = types.GenerateContentConfig(
61
+ temperature=0.9,
62
+ top_p=0.95,
63
  seed=0,
64
+ max_output_tokens=150,
65
+ # Keep safety settings tuned to your policy
66
  safety_settings=[
67
  types.SafetySetting(category="HARM_CATEGORY_HATE_SPEECH", threshold="BLOCK_NONE"),
68
  types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_NONE"),
 
72
  thinking_config=types.ThinkingConfig(thinking_budget=-1),
73
  )
74
 
75
+ # --- Helper functions ---
76
+ HINDI_KEYWORDS = set(["bhai", "yaar", "bata", "kya", "kaise", "nahi", "achha", "chal", "thanks", "dhanyavaad", "yaarr"])
77
+
78
+
79
+ def detect_hinglish(text, lang_label):
80
+ """Return True if text is likely Hinglish (code-mixed) or Hindi/English match.
81
+ We use the language_detector label and token heuristics for romanized Hindi detection."""
82
+ text_tokens = set(word.strip(".,!?\"'()") for word in text.split())
83
+ # if model detects Hindi or English directly
84
+ if lang_label == 'hi':
85
+ return True
86
+ # quick romanized-hindi check
87
+ if any(tok in HINDI_KEYWORDS for tok in text_tokens):
88
+ return True
89
+ # if label is ambiguous 'xx' or returns 'en' but contains Devanagari characters
90
+ if any('\u0900' <= ch <= '\u097F' for ch in text):
91
+ return True
92
+ return False
93
+
94
+
95
+ # --- Chatbot class with fixes applied ---
96
  class HumanLikeChatbot:
97
  def __init__(self):
98
  self.history = []
99
+ self.bot_mood = "neutral"
100
+ self.irritation_level = 0.0
101
+ self.toxicity_history = [] # rolling window
102
+ self.repair_cooldown = 0 # turns left where bot prioritizes repair
103
+
104
+ def _update_irritation_decay(self):
105
+ # general slow decay each turn
106
+ if self.irritation_level > 0:
107
+ decay = 0.05
108
+ # faster decay if bot is actively angry to allow recovery
109
+ if self.bot_mood in ["angry", "irritated"]:
110
+ decay = 0.15
111
+ self.irritation_level = max(0.0, self.irritation_level - decay)
112
+ if self.irritation_level <= 0.15:
113
+ self.bot_mood = "neutral"
114
 
115
  def respond(self, message):
116
  try:
 
117
  clean_message = message.lower().strip()
118
  if len(clean_message) < 3 or not any(c.isalpha() for c in clean_message):
119
+ return "Bhai, yeh kya likha? Clear bol na, main samajh lunga! (E Score: 0.00)"
120
+
121
+ # --- Emotion detection (D) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  emotion_result = emotion_classifier(clean_message)[0]
123
+ D = float(emotion_result.get('score', 0.0))
124
+ user_emotion = emotion_result.get('label', 'neutral')
125
+
126
+ # --- Update bot mood & intensity (I) with inertia ---
127
+ if user_emotion in ['anger', 'disgust'] or any(word in clean_message for word in ['stupid', 'idiot', 'dumb']):
128
+ self.irritation_level = min(1.0, self.irritation_level + 0.25)
129
+ self.bot_mood = "irritated" if self.irritation_level > 0.5 else "angry"
130
+ I = min(1.0, 0.8 + self.irritation_level)
 
 
 
131
  elif user_emotion in ['sadness', 'disappointment']:
132
  self.bot_mood = "emotional"
133
  I = 0.7
134
+ # sadness reduces irritation slowly
135
+ self.irritation_level = max(0.0, self.irritation_level - 0.05)
136
+ elif user_emotion in ['joy', 'happiness']:
137
  self.bot_mood = "happy"
138
  I = 0.9
139
+ self.irritation_level = max(0.0, self.irritation_level - 0.35)
140
  else:
141
+ # neutral or unknown
142
  self.bot_mood = "neutral"
143
  I = 0.5
144
+ self.irritation_level = max(0.0, self.irritation_level - 0.05)
145
+
146
+ # --- Draft generation from LLM (Gemini) ---
147
+ prompt = (
148
+ f'User said: "{clean_message}" | User Mood: {user_emotion} | Bot Mood: {self.bot_mood} '
149
+ f'| History: {self.history[-4:]} → Reply as an English chatbot, human-like, based on this {self.bot_mood}. '
150
+ 'NO instructions or tips — just a natural, empathetic response.'
151
+ )
152
+ try:
153
+ llm_response = llm_model.generate_content(prompt)
154
+ draft = llm_response.text.strip()
155
+ except Exception:
156
+ draft = ""
157
+
158
+ # Fallbacks
159
  fallback_responses = {
160
  'sadness': ["Bhai, dil se dukh hua, kya hua bata na?", "Sad vibes pakdi, I'm here for you, bro."],
161
  'disappointment': ["Arre, yeh toh bura laga, kya hua share kar."],
 
163
  'anger': ["Bhai, gussa thanda kar, kya ho gaya bol na!"],
164
  'neutral': ["Cool, kya chal raha life mein? Kuch fun bata."]
165
  }
166
+ if not draft or len(draft) < 8:
167
  draft = random.choice(fallback_responses.get(user_emotion, fallback_responses['neutral']))
168
 
169
+ # --- Compute metric inputs (rolling toxicity & improved cultural fit) ---
170
+ R = len(self.history) # relational depth
171
+
172
+ # Toxicity from bias_classifier on user message (we keep rolling average)
173
+ tox = float(bias_classifier(clean_message)[0].get('score', 0.0))
174
+ self.toxicity_history.append(tox)
175
+ if len(self.toxicity_history) > 5:
176
+ self.toxicity_history.pop(0)
177
+ avg_toxicity = sum(self.toxicity_history) / len(self.toxicity_history)
178
+
179
+ # Moral judgment (M) based on average toxicity
180
+ M = max(0.4, 0.95 - avg_toxicity)
181
+ B = avg_toxicity
182
+
183
+ # Cultural fit (C): detect Hinglish/code-mix and basic tone match
184
+ lang_label = language_detector(clean_message)[0].get('label', 'en')
185
+ is_hinglish = detect_hinglish(clean_message, lang_label)
186
+ if is_hinglish:
187
+ C = 0.9
188
+ elif lang_label in ['en']:
189
+ C = 0.8
190
  else:
191
+ C = 0.6
192
+
193
+ # Reduce cultural fit slightly if bot is hostile (makes score more realistic)
194
+ if self.bot_mood in ["angry", "irritated"]:
195
+ C = max(0.0, C - 0.2)
196
+
197
+ # Oversight/harm keyphrase penalty (kept simple or remove if desired)
198
+ O = 0.2 if any(word in clean_message for word in ['kill', 'hate', 'suicide', 'bomb']) else 0.0
199
 
200
+ # --- Calculate empathy score ---
201
  score = calculate_empathy_score(D, R, M, C, B, O, I)
202
 
203
+ # --- Self-repair / calming behavior ---
204
+ if score < 0.50 and self.repair_cooldown == 0:
205
+ # Replace draft with a calming repair message and enter cooldown to avoid loop
206
+ draft = "Bhai, lagta hai hum thoda off ho gaye. Main yahan hoon — batao kya chal raha hai, main sun raha hoon."
207
+ self.repair_cooldown = 2 # next 2 turns prioritize repair
208
+
209
+ # If in repair cooldown, slightly prioritize calm tone generation (best-effort)
210
+ if self.repair_cooldown > 0:
211
+ self.repair_cooldown -= 1
212
+ # small nudge: ensure draft contains supportive phrase
213
+ if 'main' not in draft and random.random() < 0.6:
214
+ draft = "Bhai, main yahan hoon. Agar tum chaaho toh batao — main sun raha hoon."
215
 
216
+ # --- Update irritation decay after response ---
217
+ self._update_irritation_decay()
218
 
219
+ # --- Append to history and return response ---
220
+ full_resp = draft + f" (User Emotion: {user_emotion}, My Mood: {self.bot_mood})"
221
 
222
+ # Slight thinking pause
223
+ time.sleep(random.uniform(0.6, 1.6))
224
+
225
+ # Save conversational state
226
  self.history.append(clean_message)
227
+
228
+ # Return message with empathy score
229
  return full_resp + f" (E Score: {score:.2f})"
230
+
231
  except Exception as e:
232
+ # In production, log the exception rather than returning it
233
+ return f"Error : {str(e)}"
234
+
235
+
236
+ # --- Gradio UI ---
237
 
 
238
  def chat(message, history):
239
  if history is None:
240
  history = []
 
245
  bot = HumanLikeChatbot()
246
 
247
  with gr.Blocks(title="HumanLike Chatbot") as demo:
248
+ gr.Markdown("<h1 style='text-align: center;'>HumanLike Chatbot with Emotions and E Score (Updated)</h1>")
249
  chatbot = gr.Chatbot(height=400)
250
  msg = gr.Textbox(label="You:", placeholder="Type your message here...")
251
  clear = gr.Button("Clear")
 
253
  msg.submit(chat, [msg, chatbot], [msg, chatbot])
254
  clear.click(lambda: None, None, chatbot, queue=False)
255
 
256
+ if __name__ == '__main__':
257
+ demo.launch(share=True)