# Project export: YouLearnTube

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: OpenAI Build Week
- Tagline: YouLearnTube turns scattered YouTube tutorials into one guided course, takes inspiration from platforms like Udemy, Coursera and provides user the premium experience with playlist that millions watch.
- Devpost: https://devpost.com/software/youlearntube
- GitHub: https://github.com/Akshat2734/Adaptive-Learning-Platform-for-YouTube-Videos
- Demo: https://adaptive-learning-platform-for-you.vercel.app/
- Video: https://www.youtube.com/embed/NHmYTc0ZFvE?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Akshat2734 (5 commits)

## Devpost submission (written by the team)

### Inspiration

Learning on YouTube is one of the most accessible ways to gain technical skills, but it is also one of the most fragmented. Learners often spend hours searching for quality playlists leading to tutorial hell, encounter repeated content across multiple creators, struggle to track their progress, and have no structured way to review or test what they have learned. While AI chatbots can answer questions about videos, they are not designed around the learning process. They can easily reveal concepts from future lessons, break the intended progression of a course, and rarely provide an experience similar to a structured educational platform. We wanted to transform YouTube from a collection of independent videos into an adaptive learning platform that provides a premium experience just like Udemy, Coursera etc. Instead of simply adding AI on top of YouTube, our goal was to build an experience that understands what a learner has already watched, generates learning resources only from that material, and guides them through a personalized learning journey. This led to YouLearnTube an AI-powered learning workspace that automatically merges playlists into a single course, removes duplicate content, generates AI enhanced tutoring, mind maps, quizzes, flashcards, and adaptive recommendations, allowing anyone to learn from YouTube as if they were taking a professionally designed online course.

### What it does

YouLearnTube turns scattered YouTube tutorials into one guided course. A learner writes a goal in plain language, selects recommended playlists, which then turns them into a structured video path, and receives AI assistance that is based only in the material they have already watched thus avoiding questions or explanations that introduces concept that learner don't understand. The goal is to make free video learning feel like a focused learning product: a course with a sequence, watched-time awareness, source-linked explanations, progressive concepts, easing learners to note taking, checks for understanding, and a recommendation for what to do next.

### How we built it

Codex was used as a build partner from planning through the final pitch. Its role was not limited to producing code. We continuously moved between product design, implementation, debugging, verification, documentation, and presentation polish. We decided to take divide the project in 7 days roadmap with the help of codex, where day 1-2 was used by us to generate a roadmap containing functions that helped us wrote the backend and frontend code and ensured that the code is disjointed. We asked codex to fix the code base using gpt 5.6 luna as planner and gpt 5.6 terra as editor. Day 3-4 was used to implement the ai tutor and other features, luna helped us by recommending direct and Socratic modes which was implemented by terra, here in order to check the code quality we did a hour to hour roadmap where each hour had 7 tasks, we saw that the code quality remains same even when doing hour to hour as when doing task to task, but saw a huge substantial token consumption when doing hour to hour. Day 5-6 was used to sprint run the features by just asking the features and codex implementing it, while bugs were nonexistent in the code throughout, we saw fewer extra details added and measured huge amount of time implementing a feature with us having to add smaller details that made the overall time spend much higher. We also used codex to generate demo video using screenshot video taken by us, generate docs etc. Most of the features implemented moved from being isolated to being boxes together to form the perfect union between wow-factor and useful cases.

### Challenges we ran into

-Bugs in Codex -> One common issue was steering the conversation with our prompt where once it was thinking, when we wrote our idea to steer it and clicked steer the idea was removed. This made us write the whole conversation from scratch. -Repeated Generation -> Sometimes, a statement was repeated twice before abruptly stopping and us needing to start it again. -GPT 5.6 -> While it was great at introducing higher level designs the low-level designs that is necessary to improve user experience for the feature we were talking about was missing, this led to repeated conversations about adding a button, removing X adding Y. -Missing Information regarding third party providers -> Luna/Terra both sometimes gave information about third party Api that was wrong with the best example being them sometimes telling that YouTube-transcript-retrieval works on google cloud but after deploying it I found that was not true leading me to look at other alternatives and changing a segment of code.

### Accomplishments we're proud of

