# Project export: debAIDe

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: love debating and Chess.com? you'll love debAIDe too!
- Devpost: https://devpost.com/software/debaide
- GitHub: https://github.com/juliezyli/debAIDe
- Video: https://www.youtube.com/embed/nPDyinyXkOs?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Julie (2 commits)

## Devpost submission (written by the team)

### Inspiration

We referenced how people enjoy playing on Chess.com, and the competitive element to it was applicable to many fields. In addition, it is often common to see people pointlessly arguing on social media, without proper moderation, and often unwarranted. It is clear that people need an avenue to argue, but it would also be good to be able to concurrently improve their argumentation and logical reasoning skills. Thus, we believe that a debating app, similar to Chess.com app, would be able to bring people of opposing views together, to come to possible resolutions. We aimed to create a mobile app so it would be accessible and usable for the average person.

### What it does

Our debating app, debAIDe, pairs individuals of similar debating skill, and assigns each individual with a stand to defend. Individuals will then take turns proposing arguments and countering their opponent’s arguments, and an AI judge will determine a winner. The winner will have an increase in rating, and the loser will be given advice on how to improve their arguments.

### How we built it

For our frontend, we used React Native (Expo) using Expo AV to record audio, Zustand for global state management, React Query to fetch and cache data, and TypeScript for type-safe development. For our backend, we used FastAPI, PostgreSQL, SQLAlchemy, Google Gemini AI (for scoring), Whisper for speech-to-text transcription, and Uvicorn for our server.

### Challenges we ran into

The toughest challenge was actually coming up with a good idea. Our society is constantly filled with problems that we would love to solve, so we wanted to create something that would benefit society while also making sure to use AI meaningfully.

### Accomplishments we're proud of

Creating a mobile app was a challenge for us, as we were not very experienced in app development, and had to learn a lot in our creation process. We are proud that we created a fully-functional mobile app that looks and works well.

### What we learned

We learned how to send information to be processed by Gemini, and to curate our prompts to ensure proper output formats. We also learned how to create an app that stored data from different users, and that could coordinate between different users concurrently.

### What's next

We are considering more interesting formats, such as 2v2, clan battles or even “battle royale”. We are also considering moving into educational mode, where the user can directly pick apart arguments with fallacies.

## README (from the GitHub repository)

# 🎤 debAIDe

**AI-powered debate practice platform with real-time feedback and 1v1 battle mode**

