Voice clone
Clone a narrator's voice from a clean voice audio file using MiniMax voice-cloning on Replicate, then generate new speech (TTS) in that cloned voice with MiniMax speech-2.8-hd. Cloning takes the clean voice MP3/WAV (e.g. voice_concat.mp3 from the voice-isolate skill), trains a voice (default speech-2.6-hd) and saves voice_id + a preview under <avatar>/voices/<name>.json. Generation reuses the avatar's trained voice (or trains one if missing), auto-detects the text language for MiniMax's language_boost, supports per-line emotion and expressive interjections ((laughs), (sighs), …) plus manual <#x#> pauses, and saves audio under <avatar>/generated-audios/ with a manifest.json. Use when the user wants to clone a voice, create/train a TTS voice, get a voice_id, or GENERATE speech / narration / audio in a cloned voice, or mentions "clonar la voz", "voice clone", "voice_id", "entrenar la voz", "generar audio", "text to speech", or "TTS con la voz".From its SKILL.md
npx -y skills add puntorigen/avatar-skills --skill voice-cloneAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.8 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it
Voice Clone
Two capabilities, one skill:
- Clone a narrator's voice with MiniMax voice-cloning → a reusable
voice_idsaved in the avatar folder. - Generate new speech in that cloned voice with MiniMax
speech-2.8-hd, saved under<avatar>/generated-audios/with a manifest.
The clone input is a clean voice file — ideally voice_concat.mp3 produced by the
voice-isolate skill.
Requirements
pip3 install -r requirements.txt(replicateclient +langidfor language detection).- A Replicate API token. It is shared with the other Replicate skills
(avatar-video-reel, gpt-image-2, bg-music, …) and discovered automatically.
To set/refresh it:
python3 scripts/setup_key.py YOUR_REPLICATE_API_TOKEN. - The voice file must be MP3/M4A/WAV, 10s–5min, <20MB.
- A local tunnel —
cloudflared(preferred) orngrok— installed on PATH (only for cloning, not for generation).brew install cloudflared(no account needed) orngrok config add-authtoken <token>once. See How the upload works below.
How the upload works
minimax/voice-cloning re-fetches the audio from MiniMax's own servers, so it
needs a public URL with a real extension — a raw file object or Replicate's
auth-protected upload both fail with invalid file ext. To avoid uploading your
voice to a third party, the skill serves the file straight from your machine
over a short-lived tunnel that is torn down as soon as the clone finishes:
- Prefer cloudflared quick tunnel (no account, ephemeral per-run URL), then
fall back to ngrok, then — only if neither is installed — a temporary
public host (
tmpfiles.org/catbox.moe). - Reachability is verified the way MiniMax sees it: if the local resolver blocks
the tunnel domain (some ISPs filter
*.trycloudflare.com), it re-checks via public DNS (1.1.1.1 / 8.8.8.8) so a blocked local resolver is not mistaken for an unreachable URL.
Clone a voice
python3 scripts/clone_voice.py <video>_voice/voice_concat.mp3
That's it — everything else is auto:
- Model:
speech-2.6-hdby default (the current HD model; MiniMax may serve it on a newer HD engine). Override with--model(speech-2.6-turbo,speech-02-hd,speech-02-turbo). - Defaults match the model:
--accuracy 0.7, noise reduction off, volume normalization off (the input is already clean). Flags:--noise-reduction,--volume-normalization. - Where it saves (auto-inferred):
- Source
name: if the file is<stem>_voice/voice_concat.mp3→<stem>; otherwise the file's own stem. Override with--name. - Avatar dir: the folder containing a
videos/directory (e.g.lolo/). Override with--avatar-dir.
- Source
Output (in <avatar>/voices/)
| File | What it is |
|---|---|
<name>.json | The record: voice_id, model, source, preview_url, created_at |
<name>_preview.mp3 | Preview clip of the cloned voice (skip with --no-preview) |
index.json | Registry mapping every name → voice_id for this avatar |
The voice_id is what you pass to MiniMax text-to-speech to synthesize new
speech in this cloned voice — which is exactly what generate_speech.py does.
Report the voice_id and the path to <name>.json when done.
Generate speech (TTS)
Synthesize new audio in the avatar's cloned voice with minimax/speech-2.8-hd.
# Reuse the avatar's trained voice (auto-detects language, here Spanish):
python3 scripts/generate_speech.py "Hola, soy Lolo" --avatar-dir lolo
# Train automatically first if the avatar has no voice yet:
python3 scripts/generate_speech.py "Hello!" --source lolo/videos/clip_voice/voice_concat.mp3
# Pick an emotion explicitly:
python3 scripts/generate_speech.py "Great news!" --avatar-dir lolo --emotion happy
Voice resolution (automatic):
--voice-idif given.- Else the avatar's already-trained voice (
<avatar>/voices/). With one trained voice it's picked automatically; with several, pass--name. - Else, if
--sourceis given, it trains one first (a clean voice file, or a video whose<stem>_voice/voice_concat.mp3exists), then generates. - Else it errors asking for
--sourceor--voice-id.
Key options:
--emotion(defaultauto):auto,happy,sad,angry,fearful,disgusted,surprised,calm,fluent,neutral. The agent should choose one that fits the line when appropriate.language_boostdefaults toNone(no boost) so the cloned voice keeps its own accent. Boosting a language nudges pronunciation toward a "standard"/regional accent that can fight the clone — e.g. a neutral or Chilean voice drifting into Argentinian voseo. Pass--language-boost detectto auto-detect from the text (Unicode script for CJK/Cyrillic/Arabic/… +langidfor Latin scripts), or a locale (Spanish,English, …) only when you specifically need that pronunciation help.- Audio:
--speed,--volume,--pitch,--audio-format(mp3/wav/flac/pcm),--sample-rate,--bitrate,--channel,--english-normalization. - Text: pass inline or via
--text-file script.txt.
Expressive interjections & pauses
speech-2.8-hd renders expressive interjections written inline in the text,
so the voice doesn't sound flat. Drop them right where they happen:
python3 scripts/generate_speech.py "Lo logramos (laughs softly)… (sighs) y por fin puedo soltar." --avatar-dir lolo
- Recognized (common, reliably-rendered) set:
(laughs),(laughs softly),(chuckles),(giggles),(sighs),(gasps),(coughs),(clears throat),(sneezes),(sniffs),(groans),(yawns),(whistles),(humming),(hums),(exhales),(inhales),(breathes),(gulps),(crying),(sobs),(screams),(applause). The model recognizes 20+; runpython3 scripts/generate_speech.py --list-interjectionsto print them. - The script logs the interjections it detects and warns about any other
parenthesized text (which may otherwise be read out literally). Detected
interjections are recorded in
manifest.jsonper clip. - Manual pauses:
<#x#>insertsxseconds of silence (0.01–99.99), e.g."Respira hondo <#0.6#> y continúa."— useful for beats and emphasis. - Use interjections sparingly — one or two per passage reads as natural;
overusing them sounds theatrical. Pair with
--emotionfor the overall tone.
Long narrations: synthesize per sentence
The model degrades on very long single takes (its own docs recommend short
sentences for smoother delivery). For multi-paragraph scripts, synthesize one
sentence at a time and join the clips rather than sending everything in one
call. The avatar-reel-composer skill's narrate.py does exactly this (one
MiniMax call per sentence + a small silence gap); reuse that flow for reels.
Output (in <avatar>/generated-audios/)
| File | What it is |
|---|---|
<NNN>_<slug>.<ext> | The generated audio clip (auto-numbered) |
manifest.json | items[] mapping each file → text, voice_id, voice_name, emotion, language_boost, and synth params |
Report the audio path, the voice_id used, and the detected language_boost.
Notes
- One clone per source recording: re-running with the same
nameoverwrites its record and updatesindex.json. - The clone quality depends on the input. Use the clean, SFX-free
voice_concat.mp3fromvoice-isolatefor best results; keep--noise-reductionoff when the audio is already clean. - Generation never re-uploads the voice sample (it only sends the
voice_id+ text), so it needs no tunnel and is fast. - A trained
voice_idworks across MiniMax speech models, so the voice trained withspeech-2.6-hdis used forspeech-2.8-hdgeneration.
What ships with it: 6 files
53.8 KB alongside SKILL.md, 5 of them executable
scripts/
- clone_voice.pyruns10.5 KB
- _common.pyruns12.9 KB
- elevenlabs_tts.pyruns11.7 KB
- generate_speech.pyruns16.9 KB
- setup_key.pyruns1.6 KB
- requirements.txt157 B