diff --git a/README.md b/README.md index da18256..79d902c 100755 --- a/README.md +++ b/README.md @@ -195,6 +195,25 @@ The frontend uses a reverse proxy to route requests, so when running with `--pro +## Olares Packaging + +Olares chart and manifest are under: + +- `olares/chatterboxapi` + +The Olares package is modeled as a shared app: + +- Admin install: deploys the shared GPU-backed Chatterbox API service. +- User install: deploys a lightweight user-space API proxy. +- Shared internal endpoint: `http://chatterboxapi.shared.olares.com` +- User endpoint: `https://chatterboxapi.{OlaresID}.olares.com` + +Package manually: + +```bash +helm package olares/chatterboxapi +``` + ## Screenshots of Frontend (Web UI)
diff --git a/olares/chatterboxapi/Chart.yaml b/olares/chatterboxapi/Chart.yaml index 5db80c2..dc4042d 100644 --- a/olares/chatterboxapi/Chart.yaml +++ b/olares/chatterboxapi/Chart.yaml @@ -3,4 +3,4 @@ name: chatterboxapi description: Olares app for Chatterbox TTS API type: application version: 2.31.0 -appVersion: "2.31.0" \ No newline at end of file +appVersion: "2.31.0" diff --git a/olares/chatterboxapi/OlaresManifest.yaml b/olares/chatterboxapi/OlaresManifest.yaml index e4c4439..f0b3b31 100644 --- a/olares/chatterboxapi/OlaresManifest.yaml +++ b/olares/chatterboxapi/OlaresManifest.yaml @@ -1,5 +1,6 @@ olaresManifest.version: "0.11.0" olaresManifest.type: app +apiVersion: "v2" metadata: name: chatterboxapi description: Private text-to-speech API powered by Chatterbox. @@ -11,6 +12,22 @@ metadata: - AI - Utilities - Developer Tools +sharedEntrances: + - name: chatterboxapi + port: 0 + host: sharedentrances-api + title: Chatterbox API + icon: https://avatars.githubusercontent.com/u/21249137?s=200&v=4 + invisible: true + authLevel: internal +entrances: + - name: chatterboxapi + port: 8080 + host: chatterboxapi-proxy + title: Chatterbox API + icon: https://avatars.githubusercontent.com/u/21249137?s=200&v=4 + authLevel: internal + openMethod: window permission: appData: true appCache: true @@ -36,9 +53,12 @@ spec: - Multipart speech endpoint with optional uploaded reference audio. Example request - - `curl -X POST http://chatterboxapi-svc:4123/v1/audio/speech -H "Content-Type: application/json" -d '{"model":"turbo","input":"Hello from Olares","response_format":"wav"}' --output speech.wav` + - Internal shared endpoint: `http://chatterboxapi.shared.olares.com` + - User endpoint: `https://chatterboxapi.{OlaresID}.olares.com` + - `curl -X POST http://chatterboxapi.shared.olares.com/v1/audio/speech -H "Content-Type: application/json" -d '{"model":"turbo","input":"Hello from Olares","response_format":"wav"}' --output speech.wav` Notes + - This is a shared Olares app. The GPU-backed API service is installed once by the Olares admin, while each user receives a lightweight user-space API entrance. - This package targets `amd64` Olares nodes with NVIDIA GPU support. - First request may be slow while model artifacts are downloaded. - Hugging Face and torch cache paths are persisted under `userspace.appData`. @@ -52,6 +72,7 @@ spec: url: https://github.com/resemble-ai/chatterbox/blob/main/LICENSE locale: - en-US + {{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} requiredMemory: 12Gi limitedMemory: 12Gi requiredDisk: 5Gi @@ -60,14 +81,42 @@ spec: limitedCpu: 4 requiredGpu: 12Gi limitedGpu: 16Gi + {{- else }} + requiredMemory: 64Mi + limitedMemory: 256Mi + requiredDisk: 1Mi + limitedDisk: 100Mi + requiredCpu: 10m + limitedCpu: 100m + {{- end }} supportArch: - amd64 + subCharts: + - name: chatterboxapiserver + shared: true + - name: chatterboxapi options: apiTimeout: 0 dependencies: - name: olares type: system - version: ">=1.12.1-0" + version: ">=1.12.3-0" + {{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} + {{- else }} + - name: chatterboxapi + type: application + version: ">=2.2.0" + mandatory: true + {{- end }} + appScope: + {{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} + clusterScoped: true + appRef: + - chatterboxapi + {{- else }} + clusterScoped: false + {{- end }} +{{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} envs: - envName: OLARES_USER_HUGGINGFACE_TOKEN required: false @@ -79,11 +128,4 @@ envs: applyOnChange: true valueFrom: envName: OLARES_USER_HUGGINGFACE_SERVICE -entrances: - - name: chatterboxapi - port: 4123 - host: chatterboxapi-svc - title: Chatterbox API - icon: https://avatars.githubusercontent.com/u/21249137?s=200&v=4 - authLevel: internal - openMethod: window +{{- end }} diff --git a/olares/chatterboxapi/README.md b/olares/chatterboxapi/README.md index e52c4c9..8ad0d31 100644 --- a/olares/chatterboxapi/README.md +++ b/olares/chatterboxapi/README.md @@ -1,13 +1,38 @@ # Chatterbox API for Olares -This package deploys the published image: +This package deploys Chatterbox API as an Olares shared application. + +The Olares admin installs the shared GPU-backed API service once for the +cluster. Each user installation receives a lightweight user-space API entrance +that proxies to that shared service. + +The shared service uses the published image: - `ghcr.io/progress44/rpi-system-chatterbox-api:latest` -The app exposes text-to-speech endpoints at: +## Olares endpoints + +Backend-to-backend clients inside Olares should use the hidden shared entrance: + +- `http://chatterboxapi.shared.olares.com` + +Browser clients or per-user integrations should use the normal user-space +entrance: + +- `https://chatterboxapi.{OlaresID}.olares.com` + +Inside the shared server namespace, the admin-installed service is exposed at: - `http://chatterboxapi-svc:4123` +From another namespace, use: + +- `http://chatterboxapi-svc.chatterboxapiserver-shared:4123` + +User-space installations proxy through: + +- `http://chatterboxapi-proxy:8080` + ## Endpoints - `GET /` @@ -26,6 +51,24 @@ curl -X POST http://chatterboxapi-svc:4123/v1/audio/speech \ --output speech.wav ``` +Shared Olares endpoint: + +```bash +curl -X POST http://chatterboxapi.shared.olares.com/v1/audio/speech \ + -H "Content-Type: application/json" \ + -d '{"model":"turbo","input":"Hello from Olares","response_format":"wav"}' \ + --output speech.wav +``` + +User-space endpoint: + +```bash +curl -X POST https://chatterboxapi.{OlaresID}.olares.com/v1/audio/speech \ + -H "Content-Type: application/json" \ + -d '{"model":"turbo","input":"Hello from Olares","response_format":"wav"}' \ + --output speech.wav +``` + ## Notes - The first synthesis request may be slower while model files are downloaded. diff --git a/olares/chatterboxapi/chatterboxapi/Chart.yaml b/olares/chatterboxapi/chatterboxapi/Chart.yaml new file mode 100644 index 0000000..43cf173 --- /dev/null +++ b/olares/chatterboxapi/chatterboxapi/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: chatterboxapi +description: User-space proxy for the shared Chatterbox API service +type: application +version: 2.2.0 +appVersion: "2.2.0" diff --git a/olares/chatterboxapi/chatterboxapi/templates/clientproxy.yaml b/olares/chatterboxapi/chatterboxapi/templates/clientproxy.yaml new file mode 100644 index 0000000..5a18cce --- /dev/null +++ b/olares/chatterboxapi/chatterboxapi/templates/clientproxy.yaml @@ -0,0 +1,126 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: chatterboxapi-proxy-config + namespace: {{ .Release.Namespace }} +data: + nginx.conf: | + server { + listen 8080; + access_log /opt/bitnami/openresty/nginx/logs/access.log; + error_log /opt/bitnami/openresty/nginx/logs/error.log; + + proxy_connect_timeout 30s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-BFL-USER {{ .Values.bfl.username }}; + proxy_set_header Authorization $http_authorization; + proxy_set_header Cookie $http_cookie; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + location / { + resolver coredns.kube-system.svc.cluster.local valid=10s; + proxy_pass http://chatterboxapi-svc.chatterboxapiserver-shared:4123; + + proxy_hide_header Access-Control-Allow-Origin; + proxy_hide_header Access-Control-Allow-Methods; + proxy_hide_header Access-Control-Allow-Headers; + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS, HEAD"; + add_header Access-Control-Allow-Headers "deviceType,token,authorization,content-type,x-csrftoken"; + + if ($request_method = 'OPTIONS') { + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS, HEAD"; + add_header Access-Control-Allow-Headers "deviceType,token,authorization,content-type,x-csrftoken"; + return 204; + } + } + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: chatterboxapi-proxy +spec: + replicas: 1 + selector: + matchLabels: + app: chatterboxapi-proxy + strategy: + type: Recreate + template: + metadata: + labels: + app: chatterboxapi-proxy + spec: + volumes: + - name: nginx-config + configMap: + name: chatterboxapi-proxy-config + items: + - key: nginx.conf + path: nginx.conf + containers: + - name: nginx + image: "docker.io/beclab/aboveos-bitnami-openresty:1.25.3-2" + ports: + - containerPort: 8080 + protocol: TCP + env: + - name: OPENRESTY_CONF_FILE + value: /etc/nginx/nginx.conf + readinessProbe: + exec: + command: + - /bin/sh + - -c + - | + http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health) + [ "$http_code" -ge 200 ] && [ "$http_code" -lt 500 ] + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 120 + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 100m + memory: 256Mi + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + - name: nginx-config + mountPath: /opt/bitnami/openresty/nginx/conf/server_blocks/nginx.conf + subPath: nginx.conf +--- +apiVersion: v1 +kind: Service +metadata: + name: chatterboxapi-proxy + namespace: {{ .Release.Namespace }} +spec: + type: ClusterIP + selector: + app: chatterboxapi-proxy + ports: + - name: http + protocol: TCP + port: 8080 + targetPort: 8080 diff --git a/olares/chatterboxapi/chatterboxapi/values.yaml b/olares/chatterboxapi/chatterboxapi/values.yaml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/olares/chatterboxapi/chatterboxapi/values.yaml @@ -0,0 +1 @@ + diff --git a/olares/chatterboxapi/chatterboxapiserver/Chart.yaml b/olares/chatterboxapi/chatterboxapiserver/Chart.yaml new file mode 100644 index 0000000..5fd1206 --- /dev/null +++ b/olares/chatterboxapi/chatterboxapiserver/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: chatterboxapiserver +description: Shared GPU-backed Chatterbox API service +type: application +version: 2.2.0 +appVersion: "2.2.0" diff --git a/olares/chatterboxapi/templates/configmap.yaml b/olares/chatterboxapi/chatterboxapiserver/templates/configmap.yaml similarity index 92% rename from olares/chatterboxapi/templates/configmap.yaml rename to olares/chatterboxapi/chatterboxapiserver/templates/configmap.yaml index 9ab8139..3d01fc4 100644 --- a/olares/chatterboxapi/templates/configmap.yaml +++ b/olares/chatterboxapi/chatterboxapiserver/templates/configmap.yaml @@ -1,3 +1,4 @@ +{{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} --- apiVersion: v1 kind: ConfigMap @@ -26,3 +27,4 @@ data: TORCH_HOME: /data/torch NVIDIA_VISIBLE_DEVICES: {{ .Values.tts.nvidiaVisibleDevices | quote }} NVIDIA_DRIVER_CAPABILITIES: {{ .Values.tts.nvidiaDriverCapabilities | quote }} +{{- end }} diff --git a/olares/chatterboxapi/templates/deployment.yaml b/olares/chatterboxapi/chatterboxapiserver/templates/deployment.yaml similarity index 92% rename from olares/chatterboxapi/templates/deployment.yaml rename to olares/chatterboxapi/chatterboxapiserver/templates/deployment.yaml index 66b716f..1e8b64d 100644 --- a/olares/chatterboxapi/templates/deployment.yaml +++ b/olares/chatterboxapi/chatterboxapiserver/templates/deployment.yaml @@ -1,3 +1,4 @@ +{{- if and .Values.admin .Values.bfl.username (eq .Values.admin .Values.bfl.username) }} --- apiVersion: apps/v1 kind: Deployment @@ -139,3 +140,19 @@ spec: protocol: TCP port: {{ .Values.service.port }} targetPort: http +--- +apiVersion: v1 +kind: Service +metadata: + name: sharedentrances-api + namespace: {{ .Release.Namespace }} +spec: + type: ClusterIP + selector: + app: chatterboxapi + ports: + - name: http + protocol: TCP + port: 80 + targetPort: http +{{- end }} diff --git a/olares/chatterboxapi/chatterboxapiserver/values.yaml b/olares/chatterboxapi/chatterboxapiserver/values.yaml new file mode 100644 index 0000000..7736f08 --- /dev/null +++ b/olares/chatterboxapi/chatterboxapiserver/values.yaml @@ -0,0 +1,18 @@ +image: + repository: ghcr.io/progress44/rpi-system-chatterbox-api + tag: latest + pullPolicy: Always + +service: + port: 4123 + +tts: + device: cuda + maxTotalLength: "4000" + maxChunkLength: "280" + exaggeration: "0.5" + cfgWeight: "0.5" + temperature: "0.8" + useMultilingualModel: "true" + nvidiaVisibleDevices: all + nvidiaDriverCapabilities: compute,utility diff --git a/olares/chatterboxapi/templates/keep b/olares/chatterboxapi/templates/keep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/olares/chatterboxapi/templates/keep @@ -0,0 +1 @@ +