aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/clone-voice.sh
blob: 348b076adc69d1e2135fee24bcc09673c5fa88e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/env bash
# Extracts the latents of a voice from a recording, so the assistant can
# speak with it.
#
#   scripts/clone-voice.sh recording.wav transcript.txt [name]
#
# Produces assets/voices/<name>.{spk,rvq,txt}, which is what the assistant
# registers with tts-server at startup. It is done once: on every start the
# already extracted latents are sent, not the recording.
set -euo pipefail

cd "$(dirname "$0")/.."

WAV="${1:?usage: clone-voice.sh <recording.wav> <transcript.txt> [name]}"
TXT="${2:?missing the transcript of the recording}"
NAME="${3:-asistente}"

CODEC=vendor/qwentts.cpp/build/qwen-codec
TOKENIZER=models/qwen-tokenizer-12hz-Q8_0.gguf

for f in "$CODEC" "$TOKENIZER" "$WAV" "$TXT"; do
  [ -e "$f" ] || { echo "missing: $f" >&2; exit 1; }
done

OUT="assets/voices"
mkdir -p "$OUT"

echo "Extracting the voice from $WAV…"
# --talker produces the speaker embedding (.spk) and the reference codes
# (.rvq); with the transcript, the server enables ICL cloning, which sounds a
# lot closer to the original than the embedding alone.
"$CODEC" --model "$TOKENIZER" --talker \
         --input "$WAV" \
         -o "$OUT/$NAME"

cp "$TXT" "$OUT/$NAME.txt"

echo
echo "Done:"
ls -la "$OUT/$NAME".{spk,rvq,txt}
echo
echo "Point config/asistente.toml at this voice:"
echo "  [tts.reference]"
echo "  name = \"$NAME\""
echo "  speaker    = \"../$OUT/$NAME.spk\""
echo "  codes      = \"../$OUT/$NAME.rvq\""
echo "  transcript = \"../$OUT/$NAME.txt\""