One terminal per model
omni runs every model behind 127.0.0.1:10000, supervised and restarted if one crashes.
free · local · open source
Multiple models expose their API behind a single port. Set it all up in just a couple of clicks.
curl -fsSL https://raw.githubusercontent.com/nvkudva/omni-api/main/install.sh | sh
brew tap nvkudva/omni && brew trust nvkudva/omni && brew install omni
Then run it
omni init && omni up
Why omni
A virtual agent needs text, speech-to-text, text-to-speech and embeddings. Wiring them up by hand is where the weekend goes.
omni runs every model behind 127.0.0.1:10000, supervised and restarted if one crashes.
Small, sensible defaults for every role. The playground searches for alternatives and warns before one won't fit your RAM.
omni init installs and downloads everything. Your app asks for a role like chat or tts, never a model name.
Architecture
Your app talks to one gateway. omni routes each request to the right model and keeps the engines private.
your app
gateway
roles · engines
Quickstart
Install, pull the models, start. Then open the playground and click.
Brings Python and uv if they are missing, then installs the omni command. On macOS you can use Homebrew instead — each command below is its own copy button.
curl -fsSL https://raw.githubusercontent.com/nvkudva/omni-api/main/install.sh | sh
brew tap nvkudva/omni
brew trust nvkudva/omni
brew install omni
Installs Ollama if needed, fetches chat and embed, and sets up decide and speech. Add --media for image and video.
omni init # core models + speech
omni init --media # also image and video
Runs the gateway and every worker in the background. Then open http://127.0.0.1:10000/. Stuck? omni doctor says what to fix.
omni up
Playground
No terminal needed after step 3. Each role has a page to test it, swap its model and watch its logs.
Models
Settings lists every model for every role. Add one, make it the default, or remove it without touching a config file.
Build
Change one base_url; the Python tabs reuse the client from Chat. Full endpoint reference is in the README.
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:10000/v1", api_key="local")
reply = client.chat.completions.create(
model="qwen2.5:0.5b",
messages=[{"role": "user", "content": "Hi!"}],
)
print(reply.choices[0].message.content)
curl localhost:10000/v1/systemone -H 'content-type: application/json' -d '{
"state": "I have asked three times and still no refund!",
"questions": {
"is_frustrated": {"type": "noul", "instructions": "Does the customer sound frustrated?"},
"topic": {"type": "choice", "instructions": "What is this about?",
"criteria": {"billing": "money, refunds", "shipping": "delivery"}}
}
}'
client.embeddings.create(model="embed", input=["refund policy", "shipping times"])
client.audio.speech.create(
model="tts", voice="af_heart", input="Hello from omni."
).write_to_file("out.wav")
client.audio.transcriptions.create(model="stt", file=open("out.wav", "rb"))
client.images.generate(model="image", prompt="a lighthouse at dawn", size="1024x1024")
FAQ
No. omni binds to 127.0.0.1. The only network traffic is the first model download from Ollama or Hugging Face.
Every worker is health-checked and restarted automatically. One role going down never takes the others with it.
Yes — it loads the model. Pin the roles you use often and they stay loaded across restarts.
macOS on Apple Silicon runs every role. Linux serves chat and embed through Ollama, decide on ONNX Runtime, and adds speech and video with the media extra. Image generation is macOS-only.
One install, one port, every model your app needs.