File size: 6,970 Bytes
87af61d | 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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | from __future__ import annotations
import json
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
SRC_DIR = REPO_ROOT / "src"
if str(SRC_DIR) not in sys.path:
sys.path.insert(0, str(SRC_DIR))
from wfloat_tts import SPEAKER_IDS, load_generator, write_wave
@dataclass(frozen=True)
class SampleSpec:
voice: str
emotion: str
intensity: float
text: str
SAMPLES = (
SampleSpec(
voice="skilled_hero_man",
emotion="joy",
intensity=0.7,
text="We did it! The bridge is secure and everyone made it across. Take a breath and enjoy this moment with me.",
),
SampleSpec(
voice="skilled_hero_woman",
emotion="neutral",
intensity=0.5,
text="Stay close. The stones are loose near the edge. We will move carefully and get there together.",
),
SampleSpec(
voice="fun_hero_man",
emotion="surprise",
intensity=0.6,
text="Wait, that worked? I pulled one lever, the whole wall spun around, and now there is treasure everywhere!",
),
SampleSpec(
voice="fun_hero_woman",
emotion="joy",
intensity=0.7,
text="Come on, keep up! The crowd is cheering.",
),
SampleSpec(
voice="strong_hero_man",
emotion="anger",
intensity=0.80,
text="Enough. You had your warning, and you kept pushing innocent people around. Take one more step, and I end this.",
),
SampleSpec(
voice="strong_hero_woman",
emotion="anger",
intensity=0.8,
text="The chain is holding, and we are not letting this town fall today. Push harder.",
),
SampleSpec(
voice="mad_scientist_man",
emotion="joy",
intensity=0.90,
text="Look at that reaction. The coils are singing, the chamber is stable, and the entire machine is finally alive. Oh, this is magnificent.",
),
SampleSpec(
voice="mad_scientist_woman",
emotion="surprise",
intensity=0.80,
text="No, no, that's not possible. The formula should have crystallized, but it adapted instead. Do you realize what that means for the rest of my work?",
),
SampleSpec(
voice="clever_villain_man",
emotion="dismissive",
intensity=0.60,
text="You came all this way for that little threat? I have heard sharper words from people with far less ambition. Sit down and let the adults finish the game.",
),
SampleSpec(
voice="clever_villain_woman",
emotion="dismissive",
intensity=0.74,
text="Please. If that was your grand reveal, I expected more style and much better timing. You are already behind, and you still do not know the real plan.",
),
SampleSpec(
voice="narrator_man",
emotion="neutral",
intensity=0.5,
text="The harbor was quiet again. The storm had passed in the night, leaving scattered crates, broken rope, and one unanswered question.",
),
SampleSpec(
voice="narrator_woman",
emotion="sadness",
intensity=0.4,
text="When the letter finally arrived, no one rushed to open it. The room had grown too familiar with bad news, and hope had learned to speak softly.",
),
SampleSpec(
voice="wise_elder_man",
emotion="anger",
intensity=0.4,
text="I have seen this mistake before. Pride speaks loudly in the beginning, but regret is the voice that stays with you. Listen while there is still time to change course.",
),
SampleSpec(
voice="wise_elder_woman",
emotion="joy",
intensity=0.5,
text="There you are. The answer was never as far away as you feared, and your patience has finally borne fruit. Let yourself be proud of how far you have come.",
),
SampleSpec(
voice="outgoing_anime_man",
emotion="joy",
intensity=0.8,
text="Yes. This is our chance, and I can feel the whole day lighting up around us. We are going in together, and we are coming out legends.",
),
SampleSpec(
voice="outgoing_anime_woman",
emotion="surprise",
intensity=0.5,
text="Hold on, you are telling me that tiny mascot can drive the entire ship? That is completely ridiculous, and somehow it makes me want to see it even more.",
),
SampleSpec(
voice="scary_villain_man",
emotion="anger",
intensity=0.5,
text="You should have stayed hidden. Now I know your face, your voice, and exactly how afraid you are trying not to sound. Run, if it helps you feel alive.",
),
SampleSpec(
voice="scary_villain_woman",
emotion="fear",
intensity=0.80,
text="Did you hear that? The halls were silent a moment ago, and now something is moving behind the walls. Do not leave me alone with that sound.",
),
SampleSpec(
voice="news_reporter_man",
emotion="neutral",
intensity=0.5,
text="We are live outside city hall, where officials say the meeting will begin within the hour. Security has tightened, and a large crowd is still gathering behind us.",
),
SampleSpec(
voice="news_reporter_woman",
emotion="neutral",
intensity=0.6,
text="We are receiving conflicting reports from the scene. One agency says the system is back online, while another says key services are still down. We are working to confirm the facts.",
),
)
def intensity_slug(value: float) -> str:
return f"{int(round(value * 100)):03d}"
def sample_filename(index: int, sample: SampleSpec) -> str:
return f"{index:02d}_{sample.voice}_{sample.emotion}_{intensity_slug(sample.intensity)}.wav"
def main() -> None:
output_dir = REPO_ROOT / "samples"
output_dir.mkdir(parents=True, exist_ok=True)
generator = load_generator(
checkpoint_path=REPO_ROOT / "model.safetensors",
config_path=REPO_ROOT / "config.json",
)
manifest: list[dict[str, object]] = []
for index, sample in enumerate(SAMPLES, start=1):
sid = SPEAKER_IDS[sample.voice]
audio = generator.generate(
text=sample.text,
sid=sid,
emotion=sample.emotion,
intensity=sample.intensity,
)
filename = sample_filename(index, sample)
output_path = output_dir / filename
write_wave(output_path, audio.samples, audio.sample_rate)
manifest.append(
{
"filename": filename,
"sid": sid,
**asdict(sample),
}
)
print(output_path.relative_to(REPO_ROOT))
manifest_path = output_dir / "manifest.json"
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
print(manifest_path.relative_to(REPO_ROOT))
if __name__ == "__main__":
main()
|