# Project export: BeneAI

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: BeneAI is a social coach living on your Snapchat Spectacles. Read the room and decode social cues easily with real-time AI guidance. Built for those with social and communication disabilities.
- Devpost: https://devpost.com/software/beneai-go1txp
- GitHub: https://github.com/BazWiredIn/BeneAI
- Video: https://www.youtube.com/embed/paPjhzW7oC0?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 5 GitHub contributor(s) — Johnny Li (3 commits), BazilAhmad (3 commits), Claude (1 commits), Siddharth Chalasani (1 commits), BazWiredIn (1 commits)

## Devpost submission (written by the team)

### Inspiration

We were inspired to build this project as per our shared experiences as Low EQ CS majors.

### How we built it

We utilized LensStudio

### What's next

Our next goal is to expand the AR UI and to execute a Swift mobile companion app!

## README (from the GitHub repository)

BeneAI Social Coach

## Detected evidence (automated analysis)

Indexed codebase: 59 recognized source files, 491 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- TypeScript (language) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository; commit authorship or trailers

## Codebase structure (from repository index)

### Files (76 of 76)

```
.claude/claude.md
.gitignore
backend/.gitignore
backend/app/__init__.py
backend/app/cache.py
backend/app/config.py
backend/app/google_speech_client.py
backend/app/hume_client.py
backend/app/interval_aggregator.py
backend/app/llm_context_builder.py
backend/app/llm.py
backend/app/prompts.py
backend/app/session_logger.py
backend/app/speech_mapper.py
backend/app/timeseries_buffer.py
backend/check_api_key.py
backend/Dockerfile
backend/extract_last_session.py
backend/main.py
backend/requirements.txt
backend/session_2025-10-23_23-28-37.json
backend/session_2025-10-23_23-29-18.json
backend/session_2025-10-23_23-29-28.json
backend/session_2025-10-23_23-42-05.json
backend/session_2025-10-23_23-42-46.json
backend/session_2025-10-23_23-43-27.json
backend/session_data.json
backend/test_debug_face.py
backend/test_hume.py
backend/test_speech_metrics.py
backend/test_websocket.py
backend/test_with_photo.py
backend/visualize_emotions.py
backend/visualize_session.sh
CACHE_BUG_FIXED.md
CRITICAL_BUG_FIXED.md
DATA_FLOW.md
DEEPGRAM_INTEGRATION_COMPLETE.md
EMOTION_TIMESERIES.md
FIX_OPENAI_KEY.md
FIXED_ISSUES.md
frontend/css/styles.css
frontend/index.html
frontend/js/app.js
frontend/js/audio-analyzer.js
frontend/js/audio-capture.js
frontend/js/config.js
frontend/js/emotion-detector.js
frontend/js/video-processor.js
frontend/js/video-worker.js
frontend/js/websocket-client.js
frontend/overlay.html
frontend/run_https.sh
frontend/server.py
GOOGLE_CLOUD_SPEECH_SETUP.md
IMPLEMENTATION_COMPLETE.md
QUICK_REFERENCE.md
QUICK_START.md
QUICK_TEST_GUIDE.md
README.md
SPEECH_RECOGNITION_FIXED.md
start_demo.sh
TEST_NOW.md
testing/ground_truth_template.json
testing/performance_test.ipynb
testing/QUICKSTART.md
testing/README.md
testing/requirements.txt
testing/results/.gitignore
testing/results/README.md
testing/SUMMARY.md
testing/test_utils.py
testing/videos/.gitkeep
testing/videos/test_video_annotations.json
USAGE_GUIDE.md
WHERE_IS_DATA.md
```

### Dependencies

