Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Start here
Concepts
Release notes
What's new
Elyra

Dictation

Félagi Desktop has a microphone. In a meeting somebody says a point aloud instead of typing it, and it lands as text in their own notes. The app records, and the recording becomes text through this server.

Then no key is on anybody's laptop: the desktop sends the transcription request it would have sent OpenAI, with the person's own API token, and the server adds its key, checks what is being sent, and passes the answer back.

Off by default, like the other places where Félagi's server calls a model (minutes, tidying up prose, the assistant — see Configuration). An installation that decided nothing sends nothing anywhere, and the desktop shows no microphone.


Turning it on

FELAGI_TRANSCRIPTION_PROVIDER=openai
OPENAI_API_KEY=sk-…

The key and the address are the AI SDK's own (OPENAI_API_KEY, and OPENAI_URL, which defaults to https://api.openai.com/v1). openai is the only provider: the desktop sends OpenAI's own request. Anything else, or no key, and the route answers 503 without calling anybody.

Variable Default
FELAGI_TRANSCRIPTION_PROVIDER empty — off openai turns it on
FELAGI_TRANSCRIPTION_MODELS whisper-1,gpt-4o-transcribe,gpt-4o-mini-transcribe The models the desktop may ask for, comma-separated. Anything else is a 422. The desktop asks for whisper-1
FELAGI_TRANSCRIPTION_MAX_KB 25600 The largest recording, in KB; larger is a 413. OpenAI takes up to 25 MB, and the desktop records at most five minutes, under 10 MB. PHP's own upload_max_filesize and post_max_size must allow it too
FELAGI_TRANSCRIPTION_PER_MINUTE 20 Requests per person per minute, across all their devices and tokens. Over it is a 429 with retry-after

GET /api/v1/me says whether it is on, as features.transcription.


The route

POST /api/elyra/transcription/v1/audio/transcriptions
Authorization: Bearer fat_…
Content-Type: multipart/form-data

file=@recording.wav  model=whisper-1  language=no

Elyra's contract (Backend::transcription() in the desktop, RFC 0032), not the API's, which is why it is outside /api/v1, beside the assistant's. Any of the person's API tokens, and the API's own rate limit applies as well. language is a hint, an ISO-639-1 code; anything else is left out rather than refused.

The answer is OpenAI's, unchanged: { "text": "…" }, or its error with its status and retry-after. On success the server dispatches App\Events\TranscriptionUsed — the person, the workspace, the model and the recording's size in bytes — and logs the same.

What is checked, in order

Every refusal is in OpenAI's error shape, which the desktop shows:

{ "error": { "type": "invalid_request_error", "message": "A recording is needed, as `file`." } }
Answer
Not switched on 503 server_error — Transcription isn't set up on the server. Nothing is sent anywhere
No token, or a bad one 401, as everywhere in the API
Over FELAGI_TRANSCRIPTION_PER_MINUTE 429 rate_limit_exceeded, with retry-after in seconds
A model not in FELAGI_TRANSCRIPTION_MODELS 422 invalid_request_error
No file 422 invalid_request_error
A recording above FELAGI_TRANSCRIPTION_MAX_KB 413 invalid_request_error
OpenAI cannot be reached, or does not answer in 120 seconds 502 server_error

What leaves the server

The recording: the person's voice, and whatever else the microphone heard while they held it. That is why this is off until an operator decides, and why the desktop says, beside the microphone, that a recording goes to the server and on to OpenAI.

Nothing is kept here. The recording is read from where PHP put it for the length of the request and passed on, and PHP removes it after. Neither it nor the text is stored or logged — only who, which model and how many bytes. The text goes back to the desktop, into the person's own notes, and is somebody else's to read only when they share it.