pythonprincess commited on
Commit
18f003a
·
verified ·
1 Parent(s): f94a9a7

Delete frontend_pam.py

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