# Project export: The Rizzistant

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: the rizzistant helps, the rizzistant prevents, the rizzistant rizzes
- Devpost: https://devpost.com/software/the-rizzistant
- GitHub: https://github.com/MasakiAllwardt/the_rizzistant#
- Video: https://www.youtube.com/embed/cFzRkaiSElI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Alex Sun (25 commits), MasakiAllwardt (6 commits)

## Devpost submission (written by the team)

### Inspiration

Back in high school, Masaki had a stalker that wouldn’t leave him alone. Ever since then, a fear of women and dates has prevented him from finding a partner. To save him from such a lonely life, we created the rizzistant. It helps him through dates even if he’s extremely nervous and dumb. AND, we added a safe word so that if meets any more weirdly violent girls, it can create an excuse to make escape.

### What it does

The Rizzistant is your live AI dating coach that listens in on your date through Omi's live transcription and delivers real-time feedback straight to your phone. It monitors the flow of conversation, detecting pacing, engagement, and overall interaction quality to help you adjust naturally in the moment. When it detects filler phrases like "yeah okay so…" or awkward pauses, The Rizzistant instantly sends you a conversation prompt tailored to the topic at hand, helping you recover smoothly and keep the dialogue engaging. If things take a turn for the worse, The Rizzistant's escape feature has you covered. By subtly working a pre-set code word into a sentence (editable via the "edit code word" command), it will trigger a fake phone call, giving you a seamless exit from the date. Afterward, The Rizzistant generates a comprehensive post-date report by scoring you across metrics like emotional awareness, conversational flow, engagement, humor, and chemistry. It also tracks your progress across multiple dates, analyzing where you've improved and where you still need work, helping you become smoother and more self-aware with every interaction.

### How we built it

The Rizzistant is built on a FastAPI backend that processes live audio transcripts from the Omi wearable device. Real-time Analysis Pipeline: Omi captures conversation audio and streams transcription segments to our /livetranscript endpoint Each segment is accumulated and analyzed by Claude 3.5 Haiku for real-time feedback A smart deduplication system prevents spam by tracking previous warnings and context Multi-Model AI Architecture: Claude Haiku handles real-time feedback with low latency (max 1024 tokens) Letta creates persistent agents for each user, powered by Claude 3.5 Sonnet, enabling cross-date context and progress tracking Each Letta agent maintains conversation history and can reference previous dates when generating new summaries Voice Command Processing: Pattern detection identifies filler phrases like "yeah okay so..." to trigger contextual conversation tips Voice commands like "edit code word [word]" or "start date" are parsed server-side via regex Code word detection triggers the emergency exit sequence Emergency Exit System: Twilio API generates authentic phone calls using TwiML responses When the code word is detected in conversation, The Rizzistant immediately calls your phone, providing you with an excuse to exit the interaction Configurable phone numbers via voice commands for seamless personalization Data Persistence: In-memory session management for active dates Letta's memory blocks maintain user goals, patterns, and coaching context across sessions Omi's memory API archives date summaries with structured tags for external access

### Challenges we ran into

The core challenge of The Rizzistant was building a context system that could provide intelligent, non-repetitive feedback both in real-time and across multiple dates. This required two distinct approaches to context engineering. For real-time analysis, we needed Claude to understand not just the current conversation, but also what warnings had already been sent to avoid notification spam. Early versions would repeatedly alert about the same problematic topic. To solve this, we pass both the full conversation transcript and the history of previous notifications with timestamps to Claude on every analysis call. For post-date analysis, the challenge was even more complex: we needed the AI to remember and reference all previous dates to track improvement. This is where Letta became essential. Letta creates persistent agents with memory blocks that store user goals, patterns, and coaching context across sessions. When generating a post-date summary, the Letta agent can use its conversation_search tool to query previous date transcripts and summaries. The result is a two-tier context system: Claude with explicit conversation + notification history for real-time advice, and Letta with persistent memory agents for cross-date analysis.

### Accomplishments we're proud of

We're proud of building a genuinely helpful AI system that actually improves people's social awareness in real-time. By orchestrating multiple cutting-edge services, we created something that goes beyond surface-level "rizz tips" to provide personalized, longitudinal coaching. The system delivers actionable feedback fast enough to matter during live conversation, remembers your patterns across multiple dates to track improvement over time, and does it all with personality that makes the experience both effective and entertaining.

### What we learned

