AI projects
AI project · 2026

Transcription and dictation,
running locally on a MacBook Air

Two Mac apps that turn Danish and English speech into text with speakers, timestamps and editing. Everything runs on the machine itself: no cloud and no subscription. Built in a week with Claude Code, with me as product owner, test lead and quality judge.

  • Claude Code
  • Python
  • Swift
  • MLX
  • Whisper
  • pyannote
The transcription app showing a project meeting with three speakers. Each paragraph has a speaker and timestamp, and the word being played is highlighted.The transcription app showing a project meeting with three speakers. Each paragraph has a speaker and timestamp, and the word being played is highlighted.
A project meeting with three speakers. The text follows the audio word by word, and yellow marks where two people spoke at once.
7 days
from first test to two apps in daily use
€0/month
replaces a cloud subscription
100% local
the audio never leaves the Mac
106 tests
automated tests of the core
01 Starting point

A subscription I wanted to drop, and a workflow it didn't fit

I record meetings, calls and interviews, always with the participants' knowledge, because accurate notes are worth a lot. For that I paid for a cloud service.

I wanted three things it didn't give me: better Danish, full control over the recordings and a tool built around how I actually use the text. It almost always ends up in a conversation with a language model, where I turn it into minutes, task lists and drafts.

Accuracy over speed
A wrong word in the minutes is worse than waiting a few extra minutes.
Local only
No cloud and no paid APIs. Recordings of other people stay on my machine.
Ordinary hardware
A MacBook Air M2 with 8 GB of memory and no fan. Not a workstation.
02 The result

Two apps that work together

Dock app

Transcription

Drop in an audio file. Out comes text with speakers, a timestamp for every word and audio that follows along in the text.

  • Danish and English
  • Automatic speaker separation
  • Edit text and speakers, undo with ⌘Z
  • Copy for an LLM with one button
Menu bar app

Dictation

Hold the left ⌥ key, speak and release. The text appears wherever the cursor is, in any app.

  • Same Danish model as transcription
  • Double-tap ⌥ for long dictations
  • The clipboard is preserved
  • The model stays in memory between dictations