- backend/requirements.txt: black@==23.12.0, fastapi@==0.104.1, flake8@==6.1.0, google-cloud-speech@==2.27.0, httpx@==0.25.2, hume@==0.12.1, matplotlib@==3.8.2, mypy@==1.7.1, openai@==1.3.5, passlib[bcrypt]@==1.7.4, pydantic@>=2.10.0,<3.0.0, pydantic-settings@>=2.6.0, pytest@==7.4.3, pytest-asyncio@==0.21.1, python-dotenv@==1.0.0, python-jose[cryptography]@==3.3.0, python-multipart@==0.0.6, tenacity@==8.2.3, uvicorn[standard]@==0.24.0, websockets@>=13.1,<14.0
- testing/requirements.txt: asyncio@>=3.4.3, ipywidgets@>=8.0.0, jsonschema@>=4.19.0, jupyter@>=1.0.0, matplotlib@>=3.7.0, nest-asyncio@>=1.5.8, notebook@>=7.0.0, numpy@>=1.24.0, opencv-contrib-python@>=4.8.0, opencv-python@>=4.8.0, pandas@>=2.0.0, Pillow@>=10.0.0, plotly@>=5.17.0, scikit-learn@>=1.3.0, seaborn@>=0.12.0, tqdm@>=4.65.0, typing-extensions@>=4.7.0, websockets@>=12.0

### Recent commits (newest first)

- Update README.md
- Merge pull request #4 from BazWiredIn/johnnyl
- annotions for test video
- Merge pull request #3 from BazWiredIn/Yaseen-Johnny-Demo
- feat: transform BeneAI from negotiation to social interaction coach
- Merge pull request #2 from BazWiredIn/testing
- Addded testing files
- Merge pull request #1 from BazWiredIn/take-out-video-stream
- perf: optimize video streaming latency with Web Worker parallelization
- security: remove Google credentials from git
- Working product?
- feat: integrate Hume AI for emotion detection
- first commit
- first commit

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

### FIX_OPENAI_KEY.md

```markdown
# OpenAI API Key Issue - FIX REQUIRED

## Problem

Backend logs show:
```
HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 401 Unauthorized"
```

**This means your OpenAI API key is either expired, invalid, or missing.**

---

## Current Status

✅ **OpenAI key exists** in `backend/.env`
❌ **Key is getting 401 Unauthorized** from OpenAI API
⚠️ **System is using fallback advice** instead of GPT-4

---

## How to Fix

### 1. Get a Valid OpenAI API Key

Go to: https://platform.openai.com/api-keys

- Sign in to your OpenAI account
- Click "Create new secret key"
- Copy the key (starts with `sk-proj-...` or `sk-...`)

### 2. Update `.env` File

Edit `backend/.env`:

```bash
# Replace the existing key with your new key
OPENAI_API_KEY=sk-YOUR-NEW-KEY-HERE
```

### 3. Restart Backend

```bash
# Stop current backend (Ctrl+C)

# Restart
cd backend
python main.py
```

---

## How to Verify It's Working

After restart, backend logs should show:

**Before fix (BROKEN):**
```
INFO: HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 401 Unauthorized" ❌
INFO: Coaching advice sent: Close strong. Discuss next steps. (fallback advice)
```

**After fix (WORKING):**
```
INFO: HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK" ✅
INFO: Coaching advice sent: Great engagement! They're showing strong interest... (actual GPT-4 response)
```

**In browser console:**
```
📊 [time] Coaching advice: {"advice":"Great engagement!..."} ✅
```

---

## Temporary Workaround

The system works without a valid OpenAI key but will only provide generic fallback advice:
- "Close strong. Discuss next steps." (for positive states)
- "Slow down. Emphasize key wins clearly." (for evaluative states)
- etc.

To get real GPT-4 coaching, you **must** fix the API key.

---

## Cost Warning

OpenAI API usage is **not free**. GPT-4 Turbo costs approximately:
- **$0.01 per 1,000 input tokens** (~750 words)
- **$0.03 per 1,000 output tokens**

Each 5-second coaching update sends ~200-300 tokens and receives ~30 tokens.

**Estimated cost:**
- 1-minute session: ~$0.005 (half a cent)
- 10-minute session: ~$0.05 (5 cents)
- 1-hour session: ~$0.30 (30 cents)

Make sure you have credits on your OpenAI account!

---

## Test After Fixing

1. **Restart backend** with new key
2. **Open frontend**: http://localhost:8080
3. **Click "Start Session"**
4. **Wait for 5-10 seconds** (until first LLM update)
5. **Check browser console** for:
   ```
   📊 Coaching advice: {...}
   ```
6. **Check backend logs** for:
   ```
   HTTP/1.1 200 OK ✅
   ```

If you see 200 OK, it's working! 🎉

---

**Fix this before testing the visualization system!**

```

