Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ Format: [Keep a Changelog](https://keepachangelog.com/); versioning: [SemVer](ht

## [Unreleased]

### Fixed
- Phone header: Studio, data saver and the theme switch were off-screen below ~560 px. Header, Studio and /try now fit 360 px (Phase 23)

### Added
- Weak spots on Saved: wrong quiz answers become a personal revision reel of the explanations you missed (Phase 22)
- Study notes `/notes/[id]` and `GET /api/lectures/[id]/notes`: a timestamp-linked study sheet per session, as Markdown or PDF (Phase 22)
- Data saver: a header switch (automatic on Save-Data and 2G/3G) that serves lighter Cloudinary renditions and the `sd` streaming ladder; 33–76% fewer bytes measured (Phase 21)
- `/judges`: the submission requirements mapped to 14 Cloudinary capabilities, live URLs and a 90-second test; revision reel on `/saved` (Phase 20)
- Concept Map `/concepts` and Compare view `/concepts/[key]`: the same concept from every teacher as one Compare Reel (Phase 19)
- Cloudinary asset index: tags and contextual metadata on each session's asset, synced from the Studio and read back with the Search API (Phase 19)

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Colleges, clubs and coaching institutes record hundreds of hours of lectures and
| **Data saver** | One switch (and automatic on Save-Data or 2G/3G) serves smaller, lower-quality Cloudinary renditions: thumbnails 76% lighter, clips and reels 38–41%, and a streaming ladder that tops out at 0.9 Mbps instead of 3.4. Built for India’s mobile data. |
| **Weak spots** | Quiz mistakes are remembered on your device and come back as **one Cloudinary reel of exactly the explanations you missed**, with the answer and the second to jump to. Get a question right and it leaves the list. |
| **Study notes** | Every session has a study sheet at `/notes/[id]`: summary, key concepts, chapters and the quiz with answers, each point linked to its timestamp. Copy it as Markdown, download it, or save it as a PDF. |
| **Revision reel** | On `/saved`, the latest saved moments from any sessions play as one labelled video: a revision reel for the night before an exam. |
| **Study Packs** | Every session gets a summary, key concepts, a quiz whose explanations **play the moment** the teacher explains it, and a "Session in 60 seconds" highlight reel. Pravaha generates them automatically from the transcript. |
| **Moments** | One tap turns any cited clip into a vertical, AI-cropped, subtitled short for WhatsApp or Instagram, with its own share page and preview card. The short is just a Cloudinary URL; nothing is rendered. |
| **Insights** | Organizers see what learners ask, the **knowledge gaps** the library can't answer yet (what to record next), and which Moments get shared. Every report downloads as CSV. Visitors can explore a read-only demo of the Studio. |
Expand Down Expand Up @@ -164,6 +165,8 @@ Diagrams and reasoning: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) · [`docs

## How to test it

> **Judges:** [`/judges`](https://pravaha-cyan.vercel.app/judges) maps the submission requirements to the Cloudinary features, with live URLs and a 90-second test.

Open the live app at **[pravaha-cyan.vercel.app](https://pravaha-cyan.vercel.app)**. Learners need no login.

1. On the home page, type a question or tap a suggestion. Try "Why should the learning rate decrease during training, and how do adaptive optimizers handle it?": live progress appears, then one answer citing two professors from two institutes, plus an Answer Reel. Or ask in Hindi: "ओवरफिटिंग क्या है?"
Expand Down
9 changes: 9 additions & 0 deletions docs/DEMO.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ Never show setup, code, dashboards or waiting. Every shot is the problem, the pr
**Study shots (if there is time):** answer a quiz question wrong → `/saved` → **Play my weak-spot reel** ("What you get wrong comes back as video.") → a session’s **Study notes** → **Download .md** ("Every point links to the second the teacher said it.")

**Bonus shot (if there is time):** header → **Data saver** on → the same answer reel and thumbnails reload visibly lighter. Voice-over: "Built for India’s mobile data: one switch, and Cloudinary serves everything at a fraction of the bytes."
## Phase 18–20 scenes (Oct 3) — swap in for the 2:06–2:35 shots if time is tight

| Shot | Voice-over |
|---|---|
| Ask "What is the bias-variance trade-off?" → the answer says honestly the lecturer never uses that phrase, then explains the related ideas with clips | "It doesn’t bluff. If the lecturer never said it, Pravaha says so and teaches the closest ideas." |
| Ask the same in Hindi: "ओवरफिटिंग क्या है?" → Hindi answer citing English lectures | "Ask in Hindi, answer from English lectures." |
| `/concepts/overfitting` → play the Compare Reel: three professors, labelled | "Same idea, three teachers, one video, until one explanation clicks." |
| `/learn` → "Choosing a learning rate" → 4-step course video | "Any topic becomes a short course, ordered basics first, edited by Cloudinary." |
| `/judges` → capability list → Studio → Cloudinary asset index (Search API) | "Every capability is listed with live URLs. Even our tags are read back from Cloudinary’s Search API." |

## Pre-Recording Checklist

Expand Down
2 changes: 2 additions & 0 deletions docs/IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,5 @@ The core loop (Phases 01–09) is built and verified on real Cloudinary + Neon.
| 19 | Concept Map & Cloudinary asset index | Same concept, every teacher, as one Compare Reel; tags + contextual metadata on Cloudinary assets, read back with the Search API | ✅ done (Oct 3) |
| 21 | Data saver | Light Cloudinary renditions (35–76% fewer bytes, sd streaming ladder) for slow or metered connections; follows Save-Data and 2G/3G automatically | ✅ done (Oct 3) |
| 22 | Weak spots & study notes | Quiz mistakes become a personal revision reel; every session exports a timestamp-linked study sheet (Markdown / print) | ✅ done (Oct 3) |
| 20 | Judges page & revision reel | `/judges` maps the brief to Cloudinary capabilities with live URLs; saved moments replay as one reel | ✅ done (Oct 3) |
| 23 | Phone layout | Header, Studio and /try fit a 360 px phone; e2e guard | ✅ done (Oct 3) |
7 changes: 6 additions & 1 deletion docs/SUBMISSION_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@ Deadline: submit by **Oct 3, 2026**; code freeze **Oct 4, 00:15 IST**. Submit vi
- [x] Learner flows (Watch, Find, Ask, Moments) work without login (Oct 2: Playwright smoke tests 12/12 against production, desktop and mobile)
- [x] Demo library: 6 public sessions (NPTEL excerpts, CC BY-NC-SA, credited in the README), uploaded through the production pipeline on Oct 2
- [x] Organizer and enterprise features merged and checked on Vercel previews (Oct 2–3): demo Studio, Insights charts and CSV export, LMS embed, Privacy and Terms, health endpoint
- [ ] **Cloudinary credits:** 24.3 of 25 used on Oct 3 (free plan). Upgrade, or confirm the reset date is before judging, so new answer clips and Moments keep generating
- [ ] **Cloudinary credits:** the Admin API reported 14.1 of 25 used (56%) at its last update (Oct 2). Every new reel, Moment and Compare Reel spends some, so avoid regenerating them in bulk before judging, and re-check `api.usage()` on submission day
- [ ] Trials decision after that: keep `/try` paused (`TRIALS_PER_DAY=0`) or re-enable (`TRIALS_PER_DAY=5`, then redeploy)

- [x] Phone check at 360 px on every key page (Oct 3, Phase 23): header controls reachable, no sideways scroll

## Repository
- [x] Public repo: `Monolithic-Dev/Pravaha` (own repo is allowed by HackIndia's FAQ)
- [ ] README explains track, problem, Cloudinary usage, how to test — with live URL, screenshots, demo link (all done except the demo link; screenshots retaken with the real library on Oct 2)
- [x] README keeps the HackIndia team tag line
- [ ] Setup instructions a stranger can follow cold (`SETUP.md`)
- [x] No API keys or credentials anywhere in history — `git log -p | grep -iE "api_secret|sk-ant|postgres://|passcode"` returns only env-variable references (checked Oct 2)

- [ ] Studio → **Cloudinary asset index** → Sync tags run once on production, so the Search API shows tagged assets
- [x] `/judges` page maps the brief to Cloudinary capabilities and the 90-second test (Phase 20)

## Demo
- [ ] 2–4 minute video recorded per `DEMO.md` (target 2:45), publicly viewable link (check credits first: see its pre-recording checklist)
- [ ] Demo video link added to the README
Expand Down
6 changes: 6 additions & 0 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ Scope: the things that would embarrass the product in front of a judge or corrup

Against the **deployed** `APP_URL`: home → search a known phrase → result opens `/watch/id?t=` at the right second → Ask a known question → ≥1 citation card → open Moment sheet. Run before recording the demo and before submitting.

### More end-to-end specs (all run against the deployed `APP_URL`, `--project=desktop --project=mobile`)
- `judges.spec.ts`: the judges page, the concept map with its compare reel, `/learn`
- `data-saver.spec.ts`: the header switch makes Cloudinary thumbnails `w_320,q_auto:low`, is remembered, and a session streams the `sp_sd` ladder
- `revision.spec.ts`: a wrong quiz answer appears under Weak spots with a revision reel and clears; study notes carry timestamp links and download as Markdown
- `mobile.spec.ts`: at 360 px the header's Studio, data saver and theme controls are on screen and no page scrolls sideways

## AI Eval (`pnpm eval:ask`)

10 questions (7 answerable, 3 not) against the demo library; results recorded in `AI_EVALUATION.md`.
Expand Down
2 changes: 1 addition & 1 deletion docs/UX_UI.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Skeletons, never bare spinners. 404 session → "This session isn't available."

### Motion & shell (v3)
- `rise` (staggered entrance), `word-in` (answer reveal), `lift` (hover), `spinner`; all disabled under `prefers-reduced-motion`
- Sticky blurred header with the Pravaha mark (also the favicon, `app/icon.svg`), Library and Studio links, a skip link, and a footer
- Sticky blurred header with the Pravaha mark (also the favicon, `app/icon.svg`), the page links (Library, Learn, Concepts, Saved, Studio) and the data saver and theme switches. On a phone the links drop to a second, sideways-scrolling row so nothing is pushed off-screen (Phase 23); a skip link, and a footer
- Home: "How it works" in three steps under the Ask bar
- `/` or Ctrl/⌘K focuses the Ask bar from anywhere

Expand Down
15 changes: 15 additions & 0 deletions docs/phases/PHASE-20-judges-page-revision-reel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Phase 20 — Judges page and revision reel

**Status: DONE (Oct 3)** · branch `feature/judges-page-revision-reel`

## Why
A hackathon is judged in minutes. The product was strong but a judge had to discover how Cloudinary is used by reading code and docs. This phase puts the evidence in the product.

## What shipped
1. **`/judges`** (`src/app/judges/page.tsx`, `src/lib/capabilities.ts`): the submission requirements mapped to where each is met, a 90-second test with deep links, 14 Cloudinary capabilities (what each does, where to see it, which file), and the live Cloudinary URLs generated from the real library. `tests/unit/capabilities.test.ts` fails if any listed file doesn't exist, so the page can't drift from the code.
2. **Revision reel** on `/saved`: the latest saved moments, from any sessions, as one labelled `fl_splice` video. Saved moments stay on the device; only the Cloudinary URL is built from them.
3. Playwright smoke tests for `/judges`, `/concepts` and `/learn`; the demo script and submission checklist updated.

## Findings from the Oct 3 architecture review
- Cloudinary credits were 14.1 of 25 (56%) at the Admin API's last update (Oct 2): enough for judging if reels aren't regenerated in bulk. The biggest consumers are `sd_video_second` and AI hover previews.
- The Gemini free quota remains the main production risk; Groq is the working fallback.
17 changes: 17 additions & 0 deletions docs/phases/PHASE-23-mobile-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Phase 23 — Phone layout

**Status: DONE (Oct 3)** · branch `fix/mobile-layout-audit`

## Why
A 360 px audit of every key page (Playwright, `isMobile`, scanning for elements past the viewport) found one real bug that appeared on **every page**: the header's single row needed ~560 px, so on a phone **Studio, the data saver switch and the theme switch were off-screen and unreachable** (the page clips horizontal overflow, so there was no scrollbar to hint at them). Judges often open a link on a phone.

## What changed
- **Header:** on phones the logo and the two switches share row one; the page links sit on a second row that scrolls sideways if it must. From `sm` up it is the same single row as before (checked at 1280 px).
- **Studio:** the page grid had no explicit column, so its content's minimum width pushed it 19 px past the screen. `grid-cols-1` fixes it.
- **/try:** the three-step progress bar wraps instead of overflowing.
- `tests/e2e/mobile.spec.ts` asserts, for 8 pages at 360 px, that Studio, data saver and the theme switch are on screen and the page doesn't scroll sideways.

## Verified
Before: 11 of 11 audited pages had off-screen header controls. After: 0 offenders on all 11 pages (home's remaining hits are decorative clipped backgrounds).

Bundled in this PR: the judges page and revision reel (Phase 20), which touch the same header and footer.
8 changes: 8 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,11 @@ body {
.playhead { width: 100%; }
.lift, .lift:hover { transition: none; transform: none; }
}

/* A row that scrolls sideways without showing a scrollbar (the phone header's page links). */
.no-scrollbar {
scrollbar-width: none;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
109 changes: 109 additions & 0 deletions src/app/judges/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type { Metadata } from "next";
import Link from "next/link";

import { UnderTheHood } from "@/components/UnderTheHood";
import { CAPABILITIES } from "@/lib/capabilities";
import { getConcept, listConcepts } from "@/lib/concepts";
import { conceptHoodItems, sessionHoodItems, type HoodItem } from "@/lib/hood-items";
import { getLecture, getSegments, listLectures } from "@/lib/lectures";
import { getStudyPack } from "@/lib/study-packs";

export const dynamic = "force-dynamic";

export const metadata: Metadata = {
title: "For judges — Pravaha",
description: "How Pravaha uses Cloudinary, mapped to the hackathon's requirements, with live URLs and a 90-second test.",
};

const REQUIREMENTS: [string, string][] = [
["Cloudinary is an active part of the product", "Media in is raw video; transcripts, chapters, streams, clips, reels, cards and tags all come from Cloudinary. Without it there is no product."],
["Upload, manage, transform, optimize, search, deliver", "Signed upload · tags and context · Search API · splice, crop, caption, preview transformations · f_auto/q_auto · HLS delivery."],
["A live working demo", "This site. Six real NPTEL sessions, no login for learners."],
["Public repo with setup instructions", "github.com/Monolithic-Dev/Pravaha, SETUP.md."],
["README: track, problem, Cloudinary usage, how to test", "Track 3 (Your Media-Savvy Startup); see the README."],
];

const STEPS: [string, string, string][] = [
["Ask", "Type: “What is the bias-variance trade-off?” The answer cites clips; open one. Try it in Hindi: “ओवरफिटिंग क्या है?”", "/"],
["Watch the answer", "Tap “Watch the answer”: moments from different lecturers as one Cloudinary-edited video.", "/"],
["Compare teachers", "Open the Overfitting concept: three lecturers, one video.", "/concepts/overfitting"],
["Build a course", "Ask for “Choosing a learning rate”: a 4-step course, one video.", "/learn?topic=Choosing%20a%20learning%20rate"],
["Share a Moment", "On any clip tap “Share as Moment”: vertical, speaker-tracked, captioned.", "/search?q=overfitting"],
["See the proof", "Open “Cloudinary under the hood” at the bottom of a session, answer or concept.", "/#library"],
];

export default async function JudgesPage() {
const [lectures, concepts] = await Promise.all([listLectures({ includeAll: false }), listConcepts()]);
const lecture = lectures[0] ? await getLecture(lectures[0].id) : null;
const shared = concepts.find((c) => c.entries.length > 1);
const [segments, pack, concept] = await Promise.all([
lecture ? getSegments(lecture.id) : [],
lecture ? getStudyPack(lecture.id) : null,
shared ? getConcept(shared.key) : null,
]);
const items: HoodItem[] = [
...(lecture && segments.length ? sessionHoodItems(lecture, segments, pack?.highlights) : []),
...(concept ? conceptHoodItems(concept.key, concept.moments) : []),
];

return (
<div className="mx-auto mt-6 max-w-4xl">
<p className="text-sm font-semibold tracking-wide text-accent uppercase">Track 3 · Your Media-Savvy Startup</p>
<h1 className="mt-1 text-3xl font-semibold tracking-tight sm:text-4xl">Pravaha, for judges</h1>
<p className="mt-3 max-w-2xl text-muted">
Pravaha turns lecture recordings into knowledge you can ask. Every answer is a clip of the teacher saying it, and the clip,
the reel, the share card and the Hindi subtitles are all Cloudinary. This page maps that to the submission requirements.
</p>

<section className="mt-8" aria-labelledby="req">
<h2 id="req" className="text-lg font-semibold">The requirements, and where they are met</h2>
<dl className="mt-3 divide-y divide-border rounded-2xl border border-border bg-surface">
{REQUIREMENTS.map(([need, met]) => (
<div key={need} className="grid gap-1 p-4 sm:grid-cols-[1fr_2fr] sm:gap-4">
<dt className="font-medium">{need}</dt>
<dd className="text-sm text-muted">{met}</dd>
</div>
))}
</dl>
</section>

<section className="mt-8" aria-labelledby="test">
<h2 id="test" className="text-lg font-semibold">Test it in 90 seconds</h2>
<ol className="mt-3 space-y-2">
{STEPS.map(([name, text, href], i) => (
<li key={name} className="flex gap-3 rounded-2xl border border-border bg-surface p-3">
<span className="grid size-7 shrink-0 place-items-center rounded-full bg-accent text-sm font-semibold text-accent-fg">{i + 1}</span>
<span className="text-sm">
<Link href={href} className="font-medium text-accent hover:underline">{name}</Link>
<span className="text-muted"> · {text}</span>
</span>
</li>
))}
</ol>
</section>

<section className="mt-8" aria-labelledby="caps">
<h2 id="caps" className="text-lg font-semibold">{CAPABILITIES.length} Cloudinary capabilities in use</h2>
<ul className="mt-3 grid gap-3 sm:grid-cols-2">
{CAPABILITIES.map((c) => (
<li key={c.name} className="rounded-2xl border border-border bg-surface p-4">
<p className="font-medium">{c.name}</p>
<p className="mt-1 text-sm text-muted">{c.does}</p>
<p className="mt-2 text-xs text-muted">
See it: <span className="text-fg">{c.see}</span> · <code className="font-mono">{c.code}</code>
</p>
</li>
))}
</ul>
</section>

{items.length > 0 && (
<section className="mt-8" aria-labelledby="live">
<h2 id="live" className="text-lg font-semibold">Live Cloudinary URLs</h2>
<p className="mt-1 text-sm text-muted">Generated from the real library right now. Open any of them.</p>
<UnderTheHood items={items} title="The URLs behind this library" />
</section>
)}
</div>
);
}
Loading
Loading