Spaces:
Running on Zero
Running on Zero
Improve generation limits and cancellation
Browse files- README.md +4 -1
- app.py +32 -12
- run_local.sh +2 -2
- tts_utils.py +1 -1
README.md
CHANGED
|
@@ -20,7 +20,10 @@ The model selector defaults to the 30B-A3B and can switch to 2B model.
|
|
| 20 |
|
| 21 |
The demo includes **audio understanding, speech recognition, speech translation, text reasoning, text-to-speech, and speech-to-speech**.
|
| 22 |
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
The hosted ZeroGPU runtime uses a prebuilt `mamba-ssm==2.3.2.post1` Blackwell wheel.
|
| 26 |
|
|
|
|
| 20 |
|
| 21 |
The demo includes **audio understanding, speech recognition, speech translation, text reasoning, text-to-speech, and speech-to-speech**.
|
| 22 |
|
| 23 |
+
* Audio inputs support up to 15 minutes.
|
| 24 |
+
* Text generation defaults to 1,024 tokens and supports up to 4,096. `Max new tokens` sets a total cap shared by reasoning and the final answer. Reasoning has no separate token cap by default for most tasks.
|
| 25 |
+
* TTS uses a separate 256-token speech budget.
|
| 26 |
+
* Speech-to-speech defaults to a 1,536-token reasoning budget so the model has room for its final answer.
|
| 27 |
|
| 28 |
The hosted ZeroGPU runtime uses a prebuilt `mamba-ssm==2.3.2.post1` Blackwell wheel.
|
| 29 |
|
app.py
CHANGED
|
@@ -70,10 +70,10 @@ MODEL_2B_NAME = "Nemotron-Labs-Audex-2B"
|
|
| 70 |
|
| 71 |
# Shared generation configuration
|
| 72 |
SAMPLE_RATE = 16000
|
| 73 |
-
MAX_AUDIO_DURATION_SECONDS = float(os.environ.get("AUDEX_MAX_AUDIO_SECONDS", "
|
| 74 |
-
MAX_NEW_TOKENS = int(os.environ.get("AUDEX_MAX_NEW_TOKENS", "
|
| 75 |
DEFAULT_MAX_NEW_TOKENS = min(
|
| 76 |
-
int(os.environ.get("AUDEX_DEFAULT_MAX_NEW_TOKENS", "
|
| 77 |
MAX_NEW_TOKENS,
|
| 78 |
)
|
| 79 |
DEFAULT_REASONING_BUDGET = max(
|
|
@@ -146,9 +146,12 @@ TTS_EXAMPLE_TEXT = (
|
|
| 146 |
|
| 147 |
# Task-specific limits and feature switches
|
| 148 |
TTS_MAX_NEW_TOKENS = min(
|
| 149 |
-
int(os.environ.get("AUDEX_TTS_MAX_NEW_TOKENS", "
|
| 150 |
MAX_NEW_TOKENS,
|
| 151 |
)
|
|
|
|
|
|
|
|
|
|
| 152 |
S2S_TEXT_MAX_NEW_TOKENS = int(os.environ.get("AUDEX_S2S_TEXT_MAX_NEW_TOKENS", "2048"))
|
| 153 |
S2S_REASONING_BUDGET = int(os.environ.get("AUDEX_S2S_REASONING_BUDGET", "1536"))
|
| 154 |
S2S_GPU_DURATION_SECONDS = int(os.environ.get("AUDEX_S2S_GPU_DURATION_SECONDS", "120"))
|
|
@@ -833,7 +836,7 @@ def _stream_model_generate(
|
|
| 833 |
)
|
| 834 |
finally:
|
| 835 |
cancel_event.set()
|
| 836 |
-
thread.join(
|
| 837 |
|
| 838 |
|
| 839 |
def _generate(
|
|
@@ -1336,6 +1339,7 @@ def _estimate_unified(
|
|
| 1336 |
reasoning: bool,
|
| 1337 |
reasoning_budget: int,
|
| 1338 |
max_new_tokens: int,
|
|
|
|
| 1339 |
temperature: float,
|
| 1340 |
top_p: float,
|
| 1341 |
guidance_scale: float,
|
|
@@ -1344,9 +1348,11 @@ def _estimate_unified(
|
|
| 1344 |
) -> int:
|
| 1345 |
if task == S2S_TASK:
|
| 1346 |
return S2S_GPU_DURATION_SECONDS
|
| 1347 |
-
if task
|
| 1348 |
-
if
|
| 1349 |
-
return
|
|
|
|
|
|
|
| 1350 |
return _estimate_text(
|
| 1351 |
prompt,
|
| 1352 |
reasoning,
|
|
@@ -1374,6 +1380,7 @@ def run_unified(
|
|
| 1374 |
reasoning: bool,
|
| 1375 |
reasoning_budget: int,
|
| 1376 |
max_new_tokens: int,
|
|
|
|
| 1377 |
temperature: float,
|
| 1378 |
top_p: float,
|
| 1379 |
guidance_scale: float,
|
|
@@ -1402,7 +1409,7 @@ def run_unified(
|
|
| 1402 |
for status, wav_path, player in _generate_tts(
|
| 1403 |
runtime,
|
| 1404 |
prompt,
|
| 1405 |
-
int(
|
| 1406 |
temperature,
|
| 1407 |
top_p,
|
| 1408 |
guidance_scale=float(guidance_scale),
|
|
@@ -1449,7 +1456,6 @@ def unified_task_defaults(
|
|
| 1449 |
has_speech_output = settings["modality"] in {"tts", "s2s"}
|
| 1450 |
reasoning = bool(settings["reasoning"])
|
| 1451 |
default_max_new_tokens = int(settings.get("max_new_tokens", DEFAULT_MAX_NEW_TOKENS))
|
| 1452 |
-
max_new_tokens_limit = int(settings.get("max_new_tokens_limit", MAX_NEW_TOKENS))
|
| 1453 |
reasoning_budget_limit = _max_reasoning_budget(default_max_new_tokens)
|
| 1454 |
return (
|
| 1455 |
gr.update(visible=is_audio),
|
|
@@ -1479,9 +1485,10 @@ def unified_task_defaults(
|
|
| 1479 |
float(settings["temperature"]),
|
| 1480 |
float(settings["top_p"]),
|
| 1481 |
gr.update(
|
| 1482 |
-
value=
|
| 1483 |
-
|
| 1484 |
),
|
|
|
|
| 1485 |
gr.update(
|
| 1486 |
value=float(settings.get("guidance_scale", 2.0)),
|
| 1487 |
visible=has_speech_output,
|
|
@@ -1577,6 +1584,17 @@ with gr.Blocks(title="Nemotron-Labs-Audex") as demo:
|
|
| 1577 |
"If reached, the displayed output is incomplete."
|
| 1578 |
),
|
| 1579 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1580 |
unified_temperature = gr.Slider(
|
| 1581 |
0.1,
|
| 1582 |
1.5,
|
|
@@ -1638,6 +1656,7 @@ with gr.Blocks(title="Nemotron-Labs-Audex") as demo:
|
|
| 1638 |
unified_temperature,
|
| 1639 |
unified_top_p,
|
| 1640 |
unified_max_new_tokens,
|
|
|
|
| 1641 |
unified_guidance_scale,
|
| 1642 |
unified_answer_out,
|
| 1643 |
unified_thinking_out,
|
|
@@ -1669,6 +1688,7 @@ with gr.Blocks(title="Nemotron-Labs-Audex") as demo:
|
|
| 1669 |
unified_reasoning,
|
| 1670 |
unified_reasoning_budget,
|
| 1671 |
unified_max_new_tokens,
|
|
|
|
| 1672 |
unified_temperature,
|
| 1673 |
unified_top_p,
|
| 1674 |
unified_guidance_scale,
|
|
|
|
| 70 |
|
| 71 |
# Shared generation configuration
|
| 72 |
SAMPLE_RATE = 16000
|
| 73 |
+
MAX_AUDIO_DURATION_SECONDS = float(os.environ.get("AUDEX_MAX_AUDIO_SECONDS", "900"))
|
| 74 |
+
MAX_NEW_TOKENS = int(os.environ.get("AUDEX_MAX_NEW_TOKENS", "4096"))
|
| 75 |
DEFAULT_MAX_NEW_TOKENS = min(
|
| 76 |
+
int(os.environ.get("AUDEX_DEFAULT_MAX_NEW_TOKENS", "1024")),
|
| 77 |
MAX_NEW_TOKENS,
|
| 78 |
)
|
| 79 |
DEFAULT_REASONING_BUDGET = max(
|
|
|
|
| 146 |
|
| 147 |
# Task-specific limits and feature switches
|
| 148 |
TTS_MAX_NEW_TOKENS = min(
|
| 149 |
+
int(os.environ.get("AUDEX_TTS_MAX_NEW_TOKENS", "256")),
|
| 150 |
MAX_NEW_TOKENS,
|
| 151 |
)
|
| 152 |
+
TTS_30B_GPU_DURATION_SECONDS = int(
|
| 153 |
+
os.environ.get("AUDEX_TTS_30B_GPU_DURATION_SECONDS", "90")
|
| 154 |
+
)
|
| 155 |
S2S_TEXT_MAX_NEW_TOKENS = int(os.environ.get("AUDEX_S2S_TEXT_MAX_NEW_TOKENS", "2048"))
|
| 156 |
S2S_REASONING_BUDGET = int(os.environ.get("AUDEX_S2S_REASONING_BUDGET", "1536"))
|
| 157 |
S2S_GPU_DURATION_SECONDS = int(os.environ.get("AUDEX_S2S_GPU_DURATION_SECONDS", "120"))
|
|
|
|
| 836 |
)
|
| 837 |
finally:
|
| 838 |
cancel_event.set()
|
| 839 |
+
thread.join()
|
| 840 |
|
| 841 |
|
| 842 |
def _generate(
|
|
|
|
| 1339 |
reasoning: bool,
|
| 1340 |
reasoning_budget: int,
|
| 1341 |
max_new_tokens: int,
|
| 1342 |
+
tts_max_new_tokens: int,
|
| 1343 |
temperature: float,
|
| 1344 |
top_p: float,
|
| 1345 |
guidance_scale: float,
|
|
|
|
| 1348 |
) -> int:
|
| 1349 |
if task == S2S_TASK:
|
| 1350 |
return S2S_GPU_DURATION_SECONDS
|
| 1351 |
+
if task == TTS_TASK:
|
| 1352 |
+
if model_name == DEFAULT_MODEL_NAME:
|
| 1353 |
+
return TTS_30B_GPU_DURATION_SECONDS
|
| 1354 |
+
return MAX_GPU_DURATION_SECONDS
|
| 1355 |
+
if task == TEXT_TASK:
|
| 1356 |
return _estimate_text(
|
| 1357 |
prompt,
|
| 1358 |
reasoning,
|
|
|
|
| 1380 |
reasoning: bool,
|
| 1381 |
reasoning_budget: int,
|
| 1382 |
max_new_tokens: int,
|
| 1383 |
+
tts_max_new_tokens: int,
|
| 1384 |
temperature: float,
|
| 1385 |
top_p: float,
|
| 1386 |
guidance_scale: float,
|
|
|
|
| 1409 |
for status, wav_path, player in _generate_tts(
|
| 1410 |
runtime,
|
| 1411 |
prompt,
|
| 1412 |
+
int(tts_max_new_tokens),
|
| 1413 |
temperature,
|
| 1414 |
top_p,
|
| 1415 |
guidance_scale=float(guidance_scale),
|
|
|
|
| 1456 |
has_speech_output = settings["modality"] in {"tts", "s2s"}
|
| 1457 |
reasoning = bool(settings["reasoning"])
|
| 1458 |
default_max_new_tokens = int(settings.get("max_new_tokens", DEFAULT_MAX_NEW_TOKENS))
|
|
|
|
| 1459 |
reasoning_budget_limit = _max_reasoning_budget(default_max_new_tokens)
|
| 1460 |
return (
|
| 1461 |
gr.update(visible=is_audio),
|
|
|
|
| 1485 |
float(settings["temperature"]),
|
| 1486 |
float(settings["top_p"]),
|
| 1487 |
gr.update(
|
| 1488 |
+
value=default_max_new_tokens,
|
| 1489 |
+
visible=not is_tts,
|
| 1490 |
),
|
| 1491 |
+
gr.update(value=TTS_MAX_NEW_TOKENS, visible=is_tts),
|
| 1492 |
gr.update(
|
| 1493 |
value=float(settings.get("guidance_scale", 2.0)),
|
| 1494 |
visible=has_speech_output,
|
|
|
|
| 1584 |
"If reached, the displayed output is incomplete."
|
| 1585 |
),
|
| 1586 |
)
|
| 1587 |
+
unified_tts_max_new_tokens = gr.Slider(
|
| 1588 |
+
16,
|
| 1589 |
+
TTS_MAX_NEW_TOKENS,
|
| 1590 |
+
value=TTS_MAX_NEW_TOKENS,
|
| 1591 |
+
step=16,
|
| 1592 |
+
label="Max speech tokens",
|
| 1593 |
+
info=(
|
| 1594 |
+
"Speech-token cap. If reached, generated audio may be incomplete."
|
| 1595 |
+
),
|
| 1596 |
+
visible=False,
|
| 1597 |
+
)
|
| 1598 |
unified_temperature = gr.Slider(
|
| 1599 |
0.1,
|
| 1600 |
1.5,
|
|
|
|
| 1656 |
unified_temperature,
|
| 1657 |
unified_top_p,
|
| 1658 |
unified_max_new_tokens,
|
| 1659 |
+
unified_tts_max_new_tokens,
|
| 1660 |
unified_guidance_scale,
|
| 1661 |
unified_answer_out,
|
| 1662 |
unified_thinking_out,
|
|
|
|
| 1688 |
unified_reasoning,
|
| 1689 |
unified_reasoning_budget,
|
| 1690 |
unified_max_new_tokens,
|
| 1691 |
+
unified_tts_max_new_tokens,
|
| 1692 |
unified_temperature,
|
| 1693 |
unified_top_p,
|
| 1694 |
unified_guidance_scale,
|
run_local.sh
CHANGED
|
@@ -35,9 +35,9 @@ export AUDEX_TORCH_ARCH="${AUDEX_TORCH_ARCH:-$detected_arch}"
|
|
| 35 |
export AUDEX_WHEELS_DIR="${AUDEX_WHEELS_DIR:-$APP_DIR/.local/wheels/$runtime_tag}"
|
| 36 |
export AUDEX_BUILD_DIR="${AUDEX_BUILD_DIR:-$APP_DIR/.local/build/$runtime_tag}"
|
| 37 |
export AUDEX_MAX_AUDIO_SECONDS="${AUDEX_MAX_AUDIO_SECONDS:-900}"
|
| 38 |
-
export AUDEX_MAX_NEW_TOKENS="${AUDEX_MAX_NEW_TOKENS:-
|
| 39 |
export AUDEX_DEFAULT_MAX_NEW_TOKENS="${AUDEX_DEFAULT_MAX_NEW_TOKENS:-1024}"
|
| 40 |
-
export AUDEX_TTS_MAX_NEW_TOKENS="${AUDEX_TTS_MAX_NEW_TOKENS:-
|
| 41 |
export AUDEX_S2S_TEXT_MAX_NEW_TOKENS="${AUDEX_S2S_TEXT_MAX_NEW_TOKENS:-2048}"
|
| 42 |
export AUDEX_S2S_TTS_MAX_NEW_TOKENS="${AUDEX_S2S_TTS_MAX_NEW_TOKENS:-2400}"
|
| 43 |
export GRADIO_SERVER_NAME="${GRADIO_SERVER_NAME:-0.0.0.0}"
|
|
|
|
| 35 |
export AUDEX_WHEELS_DIR="${AUDEX_WHEELS_DIR:-$APP_DIR/.local/wheels/$runtime_tag}"
|
| 36 |
export AUDEX_BUILD_DIR="${AUDEX_BUILD_DIR:-$APP_DIR/.local/build/$runtime_tag}"
|
| 37 |
export AUDEX_MAX_AUDIO_SECONDS="${AUDEX_MAX_AUDIO_SECONDS:-900}"
|
| 38 |
+
export AUDEX_MAX_NEW_TOKENS="${AUDEX_MAX_NEW_TOKENS:-4096}"
|
| 39 |
export AUDEX_DEFAULT_MAX_NEW_TOKENS="${AUDEX_DEFAULT_MAX_NEW_TOKENS:-1024}"
|
| 40 |
+
export AUDEX_TTS_MAX_NEW_TOKENS="${AUDEX_TTS_MAX_NEW_TOKENS:-256}"
|
| 41 |
export AUDEX_S2S_TEXT_MAX_NEW_TOKENS="${AUDEX_S2S_TEXT_MAX_NEW_TOKENS:-2048}"
|
| 42 |
export AUDEX_S2S_TTS_MAX_NEW_TOKENS="${AUDEX_S2S_TTS_MAX_NEW_TOKENS:-2400}"
|
| 43 |
export GRADIO_SERVER_NAME="${GRADIO_SERVER_NAME:-0.0.0.0}"
|
tts_utils.py
CHANGED
|
@@ -298,7 +298,7 @@ def stream_tts(
|
|
| 298 |
)
|
| 299 |
finally:
|
| 300 |
cancel_event.set()
|
| 301 |
-
thread.join(
|
| 302 |
|
| 303 |
|
| 304 |
def encode_pcm_chunk(pcm: np.ndarray) -> str:
|
|
|
|
| 298 |
)
|
| 299 |
finally:
|
| 300 |
cancel_event.set()
|
| 301 |
+
thread.join()
|
| 302 |
|
| 303 |
|
| 304 |
def encode_pcm_chunk(pcm: np.ndarray) -> str:
|