ZeroGPU attempt: boot-safe loader + @spaces.GPU realtime handler.
Browse files- peitho_model.py: load base + overlay German v6 with NO import-time CUDA
warmup (warmup crashes ZeroGPU on boot, which has no GPU until a
@spaces.GPU call). Import spaces first so CUDA placement is deferred.
- app.py: load via peitho_model instead of liquid_audio.demo.model.
- chat.py: import from peitho_model; wrap the FastRTC streaming handler in
@spaces.GPU so the whole generation runs in one GPU-scoped slice.
- requirements: add spaces.
Experimental: realtime FastRTC on ZeroGPU is unverified locally; validate
on the live build with hardware set to ZeroGPU.
Co-authored-by: Cursor <cursoragent@cursor.com>
- app.py +9 -25
- chat.py +5 -1
- peitho_model.py +37 -0
- requirements.txt +1 -0
app.py
CHANGED
|
@@ -1,45 +1,29 @@
|
|
| 1 |
-
"""HF Spaces entry point: Peitho 1.5B v6
|
| 2 |
|
| 3 |
Background: the stock LFM2.5-Audio-1.5B base model is English-only for
|
| 4 |
speech-to-speech (see https://huggingface.co/LiquidAI/LFM2.5-Audio-1.5B —
|
| 5 |
-
"Supported languages: English"). Our
|
| 6 |
-
|
| 7 |
-
|
| 8 |
|
| 9 |
-
|
| 10 |
-
|
|
|
|
| 11 |
"""
|
| 12 |
from __future__ import annotations
|
| 13 |
|
| 14 |
import sys
|
| 15 |
from pathlib import Path
|
| 16 |
|
| 17 |
-
from accelerate import load_checkpoint_in_model
|
| 18 |
-
from huggingface_hub import snapshot_download
|
| 19 |
-
|
| 20 |
sys.path.insert(0, str(Path(__file__).parent))
|
| 21 |
|
| 22 |
-
PEITHO_REPO = "jempf/peitho-1.5b-v6"
|
| 23 |
-
|
| 24 |
|
| 25 |
def main() -> None:
|
| 26 |
-
|
| 27 |
-
weights_dir = snapshot_download(
|
| 28 |
-
repo_id=PEITHO_REPO,
|
| 29 |
-
allow_patterns=["model.safetensors", "config.json"],
|
| 30 |
-
)
|
| 31 |
-
print(f"Weights cached at {weights_dir}")
|
| 32 |
-
|
| 33 |
-
print("Loading base LFM2.5-Audio-1.5B...")
|
| 34 |
-
import liquid_audio.demo.model as model_mod
|
| 35 |
-
|
| 36 |
-
print(f"Overlaying v6 weights onto base model...")
|
| 37 |
-
load_checkpoint_in_model(model_mod.lfm2_audio, weights_dir)
|
| 38 |
-
model_mod.lfm2_audio.eval()
|
| 39 |
-
print("v6 ready.")
|
| 40 |
|
| 41 |
print("Importing chat demo and launching...")
|
| 42 |
import chat as chat_mod
|
|
|
|
| 43 |
chat_mod.demo.launch()
|
| 44 |
|
| 45 |
|
|
|
|
| 1 |
+
"""HF Spaces (ZeroGPU) entry point: Peitho 1.5B v6 German voice demo.
|
| 2 |
|
| 3 |
Background: the stock LFM2.5-Audio-1.5B base model is English-only for
|
| 4 |
speech-to-speech (see https://huggingface.co/LiquidAI/LFM2.5-Audio-1.5B —
|
| 5 |
+
"Supported languages: English"). Our v6 fine-tune is what teaches it German
|
| 6 |
+
audio output. A short A/B with the unmodified base model produced garbled
|
| 7 |
+
German + robotic audio — confirming the fine-tune is essential.
|
| 8 |
|
| 9 |
+
Model loading + the German v6 overlay live in `peitho_model.py`, which is
|
| 10 |
+
written to be boot-safe on ZeroGPU (no CUDA warmup at import). This entry
|
| 11 |
+
point just imports the model, then launches the chat demo.
|
| 12 |
"""
|
| 13 |
from __future__ import annotations
|
| 14 |
|
| 15 |
import sys
|
| 16 |
from pathlib import Path
|
| 17 |
|
|
|
|
|
|
|
|
|
|
| 18 |
sys.path.insert(0, str(Path(__file__).parent))
|
| 19 |
|
|
|
|
|
|
|
| 20 |
|
| 21 |
def main() -> None:
|
| 22 |
+
import peitho_model # noqa: F401 # triggers load + v6 overlay (boot-safe)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
print("Importing chat demo and launching...")
|
| 25 |
import chat as chat_mod
|
| 26 |
+
|
| 27 |
chat_mod.demo.launch()
|
| 28 |
|
| 29 |
|
chat.py
CHANGED
|
@@ -21,6 +21,7 @@ from queue import Queue
|
|
| 21 |
from threading import Thread
|
| 22 |
from typing import Any
|
| 23 |
|
|
|
|
| 24 |
import gradio as gr
|
| 25 |
import httpx
|
| 26 |
import numpy as np
|
|
@@ -39,7 +40,9 @@ from briefing import (
|
|
| 39 |
format_schedule_html,
|
| 40 |
)
|
| 41 |
from liquid_audio import ChatState, LFMModality
|
| 42 |
-
from
|
|
|
|
|
|
|
| 43 |
|
| 44 |
AUDIO_EOS_TOKEN = 2048
|
| 45 |
TURN_TTL_SECONDS = 600
|
|
@@ -143,6 +146,7 @@ def chat_producer(
|
|
| 143 |
q.put(None)
|
| 144 |
|
| 145 |
|
|
|
|
| 146 |
def chat_response(
|
| 147 |
audio: tuple[int, np.ndarray],
|
| 148 |
_id: str,
|
|
|
|
| 21 |
from threading import Thread
|
| 22 |
from typing import Any
|
| 23 |
|
| 24 |
+
import spaces
|
| 25 |
import gradio as gr
|
| 26 |
import httpx
|
| 27 |
import numpy as np
|
|
|
|
| 40 |
format_schedule_html,
|
| 41 |
)
|
| 42 |
from liquid_audio import ChatState, LFMModality
|
| 43 |
+
from peitho_model import lfm2_audio, mimi, proc
|
| 44 |
+
|
| 45 |
+
GPU_DURATION_SECONDS = 120
|
| 46 |
|
| 47 |
AUDIO_EOS_TOKEN = 2048
|
| 48 |
TURN_TTL_SECONDS = 600
|
|
|
|
| 146 |
q.put(None)
|
| 147 |
|
| 148 |
|
| 149 |
+
@spaces.GPU(duration=GPU_DURATION_SECONDS)
|
| 150 |
def chat_response(
|
| 151 |
audio: tuple[int, np.ndarray],
|
| 152 |
_id: str,
|
peitho_model.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Boot-safe Peitho model loader for ZeroGPU.
|
| 2 |
+
|
| 3 |
+
Unlike `liquid_audio.demo.model`, this module does NOT run a CUDA warmup at
|
| 4 |
+
import time. On ZeroGPU there is no GPU outside an `@spaces.GPU` call, so any
|
| 5 |
+
eager CUDA op at import would crash the Space on boot. We import `spaces`
|
| 6 |
+
first (which patches torch so `.to("cuda")` is deferred until a GPU is
|
| 7 |
+
actually allocated), load the base model, overlay the German v6 fine-tune,
|
| 8 |
+
and request the CUDA placement — the real transfer happens lazily inside the
|
| 9 |
+
first GPU-scoped call.
|
| 10 |
+
"""
|
| 11 |
+
from __future__ import annotations
|
| 12 |
+
|
| 13 |
+
import spaces # noqa: F401 # must precede torch CUDA usage to enable ZeroGPU
|
| 14 |
+
import torch
|
| 15 |
+
from accelerate import load_checkpoint_in_model
|
| 16 |
+
from huggingface_hub import snapshot_download
|
| 17 |
+
from liquid_audio import LFM2AudioModel, LFM2AudioProcessor
|
| 18 |
+
|
| 19 |
+
BASE_REPO: str = "LiquidAI/LFM2.5-Audio-1.5B"
|
| 20 |
+
PEITHO_REPO: str = "jempf/peitho-1.5b-v6"
|
| 21 |
+
|
| 22 |
+
print("Loading processor + base LFM2.5-Audio-1.5B (no CUDA warmup)...")
|
| 23 |
+
proc = LFM2AudioProcessor.from_pretrained(BASE_REPO).eval()
|
| 24 |
+
lfm2_audio = LFM2AudioModel.from_pretrained(BASE_REPO).eval()
|
| 25 |
+
mimi = proc.mimi.eval()
|
| 26 |
+
|
| 27 |
+
print(f"Overlaying German v6 weights from {PEITHO_REPO}...")
|
| 28 |
+
_weights_dir = snapshot_download(
|
| 29 |
+
repo_id=PEITHO_REPO,
|
| 30 |
+
allow_patterns=["model.safetensors", "config.json"],
|
| 31 |
+
)
|
| 32 |
+
load_checkpoint_in_model(lfm2_audio, _weights_dir)
|
| 33 |
+
lfm2_audio.eval()
|
| 34 |
+
|
| 35 |
+
lfm2_audio.to("cuda")
|
| 36 |
+
mimi.to("cuda")
|
| 37 |
+
print("Peitho v6 ready (CUDA placement deferred until first GPU call).")
|
requirements.txt
CHANGED
|
@@ -3,3 +3,4 @@ fastrtc[vad]>=0.0.30
|
|
| 3 |
accelerate>=1.0.0
|
| 4 |
huggingface_hub>=0.27.0
|
| 5 |
httpx>=0.27.0
|
|
|
|
|
|
| 3 |
accelerate>=1.0.0
|
| 4 |
huggingface_hub>=0.27.0
|
| 5 |
httpx>=0.27.0
|
| 6 |
+
spaces>=0.30.0
|