TTSFM: an OpenAI-compatible TTS endpoint built on a reverse-engineered openai.fm backend
TTSFM mirrors OpenAI's TTS service, providing a compatible interface for text-to-speech conversion with multiple voice options for free.
At a glance
- What is it?
- TTSFM wraps the openai.fm service in a FastAPI-style server with an OpenAI-shaped /v1/audio/speech route, an 11-voice catalogue and a Docker image split that decides which audio features you actually get. It is an educational reverse-engineering project, not a production TTS vendor.
- Who is it for?
- Adopt TTSFM if you want a local endpoint that speaks the OpenAI /v1/audio/speech request shape and you accept that the audio ultimately comes from someone else's reverse-engineered service. Do not adopt it for a paid product, for anything requiring an uptime or content guarantee, or where you cannot accept the README's own educational-and-research restriction.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 103 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap TTSFM fills, and the one it does not
OpenAI's speech endpoint has a stable request shape: model, input, voice, response_format, and an optional speed. Any code written against it is short and easy to copy. The problem TTSFM addresses is what happens when you want that same call to work without an OpenAI key, or when you want to experiment with voices and formats locally before spending anything. The README describes the project as a free, OpenAI-compatible text-to-speech API service built on top of the openai.fm backend, with a Python SDK, REST endpoints and a web playground. The intended audience is developers who want a drop-in replacement for the OpenAI TTS call while testing, plus anyone who wants a browser page to hear the voices without writing code first.
The second half of that sentence matters more than the first. TTSFM does not synthesise speech. It is a client and a server in front of openai.fm, and the README is explicit that it is a reverse-engineered implementation of that service, intended for educational and research purposes only, not for commercial use or production. So the honest description of the problem solved is narrower than the tagline suggests: it removes the credential requirement and the boilerplate, not the dependency on an upstream service you do not control.
Request path: from your curl call to a combined audio file
The architecture visible in the material is a thin proxy with local post-processing. A request arrives at the container on /v1/audio/speech with an OpenAI-shaped JSON body. The server forwards the text and voice selection to the openai.fm backend, receives audio, and then, if the request needs it, applies local work before returning bytes to the caller. The docs directory includes an architecture overview at docs/architecture.md with component diagrams, which is where the exact internal boundaries are documented; the README itself only describes the outer behaviour.
Two pieces of that outer behaviour are worth naming. The first is long-text handling: the README states that content of any length is supported through automatic text splitting and audio combining. That means the server chunks your input, issues multiple upstream requests, and concatenates the resulting audio. The second is speed: adjustments between 0.25x and 4.0x are performed with ffmpeg-based audio processing rather than by asking the upstream service for a different rate. Both of these are local operations, and both are conditional on the image variant you deployed, which is the single most important structural fact about this project.
The full and slim images are two different products
TTSFM ships two Docker images, and the feature matrix between them is not a minor packaging detail. The full variant is documented as including ffmpeg and therefore all six audio formats (MP3, WAV, OPUS, AAC, FLAC, PCM), speed adjustment across the full 0.25x to 4.0x range, format conversion, and MP3 and WAV auto-combine for long text. The slim variant is described as roughly 100MB and minimal: basic TTS, MP3 and WAV only, WAV auto-combine for long text, and explicitly no speed adjustment, no format conversion, and no MP3 auto-combine.
Read that list again, because the asymmetry is odd. Long text works in both images, but when the requested format is MP3 the slim image cannot stitch the chunks back together. So a long MP3 request against the slim image either fails or returns something other than one continuous file, depending on how the error path is implemented. The README does not say which. If you are deploying this, the slim image is only safe when your inputs are short and your output format is WAV or a short MP3. The README recommends the full variant, and the feature list gives a concrete reason to follow that recommendation rather than a vague one.
Getting it running, and the endpoint that tells you what you got
Installation is two commands. For the Python package, pip install ttsfm for the core client, or pip install ttsfm[web] to pull in the web and server dependencies. For Docker, docker run -p 8000:8000 dbcccc/ttsfm:latest for the full image, or dbcccc/ttsfm:slim for the minimal one. The container serves the web playground at http://localhost:8000 and the OpenAI-compatible route at /v1/audio/speech.
Before you build anything on top, hit the capabilities endpoint: curl http://localhost:8000/api/capabilities. The v3.5.0 release notes describe this as a runtime capabilities API for checking feature availability, and it exists precisely because the two images differ. If your code assumes speed adjustment and you deployed slim, this call is how you find out at startup rather than in production.
From the Python side, the client is constructed with no arguments in the README example, and generate_speech takes text, voice, response_format and an optional speed. Voices and formats are exposed as enums (Voice.ALLOY, AudioFormat.MP3), and the response object has a save_to_file method that appends the extension. There is also a CLI: ttsfm "Hello, world" --voice nova --format mp3 --output hello.mp3. The REST example sends model as tts-1, which is a compatibility field rather than a real model selector; the README does not describe it changing behaviour.
What breaks, and when this is the wrong tool
The largest limitation is not technical. A reverse-engineered client depends on an upstream service that has made no commitment to it. The README does not document rate limits, quota behaviour, or what happens when openai.fm changes its request format or blocks a caller. There is no stated retry policy, no circuit breaker, and no fallback path described. When the upstream changes, the failure mode is a broken endpoint with whatever error the proxy surfaces, and the fix is a new release of TTSFM. The gap between v3.4.2 in December 2025 and v3.5.0 in May 2026 shows that releases are not tied to upstream breakage, so you cannot infer responsiveness from version cadence.
There are smaller constraints too. Speed adjustment costs an ffmpeg pass over the audio, which adds latency proportional to clip length; the README does not quantify it. The voice list is fixed at 11 names, and the README offers no way to add or clone a voice. The model field in the request is accepted for compatibility but is not documented as selecting anything. And the licence position is split: the repository is MIT, but the disclaimer restricts use to educational and research purposes and puts responsibility for compliance with applicable laws and terms of service on the user. The MIT grant covers the code in this repository, not the upstream service the code calls. If you need a speech vendor with a contract, an SLA, or a data-processing agreement, TTSFM is the wrong tool and no amount of Docker tuning changes that.
The realistic alternative, and where the approaches diverge
The obvious alternative is OpenAI's own TTS endpoint, which is what TTSFM imitates. The difference is not the API shape, since TTSFM copies it deliberately. The difference is where the audio is produced and who is accountable for it. With OpenAI you send the same JSON to api.openai.com with an API key, you pay per character, and you get a documented service with published limits and a support path. With TTSFM you send the same JSON to localhost, you pay nothing, and the audio is produced by openai.fm through a reverse-engineered path with no stated guarantees. One is a vendor relationship; the other is a local proxy over someone else's free endpoint.
A second alternative is a self-hosted open-weight TTS model, which flips the trade-off again. That route gives you full control over the model, the voices and the data path, at the cost of running inference hardware and giving up the OpenAI request shape unless you write the adapter yourself. TTSFM sits between the two: OpenAI-compatible surface, no local inference, no contract. Which of the three is right depends entirely on whether the constraint you are solving is cost, control, or compliance. TTSFM only wins on cost and convenience.
Maintenance cost and what to verify before you depend on it
The maintenance burden here is mostly upgrade risk rather than code volume. The project is Python, MIT-licensed, and small enough that the interesting surface is the Docker image and the upstream dependency. The upgrade path that matters is the image tag: latest and slim are the two documented entry points, so pinning to a digest is the only way to make a deployment reproducible, and the README does not discuss pinning. The capabilities endpoint is the other upgrade tool, since it lets your integration fail loudly at startup if a feature disappeared between images.
The things to verify before adopting, in order: run the full image, not slim, unless you have confirmed your inputs are short and your format is WAV; call /api/capabilities and assert on the specific features your code uses, particularly speed and the four ffmpeg-only formats; confirm that openai.fm permits your usage pattern, because the MIT licence on this repository does not grant you anything with respect to that service; and decide in advance what your endpoint does when the upstream returns an error, since the README documents no retry or fallback behaviour. If you cannot answer the fourth question, you are not ready to put this in front of users.
Editorial conclusion
Adopt TTSFM if you want a local endpoint that speaks the OpenAI /v1/audio/speech request shape and you accept that the audio ultimately comes from someone else's reverse-engineered service. Do not adopt it for a paid product, for anything requiring an uptime or content guarantee, or where you cannot accept the README's own educational-and-research restriction. Before committing, run the full image rather than slim, call /api/capabilities and compare it against the feature list you need, and confirm with the operator of openai.fm that your usage is permitted, because the MIT licence on this repository does not extend to the upstream service it calls.
Frequently asked questions
What is TTSFM and is it an official OpenAI product?
TTSFM is an independent, reverse engineered implementation of the openai.fm speech service, built on the GPT-4o mini TTS backend and presented as an OpenAI compatible endpoint. The project states it is intended for educational and research purposes only, should not be used for commercial purposes or in production environments, and that users are responsible for compliance with applicable laws and terms of service.
What is the difference between the ttsfm full and slim Docker images?
The full image includes ffmpeg, so it supports all six audio formats, speed adjustment from 0.25x to 4.0x, format conversion, and automatic combining for both MP3 and WAV on long text. The slim image, around 100MB, has no ffmpeg, offers only MP3 and WAV, and keeps WAV auto-combine while dropping speed adjustment, format conversion and MP3 auto-combine. The variant is chosen at build time and exposed as TTSFM_VARIANT.
Does TTSFM require an API key to use?
The shipped configuration template sets REQUIRE_API_KEY=false with a placeholder TTSFM_API_KEY, so protection is off by default and the service listens on 0.0.0.0 port 8000. Setting REQUIRE_API_KEY=true turns it on, and the key can then be supplied as an Authorization bearer header, an X-API-Key header, an api_key query parameter, or api_key in the JSON body.
Which voices and audio formats does TTSFM support?
Eleven voices are offered: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer and verse. Six formats are supported in the full image, MP3, WAV, OPUS, AAC, FLAC and PCM, while the slim image offers MP3 and WAV only. The running instance can be asked directly what it supports through the api/capabilities endpoint.
How do I install TTSFM as a Python package?
pip install ttsfm installs the core client, and pip install ttsfm[web] adds the web and server dependencies. The gevent path additionally needs the web-gevent extra plus the environment variable TTSFM_SOCKETIO_ASYNC_MODE=gevent. The package declares requires-python >=3.8 with classifiers through 3.12, and the container images build on python:3.11-slim.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dbccccccc-ttsfm)