Spaces:
Running on Zero
Running on Zero
Resample an edit that runs on, up to three times, and explain the edit interval
Browse files
app.py
CHANGED
|
@@ -94,6 +94,14 @@ def process_fn(audio_path: str, target_text: str, start_time: float, end_time: f
|
|
| 94 |
return regenerate(audio_path, target_text, start_time, end_time, duration)
|
| 95 |
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
@spaces.GPU(duration=60)
|
| 98 |
def regenerate(audio_path: str, target_text: str, start_time: float, end_time: float,
|
| 99 |
duration: float) -> str:
|
|
@@ -109,22 +117,35 @@ def regenerate(audio_path: str, target_text: str, start_time: float, end_time: f
|
|
| 109 |
"codec_sr": CODEC_RATE,
|
| 110 |
"silence_tokens": [1388, 1898, 131],
|
| 111 |
}
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
# The model is mono at 16 kHz, so the result is resampled back to the input's rate and copied
|
| 125 |
# across its channels
|
| 126 |
input_info = sf.info(audio_path)
|
| 127 |
-
audio =
|
| 128 |
if input_info.samplerate != 16000:
|
| 129 |
audio = torchaudio.functional.resample(audio, 16000, input_info.samplerate)
|
| 130 |
audio = audio[:1].T.repeat(1, input_info.channels)
|
|
@@ -145,12 +166,15 @@ if __name__ == "__main__":
|
|
| 145 |
.set_info("English speech to edit, up to 60 seconds."),
|
| 146 |
gr.Textbox(label="Target Transcript", lines=4)
|
| 147 |
.harp_required(True)
|
| 148 |
-
.set_info("
|
| 149 |
-
"up to 500 characters."
|
|
|
|
| 150 |
gr.Number(label="Edit Start (seconds)", value=0.5, precision=2)
|
| 151 |
-
.set_info("
|
|
|
|
| 152 |
gr.Number(label="Edit End (seconds)", value=1.5, precision=2)
|
| 153 |
-
.set_info("
|
|
|
|
| 154 |
],
|
| 155 |
output_components=[
|
| 156 |
gr.Audio(type="filepath", label="Edited Speech")
|
|
|
|
| 94 |
return regenerate(audio_path, target_text, start_time, end_time, duration)
|
| 95 |
|
| 96 |
|
| 97 |
+
# The replacement is generated token by token until the model decides it has ended, and it
|
| 98 |
+
# sometimes runs on, stretching a two-second edit into ten seconds of speech. A result is
|
| 99 |
+
# accepted when the recording has grown by no more than this many seconds, and otherwise the
|
| 100 |
+
# edit is sampled again, up to the limit below, keeping the shortest result.
|
| 101 |
+
MAX_GROWTH_SECONDS = 2.0
|
| 102 |
+
MAX_ATTEMPTS = 3
|
| 103 |
+
|
| 104 |
+
|
| 105 |
@spaces.GPU(duration=60)
|
| 106 |
def regenerate(audio_path: str, target_text: str, start_time: float, end_time: float,
|
| 107 |
duration: float) -> str:
|
|
|
|
| 117 |
"codec_sr": CODEC_RATE,
|
| 118 |
"silence_tokens": [1388, 1898, 131],
|
| 119 |
}
|
| 120 |
+
best = None
|
| 121 |
+
for attempt in range(MAX_ATTEMPTS):
|
| 122 |
+
generated = inference_one_sample(
|
| 123 |
+
model,
|
| 124 |
+
model.args,
|
| 125 |
+
model.args.phn2num,
|
| 126 |
+
text_tokenizer,
|
| 127 |
+
audio_tokenizer,
|
| 128 |
+
audio_path,
|
| 129 |
+
target_text,
|
| 130 |
+
mask,
|
| 131 |
+
DEVICE,
|
| 132 |
+
decode_config,
|
| 133 |
+
)
|
| 134 |
+
candidate = generated[0].detach().cpu().float()
|
| 135 |
+
seconds = candidate.shape[-1] / 16000
|
| 136 |
+
print(f"VoiceCraft: attempt {attempt + 1} gives {seconds:.1f} s for a {duration:.1f} s "
|
| 137 |
+
"recording", flush=True)
|
| 138 |
+
if best is None or candidate.shape[-1] < best.shape[-1]:
|
| 139 |
+
best = candidate
|
| 140 |
+
if seconds <= duration + MAX_GROWTH_SECONDS:
|
| 141 |
+
break
|
| 142 |
+
# A sample that ran on is more likely to stop with silence penalized harder
|
| 143 |
+
decode_config["stop_repetition"] = max(1, decode_config["stop_repetition"] - 1)
|
| 144 |
+
|
| 145 |
# The model is mono at 16 kHz, so the result is resampled back to the input's rate and copied
|
| 146 |
# across its channels
|
| 147 |
input_info = sf.info(audio_path)
|
| 148 |
+
audio = best
|
| 149 |
if input_info.samplerate != 16000:
|
| 150 |
audio = torchaudio.functional.resample(audio, 16000, input_info.samplerate)
|
| 151 |
audio = audio[:1].T.repeat(1, input_info.channels)
|
|
|
|
| 166 |
.set_info("English speech to edit, up to 60 seconds."),
|
| 167 |
gr.Textbox(label="Target Transcript", lines=4)
|
| 168 |
.harp_required(True)
|
| 169 |
+
.set_info("The whole transcript of the recording, as it should read after the "
|
| 170 |
+
"edit, up to 500 characters. Only the words inside the edit interval "
|
| 171 |
+
"are regenerated, so change those and leave the rest as spoken."),
|
| 172 |
gr.Number(label="Edit Start (seconds)", value=0.5, precision=2)
|
| 173 |
+
.set_info("Where the words to replace begin, in seconds from the start of the "
|
| 174 |
+
"recording. Read the time off the ruler of the input track."),
|
| 175 |
gr.Number(label="Edit End (seconds)", value=1.5, precision=2)
|
| 176 |
+
.set_info("Where the words to replace end, in seconds. The interval should cover "
|
| 177 |
+
"whole words, and a little silence on either side helps."),
|
| 178 |
],
|
| 179 |
output_components=[
|
| 180 |
gr.Audio(type="filepath", label="Edited Speech")
|