Built an end-to-end AI learning platform that transforms scattered YouTube playlists into a structured, adaptive course instead of simply adding a chatbot on top of videos. Built an end-to-end AI learning platform that transforms scattered YouTube playlists into a structured, adaptive course instead of simply adding a chatbot on top of videos. Designed a spoiler-safe retrieval system where the backend enforces learning boundaries, ensuring every tutor response, quiz, flashcard, and mind map is generated only from content the learner has already watched. Designed a spoiler-safe retrieval system where the backend enforces learning boundaries, ensuring every tutor response, quiz, flashcard, and mind map is generated only from content the learner has already watched. Implemented course formation using embeddings and similarity, automatically merging multiple playlists into a single high-quality learning path by removing similar videos and hosting it using local embedding model instead of paid model. Implemented course formation using embeddings and similarity, automatically merging multiple playlists into a single high-quality learning path by removing similar videos and hosting it using local embedding model instead of paid model. Developed lazy transcript ingestion that processes only the active lesson, significantly reducing startup latency and API costs while keeping the learning experience responsive. This was done by creating chunks of transcript. Developed lazy transcript ingestion that processes only the active lesson, significantly reducing startup latency and API costs while keeping the learning experience responsive. This was done by creating chunks of transcript. Created a shared instructional-content filtering pipeline (basically a prompt) that removes introductions, sponsorships, and other non-learning content before generating quizzes, flashcards, mind maps, and tutor responses. Created a shared instructional-content filtering pipeline (basically a prompt) that removes introductions, sponsorships, and other non-learning content before generating quizzes, flashcards, mind maps, and tutor responses. Built an explainable adaptive learning engine (pretty proud of) that combines quiz performance, concept understanding, tutor feedback, watch history, and focus sessions to recommend the learner's next step. It changes after every input from the user. Built an explainable adaptive learning engine (pretty proud of) that combines quiz performance, concept understanding, tutor feedback, watch history, and focus sessions to recommend the learner's next step. It changes after every input from the user. Designed the backend with clear service boundaries, separating language models from business logic, external APIs, retrieval, embeddings, and application state for improved reliability and maintainability. Designed the backend with clear service boundaries, separating language models from business logic, external APIs, retrieval, embeddings, and application state for improved reliability and maintainability. Added deterministic mock providers for language models, embeddings, transcripts, and YouTube discovery, allowing the complete application to be demonstrated without external API credits. Used that in order to create a mock frontend where every ui change was seen and brought to main of it looked good. Added deterministic mock providers for language models, embeddings, transcripts, and YouTube discovery, allowing the complete application to be demonstrated without external API credits. Used that in order to create a mock frontend where every ui change was seen and brought to main of it looked good. Delivered a deployable full-stack application using React, FastAPI, ChromaDB, and Cloud Run architecture, supported by comprehensive documentation, deployment guides, and a presentation-ready demo workflow. Delivered a deployable full-stack application using React, FastAPI, ChromaDB, and Cloud Run architecture, supported by comprehensive documentation, deployment guides, and a presentation-ready demo workflow.

### What we learned

Building YouLearnTube taught us that creating a great AI product is much more than integrating language models. We learned that AI performs best when it is given a clearly defined responsibility We also learned that the quality of an AI learning experience depends heavily on retrieval and context. Features such as spoiler-safe retrieval, filtering, transcript ingestion, and playlist similarity had a greater impact on the learner experience than simply using a more capable language model. Throughout development, Codex became much more than a code-generation tool. It acted as an engineering partner across the entire development lifecycle helping us refine the product vision, review architecture, implement backend services, debug complex issues, improve the frontend experience, optimize deployment, and produce comprehensive technical documentation. Codex helped us reason about system design, evaluate trade-offs, and iterate quickly while keeping the codebase organized. Most importantly, we learned that AI-assisted software development is not about replacing engineering decisions. It is about accelerating them. By combining Codex with careful architectural design and human review, we were able to build a significantly more polished, maintainable, and production-ready application within the limited timeframe of a hackathon.

### What's next

authentication and per-user/course authorisation; a shared database for course, progression, quiz, map, feedback, and focus state; Had a pretty great experience with the discord community and stressing about managing credits as well as making it a 0 dollar build where I spend nothing on credit for anything.

## README (from the GitHub repository)

# YouLearnTube

> Turn a learning goal and selected YouTube playlists into a spoiler-safe, adaptive study workspace.

YouLearnTube turns scattered YouTube tutorials into one guided course. A learner writes a goal in plain language, selects recommended playlists, which then turns them into a structured video path, and receives AI assistance that is based only in the material they have already watched thus avoiding questions or explanations that introduces concept that learner don't understand.

The goal is not to add a chat box on top of YouTube which can already be done by using 'ask question' option. The goal is to make free video learning feel like a focused learning product: a course with a sequence, watched-time awareness, source-linked explanations, progressive concepts, easing learners to note taking, checks for understanding, and a recommendation for what to do next.

## Contents