debAIDe helps you master the art of debate through AI-powered coaching, instant feedback, and competitive battles with other debaters. Practice solo or challenge opponents in real-time debates.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python](https://img.shields.io/badge/Python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![React Native](https://img.shields.io/badge/React%20Native-Expo-blue.svg)](https://expo.dev/)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.100+-green.svg)](https://fastapi.tiangolo.com/)

## ✨ Features

### 🎯 Practice Mode
- **AI-Powered Topics** - Choose from curated topics or get daily AI-generated suggestions
- **Voice Recording** - Record your opening, rebuttal, and closing statements
- **Auto-Transcription** - Automatic speech-to-text conversion
- **Instant AI Feedback** - Get detailed scores on structure, logic, delivery, and time management
- **Personalized Coaching** - Receive strengths, improvement areas, and targeted practice drills
- **Key Moments** - AI identifies and highlights your best arguments with timestamps

### ⚔️ Battle Mode
- **1v1 Debates** - Challenge other users in real-time debates
- **Matchmaking** - Find opponents or join existing battle rooms
- **Turn-Based System** - Take turns presenting arguments in structured debate rounds
- **AI Judging** - Automated scoring and winner determination
- **Leaderboards** - Track your win rate, streaks, and climb the rankings
- **Battle History** - Review past debates and learn from your performances

### 🎨 User Experience
- **Dark/Light Mode** - Beautiful theme switching throughout the app
- **Cross-Platform** - iOS, Android, and Web support via Expo
- **Real-Time Updates** - Live battle status and instant feedback
- **User Stats** - Comprehensive statistics tracking your progress

## 🚀 Tech Stack

**Frontend**
- React Native (Expo) - Cross-platform mobile framework
- TypeScript - Type-safe development
- React Query - Server state management
- Zustand - Global state management
- Expo AV - Audio recording and playback

**Backend**
- FastAPI - High-performance Python API framework
- PostgreSQL - Relational database
- SQLAlchemy - Async ORM
- Google Gemini AI - Scoring, feedback, and judging
- Whisper - Speech-to-text transcription
- Uvicorn - ASGI server

## � Screenshots

*Practice Mode - Topic Selection*  
Choose from diverse debate topics or try the AI-generated topic of the day.

*Battle Mode - Live Debate*  
Compete against real opponents in structured, turn-based debates.

*Results - AI Feedback*  
Get detailed scoring and personalized improvement suggestions.

##  Project Structure

```
debaide/
├── backend/
│   ├── main.py                  # FastAPI application
│   ├── models.py                # Database models (Users, Topics, Sessions, Battles)
│   ├── database.py              # PostgreSQL configuration
│   ├── schemas.py               # Pydantic request/response schemas
│   ├── services/
│   │   ├── gemini_service.py    # AI scoring, feedback & judging
│   │   ├── storage_service.py   # Audio file management
│   │   ├── stt_service.py       # Speech-to-text transcription
│   │   └── auth_service.py      # JWT authentication
│   ├── requirements.txt
│   └── .env.example
│
└── frontend/
    ├── app/
    │   ├── _layout.tsx          # Root navigation
    │   ├── index.tsx            # Auth redirect
    │   ├── home.tsx             # Main dashboard
    │   ├── topics.tsx           # Topic selection
    │   ├── session.tsx          # Practice recording
    │   ├── results.tsx          # Practice feedback
    │   ├── auth/                # Login & registration
    │   └── battle/              # Battle mode screens
    │       ├── lobby.tsx        # Matchmaking
    │       ├── room.tsx         # Live battle
    │       └── results.tsx      # Battle outcome
    ├── components/
    │   ├── NavBar.tsx           # Navigation component
    │   └── ThemeToggle.tsx      # Dark mode toggle
    ├── lib/
    │   ├── api.ts               # API client
    │   ├── theme.tsx            # Theme configuration
    │   ├── authStore.ts         # Auth state
    │   └── store.ts             # Global state
    ├── package.json
    └── .env.example
```

## 🛠️ Setup Instructions

### Prerequisites
- **Python 3.11+**
- **Node.js 18+**
- **PostgreSQL 14+** (or use Neon DB, Supabase)
- **Gemini API Key** (get from [Google AI Studio](https://makersuite.google.com/))

### Quick Start (Recommended)

1. **Clone the repository:**
   ```bash
   git clone https://github.com/juliezyli/debaide.git
   cd debaide
   ```

2. **Set up backend:**
   ```bash
   cd backend
   python -m venv venv
   source venv/bin/activate  # Windows: venv\Scripts\activate
   pip install -r requirements.txt
   cp .env.example .env
   # Edit .env with your DATABASE_URL and GEMINI_API_KEY
   python main.py
   ```
   Backend runs at `http://localhost:8000` • API docs at `/docs`

3. **Set up frontend (in a new terminal):**
   ```bash
   cd frontend
   npm install
   cp .env.example .env
   # Edit .env if backend is not on localhost:8000
   npx expo start
   ```
   Then scan the QR code with Expo Go app or press `w` for web

### Detailed Setup

<details>
<summary><b>Backend Configuration</b></summary>

1. **Install Python 3.11+** and PostgreSQL 14+

2. **Set up database:**
   - **Option A:** Local PostgreSQL
     ```bash
     psql postgres
     CREATE DATABASE debaide;
     ```
   - **Option B:** [Neon DB](https://neon.tech) (recommended - free serverless)
   - **Option C:** [Supabase](https://supabase.com)

3. **Get Gemini API Key:**
   - Visit [Google AI Studio](https://makersuite.google.com/)
   - Sign in and create a new API key (free tier available)

4. **Configure .env:**
   ```env
   DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/debaide
   GEMINI_API_KEY=your_gemini_api_key_here
   SECRET_KEY=your_secret_key_for_jwt
   API_BASE_URL=http://localhost:8000
   ```

5. **Run the server:**
   ```bash
   uvicorn main:app --host 0.0.0.0 --port 8000 --reload
   ```

</details>

<details>
<summary><b>Frontend Configuration</b></summary>

1. **Install Node.js 18+**

2. **Configure .env:**
   ```env
   EXPO_PUBLIC_API_URL=http://localhost:8000
   ```

3. **Run on different platforms:**
   ```bash
   npx expo start
   ```
   - **iOS:** Press `i` (requires Xcode on macOS)
   - **Android:** Press `a` (requires Android Studio)
   - **Web:** Press `w`
   - **Mobile device:** Scan QR with Expo Go app

</details>

## 🛠️ Setup Instructions

### Prerequisites
- Python 3.11+
- Node.js 18+
- PostgreSQL 14+ (or use Neon DB, Supabase)
- Gemini API Key ([Get it here](https://makersuite.google.com/))
   cd frontend
   ```

2. **Install dependencies:**
   ```bash
   npm install
   ```

3. **Configure environment:**
   ```bash
   cp .env.example .env
   # Edit .env if your backend is not on localhost:8000
   ```

4. **Start Expo:**
   ```bash
   npm start
   ```

5. **Run on device:**
   - Scan QR code with Expo Go app (iOS/Android)
   - Press `i` for iOS simulator
   - Press `a` for Android emulator
   - Press `w` for web

## 🎮 How to Use

### Practice Mode
1. **Sign up / Log in** to your account
2. **Choose a topic** from the list or try the daily AI-generated topic
3. **Get your stance** - System assigns you PRO or CON position
4. **Record your debate** in three segments:
   - Opening Statement (introduce your position)
   - Rebuttal (counter opposing arguments)
   - Closing Argument (summarize and conclude)
5. **Review AI feedback** - Get scores, strengths, improvements, and practice drills

### Battle Mode
1. **Enter the lobby** and see available battles
2. **Create a room** or join an existing one
3. **Wait for opponent** to join
4. **Take turns debating:**
   - Each player records their segments
   - AI transcribes in real-time
   - Follow

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 203 KB.
- FastAPI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- PostgreSQL (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (40 of 40)

```
.DS_Store
backend/.env.example
backend/.gitignore
backend/database.py
backend/Dockerfile
backend/main.py
backend/models.py
backend/requirements.txt
backend/schemas.py
backend/seed.py
backend/services/__init__.py
backend/services/auth_service.py
backend/services/gemini_service.py
backend/services/storage_service.py
backend/services/stt_service.py
docker-compose.yml
frontend/.env.example
frontend/.gitignore
frontend/app.json
frontend/app/_layout.tsx
frontend/app/auth/login.tsx
frontend/app/auth/register.tsx
frontend/app/battle/lobby.tsx
frontend/app/battle/results.tsx
frontend/app/battle/room.tsx
frontend/app/home.tsx
frontend/app/index.tsx
frontend/app/results.tsx
frontend/app/session.tsx
frontend/app/topics.tsx
frontend/components/NavBar.tsx
frontend/components/ThemeToggle.tsx
frontend/lib/api.ts
frontend/lib/authStore.ts
frontend/lib/store.ts
frontend/lib/theme.ts
frontend/lib/theme.tsx
frontend/package.json
frontend/tsconfig.json
README.md
```

### Dependencies

- backend/requirements.txt: asyncpg@==0.30.0, boto3@==1.35.70, fastapi@==0.115.0, google-generativeai@==0.8.3, openai-whisper, pydantic@==2.10.0, python-dotenv@==1.0.1, python-multipart@==0.0.12, sqlalchemy@==2.0.36, uvicorn[standard]@==0.32.0
- frontend/package.json: @babel/core@^7.25.0, @expo/metro-runtime@~6.1.2, @expo/vector-icons@^15.0.3, @react-native-async-storage/async-storage@^2.2.0, @tanstack/react-query@^5.0.0, @types/react@~19.1.10, axios@^1.6.0, expo@~54.0.0, expo-asset@~12.0.9, expo-av@~16.0.7, expo-constants@~18.0.10, expo-file-system@~19.0.17, expo-font@~14.0.9, expo-linking@~8.0.8, expo-router@~6.0.13, expo-splash-screen@~31.0.10, expo-status-bar@~3.0.7, react@^19.1.0, react-dom@^19.1.0, react-native@^0.81.5, react-native-safe-area-context@~5.6.0, react-native-screens@~4.16.0, react-native-web@^0.21.2, typescript@~5.9.2, zustand@^4.5.0

### Recent commits (newest first)

- final vers
- final version

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

### docker-compose.yml

```yaml
version: '3.8'

services:
  # PostgreSQL Database
  db:
    image: postgres:14-alpine
    container_name: debaide_db
    environment:
      POSTGRES_DB: debaide
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # FastAPI Backend
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: debaide_backend
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql+asyncpg://postgres:postgres@db:5432/debaide
      GEMINI_API_KEY: ${GEMINI_API_KEY}
      API_BASE_URL: http://localhost:8000
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./backend:/app
      - audio_storage:/app/storage/audio
    command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload

  # Adminer - Database Management UI
  adminer:
    image: adminer:latest
    container_name: debaide_adminer
    ports:
      - "8080:8080"
    environment:
      ADMINER_DEFAULT_SERVER: db
    depends_on:
      - db

volumes:
  postgres_data:
  audio_storage:

```

### backend/requirements.txt

```
fastapi==0.115.0
uvicorn[standard]==0.32.0
sqlalchemy==2.0.36
asyncpg==0.30.0
pydantic==2.10.0
python-multipart==0.0.12
google-generativeai==0.8.3
openai-whisper
boto3==1.35.70
python-dotenv==1.0.1

```

### backend/Dockerfile

```
# Use Python 3.11 slim image
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && 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 . .

# Create storage directory
RUN mkdir -p storage/audio

# Expose port
EXPOSE 8000

# Set environment variables
ENV PYTHONUNBUFFERED=1

# Run the application
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

```

### frontend/package.json

```
{
  "name": "debaide-mobile",
  "version": "1.0.0",
  "main": "expo-router/entry",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@expo/vector-icons": "^15.0.3",
    "@react-native-async-storage/async-storage": "^2.2.0",
    "@tanstack/react-query": "^5.0.0",
    "axios": "^1.6.0",
    "expo": "~54.0.0",
    "expo-asset": "~12.0.9",
    "expo-av": "~16.0.7",
    "expo-constants": "~18.0.10",
    "expo-file-system": "~19.0.17",
    "expo-font": "~14.0.9",
    "expo-linking": "~8.0.8",
    "expo-router": "~6.0.13",
    "expo-splash-screen": "~31.0.10",
    "expo-status-bar": "~3.0.7",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "react-native": "^0.81.5",
    "react-native-safe-area-context": "~5.6.0",
    "react-native-screens": "~4.16.0",
    "react-native-web": "^0.21.2",
    "zustand": "^4.5.0"
  },
  "devDependencies": {
    "@babel/core": "^7.25.0",
    "@expo/metro-runtime": "~6.1.2",
    "@types/react": "~19.1.10",
    "typescript": "~5.9.2"
  },
  "private": true
}

```

### frontend/app/_layout.tsx

```typescript
/**
 * Root layout with React Query provider
 */
import { Stack } from 'expo-router';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { SafeAreaProvider } from 'react-native-safe-area-context';

const queryClient = new QueryClient();

export default function RootLayout() {
  return (
    <QueryClientProvider client={queryClient}>
      <SafeAreaProvider>
        <Stack
          screenOptions={{
            headerShown: false,
          }}
        >
          <Stack.Screen name="index" />
          <Stack.Screen name="topics" />
          <Stack.Screen name="session" />
          <Stack.Screen name="results" />
        </Stack>
      </SafeAreaProvider>
    </QueryClientProvider>
  );
}

```

### frontend/app/index.tsx

```typescript
/**
 * Home screen - Redirects to login or home based on auth state
 */
import { useEffect } from 'react';
import { View, ActivityIndicator } from 'react-native';
import { useRouter } from 'expo-router';
import { useAuthStore } from '../lib/authStore';

export default function IndexScreen() {
  const router = useRouter();
  const { token, loadToken } = useAuthStore();

  useEffect(() => {
    // Load token from storage first
    loadToken().then(() => {
      // If user is already authenticated, go to home
      // Otherwise, go to login
      if (token) {
        router.replace('/home');
      } else {
        router.replace('/auth/login');
      }
    });
  }, []);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <ActivityIndicator size="large" />
    </View>
  );
}

```

### backend/main.py

```python
"""
debAIDe - FastAPI Backend
API server for debate practice application
"""
from dotenv import load_dotenv
load_dotenv()  # Load environment variables from .env file

from fastapi import FastAPI, HTTPException, UploadFile, File, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession
from contextlib import asynccontextmanager
import uuid
import random
import os

from database import get_db, init_db
from models import (
    Session as DebateSession, 
    Segment, 
    Scorecard, 
    Topic, 
    User,
    Battle,
    BattleSegment
)
from schemas import (
    SessionStartRequest,
    SessionStartResponse,
    SegmentUploadResponse,
    ScoreResponse,
    ScoreBreakdown,
    TopicResponse
)
from services.gemini_service import GeminiService
from services.storage_service import StorageService
from services.stt_service import STTService
from services.auth_service import (
    verify_password,
    get_password_hash,
    create_access_token,
    decode_access_token
)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Initialize database on startup"""
    await init_db()
    yield


app = FastAPI(
    title="debAIDe API",
    description="AI-powered debate practice platform",
    version="1.0.0",
    lifespan=lifespan
)

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

# Initialize services
gemini_service = GeminiService()
storage_service = StorageService()
stt_service = STTService()

# Security
security = HTTPBearer(auto_error=False)


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: AsyncSession = Depends(get_db)
) -> User:
    """Get current authenticated user from JWT token"""
    if not credentials:
        raise HTTPException(status_code=401, detail="Not authenticated")
    
    token = credentials.credentials
    payload = decode_access_token(token)
    
    if not payload:
        raise HTTPException(status_code=401, detail="Invalid or expired token")
    
    user_id = payload.get("sub")
    if not user_id:
        raise HTTPException(status_code=401, detail="Invalid token payload")
    
    from sqlalchemy import select
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalars().first()
    
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    return user


@app.get("/")
async def root():
    """Health check endpoint"""
    return {
        "status": "healthy",
        "service": "debAIDe API",
        "version": "1.0.0"
    }


# ============================================================================
# AUTH ENDPOINTS
# ============================================================================

@app.post("/auth/register")
async def register(
    username: str,
    email: str,
    password: str,
    db: AsyncSession = Depends(get_db)
):
    """Register a new user"""
    from sqlalchemy import select
    
    # Check if username exists
    result = await db.execute(select(User).where(User.username == username))
    if result.scalars().first():
        raise HTTPException(status_code=400, detail="Username already taken")
    
    # Check if email exists
    result = await db.execute(select(User).where(User.email == email))
    if result.scalars().first():
        raise HTTPException(status_code=400, detail="Email already registered")
    
    # Create new user
    user = User(
        id=str(uuid.uuid4()),
        username=username,
        email=email,
        hashed_password=get_password_hash(password)
    )
    
    db.add(user)
    await db.commit()
    await db.refresh(user)
    
    # Create initial stats for user
    from models import UserStats
    stats = UserStats(user_id=user.id)
    db.add(stats)
    await db.commit()
    
    # Generate token
    access_token = create_access_token(data={"sub": user.id})
    
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "user": {
            "id": user.id,
            "username": user.username,
            "email": user.email
        }
    }


@app.post("/auth/login")
async def login(
    username: str,
    password: str,
    db: AsyncSession = Depends(get_db)
):
    """Login user"""
    from sqlalchemy import select
    
    # Find user by username
    result = await db.execute(select(User).where(User.username == username))
    user = result.scalars().first()
    
    if not user or not verify_password(password, user.hashed_password):
        raise HTTPException(status_code=401, detail="Invalid username or password")
    
    # Generate token
    access_token = create_access_token(data={"sub": user.id})
    
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "user": {
            "id": user.id,
            "username": user.username,
            "email": user.email
        }
    }


@app.get("/auth/me")
async def get_me(current_user: User = Depends(get_current_user)):
    """Get current user info"""
    return {
        "id": current_user.id,
        "username": current_user.username,
        "email": current_user.email,
        "created_at": current_user.created_at
    }


# ============================================================================
# USER STATS ENDPOINTS
# ============================================================================


@app.get("/user/stats")
async def get_user_stats(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Get user statistics"""
    from sqlalchemy import select
    from models import UserStats
    
    # Get or create user stats
    result = await db.execute(select(UserStats).where(UserStats.user_id == current_user.id))
    stats = result.scalars().fir
[truncated — 33716 more characters]
```

### backend/database.py

```python
"""
Database configuration and session management
"""
import os
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import declarative_base

# Database URL from environment
DATABASE_URL = os.getenv(
    "DATABASE_URL",
    "postgresql+asyncpg://postgres:postgres@localhost:5432/debaide"
)

# Create async engine
engine = create_async_engine(
    DATABASE_URL,
    echo=True,  # Set to False in production
    future=True
)

# Create session factory
AsyncSessionLocal = async_sessionmaker(
    engine,
    class_=AsyncSession,
    expire_on_commit=False
)

# Base class for models
Base = declarative_base()


async def init_db():
    """Initialize database tables"""
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)


async def get_db() -> AsyncSession:
    """Dependency for getting database sessions"""
    async with AsyncSessionLocal() as session:
        try:
            yield session
        finally:
            await session.close()

```

### backend/schemas.py

```python
"""
Pydantic schemas for request/response validation
"""
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
from datetime import datetime


class SessionStartRequest(BaseModel):
    """Request to start a new debate session"""
    topic_id: int
    user_id: Optional[str] = None


class SessionStartResponse(BaseModel):
    """Response when starting a new session"""
    session_id: str
    topic_title: str
    topic_description: Optional[str] = None
    stance: str  # 'pro' or 'con'


class SegmentUploadResponse(BaseModel):
    """Response after uploading an audio segment"""
    segment_id: int
    transcript: str
    audio_url: str | None  # Optional for text submissions
    duration: float


class ScoreBreakdown(BaseModel):
    """Individual score breakdown"""
    structure: float = Field(..., ge=0, le=5)
    logic: float = Field(..., ge=0, le=5)
    delivery: float = Field(..., ge=0, le=5)
    time_use: float = Field(..., ge=0, le=5)
    total: float = Field(..., ge=0, le=20)


class Highlight(BaseModel):
    """Highlighted moment in the debate"""
    timestamp: float
    text: str
    reason: str


class ScoreResponse(BaseModel):
    """Response after scoring a debate session"""
    session_id: str
    scores: ScoreBreakdown
    feedback: Dict[str, Any]
    highlights: List[Highlight]
    drills: List[Any]  # Can be strings or objects with drill_name/description


class TopicResponse(BaseModel):
    """Debate topic response"""
    id: int
    title: str
    description: Optional[str] = None
    difficulty: str
    category: Optional[str] = None


class TopicGeneration(BaseModel):
    """Generated topic from AI"""
    title: str
    description: str
    difficulty: str
    category: str

```

### backend/seed.py

```python
"""
Seed script to populate database with initial debate topics
"""
import asyncio
from sqlalchemy.ext.asyncio import AsyncSession
from database import AsyncSessionLocal, init_db
from models import Topic


async def seed_topics():
    """Add initial debate topics to database"""
    
    initial_topics = [
        {
            "title": "Social media does more harm than good",
            "description": "Examine the impact of social media on mental health, democracy, and social connections.",
            "difficulty": "medium",
            "category": "technology"
        },
        {
            "title": "Remote work should be the default for office jobs",
            "description": "Debate the future of work considering productivity, work-life balance, and company culture.",
            "difficulty": "easy",
            "category": "economics"
        },
        {
            "title": "Artificial intelligence poses an existential threat to humanity",
            "description": "Discuss AI safety, regulation, and the long-term implications of advanced AI systems.",
            "difficulty": "hard",
            "category": "technology"
        },
        {
            "title": "College education should be free for all citizens",
            "description": "Explore the economic impact, accessibility, and value of higher education.",
            "difficulty": "medium",
            "category": "education"
        },
        {
            "title": "Climate change is primarily caused by human activity",
            "description": "Evaluate scientific evidence and debate policy responses to environmental challenges.",
            "difficulty": "medium",
            "category": "environment"
        },
        {
            "title": "Universal basic income would benefit society",
            "description": "Analyze the economic feasibility and social impact of guaranteed income programs.",
            "difficulty": "hard",
            "category": "economics"
        },
        {
            "title": "Video games contribute to violent behavior",
            "description": "Examine research on gaming's psychological effects and media influence on behavior.",
            "difficulty": "easy",
            "category": "ethics"
        },
        {
            "title": "Privacy is more important than security",
            "description": "Debate the balance between civil liberties and safety in the digital age.",
            "difficulty": "medium",
            "category": "politics"
        },
        {
            "title": "Nuclear energy is essential for fighting climate change",
            "description": "Weigh the benefits and risks of nuclear power as a clean energy source.",
            "difficulty": "hard",
            "category": "environment"
        },
        {
            "title": "Standardized testing accurately measures student ability",
            "description": "Evaluate testing methods and their role in education assessment and college admissions.",
            "difficulty": "easy",
            "category": "education"
        }
    ]
    
    # Initialize database
    await init_db()
    
    # Create session
    async with AsyncSessionLocal() as session:
        # Check if topics already exist
        from sqlalchemy import select
        result = await session.execute(select(Topic))
        existing_topics = result.scalars().all()
        
        if existing_topics:
            print(f"Database already has {len(existing_topics)} topics. Skipping seed.")
            return
        
        # Add topics
        for topic_data in initial_topics:
            topic = Topic(**topic_data)
            session.add(topic)
        
        await session.commit()
        print(f"✅ Successfully seeded {len(initial_topics)} debate topics!")


if __name__ == "__main__":
    asyncio.run(seed_topics())

```

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