### QUICK_TEST_GUIDE.md

```markdown
# Quick Test Guide - After Implementation

## 🔴 CRITICAL: Fix OpenAI Key First!

```bash
# 1. Get key from: https://platform.openai.com/api-keys
# 2. Edit backend/.env:
vim backend/.env
# Change: OPENAI_API_KEY=sk-YOUR-NEW-KEY-HERE

# 3. Restart backend
lsof -ti:8000 | xargs kill
cd backend
python main.py
```

---

## ✅ Quick Test (3 minutes)

### 1. Open Frontend
```
http://localhost:8080
```

### 2. Open Browser Console (F12)

### 3. Click "Start Session"

### 4. Wait 10-20 seconds
Look for these logs in console:

```
📊 Frame sent: {"count":1}           ← Frames being captured
📊 Emotion received: {...}            ← Hume AI working
📊 Interval complete: {...}           ← Aggregation working
📊 Coaching advice: {...}             ← LLM working! ✅
```

**If you see "Coaching advice" → SUCCESS!** 🎉

### 5. Stop Session

### 6. Visualize Data
```bash
cd backend
./visualize_session.sh
```

---

## 🎯 What to Check

### Backend Terminal:
```
✅ HTTP/1.1 200 OK  (good - OpenAI working)
❌ HTTP/1.1 401 Unauthorized (bad - fix key!)
```

### Browser Console:
```
✅ "Coaching advice" messages (GPT-4 responses)
❌ Only emotions/intervals (LLM not triggering)
```

### Visualization:
```
✅ Purple dashed lines on emotion plot (LLM updates)
✅ LLM Updates timeline plot appears
✅ Coaching advice printed in terminal
```

---

## 📊 Expected Output

### Successful Test Session:
- **10-20 frames** sent
- **3-6 emotions** detected
- **3-6 intervals** completed
- **1-2 LLM updates** generated ✅

### Data File:
```bash
ls -lh backend/session_data.json
# Should be 2-10 KB
```

### Plots Generated:
1. Emotion timeseries (with LLM markers)
2. Investor state timeline
3. LLM updates timeline
4. Emotion trends (if --trends)

---

## 🐛 Common Issues

### Issue: "401 Unauthorized"
**Fix**: Update OpenAI key in `.env` and restart

### Issue: No coaching advice in console
**Check**:
- Did you wait 5+ seconds? (LLM triggers after 5 intervals)
- Is OpenAI key valid? (check backend logs for 200 OK)

### Issue: "session_data.json not found"
**Fix**: Backend not started or session not run
```bash
cd backend
python main.py
# Then run session in browser
```

### Issue: Speech recognition errors
**Status**: Non-critical, emotion detection still works

---

## 🚀 All Commands in One Place

```bash
# Fix OpenAI key (do this first!)
vim backend/.env
# OPENAI_API_KEY=sk-YOUR-NEW-KEY-HERE

# Restart backend
lsof -ti:8000 | xargs kill
cd backend
python main.py

# Open frontend (in browser)
# http://localhost:8080

# After session, visualize
cd backend
./visualize_session.sh

# Or with all options:
python visualize_emotions.py session_data.json --trends --prompts --output ./plots/
```

---

## ✅ Success Criteria

You'll know it's working when you see:

1. ✅ Purple "LLM #1" markers on emotion plot
2. ✅ "Coaching advice" in browser console
3. ✅ "HTTP/1.1 200 OK" in backend logs
4. ✅ LLM prompts and responses printed

**If all 4 appear → FULLY WORKING!** 🎊

---

**Read `IMPLEMENTATION_COMPLETE.
[truncated — 24 more characters]
```

### backend/requirements.txt

```
# FastAPI and server
fastapi==0.104.1
uvicorn[standard]==0.24.0
websockets>=13.1,<14.0
python-multipart==0.0.6

