personal project — 2025

friday

A voice-first personal AI that filters your attention through your goals.

python openai realtime api websockets pwa
view on github →
friday_mk2.py
$ python friday_mk2.py
Loading Vosk wake word model...
Friday Mk2 Online — always listening.
 
Heard: friday
--- Conversation started ---
[realtime] Connected and ready.

what it is

I got tired of AI tools that forget everything between conversations. Friday holds your goals in context — so when you ask it to check your email, it tells you what's actually relevant, not just what arrived. Say “friday” from anywhere and it's instant. No clicking, no opening apps.

goals-first system prompt

your goals inject into every session, so responses are always filtered through what matters

always-on voice

a persistent websocket means no delay on wake — the conversation starts the moment it hears “friday”

mobile pwa

a cloudflare tunnel auto-starts on launch — https in seconds, installable to your home screen

persistent memory

facts from each conversation carry forward, tied to your active goals

how it works

the interesting parts

01

shared mic queue

Windows won't open the same audio device twice. My first version ran two separate streams that silently conflicted — nothing worked and I had no idea why.

The fix was one sd.RawInputStream feeding a thread-safe queue, with the realtime loop resampling on the fly via audioop.ratecv.

02

always-on websocket

Connecting to OpenAI's Realtime API takes 2–3 seconds. Opening a new connection on every wake word would feel broken.

Instead the connection stays open permanently. A flag flips when “friday” is heard and audio starts flowing — the conversation is instant.

03

tool executor

Things like fetching email or hitting the Govee API are slow. Running them inline would freeze the voice session.

A ThreadPoolExecutor runs tools off the event loop, and a flag pauses the silence timer so the session doesn't die mid-tool-call.

04

https in one command

Phone browsers block mic access without HTTPS, and certificates are a pain. So Friday just auto-starts a Cloudflare tunnel on launch.

The URL is parsed from stdout within a few seconds. Open it on your phone and the mic button works.

integrations

communication

  • Gmail — read, search, reply, send
  • Google Calendar — events + invites
  • Phone notifications via ntfy.sh

environment

  • Spotify — play, skip, volume
  • Govee smart lights — color + brightness
  • Weather — current + forecast

information

  • Web search via DuckDuckGo
  • News headlines + topic search
  • Live sports scores — ESPN API

productivity

  • Goals — persistent, priority-ranked
  • To-do list — sorted by goal alignment
  • Reminders — voice-set push notifications

tech stack

voice / aiOpenAI Realtime API — gpt-4o-mini-realtime
wake wordVosk — offline, no API key
audiosounddevice + audioop (stdlib resampling)
backendPython 3.11, asyncio, ThreadPoolExecutor
guipywebview + WebSockets
mobilePWA + Cloudflare Tunnel (auto-started)
apisGoogle (OAuth2), Govee, Spotipy, ESPN, ntfy.sh

see the code

full source on github — architecture, setup, and design decisions in the readme.

github.com/ethans-design/friday →