About the Buffalo Bark Machine
A 2018 text-to-speech demo, still alive in 2026
What This Is
You type some text, pick a "buffalo dialect" (really an
Amazon Polly voice),
click "Say it!", and a few seconds later a playable MP3 of that text
in that voice shows up in the results table. Every post gets a UUID;
you can search them back later by ID, or use * to list
everything in the database.
Originally built in 2018 following an AWS reference architecture for serverless text-to-speech. Backend went dark sometime between then and now (the DynamoDB table got deleted at some point), revived in 2026 with the Lambdas migrated from Python 2.7 to 3.12.
Architecture at a Glance
Single-headed arrows are one-way (publish / upload / trigger); double-headed arrows are request/response. The numbered sequence matches the "What happens when you click Say it!" steps below.
What Happens When You Click "Say it!"
-
The browser POSTs
{voice, text}as JSON to the API Gateway endpoint. -
API Gateway invokes PostReader_NewPosts. The
Lambda generates a UUID, writes a new row to the
postsDynamoDB table withstatus: "PROCESSING", then publishes the UUID as a message to theNew_PostsSNS topic. Returns the UUID to the browser. - SNS fans out the message to its only subscriber: PostReader_ConvertToAudio. (This decoupling means NewPosts can return the post ID immediately without waiting on Polly.)
-
ConvertToAudio looks up the row in DynamoDB, splits the text into
~1,000-character blocks (Polly's per-call limit), and calls
Polly.synthesize_speechon each block. The audio streams are concatenated into a single MP3 file in/tmp/. -
The MP3 is uploaded to S3 (
pollymp3pail/<uuid>.mp3) with a public-read ACL, and the DynamoDB row is updated:status: "UPDATED"with the S3 URL. -
Later, when you "Search" by post ID (or
*), PostReader_GetPosts queries / scans the table and returns the rows. The browser renders each row as a table entry; if aurlis present it embeds an<audio>player pointing at the S3 MP3.
Tech Stack
| Layer | Tools |
|---|---|
| Frontend | Static HTML + jQuery 3.7.1 (only the bark page uses jQuery; everything else on the site is plain JS) |
| API layer | AWS API Gateway (REST, regional) |
| Compute | 3 × AWS Lambda (Python 3.12) — PostReader_NewPosts, PostReader_GetPosts, PostReader_ConvertToAudio |
| Speech synthesis | Amazon Polly (~40 voices across a dozen languages) |
| Message bus | Amazon SNS topic New_Posts (one subscriber: the audio-worker Lambda) |
| Database | Amazon DynamoDB table posts (on-demand billing, single hash key id) |
| Audio storage | Amazon S3 bucket pollymp3pail — public objects, no CDN in front |
Hosting & Cost
Entirely AWS free-tier at the volume this thing actually sees (single-digit requests per month, most months zero). The only line items that ever bill are pennies for S3 storage of accumulated MP3s and DynamoDB on-demand reads. Estimated cost: $0/month, rounding up.
Because everything is serverless / on-demand, there's nothing running when nobody's using it. Cold-start latency on the Lambdas is around 300–500ms; a full POST-to-MP3-ready round trip takes 3–6 seconds.
Source Code
All of it — HTML, client JS, Lambda sources, README —
lives in one directory:
github.com/JackVance/bigolbuffalo/tree/main/src/BuffaloBarkMachine