We learned how to work with a bunch of cool AI technologies like Letta for persistent memory management and Claude for intelligent language processing, as well as backend technologies like FastAPI for building real-time APIs. Integrating Twilio for telephony and Omi for live transcription also gave us hands-on experience with multiple external services and how to orchestrate them into a cohesive system.

### What's next

Better speaker detection to accurately differentiate between you and your date, ensuring feedback is based on the correct attribution of who said what. Beyond that, we want to implement multimodal real-time analysis that goes beyond just transcription to analyze tone, pacing, nervousness, speech cadence, or conversation dynamics to provide even more nuanced coaching.

## README (from the GitHub repository)

# The Rizzistant

A real-time date coaching assistant that monitors conversations and provides intelligent feedback using Claude AI.

## Features

- Real-time conversation monitoring via live transcripts
- AI-powered analysis to detect conversation issues
- Smart warnings to help improve dating conversations
- Date session management (start/end)
- Post-date summaries with actionable tips
- Integration with OMI for memory storage

## Prerequisites

- Docker installed on your system
- Environment variables configured (see below)

## Environment Variables

Create a `.env` file in the project root with your actual credentials. You can use `.env.example` as a template.

## Quick Start

### Using Docker (Recommended)

1. **Start Server**
   ```bash
   make dev
   ```
   The app will be running at `http://localhost:8000`

2. **Expose with ngrok (if running locally)**
   ```bash
   ngrok http 8000
   ```

## API Endpoints

### `POST /livetranscript`

Receives live transcript segments and provides real-time coaching.

### `GET /` (root)

Health check endpoint.

## Docker Commands

| Command | Description |
|---------|-------------|
| `make build` | Build the Docker image |
| `make start` | Start the container (auto-stops existing) |
| `make stop` | Stop the running container |
| `make logs` | View container logs (follows output) |
| `make clean` | Remove container and image |

## How It Works

1. **Session Management**: Users can start/end date sessions with voice commands
2. **Real-time Analysis**: Each transcript batch is analyzed by Claude AI for conversation issues
3. **Smart Warnings**: The system detects problematic topics (especially CS-related) and provides coaching
4. **Warning Deduplication**: Prevents sending duplicate warnings for the same issue
5. **Post-Date Summary**: Generates a comprehensive summary with tips after each date, WITH ACCESS TO PREVIOUS POST-DATE SUMMARIES AS WELL THANKS TO LETTA


## Detected evidence (automated analysis)

Indexed codebase: 10 recognized source files, 36 KB.
- Anthropic (technology) — detected in the code
- FastAPI (technology) — detected in the code
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (15 of 15)

```
.env.example
.gitignore
app/__init__.py
app/config.py
app/database.py
app/main.py
app/models.py
app/prompts.py
app/services.py
Dockerfile
main.py
Makefile
README.md
requirements.txt
test/test_twilio.py
```

### Dependencies

- requirements.txt: anthropic, fastapi, letta-client, python-dotenv, requests, twilio, uvicorn[standard]

### Recent commits (newest first)

- edit phone number command
- Merge pull request #3 from MasakiAllwardt/letta
- clean documentation
- works
- letta for memory only
- letta
- comment transcript processed
- Merge branch 'main' of github.com:MasakiAllwardt/the_rizzistant
- refactor
- Fixed previous_summary is not defined error
- Resolved merge conflicts
- Added db file to .ignore
- Added SQL database to store latest date summary. Added improvements from previous date to the end of date summary. Tweaked prompt for end of date summary to be more formatted.
- changed to hardcode gender
- Merge branch 'main' of https://github.com/MasakiAllwardt/the_rizzistant
- lolz
- Merge pull request #2 from MasakiAllwardt/codeword
- env readme
- twilio works
- readme

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
fastapi
uvicorn[standard]
requests
anthropic
python-dotenv
twilio
letta-client

```

### Dockerfile

```
# Dockerfile for The Rizzistant
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Install system dependencies (if needed)
RUN apt-get update && apt-get install -y --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

# Copy requirements first for better caching
COPY requirements.txt .

# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY app/ ./app/
COPY main.py .
COPY .env* ./

# Expose port
EXPOSE 8000

# Set environment variables
ENV PORT=8000
ENV HOST=0.0.0.0

# Run the application
CMD ["python", "main.py"]

```

### main.py

```python
"""Entry point for running the FastAPI application"""
import uvicorn
from app.main import app

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

```

### app/main.py

```python
"""FastAPI application and route handlers"""
import re
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.database import init_database
from app.models import get_or_create_user, DateObject
from app.services import claude_service, twilio_service, omi_service, letta_service


