Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| """ | |
| Comprehensive demo: AI Summarization + Keyword Alerts + Batch Processing | |
| Shows the complete workflow from: | |
| 1. Loading discovered jurisdictions | |
| 2. AI summarization of meeting content | |
| 3. Keyword alert generation | |
| 4. Quality metrics tracking | |
| """ | |
| import asyncio | |
| from datetime import datetime | |
| from pathlib import Path | |
| # Check for OpenAI API key | |
| from config.settings import settings | |
| # Import our new capabilities | |
| from extraction.summarizer import MeetingSummarizer, summarize_meeting_simple | |
| from alerts.keyword_monitor import KeywordAlertSystem, generate_alert_email | |
| from discovery.batch_processor import BatchProcessor, JurisdictionQuality | |
| from models.meeting_event import MeetingEvent, Classification, Location | |
| def print_section(title: str): | |
| """Print a section header.""" | |
| print("\n" + "=" * 80) | |
| print(f" {title}") | |
| print("=" * 80 + "\n") | |
| def demo_ai_summarization(): | |
| """Demo: AI-powered meeting summarization (OpenTowns pattern).""" | |
| print_section("π€ AI SUMMARIZATION (OpenTowns Pattern)") | |
| # Example meeting | |
| event = MeetingEvent( | |
| title="City Council Regular Meeting", | |
| description="Discussion of community water fluoridation program", | |
| classification=Classification.COUNCIL, | |
| start=datetime(2026, 4, 15, 18, 0), | |
| location=Location( | |
| name="City Hall Council Chambers", | |
| address="710 N 20th Street", | |
| city="Birmingham", | |
| state="AL" | |
| ), | |
| jurisdiction_name="Birmingham", | |
| state_code="AL", | |
| source="https://birminghamal.gov/meetings/2026-04-15" | |
| ) | |
| # Example meeting transcript | |
| transcript = """ | |
| BIRMINGHAM CITY COUNCIL REGULAR MEETING | |
| April 15, 2026 - 6:00 PM | |
| City Hall Council Chambers | |
| PRESENT: Mayor Woodfin, Council President Scales, Councilors Smith, | |
| Johnson, Martinez, Davis, Brown, Wilson, Thompson, Lee | |
| AGENDA ITEM 3: RESOLUTION 2026-045 | |
| Community Water Fluoridation Program Implementation | |
| Mayor Woodfin: "Tonight we are considering Resolution 2026-045, which | |
| would implement a community water fluoridation program for Birmingham's | |
| municipal water system. Dr. Sarah Johnson from the Alabama Department | |
| of Public Health is here to present." | |
| Dr. Johnson: "Thank you, Mayor. Community water fluoridation is recognized | |
| by the CDC as one of the ten great public health achievements of the 20th | |
| century. It's a safe, effective, and equitable way to prevent tooth decay | |
| across all age groups and socioeconomic levels. | |
| The proposed program would adjust fluoride levels in Birmingham's water | |
| to 0.7 mg/L, consistent with CDC and American Dental Association guidelines. | |
| Research shows this reduces tooth decay by 25% in children and adults. | |
| We estimate the program would cost $120,000 annually in operation and | |
| maintenance. However, the economic benefits are substantial - for every | |
| dollar invested, we save approximately $10 in dental treatment costs. | |
| That's $1.2 million in prevented costs annually for Birmingham." | |
| Councilor Smith: "I've reviewed the financial analysis and support this | |
| initiative. Tooth decay is a significant problem in our community, | |
| particularly among children. This is a cost-effective prevention measure." | |
| Councilor Johnson: "I appreciate the presentation, but I'd like to hear | |
| from our residents before we vote. I propose we schedule a public hearing | |
| to gather community input." | |
| Mayor Woodfin: "That's a reasonable request. Let's schedule a public | |
| hearing for May 6th at 6:00 PM." | |
| MOTION by Councilor Smith, seconded by Councilor Martinez, to schedule | |
| a public hearing on Resolution 2026-045 for May 6, 2026 at 6:00 PM. | |
| VOTE: 9 Ayes, 1 No (Councilor Thompson) | |
| Motion carried. | |
| AGENDA ITEM 4: UPDATE ON MEDICAID DENTAL EXPANSION | |
| Health Director Martinez: "The state has approved expanded Medicaid dental | |
| coverage for adults. We're working with local dental clinics to ensure | |
| capacity. We expect 5,000 newly eligible residents in Birmingham." | |
| MEETING ADJOURNED at 8:15 PM | |
| Next meeting: April 29, 2026 at 6:00 PM | |
| """ | |
| # Check if API key is configured | |
| if not settings.openai_api_key: | |
| print("β οΈ OpenAI API key not configured.") | |
| print("\nTo enable AI summarization:") | |
| print(" 1. Set OPENAI_API_KEY in your .env file") | |
| print(" 2. Or export OPENAI_API_KEY='sk-...'") | |
| print("\nπ Showing what the output would look like:\n") | |
| # Show mock summary | |
| print("Executive Summary:") | |
| print(" The Birmingham City Council voted 9-1 to schedule a public hearing") | |
| print(" on a community water fluoridation program. The program would cost") | |
| print(" $120,000 annually but could prevent $1.2M in dental costs.") | |
| print("\nKey Decisions:") | |
| print(" β’ Public hearing scheduled for May 6, 2026") | |
| print(" β’ Resolution 2026-045 moved to public comment phase") | |
| print("\nHealth Policy Items:") | |
| print(" β’ Community water fluoridation program (0.7 mg/L CDC standard)") | |
| print(" β’ Medicaid dental expansion for 5,000 Birmingham residents") | |
| print("\nNext Actions:") | |
| print(" β’ Public hearing: May 6, 2026 at 6:00 PM") | |
| print(" β’ Next council meeting: April 29, 2026") | |
| return | |
| # Generate real summary | |
| try: | |
| summarizer = MeetingSummarizer() | |
| summary = summarizer.summarize(event, transcript, focus_on_health=True) | |
| print(f"π Meeting: {event.title}") | |
| print(f"π Location: {event.jurisdiction_name}, {event.state_code}") | |
| print(f"π Date: {event.start.strftime('%B %d, %Y')}") | |
| print(f"\n⨠Executive Summary:") | |
| print(f" {summary.executive_summary}") | |
| if summary.key_decisions: | |
| print(f"\nβ Key Decisions ({len(summary.key_decisions)}):") | |
| for decision in summary.key_decisions: | |
| print(f" β’ {decision}") | |
| if summary.health_policy_items: | |
| print(f"\nπ₯ Health Policy Items ({len(summary.health_policy_items)}):") | |
| for item in summary.health_policy_items: | |
| print(f" β’ {item}") | |
| if summary.next_actions: | |
| print(f"\nβοΈ Next Actions ({len(summary.next_actions)}):") | |
| for action in summary.next_actions: | |
| print(f" β’ {action}") | |
| print(f"\nπ Quality Metrics:") | |
| print(f" Confidence: {summary.confidence_score:.0%}") | |
| print(f" Source length: {summary.source_length:,} chars") | |
| print(f" Summary length: {summary.summary_length:,} chars") | |
| print(f" Compression ratio: {(summary.summary_length/summary.source_length):.1%}") | |
| print(f" Model: {summary.model_used}") | |
| print(f" Tokens used: {summary.tokens_used:,}") | |
| except Exception as e: | |
| print(f"β Error generating summary: {e}") | |
| def demo_keyword_alerts(): | |
| """Demo: Keyword-based alert system (OpenTowns pattern).""" | |
| print_section("π KEYWORD ALERTS (OpenTowns Pattern)") | |
| # Same event and transcript as above | |
| event = MeetingEvent( | |
| title="City Council Regular Meeting", | |
| classification=Classification.COUNCIL, | |
| start=datetime(2026, 4, 15, 18, 0), | |
| jurisdiction_name="Birmingham", | |
| state_code="AL", | |
| source="https://birminghamal.gov/meetings/2026-04-15" | |
| ) | |
| transcript = """ | |
| Birmingham City Council - April 15, 2026 | |
| Resolution 2026-045: Community Water Fluoridation Program | |
| The council voted to schedule a public hearing on implementing community | |
| water fluoridation. Dr. Johnson from the Alabama Department of Public Health | |
| presented data showing fluoridation reduces tooth decay by 25%. The program | |
| would adjust fluoride levels to 0.7 mg/L per CDC guidelines. | |
| Cost-benefit analysis: $120,000 annual cost, $1.2 million in prevented | |
| dental treatment costs. Vote: 9-1 to schedule public hearing May 6. | |
| Also discussed: Medicaid dental expansion for adults, 5,000 newly eligible | |
| Birmingham residents. Health Director Martinez coordinating with dental | |
| clinics to ensure capacity. | |
| """ | |
| # Scan for keywords | |
| alert_system = KeywordAlertSystem() | |
| alerts = alert_system.scan_meeting(event, transcript) | |
| if alerts: | |
| alert = alerts[0] | |
| print(f"π¨ ALERT GENERATED!") | |
| print(f"\nAlert ID: {alert.alert_id}") | |
| print(f"Priority: {alert.priority.value.upper()} ({'π΄' if alert.priority.value == 'critical' else 'π ' if alert.priority.value == 'high' else 'π‘'})") | |
| print(f"\nπ Meeting Details:") | |
| print(f" Jurisdiction: {alert.jurisdiction_name}, {alert.state_code}") | |
| print(f" Title: {alert.meeting_title}") | |
| print(f" Date: {alert.meeting_date.strftime('%B %d, %Y at %I:%M %p')}") | |
| print(f"\nπ― Match Details:") | |
| print(f" Total matches: {alert.total_matches}") | |
| print(f" Categories: {', '.join(alert.categories_matched)}") | |
| print(f" Confidence: {alert.confidence_score:.0%}") | |
| print(f"\nπ Keywords Found ({len(alert.keywords_found)}):") | |
| for i, keyword in enumerate(alert.keywords_found[:12], 1): | |
| print(f" {i:2d}. {keyword}") | |
| if len(alert.keywords_found) > 12: | |
| print(f" ... and {len(alert.keywords_found) - 12} more") | |
| print(f"\nπ Relevant Excerpt:") | |
| print(f" \"{alert.snippet[:250]}...\"") | |
| print(f"\nπ§ Email Alert:") | |
| print(f" Generated HTML email ready to send to subscribers") | |
| print(f" Preview: 'CRITICAL Priority Alert: {alert.meeting_title}'") | |
| # Show first few lines of HTML email | |
| email_html = generate_alert_email(alert) | |
| print(f" Length: {len(email_html):,} chars") | |
| else: | |
| print("βΉοΈ No alerts generated (insufficient keyword matches)") | |
| def demo_batch_processing(): | |
| """Demo: Batch processing with quality metrics (LocalView pattern).""" | |
| print_section("π BATCH PROCESSING & QUALITY METRICS (LocalView Pattern)") | |
| print("This system handles large-scale processing of 1,000+ jurisdictions:\n") | |
| # Show quality metric example | |
| print("π Quality Tracking Per Jurisdiction:\n") | |
| example_metrics = JurisdictionQuality( | |
| jurisdiction_name="Birmingham", | |
| state_code="AL", | |
| fips_code="0107000", | |
| url="https://birminghamal.gov", | |
| platform="legistar", | |
| total_meetings_expected=24, # Biweekly meetings | |
| total_meetings_found=20, | |
| meetings_with_agendas=20, | |
| meetings_with_minutes=15, | |
| meetings_with_videos=10, | |
| meetings_with_transcripts=8, | |
| last_scraped=datetime.utcnow(), | |
| last_meeting_found=datetime(2026, 4, 15), | |
| scraping_frequency="biweekly", | |
| consecutive_successes=5, | |
| consecutive_failures=0, | |
| total_scrapes=10, | |
| successful_scrapes=10, | |
| last_success=datetime.utcnow(), | |
| last_error=None, | |
| completeness_score=85.0, | |
| reliability_score=100.0, | |
| freshness_score=100.0, | |
| overall_quality=90.0, | |
| health_status="healthy", | |
| created_at=datetime(2026, 1, 1), | |
| updated_at=datetime.utcnow() | |
| ) | |
| print(f"Jurisdiction: {example_metrics.jurisdiction_name}, {example_metrics.state_code}") | |
| print(f"Platform: {example_metrics.platform}") | |
| print(f"\nData Completeness:") | |
| print(f" Expected meetings: {example_metrics.total_meetings_expected}") | |
| print(f" Found meetings: {example_metrics.total_meetings_found}") | |
| print(f" With agendas: {example_metrics.meetings_with_agendas}") | |
| print(f" With minutes: {example_metrics.meetings_with_minutes}") | |
| print(f" With videos: {example_metrics.meetings_with_videos}") | |
| print(f"\nReliability:") | |
| print(f" Total scrapes: {example_metrics.total_scrapes}") | |
| print(f" Successful: {example_metrics.successful_scrapes}") | |
| print(f" Success rate: {(example_metrics.successful_scrapes/example_metrics.total_scrapes)*100:.0f}%") | |
| print(f" Consecutive successes: {example_metrics.consecutive_successes}") | |
| print(f"\nQuality Scores:") | |
| print(f" Completeness: {example_metrics.completeness_score:.1f}/100") | |
| print(f" Reliability: {example_metrics.reliability_score:.1f}/100") | |
| print(f" Freshness: {example_metrics.freshness_score:.1f}/100") | |
| print(f" Overall: {example_metrics.overall_quality:.1f}/100") | |
| print(f"\nHealth Status: {example_metrics.health_status.upper()} β ") | |
| print("\nπ Batch Processing Features:") | |
| print(" β’ Process 100 jurisdictions at a time") | |
| print(" β’ Track success/failure per batch") | |
| print(" β’ Automatic retry with exponential backoff") | |
| print(" β’ Resume from interruption") | |
| print(" β’ Quality metrics per jurisdiction") | |
| print(" β’ System-wide health reporting") | |
| print("\nπ‘ Example Usage:") | |
| print(""" | |
| from discovery.batch_processor import BatchProcessor | |
| processor = BatchProcessor(batch_size=100) | |
| # Process all high-priority jurisdictions | |
| for batch_result in processor.process_all_jurisdictions(priority_filter='high'): | |
| print(f"Batch {batch_result.batch_number}: " | |
| f"{batch_result.success_rate:.1f}% success") | |
| print(f" Meetings found: {batch_result.meetings_found}") | |
| print(f" Duration: {batch_result.duration_seconds:.0f}s") | |
| # Get system health report | |
| health = processor.get_system_health_report() | |
| print(f"System health: {health['health_percentage']:.1f}% healthy jurisdictions") | |
| """) | |
| def demo_integration_summary(): | |
| """Show summary of all integrated capabilities.""" | |
| print_section("π― COMPLETE INTEGRATION SUMMARY") | |
| print("β Integrated Patterns from 11 Civic Tech Projects:\n") | |
| capabilities = [ | |
| ("Platform Detection", "Civic Scraper", "β discovery/platform_detector.py"), | |
| ("Event Schema", "City Scrapers", "β models/meeting_event.py"), | |
| ("Matter Tracking", "Engagic", "β models/meeting_event.py"), | |
| ("AI Summarization", "OpenTowns", "β extraction/summarizer.py"), | |
| ("Keyword Alerts", "OpenTowns", "β alerts/keyword_monitor.py"), | |
| ("Batch Processing", "LocalView", "β discovery/batch_processor.py"), | |
| ("Quality Metrics", "LocalView", "β discovery/batch_processor.py"), | |
| ("Summary Validation", "MeetingBank", "β extraction/summarizer.py"), | |
| ("Video Ingestion", "CDP", "π Roadmapped"), | |
| ("Cross-Jurisdiction Search", "CivicBand", "π Architecture designed"), | |
| ("Person/Vote Tracking", "Councilmatic", "π Planned"), | |
| ] | |
| for capability, source, status in capabilities: | |
| icon = "β " if "β " in status else "π" | |
| print(f"{icon} {capability:25s} ({source:15s}) β {status.replace('β ', '').replace('π', '').strip()}") | |
| print("\nπ Documentation:") | |
| print(" β’ docs/INTEGRATION_GUIDE.md - First 5 projects (Civic Scraper, City Scrapers, CDP, Engagic, Councilmatic)") | |
| print(" β’ docs/SCALE_AND_SEARCH_PATTERNS.md - Next 6 projects (OpenTowns, LocalView, etc.)") | |
| print("\n㪠Demo Scripts:") | |
| print(" β’ examples/integration_demo.py - Platform detection & event models") | |
| print(" β’ examples/full_demo.py (this file) - AI summarization, alerts, batch processing") | |
| print("\nπ Ready for Production:") | |
| print(" 1. β Jurisdiction discovery (85,302 records from Census)") | |
| print(" 2. β URL matching (76 .gov domains found)") | |
| print(" 3. β Platform detection (8 platforms supported)") | |
| print(" 4. β AI summarization (GPT-4o-mini)") | |
| print(" 5. β Keyword alerts (6 categories, 4 priority levels)") | |
| print(" 6. β Batch processing (100 at a time with quality tracking)") | |
| print(" 7. π Next: Implement actual scrapers (Legistar, Granicus, etc.)") | |
| def main(): | |
| """Run all demos.""" | |
| print("\n" + "π¦·" * 40) | |
| print(" ORAL HEALTH POLICY PULSE") | |
| print(" Full Integration Demo: AI + Alerts + Scale") | |
| print("π¦·" * 40) | |
| # Run demos | |
| demo_ai_summarization() | |
| demo_keyword_alerts() | |
| demo_batch_processing() | |
| demo_integration_summary() | |
| print("\n" + "=" * 80) | |
| print(" β Demo Complete!") | |
| print("=" * 80) | |
| print("\nπ‘ Try it yourself:") | |
| print(" python examples/full_demo.py") | |
| print("\n Or explore individual capabilities:") | |
| print(" β’ python extraction/summarizer.py") | |
| print(" β’ python alerts/keyword_monitor.py") | |
| print(" β’ python discovery/batch_processor.py") | |
| if __name__ == "__main__": | |
| main() | |