# OpenAI
openai==1.3.5

# Hume AI
hume==0.12.1

# Google Cloud Speech-to-Text
google-cloud-speech==2.27.0

# Environment and configuration
python-dotenv==1.0.0
pydantic>=2.10.0,<3.0.0
pydantic-settings>=2.6.0

# CORS and security
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4

# Utilities
httpx==0.25.2
tenacity==8.2.3

# Visualization (for development/analysis)
matplotlib==3.8.2

# Testing
pytest==7.4.3
pytest-asyncio==0.21.1

# Development
black==23.12.0
flake8==6.1.0
mypy==1.7.1

```

### testing/requirements.txt

```
# BeneAI Performance Testing Requirements

# Jupyter and notebook support
jupyter>=1.0.0
notebook>=7.0.0
ipywidgets>=8.0.0

# Video processing
opencv-python>=4.8.0
opencv-contrib-python>=4.8.0

# Image processing
Pillow>=10.0.0

# WebSocket communication
websockets>=12.0

# Data analysis
numpy>=1.24.0
pandas>=2.0.0

# Machine learning metrics
scikit-learn>=1.3.0

# Visualization
matplotlib>=3.7.0
seaborn>=0.12.0
plotly>=5.17.0

# Progress bars
tqdm>=4.65.0

# Async support
asyncio>=3.4.3
nest-asyncio>=1.5.8  # For running async in Jupyter

# JSON handling
jsonschema>=4.19.0

# Type hints
typing-extensions>=4.7.0

```

### backend/Dockerfile

```
# Use official Python runtime as base image
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PORT=8080

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copy requirements file
COPY requirements.txt .

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

# Copy application code
COPY . .

# Create non-root user for security
RUN useradd -m -u 1000 beneai && \
    chown -R beneai:beneai /app
USER beneai

# Expose port
EXPOSE 8080

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD python -c "import requests; requests.get('http://localhost:8080/')"

# Run the application
CMD exec uvicorn main:app --host 0.0.0.0 --port ${PORT} --workers 1

```

### frontend/server.py

```python
#!/usr/bin/env python3
"""
HTTPS Server for BeneAI Frontend
Serves static files over HTTPS for Chrome extension development
"""

import http.server
import ssl
import sys
import os

def run_https_server(port=8443, certfile='cert.pem', keyfile='key.pem'):
    """
    Run an HTTPS server with SSL support

    Args:
        port: Port to listen on (default 8443)
        certfile: Path to SSL certificate file
        keyfile: Path to SSL private key file
    """

    # Check if certificate files exist
    if not os.path.exists(certfile):
        print(f"Error: Certificate file '{certfile}' not found")
        print("Run ./run_https.sh to generate certificates")
        sys.exit(1)

    if not os.path.exists(keyfile):
        print(f"Error: Key file '{keyfile}' not found")
        print("Run ./run_https.sh to generate certificates")
        sys.exit(1)

    # Create HTTP server
    server_address = ('localhost', port)
    httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)

    # Wrap with SSL
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain(certfile=certfile, keyfile=keyfile)
    httpd.socket = context.wrap_socket(httpd.socket, server_side=True)

    print(f"Serving HTTPS on https://localhost:{port}")
    print(f"Certificate: {certfile}")
    print(f"Key: {keyfile}")
    print("\nNote: Browser will show security warning - click 'Advanced' → 'Proceed to localhost'")
    print("\nPress Ctrl+C to stop the server\n")

    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n\nShutting down server...")
        httpd.shutdown()

if __name__ == '__main__':
    # Parse command line arguments
    port = 8443
    if len(sys.argv) > 1:
        try:
            port = int(sys.argv[1])
        except ValueError:
            print(f"Invalid port: {sys.argv[1]}")
            print("Usage: python3 server.py [port]")
            sys.exit(1)

    run_https_server(port=port)

```

### frontend/js/app.js

```javascript
/**
 * BeneAI Main Application
 */

