#!/usr/bin/env python3 """ Complete workflow example: Ingest emails and then analyze them with AI. This demonstrates the full pipeline from email ingestion to AI analysis. """ import os import sys from datetime import datetime, timedelta # Add the src directory to the path sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) from database import ( Message, SessionLocal, Thread, analyze_and_update_threads, create_db_tables, get_threads_needing_analysis, ingest_emails, ) def create_sample_emails(account_email: str) -> list: """Create some sample email data for testing.""" now = datetime.now() # Using datetime.now() instead of utcnow() sample_emails = [ { "messageId": "msg001", "subject": "Meeting Request - Project Review", "from": "colleague@company.com", "to": account_email, "date": now - timedelta(days=2), "body": "Hi, could we schedule a meeting to review the project progress? I'm available this week on Tuesday or Wednesday afternoon. Please let me know what works for you.", "folder": "INBOX", }, { "messageId": "msg002", "subject": "Re: Meeting Request - Project Review", "from": account_email, "to": "colleague@company.com", "date": now - timedelta(days=1, hours=8), "body": "Sure! Wednesday afternoon works for me. How about 2 PM in the conference room?", "folder": "Sent", "inReplyTo": "msg001", }, { "messageId": "msg003", "subject": "Re: Meeting Request - Project Review", "from": "colleague@company.com", "to": account_email, "date": now - timedelta(days=1, hours=6), "body": "Perfect! See you Wednesday at 2 PM. Should I prepare anything specific for the meeting?", "folder": "INBOX", "inReplyTo": "msg002", }, { "messageId": "msg004", "subject": "Weekly Newsletter - Company Updates", "from": "no-reply@company.com", "to": account_email, "date": now - timedelta(hours=12), "body": "Welcome to this week's company newsletter! Here are the latest updates: New office opening, Q3 results, upcoming events...", "folder": "INBOX", }, { "messageId": "msg005", "subject": "Urgent: Server Issue in Production", "from": "ops-team@company.com", "to": account_email, "date": now - timedelta(hours=2), "body": "We're experiencing a critical server issue in production. The application is currently down. Can you please help investigate? Login credentials are attached.", "folder": "INBOX", }, ] return sample_emails def main(): """Main function demonstrating the complete workflow.""" # Create database tables if they don't exist create_db_tables() # Example account email account_email = "test-user@company.com" print(f"Starting workflow for account: {account_email}") print("=" * 50) # Get a database session db = SessionLocal() try: # Step 1: Ingest sample emails print("Step 1: Ingesting sample emails...") sample_emails = create_sample_emails(account_email) ingest_emails(db, account_email, sample_emails) print(f"āœ“ Ingested {len(sample_emails)} emails") # Show what was ingested threads = ( db.query(Thread).filter(Thread.account_email == account_email.lower()).all() ) print(f"āœ“ Created {len(threads)} threads") for thread in threads: messages = db.query(Message).filter(Message.thread_id == thread.id).count() print(f" - Thread {thread.id}: '{thread.subject}' ({messages} messages)") print() # Step 2: Check threads needing analysis print("Step 2: Checking threads needing analysis...") threads_needing_analysis = get_threads_needing_analysis(db, account_email) print(f"āœ“ Found {len(threads_needing_analysis)} threads needing analysis") if not threads_needing_analysis: print("No threads need analysis.") return print() # Step 3: Run AI analysis print("Step 3: Running AI analysis...") print( "This will analyze threads to determine if they're actionable and generate summaries." ) analyze_and_update_threads( account_email=account_email, max_concurrent=3, only_unanalyzed=True ) print("āœ“ AI analysis complete!") print() # Step 4: Show results print("Step 4: Analysis Results") print("-" * 30) # Show results analyzed_threads = ( db.query(Thread) .filter( Thread.account_email == account_email.lower(), Thread.last_analyzed_at.isnot(None), ) .all() ) # Refresh the threads to get the latest data for thread in analyzed_threads: db.refresh(thread) actionable_count = sum(1 for t in analyzed_threads if t.actionable) print(f"Total analyzed threads: {len(analyzed_threads)}") print(f"Actionable threads: {actionable_count}") print(f"Non-actionable threads: {len(analyzed_threads) - actionable_count}") print() for thread in analyzed_threads: confidence = thread.ai_confidence or 0.0 print(f"Thread {thread.id}: {thread.subject}") print(f" šŸ“§ Actionable: {'YES' if thread.actionable else 'No'}") print(f" šŸŽÆ Confidence: {confidence:.2f}") print(f" šŸ“ Summary: {thread.ai_summary or 'No summary available'}") print(f" šŸ• Analyzed: {thread.last_analyzed_at}") print() # Step 5: Show threads requiring replies print("Step 5: Threads Requiring Reply") print("-" * 30) from database import get_threads_requiring_reply reply_threads = get_threads_requiring_reply(db, account_email) print(f"Threads requiring reply: {len(reply_threads)}") for thread in reply_threads: actionable_note = ( " (AI: Actionable)" if thread.actionable else " (AI: Not actionable)" ) print(f" - {thread.subject}{actionable_note}") if reply_threads: print( "\nšŸ’” Tip: Focus on threads marked as both 'requiring reply' and 'AI: Actionable'" ) except Exception as e: print(f"āŒ Error: {e}") import traceback traceback.print_exc() finally: db.close() if __name__ == "__main__": main()