pythonprincess commited on
Commit
d631d4d
·
verified ·
1 Parent(s): 0f78395

Delete gradio_app.py

Browse files
Files changed (1) hide show
  1. gradio_app.py +0 -502
gradio_app.py DELETED
@@ -1,502 +0,0 @@
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
- import os
14
- from dotenv import load_dotenv # Add this
15
- from typing import List, Tuple, Dict, Any
16
- from datetime import datetime
17
-
18
- # Load environment variables from .env file
19
- load_dotenv() # Add this line
20
-
21
- # Verify the key loaded (optional debug)
22
- if os.getenv("AZURE_MAPS_KEY"):
23
- print("✅ AZURE_MAPS_KEY loaded successfully")
24
- else:
25
- print("⚠️ AZURE_MAPS_KEY not found!")
26
-
27
- from typing import List, Tuple, Dict, Any
28
- from datetime import datetime
29
-
30
- # Setup logging
31
- logging.basicConfig(
32
- level=logging.INFO,
33
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
34
- handlers=[logging.StreamHandler(sys.stdout)]
35
- )
36
- logger = logging.getLogger(__name__)
37
-
38
- # ============================================================
39
- # IMPORT PENNY MODULES - FIXED FOR ACTUAL FILE STRUCTURE
40
- # ============================================================
41
-
42
- try:
43
- # Core orchestration and routing
44
- from app.orchestrator import run_orchestrator
45
- from app.router import route_query
46
-
47
- # Utilities
48
- from app.location_utils import geocode_address, get_user_location
49
- from app.logging_utils import setup_logger
50
-
51
- # Event and weather handling
52
- from app.event_weather import get_event_recommendations_with_weather
53
-
54
- # Tool agent for officials and resources
55
- from app.tool_agent import (
56
- search_officials,
57
- search_resources,
58
- format_official_response,
59
- format_resource_response
60
- )
61
-
62
- # Model loader (if needed for initialization)
63
- from app.model_loader import initialize_models
64
-
65
- # Intent classification
66
- from app.intents import classify_intent, IntentType
67
-
68
- logger.info("✅ Successfully imported PENNY modules from app/")
69
-
70
- except ImportError as import_error:
71
- logger.error(f"❌ Failed to import PENNY modules: {import_error}")
72
- logger.error(f" Make sure all files exist in app/ folder")
73
- logger.error(f" Current error: {str(import_error)}")
74
-
75
- # Create fallback functions so the interface can still load
76
- async def run_orchestrator(message: str, context: Dict[str, Any]) -> Dict[str, Any]:
77
- return {
78
- "reply": "⚠️ PENNY is initializing. Please try again in a moment.",
79
- "intent": "error",
80
- "confidence": 0.0
81
- }
82
-
83
- def get_service_availability() -> Dict[str, bool]:
84
- return {
85
- "orchestrator": False,
86
- "weather_service": False,
87
- "event_database": False,
88
- "resource_finder": False
89
- }
90
-
91
- # ============================================================
92
- # SERVICE AVAILABILITY CHECK
93
- # ============================================================
94
-
95
- def get_service_availability() -> Dict[str, bool]:
96
- """
97
- Check which PENNY services are available.
98
- Returns dict of service_name -> availability status.
99
- """
100
- services = {}
101
-
102
- try:
103
- # Check if orchestrator is callable
104
- services["orchestrator"] = callable(run_orchestrator)
105
- except:
106
- services["orchestrator"] = False
107
-
108
- try:
109
- # Check if event/weather module loaded
110
- from app.event_weather import get_event_recommendations_with_weather
111
- services["weather_service"] = True
112
- except:
113
- services["weather_service"] = False
114
-
115
- try:
116
- # Check if event database accessible
117
- from app.event_weather import get_event_recommendations_with_weather
118
- services["event_database"] = True
119
- except:
120
- services["event_database"] = False
121
-
122
- try:
123
- # Check if tool agent loaded
124
- from app.tool_agent import search_resources
125
- services["resource_finder"] = True
126
- except:
127
- services["resource_finder"] = False
128
-
129
- return services
130
-
131
-
132
- # ============================================================
133
- # SUPPORTED CITIES CONFIGURATION
134
- # ============================================================
135
-
136
- SUPPORTED_CITIES = [
137
- "Atlanta, GA",
138
- "Birmingham, AL",
139
- "Chesterfield, VA",
140
- "El Paso, TX",
141
- "Norfolk, VA",
142
- "Providence, RI",
143
- "Seattle, WA"
144
- ]
145
-
146
- def get_city_choices() -> List[str]:
147
- """Get list of supported cities for dropdown."""
148
- try:
149
- return ["Not sure / Other"] + sorted(SUPPORTED_CITIES)
150
- except Exception as e:
151
- logger.error(f"Error loading cities: {e}")
152
- return ["Not sure / Other", "Norfolk, VA"]
153
-
154
-
155
- # ============================================================
156
- # CHAT HANDLER
157
- # ============================================================
158
-
159
- async def chat_with_penny(
160
- message: str,
161
- city: str,
162
- history: List[Tuple[str, str]]
163
- ) -> Tuple[List[Tuple[str, str]], str]:
164
- """
165
- Process user message through PENNY's orchestrator and return response.
166
-
167
- Args:
168
- message: User's input text
169
- city: Selected city/location
170
- history: Chat history (list of (user_msg, bot_msg) tuples)
171
-
172
- Returns:
173
- Tuple of (updated_history, empty_string_to_clear_input)
174
- """
175
- if not message.strip():
176
- return history, ""
177
-
178
- try:
179
- # Build context from selected city
180
- context = {
181
- "timestamp": datetime.now().isoformat(),
182
- "conversation_history": history[-5:] if history else [] # Last 5 exchanges
183
- }
184
-
185
- # Add location if specified
186
- if city and city != "Not sure / Other":
187
- context["location"] = city
188
- context["tenant_id"] = city.split(",")[0].lower().replace(" ", "_")
189
-
190
- logger.info(f"📨 Processing: '{message[:60]}...' | City: {city}")
191
-
192
- # Call PENNY's orchestrator
193
- result = await run_orchestrator(message, context)
194
-
195
- # Extract response
196
- reply = result.get("reply", "I'm having trouble right now. Please try again! 💛")
197
- intent = result.get("intent", "unknown")
198
- confidence = result.get("confidence", 0.0)
199
-
200
- # Add to history
201
- history.append((message, reply))
202
-
203
- logger.info(f"✅ Response generated | Intent: {intent} | Confidence: {confidence:.2f}")
204
-
205
- return history, ""
206
-
207
- except Exception as e:
208
- logger.error(f"❌ Error processing message: {e}", exc_info=True)
209
-
210
- error_reply = (
211
- "I'm having trouble processing your request right now. "
212
- "Please try again in a moment! 💛\n\n"
213
- f"_Error: {str(e)[:100]}_"
214
- )
215
- history.append((message, error_reply))
216
- return history, ""
217
-
218
-
219
- def chat_with_penny_sync(message: str, city: str, history: List[Tuple[str, str]]) -> Tuple[List[Tuple[str, str]], str]:
220
- """
221
- Synchronous wrapper for chat_with_penny to work with Gradio.
222
- Gradio expects sync functions, so we create an event loop here.
223
- """
224
- try:
225
- # Create new event loop for this call
226
- loop = asyncio.new_event_loop()
227
- asyncio.set_event_loop(loop)
228
- result = loop.run_until_complete(chat_with_penny(message, city, history))
229
- loop.close()
230
- return result
231
- except Exception as e:
232
- logger.error(f"Error in sync wrapper: {e}")
233
- error_msg = f"Error: {str(e)}"
234
- history.append((message, error_msg))
235
- return history, ""
236
-
237
-
238
- # ============================================================
239
- # SERVICE STATUS DISPLAY
240
- # ============================================================
241
-
242
- def get_service_status() -> str:
243
- """Display current service availability status."""
244
- try:
245
- services = get_service_availability()
246
- status_lines = ["**🔧 PENNY Service Status:**\n"]
247
-
248
- service_names = {
249
- "orchestrator": "🧠 Core Orchestrator",
250
- "weather_service": "🌤️ Weather Service",
251
- "event_database": "📅 Event Database",
252
- "resource_finder": "🏛️ Resource Finder"
253
- }
254
-
255
- for service_key, available in services.items():
256
- icon = "✅" if available else "⚠️"
257
- status = "Online" if available else "Limited"
258
- name = service_names.get(service_key, service_key.replace('_', ' ').title())
259
- status_lines.append(f"{icon} **{name}**: {status}")
260
-
261
- return "\n".join(status_lines)
262
- except Exception as e:
263
- logger.error(f"Error getting service status: {e}")
264
- return "**⚠️ Status:** Unable to check service availability"
265
-
266
-
267
- # ============================================================
268
- # GRADIO UI DEFINITION
269
- # ============================================================
270
-
271
- # Custom CSS for enhanced styling
272
- custom_css = """
273
- #chatbot {
274
- height: 500px;
275
- overflow-y: auto;
276
- border-radius: 8px;
277
- }
278
- .gradio-container {
279
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
280
- }
281
- #status-panel {
282
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
283
- padding: 15px;
284
- border-radius: 8px;
285
- margin: 10px 0;
286
- }
287
- footer {
288
- display: none !important;
289
- }
290
- .message-user {
291
- background-color: #e3f2fd !important;
292
- }
293
- .message-bot {
294
- background-color: #fff3e0 !important;
295
- }
296
- """
297
-
298
- # Build the Gradio interface
299
- with gr.Blocks(
300
- theme=gr.themes.Soft(primary_hue="amber", secondary_hue="blue"),
301
- css=custom_css,
302
- title="PENNY V2.2 - Civic Assistant"
303
- ) as demo:
304
-
305
- # Header
306
- gr.Markdown(
307
- """
308
- # 🤖 PENNY V2.2 - People's Engagement Network Navigator for You
309
-
310
- **Your multilingual civic assistant connecting residents to local government services and community resources.**
311
-
312
- ### 💬 Ask me about:
313
- - 🌤️ **Weather conditions** and forecasts
314
- - 📅 **Community events** and activities
315
- - 🏛️ **Local resources** (shelters, libraries, food banks, healthcare)
316
- - 👥 **Elected officials** and government contacts
317
- - 🌍 **Translation** services (27+ languages)
318
- - 📄 **Document assistance** and form help
319
- """
320
- )
321
-
322
- with gr.Row():
323
- with gr.Column(scale=2):
324
- # City selector
325
- city_dropdown = gr.Dropdown(
326
- choices=get_city_choices(),
327
- value="Norfolk, VA",
328
- label="📍 Select Your City",
329
- info="Choose your city for location-specific information",
330
- interactive=True
331
- )
332
-
333
- # Chat interface
334
- chatbot = gr.Chatbot(
335
- label="💬 Chat with PENNY",
336
- elem_id="chatbot",
337
- avatar_images=(None, "🤖"),
338
- show_label=True,
339
- height=500,
340
- bubble_full_width=False
341
- )
342
-
343
- # Input row
344
- with gr.Row():
345
- msg_input = gr.Textbox(
346
- placeholder="Type your message here... (e.g., 'What's the weather today?')",
347
- show_label=False,
348
- scale=4,
349
- container=False,
350
- lines=1
351
- )
352
- submit_btn = gr.Button("Send 📤", variant="primary", scale=1)
353
-
354
- # Clear button
355
- clear_btn = gr.Button("🗑️ Clear Chat", variant="secondary", size="sm")
356
-
357
- # Example queries
358
- gr.Examples(
359
- examples=[
360
- ["What's the weather in Norfolk today?"],
361
- ["Any community events this weekend?"],
362
- ["I need help finding a food bank"],
363
- ["Who is my city council representative?"],
364
- ["Show me local libraries"],
365
- ["Translate 'hello' to Spanish"],
366
- ["Help me understand this document"]
367
- ],
368
- inputs=msg_input,
369
- label="💡 Try asking:"
370
- )
371
-
372
- with gr.Column(scale=1):
373
- # Service status panel
374
- status_display = gr.Markdown(
375
- value=get_service_status(),
376
- label="System Status",
377
- elem_id="status-panel"
378
- )
379
-
380
- # Refresh status button
381
- refresh_btn = gr.Button("🔄 Refresh Status", size="sm", variant="secondary")
382
-
383
- gr.Markdown(
384
- """
385
- ### 🌟 Key Features
386
-
387
- - ✅ **27+ Languages** supported
388
- - ✅ **Real-time weather** via Azure Maps
389
- - ✅ **Community events** database
390
- - ✅ **Local resource** finder
391
- - ✅ **Government contact** lookup
392
- - ✅ **Document processing** help
393
- - ✅ **Multilingual** support
394
-
395
- ---
396
-
397
- ### 📍 Supported Cities
398
-
399
- - Atlanta, GA
400
- - Birmingham, AL
401
- - Chesterfield, VA
402
- - El Paso, TX
403
- - Norfolk, VA
404
- - Providence, RI
405
- - Seattle, WA
406
-
407
- ---
408
-
409
- ### 🆘 Need Help?
410
-
411
- PENNY can assist with:
412
- - Finding emergency services
413
- - Locating government offices
414
- - Understanding civic processes
415
- - Accessing community programs
416
-
417
- ---
418
-
419
- 💛 *PENNY is here to help connect you with civic resources!*
420
- """
421
- )
422
-
423
- # Event handlers
424
- submit_btn.click(
425
- fn=chat_with_penny_sync,
426
- inputs=[msg_input, city_dropdown, chatbot],
427
- outputs=[chatbot, msg_input]
428
- )
429
-
430
- msg_input.submit(
431
- fn=chat_with_penny_sync,
432
- inputs=[msg_input, city_dropdown, chatbot],
433
- outputs=[chatbot, msg_input]
434
- )
435
-
436
- clear_btn.click(
437
- fn=lambda: ([], ""),
438
- inputs=None,
439
- outputs=[chatbot, msg_input]
440
- )
441
-
442
- refresh_btn.click(
443
- fn=get_service_status,
444
- inputs=None,
445
- outputs=status_display
446
- )
447
-
448
- # Footer
449
- gr.Markdown(
450
- """
451
- ---
452
- **Built with:** Python • FastAPI • Gradio • Azure ML • Hugging Face Transformers
453
-
454
- **Version:** 2.2 | **Last Updated:** November 2025
455
-
456
- _PENNY is an open-source civic engagement platform designed to improve access to government services._
457
- """
458
- )
459
-
460
-
461
- # ============================================================
462
- # INITIALIZATION AND LAUNCH
463
- # ============================================================
464
-
465
- def initialize_penny():
466
- """Initialize PENNY services at startup."""
467
- logger.info("=" * 70)
468
- logger.info("🚀 Initializing PENNY V2.2 Gradio Interface")
469
- logger.info("=" * 70)
470
-
471
- # Display service availability at startup
472
- logger.info("\n📊 Service Availability Check:")
473
- services = get_service_availability()
474
-
475
- all_available = True
476
- for service, available in services.items():
477
- status = "✅ Available" if available else "❌ Not loaded"
478
- logger.info(f" {service.ljust(20)}: {status}")
479
- if not available:
480
- all_available = False
481
-
482
- if all_available:
483
- logger.info("\n✅ All services loaded successfully!")
484
- else:
485
- logger.warning("\n⚠️ Some services are not available. PENNY will run with limited functionality.")
486
-
487
- logger.info("\n" + "=" * 70)
488
- logger.info("🤖 PENNY is ready to help residents!")
489
- logger.info("=" * 70 + "\n")
490
-
491
-
492
- if __name__ == "__main__":
493
- # Initialize services
494
- initialize_penny()
495
-
496
- # Launch the Gradio app
497
- demo.launch(
498
- server_name="0.0.0.0",
499
- server_port=7860,
500
- share=False,
501
- show_error=True
502
- )