# Initialize database on startup
init_database()

# Create FastAPI app
app = FastAPI(title="The Rizzistant", description="Real-time Dating Coach")

# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get('/')
def root():
    """Health check endpoint"""
    return {"message": "Rizz Meter API - Live Conversation Coaching"}


@app.post("/webhook")
def webhook(memory: dict, uid: str):
    """Webhook endpoint for receiving memories"""
    print(memory)
    print(uid)
    return {"message": "we got it"}


@app.post("/livetranscript")
def livetranscript(transcript: dict, uid: str):
    """
    Process live transcript segments from the user.
    Handles commands (start date, end date, code word) and analyzes conversation.
    """
    # Get or create user
    user = get_or_create_user(uid)

    print(f"Received {len(transcript['segments'])} segments in this request")

    # First pass: check for start/end date commands and code word
    for segment in transcript["segments"]:
        text = segment["text"]
        text_lower = text.lower()

        # Check for "omi edit code word" command
        if "edit code word" in text_lower:
            parts = text_lower.split("edit code word")
            if len(parts) > 1 and parts[1].strip():
                remaining_text = parts[1].strip()
                words = remaining_text.split()
                if len(words) > 0:
                    new_code_word = words[0]
                    user.code_word = new_code_word
                    print(f"Updated code word for user {uid} to: {new_code_word}")
                    return {
                        "message": f"Code word has been updated to: {new_code_word}",
                        "should_notify": True,
                        "event_type": "code_word_updated"
                    }

        # Check for "edit phone number" command
        if "edit phone number" in text_lower:
            parts = text_lower.split("edit phone number")
            if len(parts) > 1 and parts[1].strip():
                remaining_text = parts[1].strip()
                # Extract digits only from the remaining text
                digits = re.sub(r'\D', '', remaining_text)
                # Check if we have exactly 10 digits
                if len(digits) >= 10:
                    phone_number = digits[:10]  # Take first 10 digits
                    user.phone_number = phone_number
                    print(f"Updated phone number for user {uid} to: {phone_number}")
                    return {
                        "message": f"Phone number has been updated to: {phone_number}",
                        "event_type": "phone_number_updated"
                    }
            print(f"Unable to update phone number for user {uid}. We heard: {remaining_text}")
            return {
                "message": f"Unable to update phone number. We received: {remaining_text}",
                "event_type": "phone_number_not_updated"
            }

        # Check if code word is said (emergency exit)
        if user.code_word.lower() in text_lower:
            print(f"Code word '{user.code_word}' detected for user {uid}")

            # Make the emergency phone call using user's saved phone number
            twilio_service.make_emergency_call(user.phone_number)

            # End the date if active
            if user.current_date_id and user.current_date_id in user.dates:
                current_date = user.dates[user.current_date_id]
                current_date.finalize()

                # Generate summary with tips using Letta
                if current_date.accumulated_transcript.strip():
                    # Use Letta agent to generate summary with full historical context
                    # Letta automatically has access to all previous dates via its memory
                    summary = letta_service.process_date_end(
                        uid,
                        current_date.accumulated_transcript
                    )
                    print(f"Generated date summary for user {uid} via Letta")

                    # Send to OMI for external memory storage
                    omi_service.create_memory(uid, summary)

                user.current_date_id = None

            return {
                "message": "Date ended! Your date summary has been saved.",
                "should_notify": True,
                "event_type": "date_ended"
            }

        # Check if "start date" is said
        if "start date" in text_lower:
            print(f"Starting new date for user {uid}")
            user.date_counter += 1
            date_id = f"date_{user.date_counter}"
            user.dates[date_id] = DateObject(date_id)
            user.current_date_id = date_id

            return {
                "message": "Date started! Good luck and have fun!",
                "should_notify": True,
                "event_type": "date_started"
            }

        # Check if "end date" is said
        if "end date" in text_lower:
            print(f"Ending date for user {uid}")
            if user.current_date_id and user.current_date_id in user.dates:
                current_date = user.dates[user.current_date_id]
                current_date.finalize()

                # Generate summary with tips using Letta
                if current_date.accumulated_transcript.strip():
                    # Use Letta agent to generate summary with full historical context
                    # Letta automatically has access to all previous dates via its memory
                    summary = letta_service.proce
[truncated — 2901 more characters]
```

### app/__init__.py

```python
"""The Rizzistant - Real-time Dating Coach"""

