Spaces:
Running on Zero
Running on Zero
Refuse a recording over 60 seconds or a transcript over 1000 characters before reserving the GPU
Browse filesThe recording is the model's context and the replacement is generated a token at a time, so neither had a bound. Both are now capped, and an unreadable recording is refused, before the GPU is reserved. The output info no longer says 16 kHz, since the result comes back at the recording's own rate.
app.py
CHANGED
|
@@ -32,6 +32,13 @@ audio_tokenizer = AudioTokenizer(device=DEVICE, signature=codec_path)
|
|
| 32 |
text_tokenizer = TextTokenizer(backend="espeak")
|
| 33 |
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
def edit_speech(audio_path: str, target_text: str, start_time: float, end_time: float) -> str:
|
| 36 |
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 37 |
# caller's ZeroGPU allowance
|
|
@@ -40,10 +47,23 @@ def edit_speech(audio_path: str, target_text: str, start_time: float, end_time:
|
|
| 40 |
target_text = target_text.strip()
|
| 41 |
if not target_text:
|
| 42 |
raise gr.Error("Enter the full transcript with the replacement text.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
# soundfile rather than torchaudio, whose ffmpeg backend fails outside a GPU call under
|
| 45 |
# ZeroGPU's emulation
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
if not 0 <= start_time < end_time <= duration:
|
| 48 |
raise gr.Error(f"Select an edit interval within the {duration:.2f} second recording.")
|
| 49 |
|
|
@@ -109,10 +129,11 @@ if __name__ == "__main__":
|
|
| 109 |
input_components=[
|
| 110 |
gr.Audio(type="filepath", label="Speech Recording")
|
| 111 |
.harp_required(True)
|
| 112 |
-
.set_info("English speech to edit."),
|
| 113 |
gr.Textbox(label="Target Transcript", lines=4)
|
| 114 |
.harp_required(True)
|
| 115 |
-
.set_info("Full transcript of the recording, with the replacement words in place
|
|
|
|
| 116 |
gr.Number(label="Edit Start (seconds)", value=0.5, precision=2)
|
| 117 |
.set_info("Start of the words to replace."),
|
| 118 |
gr.Number(label="Edit End (seconds)", value=1.5, precision=2)
|
|
@@ -120,7 +141,7 @@ if __name__ == "__main__":
|
|
| 120 |
],
|
| 121 |
output_components=[
|
| 122 |
gr.Audio(type="filepath", label="Edited Speech")
|
| 123 |
-
.set_info("
|
| 124 |
],
|
| 125 |
process_fn=edit_speech,
|
| 126 |
)
|
|
|
|
| 32 |
text_tokenizer = TextTokenizer(backend="espeak")
|
| 33 |
|
| 34 |
|
| 35 |
+
# The whole recording is the model's context, and the replacement is generated a token at a
|
| 36 |
+
# time, so the cost grows with both. Measured at about 13 s for a 230-character replacement, so
|
| 37 |
+
# the longest transcript stays well inside the reservation below
|
| 38 |
+
MAX_INPUT_SECONDS = 60
|
| 39 |
+
MAX_TRANSCRIPT_CHARACTERS = 1000
|
| 40 |
+
|
| 41 |
+
|
| 42 |
def edit_speech(audio_path: str, target_text: str, start_time: float, end_time: float) -> str:
|
| 43 |
# Checked before the GPU is reserved, so a request the model cannot take spends none of the
|
| 44 |
# caller's ZeroGPU allowance
|
|
|
|
| 47 |
target_text = target_text.strip()
|
| 48 |
if not target_text:
|
| 49 |
raise gr.Error("Enter the full transcript with the replacement text.")
|
| 50 |
+
if len(target_text) > MAX_TRANSCRIPT_CHARACTERS:
|
| 51 |
+
raise gr.Error(
|
| 52 |
+
f"The transcript is {len(target_text)} characters long. Shorten it to "
|
| 53 |
+
f"{MAX_TRANSCRIPT_CHARACTERS} or fewer."
|
| 54 |
+
)
|
| 55 |
|
| 56 |
# soundfile rather than torchaudio, whose ffmpeg backend fails outside a GPU call under
|
| 57 |
# ZeroGPU's emulation
|
| 58 |
+
try:
|
| 59 |
+
duration = sf.info(audio_path).duration
|
| 60 |
+
except Exception as exc:
|
| 61 |
+
raise gr.Error(f"Could not read the audio file: {exc}") from exc
|
| 62 |
+
if duration > MAX_INPUT_SECONDS:
|
| 63 |
+
raise gr.Error(
|
| 64 |
+
f"The recording is {duration:.1f} s long. Trim it to {MAX_INPUT_SECONDS} seconds or "
|
| 65 |
+
"less."
|
| 66 |
+
)
|
| 67 |
if not 0 <= start_time < end_time <= duration:
|
| 68 |
raise gr.Error(f"Select an edit interval within the {duration:.2f} second recording.")
|
| 69 |
|
|
|
|
| 129 |
input_components=[
|
| 130 |
gr.Audio(type="filepath", label="Speech Recording")
|
| 131 |
.harp_required(True)
|
| 132 |
+
.set_info("English speech to edit, up to 60 seconds."),
|
| 133 |
gr.Textbox(label="Target Transcript", lines=4)
|
| 134 |
.harp_required(True)
|
| 135 |
+
.set_info("Full transcript of the recording, with the replacement words in place, "
|
| 136 |
+
"up to 1000 characters."),
|
| 137 |
gr.Number(label="Edit Start (seconds)", value=0.5, precision=2)
|
| 138 |
.set_info("Start of the words to replace."),
|
| 139 |
gr.Number(label="Edit End (seconds)", value=1.5, precision=2)
|
|
|
|
| 141 |
],
|
| 142 |
output_components=[
|
| 143 |
gr.Audio(type="filepath", label="Edited Speech")
|
| 144 |
+
.set_info("The edited recording, at its own sample rate and channel count."),
|
| 145 |
],
|
| 146 |
process_fn=edit_speech,
|
| 147 |
)
|