uncloseai.
Open-Source Speech-to-Text
Speech-to-Text
uncloseai-speech listens as well as speaks: send any recording to POST https://speech.ai.unturf.com/v1/audio/transcriptions and get its words back, with word timestamps or ready-made subtitles. Free, no API keys, and OpenAI-compatible: model stt-1-parakeet also answers to whisper-1.
We recommend Parakeet for listening (CPU or GPU) and F5-TTS for speaking. Your audio stays on our own hardware, never a browser vendor's or a cloud speech API.
Try It
Tap our microphone and speak, or pick an audio file (up to 25 MB).
Recommended: Parakeet
NVIDIA Parakeet TDT 0.6B v3 (CC-BY-4.0), run through onnx-asr. 25 languages detected automatically, with punctuation: Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Ukrainian.
| Runs on | Memory | Speed |
|---|---|---|
| CPU (fp32) | ~2.4 GB RAM | ~25x realtime |
| GPU (fp16, our prod) | ~1.7 GB VRAM | ~140x realtime: 84 s of audio in about a second |
Word error rate on LibriSpeech test-clean through our production settings: 1.93% on 200 short utterances and 2.69% on 12 long recordings, with no sentences lost. fp16 matches fp32. Never use int8: our test build lost up to 41 percent of words on long audio.
Quick Start
curl https://speech.ai.unturf.com/v1/audio/transcriptions -F file=@clip.wav -F model=whisper-1
# {"text":"but the windows are patched with wooden panes, and the door, I think, is like the gate. It is never opened.","usage":{"type":"duration","seconds":8.03}}
curl https://speech.ai.unturf.com/v1/audio/transcriptions -F file=@talk.mp4 -F response_format=srt -o talk.srt
from openai import OpenAI
client = OpenAI(api_key="not-needed", base_url="https://speech.ai.unturf.com/v1")
print(client.audio.transcriptions.create(model="whisper-1", file=open("meeting.mp3", "rb")).text)
words = client.audio.transcriptions.create(
model="whisper-1", file=open("meeting.mp3", "rb"),
response_format="verbose_json", timestamp_granularities=["word"],
).words
// Browser, with uncloseai.js loaded
const text = await window.uncloseai.transcribeAudio(audioBlob);
const mic = window.uncloseai.createMicButton(document.querySelector("textarea"));
API Reference
| Field | Values |
|---|---|
file | Required. Any audio or video ffmpeg reads (wav, mp3, m4a, mp4, ogg, webm, flac), up to 25 MB. |
model | stt-1-parakeet (default), whisper-1, parakeet-tdt-0.6b-v3 |
response_format | json (default), text, verbose_json, srt, vtt |
timestamp_granularities[] | With verbose_json: segment (default), word |
language | Optional and echoed back; Parakeet detects language itself. |
Segments are whole sentences, so subtitles read cleanly. Real verbose_json, trimmed:
{
"duration": 8.03,
"text": "but the windows are patched with wooden panes, and the door, I think, is like the gate. It is never opened.",
"segments": [
{"id": 0, "start": 0.436, "end": 6.436, "text": "but the windows are patched with wooden panes, and the door, I think, is like the gate."},
{"id": 1, "start": 6.436, "end": 8.03, "text": "It is never opened."}
],
"words": [{"word": "but", "start": 0.436, "end": 0.596}, {"word": "the", "start": 0.596, "end": 0.756}]
}
Errors return HTTP 400 with JSON (undecodable audio, unknown model, over 25 MB). Silent clips return empty text.
Self-Hosting
Transcription ships in uncloseai-speech beside F5-TTS. On any Linux CPU:
git clone https://git.unturf.com/engineering/unturf/uncloseai-speech.git
cd uncloseai-speech
make apt-deps && make venv && make venv-run # F5-TTS + Parakeet on :8000
make test
For GPU transcription set STT_DEVICE=cuda with onnxruntime-gpu matching torch's CUDA version; it falls back to CPU if CUDA cannot start. NVIDIA, AMD and Mac setup live in our README (AGPL v3).
Questions & Community
Ask questions, share your deployments, or tell us how transcription works for your language below!