```

### app/database.py

```python
"""Database operations for date summaries"""
import sqlite3
from datetime import datetime
from typing import Optional
from app.config import DB_PATH


def init_database():
    """Initialize the SQLite database and create the table if it doesn't exist"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS date_summaries (
            uid TEXT PRIMARY KEY,
            summary TEXT NOT NULL,
            created_at TIMESTAMP NOT NULL
        )
    """)
    conn.commit()
    conn.close()


def get_previous_summary(uid: str) -> Optional[str]:
    """Retrieve the previous date summary for a user"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("SELECT summary FROM date_summaries WHERE uid = ?", (uid,))
    result = cursor.fetchone()
    conn.close()
    return result[0] if result else None


def save_summary(uid: str, summary: str):
    """Save or replace the date summary for a user"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        INSERT OR REPLACE INTO date_summaries (uid, summary, created_at)
        VALUES (?, ?, ?)
    """, (uid, summary, datetime.now()))
    conn.commit()
    conn.close()

```

### app/config.py

```python
"""Configuration and environment variables"""
import os
from dotenv import load_dotenv
from anthropic import Anthropic
from twilio.rest import Client
from letta_client import Letta

# Load environment variables from .env file
load_dotenv()

# Database configuration
DB_PATH = "date_summaries.db"

# API clients
def get_claude_client():
    """Get initialized Claude API client"""
    return Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))

def get_twilio_client():
    """Get initialized Twilio client"""
    return Client(
        os.environ.get("TWILIO_ACCOUNT_SID"),
        os.environ.get("TWILIO_AUTH_TOKEN")
    )

def get_letta_client():
    """Get initialized Letta API client"""
    return Letta(token=os.environ.get("LETTA_API_KEY"))

# Environment variables
def get_env_var(key: str, default=None):
    """Get environment variable with optional default"""
    return os.environ.get(key, default)

# OMI API configuration
OMI_APP_ID = os.environ.get("OMI_APP_ID")
OMI_API_KEY = os.environ.get("OMI_API_KEY")
OMI_BASE_URL = "https://api.omi.me/v2"

# Twilio configuration
PHONE_NUMBER = os.environ.get("PHONE_NUMBER")
TWILIO_PHONE_NUMBER = os.environ.get("TWILIO_PHONE_NUMBER")

# Letta API configuration
LETTA_API_KEY = os.environ.get("LETTA_API_KEY")

```

### app/models.py

```python
"""Data models for users and dates"""
from datetime import datetime
from typing import Dict, List, Optional


class DateObject:
    """Represents a single date session"""

    def __init__(self, date_id: str):
        self.date_id = date_id
        self.start_time = datetime.now()
        self.accumulated_transcript = ""
        self.is_active = True
        self.count = 0
        self.end_time = None
        self.previous_warnings: List[Dict] = []  # Store previous warnings to avoid repetition

    def add_transcript(self, text: str):
        """Add text to accumulated transcript"""
        if self.is_active:
            self.accumulated_transcript += " " + text

    def add_warning(self, warning_message: str, reason: str):
        """Add a warning to the history"""
        self.previous_warnings.append({
            "message": warning_message,
            "reason": reason,
            "timestamp": datetime.now().isoformat()
        })

    def finalize(self):
        """Mark this date as ended"""
        self.is_active = False
        self.end_time = datetime.now()


class User:
    """Represents a user with their date history"""

    def __init__(self, uid: str):
        self.uid = uid
        self.dates: Dict[str, DateObject] = {}  # Dictionary of date_id -> DateObject
        self.current_date_id: Optional[str] = None
        self.date_counter = 0
        self.code_word = "peanuts"  # Default code word
        self.phone_number: Optional[str] = None  # User's phone number


# In-memory storage for user objects
users: Dict[str, User] = {}


def get_or_create_user(uid: str) -> User:
    """Get existing user or create new one"""
    if uid not in users:
        users[uid] = User(uid)
    return users[uid]

```

### test/test_twilio.py

```python
#!/usr/bin/env python3
"""
Test script to verify Twilio API integration
Run this to make sure your Twilio credentials are set up correctly
"""

from twilio.rest import Client
from dotenv import load_dotenv
import os

def test_twilio_call():
    """Test making a phone call with Twilio"""
    
    # Load environment variables
    load_dotenv()
    
    # Get credentials from environment
    account_sid = os.environ.get("TWILIO_ACCOUNT_SID")
    auth_token = os.environ.get("TWILIO_AUTH_TOKEN")
    twilio_phone_number = os.environ.get("TWILIO_PHONE_NUMBER")
    phone_number = os.environ.get("PHONE_NUMBER")
    
    # Check if all required environment variables are set
    print("🔍 Checking environment variables...")
    print(f"  TWILIO_ACCOUNT_SID: {'✓ Set' if account_sid else '✗ Not set'}")
    print(f"  TWILIO_AUTH_TOKEN: {'✓ Set' if auth_token else '✗ Not set'}")
    print(f"  TWILIO_PHONE_NUMBER: {twilio_phone_number if twilio_phone_number else '✗ Not set'}")
    print(f"  PHONE_NUMBER: {phone_number if phone_number else '✗ Not set'}")
    print()
    
    if not all([account_sid, auth_token, twilio_phone_number, phone_number]):
        print("❌ Error: Missing required environment variables in .env file")
        print("\nPlease add the following to your .env file:")
        print("  TWILIO_ACCOUNT_SID=your_account_sid")
        print("  TWILIO_AUTH_TOKEN=your_auth_token")
        print("  TWILIO_PHONE_NUMBER=+1234567890")
        print("  PHONE_NUMBER=+1234567890")
        return False
    
    try:
        # Initialize Twilio client
        print("📞 Initializing Twilio client...")
        client = Client(account_sid, auth_token)
        print("  ✓ Client initialized successfully\n")
        
        # Make a test call
        print(f"📱 Making test call from {twilio_phone_number} to {phone_number}...")
        print("  (This may take a few seconds...)\n")
        
        call = client.calls.create(
            to=phone_number,
            from_=twilio_phone_number,
            twiml='<Response><Say>This is a test call from your Rizzistant app. Your Twilio integration is working perfectly!</Say></Response>'
        )
        
        print(f"✅ SUCCESS! Phone call initiated successfully!")
        print(f"\nCall Details:")
        print(f"  Call SID: {call.sid}")
        print(f"  Status: {call.status}")
        print(f"  From: {twilio_phone_number}")
        print(f"  To: {phone_number}")
        print(f"\n🎉 Your phone should be ringing now!")
        print(f"\nYou can check the call status at:")
        print(f"  https://console.twilio.com/us1/monitor/logs/calls/{call.sid}")
        
        return True
        
    except Exception as e:
        print(f"❌ ERROR: Failed to make phone call")
        print(f"\nError details: {str(e)}")
        print("\nCommon issues:")
        print("  1. Invalid Twilio credentials (check Account SID and Auth Token)")
        print("  2. Invalid phone numbers (must be in E.164 format, e.g., +1234567890)")
        print("  3. Trial account limitations (can only call verified numbers)")
        print("  4. Insufficient Twilio account balance")
        print("\nCheck your Twilio console at: https://console.twilio.com")
        return False

if __name__ == "__main__":
    print("=" * 60)
    print("  TWILIO API INTEGRATION TEST")
    print("=" * 60)
    print()
    
    success = test_twilio_call()
    
    print("\n" + "=" * 60)
    if success:
        print("  ✅ ALL TESTS PASSED - Twilio is ready to use!")
    else:
        print("  ❌ TEST FAILED - Please fix the issues above")
    print("=" * 60)


```

### app/prompts.py

```python
"""Claude API prompt templates"""
from typing import List, Dict, Optional


def build_date_analysis_prompt(
    current_text: str,
    accumulated_transcript: str,
    previous_warnings: List[Dict] = None
) -> str:
    """Build prompt for analyzing date conversation and determining if intervention is needed"""
    previous_warnings_text = ""
    if previous_warnings and len(previous_warnings) > 0:
        previous_warnings_text = "\n\nPrevious warnings already sent (DO NOT repeat similar warnings):\n"
        for warning in previous_warnings:
            previous_warnings_text += f"- {warning['reason']}: {warning['message']}\n"

    return f"""You are monitoring a date conversation. Analyze the following transcript and determine if the person is discussing something really wrong that needs urgent changing. Keep track of the flow of the conversation and only give suggestions based on what the male is saying.

