Spraaknotities met AI: zo zet BillableMe audio om in tekst met Whisper

Als freelancer krijg je de beste ideeën in de auto of op de werf, net wanneer typen niet lukt. Daarom kreeg BillableMe spraaknotities: je spreekt een to-do, herinnering of notitie in, en een halve minuut later staat de tekst erbij, doorzoekbaar. Zo heb ik dat aangepakt.

De eisen

  • Audio blijft op mijn eigen server, zonder externe transcriptiedienst.
  • Nederlands en Engels, met automatische taaldetectie.
  • Geen GPU: het moet draaien op de bestaande Docker Swarm.
  • De gebruiker wacht nooit op de transcriptie.

Stap 1: opnemen in Flutter

De app neemt op met het record-package in AAC (m4a), vraagt de microfoonpermissie en laat je meteen een categorie, een vlag en een titel kiezen. Het bestand gaat als multipart-upload naar de NestJS-API. Vanaf dat moment staat de notitie in de lijst, met de status “wordt verwerkt”.

Stap 2: een wachtrij in plaats van wachten

De API bewaart het audiobestand op een gedeeld volume, maakt een record aan in PostgreSQL en zet een job op een Bull-wachtrij in Redis. De HTTP-call is daarmee klaar in een fractie van een seconde. Een worker pikt de job op, roept de transcriptiedienst aan en probeert het bij een fout tot drie keer opnieuw met oplopende wachttijd. De status gaat van pending naar processing naar completed of failed.

Stap 3: een eigen Whisper-dienst in Python

De transcriptie zelf gebeurt in een kleine FastAPI-service met OpenAI Whisper. Ik koos het base-model: 74 MB, ongeveer 30 seconden per minuut audio op een CPU, en ruim voldoende voor gesproken notities in het Nederlands en het Engels. De modelgrootte is een omgevingsvariabele, zodat ik kan opschalen naar small of medium als de hardware het toelaat. ffmpeg zit mee in de container om m4a te decoderen.

Stap 4: terug in de app

Zodra de tekst in de databank staat, toont de app hem onder de notitie. Je kan de opname afspelen op 0,75 tot 1,5 keer de snelheid, de notitie bewerken, filteren per categorie of periode en zoeken in de transcripties.

Wat ik eruit leerde

  • Kies het kleinste model dat goed genoeg is. Het small-model is op CPU drie keer trager dan base; voor korte gesproken notities was base ruim voldoende.
  • Asynchroon is geen luxe. Dertig seconden wachten in een mobiele app voelt als een eeuwigheid. Een wachtrij met een zichtbare status maakt het vanzelfsprekend.
  • Houd de audio lokaal. Eén gedeeld volume tussen de API en de Whisper-service volstaat. De opnames verlaten de server nooit.

Wil je een gelijkaardige AI-functie in je eigen app? Neem contact op.