Heartbeat: Update docs and remove old skill
This commit is contained in:
parent
b23fd9f876
commit
93555dfb7b
@ -1,113 +1,59 @@
|
|||||||
# Daily Digest Podcast - PRD & Roadmap
|
# Daily Digest Podcast - PRD & Roadmap
|
||||||
|
|
||||||
## Current State (What We Have)
|
## Current State
|
||||||
|
|
||||||
### ✅ Built & Working
|
### ✅ DONE - What's Built & Working
|
||||||
- TTS generation (3 providers: OpenAI, Piper, macOS say)
|
- TTS generation (macOS say - built-in, no external API)
|
||||||
- Audio storage in Supabase (`podcast-audio` bucket)
|
- Audio mixing with ffmpeg (Intro → Speech → Outro)
|
||||||
- RSS feed endpoint (`/api/podcast/rss`)
|
- Music files in `blog-creator/public/podcast-audio/`
|
||||||
- Database schema (`audio_url`, `audio_duration`)
|
- Environment config set up
|
||||||
- Daily digest workflow at 7am CST
|
- Daily digest workflow at 7am CST
|
||||||
|
- **TESTED:** Audio generated successfully with music!
|
||||||
### ⚠️ Not Working / Disabled
|
|
||||||
- TTS generation is OFF (`ENABLE_TTS=false`)
|
|
||||||
- No music layering yet
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## TODO: Music Layering Feature
|
## What's Left to Do
|
||||||
|
|
||||||
### What We Need
|
### 1. Integrate TTS into Daily Digest Cron
|
||||||
|
- [ ] The 7am cron creates digest but doesn't auto-generate audio
|
||||||
|
- [ ] Need to add TTS call to the daily-digest workflow
|
||||||
|
|
||||||
1. **Intro/Outro Music Files**
|
### 2. Refine Audio Mixing (Optional)
|
||||||
- Store MP3 files somewhere (Supabase Storage or local)
|
- [ ] Current: Simple concat with volume adjustment
|
||||||
- Need: 5-10 sec intro, 5-10 sec outro
|
- [ ] Could add crossfades for smoother transitions
|
||||||
|
- [ ] Could add background music bed under speech
|
||||||
2. **Audio Mixing with ffmpeg**
|
|
||||||
- Layer: Intro → TTS Speech → Outro
|
|
||||||
- Optional: Background music under speech (lower volume)
|
|
||||||
|
|
||||||
3. **Environment Config**
|
|
||||||
- `INTRO_MUSIC_URL` - Path to intro file
|
|
||||||
- `OUTRO_MUSIC_URL` - Path to outro file
|
|
||||||
- `BACKGROUND_MUSIC_URL` - Optional background track
|
|
||||||
- `MUSIC_VOLUME` - Background volume (0.1-0.3)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Implementation Plan
|
## Configuration (Already Set)
|
||||||
|
|
||||||
### Phase 1: Basic TTS (Quick Win)
|
|
||||||
- [ ] Enable TTS in `.env.production`
|
|
||||||
- [ ] Test with OpenAI provider
|
|
||||||
- [ ] Verify audio appears on blog
|
|
||||||
|
|
||||||
### Phase 2: Music Files
|
|
||||||
- [ ] Source or create intro/outro music
|
|
||||||
- [ ] Upload to Supabase Storage bucket
|
|
||||||
- [ ] Add URLs to environment config
|
|
||||||
|
|
||||||
### Phase 3: Audio Mixing
|
|
||||||
- [ ] Add ffmpeg dependency
|
|
||||||
- [ ] Create mixing function in `tts.ts`
|
|
||||||
- [ ] Mix: Intro + TTS + Outro
|
|
||||||
- [ ] Optional: Background music layer
|
|
||||||
|
|
||||||
### Phase 4: Production
|
|
||||||
- [ ] Deploy with music mixing enabled
|
|
||||||
- [ ] Test full pipeline
|
|
||||||
- [ ] Verify RSS includes mixed audio
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Reference
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `src/lib/tts.ts` | TTS generation (add mixing here) |
|
|
||||||
| `src/lib/storage.ts` | Audio file upload/download |
|
|
||||||
| `src/app/api/tts/routeTS API endpoint |
|
|
||||||
| `src/app/api/digest/r.ts` | Toute.ts` | Digest creation + TTS trigger |
|
|
||||||
| `.env.production` | TTS config (ENABLE_TTS, TTS_PROVIDER, etc.) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configuration Variables
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Local TTS (macOS built-in)
|
# blog-backup .env.local
|
||||||
ENABLE_TTS=true
|
ENABLE_TTS=true
|
||||||
TTS_PROVIDER=macsay
|
TTS_PROVIDER=macsay
|
||||||
|
|
||||||
# Music Files - LOCAL PATHS (no external hosting)
|
|
||||||
INTRO_MUSIC_URL=/Users/mattbruce/Documents/Projects/OpenClaw/Web/blog-backup/public/podcast-audio/intro.mp3
|
|
||||||
OUTRO_MUSIC_URL=/Users/mattbruce/Documents/Projects/OpenClaw/Web/blog-backup/public/podcast-audio/outro.mp3
|
|
||||||
|
|
||||||
# Enable music mixing
|
|
||||||
ENABLE_PODCAST_MUSIC=true
|
ENABLE_PODCAST_MUSIC=true
|
||||||
|
INTRO_MUSIC_URL=/Users/mattbruce/Documents/Projects/OpenClaw/Web/blog-creator/public/podcast-audio/intro.mp3
|
||||||
|
OUTRO_MUSIC_URL=/Users/mattbruce/Documents/Projects/OpenClaw/Web/blog-creator/public/podcast-audio/outro.mp3
|
||||||
```
|
```
|
||||||
|
|
||||||
### File Locations
|
---
|
||||||
- **Intro:** `blog-backup/public/podcast-audio/intro.mp3`
|
|
||||||
- **Outro:** `blog-backup/public/podcast-audio/outro.mp3`
|
## File Locations
|
||||||
- **Generated Audio:** Stored in Supabase `podcast-audio` bucket (optional, can use local)
|
|
||||||
|
| Component | Location |
|
||||||
|
|-----------|----------|
|
||||||
|
| PRD | `~/.openclaw/workspace/docs/PODCAST_PRD.md` |
|
||||||
|
| Skills | `blog-creator/skills/daily-digest/` |
|
||||||
|
| Intro Music | `blog-creator/public/podcast-audio/intro.mp3` |
|
||||||
|
| Outro Music | `blog-creator/public/podcast-audio/outro.mp3` |
|
||||||
|
| TTS + Mixing Code | `blog-backup/src/lib/tts.ts` |
|
||||||
|
| Daily Digest API | `blog-backup/src/app/api/digest/route.ts` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Blockers
|
## Test Result
|
||||||
|
|
||||||
~~1. **No intro/outro music files** - Need to source or create~~
|
**Test successful!** Generated audio file:
|
||||||
~~2. **ffmpeg not installed on Vercel** - May need local-only generation or custom build~~
|
- URL: `https://qnatchrjlpehiijwtreh.supabase.co/storage/v1/object/public/podcast-audio/tts-1772476798520.mp3`
|
||||||
|
- Duration: 108 seconds
|
||||||
### Phase 1: Basic TTS - COMPLETE ✅
|
- Contains: Intro music + TTS speech + Outro music
|
||||||
- [x] Enable TTS in `.env.production`
|
|
||||||
- [x] Using macOS say (built-in, no external API)
|
|
||||||
- [x] Verify audio appears on blog
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Questions to Answer
|
|
||||||
|
|
||||||
1. Do you have intro/outro music already, or should we source it?
|
|
||||||
2. Prefer OpenAI TTS or Piper (local/free)?
|
|
||||||
3. Want background music under speech, or just intro/outro?
|
|
||||||
|
|||||||
@ -1,223 +0,0 @@
|
|||||||
---
|
|
||||||
name: daily-digest
|
|
||||||
description: Daily digest creation workflow - research, format, and publish to blog. Runs at 7am daily. Uses Tavily for research, formats with proper title, publishes to blog API. NO Vercel mentions ever.
|
|
||||||
---
|
|
||||||
|
|
||||||
# daily-digest
|
|
||||||
|
|
||||||
**Orchestrator Skill** - Creates and publishes the daily digest to blog.twisteddevices.com.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Run every morning at 7am CST to:
|
|
||||||
1. Research top stories in target categories via Tavily
|
|
||||||
2. Extract content from top articles
|
|
||||||
3. Format digest with proper title format
|
|
||||||
4. Publish to blog API (NOT Vercel - no Vercel notes ever!)
|
|
||||||
5. Handle duplicates gracefully
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export BLOG_API_URL="https://blog.twisteddevices.com/api"
|
|
||||||
export BLOG_MACHINE_TOKEN="21719c689a355e40b427a35c548b28699bd7c014aac4d23f5c1bbb122bbb9878"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Title Format (MANDATORY)
|
|
||||||
|
|
||||||
**ALWAYS use this exact format:**
|
|
||||||
```
|
|
||||||
## Daily Digest - <FULL_DATE>
|
|
||||||
|
|
||||||
Example: ## Daily Digest - Monday, March 2, 2026
|
|
||||||
```
|
|
||||||
|
|
||||||
- Day of week: Full name (Monday, Tuesday, etc.)
|
|
||||||
- Month: Full name (January, February, March, etc.)
|
|
||||||
- Day: Number (1, 2, 3, etc.)
|
|
||||||
- Year: 4-digit year (2026)
|
|
||||||
|
|
||||||
**CRITICAL:** This format is required - never use any other title format!
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### Step 1: Check for Existing Digest
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source ~/.agents/skills/blog-backup/lib/blog.sh
|
|
||||||
|
|
||||||
TODAY=$(date +%Y-%m-%d)
|
|
||||||
if blog_post_status "$TODAY"; then
|
|
||||||
echo "Digest already exists for today - delete it first"
|
|
||||||
# Get existing ID and delete
|
|
||||||
EXISTING=$(curl -s "$BLOG_API_URL/messages?date=eq.$TODAY" -H "Authorization: Bearer $BLOG_MACHINE_TOKEN" | jq -r '.[0].id')
|
|
||||||
if [ -n "$EXISTING" ]; then
|
|
||||||
blog_post_delete "$EXISTING"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Research Categories
|
|
||||||
|
|
||||||
Research these 4 categories using Tavily:
|
|
||||||
1. **iOS/Apple AI** - iOS development, Apple AI, Swift
|
|
||||||
2. **AI Coding Assistants** - Claude Code, Cursor, AI coding tools
|
|
||||||
3. **OpenClaw/AI Agents** - OpenClaw updates, AI agent news
|
|
||||||
4. **Entrepreneurship** - Indie hacking, startups, side projects
|
|
||||||
|
|
||||||
**Tavily search commands:**
|
|
||||||
```bash
|
|
||||||
cd ~/.openclaw/workspace
|
|
||||||
./tavily-search.sh "iOS 26 Apple AI development" -n 5
|
|
||||||
./tavily-search.sh "Claude Code Cursor AI coding assistant" -n 5
|
|
||||||
./tavily-search.sh "OpenClaw AI agents updates" -n 5
|
|
||||||
./tavily-search.sh "indie hacking entrepreneurship startup" -n 5
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Extract Top Articles
|
|
||||||
|
|
||||||
For each category, extract 2-3 articles using Tavily or direct content extraction.
|
|
||||||
|
|
||||||
**Target:** 7-10 articles total across 4 categories
|
|
||||||
|
|
||||||
### Step 4: Format Digest Content
|
|
||||||
|
|
||||||
**Use this template:**
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Daily Digest - <FULL_DATE>
|
|
||||||
|
|
||||||
### iOS & Apple AI News
|
|
||||||
|
|
||||||
**[Article Title]**
|
|
||||||
|
|
||||||
[2-3 sentence summary]
|
|
||||||
|
|
||||||
[Read more](URL)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AI Coding Assistants
|
|
||||||
|
|
||||||
**[Article Title]**
|
|
||||||
|
|
||||||
[2-3 sentence summary]
|
|
||||||
|
|
||||||
[Read more](URL)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### OpenClaw & AI Agents
|
|
||||||
|
|
||||||
**[Article Title]**
|
|
||||||
|
|
||||||
[2-3 sentence summary]
|
|
||||||
|
|
||||||
[Read more](URL)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Entrepreneurship & Indie Hacking
|
|
||||||
|
|
||||||
**[Article Title]**
|
|
||||||
|
|
||||||
[2-3 sentence summary]
|
|
||||||
|
|
||||||
[Read more](URL)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Generated by OpenClaw*
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Publish to API
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source ~/.agents/skills/blog-backup/lib/blog.sh
|
|
||||||
|
|
||||||
TODAY=$(date +%Y-%m-%d)
|
|
||||||
FULL_DATE=$(date +"%A, %B %-d, %Y") # e.g., "Monday, March 2, 2026"
|
|
||||||
|
|
||||||
# Prepend title to content
|
|
||||||
CONTENT="## Daily Digest - $FULL_DATE
|
|
||||||
|
|
||||||
$ARTICLE_CONTENT"
|
|
||||||
|
|
||||||
# Create digest
|
|
||||||
DIGEST_ID=$(blog_post_create \
|
|
||||||
--date "$TODAY" \
|
|
||||||
--content "$CONTENT" \
|
|
||||||
--tags '["daily-digest", "iOS", "AI", "Apple", "OpenClaw"]')
|
|
||||||
|
|
||||||
echo "Digest created: $DIGEST_ID"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: Handle Duplicates
|
|
||||||
|
|
||||||
**BEFORE publishing, check and remove existing digest for today:**
|
|
||||||
```bash
|
|
||||||
# Check for existing
|
|
||||||
EXISTING=$(curl -s "$BLOG_API_URL/messages?date=eq.$TODAY" \
|
|
||||||
-H "Authorization: Bearer $BLOG_MACHINE_TOKEN" | jq -r '.[0].id // empty')
|
|
||||||
|
|
||||||
if [ -n "$EXISTING" ]; then
|
|
||||||
echo "Deleting existing digest: $EXISTING"
|
|
||||||
curl -s -X DELETE "$BLOG_API_URL/messages" \
|
|
||||||
-H "x-api-key: $BLOG_MACHINE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"id\": \"$EXISTING\"}"
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cron Configuration
|
|
||||||
|
|
||||||
**Schedule:** Every day at 7:00 AM CST (America/Chicago)
|
|
||||||
|
|
||||||
**Environment variables required:**
|
|
||||||
```bash
|
|
||||||
export BLOG_API_URL="https://blog.twisteddevices.com/api"
|
|
||||||
export BLOG_MACHINE_TOKEN="21719c689a355e40b427a35c548b28699bd7c014aac4d23f5c1bbb122bbb9878"
|
|
||||||
export TAVILY_API_KEY="your-tavily-key" # if not auto-loaded
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Issues
|
|
||||||
|
|
||||||
### "No digest found" after posting
|
|
||||||
- The API endpoint for status check uses `/messages`, not `/digest`
|
|
||||||
- Check directly: `curl -s "$BLOG_API_URL/messages?date=eq.$TODAY"`
|
|
||||||
|
|
||||||
### Duplicate digests
|
|
||||||
- ALWAYS delete existing digest before creating new one
|
|
||||||
- Use the duplicate check Step 6 above
|
|
||||||
|
|
||||||
### Vercel deployment issues
|
|
||||||
- **NEVER mention Vercel in the digest content**
|
|
||||||
- The blog is hosted on Vercel but we don't talk about that
|
|
||||||
- If there's an infrastructure issue, handle it silently
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
```
|
|
||||||
~/.agents/skills/daily-digest/
|
|
||||||
├── SKILL.md # This file
|
|
||||||
└── lib/
|
|
||||||
└── daily-digest.sh # Helper functions (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run the full workflow
|
|
||||||
source ~/.agents/skills/daily-digest/lib/daily-digest.sh
|
|
||||||
run_daily_digest
|
|
||||||
```
|
|
||||||
|
|
||||||
Or manually run each step following the workflow above.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**REMEMBER:**
|
|
||||||
- Title format: `## Daily Digest - <FULL_DATE>`
|
|
||||||
- NO Vercel mentions
|
|
||||||
- Delete duplicates before posting
|
|
||||||
- Use blog API (not Vercel CLI)
|
|
||||||
Loading…
Reference in New Issue
Block a user