SPECIAL RULE: If they are talking about computer science topics, this is considered a really wrong topic that urgently needs to be changed.

IMPORTANT: You have already sent the warnings listed below. DO NOT send similar or duplicate warnings. Only notify if there is a NEW issue that hasn't been warned about yet.{previous_warnings_text}

Current segment: {current_text}

Full accumulated date transcript so far:
{accumulated_transcript}

Respond ONLY with valid JSON, no other text. Use this exact format:
{{
    "should_notify": true,
    "reason": "brief reason if notification needed",
    "message": "the warning message to send to user if notification needed"
}}

CRITICAL: The warning message must be a SINGLE CASUAL SENTENCE that is funny and nonchalant. Be roasting and playful like a friend calling them out. Examples:
- "yo shut up about one piece bro"
- "bro really talking about python on a date rn"
- "dawg nobody wants to hear about binary search trees"
- "my guy you gotta chill with the anime talk"

Be strict about computer science topics - any mention of programming, algorithms, data structures, etc. should trigger a notification. However, do NOT send duplicate warnings for issues you've already warned about."""


def build_conversation_tip_prompt(accumulated_transcript: str) -> str:
    """Build prompt for generating a helpful conversation tip when user seems stuck"""
    return f"""You are a real-time dating coach. The person on a date just said something like "yeah okay so" which suggests they might be stuck or transitioning awkwardly in the conversation.

Based on the conversation so far, provide ONE short, actionable tip (very short sentences) to help them continue the conversation naturally and engagingly.

Make the tip specific to their current conversation context if possible. Focus on:
- Asking an interesting follow-up question
- Sharing a related personal story
- Making a playful observation
- Changing the topic smoothly
- For example, if the girl mentioned an interest earlier in the date say "ask her to expand more on figure skating"
Keep it casual and conversational, not robotic. Don't mention that they said "yeah okay so".

Date transcript so far:
{accumulated_transcript}

Respond with ONLY the tip, no extra formatting or preamble."""


