Spaces:
Running
Running
feat: add HuggingFace Spaces Docker deployment
Browse files- Dockerfile: python:3.11-slim + Node 22, builds all 3 layers
- nginx.conf: routes /api/* and /health to Node proxy (3000),
everything else to Next.js standalone (3030); listens on 7860
- supervisord.conf: manages model + server + frontend + nginx
- .dockerignore: excludes node_modules, .venv, .next, .env.local
- next.config.ts: enable standalone output for Docker
- README.md: add HF Spaces YAML frontmatter (sdk: docker, port: 7860)
NEXT_PUBLIC_API_URL="" at build time β relative /api/* URLs β
nginx proxies to Node β Node proxies to Python model.
Model weights cached in /data/models (HF Spaces persistent storage).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- .dockerignore +24 -0
- Dockerfile +55 -0
- README.md +10 -0
- demo/next.config.ts +1 -1
- nginx.conf +39 -0
- supervisord.conf +54 -0
.dockerignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Build artifacts
|
| 2 |
+
demo/.next/
|
| 3 |
+
demo/out/
|
| 4 |
+
|
| 5 |
+
# Dependencies (installed inside Docker)
|
| 6 |
+
demo/node_modules/
|
| 7 |
+
demo/server/node_modules/
|
| 8 |
+
model/voxtral-server/.venv/
|
| 9 |
+
|
| 10 |
+
# Local env overrides
|
| 11 |
+
demo/.env.local
|
| 12 |
+
demo/.env*.local
|
| 13 |
+
|
| 14 |
+
# Python cache
|
| 15 |
+
**/__pycache__/
|
| 16 |
+
**/*.pyc
|
| 17 |
+
**/*.pyo
|
| 18 |
+
**/*.egg-info/
|
| 19 |
+
|
| 20 |
+
# Git
|
| 21 |
+
.git/
|
| 22 |
+
|
| 23 |
+
# Logs
|
| 24 |
+
*.log
|
Dockerfile
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ethos Studio β HuggingFace Spaces Docker deployment
|
| 2 |
+
# Architecture: Python model (8000) + Node proxy (3000) + Next.js (3030)
|
| 3 |
+
# nginx on port 7860 routes traffic between layers
|
| 4 |
+
|
| 5 |
+
FROM python:3.11-slim
|
| 6 |
+
|
| 7 |
+
# βββ System dependencies ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 8 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 9 |
+
ffmpeg curl nginx supervisor \
|
| 10 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
+
|
| 12 |
+
# Node.js 22
|
| 13 |
+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
| 14 |
+
&& apt-get install -y --no-install-recommends nodejs \
|
| 15 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 16 |
+
|
| 17 |
+
WORKDIR /app
|
| 18 |
+
|
| 19 |
+
# βββ Model layer: Python dependencies ββββββββββββββββββββββββββββββββββββββββ
|
| 20 |
+
COPY model/voxtral-server/requirements.txt model/voxtral-server/requirements.txt
|
| 21 |
+
RUN pip install --no-cache-dir -r model/voxtral-server/requirements.txt
|
| 22 |
+
|
| 23 |
+
COPY model/voxtral-server/ model/voxtral-server/
|
| 24 |
+
|
| 25 |
+
# βββ Proxy server: Node dependencies βββββββββββββββββββββββββββββββββββββββββ
|
| 26 |
+
COPY demo/server/package*.json demo/server/
|
| 27 |
+
RUN cd demo/server && npm ci --omit=dev
|
| 28 |
+
|
| 29 |
+
COPY demo/server/ demo/server/
|
| 30 |
+
|
| 31 |
+
# βββ Frontend: Next.js build ββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 32 |
+
COPY demo/package*.json demo/
|
| 33 |
+
RUN cd demo && npm ci
|
| 34 |
+
|
| 35 |
+
COPY demo/ demo/
|
| 36 |
+
|
| 37 |
+
# Build with empty API base β browser uses relative paths β nginx routes /api/*
|
| 38 |
+
RUN cd demo && NEXT_PUBLIC_API_URL="" npm run build \
|
| 39 |
+
&& cp -r public .next/standalone/public \
|
| 40 |
+
&& cp -r .next/static .next/standalone/.next/static
|
| 41 |
+
|
| 42 |
+
# βββ Process manager + reverse proxy config βββββββββββββββββββββββββββββββββββ
|
| 43 |
+
COPY nginx.conf /etc/nginx/nginx.conf
|
| 44 |
+
COPY supervisord.conf /etc/supervisor/conf.d/app.conf
|
| 45 |
+
|
| 46 |
+
# βββ Model weight cache βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 47 |
+
# /data is persisted across Space restarts on HuggingFace Spaces
|
| 48 |
+
RUN mkdir -p /data/models
|
| 49 |
+
ENV TRANSFORMERS_CACHE=/data/models
|
| 50 |
+
ENV HF_HOME=/data/models
|
| 51 |
+
|
| 52 |
+
# HuggingFace Spaces public port
|
| 53 |
+
EXPOSE 7860
|
| 54 |
+
|
| 55 |
+
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/app.conf"]
|
README.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Ethos Studio β Emotional Speech Recognition
|
| 2 |
|
| 3 |
Speech-to-text service with VAD sentence segmentation and per-segment emotion analysis, powered by [Voxtral Mini 4B](https://huggingface.co/mistralai/Voxtral-Mini-4B-Realtime-2602). Three-layer architecture: **Model** (Python) + **Server** (Node) + **Frontend** (Next.js).
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Ethos Studio
|
| 3 |
+
emoji: π€
|
| 4 |
+
colorFrom: purple
|
| 5 |
+
colorTo: indigo
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
pinned: false
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
# Ethos Studio β Emotional Speech Recognition
|
| 12 |
|
| 13 |
Speech-to-text service with VAD sentence segmentation and per-segment emotion analysis, powered by [Voxtral Mini 4B](https://huggingface.co/mistralai/Voxtral-Mini-4B-Realtime-2602). Three-layer architecture: **Model** (Python) + **Server** (Node) + **Frontend** (Next.js).
|
demo/next.config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import type { NextConfig } from "next";
|
| 2 |
|
| 3 |
const nextConfig: NextConfig = {
|
| 4 |
-
|
| 5 |
};
|
| 6 |
|
| 7 |
export default nextConfig;
|
|
|
|
| 1 |
import type { NextConfig } from "next";
|
| 2 |
|
| 3 |
const nextConfig: NextConfig = {
|
| 4 |
+
output: "standalone",
|
| 5 |
};
|
| 6 |
|
| 7 |
export default nextConfig;
|
nginx.conf
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
worker_processes 1;
|
| 2 |
+
error_log /dev/stderr warn;
|
| 3 |
+
pid /tmp/nginx.pid;
|
| 4 |
+
|
| 5 |
+
events {
|
| 6 |
+
worker_connections 512;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
http {
|
| 10 |
+
include /etc/nginx/mime.types;
|
| 11 |
+
default_type application/octet-stream;
|
| 12 |
+
access_log /dev/stdout;
|
| 13 |
+
client_max_body_size 100M;
|
| 14 |
+
|
| 15 |
+
server {
|
| 16 |
+
listen 7860;
|
| 17 |
+
|
| 18 |
+
# API + health check β Node proxy server (port 3000)
|
| 19 |
+
location ~ ^/(api|health)(/|$) {
|
| 20 |
+
proxy_pass http://127.0.0.1:3000;
|
| 21 |
+
proxy_read_timeout 660s;
|
| 22 |
+
proxy_send_timeout 660s;
|
| 23 |
+
proxy_connect_timeout 10s;
|
| 24 |
+
proxy_set_header Host $host;
|
| 25 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 26 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
# All other requests β Next.js standalone (port 3030)
|
| 30 |
+
location / {
|
| 31 |
+
proxy_pass http://127.0.0.1:3030;
|
| 32 |
+
proxy_set_header Host $host;
|
| 33 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 34 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
| 35 |
+
proxy_set_header Upgrade $http_upgrade;
|
| 36 |
+
proxy_set_header Connection "upgrade";
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
}
|
supervisord.conf
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[supervisord]
|
| 2 |
+
nodaemon=true
|
| 3 |
+
logfile=/dev/null
|
| 4 |
+
logfile_maxbytes=0
|
| 5 |
+
pidfile=/tmp/supervisord.pid
|
| 6 |
+
|
| 7 |
+
; βββ Model layer: Voxtral FastAPI (port 8000) βββββββββββββββββββββββββββββββββ
|
| 8 |
+
[program:model]
|
| 9 |
+
command=uvicorn main:app --host 127.0.0.1 --port 8000
|
| 10 |
+
directory=/app/model/voxtral-server
|
| 11 |
+
autostart=true
|
| 12 |
+
autorestart=true
|
| 13 |
+
stdout_logfile=/dev/stdout
|
| 14 |
+
stdout_logfile_maxbytes=0
|
| 15 |
+
stderr_logfile=/dev/stderr
|
| 16 |
+
stderr_logfile_maxbytes=0
|
| 17 |
+
priority=10
|
| 18 |
+
|
| 19 |
+
; βββ Proxy server: Node/Express (port 3000) βββββββββββββββββββββββββββββββββββ
|
| 20 |
+
[program:server]
|
| 21 |
+
command=node index.js
|
| 22 |
+
directory=/app/demo/server
|
| 23 |
+
autostart=true
|
| 24 |
+
autorestart=true
|
| 25 |
+
stdout_logfile=/dev/stdout
|
| 26 |
+
stdout_logfile_maxbytes=0
|
| 27 |
+
stderr_logfile=/dev/stderr
|
| 28 |
+
stderr_logfile_maxbytes=0
|
| 29 |
+
environment=PORT="3000",MODEL_URL="http://127.0.0.1:8000"
|
| 30 |
+
priority=20
|
| 31 |
+
|
| 32 |
+
; βββ Frontend: Next.js standalone (port 3030) βββββββββββββββββββββββββββββββββ
|
| 33 |
+
[program:frontend]
|
| 34 |
+
command=node .next/standalone/server.js
|
| 35 |
+
directory=/app/demo
|
| 36 |
+
autostart=true
|
| 37 |
+
autorestart=true
|
| 38 |
+
stdout_logfile=/dev/stdout
|
| 39 |
+
stdout_logfile_maxbytes=0
|
| 40 |
+
stderr_logfile=/dev/stderr
|
| 41 |
+
stderr_logfile_maxbytes=0
|
| 42 |
+
environment=PORT="3030",HOSTNAME="127.0.0.1"
|
| 43 |
+
priority=20
|
| 44 |
+
|
| 45 |
+
; βββ nginx reverse proxy (port 7860 β HF Spaces public port) βββββββββββββββββ
|
| 46 |
+
[program:nginx]
|
| 47 |
+
command=nginx -g "daemon off;"
|
| 48 |
+
autostart=true
|
| 49 |
+
autorestart=true
|
| 50 |
+
stdout_logfile=/dev/stdout
|
| 51 |
+
stdout_logfile_maxbytes=0
|
| 52 |
+
stderr_logfile=/dev/stderr
|
| 53 |
+
stderr_logfile_maxbytes=0
|
| 54 |
+
priority=30
|