# Project export: Ducky.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 11.0
- Tagline: An LLM Rubber Ducky. Never worry about being unprepared for a presentation ever again.
- Devpost: https://devpost.com/software/ducky-ai
- GitHub: https://github.com/adit-bala/ducky.ai
- Result: winner (The House Fund: "Cal" Track)
- Team: 3 GitHub contributor(s) — adit-bala (16 commits), Matthew Rowland (14 commits), Saurav Suresh (8 commits)

## Devpost submission (written by the team)

### Inspiration

Sometimes it's hard to find the right person to practice your presentation with. Maybe you're presenting to a grad class about distributed systems, or you're presenting in your anthropology class about a presentation you made at 4am and you have no idea of what you're saying, or maybe you're a startup presenting to an AI accelerator. In all of these situations -- it's quite hard to find someone who's an accurate representation of your audience member, and sometimes the feedback that people can give us doesn't really match what we need for preparation. After all, how can your dog ask you if Paxos is deployed in an asynchronous, partially synchronous, or synchronous model

### What it does

Ducky.AI is a platform for you to upload, present, and persist your presentations. It's very simple. 1) Upload a presentation 2) Upload configurations like what you're presenting about, who you're presenting to, and what kind of tone you want the presentation to be -- is it casual? or is it as serious as talking to a C-level executive

### How we built it

Front-End: Vite, Nginx Back-End: Deno, AWS S3/Lambda, RabbitMQ Databases: Redis, MongoDB Infra, Pulumi (IaC), Docker

### Challenges we ran into

Integration + those pesky bugs that you can only test in a full run through of the pipeline

### Accomplishments we're proud of

A completely working prototype.

### What we learned

too much to write here

### What's next

series A, real-time AI questions, posture and expression analysis

## README (from the GitHub repository)

# **ducky.ai**  
*CalHacks 2024*  

### 🏆 **Top 3 Project** selected by [The House Fund](https://www.thehouse.fund/)

---

## **What is ducky.ai?**  
ducky.ai is an AI-powered platform designed to help you practice presentations with precision feedback. Whether you're:  
- **A PhD student** presenting deep-tech ideas on distributed systems to investors, or  
- **A college student** rushing to finish your slides at 4 AM for a morning presentation  

In all of these situations, it's hard to find someone who accurately represents your audience, and the feedback you get may not always align with your preparation needs. After all, how can your dog ask you if **Paxos** is deployed in an **asynchronous, partially synchronous, or synchronous model**?

**ducky.ai** offers the perfect feedback to prepare you for success.

---

## **What makes ducky.ai different?**  
✨ **Complete Context Understanding:**  
We analyze your entire presentation—including **images, videos, and audio**—from start to finish.