def build_date_summary_prompt(
    accumulated_transcript: str,
    previous_summary: Optional[str] = None
) -> str:
    """Build prompt for summarizing the date and providing tips for improvement"""
    comparison_note = " Explicitly state how this date compares to the previous one (better/worse/similar and why)."
    improvements_section = "\n    - **Improvements from Last Date**: [List specific improvements observed]"
    persistent_issues_section = "\n    - **Persistent Issues**: [Note any problems that carried over from the previous date]"

    return f"""You are an elite dating coach and conversational analyst. Provide a comprehensive, structured report on this date conversation. This is a REPORT ONLY - do not ask any follow-up questions or include prompts for the user to respond.

    IMPORTANT: Compare this date to the most recent previous Date Performance Report, REGARDLESS of if you think its relevant or not (the previous message will ALWAYS be a relevant past date). Highlight specific improvements made, areas where the user applied previous advice, and new areas that need attention. Be concrete about what changed (better or worse) since the last date.

    Your analysis must follow this EXACT structure:

    # DATE PERFORMANCE REPORT

    ## OVERALL ASSESSMENT
    Provide a 2-3 sentence executive summary of the date's success. Include: chemistry level (strong/moderate/weak), conversational balance (balanced/one-sided), and overall vibe (engaged/surface-level/disconnected).{comparison_note}

    ## PERFORMANCE SCORES

    ### Overall Score: [X.X/10]

    ### Category Breakdown:
    - **Emotional Awareness (20%)**: [X/10] - [One sentence assessment]
    - **Conversational Flow (20%)**: [X/10] - [One sentence assessment]
    - **Authenticity & Presence (15%)**: [X/10] - [One sentence assessment]
    - **Curiosity & Engagement (15%)**: [X/10] - [One sentence assessment]
    - **Confidence (10%)**: [X/10] - [One sentence assessment]
    - **Listening & Responsiveness (10%)**: [X/10] - [One sentence assessment]
    - **Humor & Playfulness (5%)**: [X/10] - [One sentence assessment]
    - **Flirtation & Chemistry (5%)**: [X/10] - [One sentence assessment]

    ## KEY HIGHLIGHTS
    List 3-4 specific moments where you excelled. Include brief quotes from the transcript.
    - [Strength 1]: [Quote or paraphrase]
    - [Strength 2]: [Quote or paraphrase]
    - [Strength 3]: [Quote or paraphrase]{improvements_section}

    ## CRITICAL WEAKNESSES
    List 2-4 specific issues that hurt the connection. Be direct and specific.
    - [Weakness 1]: [Specific example]
    - [Weakness 2]: [Specific example]{persistent_issues_section}

    ## EMOTIONAL DYNAMICS
    Analyze the underlying emotional flow:
    - **Interest Level**: [Their apparent 
[truncated — 1081 more characters]
```

[1 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]