Hallo zusammen,
Nachdem ich erfolgreich meinen Openclaw-Agenten erstmalig installiert habe und es geschafft habe, das Ganze so zu gestalten, dass meine Änderungen persistent bleiben, auch wenn ich Updates hole, war mein nächstes Ziel, mit dem Bot in echter Sprache reden zu können (SpeechToText). Darum soll es hier gehen:
Ziel
- Whisper lokal in das OpenClaw‑Image integrieren, so dass Speech‑to‑Text auch nach einem Image‑Update verfügbar bleibt.
Kurzfassung
- Wir erweitern das Build‑/Dockerfile um die notwendigen System‑ und Python‑Pakete (ffmpeg, python3‑venv, etc.).
- Beim Erststart lädt ein Init‑Script das gewünschte Whisper‑Modell in das persistente Verzeichnis (falls noch nicht vorhanden).
- Ein einfacher Skill / Script im workspace stellt die Transkriptionsfunktion bereit (CLI/HTTP) und speichert Ergebnisse in einem Transcripts‑Ordner.
Die ersten beiden Schritte erfolgen in meinem "Achims_OpenClaw_Build.sh" Script, welches Dockerfile und docker-compose.yml anlegt. Der Dritte Schritt erfolgt dann mit dem Openclaw Bot über Prompts.
Dockerfile und dockercompose.yml anpassen
Mein Kernstück, das Achims_OpenClaw_Build.sh" habe ich unten angehangen. Hier nur die Änderungen, die wichtig sind, damit die beiden Image- und Container-Bauscripte entsprechend angepasst werden. Durch diese Befehle wird das Dockerfile und docker-compose.yml, welche ich mir jedesmal beim Lauf des Scriptes frisch von Openclaw hole, um meine Erweiterungen ergänzt:
# --- Whisper prerequisites patch ---
# Create model dir environment variables in .env if not present
ENV_FILE="D:\Users\User\git\openclaw\.env"
if ! grep -q "OPENCLAW_SPEECH_MODELS_DIR" "$ENV_FILE" 2>/dev/null; then
echo "" >> "$ENV_FILE"
echo "# Speech to Text (Whisper) settings" >> "$ENV_FILE"
echo "OPENCLAW_SPEECH_MODELS_DIR=/home/node/.openclaw/speech_models" >> "$ENV_FILE"
echo "OPENCLAW_SPEECH_TRANSCRIPTS_DIR=/home/node/.openclaw/transcripts" >> "$ENV_FILE"
echo "Added OPENCLAW_SPEECH_* variables to .env"
else
echo "OPENCLAW_SPEECH_* variables already present in .env"
fi
# Add docker-compose volume mapping for speech models if not present
COMPOSE_PATH="D:\Users\User\git\openclaw\docker-compose.yml"
if ! grep -q "speech_models" "$COMPOSE_PATH" 2>/dev/null; then
sed -i "/volumes:/a\ - ${OPENCLAW_SPEECH_MODELS_DIR:-/home/node/.openclaw/speech_models}:/home/node/.openclaw/speech_models\n - ${OPENCLAW_SPEECH_TRANSCRIPTS_DIR:-/home/node/.openclaw/transcripts}:/home/node/.openclaw/transcripts" "$COMPOSE_PATH"
echo "Patched docker-compose.yml with speech volumes"
else
echo "docker-compose.yml already contains speech volumes"
fi
# Add necessary system packages + whisper install block into Dockerfile
DOCKERFILE_PATH="D:\Users\User\git\openclaw\Dockerfile"
if ! grep -q "whisper" "$DOCKERFILE_PATH" 2>/dev/null; then
# insert before 'USER node' as earlier
USER_LINE=$(grep -n "^USER node" "$DOCKERFILE_PATH" | sed -n 's/^\([0-9]\+\):.*/\1/p' | head -n1)
if [ -z "$USER_LINE" ]; then
echo "Error: first 'USER node' not found in Dockerfile"
else
WHISPER_BLOCK=$'\n# Whisper (Speech-to-Text) prerequisites\nUSER root\nRUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake git ffmpeg curl python3 python3-venv python3-pip && \
rm -rf /var/lib/apt/lists/*\n\n# Python venv + whisper (OpenAI Python)
RUN python3 -m venv /opt/pyenv && \
/opt/pyenv/bin/pip install --upgrade pip setuptools wheel && \
/opt/pyenv/bin/pip install openai-whisper ffmpeg-python && \
/opt/pyenv/bin/python -c "import whisper; whisper.load_model('small', download_root='/home/node/.openclaw/speech_models')" || true\nENV PATH="/opt/pyenv/bin:${PATH}"\n\nUSER node\n'
awk -v line="$USER_LINE" -v block="$WHISPER_BLOCK" 'NR == line { print block; next } { print }' "$DOCKERFILE_PATH" > tmp_dockerfile && mv tmp_dockerfile "$DOCKERFILE_PATH"
echo "Dockerfile patched with Whisper prerequisites."
fi
else
echo "Dockerfile already contains whisper block"
fi
Wenn ich dann das Build-Script laufen lasse, werden alle Updates aus dem Openclaw-Repo gezogen, meine Änderungen eingepflegt, mein Branch aktualisiert, ein Linux gebootet und alle notwendigen Installationen durchgeführt (Node, Openclaw, Python, Himalaya,Whisper,...). Das fertig konfigurierte Betriebssystem wird dann als Image gespeichert.
Anschließen wird basierend darauf ein Container gestartet, der alle notwendigen Programme startet (u.a. Openclaw-Gateway). Das Ganze dauert mittlerweile ca. 5 - 20 Minuten (schwankt stark, abhängig von den Änderungen). Dann läuft das Openclaw Gateway.
Ergebnis nach Image Änderung
Überprüfen ob Whisper installiert wurde:
Einmalig ein Sprachmodell herunterladen
Es fehlen noch Rechte für das Sprachmodell:
User@DESKTOP-RVPAUUG MINGW64 /d/Users/User/git/openclaw (achim-local)
$ docker compose exec --user root openclaw-gateway sh -c 'chown -R node:node /home/node/.openclaw/speech_models'
Python Test
Hiermit konnte ich meinen ersten SpeechToText Test durchführen:
$ docker exec -it openclaw-openclaw-gateway-1 bash
node@fe2d9d7fad40:~/.openclaw/speech_models$ python - <<'PY'
> import whisper
> model = whisper.load_model("small", download_root="/home/node/.openclaw/speech_models")
> result = model.transcribe("/home/node/.openclaw/workspace/helbardor/WhisperDoku/Traum-Schlange.wav", language="de")
> print(result["text"])
> PY
/opt/pyenv/lib/python3.11/site-packages/whisper/transcribe.py:132: UserWarning: FP16 is not supported on CPU;
using FP32 instead
warnings.warn("FP16 is not supported on CPU; using FP32 instead")
Ich habe gerade geträumt, mich hat eine Schlange gewissen. Ich rieche mich in den Rücken mit rein und wir haben die Schlange gefangen. Wir haben gesagt, ich lasse mich da hin und wir lassen sie wieder los. Wir schauen, ...
Man sieht, dass das Sprachmodell 'small' schnell an Grenzen kommt - aber dickere Modelle brauchen länger und mehr Platz. Für mich reicht das erst mal
Ich musste beim ersten Mal noch mal Rechte vergeben:
User@DESKTOP-RVPAUUG MINGW64 /d/Users/User/git/openclaw (achim-local)
$ docker compose exec --user root openclaw-gateway sh -c 'chown -R node:node /home/node/.openclaw/transcripts'
Die Speech-Models liegen hier:
node@fe2d9d7fad40:~/.openclaw$ cd speech_models/
node@fe2d9d7fad40:~/.openclaw/speech_models$ ls -la
total 614144
drwxr-xr-x 2 node node 80 Mar 18 10:18 .
drwxrwxrwx 1 root root 512 Mar 18 08:48 ..
-rw-r--r-- 1 node node 145262807 Mar 18 10:18 base.pt
-rw-r--r-- 1 node node 483617219 Mar 18 10:12 small.pt
(Allerdings finde ich sie nicht in Windows Verzeichnissen.)
Skill erstellen
Dann habe ich den Bot gebeten, einen Whisper Skill zu erstellen.
Den hat er zwar zuerst in ein falsches Verzeichnis gesteckt, aber es hat dann (nach dem Verschieben und ein paar Rückfragen) doch funktioniert.
Was natürlich zu bedenken ist, ist, das die Übersetzung ein paar Sekunden bis Minuten dauert.
Das Übersetzen läuft lokal und kostet daher keine Gebühren. Allerdings die Nutzung des Agenten braucht bei mir pro Abfrage mittlerweile knapp 8 Cent (GPT-5 Mini).
Fazit
Das Bauen von neuen Images ist zeitaufwendig und nervig, weil Änderungen einem schon mal einen Error liefern und man (mit Hilfe von KI) nachbessern muss. Dennoch sollte man es wöchentlich machen, da derzeit viel an Openclaw gearbeitet wird.
Ich kann nun in mein Telegram Handy rein sprechen und dem Agenten sagen, was er tun soll. Das Ganze ist zwar zeitlich noch etwas zäh, funktioniert aber. Mein Image hat sich dabei von ca. 3 GByte auf 15 GByte aufgebläht, die Speichernutzung liegt bei knapp 8 GB RAM. Die Gesamtperformance hat sich nicht verschlechtert (ich habe einen 16 GB RAM PC).
Die Übersetzungsqualität hängt vom gewählten Whisper Modell, welches lokal liegt, ab. Aber hier gilt, je gründlicher, desto langsamer. Mein "small" Modell brauchte ca. 45 Sekunden um einen einfachen Satz in Text umzuwandeln. Für Demo Zwecke reicht es. Mal schauen ob ich es im Alltag oft nutzen werde.
Als Nächstes möchte ich mich wohl der Performance, lokalen LLMs und spezialisierten Agenten widmen.
So, Stay tuned,
Achim Mertens
Anhang - Achims_OpenClaw_Build.sh
#!/bin/bash
# Achims_OpenClaw_Build.sh
# git pull, apply custom patches, build image, restart gateway
# Frage nach, ob Docker im Hintergrund läuft und warte auf ein "y"
read -p "Is Docker running in the background? (y/n): " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Great! Proceeding with the build..."
else
echo "Bitte schalte das Windows Docker ein!"
exit 1
fi
# Frage nach, ob git commit gemacht wurde in Achim-local Branch und warte auf ein "y"
read -p "Are you in the achim-local-branch? Have you committed your changes in the achim-local branch? (y/n): " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Great! Proceeding with the build..."
else
echo "Please commit your changes in the achim-local branch before running this script."
echo "Use i.e. 'git push mine achim-local -f' to push your commits to the remote repository."
exit 1
fi
set -e
echo "Starting Achims_OpenClaw_Build.sh..."
#!/bin/bash
# Achims_OpenClaw_Build.sh
# Script to backup configs, pull updates, restore configs, modify Dockerfile, build image, and restart gateway
set -e # Exit on any error
echo "Starting Achims_OpenClaw_Build.sh..."
# Backup der Konfigurationsdateien erstellen
echo "Creating backups..."
cp "D:\OpenClawConfig\openclaw.json" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\openclaw.json"
cp "D:\Users\User\git\openclaw\.env" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\.env"
cp "D:\Users\User\git\openclaw\docker-compose.yml" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\docker-compose.yml"
cp "D:\Users\User\git\openclaw\Dockerfile" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\Dockerfile"
cp "D:\Users\User\git\openclaw\Achims_README.md" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\Achims_README.md"
cp "D:\Users\User\git\openclaw\Achims_OpenClaw_Build.sh" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\Achims_OpenClaw_Build.sh"
cp "D:\Users\User\git\openclaw\Achims_OpenClaw_Build.sh" "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw\Achims_OpenClaw_Build.sh"
########################################
# 1) git pull
########################################
echo "pulling updates..."
cd "D:\Users\User\git\openclaw"
git stash
# Offizielles Repo aktualisieren
echo "Pulling updates from main..."
git checkout main
git fetch origin
git reset --hard origin/main
# Deinen Branch aktualisieren
# Make achim-local identical to main so OpenClaw updates are imported unconditionally.
echo "Resetting achim-local to main (upstream) ..."
git checkout achim-local
git merge -Xours main
# Backup Dateien wieder einspielen
# echo "Restoring backups..."
# cp "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw"/openclaw.json "D:\OpenClawConfig\openclaw.json"
# cp "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw"/.env "D:\Users\User\git\openclaw\.env"
# cp "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw"/docker-compose.yml "D:\Users\User\git\openclaw\docker-compose.yml"
# cp "C:\Users\User\OneDrive\Win-Documents\Notizen\Dokumentation\Openclaw"/Achims_README.md "D:\Users\User\git\openclaw\Achims_README.md"
# --- Whisper prerequisites patch ---
# Create model dir environment variables in .env if not present
ENV_FILE="D:\Users\User\git\openclaw\.env"
if ! grep -q "OPENCLAW_SPEECH_MODELS_DIR" "$ENV_FILE" 2>/dev/null; then
echo "" >> "$ENV_FILE"
echo "# Speech to Text (Whisper) settings" >> "$ENV_FILE"
echo "OPENCLAW_SPEECH_MODELS_DIR=/home/node/.openclaw/speech_models" >> "$ENV_FILE"
echo "OPENCLAW_SPEECH_TRANSCRIPTS_DIR=/home/node/.openclaw/transcripts" >> "$ENV_FILE"
echo "Added OPENCLAW_SPEECH_* variables to .env"
else
echo "OPENCLAW_SPEECH_* variables already present in .env"
fi
# Add docker-compose volume mapping for speech models if not present
COMPOSE_PATH="D:\Users\User\git\openclaw\docker-compose.yml"
if ! grep -q "speech_models" "$COMPOSE_PATH" 2>/dev/null; then
sed -i "/volumes:/a\ - ${OPENCLAW_SPEECH_MODELS_DIR:-/home/node/.openclaw/speech_models}:/home/node/.openclaw/speech_models\n - ${OPENCLAW_SPEECH_TRANSCRIPTS_DIR:-/home/node/.openclaw/transcripts}:/home/node/.openclaw/transcripts" "$COMPOSE_PATH"
echo "Patched docker-compose.yml with speech volumes"
else
echo "docker-compose.yml already contains speech volumes"
fi
# Add necessary system packages + whisper install block into Dockerfile
DOCKERFILE_PATH="D:\Users\User\git\openclaw\Dockerfile"
if ! grep -q "whisper" "$DOCKERFILE_PATH" 2>/dev/null; then
# insert before 'USER node' as earlier
USER_LINE=$(grep -n "^USER node" "$DOCKERFILE_PATH" | sed -n 's/^\([0-9]\+\):.*/\1/p' | head -n1)
if [ -z "$USER_LINE" ]; then
echo "Error: first 'USER node' not found in Dockerfile"
else
WHISPER_BLOCK=$'\n# Whisper (Speech-to-Text) prerequisites\nUSER root\nRUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake git ffmpeg curl python3 python3-venv python3-pip && \
rm -rf /var/lib/apt/lists/*\n\n# Python venv + whisper (OpenAI Python)
RUN python3 -m venv /opt/pyenv && \
/opt/pyenv/bin/pip install --upgrade pip setuptools wheel && \
/opt/pyenv/bin/pip install openai-whisper ffmpeg-python && \
/opt/pyenv/bin/python -c "import whisper; whisper.load_model('small', download_root='/home/node/.openclaw/speech_models')" || true\nENV PATH="/opt/pyenv/bin:${PATH}"\n\nUSER node\n'
awk -v line="$USER_LINE" -v block="$WHISPER_BLOCK" 'NR == line { print block; next } { print }' "$DOCKERFILE_PATH" > tmp_dockerfile && mv tmp_dockerfile "$DOCKERFILE_PATH"
echo "Dockerfile patched with Whisper prerequisites."
fi
else
echo "Dockerfile already contains whisper block"
fi
#####
# Himalaya + Python integration
#####
# Block that will be inserted (used both before and after stash pop)
if ! grep -q "Python 3 + venv + beem bereitstellen" "$DOCKERFILE_PATH"; then
USER_LINE=$(grep -n "^USER node" "$DOCKERFILE_PATH" | sed -n 's/^\([0-9]\+\):.*/\1/p' | head -n1)
if [ -z "$USER_LINE" ]; then
echo "Error: first 'USER node' not found in Dockerfile"
exit 1
fi
COMBINED_BLOCK=$'\n# Himalaya installieren (als root, Binary landet in /usr/local/bin)\nUSER root\nRUN curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | sh -s -- --root /usr/local\nENV PATH=\"/usr/local/bin:${PATH}\"\n\n# Python 3 + venv + beem bereitstellen, damit Agent Python-Scripte ausführen kann\nRUN apt-get update && \\\n DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \\\n python3 python3-venv ca-certificates curl && \\\n python3 -m venv /opt/pyenv && \\\n /opt/pyenv/bin/python -m pip install --no-cache-dir --upgrade pip && \\\n /opt/pyenv/bin/python -m pip install --no-cache-dir beem && \\\n apt-get clean && \\\n rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*\nENV PATH=\"/opt/pyenv/bin:${PATH}\"\n\nUSER node\n'
awk -v line="$USER_LINE" -v block="$COMBINED_BLOCK" '
NR == line { print block; next }
{ print }
' "$DOCKERFILE_PATH" > tmp_dockerfile && mv tmp_dockerfile "$DOCKERFILE_PATH"
echo "Dockerfile patched with Himalaya and Python."
else
echo "Dockerfile already patched."
fi
# Patch docker-compose.yml: Add port 18791 if not present
COMPOSE_PATH="D:\Users\User\git\openclaw\docker-compose.yml"
if ! grep -q "18791:18791" "$COMPOSE_PATH"; then
# Find the ports section and add the line
sed -i '/ports:/a\ - "18791:18791"' "$COMPOSE_PATH"
echo "docker-compose.yml patched with port 18791."
else
echo "Port 18791 already present in docker-compose.yml."
fi
# Build the Docker image
echo "Building Docker image..."
docker build -t openclaw:local .
# Restart the gateway
echo "Restarting OpenClaw gateway..."
docker compose down
docker compose up
echo "Build and restart completed successfully!"
# Image sichern und wieder herstellen
#
# Sichern des Images
# docker tag openclaw:local openclaw_achim:local
# docker save -o openclaw_achim.tar openclaw_achim:local
#
# Image wieder herstellen:
# docker load -i openclaw_achim.tar
#
# In der docker-compose.yml dann das Image auf openclaw_achim:local ändern, damit es verwendet wird.