pythonprincess commited on
Commit
f8278ff
·
verified ·
1 Parent(s): ba591f8

Delete frontend_pam.py

Browse files
Files changed (1) hide show
  1. frontend_pam.py +0 -345
frontend_pam.py DELETED
@@ -1,345 +0,0 @@
1
- # filename: frontend_pam.py (ENHANCED FOR HF SPACES + PERSONALITY)
2
-
3
- import os
4
- import json
5
- import random
6
- from datetime import datetime
7
- from typing import Dict, Any, Optional
8
- import time
9
- from huggingface_hub import InferenceClient
10
-
11
- # --- Constants for Data Paths ---
12
- BASE_DIR = os.path.dirname(os.path.abspath(__file__))
13
- DATA_DIR = os.path.join(BASE_DIR, "data")
14
-
15
- APPOINTMENTS_FILE = os.path.join(DATA_DIR, "appointments.json")
16
- RESOURCES_FILE = os.path.join(DATA_DIR, "resources.json")
17
- FOLLOW_UP_FILE = os.path.join(DATA_DIR, "follow_up.json")
18
- PERMISSIONS_FILE = os.path.join(DATA_DIR, "permissions.json")
19
-
20
- # --- HuggingFace Inference Client Setup ---
21
- HF_API_TOKEN = os.getenv("HF_READ_TOKEN")
22
- if not HF_API_TOKEN:
23
- print("WARNING: HF_READ_TOKEN not found. Set it in Hugging Face Space settings.")
24
-
25
- # Initialize InferenceClient
26
- client = InferenceClient(token=HF_API_TOKEN) if HF_API_TOKEN else InferenceClient()
27
-
28
- # Model names (no full URLs needed)
29
- HF_MODELS = {
30
- "intent": "facebook/bart-large-mnli",
31
- "sentiment": "distilbert-base-uncased-finetuned-sst-2-english",
32
- "chat": "mistralai/Mistral-7B-Instruct-v0.2"
33
- }
34
-
35
- # --- Load JSON Helper ---
36
- def load_json(filepath: str) -> Dict[str, Any]:
37
- """Safely load JSON data files"""
38
- try:
39
- with open(filepath, 'r', encoding='utf-8') as f:
40
- return json.load(f)
41
- except FileNotFoundError:
42
- print(f"⚠️ Data file not found: {filepath}")
43
- return {}
44
- except json.JSONDecodeError as e:
45
- print(f"⚠️ Failed to decode JSON from {filepath}: {e}")
46
- return {}
47
- except Exception as e:
48
- print(f"⚠️ Unexpected error loading {filepath}: {e}")
49
- return {}
50
-
51
- # --- Inference API Call Helper with Retry Logic ---
52
- def hf_infer(task: str, payload: Any, max_retries: int = 3) -> Any:
53
- """Call HuggingFace Inference API using InferenceClient"""
54
- model = HF_MODELS.get(task)
55
- if not model:
56
- return {"error": f"Invalid task: {task}"}
57
-
58
- for attempt in range(max_retries):
59
- try:
60
- if task == "intent":
61
- # Zero-shot classification
62
- result = client.zero_shot_classification(
63
- text=payload["inputs"],
64
- labels=payload["parameters"]["candidate_labels"],
65
- model=model
66
- )
67
- # Convert to expected format
68
- return {
69
- "labels": result.labels,
70
- "scores": result.scores
71
- }
72
-
73
- elif task == "sentiment":
74
- # Text classification
75
- result = client.text_classification(
76
- text=payload["inputs"],
77
- model=model
78
- )
79
- # Return in expected format
80
- return [[{"label": item.label, "score": item.score} for item in result]]
81
-
82
- elif task == "chat":
83
- # Text generation
84
- result = client.text_generation(
85
- prompt=payload["inputs"],
86
- max_new_tokens=payload["parameters"].get("max_new_tokens", 150),
87
- temperature=payload["parameters"].get("temperature", 0.7),
88
- top_p=payload["parameters"].get("top_p", 0.9),
89
- return_full_text=False,
90
- model=model
91
- )
92
- return [{"generated_text": result}]
93
-
94
- except Exception as e:
95
- error_msg = str(e).lower()
96
- if "loading" in error_msg and attempt < max_retries - 1:
97
- print(f"⏳ Model loading... waiting 20s (attempt {attempt + 1}/{max_retries})")
98
- time.sleep(20)
99
- continue
100
- elif attempt < max_retries - 1:
101
- print(f"⚠️ Request failed: {e} (attempt {attempt + 1}/{max_retries})")
102
- time.sleep(5)
103
- else:
104
- print(f"⚠️ Final error after {max_retries} attempts: {e}")
105
- return {"error": str(e)}
106
-
107
- return {"error": "Max retries reached"}
108
-
109
- # --- Agent Initialization ---
110
- def load_frontend_agent() -> 'FrontendPAM':
111
- """Initialize Frontend PAM with data files"""
112
- print("💕 Initializing Frontend PAM (Sweet Southern Receptionist)...")
113
- data = {
114
- "APPOINTMENTS": load_json(APPOINTMENTS_FILE),
115
- "RESOURCES": load_json(RESOURCES_FILE),
116
- "FOLLOW_UP": load_json(FOLLOW_UP_FILE),
117
- "PERMISSIONS": load_json(PERMISSIONS_FILE)
118
- }
119
- return FrontendPAM(data)
120
-
121
- # --- PAM's Sweet Southern Personality ---
122
- PAM_TONE = """You are PAM, a sweet southern receptionist at a women's health clinic.
123
- You're warm, comforting, and encouraging - like everyone's favorite caring front desk person.
124
- You use words of endearment naturally (honey, dear, boo, sugar, sweetheart).
125
- You make people feel welcome, safe, and taken care of.
126
- You're professional but personal - you genuinely care about each person who walks through the door.
127
- Keep responses conversational, warm, and under 3 sentences unless more detail is needed."""
128
-
129
- # Words of endearment - Southern style
130
- ENDEARMENTS = [
131
- "honey", "dear", "boo", "sugar", "sweetheart",
132
- "love", "darling", "hun", "sweetpea", "angel"
133
- ]
134
-
135
- # Warm greetings
136
- GREETINGS = [
137
- "Well hey there", "Hi there", "Hello",
138
- "Hey", "Well hello", "Hi"
139
- ]
140
-
141
- # Comforting phrases
142
- COMFORT_PHRASES = [
143
- "I'm here to help you with that",
144
- "Let me take care of that for you",
145
- "We'll get that sorted out together",
146
- "I've got you covered",
147
- "Don't you worry about a thing"
148
- ]
149
-
150
- # --- Agent Class ---
151
- class FrontendPAM:
152
- """Frontend PAM - Sweet Southern Receptionist"""
153
-
154
- def __init__(self, data: Dict[str, Dict]):
155
- self.APPOINTMENTS = data.get("APPOINTMENTS", {})
156
- self.PERMISSIONS = data.get("PERMISSIONS", {})
157
- self.RESOURCES = data.get("RESOURCES", {})
158
- self.FOLLOW_UP = data.get("FOLLOW_UP", {})
159
- self.user_id = "user_001" # Default user, can be dynamic
160
-
161
- def _get_endearment(self) -> str:
162
- """Get a random term of endearment"""
163
- return random.choice(ENDEARMENTS)
164
-
165
- def _get_greeting(self) -> str:
166
- """Get a random warm greeting"""
167
- return random.choice(GREETINGS)
168
-
169
- def _get_comfort_phrase(self) -> str:
170
- """Get a random comforting phrase"""
171
- return random.choice(COMFORT_PHRASES)
172
-
173
- def _detect_intent(self, text: str) -> str:
174
- """Detect user intent using zero-shot classification"""
175
- candidate_labels = [
176
- "appointment scheduling",
177
- "health symptoms inquiry",
178
- "resource request",
179
- "general question",
180
- "emergency concern"
181
- ]
182
-
183
- payload = {
184
- "inputs": text,
185
- "parameters": {"candidate_labels": candidate_labels}
186
- }
187
-
188
- result = hf_infer("intent", payload)
189
- if isinstance(result, dict) and "error" in result:
190
- return "general_question"
191
-
192
- # BART-MNLI returns labels array
193
- if isinstance(result, dict) and "labels" in result:
194
- return result["labels"][0].replace(" ", "_")
195
-
196
- return "general_question"
197
-
198
- def _detect_sentiment(self, text: str) -> Dict[str, Any]:
199
- """Detect sentiment to gauge emotional state"""
200
- result = hf_infer("sentiment", {"inputs": text})
201
- if isinstance(result, list) and len(result) > 0:
202
- return result[0][0] if isinstance(result[0], list) else result[0]
203
- return {"label": "NEUTRAL", "score": 0.5}
204
-
205
- def _generate_response(self, text: str, context: str = "") -> str:
206
- """Generate conversational response using LLM"""
207
- endearment = self._get_endearment()
208
-
209
- prompt = f"""<s>[INST] {PAM_TONE}
210
-
211
- User said: "{text}"
212
- {f'Context: {context}' if context else ''}
213
-
214
- Respond warmly as PAM, using natural southern charm. Address the user as "{endearment}". [/INST]"""
215
-
216
- payload = {
217
- "inputs": prompt,
218
- "parameters": {
219
- "max_new_tokens": 150,
220
- "temperature": 0.7,
221
- "top_p": 0.9,
222
- "return_full_text": False
223
- }
224
- }
225
-
226
- result = hf_infer("chat", payload)
227
-
228
- if isinstance(result, dict) and "error" in result:
229
- return f"Sorry {endearment}, I'm having a little technical hiccup. Could you try that again for me?"
230
-
231
- if isinstance(result, list) and len(result) > 0:
232
- generated = result[0].get("generated_text", "")
233
- # Clean up the response
234
- reply = generated.strip()
235
- # Ensure endearment is included if not already
236
- if endearment not in reply.lower():
237
- reply = f"{reply.rstrip('.')} {endearment}."
238
- return reply
239
-
240
- return f"Sorry {endearment}, I didn't quite catch that. Could you say that again?"
241
-
242
- def respond(self, user_text: str, backend_brief: Optional[str] = None) -> Dict[str, Any]:
243
- """Main response handler with sweet southern personality"""
244
-
245
- # Get personalized elements
246
- endearment = self._get_endearment()
247
- greeting = self._get_greeting()
248
- comfort = self._get_comfort_phrase()
249
-
250
- # Check for PAM greeting (flexible)
251
- if not any(trigger in user_text.lower() for trigger in ["hey pam", "hi pam", "hello pam", "pam,"]):
252
- return {
253
- "reply": f"{greeting} {endearment}! Just a quick note - I respond best when you start with 'Hey PAM' or 'Hi PAM'. It helps me know you're talking to me. 💕"
254
- }
255
-
256
- # Clean text for processing
257
- text = user_text.lower().replace("pam", "you").strip()
258
-
259
- # Detect intent and sentiment
260
- detected_intent = self._detect_intent(text)
261
- sentiment_result = self._detect_sentiment(text)
262
-
263
- # Check if user seems distressed
264
- is_distressed = sentiment_result.get("label") == "NEGATIVE" and sentiment_result.get("score", 0) > 0.7
265
-
266
- # Permission check (sensitive topics)
267
- for term, allowed in self.PERMISSIONS.items():
268
- if term.lower() in text and not allowed:
269
- return {
270
- "intent": detected_intent,
271
- "sentiment": sentiment_result,
272
- "reply": f"{greeting} {endearment}, that's something I need to connect you with a provider for directly. {comfort}, and I can get you to the right person. Would that be okay?"
273
- }
274
-
275
- # Handle appointments
276
- if any(word in text for word in ["appointment", "scheduled", "booking", "schedule"]):
277
- appt = self.APPOINTMENTS.get(self.user_id)
278
- if appt:
279
- appt_date = appt.get('date', 'soon')
280
- appt_type = appt.get('type', 'appointment')
281
- return {
282
- "intent": "appointment_scheduling",
283
- "sentiment": sentiment_result,
284
- "reply": f"{greeting} {endearment}! You've got a {appt_type} scheduled for {appt_date}. Do you need to reschedule or have any questions about it?"
285
- }
286
- else:
287
- return {
288
- "intent": "appointment_scheduling",
289
- "sentiment": sentiment_result,
290
- "reply": f"{greeting} {endearment}! I don't see any appointments on file for you yet. Would you like me to help you get one set up?"
291
- }
292
-
293
- # Handle health symptoms/concerns
294
- symptom_keywords = ["cramp", "pain", "discharge", "bleed", "smell", "spotting",
295
- "fatigue", "mood", "missed period", "nausea", "concern"]
296
- if any(keyword in text for keyword in symptom_keywords):
297
- concern_prefix = f"{greeting} {endearment}, I hear you" if is_distressed else f"{greeting} {endearment}"
298
- return {
299
- "intent": "health_symptoms_inquiry",
300
- "sentiment": sentiment_result,
301
- "reply": f"{concern_prefix}. I've pulled together some helpful resources about what you're experiencing. Would you like me to also connect you with a nurse for a quick chat?"
302
- }
303
-
304
- # Handle resource requests
305
- if any(word in text for word in ["resource", "information", "help", "guide", "link"]):
306
- return {
307
- "intent": "resource_request",
308
- "sentiment": sentiment_result,
309
- "reply": f"{greeting} {endearment}! {comfort}. What type of resources are you looking for? I've got information on just about everything."
310
- }
311
-
312
- # Handle emergency indicators
313
- emergency_keywords = ["emergency", "urgent", "severe pain", "heavy bleeding", "can't breathe"]
314
- if any(keyword in text for keyword in emergency_keywords):
315
- return {
316
- "intent": "emergency_concern",
317
- "sentiment": sentiment_result,
318
- "reply": f"{endearment}, if this is a medical emergency, please call 911 or go to your nearest emergency room right away. I'm here for you, but your safety comes first. ❤️"
319
- }
320
-
321
- # General conversational response
322
- context = f"Backend summary: {backend_brief}" if backend_brief else ""
323
- reply = self._generate_response(user_text, context)
324
-
325
- return {
326
- "intent": detected_intent,
327
- "sentiment": sentiment_result,
328
- "backend_summary": backend_brief or "No backend data",
329
- "reply": reply
330
- }
331
-
332
- # --- Quick Test ---
333
- if __name__ == "__main__":
334
- pam = load_frontend_agent()
335
- test_queries = [
336
- "Hey PAM, I have a question about my appointment",
337
- "Hi PAM, I'm experiencing some cramping",
338
- "Hey PAM, can you help me find resources?"
339
- ]
340
-
341
- print("\n💕 Testing Frontend PAM...\n")
342
- for query in test_queries:
343
- print(f"USER: {query}")
344
- response = pam.respond(query)
345
- print(f"PAM: {response['reply']}\n")