docs: Updated 7 Forgejo wiki pages with M024 feature documentation cove…
- "Home.md" - "Data-Model.md" - "API-Surface.md" - "Frontend.md" - "Pipeline.md" - "Player.md" - "Chat-Engine.md" GSD-Task: S06/T01
This commit is contained in:
parent
0eecee4271
commit
a4a6187de2
9 changed files with 556 additions and 2 deletions
|
|
@ -374,3 +374,9 @@
|
|||
**Context:** Some API endpoints need to be publicly accessible but provide different behavior for authenticated users (e.g., showing draft posts to the owner). Using the standard `get_current_user` dependency rejects unauthenticated requests with 401.
|
||||
|
||||
**Fix:** Create `get_optional_user` using `OAuth2PasswordBearer(auto_error=False)`. When `auto_error=False`, missing/invalid tokens return `None` instead of raising 401. The endpoint receives `Optional[User]` and branches on whether the user is present and matches the resource owner.
|
||||
|
||||
## Pass CSS module styles as Record<string, string> to shared utilities
|
||||
|
||||
**Context:** When extracting a shared React utility (e.g., `parseChatCitations`) that renders JSX with CSS module class names, the utility needs the calling component's styles object. TypeScript's `CSSModuleClasses` type is structurally incompatible across module boundaries — passing `styles` typed as the specific module's interface causes type errors.
|
||||
|
||||
**Fix:** Type the styles parameter as `Record<string, string>`. CSS modules already satisfy this shape at runtime. This allows any component to pass its own CSS module styles to the shared utility without type gymnastics.
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ Shorts pipeline goes end-to-end with captioning and templates. Player gets key m
|
|||
| S02 | [A] Key Moment Pins on Player Timeline | low | — | ✅ | Key technique moments appear as clickable pins on the player timeline |
|
||||
| S03 | [A] Embed Support (iframe Snippet) | low | — | ✅ | Creators can copy an iframe embed snippet to put the player on their own site |
|
||||
| S04 | [B] Auto-Captioning + Template System | medium | — | ✅ | Shorts have Whisper-generated animated subtitles and creator-configurable intro/outro cards |
|
||||
| S05 | [B] Citation UX Improvements | low | — | ⬜ | Chat citations show timestamp links that seek the player and source cards with video thumbnails |
|
||||
| S05 | [B] Citation UX Improvements | low | — | ✅ | Chat citations show timestamp links that seek the player and source cards with video thumbnails |
|
||||
| S06 | Forgejo KB Update — Shorts, Embed, Citations | low | S01, S02, S03, S04, S05 | ⬜ | Forgejo wiki updated with shorts pipeline, embed system, citation architecture |
|
||||
|
|
|
|||
94
.gsd/milestones/M024/slices/S05/S05-SUMMARY.md
Normal file
94
.gsd/milestones/M024/slices/S05/S05-SUMMARY.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
id: S05
|
||||
parent: M024
|
||||
milestone: M024
|
||||
provides:
|
||||
- Video metadata (source_video_id, start_time, end_time, video_filename) in search results and chat SSE source events
|
||||
- Shared chatCitations.tsx and formatTime.ts utilities
|
||||
requires:
|
||||
[]
|
||||
affects:
|
||||
- S06
|
||||
key_files:
|
||||
- backend/search_service.py
|
||||
- backend/chat_service.py
|
||||
- frontend/src/utils/chatCitations.tsx
|
||||
- frontend/src/utils/formatTime.ts
|
||||
- frontend/src/api/chat.ts
|
||||
- frontend/src/pages/ChatPage.tsx
|
||||
- frontend/src/pages/ChatPage.module.css
|
||||
- frontend/src/components/ChatWidget.tsx
|
||||
- frontend/src/components/ChatWidget.module.css
|
||||
key_decisions:
|
||||
- Batch-fetch SourceVideo filenames using same pattern as creator batch-fetch
|
||||
- Video fields are empty/None for non-key_moment types to keep dict shape uniform
|
||||
- Pass CSS module styles as Record<string, string> to shared citation parser to avoid CSSModuleClasses structural typing mismatch
|
||||
patterns_established:
|
||||
- Shared parseChatCitations utility for citation rendering across ChatPage and ChatWidget
|
||||
- Shared formatTime utility replacing duplicated time formatting across 4+ files
|
||||
observability_surfaces:
|
||||
- none
|
||||
drill_down_paths:
|
||||
- .gsd/milestones/M024/slices/S05/tasks/T01-SUMMARY.md
|
||||
- .gsd/milestones/M024/slices/S05/tasks/T02-SUMMARY.md
|
||||
duration: ""
|
||||
verification_result: passed
|
||||
completed_at: 2026-04-04T11:47:32.918Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# S05: [B] Citation UX Improvements
|
||||
|
||||
**Chat citations now carry video metadata (source_video_id, start_time, end_time, video_filename) from backend through SSE to frontend, where timestamp badge links and video filename labels appear on source cards.**
|
||||
|
||||
## What Happened
|
||||
|
||||
Two tasks delivered end-to-end citation UX improvements for chat source cards.
|
||||
|
||||
**T01 (Backend):** Propagated video metadata through three code paths. In `_enrich_qdrant_results()`, added batch-fetch of SourceVideo filenames (same pattern as creator batch-fetch) and four video fields to the enriched dict. In `_keyword_search_and()`, added the same four fields from the already-joined SourceVideo. In `_build_sources()` in chat_service.py, passed all four fields through to SSE source events. Non-key_moment types get empty/None values, keeping dict shape uniform.
|
||||
|
||||
**T02 (Frontend):** Extended the ChatSource TypeScript interface with video fields. Created `utils/chatCitations.tsx` — a shared `parseChatCitations()` function that replaces duplicate implementations in both ChatPage and ChatWidget. Created `utils/formatTime.ts` — a shared hour-aware time formatter replacing copies in 4+ files. Updated source card rendering in both components: when `start_time` is defined, a timestamp badge links to `/watch/:id?t=N`; video filename appears as subtle metadata. Added CSS classes `.timestampBadge` and `.videoMeta` to both module stylesheets.
|
||||
|
||||
## Verification
|
||||
|
||||
Backend: Both `from chat_service import _build_sources` and `from search_service import SearchService` import cleanly (exit 0). Frontend: `npm run build` passes with zero TypeScript/Vite errors. Deduplication confirmed: no `CITATION_RE` or local `parseCitations` functions remain in ChatPage.tsx or ChatWidget.tsx.
|
||||
|
||||
## Requirements Advanced
|
||||
|
||||
None.
|
||||
|
||||
## Requirements Validated
|
||||
|
||||
None.
|
||||
|
||||
## New Requirements Surfaced
|
||||
|
||||
None.
|
||||
|
||||
## Requirements Invalidated or Re-scoped
|
||||
|
||||
None.
|
||||
|
||||
## Deviations
|
||||
|
||||
T01: Fixed operator precedence bug — `(sv.filename or "") if sv else ""` needed parens. T02: Used `Record<string, string>` for styles param instead of strict CSSModuleClasses interface. Added `.sourceContent` wrapper div in ChatWidget for vertical layout.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
Timestamp badges link to `/watch/:id?t=N` but actual player seek-on-load depends on WatchPage reading the `t` query param (already implemented in prior slices). No runtime integration test against live Qdrant/SSE — verified via import checks and build.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `backend/search_service.py` — Added video metadata fields to _enrich_qdrant_results() and _keyword_search_and() for key_moment results
|
||||
- `backend/chat_service.py` — Added video fields to _build_sources() SSE source events
|
||||
- `frontend/src/api/chat.ts` — Extended ChatSource interface with source_video_id, start_time, end_time, video_filename
|
||||
- `frontend/src/utils/chatCitations.tsx` — New shared parseChatCitations utility extracted from ChatPage and ChatWidget
|
||||
- `frontend/src/utils/formatTime.ts` — New shared formatTime utility replacing duplicated implementations
|
||||
- `frontend/src/pages/ChatPage.tsx` — Replaced local citation parser with shared import, added timestamp badges and video metadata to source cards
|
||||
- `frontend/src/pages/ChatPage.module.css` — Added .timestampBadge and .videoMeta CSS classes
|
||||
- `frontend/src/components/ChatWidget.tsx` — Replaced local citation parser with shared import, added timestamp badges and video metadata to source cards
|
||||
- `frontend/src/components/ChatWidget.module.css` — Added .timestampBadge, .videoMeta, and .sourceContent CSS classes
|
||||
60
.gsd/milestones/M024/slices/S05/S05-UAT.md
Normal file
60
.gsd/milestones/M024/slices/S05/S05-UAT.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# S05: [B] Citation UX Improvements — UAT
|
||||
|
||||
**Milestone:** M024
|
||||
**Written:** 2026-04-04T11:47:32.918Z
|
||||
|
||||
## UAT: Citation UX Improvements
|
||||
|
||||
### Preconditions
|
||||
- Chrysopedia stack running on ub01:8096
|
||||
- At least one key_moment with a source_video_id exists in the database
|
||||
- Chat endpoint functional with LightRAG backend
|
||||
|
||||
### Test 1: Backend — Video metadata in search results
|
||||
1. Open browser to `http://ub01:8096`
|
||||
2. Search for a term that matches a key moment (e.g., a technique name from a known video)
|
||||
3. Open browser dev tools → Network tab
|
||||
4. Observe the search API response JSON
|
||||
5. **Expected:** Key moment results include `source_video_id` (non-empty string), `start_time` (number or null), `end_time` (number or null), `video_filename` (string or empty)
|
||||
|
||||
### Test 2: Backend — Video metadata in chat SSE source events
|
||||
1. Open the chat interface at `http://ub01:8096/chat`
|
||||
2. Ask a question that should retrieve key moment sources
|
||||
3. Open browser dev tools → Network tab → find the SSE stream
|
||||
4. Inspect the `sources` SSE event data
|
||||
5. **Expected:** Source objects for key_moment-type results include `source_video_id`, `start_time`, `end_time`, `video_filename` fields
|
||||
|
||||
### Test 3: Frontend — Timestamp badge on chat source cards
|
||||
1. In the chat page, after receiving a response with key_moment sources
|
||||
2. Look at the source cards below the response
|
||||
3. **Expected:** Source cards for key moments show a timestamp badge (e.g., "1:23 – 2:45") that is a clickable link
|
||||
4. Click the timestamp badge
|
||||
5. **Expected:** Navigates to `/watch/{video_id}?t={start_time}` — the video watch page at the correct timestamp
|
||||
|
||||
### Test 4: Frontend — Video filename metadata on source cards
|
||||
1. In the chat page with key_moment sources visible
|
||||
2. Look at the source card metadata
|
||||
3. **Expected:** Video filename appears as subtle text below or beside the source title
|
||||
|
||||
### Test 5: Frontend — ChatWidget has same citation features
|
||||
1. Navigate to a technique page that has the ChatWidget in the sidebar
|
||||
2. Ask a question that returns key_moment sources
|
||||
3. **Expected:** Source cards in the widget also show timestamp badges and video filename, matching ChatPage behavior
|
||||
|
||||
### Test 6: Frontend — Shared citation parser deduplication
|
||||
1. Open `frontend/src/pages/ChatPage.tsx` in editor
|
||||
2. Search for `CITATION_RE` or `function parseCitations`
|
||||
3. **Expected:** Neither found — all citation parsing uses the shared `utils/chatCitations.tsx`
|
||||
4. Repeat for `frontend/src/components/ChatWidget.tsx`
|
||||
5. **Expected:** Same — no local citation parsing code
|
||||
|
||||
### Test 7: Frontend — formatTime utility
|
||||
1. Open `frontend/src/utils/formatTime.ts`
|
||||
2. **Expected:** Exports a `formatTime(seconds: number): string` function
|
||||
3. Format: `M:SS` for times under 1 hour, `H:MM:SS` for 1 hour or more
|
||||
4. Verify ChatPage and ChatWidget import from this shared utility (not local copies)
|
||||
|
||||
### Edge Cases
|
||||
- **Non-key_moment sources:** Technique page sources should render normally without timestamp badges (start_time is undefined/null)
|
||||
- **Missing video_filename:** Source card should render without the filename line when video_filename is empty
|
||||
- **Zero start_time:** A start_time of 0 should still show the badge (formatted as "0:00")
|
||||
16
.gsd/milestones/M024/slices/S05/tasks/T02-VERIFY.json
Normal file
16
.gsd/milestones/M024/slices/S05/tasks/T02-VERIFY.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"taskId": "T02",
|
||||
"unitId": "M024/S05/T02",
|
||||
"timestamp": 1775303160365,
|
||||
"passed": true,
|
||||
"discoverySource": "task-plan",
|
||||
"checks": [
|
||||
{
|
||||
"command": "cd frontend",
|
||||
"exitCode": 0,
|
||||
"durationMs": 6,
|
||||
"verdict": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,6 +1,88 @@
|
|||
# S06: Forgejo KB Update — Shorts, Embed, Citations
|
||||
|
||||
**Goal:** Document new systems in Forgejo knowledgebase
|
||||
**Goal:** Forgejo wiki updated with M024 feature documentation covering shorts publishing, embed support, key moment pins, auto-captioning/templates, and citation UX improvements.
|
||||
**Demo:** After this: Forgejo wiki updated with shorts pipeline, embed system, citation architecture
|
||||
|
||||
## Tasks
|
||||
- [x] **T01: Updated 7 Forgejo wiki pages with M024 feature documentation covering shorts publishing, embed support, timeline pins, auto-captioning, templates, and citation UX** — Clone the Chrysopedia Forgejo wiki on ub01, update Home.md, Data-Model.md, API-Surface.md, Frontend.md, Pipeline.md, Player.md, and Chat-Engine.md with M024 S01-S05 feature content, then commit and push.
|
||||
|
||||
**CRITICAL:** Never use the Forgejo wiki PATCH API — it corrupts pages (see KNOWLEDGE.md). Git clone → edit → push only.
|
||||
|
||||
All SSH/git operations happen on ub01 via `ssh ub01`.
|
||||
Wiki repo: `https://git.xpltd.co/xpltdco/chrysopedia.wiki.git`
|
||||
|
||||
## Content to add per page:
|
||||
|
||||
### Home.md
|
||||
Add to the feature list / recent additions:
|
||||
- Shorts publishing flow: public shareable URLs via /shorts/{token}, share_token generated at pipeline completion
|
||||
- Embed support: chrome-free /embed/:videoId player, iframe snippet with audio-aware height
|
||||
- Key moment timeline pins: 12px color-coded circle pins (technique=cyan, settings=amber, reasoning=purple, workflow=green), active-state highlighting, touch-friendly hit areas
|
||||
- Inline collapsible player on technique pages with bibliography seek wiring
|
||||
- Auto-captioning: ASS karaoke subtitles from Whisper word-level timings, \k tags for word-by-word highlighting
|
||||
- Template system: creator-configurable intro/outro cards via admin API, ffmpeg lavfi card rendering, concat demuxer assembly
|
||||
- Citation UX: timestamp badge links to /watch/:id?t=N, video filename on source cards, shared chatCitations.tsx + formatTime.ts utilities
|
||||
|
||||
### Data-Model.md
|
||||
Add new columns:
|
||||
- `share_token` (String(16), unique-indexed, nullable) on GeneratedShort — generated via secrets.token_urlsafe(8) at pipeline completion
|
||||
- `captions_enabled` (Boolean, default false) on GeneratedShort — indicates successful ASS subtitle generation
|
||||
- `shorts_template` (JSONB, nullable) on Creator — intro/outro card config with parse_template_config normalizer
|
||||
Add migrations: 026 (share_token + backfill + unique index), 027 (captions_enabled), 028 (shorts_template)
|
||||
|
||||
### API-Surface.md
|
||||
Add new endpoints:
|
||||
- `GET /api/v1/public/shorts/{share_token}` — unauthenticated, returns metadata + presigned MinIO URL, 404 for missing/non-complete shorts
|
||||
- `GET /api/v1/admin/creators/{id}/shorts-template` — returns JSONB template config
|
||||
- `PUT /api/v1/admin/creators/{id}/shorts-template` — updates template config with validation (hex color, duration 1.0-5.0)
|
||||
Update: `POST generate-shorts` now accepts `captions` boolean parameter
|
||||
Update endpoint total count (was ~92, now ~95)
|
||||
|
||||
### Frontend.md
|
||||
Add new pages/components:
|
||||
- ShortPlayer (`/shorts/:token`) — public page outside ProtectedRoute, fetches via unauthenticated API, renders video + metadata + share/embed copy buttons
|
||||
- EmbedPlayer (`/embed/:videoId`) — chrome-free, registered at top-level Routes before AppShell catch-all, content-type-aware height (120px audio, 405px video), "Powered by Chrysopedia" branding
|
||||
- ChapterMarkers upgrade: 12px circle pins replacing 3px lines, color-coded by content_type via --color-pin-{type} CSS custom properties, active-state 1.3x scale, ::before inset:-6px touch targets, tooltips with title + time range + content type
|
||||
- Inline collapsible player on TechniquePage between summary and body, grid-template-rows 0fr/1fr animation, multi-source-video selector, bibliography seek buttons
|
||||
Add shared utilities:
|
||||
- `utils/clipboard.ts` — shared copyToClipboard (navigator.clipboard + execCommand fallback)
|
||||
- `utils/chatCitations.tsx` — shared parseChatCitations replacing duplicate implementations
|
||||
- `utils/formatTime.ts` — shared hour-aware time formatter
|
||||
Add HighlightQueue updates: share link + embed code copy buttons, collapsible template config panel (intro/outro text, duration sliders, show/hide, color picker, font), per-highlight captions toggle
|
||||
|
||||
### Pipeline.md
|
||||
Add new modules:
|
||||
- `caption_generator.py`: generate_ass_captions() converts Whisper word-level timings to ASS subtitles with \k karaoke tags, clip-relative timing. Non-blocking — failures log WARNING, don't fail stage.
|
||||
- `card_renderer.py`: render_card() (lavfi color + drawtext), render_card_to_file() (ffmpeg executor), build_concat_list() + concat_segments() (ffmpeg concat demuxer), parse_template_config() (JSONB normalizer with defaults). Cards include anullsrc silent audio for codec-compatible concat.
|
||||
- `shorts_generator.py` updates: extract_clip() accepts optional ass_path for subtitle burn-in, extract_clip_with_template() for intro/main/outro concatenation
|
||||
- stage_generate_shorts updates: loads transcripts for captions, loads creator templates for cards, generates share_token on completion
|
||||
Note 45 unit tests (17 caption + 28 card)
|
||||
|
||||
### Player.md
|
||||
Add key moment pins section:
|
||||
- ChapterMarkers: 12px circle pins, color-coded (technique=cyan, settings=amber, reasoning=purple, workflow=green)
|
||||
- Active-state: 1.3x scale when playback within time range
|
||||
- Touch: ::before pseudo-element with inset:-6px
|
||||
- Tooltips: title + formatted time range + content type label
|
||||
Add inline player on technique pages:
|
||||
- Collapsible section between summary and body
|
||||
- Multi-source-video selector for multi-video technique pages
|
||||
- Bibliography time links render as seek buttons when inline player active, Links to WatchPage otherwise
|
||||
Add embed player:
|
||||
- /embed/:videoId — chrome-free, no header/nav/footer
|
||||
- Content-type-aware: video (405px) vs audio (120px)
|
||||
- "Powered by Chrysopedia" branding link with noopener
|
||||
|
||||
### Chat-Engine.md
|
||||
Add citation metadata propagation:
|
||||
- Backend: search_service enriches results with source_video_id, start_time, end_time, video_filename via batch-fetch of SourceVideo filenames
|
||||
- Backend: chat_service _build_sources() passes video fields through SSE source events
|
||||
- Frontend: ChatSource interface extended with video fields
|
||||
- Frontend: shared parseChatCitations() replaces duplicate citation parsers in ChatPage and ChatWidget
|
||||
- Frontend: timestamp badge links to /watch/:id?t=N on source cards
|
||||
- Frontend: video filename metadata on source cards
|
||||
- Estimate: 45m
|
||||
- Files: Home.md (wiki), Data-Model.md (wiki), API-Surface.md (wiki), Frontend.md (wiki), Pipeline.md (wiki), Player.md (wiki), Chat-Engine.md (wiki)
|
||||
- Verify: 1. `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && git log --oneline -1'` — shows M024 commit
|
||||
2. `ssh ub01 'curl -s https://git.xpltd.co/api/v1/repos/xpltdco/chrysopedia/wiki/pages -H "Authorization: token $(cat /vmPool/r/repos/xpltdco/.forgejo-token)" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))"'` — returns 20
|
||||
3. `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && grep -c share_token Data-Model.md'` — returns ≥1
|
||||
|
|
|
|||
99
.gsd/milestones/M024/slices/S06/S06-RESEARCH.md
Normal file
99
.gsd/milestones/M024/slices/S06/S06-RESEARCH.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
# S06 Research: Forgejo KB Update — Shorts, Embed, Citations
|
||||
|
||||
## Summary
|
||||
|
||||
Straightforward documentation slice following the established pattern (D034, prior KB slices M019/S06 through M023/S05). Clone Forgejo wiki via git on ub01, update existing pages with M024 feature content from S01-S05, commit, push. **Never use the Forgejo wiki PATCH API** (corrupts pages per KNOWLEDGE.md).
|
||||
|
||||
## Recommendation
|
||||
|
||||
Single task. Clone wiki, update 7 pages, push. Content sourced entirely from S01-S05 summaries already inlined in planner context. No new decisions to document from M024.
|
||||
|
||||
## Implementation Landscape
|
||||
|
||||
### Established Pattern (from M023/S05, M022/S07, etc.)
|
||||
|
||||
1. SSH to ub01
|
||||
2. `git clone https://git.xpltd.co/xpltdco/chrysopedia.wiki.git` into a temp dir
|
||||
3. Edit markdown files
|
||||
4. `git add . && git commit -m "..." && git push origin main`
|
||||
5. Verify via wiki pages API count (currently 20 pages)
|
||||
|
||||
### Current Wiki State
|
||||
|
||||
20 pages exist. Relevant ones to update:
|
||||
|
||||
| Page | What to add from M024 |
|
||||
|------|----------------------|
|
||||
| **Home.md** | Shorts publishing flow (public URLs), embed support (iframe snippets), key moment timeline pins, auto-captioning + template system, citation timestamp links |
|
||||
| **Data-Model.md** | `share_token` (String(16), unique-indexed) on GeneratedShort, `captions_enabled` (Boolean) on GeneratedShort, `shorts_template` (JSONB) on Creator. Migrations 026-028. |
|
||||
| **API-Surface.md** | 3 new endpoints: GET /api/v1/public/shorts/{share_token} (unauthenticated), GET/PUT /api/v1/admin/creators/{id}/shorts-template. `captions` param added to generate-shorts. Update total from ~71 to ~74. |
|
||||
| **Frontend.md** | ShortPlayer (public /shorts/:token), EmbedPlayer (chrome-free /embed/:videoId before AppShell), ChapterMarkers (12px circle pins, color-coded by content_type, active state), inline collapsible player on TechniquePage with bibliography seek, shared copyToClipboard utility, shared chatCitations.tsx + formatTime.ts utilities |
|
||||
| **Pipeline.md** | caption_generator.py (ASS karaoke subtitles from word-level timings, \k tags), card_renderer.py (ffmpeg lavfi drawtext cards, concat demuxer for intro/main/outro), parse_template_config normalizer, non-blocking enrichment pattern |
|
||||
| **Player.md** | Key moment pins (color-coded: technique=cyan, settings=amber, reasoning=purple, workflow=green), active-state highlighting, touch-friendly ::before hit areas, inline player on technique pages, embed player |
|
||||
| **Chat-Engine.md** | Citation video metadata propagation: source_video_id, start_time, end_time, video_filename in search results and SSE source events. Batch-fetch SourceVideo filenames. Timestamp badge links to /watch/:id?t=N |
|
||||
|
||||
### New Content by Feature
|
||||
|
||||
**S01 — Shorts Publishing Flow:**
|
||||
- share_token column (secrets.token_urlsafe(8)), generated at pipeline completion
|
||||
- Alembic 026: add column + backfill existing + unique index
|
||||
- Public endpoint GET /api/v1/public/shorts/{share_token} — unauthenticated, returns metadata + presigned MinIO URL
|
||||
- Returns 404 for both missing and non-complete shorts (no status leaking)
|
||||
- ShortPlayer.tsx at /shorts/:token — public page outside ProtectedRoute
|
||||
- Share link (🔗) and embed code (📋) copy buttons on HighlightQueue for completed shorts
|
||||
|
||||
**S02 — Key Moment Pins:**
|
||||
- ChapterMarkers.tsx: 12px circle pins replacing 3px line markers
|
||||
- Color-coded by content_type via --color-pin-{type} CSS custom properties
|
||||
- Active-state highlighting (1.3x scale when playback within time range)
|
||||
- Tooltips: title + formatted time range + content type label
|
||||
- ::before pseudo-element with inset:-6px for touch-friendly hit areas
|
||||
- Inline collapsible player on TechniquePage between summary and body sections
|
||||
- Multi-source-video selector dropdown for multi-video technique pages
|
||||
- Bibliography time links → seek buttons when inline player active, Links otherwise
|
||||
|
||||
**S03 — Embed Support:**
|
||||
- EmbedPlayer.tsx at /embed/:videoId — chrome-free (no header/nav/footer)
|
||||
- Route registered at top-level Routes before AppShell catch-all
|
||||
- Video/audio support with content-type-aware height (120px audio, 405px video)
|
||||
- "Powered by Chrysopedia" branding link with noopener
|
||||
- Copy Embed Code button on WatchPage with audio-aware iframe snippet
|
||||
- Shared copyToClipboard utility extracted to utils/clipboard.ts
|
||||
|
||||
**S04 — Auto-Captioning + Template System:**
|
||||
- caption_generator.py: ASS subtitles with \k karaoke tags, word-by-word highlighting from Whisper word timings
|
||||
- card_renderer.py: ffmpeg lavfi (color + drawtext) card generation, anullsrc silent audio for codec-compatible concat
|
||||
- build_concat_list + concat_segments: ffmpeg concat demuxer for intro/main/outro assembly
|
||||
- parse_template_config: JSONB normalizer with defaults
|
||||
- Non-blocking: caption/card failures log WARNING, never fail parent short
|
||||
- shorts_template JSONB on Creator model (Alembic 028)
|
||||
- captions_enabled Boolean on GeneratedShort (Alembic 027)
|
||||
- Admin API: GET/PUT /api/v1/admin/creators/{id}/shorts-template
|
||||
- Frontend: collapsible template config panel in HighlightQueue, per-highlight captions toggle
|
||||
- 45 unit tests (17 caption + 28 card)
|
||||
|
||||
**S05 — Citation UX Improvements:**
|
||||
- Backend: video metadata (source_video_id, start_time, end_time, video_filename) added to search_service enrichment and chat_service SSE source events
|
||||
- Batch-fetch SourceVideo filenames pattern (same as creator batch-fetch)
|
||||
- Frontend: chatCitations.tsx shared utility, formatTime.ts shared utility
|
||||
- Timestamp badge links to /watch/:id?t=N on source cards
|
||||
- Video filename metadata on source cards
|
||||
|
||||
### No New Decisions
|
||||
|
||||
M024 made no new registered decisions (no D04x entries). Existing decisions (D042-D044 from M023) already documented in prior KB update.
|
||||
|
||||
### Constraints
|
||||
|
||||
- **CRITICAL:** Never use Forgejo wiki PATCH API. Git clone → edit → push only (KNOWLEDGE.md).
|
||||
- Wiki repo URL: `https://git.xpltd.co/xpltdco/chrysopedia.wiki.git`
|
||||
- All SSH/git operations happen on ub01 via `ssh ub01`
|
||||
- Content must come from S01-S05 summaries — no fabrication
|
||||
- Current endpoint count: ~92 (from rg count of @router decorators across all routers)
|
||||
- Current wiki page count: 20
|
||||
|
||||
### Verification
|
||||
|
||||
1. `git push origin main` — exit code 0
|
||||
2. Wiki page count API — should remain 20 (no new pages, only updates)
|
||||
3. Spot-check one updated page via API
|
||||
109
.gsd/milestones/M024/slices/S06/tasks/T01-PLAN.md
Normal file
109
.gsd/milestones/M024/slices/S06/tasks/T01-PLAN.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
estimated_steps: 67
|
||||
estimated_files: 7
|
||||
skills_used: []
|
||||
---
|
||||
|
||||
# T01: Update 7 Forgejo wiki pages with M024 feature content
|
||||
|
||||
Clone the Chrysopedia Forgejo wiki on ub01, update Home.md, Data-Model.md, API-Surface.md, Frontend.md, Pipeline.md, Player.md, and Chat-Engine.md with M024 S01-S05 feature content, then commit and push.
|
||||
|
||||
**CRITICAL:** Never use the Forgejo wiki PATCH API — it corrupts pages (see KNOWLEDGE.md). Git clone → edit → push only.
|
||||
|
||||
All SSH/git operations happen on ub01 via `ssh ub01`.
|
||||
Wiki repo: `https://git.xpltd.co/xpltdco/chrysopedia.wiki.git`
|
||||
|
||||
## Content to add per page:
|
||||
|
||||
### Home.md
|
||||
Add to the feature list / recent additions:
|
||||
- Shorts publishing flow: public shareable URLs via /shorts/{token}, share_token generated at pipeline completion
|
||||
- Embed support: chrome-free /embed/:videoId player, iframe snippet with audio-aware height
|
||||
- Key moment timeline pins: 12px color-coded circle pins (technique=cyan, settings=amber, reasoning=purple, workflow=green), active-state highlighting, touch-friendly hit areas
|
||||
- Inline collapsible player on technique pages with bibliography seek wiring
|
||||
- Auto-captioning: ASS karaoke subtitles from Whisper word-level timings, \k tags for word-by-word highlighting
|
||||
- Template system: creator-configurable intro/outro cards via admin API, ffmpeg lavfi card rendering, concat demuxer assembly
|
||||
- Citation UX: timestamp badge links to /watch/:id?t=N, video filename on source cards, shared chatCitations.tsx + formatTime.ts utilities
|
||||
|
||||
### Data-Model.md
|
||||
Add new columns:
|
||||
- `share_token` (String(16), unique-indexed, nullable) on GeneratedShort — generated via secrets.token_urlsafe(8) at pipeline completion
|
||||
- `captions_enabled` (Boolean, default false) on GeneratedShort — indicates successful ASS subtitle generation
|
||||
- `shorts_template` (JSONB, nullable) on Creator — intro/outro card config with parse_template_config normalizer
|
||||
Add migrations: 026 (share_token + backfill + unique index), 027 (captions_enabled), 028 (shorts_template)
|
||||
|
||||
### API-Surface.md
|
||||
Add new endpoints:
|
||||
- `GET /api/v1/public/shorts/{share_token}` — unauthenticated, returns metadata + presigned MinIO URL, 404 for missing/non-complete shorts
|
||||
- `GET /api/v1/admin/creators/{id}/shorts-template` — returns JSONB template config
|
||||
- `PUT /api/v1/admin/creators/{id}/shorts-template` — updates template config with validation (hex color, duration 1.0-5.0)
|
||||
Update: `POST generate-shorts` now accepts `captions` boolean parameter
|
||||
Update endpoint total count (was ~92, now ~95)
|
||||
|
||||
### Frontend.md
|
||||
Add new pages/components:
|
||||
- ShortPlayer (`/shorts/:token`) — public page outside ProtectedRoute, fetches via unauthenticated API, renders video + metadata + share/embed copy buttons
|
||||
- EmbedPlayer (`/embed/:videoId`) — chrome-free, registered at top-level Routes before AppShell catch-all, content-type-aware height (120px audio, 405px video), "Powered by Chrysopedia" branding
|
||||
- ChapterMarkers upgrade: 12px circle pins replacing 3px lines, color-coded by content_type via --color-pin-{type} CSS custom properties, active-state 1.3x scale, ::before inset:-6px touch targets, tooltips with title + time range + content type
|
||||
- Inline collapsible player on TechniquePage between summary and body, grid-template-rows 0fr/1fr animation, multi-source-video selector, bibliography seek buttons
|
||||
Add shared utilities:
|
||||
- `utils/clipboard.ts` — shared copyToClipboard (navigator.clipboard + execCommand fallback)
|
||||
- `utils/chatCitations.tsx` — shared parseChatCitations replacing duplicate implementations
|
||||
- `utils/formatTime.ts` — shared hour-aware time formatter
|
||||
Add HighlightQueue updates: share link + embed code copy buttons, collapsible template config panel (intro/outro text, duration sliders, show/hide, color picker, font), per-highlight captions toggle
|
||||
|
||||
### Pipeline.md
|
||||
Add new modules:
|
||||
- `caption_generator.py`: generate_ass_captions() converts Whisper word-level timings to ASS subtitles with \k karaoke tags, clip-relative timing. Non-blocking — failures log WARNING, don't fail stage.
|
||||
- `card_renderer.py`: render_card() (lavfi color + drawtext), render_card_to_file() (ffmpeg executor), build_concat_list() + concat_segments() (ffmpeg concat demuxer), parse_template_config() (JSONB normalizer with defaults). Cards include anullsrc silent audio for codec-compatible concat.
|
||||
- `shorts_generator.py` updates: extract_clip() accepts optional ass_path for subtitle burn-in, extract_clip_with_template() for intro/main/outro concatenation
|
||||
- stage_generate_shorts updates: loads transcripts for captions, loads creator templates for cards, generates share_token on completion
|
||||
Note 45 unit tests (17 caption + 28 card)
|
||||
|
||||
### Player.md
|
||||
Add key moment pins section:
|
||||
- ChapterMarkers: 12px circle pins, color-coded (technique=cyan, settings=amber, reasoning=purple, workflow=green)
|
||||
- Active-state: 1.3x scale when playback within time range
|
||||
- Touch: ::before pseudo-element with inset:-6px
|
||||
- Tooltips: title + formatted time range + content type label
|
||||
Add inline player on technique pages:
|
||||
- Collapsible section between summary and body
|
||||
- Multi-source-video selector for multi-video technique pages
|
||||
- Bibliography time links render as seek buttons when inline player active, Links to WatchPage otherwise
|
||||
Add embed player:
|
||||
- /embed/:videoId — chrome-free, no header/nav/footer
|
||||
- Content-type-aware: video (405px) vs audio (120px)
|
||||
- "Powered by Chrysopedia" branding link with noopener
|
||||
|
||||
### Chat-Engine.md
|
||||
Add citation metadata propagation:
|
||||
- Backend: search_service enriches results with source_video_id, start_time, end_time, video_filename via batch-fetch of SourceVideo filenames
|
||||
- Backend: chat_service _build_sources() passes video fields through SSE source events
|
||||
- Frontend: ChatSource interface extended with video fields
|
||||
- Frontend: shared parseChatCitations() replaces duplicate citation parsers in ChatPage and ChatWidget
|
||||
- Frontend: timestamp badge links to /watch/:id?t=N on source cards
|
||||
- Frontend: video filename metadata on source cards
|
||||
|
||||
## Inputs
|
||||
|
||||
- ``~/.gsd/milestones/M024/slices/S01/S01-SUMMARY.md` — shorts publishing flow details`
|
||||
- ``~/.gsd/milestones/M024/slices/S02/S02-SUMMARY.md` — key moment pins details`
|
||||
- ``~/.gsd/milestones/M024/slices/S03/S03-SUMMARY.md` — embed support details`
|
||||
- ``~/.gsd/milestones/M024/slices/S04/S04-SUMMARY.md` — auto-captioning + template details`
|
||||
- ``~/.gsd/milestones/M024/slices/S05/S05-SUMMARY.md` — citation UX details`
|
||||
|
||||
## Expected Output
|
||||
|
||||
- ``Home.md` — updated with M024 feature summary`
|
||||
- ``Data-Model.md` — updated with share_token, captions_enabled, shorts_template columns and migrations 026-028`
|
||||
- ``API-Surface.md` — updated with 3 new endpoints and captions parameter`
|
||||
- ``Frontend.md` — updated with ShortPlayer, EmbedPlayer, ChapterMarkers upgrade, inline player, shared utilities`
|
||||
- ``Pipeline.md` — updated with caption_generator, card_renderer, shorts_generator changes`
|
||||
- ``Player.md` — updated with pin markers, inline player, embed player`
|
||||
- ``Chat-Engine.md` — updated with citation metadata propagation`
|
||||
|
||||
## Verification
|
||||
|
||||
1. `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && git log --oneline -1'` — shows M024 commit
|
||||
2. `ssh ub01 'curl -s https://git.xpltd.co/api/v1/repos/xpltdco/chrysopedia/wiki/pages -H "Authorization: token $(cat /vmPool/r/repos/xpltdco/.forgejo-token)" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))"'` — returns 20
|
||||
3. `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && grep -c share_token Data-Model.md'` — returns ≥1
|
||||
88
.gsd/milestones/M024/slices/S06/tasks/T01-SUMMARY.md
Normal file
88
.gsd/milestones/M024/slices/S06/tasks/T01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
id: T01
|
||||
parent: S06
|
||||
milestone: M024
|
||||
provides: []
|
||||
requires: []
|
||||
affects: []
|
||||
key_files: ["Home.md", "Data-Model.md", "API-Surface.md", "Frontend.md", "Pipeline.md", "Player.md", "Chat-Engine.md"]
|
||||
key_decisions: ["Used git clone/push for wiki updates per KNOWLEDGE.md (never use Forgejo wiki PATCH API)"]
|
||||
patterns_established: []
|
||||
drill_down_paths: []
|
||||
observability_surfaces: []
|
||||
duration: ""
|
||||
verification_result: "All 3 verification checks pass: git log shows M024 commit 0451abf, Forgejo API returns 20 wiki pages, grep finds share_token in Data-Model.md."
|
||||
completed_at: 2026-04-04T11:56:03.189Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T01: Updated 7 Forgejo wiki pages with M024 feature documentation covering shorts publishing, embed support, timeline pins, auto-captioning, templates, and citation UX
|
||||
|
||||
> Updated 7 Forgejo wiki pages with M024 feature documentation covering shorts publishing, embed support, timeline pins, auto-captioning, templates, and citation UX
|
||||
|
||||
## What Happened
|
||||
---
|
||||
id: T01
|
||||
parent: S06
|
||||
milestone: M024
|
||||
key_files:
|
||||
- Home.md
|
||||
- Data-Model.md
|
||||
- API-Surface.md
|
||||
- Frontend.md
|
||||
- Pipeline.md
|
||||
- Player.md
|
||||
- Chat-Engine.md
|
||||
key_decisions:
|
||||
- Used git clone/push for wiki updates per KNOWLEDGE.md (never use Forgejo wiki PATCH API)
|
||||
duration: ""
|
||||
verification_result: passed
|
||||
completed_at: 2026-04-04T11:56:03.190Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T01: Updated 7 Forgejo wiki pages with M024 feature documentation covering shorts publishing, embed support, timeline pins, auto-captioning, templates, and citation UX
|
||||
|
||||
**Updated 7 Forgejo wiki pages with M024 feature documentation covering shorts publishing, embed support, timeline pins, auto-captioning, templates, and citation UX**
|
||||
|
||||
## What Happened
|
||||
|
||||
Cloned the Chrysopedia Forgejo wiki on ub01, read all 5 slice summaries (S01-S05) for content details, updated Home.md, Data-Model.md, API-Surface.md, Frontend.md, Pipeline.md, Player.md, and Chat-Engine.md with comprehensive M024 feature documentation, then committed and pushed via git (per KNOWLEDGE.md rule to never use Forgejo wiki PATCH API).
|
||||
|
||||
## Verification
|
||||
|
||||
All 3 verification checks pass: git log shows M024 commit 0451abf, Forgejo API returns 20 wiki pages, grep finds share_token in Data-Model.md.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
| # | Command | Exit Code | Verdict | Duration |
|
||||
|---|---------|-----------|---------|----------|
|
||||
| 1 | `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && git log --oneline -1'` | 0 | ✅ pass | 500ms |
|
||||
| 2 | `ssh ub01 'curl -s .../wiki/pages | python3 -c "..."'` | 0 | ✅ pass | 800ms |
|
||||
| 3 | `ssh ub01 'cd /tmp/chrysopedia-wiki-m024 && grep -c share_token Data-Model.md'` | 0 | ✅ pass | 300ms |
|
||||
|
||||
|
||||
## Deviations
|
||||
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `Home.md`
|
||||
- `Data-Model.md`
|
||||
- `API-Surface.md`
|
||||
- `Frontend.md`
|
||||
- `Pipeline.md`
|
||||
- `Player.md`
|
||||
- `Chat-Engine.md`
|
||||
|
||||
|
||||
## Deviations
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
None.
|
||||
Loading…
Add table
Reference in a new issue