Transcript of a phone call where Torben asks if the call may be recorded and the client agrees
A client call. Recording is agreed before the conversation starts. (The app's interface is in Danish.)
The New transcription dialog with title, names and terms, language and number of speakers
New recording: language, number of speakers and names the language model should know how to spell.

All people, companies and conversations in the images are fictional. The images are real screenshots of the app.

03 Method

The AI wrote the code. I made sure it was the right code.

The project was built in close collaboration with Claude Code. My role was the one you have as a producer or DoP on a production: knowing what needs to be made, and being able to tell whether it is good enough.

A Spec

Phases with acceptance criteria

Before a single button was built, three questions had to be answered with numbers: Can the Danish model run on the Mac's GPU? Is it accurate enough on my own recordings? Is it fast enough? Only then came the interface.

B Measurement

Numbers instead of impressions

Every test logs the error rate against the previous service, the time for each phase and memory use. Timestamps are in local time, so runs can be compared across days.

C Judge

A human decides who is right

An error rate only shows where two transcripts disagree, not who is right. So we built a listening page where I judged the biggest disagreements myself, without knowing which model was behind each.

04 Decisions

Decisions made on data

A selection of the choices that shaped the app. Several of them are a no to something that sounded like a good idea.

01

English

QuestionWhich model should transcribe English?

TestThree models on a 42-minute English recording. A blind listening test of the 40 biggest disagreements: Parakeet was right 24 times, the two Whisper variants 6 times each.

DecisionParakeet for English. The Danish Whisper model for Danish, as it also handles English passages without translating them.

02

Silence

QuestionWhisper invents text when nobody is speaking.

TestOn one recording the model wrote "Ace." 337 times during four minutes of silence. Three fixes tested; two of them also removed real speech.

DecisionCautious speech detection before transcription. Anything skipped is shown in the text, so you can listen and include it.

03

Vocabulary

QuestionCan the model spell names correctly if it gets them in advance?

TestNames given to the model as a prompt, both as a list and as a sentence: 20–50 words disappeared, invented sentences appeared, and the name was not fixed.

DecisionDropped for the model. The vocabulary is sent to the language model in the export instead, where it actually helps.

04

AI clean-up

QuestionShould a language model clean up the text automatically?

TestErrors that a language model turns into something plausible become invisible to anyone who doesn't read the full text themselves.

DecisionDropped. The export leaves the text unchanged but tells the language model which kinds of errors to expect.

05

Dictation

QuestionWhich engine gives the fastest dictation without losing accuracy?

TestSeven variants of two engines on 12 clips. An 8-bit version of the model produced text identical to the original on every clip, at half the size.

DecisionThe 8-bit model on the Mac's GPU. The alternative engine (whisper.cpp) was uninstalled again.

06

Speed

QuestionWhy does a short dictation suddenly take 18 seconds?

TestThe measurements showed it wasn't the model: other apps had pushed it out of memory.

DecisionLower memory use (1.8 → 1.0 GB) and a warm-up that runs while you speak.

05 Details

Built so you can trust the text

Review uncertain words

Tab jumps between words the model was unsure about and plays exactly that piece of audio. Fix, press ↩, next.

Reviewing an uncertain word with playback and a field to correct it
Review 1 of 3: the word plays while you correct it.

Fix all at once

Correct a name, and the app offers to fix the same word everywhere else. Unchanged words keep their timestamps.

A field correcting the word Casper to Kasper with a Fix all 2 button
"Casper" becomes "Kasper" in both places with one click.

What is skipped stays visible

Passages without clear speech are not just removed. They stay in the text with Listen and Transcribe, so nothing disappears in silence.

Interview transcript with two dashed boxes: 41 seconds and 1 minute 16 seconds without clear speech
Interview: camera set-up before and during the recording is skipped, but visible.

Copy for an LLM

One button puts the whole transcript on the clipboard with a note for the language model: which errors to expect, how speakers were detected, and how names are spelled.

# Telefonmøde: brief fra Nordhavn Bryghus

Om dette transskript: Automatisk dansk transskription, lavet lokalt med Whisper. Den kan indeholde fejlhørte ord, især navne, tal og fagudtryk. Opdelingen i talere er lavet automatisk ud fra stemmerne og kan være forkert enkelte steder. Brugeren har oplyst disse navne og fagord, som kan forekomme: Nordhavn Bryghus, Mette Aagaard.

Varighed: 00:18:40 · Talere: Torben, Mette Aagaard

---

[00:00:02] Torben: Hej Mette, det er Torben. Tak fordi du havde tid.

[00:00:08] Mette Aagaard: Hej! Ja, selvfølgelig.

[00:00:11] Torben: Inden vi går i gang: Er det i orden, at jeg optager samtalen? Den bliver kun transskriberet lokalt på min egen computer, så jeg kan lave et præcist referat bagefter.

[00:00:24] Mette Aagaard: Ja, det er helt fint. Det er da smart.
Excerpt from the export of the fictional client call (in Danish, as the app produces it).
06 Dictation

Speak instead of typing, in any app

Illustration: an email where a dictated paragraph has just been inserted, with the menu bar app showing it is recording
Illustration: the microphone in the menu bar turns red while recording, and the text lands in the email.

Dictation is a small menu bar app using the same Danish model. It is built for everyday use: on a Danish keyboard ⌥ is also used for @ and {, so recording only starts when the key is held on its own. The text is inserted at the cursor, and whatever was on the clipboard is put back afterwards.

  • Hold ⌥record while the key is held
  • ⌥ ⌥lock recording for long dictations
  • Esccancel
  • Danish or English, chosen in the menu
07 Technology

From audio file to editable text

  1. 01Audioffmpeg, 16 kHz mono
  2. 02Speech foundSilero VAD skips silence
  3. 03Speech to textDanish Whisper on MLX · Parakeet for English
  4. 04Speakerspyannote finds who speaks when
  5. 05Mergeevery word gets a speaker and a timestamp
  6. 06Edit and exporteditor, Markdown, text and LLM
Models
  • Whisper (Danish fine-tune)
  • NVIDIA Parakeet
  • pyannote community-1
  • Silero VAD
Code
  • Python
  • MLX
  • FastAPI
  • JavaScript
  • Swift / AppKit
  • WKWebView
Quality
  • pytest (106 tests)
  • Playwright
  • jiwer (WER/CER)
  • blind listening tests
Way of working
  • Claude Code
  • spec-driven phases
  • small commits
08 Status

In use every day

Both apps are in daily use. Half an hour of audio with several speakers takes about 13 minutes on an 8 GB MacBook Air without a fan, and the accuracy was approved by listening against the service it replaces.

The hard part wasn't getting AI to write code. It was asking the right questions, insisting on measurements and saying no to solutions that looked good but didn't hold up when tested on real recordings.

AI can measure where two transcripts disagree. Deciding who is right still takes a human who listens.
Contact

Got a production or a role where this fits?

I live near Aarhus and am happy to work hybrid. Drop me an email and let's talk.