# Project export: Sage.ai

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: We provide businesses with an AI-powered phone line that answers calls, talks naturally with customers, and automatically books appointments through Google Calendar.
- Devpost: https://devpost.com/software/sage-ai-zhagx0
- GitHub: https://github.com/Max-Dunmire/sage.ai
- Video: https://www.youtube.com/embed/mprJaBZur58?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — sm (32 commits), Max Dunmire (17 commits), dvek27 (2 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 164 recognized source files, 450 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- MongoDB (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (120 of 186)

```
.gitignore
sage-server/call_handling.py
sage-server/db/__init__.py
sage-server/db/crud.py
sage-server/db/models.py
sage-server/db/session.py
sage-server/events/events.py
sage-server/events/templates/input_audio_buffer-append.json
sage-server/events/templates/input_audio_buffer-clear.json
sage-server/events/templates/input_audio_buffer-commit.json
sage-server/events/templates/media.json
sage-server/events/templates/session-update.json
sage-server/server.py
sage-server/twiml.xml
sage-server/utils/cache.py
sage-server/utils/logger.py
sage-server/utils/settings.py
sage-web-server/controllers/userController.js
sage-web-server/models/userSchema.js
sage-web-server/package.json
sage-web-server/routes/user.js
sage-web-server/server.js
sage-web-service/bun.lockb
sage-web-service/components.json
sage-web-service/eslint.config.js
sage-web-service/index.html
sage-web-service/package.json
sage-web-service/postcss.config.js
sage-web-service/public/robots.txt
sage-web-service/sage-ai-landing/.gitignore
sage-web-service/sage-ai-landing/bun.lockb
sage-web-service/sage-ai-landing/components.json
sage-web-service/sage-ai-landing/eslint.config.js
sage-web-service/sage-ai-landing/index.html
sage-web-service/sage-ai-landing/package.json
sage-web-service/sage-ai-landing/postcss.config.js
sage-web-service/sage-ai-landing/public/robots.txt
sage-web-service/sage-ai-landing/README.md
sage-web-service/sage-ai-landing/src/App.tsx
sage-web-service/sage-ai-landing/src/components/Demo.tsx
sage-web-service/sage-ai-landing/src/components/Features.tsx
sage-web-service/sage-ai-landing/src/components/Footer.tsx
sage-web-service/sage-ai-landing/src/components/Hero.tsx
sage-web-service/sage-ai-landing/src/components/Navigation.tsx
sage-web-service/sage-ai-landing/src/components/Pricing.tsx
sage-web-service/sage-ai-landing/src/components/ui/accordion.tsx
sage-web-service/sage-ai-landing/src/components/ui/alert-dialog.tsx
sage-web-service/sage-ai-landing/src/components/ui/alert.tsx
sage-web-service/sage-ai-landing/src/components/ui/aspect-ratio.tsx
sage-web-service/sage-ai-landing/src/components/ui/avatar.tsx
sage-web-service/sage-ai-landing/src/components/ui/badge.tsx
sage-web-service/sage-ai-landing/src/components/ui/breadcrumb.tsx
sage-web-service/sage-ai-landing/src/components/ui/button.tsx
sage-web-service/sage-ai-landing/src/components/ui/calendar.tsx
sage-web-service/sage-ai-landing/src/components/ui/card.tsx
sage-web-service/sage-ai-landing/src/components/ui/carousel.tsx
sage-web-service/sage-ai-landing/src/components/ui/chart.tsx
sage-web-service/sage-ai-landing/src/components/ui/checkbox.tsx
sage-web-service/sage-ai-landing/src/components/ui/collapsible.tsx
sage-web-service/sage-ai-landing/src/components/ui/command.tsx
sage-web-service/sage-ai-landing/src/components/ui/context-menu.tsx
sage-web-service/sage-ai-landing/src/components/ui/dialog.tsx
sage-web-service/sage-ai-landing/src/components/ui/drawer.tsx
sage-web-service/sage-ai-landing/src/components/ui/dropdown-menu.tsx
sage-web-service/sage-ai-landing/src/components/ui/form.tsx
sage-web-service/sage-ai-landing/src/components/ui/hover-card.tsx
sage-web-service/sage-ai-landing/src/components/ui/input-otp.tsx
sage-web-service/sage-ai-landing/src/components/ui/input.tsx
sage-web-service/sage-ai-landing/src/components/ui/label.tsx
sage-web-service/sage-ai-landing/src/components/ui/menubar.tsx
sage-web-service/sage-ai-landing/src/components/ui/navigation-menu.tsx
sage-web-service/sage-ai-landing/src/components/ui/pagination.tsx
sage-web-service/sage-ai-landing/src/components/ui/popover.tsx
sage-web-service/sage-ai-landing/src/components/ui/progress.tsx
sage-web-service/sage-ai-landing/src/components/ui/radio-group.tsx
sage-web-service/sage-ai-landing/src/components/ui/resizable.tsx
sage-web-service/sage-ai-landing/src/components/ui/scroll-area.tsx
sage-web-service/sage-ai-landing/src/components/ui/select.tsx
sage-web-service/sage-ai-landing/src/components/ui/separator.tsx
sage-web-service/sage-ai-landing/src/components/ui/sheet.tsx
sage-web-service/sage-ai-landing/src/components/ui/sidebar.tsx
sage-web-service/sage-ai-landing/src/components/ui/skeleton.tsx
sage-web-service/sage-ai-landing/src/components/ui/slider.tsx
sage-web-service/sage-ai-landing/src/components/ui/sonner.tsx
sage-web-service/sage-ai-landing/src/components/ui/switch.tsx
sage-web-service/sage-ai-landing/src/components/ui/table.tsx
sage-web-service/sage-ai-landing/src/components/ui/tabs.tsx
sage-web-service/sage-ai-landing/src/components/ui/textarea.tsx
sage-web-service/sage-ai-landing/src/components/ui/toast.tsx
sage-web-service/sage-ai-landing/src/components/ui/toaster.tsx
sage-web-service/sage-ai-landing/src/components/ui/toggle-group.tsx
sage-web-service/sage-ai-landing/src/components/ui/toggle.tsx
sage-web-service/sage-ai-landing/src/components/ui/tooltip.tsx
sage-web-service/sage-ai-landing/src/components/ui/use-toast.ts
sage-web-service/sage-ai-landing/src/hooks/use-mobile.tsx
sage-web-service/sage-ai-landing/src/hooks/use-toast.ts
sage-web-service/sage-ai-landing/src/index.css
sage-web-service/sage-ai-landing/src/lib/utils.ts
sage-web-service/sage-ai-landing/src/main.tsx
sage-web-service/sage-ai-landing/src/pages/Index.tsx
sage-web-service/sage-ai-landing/src/pages/NotFound.tsx
sage-web-service/sage-ai-landing/src/vite-env.d.ts
sage-web-service/sage-ai-landing/tailwind.config.ts
sage-web-service/sage-ai-landing/tsconfig.app.json
sage-web-service/sage-ai-landing/tsconfig.json
sage-web-service/sage-ai-landing/tsconfig.node.json
sage-web-service/sage-ai-landing/vite.config.ts
sage-web-service/src/App.css
sage-web-service/src/App.tsx
sage-web-service/src/components/ChatbotIcon.tsx
sage-web-service/src/components/Footer.tsx
sage-web-service/src/components/GoogleCalendar.tsx
sage-web-service/src/components/Navbar.tsx
sage-web-service/src/components/ProtectedRoute.tsx
sage-web-service/src/components/ui/accordion.tsx
sage-web-service/src/components/ui/alert-dialog.tsx
sage-web-service/src/components/ui/alert.tsx
sage-web-service/src/components/ui/aspect-ratio.tsx
sage-web-service/src/components/ui/avatar.tsx
sage-web-service/src/components/ui/badge.tsx
[66 more files omitted for size]
```