- [What the learner experiences](#what-the-learner-experiences)
- [Why YouLearnTube is different](#why-youlearntube-is-different)
- [End-to-end architecture](#end-to-end-architecture)
- [Spoiler-safe learning boundary](#spoiler-safe-learning-boundary)
- [Learning loop and adaptive path](#learning-loop-and-adaptive-path)
- [AI, transcript, and embedding design](#ai-transcript-and-embedding-design)
- [Frontend experience](#frontend-experience)
- [Repository map](#repository-map)
- [API surface](#api-surface)
- [Run locally](#run-locally)
- [Providers, mock mode, and cost control](#providers-mock-mode-and-cost-control)
- [Deployment profile](#deployment-profile)
- [How Codex helped build YouLearnTube](#how-codex-helped-build-youlearntube)
- [Demo flow](#demo-flow)
- [Current boundaries and next steps](#current-boundaries-and-next-steps)

## What the learner experiences

1. **Describe a learning goal.** A learner can write a request such as `Learn Redis caching, but skip the basics.` The model is used only to extract structured intent such as topic, level, exclusions, and search queries.
2. **Choose source playlists.** The backend, not the model, makes the YouTube Data API calls. The learner sees ranked playlist choices and selects the ones that they prefer in the course.
3. **Receive one clean course.** The selected playlists are merged, video metadata is normalised, exact and semantic duplicates are removed deterministically, and the learner gets one ordered syllabus with total, watched, and remaining duration avoiding users to go through a the introductions and realizing that the topic is same as the previous viewed video.
4. **Start watching immediately.** The active YouTube video is usable while its transcript is requested, timestamped, chunked, embedded, and indexed in the background. The app does not make the learner wait for every course transcript before opening the player. This allows faster execution thanks to only sending some part of whole transcript to be processed.
5. **Learn only from watched material.** The tutor, mind map, flashcards, quiz, and adaptive recommendation respect the learner's server-side watch position. Future lesson evidence is excluded at retrieval time rather than merely hidden in the browser. Mind-Map is used to allow users to see the important concepts and how they connect with one another in the video, flashcards helps by finding the concept and allowing user to get them as notes form.
6. **Understand concepts, not creator metadata.** A shared instructional-content filter removes greetings, channel introductions, sponsor reads, calls to subscribe, and similar low-value material before maps, quizzes, and cards are generated.
7. **Reflect and continue.** After an eligible lesson, the learner may attempt or explicitly skip its learning check. Every fifth lesson becomes a recap checkpoint. Concept understanding, quiz results, tutor feedback, and focus behavior feed an explainable next recommendation.

### The product journey

```mermaid
flowchart LR
    A["Learner writes a goal"] --> B["Intent extraction<br/>(topic, level, exclusions, search queries)"]
    B --> C["FastAPI validates the contract"]
    C --> D["YouTube Data API<br/>playlist search and ranking"]
    D --> E["Learner selects playlists"]
    E --> F["Playlist merge + metadata enrichment"]
    F --> G["Deterministic exact and semantic deduplication"]
    G --> H["Temporary course session<br/>ordered video syllabus"]
    H --> I["React learning workspace"]
    I --> J["Watch, ask, map, review, and adapt"]

    classDef learner fill:#ede9fe,stroke:#7c3aed,color:#312e81
    classDef backend fill:#e0f2fe,stroke:#0284c7,color:#0c4a6e
    classDef service fill:#ecfdf5,stroke:#059669,color:#064e3b
    class A,E,I,J learner
    class B,C,F,G,H backend
    class D service
```

## Why YouLearnTube is different

| Design choice | What it means in practice | Why it matters |
| --- | --- | --- |
| **Backend-owned discovery** | The model returns a validated intent object. FastAPI calls YouTube and decides how results are ranked. | A language model cannot make uncontrolled YouTube requests or invent playlist results. |
| **Deterministic deduplication** | Embeddings represent `title + description`; cosine similarity finds likely duplicates; quality metrics select the retained video. | Similarity is measurable and reproducible. The LLM is never asked to guess whether two videos are duplicates. |
| **Lazy transcript ingestion** | Only the active lesson is transcribed and indexed when it is needed. | The player remains responsive, cost is controlled, and transcript failures affect one lesson rather than an entire course. |
| **Server-enforced spoiler safety** | The server clamps the client timestamp to saved progress and retrieves only chunks ending before that safe position. | Changing a browser value cannot reveal future transcript evidence or future map nodes. |
| **Topic-first generation** | Shared filtering selects substantive teaching chunks before map, quiz, and flashcard generation. | Learners study React, Redis, caching, or another actual topic - not a creator's intro or channel promotion. |
| **Explainable adaptation** | The recommendation is based on visible concept states, quizzes, tutor feedback, and focus sessions. | The app can say whether the next action is to review, continue, retry a weak concept, or take a break. |
| **Provider independence** | Generation and embedding providers are configured separately and have deterministic mock paths. | The project can demo without credits, switch providers, or run local embeddings without changing product behavior. |

## End-to-end architecture

### System overview

```mermaid
flowchart TB
    UI["React + Vite workspace"]
    API["FastAPI API<br/>validation, policy, orchestration"]
    YouTube["YouTube Data API v3"]
    Captions["youtube-transcript-api<br/>or Supadata native captions"]
    Providers["OpenAI / Gemini / Anthropic<br/>compatible local endpoint / mock"]
    Embeddings["OpenAI / Gemini / FastEmbed\nor deterministic mock"]
    Store["Temporary course JSON store"]
    Chroma["ChromaDB<br/>timestamped transcript chunks"]

    UI -->|"goal, playlist selection, progress, questions"| API
    API --> YouTube
    API --> Captions
    API --> Providers
    API --> Embeddings
    API <--> Store
    API <--> Chroma
    Captions --> API
    Embeddings --> Chroma
    Chroma --> API
    API -->|"courses, evidence, maps, quizzes, cards, recommendations"| UI

    classDef app fill:#ede9fe,stroke:#7c3aed,color:#312e81
    classDef backend fill:#e0f2fe,stroke:#0284c7,color:#0c4a6e
    classDef external fill:#fff7ed,stroke:#ea580c,color:#7c2d12
    classDef data fill:#ecfdf5,stroke:#059669,color:#064e3b
    class UI app
    class API backend
    class YouTube,Captions,Providers,Embeddings external
    class Store,Chroma data
```

### Discovery and course creation

The discovery model has a deliberately narrow responsibility. It turns natural language into a typed shape, for example:

```json
{
  "topic": "Redis caching",
  "level": "intermedi

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 99 recognized source files, 647 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
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Docker (technology) — claimed on Devpost, not found in the code
- Vercel (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (111 of 111)

```
.gitignore
.vscode/settings.json
backend/.dockerignore
backend/.env.example
backend/.gitignore
backend/app/config.py
backend/app/dependencies.py
backend/app/main.py
backend/app/mock/__init__.py
backend/app/mock/mock_data_service.py
backend/app/mock/README.md
backend/app/models/adaptive_learning.py
backend/app/models/flashcard.py
backend/app/models/mindmap.py
backend/app/models/progression.py
backend/app/models/tutor.py
backend/app/routers/adaptive_learning.py
backend/app/routers/diagnostics.py
backend/app/routers/discovery.py
backend/app/routers/flashcards.py
backend/app/routers/health.py
backend/app/routers/ingestion.py
backend/app/routers/mindmap.py
backend/app/routers/presentation_demo.py
backend/app/routers/progression.py
backend/app/routers/quiz.py
backend/app/routers/tutor.py
backend/app/schemas.py
backend/app/services/adaptive_learning_service.py
backend/app/services/chroma_service.py
backend/app/services/chunking_service.py
backend/app/services/course_store.py
backend/app/services/deduplication_service.py
backend/app/services/embedding_service.py
backend/app/services/english_output_service.py
backend/app/services/flashcard_context_service.py
backend/app/services/flashcard_generation_service.py
backend/app/services/gemini_service.py
backend/app/services/ingestion_service.py
backend/app/services/instructional_content_service.py
backend/app/services/mindmap_generation_service.py
backend/app/services/mindmap_service.py
backend/app/services/openai_service.py
backend/app/services/playlist_ingestion_service.py
backend/app/services/presentation_demo_service.py
backend/app/services/progression_service.py
backend/app/services/quality_service.py
backend/app/services/quiz_context_service.py
backend/app/services/quiz_generation_service.py
backend/app/services/similarity_service.py
backend/app/services/transcript_service.py
backend/app/services/tutor_context_service.py
backend/app/services/tutor_feedback_service.py
backend/app/services/tutor_generation_service.py
backend/app/services/video_metadata_service.py
backend/app/services/video_transcript_service.py
backend/app/services/youtube_service.py
backend/Dockerfile
backend/requirements.txt
DEPLOYMENT.md
frontend/.env
frontend/.env.example
frontend/.env.mock
frontend/.gitignore
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/README.md
frontend/src/App.css
frontend/src/App.jsx
frontend/src/components/AppErrorBoundary.jsx
frontend/src/components/AppHeader.jsx
frontend/src/components/DemoControls.jsx
frontend/src/components/FeatureGuide.jsx
frontend/src/components/FinishVideoModal.jsx
frontend/src/components/FlashcardWorkspace.jsx
frontend/src/components/FocusBreakModal.jsx
frontend/src/components/FocusTimerControl.jsx
frontend/src/components/LearningDashboard.jsx
frontend/src/components/LearningPathCard.jsx
frontend/src/components/MindMapWorkspace.jsx
frontend/src/components/PlayerControls.jsx
frontend/src/components/PlaylistCard.jsx
frontend/src/components/PlaylistGrid.jsx
frontend/src/components/ProjectTourModal.jsx
frontend/src/components/QuizWorkspace.jsx
frontend/src/components/SearchBox.jsx
frontend/src/components/SkipLessonModal.jsx
frontend/src/components/TutorEvidenceReceipt.jsx
frontend/src/components/TutorWorkspace.jsx
frontend/src/components/VideoSyllabus.jsx
frontend/src/components/YouTubePlayer.jsx
frontend/src/hooks/useAdaptiveLearning.js
frontend/src/hooks/useConceptUnderstanding.js
frontend/src/hooks/useCourseProgression.js
frontend/src/hooks/useFocusSession.js
frontend/src/hooks/useLearningPath.js
frontend/src/hooks/useVideoTranscript.js
frontend/src/hooks/useWatchedTime.js
frontend/src/index.css
frontend/src/main.jsx
frontend/src/mock/mockApi.js
frontend/src/mock/MockVideoPlayer.jsx
frontend/src/mock/README.md
frontend/src/services/api.js
frontend/src/styles/learning-workspace.css
frontend/src/utils/formatters.js
frontend/vite.config.js
PITCH.md
PROJECT_CODE_GUIDE.md
README.md
```

### Dependencies

- backend/requirements.txt: chromadb, fastapi, fastembed@==0.8.0, google-api-python-client, httpx, isodate, numpy, openai, pydantic, pydantic-settings, python-dotenv, requests, tenacity, uvicorn, youtube-transcript-api
- frontend/package.json: @eslint/js@^10.0.1, @tailwindcss/vite@^4.3.2, @types/react@^19.2.17, @types/react-dom@^19.2.3, @vitejs/plugin-react@^6.0.3, @xyflow/react@^12.11.2, axios@^1.18.1, eslint@^10.6.0, eslint-plugin-react-hooks@^7.1.1, eslint-plugin-react-refresh@^0.5.3, globals@^17.7.0, lucide-react@^1.24.0, react@^19.2.7, react-dom@^19.2.7, tailwindcss@^4.3.2, vite@^8.1.1

### Recent commits (newest first)

- Merge pull request #2 from Akshat2734/finalupdate
- Final
- Merge pull request #1 from Akshat2734/mvp
- MVP
- first commit

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

### DEPLOYMENT.md

```markdown
# Deployment guide

## What can be deployed now

Deploy the React frontend as a static site and `backend/Dockerfile` as one Cloud Run service. This is an **anonymous, temporary-session deployment**:

- a learner can create and use a course while the Cloud Run instance is alive;
- course JSON, Chroma vectors, maps, cards, quizzes, and adaptive progress live in the container’s writable `/tmp` filesystem;
- Cloud Run can stop an instance at any time, which removes that temporary state;
- the Docker image expires inactive courses after four hours and keeps at most eight active courses on a warm instance;
- run **one instance only** (`max instances = 1`) because the current stores are local to an instance.

Cloud Run is appropriate because it runs the Docker image and FastEmbed model. It is not a persistent disk or a database: Cloud Run’s writable filesystem is an in-memory overlay that disappears when the container stops. [Cloud Run runtime contract](https://cloud.google.com/run/docs/overview/what-is-cloud-run)

## 1. Deploy the backend to Cloud Run

Build from the `backend/` directory so Cloud Run uses the provided Dockerfile. Configure these service variables:

```env
ENVIRONMENT=production
FRONTEND_ORIGIN=https://your-frontend.example.com
MOCK_MODE=false
LLM_PROVIDER=auto
EMBEDDING_PROVIDER=local
ENABLE_DIAGNOSTICS=false
ENABLE_PRESENTATION_DEMO=false
```

Then add only the API keys/providers you actually use, such as `YOUTUBE_API_KEY`, `GEMINI_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `SUPADATA_API_KEY`. Keep keys in Cloud Run service secrets or environment configuration, never in the Vite frontend build.

The Docker image already configures these Cloud Run-safe defaults:

```env
COURSE_STORE_PATH=/tmp/youlearn-tube/courses.json
CHROMA_PERSIST_DIRECTORY=/tmp/youlearn-tube/chroma
COURSE_SESSION_TTL_SECONDS=14400
MAX_ACTIVE_COURSES=8
LOCAL_EMBEDDING_CACHE_DIR=/opt/embedding-models
```

Set **max instances to 1**. Do not configure a persistent `/data` disk: standard Cloud Run has none. Do not use a Cloud Storage FUSE mount for Chroma’s SQLite-backed data either; it is object storage, is not fully POSIX compliant, and does not provide file locking for competing writes. [Cloud Storage volume limitations](https://cloud.google.com/run/docs/configuring/services/cloud-storage-volume-mounts)

Allocate at least 1 GiB memory if using `EMBEDDING_PROVIDER=local`. The FastEmbed model is baked into the image, avoiding a model download during a learner request.

After deployment, open `https://your-api.example.com/health`. A healthy anonymous Cloud Run service reports `"course_storage": "ephemeral"`.

## 2. Deploy the frontend

Build the Vite application with the public Cloud Run URL:

```env
VITE_API_BASE_URL=https://your-api.example.com
VITE_API_MODE=live
VITE_ENABLE_PRESENTATION_DEMO=false
```

Deploy `frontend/dist` to Vercel or another static host. `VITE_API_BASE_URL` is compiled into the frontend at build time, so rebuild when the backend URL chan
[truncated — 2733 more characters]
```

### PITCH.md

```markdown
# YouLearnTube - three-minute pitch and Codex build story

## Goal

Use the first minute to prove the learner experience. Use the final two minutes to explain how GPT-5.6 through Codex helped turn a broad hackathon idea into a working, resilient application - from architecture to the smallest interaction details.

For a reliable recording, use `MOCK_MODE=true` or a private deployment with the presentation-demo flags enabled. The **Demo** button is there only to stage a completed active lesson quickly during the pitch.

## Before recording

- Run FastAPI on port `8000` and Vite on `http://localhost:5173`, or open the deployed pair.
- Start a fresh course and leave the first lesson active.
- Enable the presentation control only for the pitch if you do not want to watch an entire lesson.
- Keep the browser at a readable desktop width.
- Keep the editor or repository visible in a second window for the Codex section.

## Timed script

### 0:00-0:15 - The problem

**Say:** "YouTube has great courses, but learning from it is fragmented. I have to choose videos, remember where I stopped, avoid duplicate lessons, and an AI tutor can easily spoil what comes next."

**Show:** The discovery screen and the learning-goal input.

### 0:15-0:32 - The product flow

**Say:** "YouLearnTube turns a plain-language goal into playlist choices. The backend validates the intent, searches YouTube, merges selected playlists, removes duplicates, and creates one structured course with real-time tracking."

**Show:** Search for `Learn Redis caching but skip basics`, select playlists, then open the course syllabus and watched/remaining time.

### 0:32-0:48 - The judge-facing feature

**Say:** "As I watch, only the current lesson transcript is indexed and a mind map is formed for better understanding. Concepts unlock progressively on the map, and the tutor can answer from watched material with source timestamps, directly or by guiding the student to find the answer. Future content is not simply hidden - it is excluded by the backend."

**Show:** Player -> Map -> one unlocked node -> Tutor answer -> evidence receipt/source jump.

### 0:48-1:00 - The learning loop

**Say:** "After a lesson, I can take or skip a learning check, review concept-focused flashcards, and get an explainable adaptive recommendation. The Demo control lets me reveal this full loop in a pitch without pretending a judge watched an entire video."

**Show:** **Demo -> Prepare full lesson & open quiz**, then briefly point to Cards, the Adaptive Learning card, and the focus timer.

---

## How GPT-5.6 and Codex brought the vision to life

### 1:00-1:20 - From vague idea to buildable architecture

**Say:** "The original idea was ambitious: playlists, transcripts, RAG, maps, quizzes, flashcards, adaptive learning, and a polished frontend. I used GPT-5.6 through Codex as a build partner to turn that into a realistic day-by-day, hour-by-hour roadmap."

**Show:** This repository's README roadmap/code guide, or the Fa
[truncated — 4594 more characters]
```

### backend/requirements.txt

```
fastapi
uvicorn
openai
httpx
pydantic
pydantic-settings
python-dotenv
requests
google-api-python-client
youtube-transcript-api
chromadb
fastembed==0.8.0
numpy
tenacity
isodate

```

### frontend/package.json

```
{
  "name": "temp",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "dev:mock": "vite --mode mock",
    "build": "vite build",
    "build:mock": "vite build --mode mock",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@xyflow/react": "^12.11.2",
    "axios": "^1.18.1",
    "lucide-react": "^1.24.0",
    "react": "^19.2.7",
    "react-dom": "^19.2.7"
  },
  "devDependencies": {
    "@eslint/js": "^10.0.1",
    "@tailwindcss/vite": "^4.3.2",
    "@types/react": "^19.2.17",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^6.0.3",
    "eslint": "^10.6.0",
    "eslint-plugin-react-hooks": "^7.1.1",
    "eslint-plugin-react-refresh": "^0.5.3",
    "globals": "^17.7.0",
    "tailwindcss": "^4.3.2",
    "vite": "^8.1.1"
  }
}

```

### backend/Dockerfile

```
FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    COURSE_STORE_PATH=/tmp/youlearn-tube/courses.json \
    CHROMA_PERSIST_DIRECTORY=/tmp/youlearn-tube/chroma \
    COURSE_SESSION_TTL_SECONDS=14400 \
    MAX_ACTIVE_COURSES=8 \
    LOCAL_EMBEDDING_CACHE_DIR=/opt/embedding-models

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Bake the default multilingual ONNX model into the image. Cloud Run then
# loads it locally on cold start instead of downloading it during a learner's
# request. A different LOCAL_EMBEDDING_MODEL can still download at runtime.
RUN python -c "from fastembed import TextEmbedding; TextEmbedding(model_name='sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2', cache_dir='/opt/embedding-models')"

RUN addgroup --system app && adduser --system --ingroup app app
COPY --chown=app:app app ./app
RUN mkdir -p /tmp/youlearn-tube /opt/embedding-models && chown -R app:app /app /tmp/youlearn-tube /opt/embedding-models

EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"

USER app

CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-8000} --proxy-headers"]

```

### frontend/src/main.jsx

```javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import './styles/learning-workspace.css'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

```

### backend/app/main.py

```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.config import settings
from app.routers.health import router as health_router
from app.routers.discovery import router as discovery_router
from app.routers.diagnostics import router as diagnostics_router
from app.routers.ingestion import router as ingestion_router
from app.routers.mindmap import router as mindmap_router
from app.routers.tutor import router as tutor_router
from app.routers.adaptive_learning import router as adaptive_learning_router
from app.routers.presentation_demo import router as presentation_demo_router
from app.routers import progression
from app.routers import quiz
from app.routers import flashcards

app = FastAPI(
    title="AI Tutor API",
    version="1.0.0"
)

allowed_origins = {
    *(origin.strip() for origin in settings.FRONTEND_ORIGIN.split(",") if origin.strip()),
}
if settings.ENVIRONMENT == "development":
    allowed_origins.update({
        "http://localhost:5173",
        "http://127.0.0.1:5173",
    })

app.add_middleware(
    CORSMiddleware,
    allow_origins=sorted(allowed_origins),
    # The anonymous app uses neither cookies nor browser credentials. Keeping
    # this false avoids advertising credentialed cross-origin access.
    allow_credentials=False,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(health_router)
app.include_router(discovery_router)
if settings.ENVIRONMENT != "production" or settings.ENABLE_DIAGNOSTICS:
    app.include_router(diagnostics_router)
app.include_router(ingestion_router)
app.include_router(mindmap_router)
app.include_router(adaptive_learning_router)
app.include_router(presentation_demo_router)
app.include_router(tutor_router)
app.include_router(progression.router)
app.include_router(quiz.router)
app.include_router(flashcards.router)

```

### frontend/src/App.jsx

```javascript
import { lazy, Suspense, useEffect, useState } from 'react'
import { AlertCircle, ArrowRight, BookOpen, CircleHelp, Loader2, Sparkles } from 'lucide-react'

import AppErrorBoundary from './components/AppErrorBoundary'
import PlaylistGrid from './components/PlaylistGrid'
import ProjectTourModal from './components/ProjectTourModal'
import SearchBox from './components/SearchBox'
import { discoverPlaylists, ingestPlaylists, isFrontendMockMode } from './services/api'

const ACTIVE_COURSE_STORAGE_KEY = isFrontendMockMode
  ? 'studysync-frontend-mock-active-course'
  : 'studysync-active-course'
const LearningDashboard = lazy(() => import('./components/LearningDashboard'))

function WorkspaceLoading() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-slate-50 p-6 text-center text-slate-800">
      <div className="max-w-sm rounded-2xl border border-slate-200 bg-white p-8 shadow-sm">
        <Loader2 className="mx-auto h-6 w-6 animate-spin text-indigo-600" />
        <p className="mt-4 text-sm font-bold">Opening your study workspace</p>
        <p className="mt-2 text-xs font-medium leading-relaxed text-slate-500">Your saved course and progress stay available while the learning tools load.</p>
      </div>
    </div>
  )
}

function loadSavedCourse() {
  try {
    const saved = window.localStorage.getItem(ACTIVE_COURSE_STORAGE_KEY)
    const course = saved ? JSON.parse(saved) : null
    return course?.courseId && Array.isArray(course.videos) ? course : null
  } catch {
    return null
  }
}

function AppContent() {
  const [course, setCourse] = useState(loadSavedCourse)
  const [appState, setAppState] = useState(() => loadSavedCourse() ? 'learning' : 'discovery')
  const [discovery, setDiscovery] = useState(null)
  const [error, setError] = useState('')
  const [isSearching, setIsSearching] = useState(false)
  const [isMerging, setIsMerging] = useState(false)
  const [isProjectTourOpen, setIsProjectTourOpen] = useState(false)
  const [selectedIds, setSelectedIds] = useState([])

  useEffect(() => {
    try {
      if (course) window.localStorage.setItem(ACTIVE_COURSE_STORAGE_KEY, JSON.stringify(course))
      else window.localStorage.removeItem(ACTIVE_COURSE_STORAGE_KEY)
    } catch {
      // The current tab remains usable if browser storage is unavailable.
    }
  }, [course])

  async function handleSearch(query) {
    setError('')
    setIsSearching(true)
    setSelectedIds([])
    try {
      setDiscovery(await discoverPlaylists(query))
    } catch (requestError) {
      setDiscovery(null)
      setError(requestError.message)
    } finally {
      setIsSearching(false)
    }
  }

  async function exploreRecommendedCourse(recommendation) {
    const query = recommendation?.searchQuery?.trim()
    if (!query) return

    // Keep the current course in local storage while the learner explores a
    // follow-up. A fresh course is created only after they select sources.
    setAppState('discovery')
    setDiscovery(null)
    setSelectedIds([])
    await handleSearch(query)
  }

  function togglePlaylist(id) {
    setSelectedIds((currentIds) => currentIds.includes(id) ? currentIds.filter((playlistId) => playlistId !== id) : [...currentIds, id])
  }

  async function mergeSelectedPlaylists() {
    if (!selectedIds.length) return

    setError('')
    setIsMerging(true)
    try {
      const ingestion = await ingestPlaylists(selectedIds)
      setCourse({
        title: `AI-Optimized Course: ${discovery.intent.topic}`,
        ...ingestion,
      })
      setAppState('learning')
    } catch (requestError) {
      setError(requestError.message)
    } finally {
      setIsMerging(false)
    }
  }

  const playlists = (discovery?.playlists ?? []).map((playlist) => ({
    ...playlist,
    selected: selectedIds.includes(playlist.id),
  }))

  if (appState === 'learning' && course) {
    return (
      <Suspense fallback={<WorkspaceLoading />}>
        <LearningDashboard course={course} onBack={() => { setCourse(null); setAppState('discovery') }} onExploreCourse={exploreRecommendedCourse} />
      </Suspense>
    )
  }

  return (
    <div className="min-h-screen bg-slate-50 font-sans text-slate-900 selection:bg-indigo-200">
      <header className="sticky top-0 z-10 flex items-center justify-between bg-slate-50/80 px-6 py-5 backdrop-blur-md md:px-8">
        <div className="flex items-center gap-2.5 text-indigo-600"><BookOpen className="h-7 w-7" /><span className="text-2xl font-extrabold tracking-tight text-slate-900">YouLearnTube</span></div>
        <div className="flex items-center gap-2">
          {course && <button className="hidden rounded-full border border-indigo-100 bg-white px-3 py-1 text-sm font-semibold text-indigo-700 transition-colors hover:bg-indigo-50 sm:block" onClick={() => setAppState('learning')} type="button">Resume current course</button>}
          <button aria-haspopup="dialog" className="hidden items-center gap-1.5 rounded-full bg-indigo-50 px-3 py-1 text-sm font-semibold text-indigo-700 transition-colors hover:bg-indigo-100 sm:inline-flex" onClick={() => setIsProjectTourOpen(true)} type="button"><CircleHelp className="h-4 w-4" /> Click here</button>
          {isFrontendMockMode && <span className="hidden rounded-full bg-violet-100 px-3 py-1 text-sm font-semibold text-violet-700 lg:block">Frontend mock</span>}
        </div>
      </header>
      <main className="mx-auto flex w-full max-w-7xl flex-col items-center px-6 pb-24 pt-16 md:pt-20">
        <section className="mb-12 max-w-3xl text-center">
          <div className="mb-6 inline-flex items-center gap-2 rounded-full bg-indigo-100 px-3 py-1 text-sm font-bold text-indigo-700"><Sparkles className="h-4 w-4" /> AI Curriculum Synthesizer</div>
          <h1 className="mb-6 text-4xl font-extrabold leading-tight tracking-tight text-slate-900 md:text-5xl">Design your perfect learning path.</h1>
          <p className="text-lg font-medium text-slate-600 md:text-xl">Tell our AI what you want to learn. 
[truncated — 2193 more characters]
```

### frontend/vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [react(), tailwindcss()],
})

```

### frontend/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>YouLearnTube</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

```

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