← Back to Case Studies
AI & Automation

AI Policy & Tech Regulation Radio

I built a 24/7 livestream that watches eight government and research feeds, summarises the new policy and research, and reads it out loud with a two-voice AI radio show. Five of my other tools are stitched together to make it work.

Project Type Personal Project
Timeline ~3 months (active iteration)
Category AI & Automation
Year 2026

01 The Challenge

AI policy moves fast. Bills get introduced in the US, EU, and UK every week. arXiv drops new papers daily. CISA publishes advisories. The Federal Register shows new proposed rules. None of these streams talk to each other, and I was missing most of them.

I wanted something that would just tell me what happened in AI policy and research, all day, without me having to check eight different sites. I did not want a Twitter bot. I did not want another newsletter. I wanted a radio.

The constraint: it had to run locally. No cloud bills, no API quotas, no scraped content being repackaged. I wanted a 24/7 station I could run on my own machine, pointed at OBS, that produced real coverage of the AI policy and research beat.

02 The Solution

I built a Node.js service that polls eight free, public-domain or open-government sources every five minutes, deduplicates what comes in, runs any PDFs through DeepSeek-OCR via Ollama, summarises the result with a local LLM at temperature 0.1 (so it does not hallucinate), and pipes each item into a queue. A separate worker pulls from the queue, asks Pocket TTS to render the announcement, and saves the WAV to disk. A WebSocket pushes the new item to a browser dashboard.

The dashboard is a 50/50 split. Left side: a Leaflet map with a marker that flies to the geocoded location of each new item, with a dark CartoDB tile layer. Right side: the content card (source badge, relative timestamp, category tag, the two-or-three-sentence summary, and a "breaking" animation if the item is high-priority). Below: a queue stats panel and the latest TTS audio file. The whole thing is designed to be dropped into OBS as a 1920x1080 browser source.

The show has two voices. The main anchor (Abigail, on Pocket TTS's "azelma" voice) reads the headline and the body of each story. After a beat, a second voice (Alba, on "alba") interjects with a short commentary. The interjections come from a small set of personality templates I wrote, not from the LLM, so they are reliable and on-brand. It sounds like a two-host local radio show, not a Siri reading the news.

03 The Architecture

The codebase is twelve separate Node modules with single responsibilities. Each one has its own job, its own config file, and its own error handling. Nothing is jammed into a single 800-line server file.

  • rss-aggregator.js, fetches and parses all eight feeds, deduplicates, geocodes by source
  • content-processor.js, detects PDFs and images, hands them to DeepSeek-OCR via Ollama, writes a fact-based summary at temperature 0.1
  • tts-generator.js, the Pocket TTS client. (Soprano and OpenAI are supported as alternative providers in the config, but Pocket TTS is the default because it runs locally for free.)
  • queue-manager.js, a 100-item rotating queue, smart promotion for breaking items, auto-cleanup of old entries
  • ollama-helper.js, the wrapper around the local Ollama server, retries, timeouts, model switching
  • short-generator.js, a tool for producing shareable 30-second clips from a single queue item, for posting elsewhere
  • show-clock.js, controls item duration, rotation timing, inter-voice pauses
  • entity-extractor.js and entity-graph.js, pull people, companies, and bills out of each item so related stories cluster on the map
  • sentiment-analyzer.js, a small classifier that drives the breaking-news animation when something is high-stakes
  • context-aware-summarizer.js, summarises with awareness of recent queue items so a new story can be framed against the previous one (e.g. "this follows yesterday's FTC ruling on...")
  • server.js, the orchestrator. HTTP routes, WebSocket broadcast, cron jobs, the lot

The configuration is split into eight small files in config/: ai.js, rss.js, feeds.js, feeds-by-category.js, ollama.js, tts.js, show-clock.js, server.js, plus a state.js and an intervals.js. Adding a new RSS feed is a one-line edit to feeds.js. Changing the rotation speed is a one-line edit to intervals.js. Nothing leaks between modules.

04 The Components I Built This From

The radio is the first project where I have stitched together five of my other tools into one production system. It is not a from-scratch build. It is integration work. That is the point: each of the pieces was a focused experiment, and the radio is where they all earn their keep.

  • The TTS pipeline comes from my work on AJVV Studio (see the VibeVoice case study). I swapped VibeVoice out for Pocket TTS as the runtime default, but the API surface and the streaming pattern are the same.
  • The OCR step uses the same DeepSeek-OCR pipeline I built into DocuLift, just pointed at RSS-attached PDFs instead of a folder watcher.
  • The local LLM call is a thin wrapper around Ollama, which is also what powers Nyaomi (the self-modifying AI companion) and the Soprano VRChat bridge.
  • The WebSocket broadcast pattern is the same one from the Would You Rather Twitch bot, just pointed at an in-process client instead of OBS.
  • The sentiment and entity extraction are the smaller helpers I built while working on a much larger project (still in progress) and pulled out because they fit.

The radio is the proof that the pieces compose. Each module has one job, they do not fight each other, and the integration code is small.

05 What It Actually Does Day To Day

When the radio is running, the cycle is straightforward. Every five minutes the RSS aggregator fires and pulls anything new. Each new item is OCR'd if it has a PDF, summarised if it does not, scored for sentiment, geocoded, queued, and rendered as audio. The WebSocket pushes a content_update event to every connected browser, the dashboard swaps the right-side card, the map marker flies to the new location, the audio plays.

Memory usage sits around 150 to 200 MB, idle CPU is under 1 percent, network is roughly 1 to 2 MB per poll, audio cache auto-cleans every hour. I have had a single instance run for a full week straight without intervention. When I check the logs, the only thing I have ever needed to do is re-add a feed whose URL changed.

It is not a SaaS product and it does not pretend to be one. It is a local tool I built because I wanted it to exist, and I run it on my own machine. If you want to run it, the README and the INSTALL guide get you from git clone to a live OBS source in about twenty minutes. All eight feeds are public-domain or open-government, so the licensing is clean.

06 What I Would Do Differently

I would not start with the dashboard. I spent the first month on the Leaflet map, the dark theme, the smooth fly-to transitions. All of that is fun to build and none of it is the hard part. The hard part is the RSS-to-summary-to-TTS pipeline. Get that right first, then add the visual layer. The map should have been week four, not week one.

I would also invest in proper logging from day one. stdout is fine for a personal project, but once you are running something 24/7 you want structured JSON logs you can grep, with timestamps, request IDs, and queue depth at every state change. I added this in month two and it made debugging trivial compared to month one.

And the interjections. I have a small library of Alba's commentary lines. I should have written twice as many of them, and a small template language for generating variations on the fly. The current set works, but it loops after about thirty minutes of listening. The next iteration adds a generator that writes new interjections from the live queue and a separate filter for the ones that land well.

07 Status

The radio is in active use. I run it on a small box here in North London, mostly for my own consumption, and I have pointed a few people at the source if they want to stand up their own instance. The system is open and the code is not currently published as a public repo, but the README and the architecture doc on this site cover enough that anyone with the relevant experience could rebuild it.

If you want me to build a similar always-on system for a different beat (security advisories, financial regulation, internal company announcements, anything that comes from a fixed set of feeds), that is exactly the kind of work I do. Get in touch and we can talk through it.