### Dependencies

- sage-web-server/package.json: bcryptjs@^3.0.2, cors@^2.8.5, express@^5.1.0, mongoose@^8.19.2
- sage-web-service/package.json: @eslint/js@^9.32.0, @hookform/resolvers@^3.10.0, @radix-ui/react-accordion@^1.2.11, @radix-ui/react-alert-dialog@^1.1.14, @radix-ui/react-aspect-ratio@^1.1.7, @radix-ui/react-avatar@^1.1.10, @radix-ui/react-checkbox@^1.3.2, @radix-ui/react-collapsible@^1.1.11, @radix-ui/react-context-menu@^2.2.15, @radix-ui/react-dialog@^1.1.14, @radix-ui/react-dropdown-menu@^2.1.15, @radix-ui/react-hover-card@^1.1.14, @radix-ui/react-label@^2.1.7, @radix-ui/react-menubar@^1.1.15, @radix-ui/react-navigation-menu@^1.2.13, @radix-ui/react-popover@^1.1.14, @radix-ui/react-progress@^1.1.7, @radix-ui/react-radio-group@^1.3.7, @radix-ui/react-scroll-area@^1.2.9, @radix-ui/react-select@^2.2.5, @radix-ui/react-separator@^1.1.7, @radix-ui/react-slider@^1.3.5, @radix-ui/react-slot@^1.2.3, @radix-ui/react-switch@^1.2.5, @radix-ui/react-tabs@^1.1.12, @radix-ui/react-toast@^1.2.14, @radix-ui/react-toggle@^1.1.9, @radix-ui/react-toggle-group@^1.1.10, @radix-ui/react-tooltip@^1.2.7, @tailwindcss/typography@^0.5.16, @tanstack/react-query@^5.83.0, @types/node@^22.16.5, @types/react@^18.3.23, @types/react-dom@^18.3.7, @vitejs/plugin-react-swc@^3.11.0, autoprefixer@^10.4.21, class-variance-authority@^0.7.1, clsx@^2.1.1, cmdk@^1.1.1, date-fns@^3.6.0, embla-carousel-react@^8.6.0, eslint@^9.32.0, eslint-plugin-react-hooks@^5.2.0, eslint-plugin-react-refresh@^0.4.20, globals@^15.15.0, input-otp@^1.4.2, lovable-tagger@^1.1.11, lucide-react@^0.462.0, next-themes@^0.3.0, postcss@^8.5.6, react@^18.3.1, react-day-picker@^8.10.1, react-dom@^18.3.1, react-hook-form@^7.61.1, react-resizable-panels@^2.1.9, react-router-dom@^6.30.1, recharts@^2.15.4, sonner@^1.7.4, tailwind-merge@^2.6.0, tailwindcss@^3.4.17, tailwindcss-animate@^1.0.7, typescript@^5.8.3, typescript-eslint@^8.38.0, vaul@^0.9.9, vite@^5.4.19, zod@^3.25.76
- sage-web-service/sage-ai-landing/package.json: @eslint/js@^9.32.0, @hookform/resolvers@^3.10.0, @radix-ui/react-accordion@^1.2.11, @radix-ui/react-alert-dialog@^1.1.14, @radix-ui/react-aspect-ratio@^1.1.7, @radix-ui/react-avatar@^1.1.10, @radix-ui/react-checkbox@^1.3.2, @radix-ui/react-collapsible@^1.1.11, @radix-ui/react-context-menu@^2.2.15, @radix-ui/react-dialog@^1.1.14, @radix-ui/react-dropdown-menu@^2.1.15, @radix-ui/react-hover-card@^1.1.14, @radix-ui/react-label@^2.1.7, @radix-ui/react-menubar@^1.1.15, @radix-ui/react-navigation-menu@^1.2.13, @radix-ui/react-popover@^1.1.14, @radix-ui/react-progress@^1.1.7, @radix-ui/react-radio-group@^1.3.7, @radix-ui/react-scroll-area@^1.2.9, @radix-ui/react-select@^2.2.5, @radix-ui/react-separator@^1.1.7, @radix-ui/react-slider@^1.3.5, @radix-ui/react-slot@^1.2.3, @radix-ui/react-switch@^1.2.5, @radix-ui/react-tabs@^1.1.12, @radix-ui/react-toast@^1.2.14, @radix-ui/react-toggle@^1.1.9, @radix-ui/react-toggle-group@^1.1.10, @radix-ui/react-tooltip@^1.2.7, @tailwindcss/typography@^0.5.16, @tanstack/react-query@^5.83.0, @types/node@^22.16.5, @types/react@^18.3.23, @types/react-dom@^18.3.7, @vitejs/plugin-react-swc@^3.11.0, autoprefixer@^10.4.21, class-variance-authority@^0.7.1, clsx@^2.1.1, cmdk@^1.1.1, date-fns@^3.6.0, embla-carousel-react@^8.6.0, eslint@^9.32.0, eslint-plugin-react-hooks@^5.2.0, eslint-plugin-react-refresh@^0.4.20, globals@^15.15.0, input-otp@^1.4.2, lovable-tagger@^1.1.11, lucide-react@^0.462.0, next-themes@^0.3.0, postcss@^8.5.6, react@^18.3.1, react-day-picker@^8.10.1, react-dom@^18.3.1, react-hook-form@^7.61.1, react-resizable-panels@^2.1.9, react-router-dom@^6.30.1, recharts@^2.15.4, sonner@^1.7.4, tailwind-merge@^2.6.0, tailwindcss@^3.4.17, tailwindcss-animate@^1.0.7, typescript@^5.8.3, typescript-eslint@^8.38.0, vaul@^0.9.9, vite@^5.4.19, zod@^3.25.76

