Maha Transcriber and Reader - speech to text and text to speech in one page. Keys stay on your device.
# Maha Transcriber and Reader Two tools that live in one page. **Transcribe** turns what you say into text. **Read** speaks text back to you and lights up each word as it is said. They sit side by side and you can send text from one to the other. **Open it:** https://markoboskoauroville.github.io/maha-transcriber-reader/ Nothing to install. Your keys stay on your own machine. --- ## First five minutes 1. Open the page. 2. Click the **gear** on the transcribe side. 3. **LOAD KEYS FROM FILE** and pick a plain text file from your disk that has your API keys in it. Any layout will do — see below. 4. Press **TEST ALL**. Keys that work say so. 5. Press **REC**, talk, press it again. The text appears and the page moves you to the transcribe tab. For reading you need no keys at all. Paste text into the **paste** tab and it starts speaking immediately in your computer's own voice. Better voices are one click away if you have a key — see below. --- ## Voices: eight providers, four free and four premium The reader speaks with your computer's own voice by default: no key, no network, no cost. Pick a different provider at the top of the **text** tab and load a key to upgrade. Each one was chosen against three tests rather than reputation. **Does it work from a browser at all?** Every provider here was checked with a real CORS preflight from this site. Hugging Face's inference API and Replicate send no allow-origin header, so a page cannot call them however good they are. They are not listed. **Does it speak Croatian?** Several of 2026's favourites — Cartesia, Deepgram Aura — are English-first. They are excellent and they are not here. **Is it honestly in its category?** "Free" means a real free tier or open weights, not a trial. ### Free | | why it is here | Croatian | |---|---|---| | **Browser** *(default)* | no key, offline, and the only engine that reports each word exactly as spoken | if your OS has a Croatian voice | | **Gemini TTS** | Google's free tier, expressive, and the same key the grammar buttons use | not listed; it will try | | **Groq PlayAI** | a genuinely free tier and the fastest of them all | no | | **DeepInfra Kokoro** | Kokoro-82M, open weights, pennies an hour | no | ### Premium | | why it is here | Croatian | |---|---|---| | **Azure Speech** | **Gabrijela and Srecko — the same voices the desktop app uses**, because edge-tts *is* this service. 140+ languages, cheapest premium option | **yes, two native voices** | | **ElevenLabs** | the most expressive voices made, 70+ languages | **yes** | | **OpenAI** | 50+ languages, and you describe how to read rather than marking up text | yes, English-tuned | | **Google Cloud TTS** | native Croatian neural voices, 1M free characters a month | **yes** | **If you read Croatian, use Azure.** It is the same voice you already know from the desktop app, and it is the cheapest of the four. **One honest limit.** Only the browser engine reports when each word is actually spoken. API voices arrive as finished audio, so words are placed against the clip's duration — accurate to about a word, and the interface says "word timing estimated" when that is what you are getting. The desktop build reads the waveform and lands within 8 ms. --- ## Cookies must be allowed, or the keys are forgotten There is no server, so there is nowhere else to keep your keys. They are stored in a **cookie on your own device**. If cookies are blocked for this site, the app still works but you will have to load the key file again on every visit, and an orange bar at the top will tell you so. **Allowing cookies:** * **Chrome / Edge** — click the icon at the left of the address bar → *Cookies and site data* → *Allow* * **Safari** — Settings → Privacy → untick *Block all cookies* * **Firefox** — the shield icon in the address bar → turn protection off for this site * **Brave** — the lion icon → *Shields down* for this site The cookie never leaves your browser. Keys are sent only to the provider they belong to — AssemblyAI or Google — and never to this site, which is a folder of static files with no back end at all. Press **FORGET KEYS** in settings to erase them. --- ## The key file Point the app at any text file. It reads the whole thing, picks out anything that looks like a key, sorts it by provider and ignores everything else. Notes, invoices, URLs and prose in the same file are all fine. ``` assemblyai 3d6bffd8aa11bb22cc33dd44ee55ae3e gemini AQ.Ab8RN6JxKqWvT2mHy... azure aabbccddeeff00112233445566778899 elevenlabs sk_0123456789abcdef... openai sk-proj-AbCdEfGh... groq gsk_kEsY... deepinfra ZyXwVuTsRqPoNmLkJiHgFeDcBa0123456 ``` Nine providers are recognised. **Azure and AssemblyAI keys are the same shape** — 32 hex characters — so nothing but the heading can tell them apart. Keep those two under headings and everything else sorts itself out. Headings are optional when the keys carry a recognisable prefix. **Two Gemini formats are both accepted.** Google is moving Gemini keys from the old `AIza…` Standard format to the new `AQ.Ab…` Auth format. New keys from AI Studio are already `AQ.`, unrestricted `AIza` keys began being refused in June 2026, and `AIza` Standard keys are due to stop working entirely in September 2026. Both shapes are recognised, and a key under a `gemini` heading is accepted whatever it looks like — the shape is a hint, never a gate. The provider decides, which is what **TEST ALL** asks it to do. A bare 32-character string of hex is AssemblyAI's format. It is also what an MD5, a git SHA and a UUID look like, so it is only taken when the file says so with a heading or the word on the line — or when the file names no provider at all and is therefore just a list of keys. This is the same file the desktop version uses. `~/Documents/maha_api_keys.txt` works in both. --- ## Using it | | | |---|---| | **SPLIT / TABS** | both apps at once, or one at a time | | **SWAP** | put the reader on the left | | **REC** | the pill *is* the record button — press, talk, press | | **X** | throw the recording away | | **SEND TO READER →** | hand the text across to the other side | | **paste** tab | read whatever is on the clipboard, straight away | | **edit** | change the words, then it re-reads them | Recording asks for microphone permission the first time. --- ## What this version cannot do Being a page rather than a program costs three things. The desktop version has them all. **No MP3 export.** The browser will not hand over the audio it synthesises, so there is nothing to save. **No audio shrinking.** The desktop version runs ffmpeg to reduce recordings to mono 16 kHz Opus, about 36× smaller, before uploading. A page has no ffmpeg. Recordings go up as the browser made them — already Opus, so the difference is smaller than it sounds, but uploads are slower on a weak connection. This is why there is no audio setting: an option that cannot do anything is worse than no option. **No queue.** If the network drops mid-upload the job fails and you press the button again. Nothing is lost, but nothing resumes by itself either. **Voices come from your operating system.** macOS and Windows ship Croatian. Some Linux and Android builds do not, and then only English appears. --- ## Files ``` index.html the shell: two frames and the top bar tx.html transcribe rd.html read keys.js the key parser and the cookie store app.js shared helpers app.css the shared stylesheet ``` The two apps are **separate documents in separate frames** on purpose. They share a stylesheet and nothing else — no ids, no scripts, no state. Two documents cannot leak into one another the way two halves of one page can, and that is the whole reason for the arrangement. They talk by `postMessage`, with the origin checked on both ends. See **HELP.md** for the longer walkthrough.