GUIDE

Ollama text to speech: make your local model talk, fully offline

Ollama runs language models on your own computer, and its chat API answers in text. To hear the answers you add a text to speech step, and if you chose Ollama to keep things private, that step should run locally as well.

This guide adds it with the free SuperClonica engine: a short Python script sends your question to Ollama, reads the reply as it streams in and speaks every sentence as soon as it is complete, so the voice starts long before the model has finished writing. Nothing leaves your computer.

Install

Install Ollama, pull a model and start it, then install the two Python packages:

ollama pull llama3.2

pip install requests superclonica-cpu

On the first run the engine downloads the Supertonic 3 model, about 400 MB; after that it works offline on an ordinary processor, and an NVIDIA graphics card only makes it faster. On Linux the script plays sound with aplay from alsa-utils.

The script

Save it as ollama_voice.py and run it. Type a question; the answer is printed and spoken at the same time, and the conversation keeps its history:

import json, os, re, subprocess, sys, tempfile
import requests
from superclonica import Superclonica

OLLAMA = "http://localhost:11434/api/chat"
MODEL = "llama3.2"  # any model you pulled with ollama pull
VOICE = "F1"  # M1..M5, F1..F5 or a voice file from the catalog
SENTENCE_END = re.compile(r"[.!?]\s+")
tts = Superclonica()

def play(path):
    if sys.platform == "win32":
        import winsound
        winsound.PlaySound(path, winsound.SND_FILENAME)
    elif sys.platform == "darwin":
        subprocess.run(["afplay", path], check=True)
    else:
        subprocess.run(["aplay", "-q", path], check=True)

def say(sentence):
    sentence = re.sub(r"[*#`_]", "", sentence).strip()
    if sentence:
        audio, _ = tts.synthesize(sentence, voice=VOICE, lang="en")
        path = os.path.join(tempfile.gettempdir(), "ollama-say.wav")
        tts.save(path, audio)
        play(path)

history = []
while True:
    history.append({"role": "user", "content": input("You: ")})
    answer = buffer = ""
    body = {"model": MODEL, "messages": history, "stream": True}
    with requests.post(OLLAMA, json=body, stream=True, timeout=300) as response:
        response.raise_for_status()
        for line in response.iter_lines():
            if not line:
                continue
            piece = json.loads(line).get("message", {}).get("content", "")
            print(piece, end="", flush=True)
            answer += piece
            buffer += piece
            while match := SENTENCE_END.search(buffer):
                say(buffer[:match.end()])
                buffer = buffer[match.end():]
    say(buffer)
    print()
    history.append({"role": "assistant", "content": answer})

The script cuts the stream at the end of each sentence and voices it while Ollama keeps writing. It strips Markdown symbols such as asterisks, which models like to use and which sound odd aloud.

Make it sound right

Ask the model for speech, not text: start the history with a system message such as “Answer in short spoken sentences, without lists, tables or formatting.” Set lang in say to the language of your conversation; the engine speaks 31 languages, but not Chinese yet. VOICE takes one of the ten stock voices, M1 to M5 and F1 to F5, or the path of a voice file from the SuperClonica catalog, for example an assistant voice in the style of a film AI.

Talk to it by voice

To speak instead of typing, put a local speech recognizer in front of the script, for example Whisper through the faster-whisper package, and send its text where the script calls input. Then the whole assistant, ears, brain and voice, runs on your own machine.