🤖 **Emotion and Confidence Analysis:**  
With **[Hume AI](https://www.hume.ai/)**, we provide insights into your **confidence level** and **perceived emotions** during your presentation.

💡 **Advanced Feedback:**  
Get detailed, actionable feedback through **GPT-4o**, fine-tuned on your specific presentation content.

---

## **Why use ducky.ai?**  
- **Personalized Practice:** Simulates real-world presentation settings tailored to your needs.  
- **Accurate Insights:** Beyond general feedback, ducky.ai captures nuances that typical practice partners miss.  
- **Holistic Support:** Whether you're pitching to an AI accelerator or presenting in class, ducky.ai equips you with feedback you can trust.  

---

Get ready to **present with confidence** and **refine your delivery** with feedback that truly matters!


## Detected evidence (automated analysis)

Indexed codebase: 38 recognized source files, 127 KB.
- CSS (language) — 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
- React (technology) — detected in the code
- Redis (technology) — detected in the code
- TypeScript (language) — detected in the code
- AWS (technology) — claimed on Devpost, not found in the code
- Docker (technology) — claimed on Devpost, not found in the code
- MongoDB (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (69 of 69)

```
.gitignore
docker-compose.yml
infra/__main__.py
infra/.gitignore
infra/create_queues.py
infra/Pulumi.dev.yaml
infra/Pulumi.yaml
infra/requirements.txt
infra/upload_pdf.sh
packages/api/app.ts
packages/api/deno.json
packages/api/deno.lock
packages/api/deps.ts
packages/api/Dockerfile
packages/api/import_map.json
packages/api/models/schema.ts
packages/api/utils.ts
packages/client/.gitignore
packages/client/Dockerfile
packages/client/eslint.config.js
packages/client/index.html
packages/client/package.json
packages/client/README.md
packages/client/src/App.tsx
packages/client/src/app/Landing/index.tsx
packages/client/src/app/Presentation/Feedback/Feedback.module.scss
packages/client/src/app/Presentation/Feedback/index.tsx
packages/client/src/app/Presentation/index.tsx
packages/client/src/app/Presentation/Menu/index.tsx
packages/client/src/app/Presentation/Menu/Menu.module.scss
packages/client/src/app/Presentation/Panel/index.tsx
packages/client/src/app/Presentation/Panel/Panel.module.scss
packages/client/src/app/Presentation/Presentation.module.scss
packages/client/src/app/Presentation/Preview/Audio/Audio.module.scss
packages/client/src/app/Presentation/Preview/Audio/index.tsx
packages/client/src/app/Presentation/Preview/index.tsx
packages/client/src/app/Presentation/Preview/Preview.module.scss
packages/client/src/app/Presentation/Preview/Transcript/index.tsx
packages/client/src/app/Presentation/Preview/Transcript/Transcript.module.scss
packages/client/src/app/Presentation/Preview/Video/index.tsx
packages/client/src/app/Presentation/Preview/Video/Video.module.scss
packages/client/src/app/Presentations/index.tsx
packages/client/src/app/Presentations/Presentations.module.scss
packages/client/src/components/Layout/index.tsx
packages/client/src/components/Layout/Layout.module.scss
packages/client/src/components/NavigationBar/index.tsx
packages/client/src/components/NavigationBar/NavigationBar.module.scss
packages/client/src/lib/api/base.ts
packages/client/src/lib/api/index.ts
packages/client/src/lib/api/presentations.ts
packages/client/src/lib/api/users.ts
packages/client/src/lib/time.ts
packages/client/src/main.tsx
packages/client/src/reset.css
packages/client/src/vite-env.d.ts
packages/client/tsconfig.app.json
packages/client/tsconfig.app.tsbuildinfo
packages/client/tsconfig.json
packages/client/tsconfig.node.json
packages/client/tsconfig.node.tsbuildinfo
packages/client/vite.config.ts
packages/nginx/default.conf
packages/nginx/Dockerfile
packages/workers/Dockerfile
packages/workers/requirements.txt
packages/workers/worker1.py
packages/workers/worker2.py
README.md
workspace.dsl
```

### Dependencies

- infra/requirements.txt: pulumi@>=3.0.0,<4.0.0, pulumi-aws@>=6.0.2,<7.0.0, pulumi-cloudamqp@>=3.0.0,<4.0.0, pulumi-command@>=0.0.1,<1.0.0, pulumi-gcp@>=6.0.0,<7.0.0, python-dotenv, requests
- packages/client/package.json: @eslint/js@^9.11.1, @radix-ui/react-icons@^1.3.0, @radix-ui/themes@^3.1.4, @tanstack/react-query@^5.59.15, @types/dom-speech-recognition@^0.0.4, @types/node@^22.7.5, @types/react@^18.3.10, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.2, classnames@^2.5.1, eslint@^9.11.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.12, globals@^15.9.0, pdfjs-dist@^4.7.76, react@^18.3.1, react-dom@^18.3.1, react-markdown@^9.0.1, react-router-dom@^6.26.2, typescript@^5.5.3, typescript-eslint@^8.7.0, vite@^5.4.8
- packages/workers/requirements.txt: arize-phoenix, deepgram-sdk, hume, openai, openinference-instrumentation-openai, pika, pymongo, python-dotenv, redis

### Recent commits (newest first)

- normalize and scale emotion score
- add feedback
- Update README.md
- feat: Normalize confidence score
- feat: Normalize confidence score
- feat: Feedback
- Merge remote-tracking branch 'refs/remotes/origin/main'
- fix: docker-compose.yml
- attempt at deploying to cloud + fixing feedback display
- Merge pull request #1 from adit-bala/Pheonix
- Merge branch 'main' into Pheonix
- phoenix + redirect to `/presentation`
- adding pheonix
- diagram
- final summary update
- update queues
- Merge remote-tracking branch 'refs/remotes/origin/main'
- fix: Audio and video recording
- small fixed
- changing prompts

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

### docker-compose.yml

```yaml
services:
  nginx:
    build:
      context: ./packages/nginx
      dockerfile: Dockerfile
    depends_on:
      - api
      - client
    networks:
      - app-network
    ports:
      - 8080:8080

  client:
    build:
      context: ./packages/client
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    networks:
      - app-network

  api:
    build:
      context: ./packages/api
      dockerfile: Dockerfile
    ports:
      - 3001:3001
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - MONGO_URI=${MONGO_URI}
      - MONGO_DB=${MONGO_DB}
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_REGION=${AWS_REGION}
      - S3_BUCKET_NAME=${S3_BUCKET_NAME}
      - S3_BUCKET_WEBSITE_ENDPOINT=${S3_BUCKET_WEBSITE_ENDPOINT}
      - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
      - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
      - GOOGLE_REDIRECT_URI=${GOOGLE_REDIRECT_URI}
      - S3_BUCKET_WEBSITE_ENDPOINT=${S3_BUCKET_WEBSITE_ENDPOINT}
    networks:
      - app-network

  mongodb:
    image: mongo:4.4
    ports:
      - 27018:27017
    volumes:
      - mongodb_data:/data/db
    networks:
      - app-network
    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/test --quiet
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:6.0-alpine
    ports:
      - 6379:6379
    command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
    volumes:
      - redis_data:/data
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  worker1:
    build:
      context: ./packages/workers
      dockerfile: Dockerfile
    command: ["python", "worker1.py"]
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - MONGO_URI=${MONGO_URI}
      - MONGO_DB=${MONGO_DB}
      - REDIS_HOST=${REDIS_HOST}
      - REDIS_PORT=${REDIS_PORT}
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - RABBITMQ_URI=${RABBITMQ_URI}
      - FIRST_QUEUE=${FIRST_QUEUE}
      - SECOND_QUEUE=${SECOND_QUEUE}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - OPENAI_ORGANIZATION=${OPENAI_ORGANIZATION}
      - OPENAI_PROJECT=${OPENAI_PROJECT}
      - DEEPGRAM_API_KEY=${DEEPGRAM_API_KEY}
      - HUME_API_KEY=${HUME_API_KEY}
      - ARIZE_API_KEY=${ARIZE_API_KEY}
    networks:
      - app-network

  worker2:
    build:
      context: ./packages/workers
      dockerfile: Dockerfile
    command: ["python", "worker2.py"]
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - MONGO_URI=${MONGO_URI}
      - MONGO_DB=${MONGO_DB}
      - REDIS_HOST=${REDIS_HOST}
      - REDIS_PORT=${REDIS_PORT}
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - RABBITMQ_URI=${RABBITMQ_URI}
      - SECOND_QUEUE=${SECOND_QUEUE}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - OPENAI_ORGANIZATION=${OPENAI_ORGANIZATION}
      - OPENAI_PROJECT=${OPENAI_PROJECT}
      - ASSISTANT_ID=${ASSISTANT_ID}
    networks:
      - app-network

networks:
  app-network:

volumes:
  mongodb_data:
  redis_data:
```

### infra/requirements.txt

```
pulumi>=3.0.0,<4.0.0
pulumi-aws>=6.0.2,<7.0.0
pulumi-cloudamqp>=3.0.0,<4.0.0
pulumi-command>=0.0.1,<1.0.0
pulumi-gcp>=6.0.0,<7.0.0
python-dotenv
requests
```

### packages/nginx/Dockerfile

```
FROM nginx:1.21
COPY default.conf /etc/nginx/conf.d/default.conf
```

### packages/workers/requirements.txt

```
pika
python-dotenv
redis
hume
openai
pymongo
deepgram-sdk
arize-phoenix
openinference-instrumentation-openai

```

### packages/client/Dockerfile

```
FROM node:alpine

WORKDIR /app

COPY package.json .

RUN npm install

RUN npm install -g serve

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["serve", "-s", "dist"]


```

### packages/workers/Dockerfile

```
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Copy requirements file
COPY requirements.txt .

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

# Copy the application code
COPY worker1.py worker2.py ./

# Set environment variables
ENV PYTHONUNBUFFERED=1

# Default command (will be overridden in docker-compose)
CMD ["python", "worker1.py"]
```

### packages/api/Dockerfile

```
# Use the official Deno image
FROM denoland/deno:latest

# Set working directory
WORKDIR /app

# Copy necessary files
COPY deno.json .
COPY import_map.json .
COPY deps.ts .

# Cache dependencies
RUN deno cache -c deno.json deps.ts

# Copy the rest of the application code
COPY . .

# Expose the application port (adjust if different)
EXPOSE 8000

# Run the application
CMD ["run", "--allow-net", "--allow-read", "--allow-env", "--allow-sys", "--unstable", "--unstable-kv", "--config=deno.json", "app.ts"]
```

### packages/client/package.json

```
{
  "name": "ch-fa-24",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@radix-ui/react-icons": "^1.3.0",
    "@radix-ui/themes": "^3.1.4",
    "@tanstack/react-query": "^5.59.15",
    "classnames": "^2.5.1",
    "pdfjs-dist": "^4.7.76",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-markdown": "^9.0.1",
    "react-router-dom": "^6.26.2"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@types/dom-speech-recognition": "^0.0.4",
    "@types/node": "^22.7.5",
    "@types/react": "^18.3.10",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.2",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.8"
  }
}

```

### packages/client/src/main.tsx

```typescript
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./reset.css";
import "@radix-ui/themes/styles.css";

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

```

### packages/client/src/App.tsx

```typescript
import { Theme } from "@radix-ui/themes";
import {
  RouterProvider,
  createBrowserRouter,
  redirect,
} from "react-router-dom";
import Landing from "@/app/Landing";
import Presentations from "@/app/Presentations";
import Presentation from "@/app/Presentation";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import Layout from "@/components/Layout";

const router = createBrowserRouter([
  {
    element: <Layout />,
    children: [
      {
        index: true,
        element: <Landing />,
      },
      {
        path: "presentations",
        element: <Presentations />,
      },
      {
        path: "presentations/:id",
        element: <Presentation />,
      },
      {
        path: "*",
        loader: () => redirect("/"),
      },
    ],
  },
]);

const client = new QueryClient({
  defaultOptions: {
    queries: {
      retry: false,
    },
  },
});

function App() {
  return (
    <QueryClientProvider client={client}>
      <Theme>
        <RouterProvider router={router} />
      </Theme>
    </QueryClientProvider>
  );
}

export default App;

```

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