class BeneAI {
    constructor() {
        this.videoProcessor = new VideoProcessor();
        this.audioCapture = new AudioCapture();  // NEW: Deepgram-based audio capture
        this.wsClient = new WebSocketClient();
        this.isRunning = false;
        this.updateInterval = null;

        // Store latest emotion data from Hume AI
        this.latestEmotion = {
            investorState: 'neutral',
            primaryEmotion: 'neutral',
            confidence: 0,
            allEmotions: {}
        };

        // Data collection tracking
        this.dataStats = {
            framesSent: 0,
            emotionsReceived: 0,
            intervalsReceived: 0,
            coachingAdviceReceived: 0,
            audioChunksSent: 0  // NEW: Track audio chunks
        };

        // UI Elements
        this.elements = {
            startBtn: document.getElementById('start-btn'),
            stopBtn: document.getElementById('stop-btn'),
            status: document.getElementById('status'),
            statusText: document.getElementById('status-text'),
            emotion: document.getElementById('emotion'),
            emotionConfidence: document.getElementById('emotion-confidence'),
            wpm: document.getElementById('wpm'),
            fillerCount: document.getElementById('filler-count'),
            pauseFreq: document.getElementById('pause-freq'),
            adviceContent: document.getElementById('advice-content'),
            webcam: document.getElementById('webcam'),
            outputCanvas: document.getElementById('output-canvas'),
            debugLog: document.getElementById('debug-log')
        };

        this.initializeUI();
    }

    /**
     * Initialize UI and event listeners
     */
    initializeUI() {
        this.elements.startBtn.addEventListener('click', () => this.start());
        this.elements.stopBtn.addEventListener('click', () => this.stop());

        // Set up WebSocket advice callback
        this.wsClient.onAdvice((advice, isComplete) => {
            this.elements.adviceContent.textContent = advice;
        });

        debug('UI initialized');
    }

