pythonprincess commited on
Commit
b7c65b1
·
verified ·
1 Parent(s): 2e4519e

Delete gradio_app.py

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