This HTTP Val converts text files to speech using Deepgram's TTS API with async callbacks to handle large files without timeouts.
- Set the
DEEPGRAM_API_KEY
environment variable in your Val Town settings - Set the
AUTH_TOKEN
environment variable for API authorization - The SQLite database tables will be created automatically on first use
The system uses Deepgram's TTS callback feature to handle large text files:
- Text Chunking: Large texts are split into chunks of ~900 characters
- Async Processing: Each chunk is submitted to Deepgram with a callback URL
- Callback Handling: Deepgram posts completed audio chunks to
/deepgram-callback
- Chunk Storage: Audio chunks are temporarily stored in blob storage with SQLite tracking
- Concatenation: A cron job checks for completed jobs and concatenates chunks into final MP3s
- Cleanup: Temporary chunk files are deleted after final MP3 creation
- Visit
/test
for a web interface to upload and convert text files - Or use the API endpoints directly (see below)
Web interface for testing file uploads and conversions.
Starts async text-to-speech conversion. Requires authorization.
Headers:
Authorization: Bearer YOUR_AUTH_TOKEN
Parameters:
file
(File): Text file to convertname
(string): Name/title for the episode
Example using curl:
curl -X POST https://your-val-url.web.val.run/convert \ -H "Authorization: Bearer your-auth-token-here" \ -F "file=@your-text-file.txt" \ -F "name=My First Episode"
Response:
{ "success": true, "message": "Text-to-speech conversion started", "data": { "job_id": "job_1234567890_abc123", "name": "My First Episode", "text_length": 1250, "status": "processing", "note": "Audio will be available once all chunks are processed. Check /job-status/:job_id for updates." } }
Check the progress of a conversion job.
Response:
{ "success": true, "job_id": "job_1234567890_abc123", "name": "My First Episode", "status": "completed", "progress": { "total_chunks": 3, "completed_chunks": 3, "failed_chunks": 0, "pending_chunks": 0, "percentage": 100 }, "mp3_url": "https://your-val-url.web.val.run/audio/tts_job_1234567890_abc123_1234567890.mp3", "created_at": "2024-01-01 12:00:00", "completed_at": "2024-01-01 12:05:00", "chunks": [ { "index": 0, "status": "completed", "completed_at": "2024-01-01 12:02:00", "error": null } ] }
Internal callback endpoint for Deepgram to post completed audio chunks. Not for direct use.
Serves MP3 audio files from storage.
Lists all converted episodes.
Get database statistics and cleanup information.
Manually trigger cleanup of old episodes. Requires authorization.
Generates an RSS podcast feed from all episodes. Requires authorization.
id
(INTEGER PRIMARY KEY)name
(TEXT) - Episode titletext
(TEXT) - Original text contentmp3_url
(TEXT) - URL to the final MP3 filetext_length
(INTEGER) - Length of original textchunk_count
(INTEGER) - Number of chunks processeddate_added
(DATETIME) - Timestamp when added
id
(INTEGER PRIMARY KEY)job_id
(TEXT UNIQUE) - Unique job identifiername
(TEXT) - Episode titletext
(TEXT) - Original text contenttext_length
(INTEGER) - Length of original textchunk_count
(INTEGER) - Number of chunksstatus
(TEXT) - Job status: 'processing', 'completed', 'failed'created_at
(DATETIME) - When job was createdcompleted_at
(DATETIME) - When job was completedmp3_url
(TEXT) - Final MP3 URL when completed
id
(INTEGER PRIMARY KEY)job_id
(TEXT) - References jobchunk_index
(INTEGER) - Order of chunk in sequencechunk_text
(TEXT) - Text content of chunkaudio_blob_key
(TEXT) - Blob storage key for audio chunkstatus
(TEXT) - 'pending', 'completed', 'failed'created_at
(DATETIME) - When chunk was createdcompleted_at
(DATETIME) - When chunk was completederror_message
(TEXT) - Error details if failed
- Frequency: Every few minutes (configurable in Val Town UI)
- Purpose: Checks for completed jobs and concatenates audio chunks
- Actions:
- Finds jobs where all chunks are completed
- Downloads and concatenates audio chunks
- Creates final episode records
- Cleans up temporary chunk files
- Handles failed jobs and cleanup
- Frequency: Weekly
- Purpose: Removes old episodes and associated files
- Actions: Same as before - cleans up episodes older than 30 days
- ✅ Async Processing: No timeout issues with large files
- ✅ Chunk-based: Handles files of any size by splitting into chunks
- ✅ Progress Tracking: Real-time status updates via job status endpoint
- ✅ Automatic Concatenation: Seamlessly combines chunks into final audio
- ✅ Error Handling: Robust error handling and recovery
- ✅ Cleanup: Automatic cleanup of temporary files and old jobs
- ✅ Authorization: Protected endpoints for content creation
- ✅ SQLite Storage: Reliable job and chunk tracking
- ✅ Blob Storage: Efficient audio file storage
- POST /convert: Requires
Authorization: Bearer YOUR_TOKEN
header - POST /deepgram-callback: Validates
dg-token
header matchesDEEPGRAM_API_KEY
- GET /podcast.xml: Requires
?key=YOUR_TOKEN
query parameter - All other endpoints (episodes list, audio serving, test page, job status) are public
- Uses Deepgram's
aura-2-draco-en
TTS model - Text is automatically chunked at ~900 characters with sentence boundary detection
- Audio chunks are temporarily stored during processing
- Final MP3 files are stored permanently in Val Town's blob storage
- Jobs older than 1 hour are automatically cleaned up if stuck
- All endpoints include proper error handling and logging