feat(talk): add ElevenLabs TTS voice notification package
- writeShellScriptBin with mpv audio + notify-send cancel button - Simultaneous audio playback and notification popup - VOICE_NOTIFY=0 toggle for disabling - Uses eleven_multilingual_v2 model with configurable voice ID - Cruncher job wrapper for task completion notifications
This commit is contained in:
@@ -33,6 +33,7 @@ in {
|
||||
openwork = pkgs.callPackage ./openwork {};
|
||||
zellij-ps = pkgs.callPackage ./zellij-ps {};
|
||||
vibetyper = pkgs.callPackage ./vibetyper {};
|
||||
talk = pkgs.callPackage ./talk {};
|
||||
|
||||
# ── Pass-through packages ──────────────────────────────────────────
|
||||
# Imported directly from flake inputs. No local modifications.
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
writeShellScriptBin,
|
||||
curl,
|
||||
python3,
|
||||
mpv,
|
||||
libnotify,
|
||||
busybox,
|
||||
}: let
|
||||
script = writeShellScriptBin "talk" ''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ── Toggle: VOICE_NOTIFY=0 deaktiviert alles ───────────────────
|
||||
if [ "''${VOICE_NOTIFY:-1}" = "0" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Config ──────────────────────────────────────────────────────
|
||||
API_KEY="''${ELEVENLABS_API_KEY:?Set ELEVENLABS_API_KEY in your environment}"
|
||||
VOICE_ID="''${ELEVENLABS_VOICE_ID:-KXxZd16DiBqt82nbarJx}"
|
||||
TEXT="''${1:?Usage: talk \"Text zum Sprechen\"}"
|
||||
AUDIO_FILE="/tmp/voice-notify-$$.mp3"
|
||||
ACTION_FILE="/tmp/voice-action-$$"
|
||||
|
||||
CURL="${lib.getExe curl}"
|
||||
PYTHON="${lib.getExe python3}"
|
||||
MPV="${lib.getExe mpv}"
|
||||
NOTIFY="${lib.getExe libnotify}"
|
||||
RM="${busybox}/bin/rm"
|
||||
CAT="${busybox}/bin/cat"
|
||||
GREP="${busybox}/bin/grep"
|
||||
SLEEP="${busybox}/bin/sleep"
|
||||
KILL="${busybox}/bin/kill"
|
||||
STAT="${busybox}/bin/stat"
|
||||
|
||||
trap '$RM -f "$AUDIO_FILE" "$ACTION_FILE"' EXIT
|
||||
|
||||
# ── TTS generieren ──────────────────────────────────────────────
|
||||
PAYLOAD=$("$PYTHON" -c '
|
||||
import json, sys
|
||||
print(json.dumps({
|
||||
"text": sys.argv[1],
|
||||
"model_id": "eleven_multilingual_v2",
|
||||
"voice_settings": {"stability": 0.5, "similarity_boost": 0.75}
|
||||
}))
|
||||
' "$TEXT")
|
||||
|
||||
HTTP_CODE=$("$CURL" -s -o "$AUDIO_FILE" -w "%{http_code}" \
|
||||
-X POST "https://api.elevenlabs.io/v1/text-to-speech/''${VOICE_ID}" \
|
||||
-H "xi-api-key: ''${API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD") || HTTP_CODE="000"
|
||||
|
||||
if [ "$HTTP_CODE" != "200" ]; then
|
||||
ERR=$($CAT "$AUDIO_FILE" 2>/dev/null | head -c 300)
|
||||
$RM -f "$AUDIO_FILE"
|
||||
"$NOTIFY" -u critical "❌ Voice Fehler" "HTTP ''${HTTP_CODE}\n''${ERR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Gleichzeitig: Audio + Notification ──────────────────────────
|
||||
"$MPV" --no-video --no-terminal --really-quiet "$AUDIO_FILE" &
|
||||
MPV_PID=$!
|
||||
|
||||
(
|
||||
exec "$NOTIFY" \
|
||||
--action=cancel="⛔ Abbrechen" \
|
||||
--urgency=normal \
|
||||
--icon=audio-x-generic \
|
||||
"🔊 KI Antwort" \
|
||||
"$TEXT" > "$ACTION_FILE" 2>/dev/null
|
||||
) &
|
||||
NOTIFY_PID=$!
|
||||
|
||||
# ── Poll-Loop ───────────────────────────────────────────────────
|
||||
while true; do
|
||||
if ! $KILL -0 "$MPV_PID" 2>/dev/null; then
|
||||
$KILL "$NOTIFY_PID" 2>/dev/null || true
|
||||
break
|
||||
fi
|
||||
if [ -f "$ACTION_FILE" ]; then
|
||||
if $GREP -q "cancel" "$ACTION_FILE" 2>/dev/null; then
|
||||
$KILL "$MPV_PID" 2>/dev/null || true
|
||||
fi
|
||||
break
|
||||
fi
|
||||
$SLEEP 0.2
|
||||
done
|
||||
|
||||
wait "$MPV_PID" 2>/dev/null || true
|
||||
'';
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "talk";
|
||||
version = "0.1.0";
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p "$out/bin"
|
||||
ln -s ${script}/bin/talk "$out/bin/talk"
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "ElevenLabs TTS voice notifications with dismissable popup";
|
||||
homepage = "https://code.m3ta.dev/m3tam3re/nixpkgs";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.linux;
|
||||
mainProgram = "talk";
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user