### Recent commits (newest first)

- multi-caller multi-client functionality
- call database logging setup
- moved utils & setup redis cache
- temp db system setup
- basic db setup
- got rid of unused openai cases
- type annotations
- got rid of empty __init__.py file
- tried cleaning up .gitignore
- updating twiml.xml
- got rid of the audio_utils
- added some more debug logging
- fixed the session.update
- packet logging added and audio fixes
- deleted old servers
- fixed twiml issue
- added a logger function
- error handling/kinda
- minor fixes
- fixed EventManager.serve

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

### sage-web-server/package.json

```
{
  "name": "product_page_backend",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node --env-file=.env server.js",
    "dev": "node --watch --env-file=.env server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcryptjs": "^3.0.2",
    "cors": "^2.8.5",
    "express": "^5.1.0",
    "mongoose": "^8.19.2"
  }
}

```

### sage-web-service/package.json

```
{
  "name": "vite_react_shadcn_ts",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "build:dev": "vite build --mode development",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@hookform/resolvers": "^3.10.0",
    "@radix-ui/react-accordion": "^1.2.11",
    "@radix-ui/react-alert-dialog": "^1.1.14",
    "@radix-ui/react-aspect-ratio": "^1.1.7",
    "@radix-ui/react-avatar": "^1.1.10",
    "@radix-ui/react-checkbox": "^1.3.2",
    "@radix-ui/react-collapsible": "^1.1.11",
    "@radix-ui/react-context-menu": "^2.2.15",
    "@radix-ui/react-dialog": "^1.1.14",
    "@radix-ui/react-dropdown-menu": "^2.1.15",
    "@radix-ui/react-hover-card": "^1.1.14",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-menubar": "^1.1.15",
    "@radix-ui/react-navigation-menu": "^1.2.13",
    "@radix-ui/react-popover": "^1.1.14",
    "@radix-ui/react-progress": "^1.1.7",
    "@radix-ui/react-radio-group": "^1.3.7",
    "@radix-ui/react-scroll-area": "^1.2.9",
    "@radix-ui/react-select": "^2.2.5",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slider": "^1.3.5",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-switch": "^1.2.5",
    "@radix-ui/react-tabs": "^1.1.12",
    "@radix-ui/react-toast": "^1.2.14",
    "@radix-ui/react-toggle": "^1.1.9",
    "@radix-ui/react-toggle-group": "^1.1.10",
    "@radix-ui/react-tooltip": "^1.2.7",
    "@tanstack/react-query": "^5.83.0",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.1.1",
    "date-fns": "^3.6.0",
    "embla-carousel-react": "^8.6.0",
    "input-otp": "^1.4.2",
    "lucide-react": "^0.462.0",
    "next-themes": "^0.3.0",
    "react": "^18.3.1",
    "react-day-picker": "^8.10.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.61.1",
    "react-resizable-panels": "^2.1.9",
    "react-router-dom": "^6.30.1",
    "recharts": "^2.15.4",
    "sonner": "^1.7.4",
    "tailwind-merge": "^2.6.0",
    "tailwindcss-animate": "^1.0.7",
    "vaul": "^0.9.9",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@eslint/js": "^9.32.0",
    "@tailwindcss/typography": "^0.5.16",
    "@types/node": "^22.16.5",
    "@types/react": "^18.3.23",
    "@types/react-dom": "^18.3.7",
    "@vitejs/plugin-react-swc": "^3.11.0",
    "autoprefixer": "^10.4.21",
    "eslint": "^9.32.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.20",
    "globals": "^15.15.0",
    "lovable-tagger": "^1.1.11",
    "postcss": "^8.5.6",
    "tailwindcss": "^3.4.17",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.38.0",
    "vite": "^5.4.19"
  }
}

```