    /**
     * Start the application
     */
    async start() {
        debug('Starting BeneAI...');

        try {
            // Update UI
            this.elements.startBtn.disabled = true;
            this.elements.statusText.textContent = 'Initializing...';

            // Initialize video processor
            await this.videoProcessor.initialize(
                this.elements.webcam,
                this.elements.outputCanvas
            );

            // Initialize audio capture (Deepgram)
            const audioReady = await this.audioCapture.initialize();
            if (!audioReady) {
                throw new Error('Failed to initialize audio capture');
            }

            // Connect to backend
            this.elements.statusText.textContent = 'Connecting to backend...';
            await this.wsClient.connect();

            // Start video processing
            this.elements.statusText.textContent = 'Starting video analysis...';
            await this.videoProcessor.start();

            // Set up frame capture callback
            this.videoProcessor.onFrameCapture((frameData) => {
                // Send frame to backend via WebSocket
                this.wsClient.sendVideoFrame(frameData);
                this.dataStats.framesSent++;
                this.logDataCollection('Frame sent', { count: this.dataStats.framesSent });
            });

            // Set up emotion result callback from backend
            this.wsClient.onEmotion((emotionResult) => {
                this.dataStats.emotionsReceived++;

                // Store latest emotion data
                if (emotionResult.detected) {
                    this.latestEmotion = {
                        investorState: emotionResult.investor_state || 'neutral',
                        primaryEmotion: emotionResult.emotion || 'neutral',
                        confidence: emotionResult.confidence || 0,
                        allEmotions: emotionResult.all_emotions || {}
                    };

                    this.logDataCollection('Emotion received', {
                        state: this.latestEmotion.investorState,
                        emotion: this.latestEmotion.primaryEmotion,
                        confidence: this.latestEmotion.confidence.toFixed(2),
                        count: this.dataStats.emotionsReceived
                    });
                }

                this.updateEmotionUI(emotionResult);

                // Optional: Draw overlay on canvas
                if (emotionResult.detected) {
                    this.videoProcessor.drawEmotionOverlay(emotionResult);
                }
            });

            // Set up interval completion callback
            this.wsClient.onInterval((intervalData) => {
                this.dataStats.intervalsReceived++;
                this.logDataCollection('Interval complete', {
                    state: intervalData.investor_state,
                    words: intervalData.words ? intervalData.words.length : 0,
                    count: this.dataStats.intervalsReceived
                });
            });

            // Set up coaching advice callback
            this.wsClient.onCoaching((coachingData) => {
                this.dataStats.coachingAdviceReceived++;
                this.logDataCollection('Coaching advice', {
                    advice: coachingData.coaching_advice,
                    state: coachingData.investor_state,
                    count: this.dataStats.coachingAdviceReceived
                });

                // Update UI with coaching advice
                if (this.elements.adviceContent) {
                    this.elements.adviceContent.textContent = coachingData.coaching_advice;
                }
            });

            // Start audio capture with callback
            this.elements.sta
[truncated — 6260 more characters]
```

### backend/main.py

```python
"""
BeneAI Backend - FastAPI Application
"""

import json
import os
import uuid
import time
import base64
import asyncio
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import logging

from app.config import settings
from app.llm import get_coaching_advice, get_negotiation_coaching
from app.cache import advice_cache
from app.hume_client import get_hume_client, close_hume_client
# Google Speech removed - using OpenAI Whisper for all transcription
from app.interval_aggregator import IntervalAggregator
from app.timeseries_buffer import TimeSeriesBuffer
from app.speech_mapper import SpeechMapper
from app.llm_context_builder import LLMContextBuilder
from app.prompts import INVESTOR_STATE_COLOR, INVESTOR_STATE_EMOJI
from app.session_logger import get_session_logger, close_session_logger


# Configure logging
logging.basicConfig(
    level=getattr(logging, settings.log_level.upper()),
    format='[%(asctime)s] %(levelname)s: %(message)s'
)
logger = logging.getLogger(__name__)

# Create FastAPI app
app = FastAPI(
    title="BeneAI API",
    description="AI-powered video call coaching backend",
    version="1.0.0"
)

# Configure CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.allowed_origins.split(","),
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Connection manager
class ConnectionManager:
    def __init__(self):
        self.active_connections: dict = {}

    async def connect(self, websocket: WebSocket, client_id: str):
        await websocket.accept()

        # Initialize time-series components for this client
        interval_aggregator = IntervalAggregator(alpha=0.3, interval_duration=1.0)
        timeseries_buffer = TimeSeriesBuffer(window_size=4, update_interval=4.0)  # LLM updates every 4 seconds (4 intervals)
        speech_mapper = SpeechMapper(silence_threshold=0.99)  # 0.99s pause threshold
        context_builder = LLMContextBuilder()

        self.active_connections[client_id] = {
            "websocket": websocket,
            "connected_at": time.time(),
            "last_message": time.time(),
            "last_frame_time": 0,  # For frame rate throttling
            # Time-series components
            "interval_aggregator": interval_aggregator,
            "timeseries_buffer": timeseries_buffer,
            "speech_mapper": speech_mapper,
            "context_builder": context_builder
        }
        logger.info(f"Client {client_id} connected. Total: {len(self.active_connections)}")

        # Create per-client session logger
        session_logger = get_session_logger(client_id, output_dir=".")
        session_logger.start_new_session()
        logger.info(f"Started new logging session for {client_id[:8]} -> {session_logger.output_file.name}")

    def disconnect(self, client_id: str):
        if client_id in self.active_connections:
            # Close and save session logger
            close_session_logger(client_id)
            del self.active_connections[client_id]
            logger.info(f"Client {client_id} disconnected. Total: {len(self.active_connections)}")

    async def send_message(self, client_id: str, message: dict):
        if client_id in self.active_connections:
            await self.active_connections[client_id]["websocket"].send_text(
                json.dumps(message)
            )

manager = ConnectionManager()


# Startup and shutdown events
@app.on_event("startup")
async def startup_event():
    """Initialize services on startup"""
    logger.info("=" * 80)
    logger.info("🚀 Starting BeneAI backend...")
    logger.info("=" * 80)

    # Log service configuration status
    logger.info("Service Configuration:")
    logger.info(f"  ✓ OpenAI API: {'Configured' if settings.openai_api_key else '✗ NOT CONFIGURED'}")
    logger.info(f"  ✓ Hume AI: {'Configured' if settings.hume_api_key else '✗ NOT CONFIGURED'}")
    logger.info(f"  ✓ Google Cloud Speech: {'Configured' if os.environ.get('GOOGLE_APPLICATION_CREDENTIALS') else '✗ NOT CONFIGURED'}")
    logger.info("")

    # Initialize Hume client if configured
    if settings.hume_api_key:
        hume = await get_hume_client()
        if hume and hume.connected:
            logger.info("✓ Hume AI client ready")
        else:
            logger.warning("✗ Hume AI client failed to connect")
    else:
        logger.info("ℹ Hume AI not configured (optional)")

    # Test OpenAI client initialization
    try:
        from app.llm import get_openai_client
        client = get_openai_client()
        logger.info("✓ OpenAI client initialized successfully")
    except Exception as e:
        logger.error(f"✗ OpenAI client initialization failed: {e}")

    logger.info("=" * 80)


@app.on_event("shutdown")
async def shutdown_event():
    """Cleanup on shutdown"""
    logger.info("Shutting down BeneAI backend...")
    await close_hume_client()
    logger.info("Cleanup complete")


# Health check endpoint
@app.get("/")
async def health_check():
    """Health check endpoint"""
    hume = await get_hume_client()
    return {
        "status": "healthy",
        "version": "1.0.0",
        "environment": settings.environment,
        "active_connections": len(manager.active_connections),
        "services": {
            "hume": bool(hume and hume.connected),
            "openai": bool(settings.openai_api_key)
        }
    }


# Cache stats endpoint
@app.get("/cache/stats")
async def cache_stats():
    """Get cache statistics"""
    return advice_cache.stats()


# WebSocket endpoint
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    """WebSocket endpoint for real-time communication"""

    client_id = str(uuid.uuid4())

    try:
        # Connect
        await manager.connect(websocket, client_id)

        # Send welcome message
        await manager.send_message(client_id, {
            "type": "connection",
            "stat
[truncated — 27321 more characters]
```

### start_demo.sh

```shell
#!/bin/bash

# BeneAI Demo Startup Script
# Starts both backend and frontend servers

echo "🚀 Starting BeneAI Demo..."
echo ""

# Check if backend dependencies are installed
if [ ! -d "backend/venv" ] && [ ! -f "backend/.env" ]; then
    echo "⚠️  First time setup detected"
    echo "📦 Installing backend dependencies..."
    cd backend
    pip install -r requirements.txt
    cd ..
fi

# Start backend in background
echo "🔧 Starting backend server on port 8000..."
cd backend
python main.py &
BACKEND_PID=$!
cd ..

# Wait for backend to start
sleep 3

# Check if backend is running
if curl -s http://localhost:8000/ > /dev/null; then
    echo "✅ Backend server running (PID: $BACKEND_PID)"
else
    echo "❌ Backend failed to start"
    exit 1
fi

# Start frontend server
echo "🌐 Starting frontend server on port 8080..."
cd frontend
python3 -m http.server 8080 &
FRONTEND_PID=$!
cd ..

# Wait for frontend to start
sleep 2

echo ""
echo "✅ BeneAI Demo Ready!"
echo ""
echo "📍 Frontend: http://localhost:8080"
echo "📍 Backend:  http://localhost:8000"
echo ""
echo "👉 Open http://localhost:8080 in your browser"
echo ""
echo "To stop the demo:"
echo "  kill $BACKEND_PID $FRONTEND_PID"
echo "  Or press Ctrl+C and run: killall python python3"
echo ""

# Keep script running
wait

```

### frontend/run_https.sh

```shell
#!/bin/bash
# Run frontend with HTTPS for testing

echo "Generating self-signed certificate..."
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
    -subj "/C=US/ST=State/L=City/O=BeneAI/CN=localhost"

echo ""
echo "Starting HTTPS server on https://localhost:8443"
echo "Note: Browser will show security warning - click 'Advanced' → 'Proceed to localhost'"
echo ""

python3 server.py 8443

```

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