Spaces:
No application file
No application file
Upload 3 files
Browse files- README.md +349 -0
- gradio_app.py +465 -0
- 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 |
+
[](https://www.python.org/downloads/)
|
| 18 |
+
[](https://azure.microsoft.com/en-us/services/machine-learning/)
|
| 19 |
+
[](https://fastapi.tiangolo.com/)
|
| 20 |
+
[](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**
|
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
|