### sage-web-service/sage-ai-landing/package.json

```
{
  "name": "vite_react_shadcn_ts",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "build:dev": "vite build --mode development",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@hookform/resolvers": "^3.10.0",
    "@radix-ui/react-accordion": "^1.2.11",
    "@radix-ui/react-alert-dialog": "^1.1.14",
    "@radix-ui/react-aspect-ratio": "^1.1.7",
    "@radix-ui/react-avatar": "^1.1.10",
    "@radix-ui/react-checkbox": "^1.3.2",
    "@radix-ui/react-collapsible": "^1.1.11",
    "@radix-ui/react-context-menu": "^2.2.15",
    "@radix-ui/react-dialog": "^1.1.14",
    "@radix-ui/react-dropdown-menu": "^2.1.15",
    "@radix-ui/react-hover-card": "^1.1.14",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-menubar": "^1.1.15",
    "@radix-ui/react-navigation-menu": "^1.2.13",
    "@radix-ui/react-popover": "^1.1.14",
    "@radix-ui/react-progress": "^1.1.7",
    "@radix-ui/react-radio-group": "^1.3.7",
    "@radix-ui/react-scroll-area": "^1.2.9",
    "@radix-ui/react-select": "^2.2.5",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slider": "^1.3.5",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-switch": "^1.2.5",
    "@radix-ui/react-tabs": "^1.1.12",
    "@radix-ui/react-toast": "^1.2.14",
    "@radix-ui/react-toggle": "^1.1.9",
    "@radix-ui/react-toggle-group": "^1.1.10",
    "@radix-ui/react-tooltip": "^1.2.7",
    "@tanstack/react-query": "^5.83.0",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.1.1",
    "date-fns": "^3.6.0",
    "embla-carousel-react": "^8.6.0",
    "input-otp": "^1.4.2",
    "lucide-react": "^0.462.0",
    "next-themes": "^0.3.0",
    "react": "^18.3.1",
    "react-day-picker": "^8.10.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.61.1",
    "react-resizable-panels": "^2.1.9",
    "react-router-dom": "^6.30.1",
    "recharts": "^2.15.4",
    "sonner": "^1.7.4",
    "tailwind-merge": "^2.6.0",
    "tailwindcss-animate": "^1.0.7",
    "vaul": "^0.9.9",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@eslint/js": "^9.32.0",
    "@tailwindcss/typography": "^0.5.16",
    "@types/node": "^22.16.5",
    "@types/react": "^18.3.23",
    "@types/react-dom": "^18.3.7",
    "@vitejs/plugin-react-swc": "^3.11.0",
    "autoprefixer": "^10.4.21",
    "eslint": "^9.32.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.20",
    "globals": "^15.15.0",
    "lovable-tagger": "^1.1.11",
    "postcss": "^8.5.6",
    "tailwindcss": "^3.4.17",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.38.0",
    "vite": "^5.4.19"
  }
}

```

