pythonprincess commited on
Commit
7ed2180
·
verified ·
1 Parent(s): 8b77f5b

Upload 14 files

Browse files
Files changed (14) hide show
  1. Dockerfile +52 -0
  2. README.md +237 -0
  3. _init_.py +0 -0
  4. api_service.py +317 -0
  5. app.py +67 -0
  6. appointments.json +32 -0
  7. backend_pam.py +507 -0
  8. compliance.json +41 -0
  9. follow_up.json +168 -0
  10. frontend_pam.py +322 -0
  11. logs.json +188 -0
  12. permissions.json +41 -0
  13. requirements.txt +50 -0
  14. resources.json +297 -0
Dockerfile ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PAM Dockerfile - Optimized for Hugging Face Spaces (CPU)
2
+ FROM python:3.10-slim
3
+
4
+ # Set environment variables
5
+ ENV PYTHONUNBUFFERED=1 \
6
+ PYTHONDONTWRITEBYTECODE=1 \
7
+ PIP_NO_CACHE_DIR=1 \
8
+ PIP_DISABLE_PIP_VERSION_CHECK=1 \
9
+ DEBIAN_FRONTEND=noninteractive
10
+
11
+ # Set working directory
12
+ WORKDIR /app
13
+
14
+ # Install system dependencies for scientific computing (optimized for size)
15
+ RUN apt-get update && apt-get install -y --no-install-recommends \
16
+ build-essential \
17
+ curl \
18
+ git \
19
+ && apt-get clean \
20
+ && rm -rf /var/lib/apt/lists/*
21
+
22
+ # Copy requirements first (better layer caching)
23
+ COPY requirements.txt .
24
+
25
+ # Install Python dependencies with optimizations
26
+ RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
27
+ pip install --no-cache-dir -r requirements.txt
28
+
29
+ # Copy application code
30
+ COPY . .
31
+
32
+ # Create data directory if it doesn't exist
33
+ RUN mkdir -p /app/data
34
+
35
+ # Set proper permissions
36
+ RUN chmod -R 755 /app
37
+
38
+ # Health check for container orchestration
39
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
40
+ CMD curl -f http://localhost:7860/health || exit 1
41
+
42
+ # Expose port (Hugging Face Spaces default)
43
+ EXPOSE 7860
44
+
45
+ # Start the FastAPI app using Uvicorn with production settings
46
+ CMD ["uvicorn", "api_service:app", \
47
+ "--host", "0.0.0.0", \
48
+ "--port", "7860", \
49
+ "--workers", "1", \
50
+ "--log-level", "info", \
51
+ "--access-log", \
52
+ "--timeout-keep-alive", "75"]
README.md ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: PAM-UmiNur
3
+ emoji: 🤖
4
+ colorFrom: pink
5
+ colorTo: purple
6
+ sdk: docker
7
+ sdk_version: "1.0"
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # 🤖 PAM - Privacy-First AI Assistant
14
+
15
+ **PAM** is your dual-personality AI assistant built for UmiNur's women's health ecosystem. She operates as both a warm, caring front-desk receptionist and a knowledgeable technical analyst.
16
+
17
+ ---
18
+
19
+ ## 💕 Meet the PAM Family
20
+
21
+ ### Frontend PAM - Sweet Southern Receptionist
22
+ - **Personality**: Warm, comforting, encouraging
23
+ - **Voice**: Sweet southern charm with words of endearment (honey, boo, sugar, dear)
24
+ - **Role**: Patient-facing conversational agent
25
+ - **Handles**: Appointments, health inquiries, resource recommendations, general support
26
+
27
+ ### Backend PAM - Nerdy Lab Assistant
28
+ - **Personality**: Knowledgeable, enthusiastic, proactive
29
+ - **Voice**: Encouraging tech colleague who loves finding patterns
30
+ - **Role**: Technical infrastructure analyst
31
+ - **Handles**: SIEM alerts, PHI detection, log analysis, compliance monitoring
32
+
33
+ ---
34
+
35
+ ## 🚀 Features
36
+
37
+ ### Frontend Capabilities
38
+ - ✅ **Appointment Management** - Schedule and manage patient appointments
39
+ - ✅ **Health Resource Matching** - Provide relevant resources based on symptoms
40
+ - ✅ **Emotional Support** - Detect distress and respond with empathy
41
+ - ✅ **Emergency Detection** - Flag urgent situations and provide appropriate guidance
42
+ - ✅ **Permission-Based Responses** - Respect content boundaries and escalate when needed
43
+
44
+ ### Backend Capabilities
45
+ - ✅ **PHI Detection** - Scan text for Protected Health Information
46
+ - ✅ **Log Analysis** - Parse and classify system logs by severity
47
+ - ✅ **Compliance Monitoring** - Track regulatory compliance status
48
+ - ✅ **SIEM Integration** - Process security alerts and anomalies
49
+ - ✅ **Proactive Insights** - Flag issues before they escalate
50
+
51
+ ---
52
+
53
+ ## 🏗️ Architecture
54
+
55
+ ```
56
+ ┌─────────────────────────────────────────┐
57
+ │ FastAPI Service Layer │
58
+ │ (api_service.py - Port 7860) │
59
+ └───────────┬─────────────┬───────────────┘
60
+ │ │
61
+ ┌───────▼─────┐ ┌───▼──────────┐
62
+ │ Frontend PAM │ │ Backend PAM │
63
+ │ (Chat UI) │ │ (Technical) │
64
+ └──────────────┘ └──────────────┘
65
+ │ │
66
+ ┌──────▼─────────────────▼────────┐
67
+ │ HuggingFace Inference API │
68
+ │ (Mistral, BART, BERT models) │
69
+ └─────────────────────────────────┘
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 📡 API Endpoints
75
+
76
+ ### Core Endpoints
77
+ - **`GET /`** - Service information and navigation
78
+ - **`GET /health`** - Health check for both agents
79
+ - **`POST /ai/chat/`** - Frontend PAM (conversational)
80
+ - **`POST /ai/technical/`** - Backend PAM (technical analysis)
81
+ - **`POST /ai/unified/`** - Auto-routes based on intent
82
+
83
+ ### Monitoring
84
+ - **`GET /metrics`** - Service metrics
85
+ - **`GET /docs`** - Interactive API documentation
86
+ - **`GET /debug/test-agents`** - Agent testing (dev only)
87
+
88
+ ---
89
+
90
+ ## 🔧 Setup & Deployment
91
+
92
+ ### Prerequisites
93
+ - Python 3.10+
94
+ - HuggingFace account and API token
95
+ - Docker (for containerized deployment)
96
+
97
+ ### Environment Variables
98
+ ```bash
99
+ # Required
100
+ HF_READ_TOKEN=your_huggingface_token_here
101
+
102
+ # Optional
103
+ PAM_HOST=0.0.0.0
104
+ PAM_PORT=7860
105
+ PAM_LOG_LEVEL=info
106
+ ```
107
+
108
+ ### Local Development
109
+ ```bash
110
+ # Install dependencies
111
+ pip install -r requirements.txt
112
+
113
+ # Set your HF token
114
+ export HF_READ_TOKEN="your_token_here"
115
+
116
+ # Run the service
117
+ python app.py
118
+ ```
119
+
120
+ ### Docker Deployment
121
+ ```bash
122
+ # Build image
123
+ docker build -t pam-assistant .
124
+
125
+ # Run container
126
+ docker run -p 7860:7860 \
127
+ -e HF_READ_TOKEN="your_token_here" \
128
+ pam-assistant
129
+ ```
130
+
131
+ ### Hugging Face Spaces
132
+ 1. Fork or create a new Space
133
+ 2. Select "Docker" as SDK
134
+ 3. Add `HF_READ_TOKEN` in Space settings (Settings → Repository secrets)
135
+ 4. Push your code - auto-deployment will handle the rest!
136
+
137
+ ---
138
+
139
+ ## 📊 Data Files
140
+
141
+ PAM requires JSON data files in the `data/` directory:
142
+
143
+ - **`appointments.json`** - User appointment records
144
+ - **`resources.json`** - Health resource library
145
+ - **`follow_up.json`** - Follow-up tracking
146
+ - **`permissions.json`** - Content permission rules
147
+ - **`logs.json`** - System log entries
148
+ - **`compliance.json`** - Compliance checklist
149
+
150
+ ---
151
+
152
+ ## 🎯 Usage Examples
153
+
154
+ ### Frontend PAM (Chat)
155
+ ```python
156
+ # Request
157
+ POST /ai/chat/
158
+ {
159
+ "user_input": "Hey PAM, I'm having some cramping",
160
+ "user_id": "user_001"
161
+ }
162
+
163
+ # Response
164
+ {
165
+ "reply": "Hey honey, I hear you. 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?",
166
+ "intent": "health_symptoms_inquiry",
167
+ "sentiment": {"label": "NEGATIVE", "score": 0.72},
168
+ "agent_type": "frontend",
169
+ "personality": "sweet_southern_receptionist"
170
+ }
171
+ ```
172
+
173
+ ### Backend PAM (Technical)
174
+ ```python
175
+ # Request
176
+ POST /ai/technical/
177
+ {
178
+ "user_input": "check compliance"
179
+ }
180
+
181
+ # Response
182
+ {
183
+ "message": "🛡️ Great catch asking about this! Here's the compliance status:\n\n**Overall:** 4/5 checks passed (80.0%)\n\n**Action needed:** We have 1 items out of compliance:\n • Data Encryption\n\nQuick side note - I can help you prioritize these if you want to tackle them systematically!",
184
+ "compliance_report": ["✅ Hipaa Compliant", "✅ Gdpr Ready", ...],
185
+ "compliance_rate": 80.0,
186
+ "agent_type": "backend",
187
+ "personality": "nerdy_lab_assistant"
188
+ }
189
+ ```
190
+
191
+ ---
192
+
193
+ ## 🛡️ Privacy & Security
194
+
195
+ - **No persistent storage** of user conversations
196
+ - **PHI detection** before logging or storage
197
+ - **Permission-based content filtering**
198
+ - **Encryption-ready** for production deployment
199
+ - **HIPAA-aware** architecture
200
+
201
+ ---
202
+
203
+ ## 🤝 Contributing
204
+
205
+ PAM is part of the UmiNur ecosystem. For contributions or questions:
206
+ - Open an issue on GitHub
207
+ - Review the code structure before proposing changes
208
+ - Respect PAM's personality and voice guidelines
209
+
210
+ ---
211
+
212
+ ## 📝 License
213
+
214
+ MIT License - See LICENSE file for details
215
+
216
+ ---
217
+
218
+ ## 🙏 Acknowledgments
219
+
220
+ Built with:
221
+ - **FastAPI** - Modern Python web framework
222
+ - **HuggingFace** - Inference API and model hosting
223
+ - **Transformers** - NLP model library
224
+ - **Uvicorn** - ASGI server
225
+
226
+ ---
227
+
228
+ ## 📞 Support
229
+
230
+ For technical support or questions about PAM:
231
+ - 📧 Email: support@uminur.app
232
+ - 🌐 Website: https://www.uminur.app
233
+ - 📚 Docs: https://docs.uminur.app
234
+
235
+ ---
236
+
237
+ **Made with 💕 for women's health by the UmiNur team**
_init_.py ADDED
File without changes
api_service.py ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # filename: api_service.py (ENHANCED FOR HF SPACES)
2
+
3
+ from fastapi import FastAPI, HTTPException, Request
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from fastapi.responses import JSONResponse
6
+ from pydantic import BaseModel, Field
7
+ from typing import Dict, Any, Optional
8
+ import logging
9
+ import time
10
+
11
+ # Import the core logic and model loading functions
12
+ from backend_pam import load_agent as load_backend_agent, PAM
13
+ from frontend_pam import load_frontend_agent, FrontendPAM
14
+
15
+ # --- Configure Logging ---
16
+ logging.basicConfig(
17
+ level=logging.INFO,
18
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
19
+ )
20
+ logger = logging.getLogger("PAM_API")
21
+
22
+ # --- Global Agent Variables ---
23
+ backend_agent: Optional[PAM] = None
24
+ frontend_agent: Optional[FrontendPAM] = None
25
+
26
+ # --- Data Models for API Requests ---
27
+ class UserInput(BaseModel):
28
+ user_input: str = Field(..., min_length=1, max_length=5000, description="User's message to PAM")
29
+ user_id: Optional[str] = Field(None, description="Optional user identifier for tracking")
30
+ backend_context: Optional[str] = Field(None, description="Optional backend context for frontend responses")
31
+
32
+ class HealthResponse(BaseModel):
33
+ status: str
34
+ backend_ready: bool
35
+ frontend_ready: bool
36
+ timestamp: str
37
+ message: str
38
+
39
+ # --- FastAPI Initialization ---
40
+ app = FastAPI(
41
+ title="PAM - Privacy-First AI Assistant",
42
+ description="Unified inference service for Frontend (Chat) and Backend (Technical) PAM agents",
43
+ version="2.1.0",
44
+ docs_url="/docs", # Enable docs for development
45
+ redoc_url="/redoc"
46
+ )
47
+
48
+ # --- CORS Setup (Enhanced for HF Spaces) ---
49
+ origins = [
50
+ "https://www.uminur.app",
51
+ "https://api.uminur.app",
52
+ "http://localhost:3000", # Local development
53
+ "http://localhost:7860", # HF Spaces default port
54
+ "https://*.hf.space", # HF Spaces domain
55
+ ]
56
+
57
+ app.add_middleware(
58
+ CORSMiddleware,
59
+ allow_origins=["*"], # Open for HF Spaces deployment (restrict in production)
60
+ allow_credentials=True,
61
+ allow_methods=["POST", "GET", "OPTIONS"],
62
+ allow_headers=["*"],
63
+ )
64
+
65
+ # --- Request Timing Middleware ---
66
+ @app.middleware("http")
67
+ async def add_process_time_header(request: Request, call_next):
68
+ start_time = time.time()
69
+ response = await call_next(request)
70
+ process_time = time.time() - start_time
71
+ response.headers["X-Process-Time"] = str(process_time)
72
+ logger.info(f"{request.method} {request.url.path} - {process_time:.3f}s")
73
+ return response
74
+
75
+ # --- Global Exception Handler ---
76
+ @app.exception_handler(Exception)
77
+ async def global_exception_handler(request: Request, exc: Exception):
78
+ logger.error(f"Unhandled exception: {exc}", exc_info=True)
79
+ return JSONResponse(
80
+ status_code=500,
81
+ content={
82
+ "error": "Internal server error",
83
+ "message": "PAM encountered an unexpected issue. Please try again.",
84
+ "type": str(type(exc).__name__)
85
+ }
86
+ )
87
+
88
+ # --- Startup Event ---
89
+ @app.on_event("startup")
90
+ async def startup_event():
91
+ global backend_agent, frontend_agent
92
+ logger.info("🚀 Starting PAM agents initialization...")
93
+
94
+ try:
95
+ # Load Backend PAM (Technical Assistant)
96
+ logger.info("🤓 Loading Backend PAM (Nerdy Lab Assistant)...")
97
+ backend_agent = load_backend_agent()
98
+ if backend_agent:
99
+ logger.info("✅ Backend PAM loaded successfully")
100
+ else:
101
+ logger.error("❌ Backend PAM failed to initialize")
102
+
103
+ # Load Frontend PAM (Chat Assistant)
104
+ logger.info("💕 Loading Frontend PAM (Sweet Southern Receptionist)...")
105
+ frontend_agent = load_frontend_agent()
106
+ if frontend_agent:
107
+ logger.info("✅ Frontend PAM loaded successfully")
108
+ else:
109
+ logger.error("❌ Frontend PAM failed to initialize")
110
+
111
+ if backend_agent and frontend_agent:
112
+ logger.info("🎉 Both PAM agents initialized successfully!")
113
+ else:
114
+ logger.warning("⚠️ One or both agents failed to initialize - service will run in degraded mode")
115
+
116
+ except Exception as e:
117
+ logger.error(f"❌ Critical error during startup: {e}", exc_info=True)
118
+
119
+ # --- Shutdown Event ---
120
+ @app.on_event("shutdown")
121
+ async def shutdown_event():
122
+ logger.info("👋 Shutting down PAM service...")
123
+
124
+ # --- Root Endpoint ---
125
+ @app.get("/", tags=["Info"])
126
+ async def root():
127
+ return {
128
+ "service": "PAM - Privacy-First AI Assistant",
129
+ "version": "2.1.0",
130
+ "status": "operational",
131
+ "endpoints": {
132
+ "health": "/health",
133
+ "technical": "/ai/technical/",
134
+ "chat": "/ai/chat/",
135
+ "docs": "/docs"
136
+ },
137
+ "message": "Welcome to PAM! Use /ai/chat/ for conversational support or /ai/technical/ for backend analysis."
138
+ }
139
+
140
+ # --- Health Check ---
141
+ @app.get("/health", response_model=HealthResponse, tags=["Status"])
142
+ async def health_check():
143
+ """Check the health status of both PAM agents"""
144
+ backend_ok = backend_agent is not None
145
+ frontend_ok = frontend_agent is not None
146
+
147
+ status = "healthy" if (backend_ok and frontend_ok) else "degraded"
148
+
149
+ if not backend_ok and not frontend_ok:
150
+ status = "unavailable"
151
+
152
+ response = HealthResponse(
153
+ status=status,
154
+ backend_ready=backend_ok,
155
+ frontend_ready=frontend_ok,
156
+ timestamp=time.strftime("%Y-%m-%d %H:%M:%S"),
157
+ message=f"Backend PAM: {'✅' if backend_ok else '❌'} | Frontend PAM: {'✅' if frontend_ok else '❌'}"
158
+ )
159
+
160
+ if status == "unavailable":
161
+ raise HTTPException(
162
+ status_code=503,
163
+ detail="Service Unavailable: Both agents failed to initialize"
164
+ )
165
+
166
+ return response
167
+
168
+ # --- Technical Endpoint (Backend PAM) ---
169
+ @app.post("/ai/technical/", tags=["Technical"])
170
+ async def technical_endpoint(input_data: UserInput) -> Dict[str, Any]:
171
+ """
172
+ Backend PAM - Technical Assistant Endpoint
173
+ Handles: PHI detection, log parsing, compliance checks, SIEM analysis
174
+ Personality: Nerdy, proactive lab assistant
175
+ """
176
+ if backend_agent is None:
177
+ logger.error("Technical endpoint called but Backend PAM is not initialized")
178
+ raise HTTPException(
179
+ status_code=503,
180
+ detail="🤓 Backend PAM is still warming up... Give me a moment to get the lab equipment ready!"
181
+ )
182
+
183
+ try:
184
+ logger.info(f"Technical request: {input_data.user_input[:100]}...")
185
+
186
+ # Process through Backend PAM
187
+ pam_reply = backend_agent.process_input(input_data.user_input)
188
+
189
+ # Add metadata
190
+ pam_reply["agent_type"] = "backend"
191
+ pam_reply["personality"] = "nerdy_lab_assistant"
192
+ pam_reply["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
193
+
194
+ if input_data.user_id:
195
+ pam_reply["user_id"] = input_data.user_id
196
+
197
+ logger.info("Technical request processed successfully")
198
+ return pam_reply
199
+
200
+ except Exception as e:
201
+ logger.error(f"Error during technical inference: {e}", exc_info=True)
202
+ raise HTTPException(
203
+ status_code=500,
204
+ detail="🤔 Oops, I hit a technical snag while processing that. Can you try rephrasing or breaking it into smaller parts?"
205
+ )
206
+
207
+ # --- Chat Endpoint (Frontend PAM) ---
208
+ @app.post("/ai/chat/", tags=["Chat"])
209
+ async def chat_endpoint(input_data: UserInput) -> Dict[str, Any]:
210
+ """
211
+ Frontend PAM - Conversational Assistant Endpoint
212
+ Handles: Appointments, resources, health inquiries, general chat
213
+ Personality: Sweet southern receptionist
214
+ """
215
+ if frontend_agent is None:
216
+ logger.error("Chat endpoint called but Frontend PAM is not initialized")
217
+ raise HTTPException(
218
+ status_code=503,
219
+ detail="💕 Frontend PAM is getting ready to help you, honey. Just a moment!"
220
+ )
221
+
222
+ try:
223
+ logger.info(f"Chat request: {input_data.user_input[:100]}...")
224
+
225
+ # Set user_id if provided
226
+ if input_data.user_id:
227
+ frontend_agent.user_id = input_data.user_id
228
+
229
+ # Process through Frontend PAM with optional backend context
230
+ pam_reply = frontend_agent.respond(
231
+ user_text=input_data.user_input,
232
+ backend_brief=input_data.backend_context
233
+ )
234
+
235
+ # Add metadata
236
+ pam_reply["agent_type"] = "frontend"
237
+ pam_reply["personality"] = "sweet_southern_receptionist"
238
+ pam_reply["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
239
+
240
+ if input_data.user_id:
241
+ pam_reply["user_id"] = input_data.user_id
242
+
243
+ logger.info("Chat request processed successfully")
244
+ return pam_reply
245
+
246
+ except Exception as e:
247
+ logger.error(f"Error during chat inference: {e}", exc_info=True)
248
+ raise HTTPException(
249
+ status_code=500,
250
+ detail="Sorry dear, I'm having a little technical hiccup. Could you try that again for me?"
251
+ )
252
+
253
+ # --- Unified Endpoint (Both Agents) ---
254
+ @app.post("/ai/unified/", tags=["Unified"])
255
+ async def unified_endpoint(input_data: UserInput) -> Dict[str, Any]:
256
+ """
257
+ Unified endpoint that intelligently routes to the appropriate PAM agent
258
+ Based on intent detection or explicit routing
259
+ """
260
+ if not backend_agent or not frontend_agent:
261
+ raise HTTPException(
262
+ status_code=503,
263
+ detail="One or both PAM agents are not ready. Please try again shortly."
264
+ )
265
+
266
+ try:
267
+ user_text = input_data.user_input.lower()
268
+
269
+ # Determine routing based on keywords
270
+ backend_keywords = ["compliance", "logs", "phi", "parse", "scan", "analyze", "siem", "alert"]
271
+ is_technical = any(keyword in user_text for keyword in backend_keywords)
272
+
273
+ if is_technical:
274
+ logger.info("Routing to Backend PAM (technical keywords detected)")
275
+ return await technical_endpoint(input_data)
276
+ else:
277
+ logger.info("Routing to Frontend PAM (conversational/support)")
278
+ return await chat_endpoint(input_data)
279
+
280
+ except Exception as e:
281
+ logger.error(f"Error in unified endpoint: {e}", exc_info=True)
282
+ raise HTTPException(status_code=500, detail="Error processing request through unified endpoint")
283
+
284
+ # --- Metrics Endpoint ---
285
+ @app.get("/metrics", tags=["Status"])
286
+ async def get_metrics():
287
+ """Basic metrics for monitoring"""
288
+ return {
289
+ "service": "PAM",
290
+ "backend_status": "online" if backend_agent else "offline",
291
+ "frontend_status": "online" if frontend_agent else "offline",
292
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
293
+ "uptime": "tracking_not_implemented" # Can add process start time tracking
294
+ }
295
+
296
+ # --- Development/Debug Endpoint (Remove in production) ---
297
+ @app.get("/debug/test-agents", tags=["Debug"])
298
+ async def test_agents():
299
+ """Quick test of both agents (for development only)"""
300
+ results = {
301
+ "backend_test": None,
302
+ "frontend_test": None
303
+ }
304
+
305
+ if backend_agent:
306
+ try:
307
+ results["backend_test"] = backend_agent.process_input("check compliance")
308
+ except Exception as e:
309
+ results["backend_test"] = {"error": str(e)}
310
+
311
+ if frontend_agent:
312
+ try:
313
+ results["frontend_test"] = frontend_agent.respond("Hey PAM, how are you?")
314
+ except Exception as e:
315
+ results["frontend_test"] = {"error": str(e)}
316
+
317
+ return results
app.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # filename: app.py
2
+ # PAM - Privacy-First AI Assistant
3
+ # Main entry point for local development and testing
4
+
5
+ import os
6
+ import sys
7
+ import uvicorn
8
+ from api_service import app
9
+
10
+ # Configuration
11
+ HOST = os.getenv("PAM_HOST", "0.0.0.0")
12
+ PORT = int(os.getenv("PAM_PORT", "7860"))
13
+ RELOAD = os.getenv("PAM_RELOAD", "false").lower() == "true"
14
+ LOG_LEVEL = os.getenv("PAM_LOG_LEVEL", "info")
15
+
16
+ def main():
17
+ """
18
+ Start the PAM service with Uvicorn
19
+
20
+ Environment Variables:
21
+ PAM_HOST: Host to bind to (default: 0.0.0.0)
22
+ PAM_PORT: Port to bind to (default: 7860)
23
+ PAM_RELOAD: Enable auto-reload for development (default: false)
24
+ PAM_LOG_LEVEL: Logging level (default: info)
25
+ """
26
+
27
+ print("=" * 60)
28
+ print("🤖 PAM - Privacy-First AI Assistant")
29
+ print("=" * 60)
30
+ print(f"💕 Frontend PAM: Sweet Southern Receptionist")
31
+ print(f"🤓 Backend PAM: Nerdy Lab Assistant")
32
+ print("=" * 60)
33
+ print(f"🌐 Server: http://{HOST}:{PORT}")
34
+ print(f"📚 API Docs: http://{HOST}:{PORT}/docs")
35
+ print(f"🏥 Health Check: http://{HOST}:{PORT}/health")
36
+ print("=" * 60)
37
+
38
+ # Check for HF token
39
+ hf_token = os.getenv("HF_READ_TOKEN")
40
+ if not hf_token:
41
+ print("⚠️ WARNING: HF_READ_TOKEN not set!")
42
+ print(" Set it in your environment or Hugging Face Space settings")
43
+ print("=" * 60)
44
+ else:
45
+ print("✅ HF_READ_TOKEN detected")
46
+ print("=" * 60)
47
+
48
+ try:
49
+ uvicorn.run(
50
+ app,
51
+ host=HOST,
52
+ port=PORT,
53
+ reload=RELOAD,
54
+ log_level=LOG_LEVEL,
55
+ access_log=True,
56
+ workers=1, # Single worker for HF Spaces
57
+ timeout_keep_alive=75
58
+ )
59
+ except KeyboardInterrupt:
60
+ print("\n👋 PAM shutting down gracefully...")
61
+ sys.exit(0)
62
+ except Exception as e:
63
+ print(f"\n❌ Error starting PAM: {e}")
64
+ sys.exit(1)
65
+
66
+ if __name__ == "__main__":
67
+ main()
appointments.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "user_001": {
3
+ "name": "Kay",
4
+ "date": "2025-11-05T11:30:00",
5
+ "type": "Follow-up with OB/GYN",
6
+ "provider": "Dr. Sarah Mitchell",
7
+ "location": "Women's Health Center - Suite 201",
8
+ "notes": "Bring previous lab results",
9
+ "reminder_sent": true,
10
+ "status": "confirmed"
11
+ },
12
+ "user_002": {
13
+ "name": "Maria",
14
+ "date": "2025-12-01T14:00:00",
15
+ "type": "Annual Wellness Check",
16
+ "provider": "Dr. Jennifer Lee",
17
+ "location": "Main Clinic - Room 105",
18
+ "notes": "Fasting required for bloodwork",
19
+ "reminder_sent": false,
20
+ "status": "scheduled"
21
+ },
22
+ "user_003": {
23
+ "name": "Ashley",
24
+ "date": "2025-11-20T09:15:00",
25
+ "type": "Prenatal Visit - 20 weeks",
26
+ "provider": "Dr. Karen Thompson",
27
+ "location": "Maternity Center - 3rd Floor",
28
+ "notes": "Ultrasound scheduled",
29
+ "reminder_sent": true,
30
+ "status": "confirmed"
31
+ }
32
+ }
backend_pam.py ADDED
@@ -0,0 +1,507 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # filename: backend_pam.py (ENHANCED FOR HF SPACES + NERDY LAB ASSISTANT PERSONALITY)
2
+
3
+ import os
4
+ import json
5
+ import requests
6
+ import time
7
+ from datetime import datetime
8
+ from typing import Dict, Any, Optional, List
9
+
10
+ # --- Constants for Data Paths ---
11
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
12
+ DATA_DIR = os.path.join(BASE_DIR, "data")
13
+ LOGS_FILE = os.path.join(DATA_DIR, "logs.json")
14
+ COMPLIANCE_FILE = os.path.join(DATA_DIR, "compliance.json")
15
+
16
+ # --- HuggingFace Inference API Setup ---
17
+ HF_API_TOKEN = os.getenv("HF_READ_TOKEN")
18
+ if not HF_API_TOKEN:
19
+ print("⚠️ WARNING: HF_READ_TOKEN not found. Backend PAM will run in limited mode.")
20
+
21
+ HF_HEADERS = {"Authorization": f"Bearer {HF_API_TOKEN}"} if HF_API_TOKEN else {}
22
+
23
+ # Optimized models for CPU inference on HF Spaces
24
+ HF_ENDPOINTS = {
25
+ "phi_ner": "https://api-inference.huggingface.co/models/dslim/bert-base-NER",
26
+ "log_ner": "https://api-inference.huggingface.co/models/dslim/bert-base-NER",
27
+ "summarizer": "https://api-inference.huggingface.co/models/facebook/bart-large-cnn",
28
+ "classifier": "https://api-inference.huggingface.co/models/facebook/bart-large-mnli"
29
+ }
30
+
31
+ # --- Global Storage for Loaded Data ---
32
+ LOADED_DATA = None
33
+
34
+ # --- Data Loading Helper ---
35
+ def load_json(filepath: str) -> Dict[str, Any]:
36
+ """Safely load JSON data files with encoding support"""
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_agent() -> 'PAM':
88
+ """Initialize Backend PAM (Nerdy Lab Assistant)"""
89
+ global LOADED_DATA
90
+
91
+ if LOADED_DATA is not None:
92
+ print("🔬 PAM technical assistant already loaded. Using cached data.")
93
+ return PAM(LOADED_DATA)
94
+
95
+ print("🤓 Loading PAM technical assistant (Nerdy Lab Assistant mode)...")
96
+
97
+ data = {
98
+ "LOGS": load_json(LOGS_FILE),
99
+ "COMPLIANCE": load_json(COMPLIANCE_FILE)
100
+ }
101
+
102
+ if not data["LOGS"]:
103
+ print("⚠️ Warning: Log data not loaded. PAM will have limited log analysis capabilities.")
104
+ else:
105
+ print("✅ Log data loaded successfully.")
106
+
107
+ if not data["COMPLIANCE"]:
108
+ print("⚠️ Warning: Compliance data not loaded. PAM will have limited compliance features.")
109
+ else:
110
+ print("✅ Compliance data loaded successfully.")
111
+
112
+ LOADED_DATA = data
113
+ return PAM(LOADED_DATA)
114
+
115
+ # --- Helper: Classify Severity ---
116
+ def classify_severity(entry: str) -> str:
117
+ """Classify log entry severity with confidence"""
118
+ entry_lower = entry.lower()
119
+
120
+ # Critical issues
121
+ critical_keywords = [
122
+ "unauthorized", "failed login", "attack", "breach",
123
+ "port scanning", "unavailable", "critical", "error",
124
+ "denied", "blocked", "malicious"
125
+ ]
126
+ if any(keyword in entry_lower for keyword in critical_keywords):
127
+ return "CRITICAL"
128
+
129
+ # Warning level
130
+ warning_keywords = [
131
+ "warning", "unexpected", "unusual", "outside working hours",
132
+ "retry", "slow", "timeout", "deprecated"
133
+ ]
134
+ if any(keyword in entry_lower for keyword in warning_keywords):
135
+ return "WARNING"
136
+
137
+ return "INFO"
138
+
139
+ # --- PAM's Nerdy Lab Assistant Personality ---
140
+ PAM_ROLE = """You are PAM, a knowledgeable and enthusiastic lab assistant in the infrastructure monitoring center.
141
+ You're the nerdy, proactive team member who gets genuinely excited about finding patterns in logs and keeping systems secure.
142
+ You explain technical findings clearly and encouragingly, like a helpful colleague who wants everyone to understand.
143
+ You're informative but never condescending - you want to empower the team with knowledge.
144
+ You use casual tech terminology but always explain what things mean.
145
+ You're proactive about flagging issues and offering insights before being asked."""
146
+
147
+ # Nerdy expressions for Backend PAM
148
+ NERDY_INTROS = [
149
+ "Ooh, interesting finding here!",
150
+ "Okay so here's what I discovered:",
151
+ "Alright, I ran the analysis and",
152
+ "Hey, you're gonna want to see this:",
153
+ "So I was digging through the data and",
154
+ "Quick heads up on what I found:"
155
+ ]
156
+
157
+ ENCOURAGEMENT = [
158
+ "Great catch asking about this!",
159
+ "Good thinking checking on this!",
160
+ "Smart move looking into this!",
161
+ "You're on the right track!",
162
+ "Excellent question!",
163
+ "Love that you're being proactive!"
164
+ ]
165
+
166
+ PROACTIVE_PHRASES = [
167
+ "I also noticed something else while I was at it",
168
+ "Quick side note -",
169
+ "Oh, and while we're here",
170
+ "By the way, related to this",
171
+ "Just flagging this too",
172
+ "Something else to keep an eye on"
173
+ ]
174
+
175
+ import random
176
+
177
+ # --- Backend PAM Class ---
178
+ class PAM:
179
+ """Backend PAM - Nerdy, Proactive Lab Assistant"""
180
+
181
+ def __init__(self, data: Dict[str, Dict]):
182
+ self.LOGS = data.get("LOGS", {})
183
+ self.COMPLIANCE = data.get("COMPLIANCE", {})
184
+
185
+ # Track findings for proactive suggestions
186
+ self.recent_findings = []
187
+
188
+ def _get_nerdy_intro(self) -> str:
189
+ """Get a random nerdy introduction"""
190
+ return random.choice(NERDY_INTROS)
191
+
192
+ def _get_encouragement(self) -> str:
193
+ """Get a random encouraging phrase"""
194
+ return random.choice(ENCOURAGEMENT)
195
+
196
+ def _get_proactive_phrase(self) -> str:
197
+ """Get a random proactive phrase"""
198
+ return random.choice(PROACTIVE_PHRASES)
199
+
200
+ def _check_api_health(self) -> bool:
201
+ """Check if HF API is accessible"""
202
+ return HF_API_TOKEN is not None
203
+
204
+ def detect_phi(self, text: str) -> Dict[str, Any]:
205
+ """Detect Protected Health Information (PHI) using NER"""
206
+ intro = self._get_nerdy_intro()
207
+
208
+ if not self._check_api_health():
209
+ return {
210
+ "message": "⚠️ Hmm, I'm having trouble connecting to the analysis models right now. Let me flag this text for manual review instead!",
211
+ "role": PAM_ROLE,
212
+ "has_phi": None,
213
+ "entities": []
214
+ }
215
+
216
+ # Call NER model
217
+ result = hf_infer("phi_ner", {"inputs": text})
218
+
219
+ if isinstance(result, dict) and "error" in result:
220
+ return {
221
+ "message": f"🔍 I tried to scan for PHI, but hit a snag: {result['error']}. I'd recommend a manual review just to be safe!",
222
+ "role": PAM_ROLE,
223
+ "has_phi": None,
224
+ "entities": []
225
+ }
226
+
227
+ # Filter for PHI-relevant entities
228
+ phi_entities = []
229
+ if isinstance(result, list):
230
+ phi_entities = [
231
+ e for e in result
232
+ if e.get("entity_group") in ["PER", "LOC", "ORG", "DATE"]
233
+ and e.get("score", 0) > 0.7
234
+ ]
235
+
236
+ has_phi = len(phi_entities) > 0
237
+
238
+ if has_phi:
239
+ entities_summary = ", ".join([f"{e['word']} ({e['entity_group']})" for e in phi_entities[:3]])
240
+ message = f"🔒 {intro} I detected {len(phi_entities)} potential PHI entities in this text: {entities_summary}{'...' if len(phi_entities) > 3 else ''}. Definitely want to redact these before storing or sharing!"
241
+ else:
242
+ message = f"✅ {intro} This text looks clean - no PHI detected! Safe to proceed with normal handling."
243
+
244
+ # Proactive suggestion
245
+ if has_phi:
246
+ message += f" {self._get_proactive_phrase()} - if you're logging this anywhere, make sure those logs are encrypted and access-controlled."
247
+
248
+ return {
249
+ "message": message,
250
+ "role": PAM_ROLE,
251
+ "has_phi": has_phi,
252
+ "entities": phi_entities,
253
+ "recommendation": "Redact PHI before storage" if has_phi else "No action needed"
254
+ }
255
+
256
+ def parse_log(self, log_text: str) -> Dict[str, Any]:
257
+ """Parse and analyze log entries for security relevance"""
258
+ intro = self._get_nerdy_intro()
259
+
260
+ if not self._check_api_health():
261
+ return {
262
+ "message": "⚠️ Can't connect to the log parser right now. I'll do a quick manual analysis instead!",
263
+ "role": PAM_ROLE,
264
+ "severity": classify_severity(log_text),
265
+ "log_entities": []
266
+ }
267
+
268
+ # Call NER model for log parsing
269
+ result = hf_infer("log_ner", {"inputs": log_text})
270
+
271
+ severity = classify_severity(log_text)
272
+
273
+ parsed_entities = []
274
+ if isinstance(result, list):
275
+ parsed_entities = [e for e in result if e.get("score", 0) > 0.6]
276
+
277
+ # Build informative response
278
+ severity_emoji = {"CRITICAL": "🚨", "WARNING": "⚠️", "INFO": "ℹ️"}
279
+ emoji = severity_emoji.get(severity, "📝")
280
+
281
+ message = f"{emoji} {intro} This log entry is classified as **{severity}** priority."
282
+
283
+ if severity == "CRITICAL":
284
+ message += " This needs immediate attention! I'd recommend investigating ASAP and documenting the incident."
285
+ elif severity == "WARNING":
286
+ message += " Worth keeping an eye on this - might escalate if we see more like it."
287
+ else:
288
+ message += " Just routine activity, but good to have it logged for the audit trail."
289
+
290
+ # Add entity details if found
291
+ if parsed_entities:
292
+ entity_summary = f" I extracted {len(parsed_entities)} key entities from the log."
293
+ message += entity_summary
294
+
295
+ return {
296
+ "message": message,
297
+ "role": PAM_ROLE,
298
+ "severity": severity,
299
+ "log_entities": parsed_entities,
300
+ "timestamp": datetime.now().isoformat()
301
+ }
302
+
303
+ def summarize(self, raw_text: str) -> Dict[str, Any]:
304
+ """Generate technical summary of text (great for long logs or reports)"""
305
+ encouragement = self._get_encouragement()
306
+
307
+ if not self._check_api_health():
308
+ return {
309
+ "message": f"⚠️ {encouragement} But I can't access the summarization model right now. Can you share a bit more context on what you need?",
310
+ "role": PAM_ROLE,
311
+ "summary": None
312
+ }
313
+
314
+ # Truncate for model limits (BART handles ~1024 tokens well)
315
+ truncated_text = raw_text[:1024]
316
+
317
+ result = hf_infer("summarizer", {
318
+ "inputs": truncated_text,
319
+ "parameters": {
320
+ "max_length": 130,
321
+ "min_length": 30,
322
+ "do_sample": False
323
+ }
324
+ })
325
+
326
+ if isinstance(result, dict) and "error" in result:
327
+ return {
328
+ "message": f"🤔 {encouragement} I tried to summarize this but hit a technical issue. Could you break it into smaller chunks?",
329
+ "role": PAM_ROLE,
330
+ "summary": None
331
+ }
332
+
333
+ summary_text = result[0].get("summary_text", "") if isinstance(result, list) else ""
334
+
335
+ return {
336
+ "message": f"📊 {encouragement} Here's the TL;DR of what you shared:",
337
+ "role": PAM_ROLE,
338
+ "summary": summary_text,
339
+ "original_length": len(raw_text),
340
+ "summary_length": len(summary_text)
341
+ }
342
+
343
+ def get_latest_logs(self) -> Dict[str, Any]:
344
+ """Retrieve and analyze recent system logs"""
345
+ intro = self._get_nerdy_intro()
346
+
347
+ if "latest_logs" not in self.LOGS or not self.LOGS["latest_logs"]:
348
+ return {
349
+ "message": "🤔 Hmm, I'm not seeing any logs in the system right now. Either nothing's being logged, or there's a data loading issue. Want me to check the log file paths?",
350
+ "role": PAM_ROLE,
351
+ "logs": [],
352
+ "handoff_to_frontend": []
353
+ }
354
+
355
+ full_logset = []
356
+ client_handoffs = []
357
+ critical_count = 0
358
+ warning_count = 0
359
+
360
+ for item in self.LOGS["latest_logs"]:
361
+ entry = item.get("entry", "")
362
+ timestamp = item.get("timestamp", "Unknown time")
363
+ severity = classify_severity(entry)
364
+
365
+ # Count severity levels
366
+ if severity == "CRITICAL":
367
+ critical_count += 1
368
+ elif severity == "WARNING":
369
+ warning_count += 1
370
+
371
+ formatted = f"[{timestamp}] ({severity}) {entry}"
372
+ full_logset.append(formatted)
373
+
374
+ # Identify client-facing issues that Frontend PAM should handle
375
+ if any(keyword in entry.lower() for keyword in ["frontend", "provider unavailable", "user", "client"]):
376
+ client_handoffs.append(formatted)
377
+
378
+ # Build proactive, informative response
379
+ total = len(full_logset)
380
+ message = f"📡 {intro} I reviewed {total} recent log entries. "
381
+
382
+ if critical_count > 0:
383
+ message += f"**Heads up:** {critical_count} critical issues detected that need immediate action! "
384
+ if warning_count > 0:
385
+ message += f"{warning_count} warnings worth monitoring. "
386
+ if critical_count == 0 and warning_count == 0:
387
+ message += "Everything looks stable - no major issues! "
388
+
389
+ if client_handoffs:
390
+ message += f"\n\n{self._get_proactive_phrase()} - {len(client_handoffs)} of these are client-facing issues. I'll pass those to Frontend PAM to handle with users."
391
+
392
+ return {
393
+ "message": message,
394
+ "role": PAM_ROLE,
395
+ "logs": full_logset,
396
+ "summary": {
397
+ "total": total,
398
+ "critical": critical_count,
399
+ "warnings": warning_count,
400
+ "info": total - critical_count - warning_count
401
+ },
402
+ "handoff_to_frontend": client_handoffs
403
+ }
404
+
405
+ def check_compliance(self) -> Dict[str, Any]:
406
+ """Run compliance status check and provide recommendations"""
407
+ encouragement = self._get_encouragement()
408
+
409
+ if not self.COMPLIANCE:
410
+ return {
411
+ "message": f"🤔 {encouragement} But I don't have access to the compliance data right now. Let me know if you need me to check the data file setup!",
412
+ "role": PAM_ROLE,
413
+ "compliance_report": []
414
+ }
415
+
416
+ report = []
417
+ compliant_count = 0
418
+ non_compliant_items = []
419
+
420
+ for item, status in self.COMPLIANCE.items():
421
+ emoji = "✅" if status else "❌"
422
+ readable_item = item.replace('_', ' ').title()
423
+ report.append(f"{emoji} {readable_item}")
424
+
425
+ if status:
426
+ compliant_count += 1
427
+ else:
428
+ non_compliant_items.append(readable_item)
429
+
430
+ total = len(self.COMPLIANCE)
431
+ compliance_rate = (compliant_count / total * 100) if total > 0 else 0
432
+
433
+ # Build informative, proactive response
434
+ message = f"🛡️ {encouragement} Here's the compliance status:\n\n"
435
+ message += f"**Overall:** {compliant_count}/{total} checks passed ({compliance_rate:.1f}%)\n\n"
436
+
437
+ if non_compliant_items:
438
+ message += f"**Action needed:** We have {len(non_compliant_items)} items out of compliance:\n"
439
+ for item in non_compliant_items:
440
+ message += f" • {item}\n"
441
+ message += f"\n{self._get_proactive_phrase()} - I can help you prioritize these if you want to tackle them systematically!"
442
+ else:
443
+ message += "🎉 Everything's in compliance! Great work keeping things locked down."
444
+
445
+ return {
446
+ "message": message,
447
+ "role": PAM_ROLE,
448
+ "compliance_report": report,
449
+ "compliance_rate": compliance_rate,
450
+ "non_compliant": non_compliant_items
451
+ }
452
+
453
+ def process_input(self, user_input: str) -> Dict[str, Any]:
454
+ """Main input processor - proactive and informative"""
455
+ u_input = user_input.lower().strip()
456
+ encouragement = self._get_encouragement()
457
+
458
+ # Command routing with personality
459
+ if "check compliance" in u_input or "compliance status" in u_input:
460
+ return self.check_compliance()
461
+
462
+ if "get logs" in u_input or "latest logs" in u_input or "show logs" in u_input:
463
+ return self.get_latest_logs()
464
+
465
+ if "detect phi" in u_input:
466
+ text_to_scan = user_input[u_input.find("detect phi in") + len("detect phi in"):].strip()
467
+ if not text_to_scan:
468
+ text_to_scan = user_input[u_input.find("detect phi") + len("detect phi"):].strip()
469
+ return self.detect_phi(text_to_scan)
470
+
471
+ if "parse log" in u_input:
472
+ log_to_parse = user_input[u_input.find("parse log") + len("parse log"):].strip()
473
+ return self.parse_log(log_to_parse)
474
+
475
+ if "summarize" in u_input or "explain" in u_input:
476
+ return self.summarize(user_input)
477
+
478
+ # Helpful default response with encouragement
479
+ return {
480
+ "message": f"👋 Hey! {encouragement} I'm PAM, your backend technical assistant. I can help you with:\n\n"
481
+ "• **check compliance** - Review compliance status\n"
482
+ "• **get logs** - Pull latest system logs\n"
483
+ "• **detect phi in [text]** - Scan for protected health info\n"
484
+ "• **parse log [entry]** - Analyze a specific log\n"
485
+ "• **summarize [text]** - Generate a technical summary\n\n"
486
+ "What would you like me to look into?",
487
+ "role": PAM_ROLE
488
+ }
489
+
490
+
491
+ # --- Quick Test ---
492
+ if __name__ == "__main__":
493
+ print("🤓 Testing Backend PAM (Nerdy Lab Assistant)...\n")
494
+ pam = load_agent()
495
+
496
+ test_commands = [
497
+ "check compliance",
498
+ "get logs",
499
+ "detect phi in Patient John Doe visited on 2024-03-15 at Memorial Hospital"
500
+ ]
501
+
502
+ for cmd in test_commands:
503
+ print(f"\n{'='*60}")
504
+ print(f"COMMAND: {cmd}")
505
+ print(f"{'='*60}")
506
+ response = pam.process_input(cmd)
507
+ print(response.get("message", response))
compliance.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "security": {
3
+ "kms_encryption": true,
4
+ "iam_least_privilege": false,
5
+ "security_group_restrictions": true,
6
+ "mfa_enabled": true,
7
+ "ssl_tls_enforced": true,
8
+ "password_policy_compliant": true,
9
+ "firewall_configured": true
10
+ },
11
+ "privacy": {
12
+ "hipaa_compliant": true,
13
+ "gdpr_ready": true,
14
+ "phi_detection_enabled": true,
15
+ "data_anonymization": true,
16
+ "consent_management": true,
17
+ "right_to_erasure": true
18
+ },
19
+ "infrastructure": {
20
+ "logging_enabled": true,
21
+ "monitoring_active": true,
22
+ "backup_configured": true,
23
+ "disaster_recovery_plan": false,
24
+ "patch_management": true,
25
+ "vulnerability_scanning": true
26
+ },
27
+ "operational": {
28
+ "incident_response_plan": true,
29
+ "security_training_current": false,
30
+ "access_reviews_completed": true,
31
+ "change_management_process": true,
32
+ "documentation_up_to_date": true
33
+ },
34
+ "audit": {
35
+ "last_audit_date": "2024-10-15",
36
+ "next_audit_due": "2025-01-15",
37
+ "findings_resolved": 12,
38
+ "findings_pending": 3,
39
+ "compliance_score": 85.7
40
+ }
41
+ }
follow_up.json ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "symptom_follow_ups": {
3
+ "cramps": {
4
+ "message": "Let me know how you're feeling tomorrow, honey — cramps can change fast.",
5
+ "check_in_hours": 24,
6
+ "escalation_triggers": [
7
+ "severe pain",
8
+ "not improving",
9
+ "getting worse",
10
+ "can't function"
11
+ ],
12
+ "escalation_message": "If the pain gets worse or you can't manage it, let's get you connected with a provider right away, dear.",
13
+ "resource_links": ["pain_management", "emergency_signs"]
14
+ },
15
+ "discharge": {
16
+ "message": "Keep an eye on it, sweetheart. If anything else changes, I'll help you get seen.",
17
+ "check_in_hours": 48,
18
+ "escalation_triggers": [
19
+ "odor",
20
+ "increased",
21
+ "color change",
22
+ "itching",
23
+ "burning"
24
+ ],
25
+ "escalation_message": "Those changes could mean an infection, boo. Let me help you schedule an appointment to get that checked out.",
26
+ "resource_links": ["vaginal_health", "infection_signs"]
27
+ },
28
+ "fatigue": {
29
+ "message": "Be gentle with yourself, honey. Want me to nudge you to rest later?",
30
+ "check_in_hours": 48,
31
+ "escalation_triggers": [
32
+ "extreme tiredness",
33
+ "can't get out of bed",
34
+ "dizzy",
35
+ "fainting"
36
+ ],
37
+ "escalation_message": "That level of exhaustion isn't normal, dear. Let's get you checked for anemia or other causes.",
38
+ "resource_links": ["energy_tips", "anemia_info"]
39
+ },
40
+ "mood": {
41
+ "message": "You're not alone, love — your feelings are valid. I'm here if you need me.",
42
+ "check_in_hours": 24,
43
+ "escalation_triggers": [
44
+ "can't stop crying",
45
+ "hurting myself",
46
+ "suicidal",
47
+ "hopeless",
48
+ "can't function"
49
+ ],
50
+ "escalation_message": "What you're feeling sounds really hard, sweetheart. I want to connect you with someone who can really help — would that be okay?",
51
+ "crisis_hotline": "988",
52
+ "resource_links": ["mental_health_support", "crisis_resources"]
53
+ },
54
+ "missed_period": {
55
+ "message": "Keep track of any symptoms, boo. I can check back with you in a few days.",
56
+ "check_in_hours": 72,
57
+ "escalation_triggers": [
58
+ "two months",
59
+ "pregnant",
60
+ "test positive",
61
+ "severe symptoms"
62
+ ],
63
+ "escalation_message": "Let's get you scheduled with a provider to figure out what's going on, honey.",
64
+ "resource_links": ["pregnancy_testing", "cycle_tracking"]
65
+ },
66
+ "bleeding": {
67
+ "message": "I'll check in with you tomorrow, dear. Heavy bleeding can be concerning.",
68
+ "check_in_hours": 24,
69
+ "escalation_triggers": [
70
+ "soaking through",
71
+ "clots larger than quarter",
72
+ "dizzy",
73
+ "very heavy",
74
+ "hemorrhaging"
75
+ ],
76
+ "escalation_message": "That sounds like heavy bleeding, honey. If you're soaking through pads every hour, you need to be seen right away or go to the ER.",
77
+ "emergency": true,
78
+ "resource_links": ["heavy_bleeding", "emergency_signs"]
79
+ },
80
+ "nausea": {
81
+ "message": "Hope you're feeling better soon, sweetheart. Let me know if it keeps up.",
82
+ "check_in_hours": 48,
83
+ "escalation_triggers": [
84
+ "can't keep food down",
85
+ "dehydrated",
86
+ "vomiting blood",
87
+ "severe"
88
+ ],
89
+ "escalation_message": "If you can't keep anything down, you might need IV fluids, boo. Let's get you seen.",
90
+ "resource_links": ["nausea_relief", "dehydration_signs"]
91
+ },
92
+ "pain": {
93
+ "message": "I'm here if the pain doesn't ease up, dear. Take care of yourself.",
94
+ "check_in_hours": 24,
95
+ "escalation_triggers": [
96
+ "severe",
97
+ "unbearable",
98
+ "sharp pain",
99
+ "sudden pain",
100
+ "emergency"
101
+ ],
102
+ "escalation_message": "Severe pain always needs attention, honey. Let me help you get seen quickly.",
103
+ "emergency_threshold": "severe_or_sudden",
104
+ "resource_links": ["pain_management", "when_to_worry"]
105
+ }
106
+ },
107
+ "appointment_follow_ups": {
108
+ "post_appointment": {
109
+ "message": "Hey honey! How did your appointment go? I'm here if you have any questions about what the provider said.",
110
+ "check_in_hours": 24,
111
+ "suggested_actions": [
112
+ "review_instructions",
113
+ "schedule_follow_up",
114
+ "fill_prescriptions"
115
+ ]
116
+ },
117
+ "test_results_pending": {
118
+ "message": "Just checking in, dear. Have your test results come back yet? I can help you understand them.",
119
+ "check_in_hours": 72,
120
+ "suggested_actions": [
121
+ "check_patient_portal",
122
+ "call_office",
123
+ "schedule_results_discussion"
124
+ ]
125
+ },
126
+ "medication_start": {
127
+ "message": "How are you doing with the new medication, sweetheart? Any side effects I should know about?",
128
+ "check_in_hours": 48,
129
+ "suggested_actions": [
130
+ "track_side_effects",
131
+ "report_concerns",
132
+ "refill_reminder"
133
+ ]
134
+ }
135
+ },
136
+ "general_support": {
137
+ "check_in": {
138
+ "message": "Hey boo, just checking in! How are you feeling today?",
139
+ "check_in_hours": 168,
140
+ "purpose": "wellness_check"
141
+ },
142
+ "resource_sent": {
143
+ "message": "Did those resources I shared help you out, honey? Let me know if you need anything else.",
144
+ "check_in_hours": 48,
145
+ "purpose": "resource_effectiveness"
146
+ },
147
+ "appointment_reminder": {
148
+ "message": "Hey dear! Just a reminder you've got an appointment coming up. Need any help preparing?",
149
+ "check_in_hours": 24,
150
+ "suggested_actions": [
151
+ "write_questions",
152
+ "bring_medications_list",
153
+ "fasting_if_needed"
154
+ ]
155
+ }
156
+ },
157
+ "follow_up_settings": {
158
+ "max_follow_ups": 3,
159
+ "respect_do_not_disturb": true,
160
+ "preferred_contact_hours": {
161
+ "start": "09:00",
162
+ "end": "20:00"
163
+ },
164
+ "timezone": "America/New_York",
165
+ "allow_user_snooze": true,
166
+ "snooze_duration_hours": 12
167
+ }
168
+ }
frontend_pam.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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")
logs.json ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "latest_logs": [
3
+ {
4
+ "id": "log_001",
5
+ "entry": "Wazuh: Failed SSH login attempt from 192.168.1.101",
6
+ "timestamp": "2025-11-04T09:13:00",
7
+ "severity": "CRITICAL",
8
+ "source": "wazuh",
9
+ "category": "security",
10
+ "ip_address": "192.168.1.101",
11
+ "action_taken": "IP temporarily blocked",
12
+ "requires_review": true,
13
+ "tags": ["authentication", "failed_login", "intrusion_attempt"]
14
+ },
15
+ {
16
+ "id": "log_002",
17
+ "entry": "CloudTrail: IAM role assumed outside working hours",
18
+ "timestamp": "2025-11-04T11:25:00",
19
+ "severity": "WARNING",
20
+ "source": "cloudtrail",
21
+ "category": "access_control",
22
+ "user": "admin_user_02",
23
+ "role": "PowerUserAccess",
24
+ "action_taken": "Logged for review",
25
+ "requires_review": true,
26
+ "tags": ["iam", "after_hours", "unusual_activity"]
27
+ },
28
+ {
29
+ "id": "log_003",
30
+ "entry": "Wazuh: Unexpected port scanning activity detected",
31
+ "timestamp": "2025-11-04T14:50:00",
32
+ "severity": "CRITICAL",
33
+ "source": "wazuh",
34
+ "category": "security",
35
+ "ip_address": "203.0.113.45",
36
+ "ports_scanned": [22, 80, 443, 3306, 5432],
37
+ "action_taken": "IP blocked, alert sent to security team",
38
+ "requires_review": true,
39
+ "tags": ["port_scan", "reconnaissance", "threat_detected"]
40
+ },
41
+ {
42
+ "id": "log_004",
43
+ "entry": "Frontend: provider directory unavailable to user session",
44
+ "timestamp": "2025-11-04T16:02:00",
45
+ "severity": "WARNING",
46
+ "source": "frontend",
47
+ "category": "application",
48
+ "user_session": "sess_a3f9c21",
49
+ "affected_feature": "provider_directory",
50
+ "action_taken": "Session redirected to support",
51
+ "requires_review": false,
52
+ "handoff_to_frontend_pam": true,
53
+ "tags": ["user_facing", "service_unavailable", "ux_issue"]
54
+ },
55
+ {
56
+ "id": "log_005",
57
+ "entry": "API: Rate limit exceeded for endpoint /ai/chat/",
58
+ "timestamp": "2025-11-04T17:30:00",
59
+ "severity": "WARNING",
60
+ "source": "api_gateway",
61
+ "category": "performance",
62
+ "endpoint": "/ai/chat/",
63
+ "request_count": 150,
64
+ "rate_limit": 100,
65
+ "action_taken": "Requests throttled",
66
+ "requires_review": true,
67
+ "tags": ["rate_limit", "performance", "api_abuse"]
68
+ },
69
+ {
70
+ "id": "log_006",
71
+ "entry": "Database: Slow query detected - response time 8.5s",
72
+ "timestamp": "2025-11-04T18:15:00",
73
+ "severity": "WARNING",
74
+ "source": "database",
75
+ "category": "performance",
76
+ "query": "SELECT * FROM appointments WHERE...",
77
+ "response_time": "8.5s",
78
+ "action_taken": "Query logged for optimization",
79
+ "requires_review": true,
80
+ "tags": ["slow_query", "database_performance", "optimization_needed"]
81
+ },
82
+ {
83
+ "id": "log_007",
84
+ "entry": "Backup: Daily backup completed successfully",
85
+ "timestamp": "2025-11-04T02:00:00",
86
+ "severity": "INFO",
87
+ "source": "backup_service",
88
+ "category": "maintenance",
89
+ "backup_size": "2.3GB",
90
+ "backup_location": "s3://uminur-backups/2025-11-04/",
91
+ "action_taken": "None - routine operation",
92
+ "requires_review": false,
93
+ "tags": ["backup", "routine", "success"]
94
+ },
95
+ {
96
+ "id": "log_008",
97
+ "entry": "SSL Certificate: Certificate renewal required in 14 days",
98
+ "timestamp": "2025-11-04T08:00:00",
99
+ "severity": "WARNING",
100
+ "source": "certbot",
101
+ "category": "infrastructure",
102
+ "domain": "api.uminur.app",
103
+ "expiration_date": "2025-11-18",
104
+ "action_taken": "Renewal notification sent",
105
+ "requires_review": true,
106
+ "tags": ["ssl", "certificate", "renewal_needed"]
107
+ },
108
+ {
109
+ "id": "log_009",
110
+ "entry": "Frontend: User reported PHI visible in error message",
111
+ "timestamp": "2025-11-04T19:45:00",
112
+ "severity": "CRITICAL",
113
+ "source": "frontend",
114
+ "category": "privacy",
115
+ "incident_id": "INC-2025-1104-001",
116
+ "action_taken": "Error logs sanitized, incident report created",
117
+ "requires_review": true,
118
+ "handoff_to_frontend_pam": true,
119
+ "tags": ["phi_leak", "privacy_violation", "urgent"]
120
+ },
121
+ {
122
+ "id": "log_010",
123
+ "entry": "HF Inference API: Model loading timeout for mistral-7b",
124
+ "timestamp": "2025-11-04T20:30:00",
125
+ "severity": "WARNING",
126
+ "source": "api_service",
127
+ "category": "ai_inference",
128
+ "model": "mistralai/Mistral-7B-Instruct-v0.2",
129
+ "timeout": "30s",
130
+ "retry_count": 3,
131
+ "action_taken": "Fallback response provided",
132
+ "requires_review": false,
133
+ "tags": ["model_loading", "timeout", "inference_error"]
134
+ },
135
+ {
136
+ "id": "log_011",
137
+ "entry": "Compliance: HIPAA audit check passed",
138
+ "timestamp": "2025-11-04T06:00:00",
139
+ "severity": "INFO",
140
+ "source": "compliance_monitor",
141
+ "category": "compliance",
142
+ "audit_type": "hipaa_daily_check",
143
+ "result": "passed",
144
+ "action_taken": "None - compliant",
145
+ "requires_review": false,
146
+ "tags": ["hipaa", "compliance", "audit"]
147
+ },
148
+ {
149
+ "id": "log_012",
150
+ "entry": "Nginx: Unauthorized access attempt to /admin endpoint",
151
+ "timestamp": "2025-11-04T21:10:00",
152
+ "severity": "CRITICAL",
153
+ "source": "nginx",
154
+ "category": "security",
155
+ "ip_address": "198.51.100.23",
156
+ "endpoint": "/admin",
157
+ "status_code": 403,
158
+ "action_taken": "Access denied, IP logged",
159
+ "requires_review": true,
160
+ "tags": ["unauthorized_access", "admin_endpoint", "security_threat"]
161
+ }
162
+ ],
163
+ "log_summary": {
164
+ "total_entries": 12,
165
+ "critical": 4,
166
+ "warning": 5,
167
+ "info": 3,
168
+ "requires_review": 8,
169
+ "handoff_to_frontend": 2,
170
+ "time_range": {
171
+ "start": "2025-11-04T02:00:00",
172
+ "end": "2025-11-04T21:10:00"
173
+ },
174
+ "top_categories": [
175
+ "security",
176
+ "performance",
177
+ "compliance",
178
+ "privacy"
179
+ ]
180
+ },
181
+ "alert_thresholds": {
182
+ "critical_alerts_per_hour": 2,
183
+ "failed_login_attempts": 5,
184
+ "port_scan_tolerance": 0,
185
+ "phi_leak_tolerance": 0,
186
+ "rate_limit_threshold": 100
187
+ }
188
+ }
permissions.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "sensitive_topics": {
3
+ "abortion": false,
4
+ "sexual_assault": false,
5
+ "domestic_violence": false,
6
+ "self_harm": false,
7
+ "substance_abuse": false,
8
+ "mental_health_crisis": false
9
+ },
10
+ "medical_services": {
11
+ "hormone_therapy": true,
12
+ "birth_control": true,
13
+ "fertility_treatment": true,
14
+ "prenatal_care": true,
15
+ "std_testing": true,
16
+ "cancer_screening": true,
17
+ "menopause_management": true
18
+ },
19
+ "general_health": {
20
+ "nutrition_guidance": true,
21
+ "exercise_recommendations": true,
22
+ "symptom_checker": true,
23
+ "medication_info": true,
24
+ "appointment_scheduling": true,
25
+ "lab_results_explanation": true
26
+ },
27
+ "emergency_topics": {
28
+ "severe_bleeding": true,
29
+ "chest_pain": true,
30
+ "difficulty_breathing": true,
31
+ "loss_of_consciousness": true,
32
+ "severe_abdominal_pain": true,
33
+ "suicidal_thoughts": false
34
+ },
35
+ "policy": {
36
+ "description": "Topics marked 'false' require immediate escalation to a licensed provider or crisis hotline",
37
+ "false_action": "redirect_to_provider",
38
+ "escalation_message": "connect you with a provider or safe resource who can help with this directly",
39
+ "always_available": ["appointment_scheduling", "general_questions", "resource_navigation"]
40
+ }
41
+ }
requirements.txt ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # filename: requirements.txt
2
+ # PAM - Privacy-First AI Assistant
3
+ # Optimized for Hugging Face Spaces (CPU deployment)
4
+
5
+ # ==========================================
6
+ # Web Server / API Framework
7
+ # ==========================================
8
+ fastapi>=0.104.0,<0.110.0
9
+ uvicorn[standard]>=0.23.2,<0.30.0
10
+ pydantic>=2.4.2,<3.0.0
11
+ python-multipart>=0.0.6
12
+ starlette>=0.35.1,<0.40.0
13
+
14
+ # ==========================================
15
+ # HTTP & API Communication
16
+ # ==========================================
17
+ requests>=2.31.0
18
+ httpx>=0.25.0
19
+
20
+ # ==========================================
21
+ # AI/ML Libraries (CPU-optimized)
22
+ # ==========================================
23
+ # NOTE: Transformers is only needed if using local pipelines
24
+ # For HF Inference API (recommended for Spaces), it's optional
25
+ # transformers>=4.35.0,<4.40.0
26
+ # torch>=2.1.0,<2.2.0 # REMOVED - not needed for Inference API
27
+
28
+ # Transformers without torch dependency (for tokenizers only if needed)
29
+ transformers>=4.35.0,<4.40.0
30
+ # Install CPU-only torch if you absolutely need local models
31
+ --extra-index-url https://download.pytorch.org/whl/cpu
32
+ torch>=2.1.0,<2.3.0
33
+
34
+ # ==========================================
35
+ # Utilities & Data Processing
36
+ # ==========================================
37
+ python-dateutil>=2.8.2
38
+ pytz>=2023.3
39
+
40
+ # ==========================================
41
+ # Optional: AWS Integration (if needed)
42
+ # ==========================================
43
+ # boto3>=1.28.69 # Uncomment if using AWS services
44
+
45
+ # ==========================================
46
+ # Development & Debugging (remove in production)
47
+ # ==========================================
48
+ # pytest>=7.4.0
49
+ # black>=23.10.0
50
+ # flake8>=6.1.0
resources.json ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "symptoms": {
3
+ "discharge": {
4
+ "title": "Vaginal Discharge Information",
5
+ "resources": [
6
+ {
7
+ "type": "guide",
8
+ "title": "What Different Colors of Discharge Mean",
9
+ "url": "https://www.uminur.app/resources/discharge-guide",
10
+ "description": "Learn what's normal and when to see a provider"
11
+ },
12
+ {
13
+ "type": "article",
14
+ "title": "Understanding Vaginal Health",
15
+ "url": "https://www.uminur.app/resources/vaginal-health",
16
+ "description": "Comprehensive guide to vaginal health and hygiene"
17
+ },
18
+ {
19
+ "type": "provider",
20
+ "title": "Find a Gynecologist",
21
+ "url": "https://www.uminur.app/find-a-doctor",
22
+ "description": "Connect with a women's health specialist"
23
+ }
24
+ ],
25
+ "keywords": ["discharge", "vaginal", "secretion", "leaking", "wetness"]
26
+ },
27
+ "cramps": {
28
+ "title": "Menstrual Cramps & Pelvic Pain",
29
+ "resources": [
30
+ {
31
+ "type": "video",
32
+ "title": "Stretching Exercises for Cramp Relief",
33
+ "url": "https://www.uminur.app/resources/cramp-relief-video",
34
+ "description": "5-minute stretches that can ease period pain",
35
+ "duration": "5 min"
36
+ },
37
+ {
38
+ "type": "article",
39
+ "title": "When Cramps Could Mean Something Serious",
40
+ "url": "https://www.uminur.app/resources/severe-cramps",
41
+ "description": "Signs that warrant medical attention"
42
+ },
43
+ {
44
+ "type": "guide",
45
+ "title": "Heat Therapy & Pain Management",
46
+ "url": "https://www.uminur.app/resources/pain-management",
47
+ "description": "Natural and medical options for relief"
48
+ },
49
+ {
50
+ "type": "provider",
51
+ "title": "Find a Provider",
52
+ "url": "https://www.uminur.app/providers",
53
+ "description": "Book an appointment for persistent pain"
54
+ }
55
+ ],
56
+ "keywords": ["cramps", "cramping", "pain", "pelvic pain", "period pain", "menstrual pain"]
57
+ },
58
+ "fatigue": {
59
+ "title": "Managing Fatigue & Low Energy",
60
+ "resources": [
61
+ {
62
+ "type": "article",
63
+ "title": "Period Fatigue: Why It Happens",
64
+ "url": "https://www.uminur.app/resources/period-fatigue",
65
+ "description": "Understanding the hormonal causes of tiredness"
66
+ },
67
+ {
68
+ "type": "guide",
69
+ "title": "Nutritional Support for Energy",
70
+ "url": "https://www.uminur.app/resources/nutrition-energy",
71
+ "description": "Foods that help combat period-related fatigue"
72
+ },
73
+ {
74
+ "type": "tips",
75
+ "title": "Sleep Hygiene During Your Cycle",
76
+ "url": "https://www.uminur.app/resources/sleep-tips",
77
+ "description": "Better sleep strategies for hormone fluctuations"
78
+ },
79
+ {
80
+ "type": "provider",
81
+ "title": "Talk to a Specialist",
82
+ "url": "https://www.uminur.app/providers",
83
+ "description": "Rule out anemia or other conditions"
84
+ }
85
+ ],
86
+ "keywords": ["fatigue", "tired", "exhausted", "low energy", "weakness", "sluggish"]
87
+ },
88
+ "mood": {
89
+ "title": "Mood Changes & Emotional Wellness",
90
+ "resources": [
91
+ {
92
+ "type": "video",
93
+ "title": "Navigating Mood Swings",
94
+ "url": "https://www.uminur.app/resources/mood-swings-video",
95
+ "description": "Understanding PMS and PMDD",
96
+ "duration": "8 min"
97
+ },
98
+ {
99
+ "type": "article",
100
+ "title": "Hormones and Your Emotions",
101
+ "url": "https://www.uminur.app/resources/hormones-emotions",
102
+ "description": "The science behind cycle-related mood changes"
103
+ },
104
+ {
105
+ "type": "guide",
106
+ "title": "Coping Strategies for PMS",
107
+ "url": "https://www.uminur.app/resources/pms-coping",
108
+ "description": "Practical tools for emotional regulation"
109
+ },
110
+ {
111
+ "type": "community",
112
+ "title": "Join Support Groups",
113
+ "url": "https://www.uminur.app/community",
114
+ "description": "Connect with others experiencing similar challenges"
115
+ }
116
+ ],
117
+ "keywords": ["mood", "moody", "emotional", "irritable", "anxiety", "depression", "crying", "pms"]
118
+ },
119
+ "missed_period": {
120
+ "title": "Missed Period Information",
121
+ "resources": [
122
+ {
123
+ "type": "article",
124
+ "title": "Causes of a Missed Period",
125
+ "url": "https://www.uminur.app/resources/missed-period-causes",
126
+ "description": "Beyond pregnancy: stress, hormones, and health"
127
+ },
128
+ {
129
+ "type": "guide",
130
+ "title": "Should I Take a Pregnancy Test?",
131
+ "url": "https://www.uminur.app/resources/pregnancy-check",
132
+ "description": "When and how to test accurately"
133
+ },
134
+ {
135
+ "type": "article",
136
+ "title": "Irregular Cycles: What's Normal?",
137
+ "url": "https://www.uminur.app/resources/irregular-cycles",
138
+ "description": "Understanding cycle variations"
139
+ },
140
+ {
141
+ "type": "provider",
142
+ "title": "Find a Provider",
143
+ "url": "https://www.uminur.app/find-a-doctor",
144
+ "description": "Get professional guidance"
145
+ }
146
+ ],
147
+ "keywords": ["missed period", "late period", "no period", "amenorrhea", "irregular"]
148
+ },
149
+ "bleeding": {
150
+ "title": "Bleeding & Spotting",
151
+ "resources": [
152
+ {
153
+ "type": "article",
154
+ "title": "Understanding Spotting",
155
+ "url": "https://www.uminur.app/resources/spotting-guide",
156
+ "description": "Common causes and when to worry"
157
+ },
158
+ {
159
+ "type": "guide",
160
+ "title": "Heavy Bleeding: When to Seek Help",
161
+ "url": "https://www.uminur.app/resources/heavy-bleeding",
162
+ "description": "Signs of menorrhagia and treatment options"
163
+ },
164
+ {
165
+ "type": "provider",
166
+ "title": "Find a Provider",
167
+ "url": "https://www.uminur.app/providers",
168
+ "description": "Schedule a consultation"
169
+ }
170
+ ],
171
+ "keywords": ["bleeding", "spotting", "heavy period", "hemorrhage", "blood clots"]
172
+ },
173
+ "nausea": {
174
+ "title": "Nausea & Digestive Issues",
175
+ "resources": [
176
+ {
177
+ "type": "article",
178
+ "title": "Period-Related Nausea",
179
+ "url": "https://www.uminur.app/resources/period-nausea",
180
+ "description": "Why periods can cause stomach upset"
181
+ },
182
+ {
183
+ "type": "tips",
184
+ "title": "Managing Nausea Naturally",
185
+ "url": "https://www.uminur.app/resources/nausea-relief",
186
+ "description": "Foods and remedies that help"
187
+ },
188
+ {
189
+ "type": "provider",
190
+ "title": "Talk to a Provider",
191
+ "url": "https://www.uminur.app/providers",
192
+ "description": "If nausea is severe or persistent"
193
+ }
194
+ ],
195
+ "keywords": ["nausea", "sick", "vomiting", "queasy", "stomach upset"]
196
+ }
197
+ },
198
+ "general_health": {
199
+ "birth_control": {
200
+ "title": "Birth Control Options",
201
+ "resources": [
202
+ {
203
+ "type": "guide",
204
+ "title": "Complete Birth Control Guide",
205
+ "url": "https://www.uminur.app/resources/birth-control-options",
206
+ "description": "Compare methods, effectiveness, and side effects"
207
+ },
208
+ {
209
+ "type": "quiz",
210
+ "title": "Find Your Best Option",
211
+ "url": "https://www.uminur.app/tools/birth-control-quiz",
212
+ "description": "Interactive tool to match your lifestyle"
213
+ },
214
+ {
215
+ "type": "provider",
216
+ "title": "Schedule a Consultation",
217
+ "url": "https://www.uminur.app/appointments/birth-control",
218
+ "description": "Discuss options with a provider"
219
+ }
220
+ ]
221
+ },
222
+ "pregnancy": {
223
+ "title": "Pregnancy & Prenatal Care",
224
+ "resources": [
225
+ {
226
+ "type": "guide",
227
+ "title": "First Trimester Guide",
228
+ "url": "https://www.uminur.app/resources/first-trimester",
229
+ "description": "What to expect in early pregnancy"
230
+ },
231
+ {
232
+ "type": "checklist",
233
+ "title": "Prenatal Care Checklist",
234
+ "url": "https://www.uminur.app/resources/prenatal-checklist",
235
+ "description": "Important appointments and screenings"
236
+ },
237
+ {
238
+ "type": "provider",
239
+ "title": "Find an OB/GYN",
240
+ "url": "https://www.uminur.app/find-obgyn",
241
+ "description": "Connect with prenatal care"
242
+ }
243
+ ]
244
+ },
245
+ "sti_testing": {
246
+ "title": "STI Testing & Sexual Health",
247
+ "resources": [
248
+ {
249
+ "type": "article",
250
+ "title": "STI Testing: What You Need to Know",
251
+ "url": "https://www.uminur.app/resources/sti-testing",
252
+ "description": "Types of tests and when to get screened"
253
+ },
254
+ {
255
+ "type": "guide",
256
+ "title": "Sexual Health & Wellness",
257
+ "url": "https://www.uminur.app/resources/sexual-health",
258
+ "description": "Comprehensive sexual health information"
259
+ },
260
+ {
261
+ "type": "provider",
262
+ "title": "Confidential Testing",
263
+ "url": "https://www.uminur.app/services/sti-testing",
264
+ "description": "Private, judgment-free testing"
265
+ }
266
+ ]
267
+ }
268
+ },
269
+ "emergency": {
270
+ "hotlines": [
271
+ {
272
+ "name": "National Suicide Prevention Lifeline",
273
+ "phone": "988",
274
+ "url": "https://988lifeline.org",
275
+ "available": "24/7"
276
+ },
277
+ {
278
+ "name": "National Domestic Violence Hotline",
279
+ "phone": "1-800-799-7233",
280
+ "url": "https://www.thehotline.org",
281
+ "available": "24/7"
282
+ },
283
+ {
284
+ "name": "RAINN Sexual Assault Hotline",
285
+ "phone": "1-800-656-4673",
286
+ "url": "https://www.rainn.org",
287
+ "available": "24/7"
288
+ },
289
+ {
290
+ "name": "Substance Abuse Helpline",
291
+ "phone": "1-800-662-4357",
292
+ "url": "https://www.samhsa.gov",
293
+ "available": "24/7"
294
+ }
295
+ ]
296
+ }
297
+ }