feat: implement authentication control with support for BYO API keys, episode deduplication, and a task queue for async processing.
This commit is contained in:
+84
-146
@@ -1,21 +1,21 @@
|
||||
# Product Requirements Document (PRD): Be My Anchor
|
||||
|
||||
**Status**: Approved (Post Grill-Me)
|
||||
**Target Version**: 2.0 (Full Refactor)
|
||||
**Architecture**: TypeScript / Node.js Fullstack
|
||||
**Status**: Approved
|
||||
**Target Version**: 2.0 (Listening-First Audio Platform)
|
||||
**Architecture**: TypeScript / Next.js Fullstack
|
||||
**Primary Output**: `docs/prd.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary & Vision
|
||||
|
||||
**Be My Anchor** transforms written materials—technical blogs, research papers, news articles, novels, and documentation—into an engaging, listening-first multimedia experience.
|
||||
**Be My Anchor** transforms written materials—technical blogs, research papers, news articles, essays, and documentation—into an engaging, listening-first audio experience.
|
||||
|
||||
Rather than relying on brittle, heavy web scrapers or monotone text-to-speech readers, Be My Anchor adopts an **API-first ingestion** model combined with:
|
||||
Rather than relying on brittle web scrapers or monotone text-to-speech readers, Be My Anchor adopts an **API-driven ingestion** model combined with:
|
||||
|
||||
1. **High-Fidelity Audio Generation**: Seamless multi-provider TTS (Edge TTS, OpenAI, ElevenLabs) with smart text chunking and audio stitching.
|
||||
1. **High-Fidelity Audio Generation**: Multi-provider neural TTS (Edge TTS, OpenAI, ElevenLabs) with smart text chunking and audio stitching.
|
||||
2. **Hearing-Front Content Adaptation**: An LLM-powered scriptwriting engine that adapts dense text into conversational spoken formats (e.g., Feynman-style technical breakdown or 2-host conversational dialogue).
|
||||
3. **Synchronized Visual Companion**: A web player that dynamically surfaces referenced figures, diagrams, and code snippets in sync with the audio narration.
|
||||
3. **Mobile-First Zen Listening Experience**: A distraction-free PWA listening environment with uninterrupted playback, synchronized auto-scrolling transcript, and tap-to-seek navigation.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +26,7 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
│ Phase 1: Robust Audio Generation Core │
|
||||
│ - Multi-provider TTS (Edge TTS, OpenAI, ElevenLabs) │
|
||||
│ - Long-form text chunking & audio stitching │
|
||||
│ - Basic web player & episode library │
|
||||
│ - Persistent audio player & episode library │
|
||||
└──────────────────────────────┬──────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
@@ -34,15 +34,15 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
│ Phase 2: Hearing-Front Content Transformation │
|
||||
│ - "Feynman" Deep-Dive Presenter Persona │
|
||||
│ - Dual-Host Dialogue Persona (NotebookLM style) │
|
||||
│ - Script stage cue tagging │
|
||||
│ - Synchronized sentence & speaker timing manifests │
|
||||
└──────────────────────────────┬──────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phase 3: Interactive Synchronized Multimedia Player │
|
||||
│ - Timestamped visual cues (figures, code, diagrams) │
|
||||
│ - Karaoke-style synced transcript │
|
||||
│ - Stage-aware responsive visual pane │
|
||||
│ Phase 3: Mobile PWA & Zen Listening Experience │
|
||||
│ - Fullscreen Zen player with synchronized transcript │
|
||||
│ - Mobile PWA & MediaSession background lockscreen controls │
|
||||
│ - Dedicated article studio and queue status tracking │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -53,14 +53,12 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
### Persona 1: The Engineer / Researcher ("The Feynman Mode")
|
||||
|
||||
- **Content**: Technical architecture posts, RFCs, research papers, algorithm deep-dives.
|
||||
- **Narrator Style**: A world-class communicator (like Richard Feynman or a top tech lead) explaining concepts using intuitive analogies, breaking down equations, and explaining diagrams.
|
||||
- **Visual Need**: When the narrator says *"Looking at Figure 2, the ingress traffic routes through..."*, Figure 2 automatically appears on screen.
|
||||
- **Narrator Style**: A world-class communicator (like Richard Feynman or a top tech lead) explaining concepts using intuitive analogies and breaking down dense material for the ear.
|
||||
|
||||
### Persona 2: The Informed Professional ("The Dual-Host Dialogue")
|
||||
|
||||
- **Content**: Industry news, opinion pieces, market shifts, newsletters.
|
||||
- **Narrator Style**: Two AI co-hosts bantering, asking each other rhetorical questions, and adding contextual background not directly present in the source article.
|
||||
- **Visual Need**: Highlight cards, quotes, and source citations appearing on the dashboard.
|
||||
- **Narrator Style**: Two AI co-hosts bantering, asking each other questions, and adding contextual background not directly present in the source article.
|
||||
|
||||
### Persona 3: The Audiobook / Direct Listener ("Verbatim Mode")
|
||||
|
||||
@@ -74,7 +72,7 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
```
|
||||
┌────────────────────────────┐
|
||||
│ API Ingestion Endpoint │
|
||||
│ (Markdown / Text / Assets) │
|
||||
│ (Markdown / Text Input) │
|
||||
└─────────────┬──────────────┘
|
||||
│
|
||||
▼
|
||||
@@ -82,11 +80,9 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
│ Hearing-Front Script Engine│
|
||||
│ (LLM: OpenAI / Claude) │
|
||||
│ - Rewrites text for ear │
|
||||
│ - Generates Stage Cues │
|
||||
│ - Speaker turn separation │
|
||||
└─────────────┬──────────────┘
|
||||
│
|
||||
Script with Stage Marks
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────┐
|
||||
│ TTS Generation Core │
|
||||
@@ -97,25 +93,28 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
│ │ ElevenLabs (Multi-Voice│ │
|
||||
│ └────────────────────────┘ │
|
||||
│ - Chunker & Audio Stitcher │
|
||||
│ - Timing Aligner (VTT/JSON)│
|
||||
│ - Timing Aligner (JSON) │
|
||||
└─────────────┬──────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────┴───────────────────────────────────┐
|
||||
│ Data & Storage │
|
||||
│ - Database: Prisma ORM (MongoDB / PostgreSQL) │
|
||||
│ - File Storage: Local static / S3-compatible (Audio MP3s & Figures) │
|
||||
│ - Database: Prisma ORM (SQLite / PostgreSQL) │
|
||||
│ - File Storage: Local static / S3-compatible (Audio MP3s) │
|
||||
└───────────────────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────────────┐
|
||||
│ Interactive Web Player (Next.js / TS) │
|
||||
│ Mobile-First Web App (Next.js / TS / PWA) │
|
||||
│ ┌───────────────────────┐ ┌───────────────────────────────────────┐ │
|
||||
│ │ Audio Player UI │ │ Synchronized Visual Stage │ │
|
||||
│ │ - Waveform / Scrubber│ │ - Figures / Diagrams from post │ │
|
||||
│ │ - Speed / ±15s Skips │ │ - Syntax-highlighted code snippets │ │
|
||||
│ │ - Live Transcript │ │ - Key takeaway summary cards │ │
|
||||
│ │ Main Index View │ │ Zen Mode Player │ │
|
||||
│ │ - Episode list │ │ - Fullscreen distraction-free player │ │
|
||||
│ │ - Live status pills │ │ - Synchronized auto-scrolled script │ │
|
||||
│ │ - Persistent bar │ │ - Tap-to-seek, large touch controls │ │
|
||||
│ └───────────────────────┘ └───────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Dedicated Add Article View (/new) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -123,56 +122,45 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
|
||||
## 5. Functional Requirements
|
||||
|
||||
### 5.1 Content Ingestion (API-Driven)
|
||||
### 5.1 Content Ingestion (API & UI Driven)
|
||||
|
||||
- Provide a clean REST API accepting:
|
||||
- Clean REST API & dedicated UI accepting:
|
||||
- `title`: String
|
||||
- `content`: Plain text or Markdown (including image references ``)
|
||||
- `format_mode`: `'feynman'` | `'dual_host'` | `'verbatim'`
|
||||
- `content`: Plain text or Markdown
|
||||
- `mode`: `'VERBATIM'` | `'FEYNMAN'` | `'DUAL_HOST'`
|
||||
- `voice_config`: Provider preference (`edge` | `openai` | `elevenlabs`), voice IDs, speed
|
||||
- `supplemental_materials`: Optional array of images/figures, captions, and links
|
||||
- No requirement for headless Selenium or browser dependencies on the server.
|
||||
|
||||
### 5.2 Hearing-Front Content Transformation
|
||||
|
||||
- **Verbatim Cleaner**: Strips markdown artifacts, normalizes punctuation, phonetic hints for acronyms.
|
||||
- **Feynman Script Generator**:
|
||||
- Rewrites technical content into an oral lecture/walkthrough.
|
||||
- Generates `[STAGE: figure_id]` or `[STAGE: code_block_id]` inline tags corresponding to visual assets.
|
||||
- **Dual-Host Dialogue Generator**:
|
||||
- Turns article content into an interactive conversation between Host A (e.g., inquisitive, relatable) and Host B (e.g., domain expert).
|
||||
- Emits speaker-tagged lines: `SpeakerA: ...` and `SpeakerB: ...`.
|
||||
- **Verbatim Cleaner**: Strips markdown artifacts, normalizes punctuation, phonetic hints.
|
||||
- **Feynman Script Generator**: Rewrites technical content into an oral lecture/walkthrough.
|
||||
- **Dual-Host Dialogue Generator**: Turns article content into an interactive conversation between Host A and Host B with speaker-tagged turns (`SpeakerA: ...`, `SpeakerB: ...`).
|
||||
|
||||
### 5.3 TTS Engine & Audio Processing
|
||||
|
||||
- **Provider Abstraction Interface (`ITextToSpeechProvider`)**:
|
||||
- `EdgeTTSProvider`: Free, instant, high-quality neural voices (`en-US-ChristopherNeural`, `en-US-JennyNeural`, etc.), zero API key required.
|
||||
- `EdgeTTSProvider`: Free, instant neural voices (`zh-CN-XiaoxiaoNeural`, `en-US-ChristopherNeural`, etc.).
|
||||
- `OpenAITTSProvider`: `alloy`, `echo`, `fable`, `onyx`, `nova`, `shimmer`.
|
||||
- `ElevenLabsProvider`: High-fidelity multi-voice assignment with voice cloning or distinct character voices for multi-host dialogue.
|
||||
- **Long-Text Chunker**:
|
||||
- Breaks script into sentence/clause chunks respecting provider character limits (e.g. 4096 chars).
|
||||
- Handles speaker switching in dual-host mode without awkward pauses.
|
||||
- **Audio Stitcher & Aligner**:
|
||||
- `ElevenLabsProvider`: High-fidelity multi-voice assignment for dual-host dialogue.
|
||||
- **Long-Text Chunker & Audio Stitcher**:
|
||||
- Breaks script into sentence/clause chunks respecting character limits.
|
||||
- Stitches chunk audio files into a unified master `.mp3`.
|
||||
- Outputs a timing manifest (`timings.json` or WebVTT) recording the start and end timestamp of each paragraph, speaker turn, and stage marker.
|
||||
- Generates synchronized sentence/turn timing manifests (`timingsJson`).
|
||||
|
||||
### 5.4 Synchronized Web View & Media Player
|
||||
### 5.4 3-View Mobile-First Listening Experience
|
||||
|
||||
- **Episode Library**:
|
||||
- List of generated episodes with duration, creation date, mode, and status (`processing`, `ready`, `failed`).
|
||||
- **Audio Player Controls**:
|
||||
- Play / Pause, Progress scrubber, Current time / Total duration.
|
||||
- Jump Back 15s (`-15s`), Jump Forward 15s (`+15s`).
|
||||
- Playback speed selection (0.8x, 1.0x, 1.25x, 1.5x, 2.0x).
|
||||
- **Synchronized Transcript Pane**:
|
||||
- Interactive transcript that auto-scrolls and highlights the active paragraph/dialogue turn as audio plays.
|
||||
- Clicking any paragraph seeks playback directly to that timestamp.
|
||||
- **Synchronized Stage (Supplemental Visual Information)**:
|
||||
- Responsive visual viewport alongside or above the player.
|
||||
- When the audio reaches a tagged stage (e.g. timestamp 02:15):
|
||||
- Automatically displays the relevant figure, architecture diagram, equation, or code snippet.
|
||||
- Provides zoom/expand view for detailed inspection.
|
||||
- Gracefully transitions to summary notes when no specific figure is active.
|
||||
1. **Main Index View (`/`)**:
|
||||
- Episode list with live statuses (`QUEUED`, `PROCESSING`, `READY`, `FAILED`, `CANCELED`).
|
||||
- Card play/pause, duration, auto-polling while jobs are active.
|
||||
- Persistent bottom mini-player bar that never interrupts playing audio.
|
||||
2. **Zen Fullscreen Player**:
|
||||
- Toggled via full-screen button on persistent bar.
|
||||
- Synchronized transcript with active sentence highlighting and smooth auto-scroll.
|
||||
- Tap-to-seek anywhere in transcript.
|
||||
- Swipe-down gesture or minimize button to return to index without audio interruption.
|
||||
3. **Dedicated Add Article View (`/new`)**:
|
||||
- Standalone view for new posts with character/word count and duration estimation.
|
||||
- Extensible for future M2 settings (prompts, dual voices).
|
||||
|
||||
---
|
||||
|
||||
@@ -180,7 +168,7 @@ Rather than relying on brittle, heavy web scrapers or monotone text-to-speech re
|
||||
|
||||
```prisma
|
||||
datasource db {
|
||||
provider = "postgresql" // or "mongodb"
|
||||
provider = "sqlite" // or "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
@@ -188,46 +176,20 @@ generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
enum ProcessingStatus {
|
||||
PENDING
|
||||
SCRIPTING
|
||||
SYNTHESIZING
|
||||
READY
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum ScriptMode {
|
||||
VERBATIM
|
||||
FEYNMAN
|
||||
DUAL_HOST
|
||||
}
|
||||
|
||||
model Episode {
|
||||
id String @id @default(cuid()) @map("_id")
|
||||
id String @id @default(cuid())
|
||||
title String
|
||||
originalContent String
|
||||
scriptContent String?
|
||||
mode ScriptMode @default(FEYNMAN)
|
||||
status ProcessingStatus @default(PENDING)
|
||||
mode String @default("VERBATIM") // VERBATIM | FEYNMAN | DUAL_HOST
|
||||
status String @default("PENDING") // QUEUED | PROCESSING | READY | FAILED | CANCELED
|
||||
errorMessage String?
|
||||
durationSeconds Float?
|
||||
audioUrl String?
|
||||
timingsJson String? // Serialized timestamp cues
|
||||
timingsJson String? // Serialized array of cues [{text, startTime, endTime, speaker}]
|
||||
|
||||
stages StageItem[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model StageItem {
|
||||
id String @id @default(cuid()) @map("_id")
|
||||
episodeId String
|
||||
timestampSeconds Float
|
||||
type String // "IMAGE" | "CODE" | "CALLOUT"
|
||||
title String?
|
||||
content String // Image URL or Code snippet / Callout text
|
||||
caption String?
|
||||
|
||||
episode Episode @relation(fields: [episodeId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
@@ -241,72 +203,48 @@ Creates a new conversion job.
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Understanding Kubernetes Ingress Controllers",
|
||||
"title": "Understanding Kubernetes Ingress",
|
||||
"content": "# Markdown content...",
|
||||
"mode": "FEYNMAN",
|
||||
"ttsProvider": "edge",
|
||||
"voiceOptions": {
|
||||
"primaryVoice": "en-US-ChristopherNeural",
|
||||
"speed": 1.0
|
||||
},
|
||||
"visualAssets": [
|
||||
{
|
||||
"id": "fig-1",
|
||||
"type": "IMAGE",
|
||||
"url": "https://example.com/arch.png",
|
||||
"caption": "Figure 1: Ingress routing architecture"
|
||||
}
|
||||
]
|
||||
"mode": "VERBATIM",
|
||||
"provider": "edge",
|
||||
"voice": "en-US-ChristopherNeural"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**: `202 Accepted` with `{ "episodeId": "clx...", "status": "PENDING" }`.
|
||||
|
||||
### `GET /api/episodes/:id`
|
||||
|
||||
Retrieves episode details, audio URL, processing status, transcript timings, and stage markers.
|
||||
Retrieves episode details, audio URL, processing status, and transcript timings.
|
||||
|
||||
### `GET /api/episodes`
|
||||
|
||||
Lists all generated episodes for the library view.
|
||||
Lists all episodes for the index view.
|
||||
|
||||
### `DELETE /api/episodes/:id`
|
||||
|
||||
Deletes or cancels an episode.
|
||||
|
||||
---
|
||||
|
||||
## 8. Technical Stack
|
||||
## 8. Implementation Roadmap
|
||||
|
||||
| Component | Technology | Rationale |
|
||||
| --- | --- | --- |
|
||||
| **Runtime & Language** | Node.js (v20+) / TypeScript | Rapid prototyping, strong typing, zero Python venv/setup friction. |
|
||||
| **Framework** | Next.js (App Router) | Unified backend API routes + reactive frontend player in one repo. |
|
||||
| **Database & ORM** | Prisma + MongoDB or PostgreSQL | Lightweight document/relational storage matching user preference. |
|
||||
| **Audio Generation** | `msedge-tts`, OpenAI API, ElevenLabs SDK | Free zero-key tier (Edge) + premium commercial options. |
|
||||
| **Audio Processing** | `fluent-ffmpeg` or Web Audio APIs | Fast server-side audio stitching and silence injection. |
|
||||
| **LLM Orchestration** | Vercel AI SDK / OpenAI SDK | Streaming script generation and structured stage extraction. |
|
||||
| **Styling** | Tailwind CSS / Lucide Icons | Clean modern aesthetic, responsive audio controls. |
|
||||
### Phase 1: Core Audio Generation & Minimal Player (Completed)
|
||||
|
||||
---
|
||||
- [x] Next.js + TypeScript project structure and Prisma configuration.
|
||||
- [x] `ITextToSpeechProvider` interface with `EdgeTTSProvider` and `OpenAITTSProvider`.
|
||||
- [x] Long-text chunking, concatenation, and static file delivery.
|
||||
- [x] Basic synchronized transcript viewer and audio player.
|
||||
|
||||
## 9. Implementation Roadmap
|
||||
|
||||
### Phase 1: Core Audio Generation & Minimal Player (Week 1)
|
||||
|
||||
- [ ] Initialize Next.js + TypeScript project structure and Prisma configuration.
|
||||
- [ ] Implement `ITextToSpeechProvider` interface with `EdgeTTSProvider` and `OpenAITTSProvider`.
|
||||
- [ ] Build audio chunking, concatenation, and static file delivery.
|
||||
- [ ] Implement basic Web Player UI (Play/Pause, Scrubber, Episode list).
|
||||
|
||||
### Phase 2: Hearing-Front Script Engine (Week 2)
|
||||
### Phase 2: Hearing-Front Script Engine (Next)
|
||||
|
||||
- [ ] Implement prompt templates for:
|
||||
- Feynman Master Presenter (single host, conversational breakdown).
|
||||
- Feynman Master Presenter (conversational breakdown).
|
||||
- Dual-Host Dialogue (speaker-tagged turns).
|
||||
- [ ] Parse speaker tags and route chunks to distinct voices in the TTS pipeline.
|
||||
- [ ] Output synchronized paragraph/sentence timestamp manifests.
|
||||
|
||||
### Phase 3: Synchronized Visual Stages (Week 3)
|
||||
### Phase 3: Mobile PWA & Zen Listening Experience (Current)
|
||||
|
||||
- [ ] Extract or link visual assets (figures/diagrams/code) to script stages.
|
||||
- [ ] Build the interactive Stage Viewer in the web player:
|
||||
- Figure transitions locked to audio progress.
|
||||
- Interactive transcript with click-to-seek.
|
||||
- [ ] End-to-end testing with technical papers, blog posts, and news feeds.
|
||||
- [x] Global `AudioProvider` ensuring uninterrupted audio playback across all navigation.
|
||||
- [x] Fullscreen Zen Player with auto-scrolling synchronized transcript & tap-to-seek.
|
||||
- [x] Dedicated Add Article View (`/new`) for extensible settings.
|
||||
- [x] PWA manifest & mobile-responsive design for phone listening.
|
||||
|
||||
Reference in New Issue
Block a user