### sage-web-server/server.js

```javascript
import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import userRoutes from './routes/user.js';

const app = express();

// Config
const PORT = process.env.PORT ? Number(process.env.PORT) : 3001;
const ORIGIN = process.env.CORS_ORIGIN || '*';
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/sage_ai';

// Middleware
app.use(cors({ origin: ORIGIN }));
app.use(express.json());

// MongoDB Connection
mongoose
  .connect(MONGODB_URI)
  .then(() => {
    console.log('MongoDB connected successfully');
  })
  .catch((error) => {
    console.error('MongoDB connection error:', error);
    process.exit(1);
  });

// Routes
app.get('/', (req, res) => {
    res.json({ ok: true, service: 'product_page_backend', message: 'Server is running' });
});

// User routes
app.use('/api/users', userRoutes);

app.get('/health', (req, res) => {
    res.status(200).json({ status: 'ok' });
});

// 404 handler
app.use((req, res) => {
    res.status(404).json({ error: 'Not found' });
});

// Error handler
// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
    console.error('Unhandled error:', err);
    res.status(500).json({ error: 'Internal server error' });
});

// Start
app.listen(PORT, () => {
    console.log(`product_page_backend listening on port ${PORT}`);
});
```

### sage-server/server.py

```python
import uvloop
import asyncio
import websockets

from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
from fastapi.responses import FileResponse

from call_handling import CallHandler
from db import AsyncSessionLocal
from db.crud import create_call
from utils.settings import settings as env
from utils.logger import setup_logger, make_logger
from utils.cache import get_cache


setup_logger(level="debug")
server_logger = make_logger("server")

GPT_REALTIME_URL = env.GPT_REALTIME_URL
HEADERS = { "Authorization": f"Bearer {env.OPENAI_API_KEY}" }

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

app = FastAPI()


@app.post('/twiml')
async def serve_websocket_endpoint(request: Request) -> FileResponse:
    form, cache = await asyncio.gather(
        request.form(),
        get_cache(),
        return_exceptions=True
    )

    call_sid = form.get("CallSid")
    account_sid = form.get("AccountSid")
    recipient = form.get("To")
    caller = form.get("From")

    async with AsyncSessionLocal() as session:
        await asyncio.gather(
            create_call(session, call_sid, account_sid, recipient, caller),
            cache.set(f"call_{call_sid}", recipient),
            return_exceptions=True
        )

    server_logger.info("/twiml : Sending Back TwiML Instructions")
    return FileResponse(path="./twiml.xml")

@app.websocket('/media')
async def media(twilio_ws: WebSocket):
    server_logger.info("/media : Starting Bidirectional MediaStream")
    await twilio_ws.accept()
    server_logger.debug("Twilio websocket accepted")

    async with websockets.connect(GPT_REALTIME_URL, additional_headers=HEADERS) as openai_ws:
        server_logger.debug("OpenAI websocket connected")

        call_handler = CallHandler(twilio_ws, openai_ws)

        async with asyncio.TaskGroup() as tg:
            tg.create_task(call_handler.audio_in())
            tg.create_task(call_handler.audio_out())


```

