bharat_voice_assistant / deploy_modal.py
Aniket2003333333's picture
Initial commit
6779337
Raw
History Blame Contribute Delete
3.13 kB
"""
Bharat Voice Assistant on Modal β€” Gradio UI on A10G (~11GB VRAM)
================================================================
MiniCPM-o 4.5 (STT + LLM) + VoxCPM2 (TTS) in one container.
modal deploy deploy_modal.py
β†’ https://aniketchopde03--bharat-voice-ui.modal.run
Dashboard: https://modal.com/apps/aniketchopde03/main
"""
import modal
app = modal.App("bharat-voice")
OMNI_REVISION = "4382fcae8a551b54d18f18462db974ff312aa7f3"
BAKE_MODELS = (
'python -c "from huggingface_hub import snapshot_download; '
f"snapshot_download('openbmb/MiniCPM-o-4_5', revision='{OMNI_REVISION}', "
"local_dir='/models/MiniCPM-o-4_5'); "
"snapshot_download('openbmb/VoxCPM2', local_dir='/models/VoxCPM2')\""
)
web_image = (
modal.Image.debian_slim(python_version="3.11")
.apt_install("ffmpeg", "libsndfile1", "build-essential")
.pip_install("torch==2.8.0", "torchaudio==2.8.0")
.pip_install(
"transformers==4.51.0",
"huggingface_hub>=0.33.5,<1.0",
"gradio>=6.0.0,<6.18.0",
"accelerate>=0.34.0",
"bitsandbytes>=0.43.0",
"librosa==0.9.0", # minicpmo-utils pins this exactly
"setuptools>=65.0.0,<81", # librosa 0.9.0 needs pkg_resources
"soundfile>=0.12.1",
"numpy>=1.26.0",
"minicpmo-utils[all]>=1.0.5",
"voxcpm>=2.0.3",
"sentencepiece>=0.2.0",
"fastapi[standard]",
)
# Bake to fixed paths β€” more reliable than HF cache + HF_HUB_OFFLINE
.run_commands(BAKE_MODELS)
.env({
"OMNI_MODEL_PATH": "/models/MiniCPM-o-4_5",
"TTS_MODEL_PATH": "/models/VoxCPM2",
"HF_HUB_DISABLE_TELEMETRY": "1",
})
.add_local_file("app.py", "/root/bharat_voice_app.py")
)
with web_image.imports():
from fastapi import FastAPI
from gradio.routes import mount_gradio_app
@app.function(
image=web_image,
gpu="A10G",
memory=16384, # 16GB β€” faster A10G scheduling; model ~8GB 4-bit
max_containers=1, # Gradio sticky sessions
scaledown_window=600, # idle 10 min β†’ scale to zero
timeout=1800, # cold GPU queue + model load can exceed 15 min
)
@modal.concurrent(max_inputs=50) # REQUIRED: Gradio heartbeat + dozens of asset requests
@modal.asgi_app()
def ui():
import importlib.util
import threading
spec = importlib.util.spec_from_file_location(
"bharat_voice_app", "/root/bharat_voice_app.py"
)
bharat = importlib.util.module_from_spec(spec)
spec.loader.exec_module(bharat)
# Mount UI first (queue/heartbeat need ASGI up); warm GPU model in background
web_app = mount_gradio_app(
app=FastAPI(),
blocks=bharat.demo,
path="/",
css=bharat._TTS_CSS,
js=bharat._TTS_JS,
theme="soft",
show_error=True,
)
def _warmup():
print("[INFO] Loading MiniCPM-o on GPU (background warmup)...")
bharat.get_omni()
print("[INFO] MiniCPM-o ready.")
# VoxCPM2 loads on first TTS (warmup is slow ~2min on A10G)
threading.Thread(target=_warmup, daemon=True).start()
return web_app