diff options
Diffstat (limited to 'xiaomi-asr.sh')
| -rw-r--r-- | xiaomi-asr.sh | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/xiaomi-asr.sh b/xiaomi-asr.sh new file mode 100644 index 0000000..532233d --- /dev/null +++ b/xiaomi-asr.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Xiaomi MiMo ASR wrapper for Hermes command STT provider. +# +# Usage (called by Hermes automatically via placeholders): +# xiaomi-asr.sh <input_audio> <output_txt> [model] [language] +# +# Xiaomi ASR uses chat/completions API with input_audio format, +# NOT the standard /v1/audio/transcriptions endpoint. +# Only wav and mp3 are accepted — other formats are auto-converted +# to 16kHz mono WAV via ffmpeg. + +set -euo pipefail + +INPUT="${1:?usage: xiaomi-asr.sh <input> <output> [model] [language]}" +OUTPUT="${2:?usage: xiaomi-asr.sh <input> <output> [model] [language]}" +MODEL="${3:-mimo-v2.5-asr}" +LANGUAGE="${4:-zh}" + +API_KEY="${XIAOMI_API_KEY:?XIAOMI_API_KEY is not set}" +BASE_URL="${XIAOMI_BASE_URL:-https://api.xiaomimimo.com/v1}" + +# Determine audio format from extension +EXT="${INPUT##*.}" +case "$EXT" in + wav|WAV) FORMAT="wav" ;; + mp3|MP3) FORMAT="mp3" ;; + *) FORMAT="wav" ;; # Will convert to WAV via ffmpeg +esac + +# If the file is not already wav/mp3, convert to wav via ffmpeg +AUDIO_INPUT="$INPUT" +if [ "$FORMAT" = "wav" ] && [[ ! "$EXT" =~ ^[Ww][Aa][Vv]$ ]] && [[ ! "$EXT" =~ ^[Mm][Pp]3$ ]]; then + if command -v ffmpeg &>/dev/null; then + AUDIO_INPUT=$(mktemp /tmp/hermes-asr-XXXXXX.wav) + ffmpeg -y -i "$INPUT" -ar 16000 -ac 1 -f wav "$AUDIO_INPUT" 2>/dev/null + trap 'rm -f "$AUDIO_INPUT"' EXIT + else + echo "ffmpeg is required to convert .$EXT to wav/mp3 for Xiaomi ASR" >&2 + exit 1 + fi +fi + +# Build JSON payload and call API using Python to avoid arg-length limits +RESPONSE=$(python3 - "$AUDIO_INPUT" "$MODEL" "$FORMAT" "$API_KEY" "$BASE_URL" << 'PYEOF' +import base64, json, sys, urllib.request, urllib.error, ssl + +input_path = sys.argv[1] +model = sys.argv[2] +fmt = sys.argv[3] +api_key = sys.argv[4] +base_url = sys.argv[5] + +with open(input_path, "rb") as f: + audio_b64 = base64.b64encode(f.read()).decode() + +payload = json.dumps({ + "model": model, + "messages": [{ + "role": "user", + "content": [ + {"type": "input_audio", "input_audio": {"data": audio_b64, "format": fmt}}, + ] + }] +}).encode() + +req = urllib.request.Request( + f"{base_url}/chat/completions", + data=payload, + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, +) +ctx = ssl.create_default_context() +try: + resp = urllib.request.urlopen(req, context=ctx, timeout=300) + print(resp.read().decode()) +except urllib.error.HTTPError as e: + body = e.read().decode() + print(f"HTTP {e.code}: {body}", file=sys.stderr) + sys.exit(1) +PYEOF +) + +# Extract the transcribed text from the response +TRANSCRIPT=$(python3 -c " +import json, sys +resp = json.loads(sys.stdin.read()) +choices = resp.get('choices', []) +if choices: + msg = choices[0].get('message', {}) + content = msg.get('content', '') + print(content.strip()) +else: + err = resp.get('error', {}) + print(err.get('message', 'No transcription result'), file=sys.stderr) + sys.exit(1) +" <<< "$RESPONSE") + +if [ -z "$TRANSCRIPT" ]; then + echo "Xiaomi ASR returned empty transcript" >&2 + exit 1 +fi + +# Write the transcript to the output file +echo "$TRANSCRIPT" > "$OUTPUT" +echo "$TRANSCRIPT" |