### sage-web-service/src/main.tsx

```typescript
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

createRoot(document.getElementById("root")!).render(<App />);

```

### sage-web-service/src/App.tsx

```typescript
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import ChatbotIcon from "./components/ChatbotIcon";
import ProtectedRoute from "./components/ProtectedRoute";
import { AuthProvider } from "./context/AuthContext";
import Home from "./pages/Home";
import Features from "./pages/Features";
import Pricing from "./pages/Pricing";
import About from "./pages/About";
import Contact from "./pages/Contact";
import Demo from "./pages/Demo";
import Signup from "./pages/Signup";
import Signin from "./pages/Signin";
import Settings from "./pages/Settings";
import NotFound from "./pages/NotFound";

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <TooltipProvider>
      <AuthProvider>
        <Toaster />
        <Sonner />
        <BrowserRouter>
          <div className="flex min-h-screen flex-col">
            <Navbar />
            <main className="flex-1">
              <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/features" element={<Features />} />
                <Route path="/demo" element={<Demo />} />
                <Route path="/pricing" element={<Pricing />} />
                <Route path="/signup" element={<Signup />} />
                <Route path="/signin" element={<Signin />} />
                <Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
                <Route path="/about" element={<About />} />
                <Route path="/contact" element={<Contact />} />
                <Route path="*" element={<NotFound />} />
              </Routes>
            </main>
            <Footer />
            <ChatbotIcon />
          </div>
        </BrowserRouter>
      </AuthProvider>
    </TooltipProvider>
  </QueryClientProvider>
);

export default App;

```

### sage-web-service/sage-ai-landing/src/main.tsx

```typescript
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

createRoot(document.getElementById("root")!).render(<App />);

```

### sage-web-service/src/pages/Index.tsx

```typescript
// Update this page (the content is just a fallback if you fail to update the page)

const Index = () => {
  return (
    <div className="flex min-h-screen items-center justify-center bg-background">
      <div className="text-center">
        <h1 className="mb-4 text-4xl font-bold">Welcome to Your Blank App</h1>
        <p className="text-xl text-muted-foreground">Start building your amazing project here!</p>
      </div>
    </div>
  );
};

export default Index;

```

### sage-web-service/sage-ai-landing/src/App.tsx

```typescript
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <TooltipProvider>
      <Toaster />
      <Sonner />
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Index />} />
          {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
          <Route path="*" element={<NotFound />} />
        </Routes>
      </BrowserRouter>
    </TooltipProvider>
  </QueryClientProvider>
);

export default App;

```

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