pythonprincess commited on
Commit
c2b0011
·
verified ·
1 Parent(s): 97d62e1

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +349 -0
  2. app.py +21 -0
  3. gradio_app.py +465 -0
  4. requirements.txt +82 -0
README.md ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: PENNY - Civic Engagement AI Assistant
3
+ emoji: 🤖
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: docker
7
+ sdk_version: latest
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # 🤖 PENNY - Civic Engagement AI Assistant
14
+
15
+ **Personal civic Engagement Nurturing Network sYstem**
16
+
17
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
18
+ [![Azure ML](https://img.shields.io/badge/Azure-ML%20Ready-0078D4.svg)](https://azure.microsoft.com/en-us/services/machine-learning/)
19
+ [![FastAPI](https://img.shields.io/badge/FastAPI-0.100+-green.svg)](https://fastapi.tiangolo.com/)
20
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
21
+
22
+ ---
23
+
24
+ ## 📋 Overview
25
+
26
+ **PENNY** is a production-grade, AI-powered civic engagement assistant designed to help citizens connect with local government services, community events, and civic resources. Built with FastAPI and Hugging Face Transformers, Penny provides warm, helpful, and contextually-aware assistance for civic participation.
27
+
28
+ ### ✨ Key Features
29
+
30
+ - **🏛️ Civic Information**: Local government services, voting info, public meetings
31
+ - **📅 Community Events**: Real-time local events discovery and recommendations
32
+ - **🌤️ Weather Integration**: Context-aware weather updates with outfit suggestions
33
+ - **🌍 Multi-language Support**: Translation services for inclusive access
34
+ - **🛡️ Safety & Bias Detection**: Built-in content moderation and bias analysis
35
+ - **🔒 Privacy-First**: PII sanitization and secure logging
36
+ - **⚡ High Performance**: Async architecture with intelligent caching
37
+
38
+ ---
39
+
40
+ ## 🏗️ Architecture
41
+ ```
42
+ penny-v2/
43
+ ├── app/ # Core application logic
44
+ │ ├── main.py # FastAPI entry point
45
+ │ ├── orchestrator.py # Central coordination engine
46
+ │ ├── router.py # API route definitions
47
+ │ ├── tool_agent.py # Civic data & events agent
48
+ │ ├── weather_agent.py # Weather & recommendations
49
+ │ ├── intents.py # Intent classification
50
+ │ ├── model_loader.py # ML model management
51
+ │ └── utils/ # Logging, location, safety utilities
52
+ ├── models/ # ML model services
53
+ │ ├── translation/ # Multi-language translation
54
+ │ ├── sentiment/ # Sentiment analysis
55
+ │ ├── bias/ # Bias detection
56
+ │ └── core/ # LLM response generation
57
+ ├── data/ # Static data & resources
58
+ │ ├── intents.json # Intent classification data
59
+ │ └── civic_resources/ # Local government info
60
+ ├── azure/ # Azure ML deployment configs
61
+ └── requirements.txt # Python dependencies
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 🚀 Quick Start
67
+
68
+ ### Prerequisites
69
+
70
+ - Python 3.10 or higher
71
+ - Docker (optional, for containerized deployment)
72
+ - Azure subscription (for production deployment)
73
+
74
+ ### Local Development Setup
75
+
76
+ 1. **Clone the repository**
77
+ ```bash
78
+ git clone https://github.com/your-org/penny-v2.git
79
+ cd penny-v2
80
+ ```
81
+
82
+ 2. **Create virtual environment**
83
+ ```bash
84
+ python -m venv venv
85
+ source venv/bin/activate # On Windows: venv\Scripts\activate
86
+ ```
87
+
88
+ 3. **Install dependencies**
89
+ ```bash
90
+ pip install --upgrade pip
91
+ pip install -r requirements.txt
92
+ ```
93
+
94
+ 4. **Configure environment variables**
95
+ ```bash
96
+ # Create .env file with required variables:
97
+ # AZURE_MAPS_KEY=your_azure_maps_key
98
+ # ENVIRONMENT=development
99
+ # DEBUG_MODE=false
100
+ ```
101
+
102
+ 5. **Run the application**
103
+ ```bash
104
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
105
+ ```
106
+
107
+ 6. **Access the API**
108
+ - API: http://localhost:8000
109
+ - Interactive docs: http://localhost:8000/docs
110
+ - Health check: http://localhost:8000/health
111
+
112
+ ---
113
+
114
+ ## 🐳 Docker Deployment
115
+
116
+ ### Build the container
117
+ ```bash
118
+ docker build -t penny:latest .
119
+ ```
120
+
121
+ ### Run locally with Docker
122
+ ```bash
123
+ docker run -p 8000:8000 \
124
+ -e AZURE_OPENAI_KEY=your_key \
125
+ -e WEATHER_API_KEY=your_key \
126
+ penny:latest
127
+ ```
128
+
129
+ ---
130
+
131
+ ## ☁️ Azure ML Deployment
132
+
133
+ ### 1. Create Azure Resources
134
+ ```bash
135
+ # Create resource group
136
+ az group create --name penny-rg --location eastus
137
+
138
+ # Create Azure ML workspace
139
+ az ml workspace create --name penny-workspace -g penny-rg
140
+
141
+ # Create Azure Container Registry
142
+ az acr create --name pennyregistry --resource-group penny-rg --sku Basic
143
+ ```
144
+
145
+ ### 2. Build and Push Container
146
+ ```bash
147
+ # Login to Azure Container Registry
148
+ az acr login --name pennyregistry
149
+
150
+ # Build and tag image
151
+ docker build -t pennyregistry.azurecr.io/penny:v1 .
152
+
153
+ # Push to registry
154
+ docker push pennyregistry.azurecr.io/penny:v1
155
+ ```
156
+
157
+ ### 3. Deploy to Azure Container Instances
158
+ ```bash
159
+ az container create \
160
+ --resource-group penny-rg \
161
+ --name penny-api \
162
+ --image pennyregistry.azurecr.io/penny:v1 \
163
+ --cpu 2 \
164
+ --memory 4 \
165
+ --registry-login-server pennyregistry.azurecr.io \
166
+ --registry-username <username> \
167
+ --registry-password <password> \
168
+ --dns-name-label penny-civic-ai \
169
+ --ports 8000 \
170
+ --environment-variables \
171
+ ENVIRONMENT=production \
172
+ AZURE_OPENAI_KEY=<your-key>
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 🔧 Configuration
178
+
179
+ ### Environment Variables
180
+
181
+ | Variable | Description | Required | Default |
182
+ |----------|-------------|----------|---------|
183
+ | `ENVIRONMENT` | Deployment environment (`development`, `production`) | No | `development` |
184
+ | `AZURE_MAPS_KEY` | Azure Maps API key (for weather) | Yes | - |
185
+ | `ENVIRONMENT` | Deployment environment | No | `development` |
186
+ | `DEBUG_MODE` | Enable debug endpoints | No | `false` |
187
+ | `ALLOWED_ORIGINS` | CORS allowed origins (comma-separated) | No | `*` |
188
+ | `LOG_LEVEL` | Logging level (`INFO`, `DEBUG`, `WARNING`) | No | `INFO` |
189
+ | `TENANT_ID` | Default tenant/city identifier | No | `default` |
190
+
191
+ ### Azure Key Vault Integration (Recommended)
192
+
193
+ For production deployments, store secrets in Azure Key Vault:
194
+ ```bash
195
+ # Create Key Vault
196
+ az keyvault create --name penny-keyvault --resource-group penny-rg
197
+
198
+ # Store secrets
199
+ az keyvault secret set --vault-name penny-keyvault --name openai-key --value "your-key"
200
+
201
+ # Reference in deployment
202
+ --environment-variables \
203
+ AZURE_OPENAI_KEY="@Microsoft.KeyVault(SecretUri=https://penny-keyvault.vault.azure.net/secrets/openai-key/)"
204
+ ```
205
+
206
+ ---
207
+
208
+ ## 📡 API Usage
209
+
210
+ ### Send a message to Penny
211
+ ```bash
212
+ curl -X POST "http://localhost:8000/chat" \
213
+ -H "Content-Type: application/json" \
214
+ -d '{
215
+ "message": "What community events are happening this weekend?",
216
+ "tenant_id": "norfolk",
217
+ "user_id": "user123",
218
+ "session_id": "session456"
219
+ }'
220
+ ```
221
+
222
+ ### Response format
223
+ ```json
224
+ {
225
+ "response": "Hi! Here are some great community events happening this weekend in Norfolk...",
226
+ "intent": "community_events",
227
+ "tenant_id": "norfolk",
228
+ "session_id": "session456",
229
+ "timestamp": "2025-11-26T10:30:00Z",
230
+ "response_time_ms": 245
231
+ }
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 🧪 Testing
237
+
238
+ ### Run unit tests
239
+ ```bash
240
+ pytest tests/ -v
241
+ ```
242
+
243
+ ### Run integration tests
244
+ ```bash
245
+ pytest tests/integration/ -v
246
+ ```
247
+
248
+ ### Check code quality
249
+ ```bash
250
+ # Linting
251
+ flake8 app/ models/
252
+
253
+ # Type checking
254
+ mypy app/ models/
255
+
256
+ # Format check
257
+ black --check app/ models/
258
+ ```
259
+
260
+ ---
261
+
262
+ ## 📊 Monitoring & Logging
263
+
264
+ Penny uses structured JSON logging for production observability:
265
+
266
+ - **Application logs**: Stored in `/logs/` directory
267
+ - **Azure Application Insights**: Integration available for production
268
+ - **Health endpoint**: `/health` provides service status
269
+
270
+ ### Log format
271
+ ```json
272
+ {
273
+ "timestamp": "2025-11-26T10:30:00Z",
274
+ "level": "INFO",
275
+ "intent": "weather_query",
276
+ "tenant_id": "norfolk",
277
+ "session_id": "abc123",
278
+ "response_time_ms": 150,
279
+ "success": true,
280
+ "model_used": "gpt-4"
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## 🛡️ Security & Privacy
287
+
288
+ - **PII Protection**: All logs sanitized before storage
289
+ - **Content Moderation**: Built-in bias and safety detection
290
+ - **Secrets Management**: Azure Key Vault integration
291
+ - **Non-root Container**: Security-hardened Docker image
292
+ - **HTTPS Only**: TLS/SSL required for production endpoints
293
+
294
+ ---
295
+
296
+ ## 🤝 Contributing
297
+
298
+ We welcome contributions! Please follow these guidelines:
299
+
300
+ 1. Fork the repository
301
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
302
+ 3. Follow code style (Black, Flake8, MyPy)
303
+ 4. Add tests for new features
304
+ 5. Ensure all tests pass
305
+ 6. Submit a pull request
306
+
307
+ ### Code Standards
308
+
309
+ - **Type hints**: Required for all functions
310
+ - **Docstrings**: Google-style format
311
+ - **Error handling**: Structured try/except blocks
312
+ - **Logging**: Use `log_interaction()` for all operations
313
+ - **PII safety**: Always sanitize user data
314
+
315
+ ---
316
+
317
+ ## 📝 License
318
+
319
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
320
+
321
+ ---
322
+
323
+ ## 🙏 Acknowledgments
324
+
325
+ - Built with [FastAPI](https://fastapi.tiangolo.com/)
326
+ - Powered by [Azure Machine Learning](https://azure.microsoft.com/en-us/services/machine-learning/)
327
+ - Civic data from local government open data initiatives
328
+
329
+ ---
330
+
331
+ ## 📞 Support
332
+
333
+ - **Issues**: [GitHub Issues](https://github.com/your-org/penny-v2/issues)
334
+ - **Documentation**: [Full docs](https://docs.penny-ai.org)
335
+ - **Email**: support@penny-ai.org
336
+
337
+ ---
338
+
339
+ ## 🗺️ Roadmap
340
+
341
+ - [ ] Multi-tenant dashboard
342
+ - [ ] Voice interface integration
343
+ - [ ] Advanced sentiment analysis
344
+ - [ ] Predictive civic engagement insights
345
+ - [ ] Mobile app integration
346
+
347
+ ---
348
+
349
+ **Made with ❤️ for civic engagement**
app.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🤖 PENNY - Hugging Face Spaces Entry Point
3
+ This file is required by Hugging Face Spaces to launch the FastAPI application.
4
+ It imports and exposes the FastAPI app from app.main.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ # Add project root to Python path
12
+ PROJECT_ROOT = Path(__file__).parent
13
+ sys.path.insert(0, str(PROJECT_ROOT))
14
+
15
+ # Import the FastAPI app from app.main
16
+ from app.main import app
17
+
18
+ # Expose the app for Hugging Face Spaces
19
+ # HF Spaces will look for a variable named 'app' or will call this file as a module
20
+ __all__ = ["app"]
21
+
gradio_app.py ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🤖 PENNY V2.2 Gradio Interface
3
+ Hugging Face Space Entry Point
4
+
5
+ This file connects PENNY's backend to a Gradio chat interface,
6
+ allowing users to interact with PENNY through a web UI on Hugging Face Spaces.
7
+ """
8
+
9
+ import gradio as gr
10
+ import logging
11
+ import sys
12
+ import asyncio
13
+ from typing import List, Tuple, Dict, Any
14
+ from datetime import datetime
15
+
16
+ # Setup logging
17
+ logging.basicConfig(
18
+ level=logging.INFO,
19
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
20
+ handlers=[logging.StreamHandler(sys.stdout)]
21
+ )
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # ============================================================
25
+ # IMPORT PENNY MODULES - FIXED FOR ACTUAL FILE STRUCTURE
26
+ # ============================================================
27
+
28
+ # Initialize variables for imports
29
+ _import_error = None
30
+
31
+ try:
32
+ # Core orchestration - this is the main function we need
33
+ from app.orchestrator import run_orchestrator
34
+
35
+ # Intent classification
36
+ from app.intents import IntentType
37
+
38
+ logger.info("✅ Successfully imported PENNY modules from app/")
39
+
40
+ except ImportError as e:
41
+ _import_error = str(e)
42
+ logger.error(f"❌ Failed to import PENNY modules: {e}")
43
+ logger.error(f" Make sure all files exist in app/ folder")
44
+ logger.error(f" Current error: {str(e)}")
45
+
46
+ # Create fallback function so the interface can still load
47
+ async def run_orchestrator(message: str, context: Dict[str, Any]) -> Dict[str, Any]:
48
+ return {
49
+ "reply": f"⚠️ PENNY is initializing. Please try again in a moment.\n\nError: {_import_error}",
50
+ "intent": "error",
51
+ "confidence": 0.0
52
+ }
53
+
54
+ # ============================================================
55
+ # SERVICE AVAILABILITY CHECK
56
+ # ============================================================
57
+
58
+ def get_service_availability() -> Dict[str, bool]:
59
+ """
60
+ Check which PENNY services are available.
61
+ Returns dict of service_name -> availability status.
62
+ """
63
+ services = {}
64
+
65
+ try:
66
+ # Check if orchestrator is callable and not None
67
+ services["orchestrator"] = run_orchestrator is not None and callable(run_orchestrator)
68
+ except:
69
+ services["orchestrator"] = False
70
+
71
+ try:
72
+ # Check if event/weather module loaded
73
+ from app.event_weather import get_event_recommendations_with_weather
74
+ services["weather_service"] = True
75
+ except:
76
+ services["weather_service"] = False
77
+
78
+ try:
79
+ # Check if event database accessible
80
+ from app.location_utils import load_city_events
81
+ services["event_database"] = True
82
+ except:
83
+ services["event_database"] = False
84
+
85
+ try:
86
+ # Check if tool agent loaded
87
+ from app.tool_agent import handle_tool_request
88
+ services["resource_finder"] = True
89
+ except:
90
+ services["resource_finder"] = False
91
+
92
+ return services
93
+
94
+
95
+ # ============================================================
96
+ # SUPPORTED CITIES CONFIGURATION
97
+ # ============================================================
98
+
99
+ SUPPORTED_CITIES = [
100
+ "Atlanta, GA",
101
+ "Birmingham, AL",
102
+ "Chesterfield, VA",
103
+ "El Paso, TX",
104
+ "Norfolk, VA",
105
+ "Providence, RI",
106
+ "Seattle, WA"
107
+ ]
108
+
109
+ def get_city_choices() -> List[str]:
110
+ """Get list of supported cities for dropdown."""
111
+ try:
112
+ return ["Not sure / Other"] + sorted(SUPPORTED_CITIES)
113
+ except Exception as e:
114
+ logger.error(f"Error loading cities: {e}")
115
+ return ["Not sure / Other", "Norfolk, VA"]
116
+
117
+
118
+ # ============================================================
119
+ # CHAT HANDLER
120
+ # ============================================================
121
+
122
+ async def chat_with_penny(
123
+ message: str,
124
+ city: str,
125
+ history: List[Tuple[str, str]]
126
+ ) -> Tuple[List[Tuple[str, str]], str]:
127
+ """
128
+ Process user message through PENNY's orchestrator and return response.
129
+
130
+ Args:
131
+ message: User's input text
132
+ city: Selected city/location
133
+ history: Chat history (list of (user_msg, bot_msg) tuples)
134
+
135
+ Returns:
136
+ Tuple of (updated_history, empty_string_to_clear_input)
137
+ """
138
+ if not message.strip():
139
+ return history, ""
140
+
141
+ try:
142
+ # Build context from selected city
143
+ context = {
144
+ "timestamp": datetime.now().isoformat(),
145
+ "conversation_history": history[-5:] if history else [] # Last 5 exchanges
146
+ }
147
+
148
+ # Add location if specified
149
+ if city and city != "Not sure / Other":
150
+ context["location"] = city
151
+ context["tenant_id"] = city.split(",")[0].lower().replace(" ", "_")
152
+
153
+ logger.info(f"📨 Processing: '{message[:60]}...' | City: {city}")
154
+
155
+ # Call PENNY's orchestrator
156
+ result = await run_orchestrator(message, context)
157
+
158
+ # Extract response
159
+ reply = result.get("reply", "I'm having trouble right now. Please try again! 💛")
160
+ intent = result.get("intent", "unknown")
161
+ confidence = result.get("confidence", 0.0)
162
+
163
+ # Add to history
164
+ history.append((message, reply))
165
+
166
+ logger.info(f"✅ Response generated | Intent: {intent} | Confidence: {confidence:.2f}")
167
+
168
+ return history, ""
169
+
170
+ except Exception as e:
171
+ logger.error(f"❌ Error processing message: {e}", exc_info=True)
172
+
173
+ error_reply = (
174
+ "I'm having trouble processing your request right now. "
175
+ "Please try again in a moment! 💛\n\n"
176
+ f"_Error: {str(e)[:100]}_"
177
+ )
178
+ history.append((message, error_reply))
179
+ return history, ""
180
+
181
+
182
+ def chat_with_penny_sync(message: str, city: str, history: List[Tuple[str, str]]) -> Tuple[List[Tuple[str, str]], str]:
183
+ """
184
+ Synchronous wrapper for chat_with_penny to work with Gradio.
185
+ Gradio expects sync functions, so we create an event loop here.
186
+ """
187
+ try:
188
+ # Create new event loop for this call
189
+ loop = asyncio.new_event_loop()
190
+ asyncio.set_event_loop(loop)
191
+ result = loop.run_until_complete(chat_with_penny(message, city, history))
192
+ loop.close()
193
+ return result
194
+ except Exception as e:
195
+ logger.error(f"Error in sync wrapper: {e}")
196
+ error_msg = f"Error: {str(e)}"
197
+ history.append((message, error_msg))
198
+ return history, ""
199
+
200
+
201
+ # ============================================================
202
+ # SERVICE STATUS DISPLAY
203
+ # ============================================================
204
+
205
+ def get_service_status() -> str:
206
+ """Display current service availability status."""
207
+ try:
208
+ services = get_service_availability()
209
+ status_lines = ["**🔧 PENNY Service Status:**\n"]
210
+
211
+ service_names = {
212
+ "orchestrator": "🧠 Core Orchestrator",
213
+ "weather_service": "🌤️ Weather Service",
214
+ "event_database": "📅 Event Database",
215
+ "resource_finder": "🏛️ Resource Finder"
216
+ }
217
+
218
+ for service_key, available in services.items():
219
+ icon = "✅" if available else "⚠️"
220
+ status = "Online" if available else "Limited"
221
+ name = service_names.get(service_key, service_key.replace('_', ' ').title())
222
+ status_lines.append(f"{icon} **{name}**: {status}")
223
+
224
+ return "\n".join(status_lines)
225
+ except Exception as e:
226
+ logger.error(f"Error getting service status: {e}")
227
+ return "**⚠️ Status:** Unable to check service availability"
228
+
229
+
230
+ # ============================================================
231
+ # GRADIO UI DEFINITION
232
+ # ============================================================
233
+
234
+ # Custom CSS for enhanced styling
235
+ custom_css = """
236
+ #chatbot {
237
+ height: 500px;
238
+ overflow-y: auto;
239
+ border-radius: 8px;
240
+ }
241
+ .gradio-container {
242
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
243
+ }
244
+ #status-panel {
245
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
246
+ padding: 15px;
247
+ border-radius: 8px;
248
+ margin: 10px 0;
249
+ }
250
+ footer {
251
+ display: none !important;
252
+ }
253
+ .message-user {
254
+ background-color: #e3f2fd !important;
255
+ }
256
+ .message-bot {
257
+ background-color: #fff3e0 !important;
258
+ }
259
+ """
260
+
261
+ # Build the Gradio interface
262
+ with gr.Blocks(
263
+ theme=gr.themes.Soft(primary_hue="amber", secondary_hue="blue"),
264
+ css=custom_css,
265
+ title="PENNY V2.2 - Civic Assistant"
266
+ ) as demo:
267
+
268
+ # Header
269
+ gr.Markdown(
270
+ """
271
+ # 🤖 PENNY V2.2 - People's Engagement Network Navigator for You
272
+
273
+ **Your multilingual civic assistant connecting residents to local government services and community resources.**
274
+
275
+ ### 💬 Ask me about:
276
+ - 🌤️ **Weather conditions** and forecasts
277
+ - 📅 **Community events** and activities
278
+ - 🏛️ **Local resources** (shelters, libraries, food banks, healthcare)
279
+ - 👥 **Elected officials** and government contacts
280
+ - 🌍 **Translation** services (27+ languages)
281
+ - 📄 **Document assistance** and form help
282
+ """
283
+ )
284
+
285
+ with gr.Row():
286
+ with gr.Column(scale=2):
287
+ # City selector
288
+ city_dropdown = gr.Dropdown(
289
+ choices=get_city_choices(),
290
+ value="Norfolk, VA",
291
+ label="📍 Select Your City",
292
+ info="Choose your city for location-specific information",
293
+ interactive=True
294
+ )
295
+
296
+ # Chat interface
297
+ chatbot = gr.Chatbot(
298
+ label="💬 Chat with PENNY",
299
+ elem_id="chatbot",
300
+ avatar_images=(None, "🤖"),
301
+ show_label=True,
302
+ height=500,
303
+ bubble_full_width=False
304
+ )
305
+
306
+ # Input row
307
+ with gr.Row():
308
+ msg_input = gr.Textbox(
309
+ placeholder="Type your message here... (e.g., 'What's the weather today?')",
310
+ show_label=False,
311
+ scale=4,
312
+ container=False,
313
+ lines=1
314
+ )
315
+ submit_btn = gr.Button("Send 📤", variant="primary", scale=1)
316
+
317
+ # Clear button
318
+ clear_btn = gr.Button("🗑️ Clear Chat", variant="secondary", size="sm")
319
+
320
+ # Example queries
321
+ gr.Examples(
322
+ examples=[
323
+ ["What's the weather in Norfolk today?"],
324
+ ["Any community events this weekend?"],
325
+ ["I need help finding a food bank"],
326
+ ["Who is my city council representative?"],
327
+ ["Show me local libraries"],
328
+ ["Translate 'hello' to Spanish"],
329
+ ["Help me understand this document"]
330
+ ],
331
+ inputs=msg_input,
332
+ label="💡 Try asking:"
333
+ )
334
+
335
+ with gr.Column(scale=1):
336
+ # Service status panel
337
+ status_display = gr.Markdown(
338
+ value=get_service_status(),
339
+ label="System Status",
340
+ elem_id="status-panel"
341
+ )
342
+
343
+ # Refresh status button
344
+ refresh_btn = gr.Button("🔄 Refresh Status", size="sm", variant="secondary")
345
+
346
+ gr.Markdown(
347
+ """
348
+ ### 🌟 Key Features
349
+
350
+ - ✅ **27+ Languages** supported
351
+ - ✅ **Real-time weather** via Azure Maps
352
+ - ✅ **Community events** database
353
+ - ✅ **Local resource** finder
354
+ - ✅ **Government contact** lookup
355
+ - ✅ **Document processing** help
356
+ - ✅ **Multilingual** support
357
+
358
+ ---
359
+
360
+ ### 📍 Supported Cities
361
+
362
+ - Atlanta, GA
363
+ - Birmingham, AL
364
+ - Chesterfield, VA
365
+ - El Paso, TX
366
+ - Norfolk, VA
367
+ - Providence, RI
368
+ - Seattle, WA
369
+
370
+ ---
371
+
372
+ ### 🆘 Need Help?
373
+
374
+ PENNY can assist with:
375
+ - Finding emergency services
376
+ - Locating government offices
377
+ - Understanding civic processes
378
+ - Accessing community programs
379
+
380
+ ---
381
+
382
+ 💛 *PENNY is here to help connect you with civic resources!*
383
+ """
384
+ )
385
+
386
+ # Event handlers
387
+ submit_btn.click(
388
+ fn=chat_with_penny_sync,
389
+ inputs=[msg_input, city_dropdown, chatbot],
390
+ outputs=[chatbot, msg_input]
391
+ )
392
+
393
+ msg_input.submit(
394
+ fn=chat_with_penny_sync,
395
+ inputs=[msg_input, city_dropdown, chatbot],
396
+ outputs=[chatbot, msg_input]
397
+ )
398
+
399
+ clear_btn.click(
400
+ fn=lambda: ([], ""),
401
+ inputs=None,
402
+ outputs=[chatbot, msg_input]
403
+ )
404
+
405
+ refresh_btn.click(
406
+ fn=get_service_status,
407
+ inputs=None,
408
+ outputs=status_display
409
+ )
410
+
411
+ # Footer
412
+ gr.Markdown(
413
+ """
414
+ ---
415
+ **Built with:** Python • FastAPI • Gradio • Azure ML • Hugging Face Transformers
416
+
417
+ **Version:** 2.2 | **Last Updated:** November 2025
418
+
419
+ _PENNY is an open-source civic engagement platform designed to improve access to government services._
420
+ """
421
+ )
422
+
423
+
424
+ # ============================================================
425
+ # INITIALIZATION AND LAUNCH
426
+ # ============================================================
427
+
428
+ def initialize_penny():
429
+ """Initialize PENNY services at startup."""
430
+ logger.info("=" * 70)
431
+ logger.info("🚀 Initializing PENNY V2.2 Gradio Interface")
432
+ logger.info("=" * 70)
433
+
434
+ # Display service availability at startup
435
+ logger.info("\n📊 Service Availability Check:")
436
+ services = get_service_availability()
437
+
438
+ all_available = True
439
+ for service, available in services.items():
440
+ status = "✅ Available" if available else "❌ Not loaded"
441
+ logger.info(f" {service.ljust(20)}: {status}")
442
+ if not available:
443
+ all_available = False
444
+
445
+ if all_available:
446
+ logger.info("\n✅ All services loaded successfully!")
447
+ else:
448
+ logger.warning("\n⚠️ Some services are not available. PENNY will run with limited functionality.")
449
+
450
+ logger.info("\n" + "=" * 70)
451
+ logger.info("🤖 PENNY is ready to help residents!")
452
+ logger.info("=" * 70 + "\n")
453
+
454
+
455
+ if __name__ == "__main__":
456
+ # Initialize services
457
+ initialize_penny()
458
+
459
+ # Launch the Gradio app
460
+ demo.launch(
461
+ server_name="0.0.0.0",
462
+ server_port=7860,
463
+ share=False,
464
+ show_error=True
465
+ )
requirements.txt ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ============================================
2
+ # PENNY Project - Production Dependencies
3
+ # Civic Engagement AI - Python 3.10+
4
+ # ============================================
5
+
6
+ # ============================================
7
+ # FastAPI Core & Web Framework
8
+ # ============================================
9
+ fastapi==0.111.0
10
+ uvicorn[standard]==0.29.0
11
+ httpx==0.27.0
12
+ python-multipart==0.0.9
13
+ pydantic==2.6.4
14
+ pydantic-settings==2.2.1
15
+
16
+ # ============================================
17
+ # Configuration & Environment
18
+ # ============================================
19
+ python-dotenv==1.0.1
20
+
21
+ # ============================================
22
+ # HTTP & API Clients
23
+ # ============================================
24
+ requests==2.31.0
25
+ aiohttp==3.9.3
26
+
27
+ # ============================================
28
+ # Machine Learning & NLP (Optimized for Production)
29
+ # ============================================
30
+ # Core ML framework
31
+ torch==2.2.1
32
+ transformers==4.38.2
33
+ sentencepiece==0.2.0
34
+ tokenizers==0.15.2
35
+
36
+ # Model acceleration (only if GPU available)
37
+ accelerate==0.27.2
38
+
39
+ # Scientific computing
40
+ numpy==1.26.4
41
+ scipy==1.12.0
42
+
43
+ # ============================================
44
+ # Data Processing & Validation
45
+ # ============================================
46
+ pandas==2.2.1
47
+ jsonschema==4.21.1
48
+
49
+ # ============================================
50
+ # Logging & Monitoring
51
+ # ============================================
52
+ python-json-logger==2.0.7
53
+ structlog==24.1.0
54
+
55
+ # ============================================
56
+ # Date/Time Handling
57
+ # ============================================
58
+ python-dateutil==2.9.0
59
+ pytz==2024.1
60
+
61
+ # ============================================
62
+ # Security & Cryptography
63
+ # ============================================
64
+ cryptography==42.0.5
65
+
66
+ # ============================================
67
+ # Testing & Development (optional - install separately for dev)
68
+ # ============================================
69
+ # pytest==8.1.1
70
+ # pytest-asyncio==0.23.5
71
+ # pytest-cov==4.1.0
72
+ # httpx==0.27.0 # Already included above
73
+ # black==24.3.0
74
+ # flake8==7.0.0
75
+ # mypy==1.9.0
76
+
77
+ # ============================================
78
+ # Gradio UI Framework (Hugging Face Spaces)
79
+ # ============================================
80
+ # Updated to latest 4.x version for compatibility and new features
81
+ # Minimum version 4.44.0 for current code compatibility
82
+ gradio>=4.44.0,<5.0.0