charts

voicestudio

Version: 0.1.0 Type: application AppVersion: 0.5.6 Artifact Hub

VoiceStudio (formerly OmniVoice Studio) — an open-source, fully local ElevenLabs alternative: voice cloning, voice design, dubbing, dictation, transcription and audiobook creation. This Helm chart runs the headless server image (API + web UI on a single port), CPU by default with optional NVIDIA or AMD ROCm acceleration, driven from values.yaml via the bjw-s common library.

TL;DR

helm repo add obeone https://charts.obeone.cloud
helm repo update
helm install voicestudio obeone/voicestudio

About

VoiceStudio (formerly OmniVoice Studio) is an open-source, fully local alternative to ElevenLabs: voice cloning, voice design, video dubbing, dictation, transcription and audiobook creation. This chart runs its headless server image, where one port serves both the API and the web UI, on CPU by default with optional NVIDIA or AMD ROCm acceleration.

Prerequisites

Configuration

This chart is built on the bjw-s-labs common library. Most configuration keys (controllers, service, ingress, persistence, …) follow its schema; see the common library documentation for everything it supports beyond what is spelled out in values.yaml.

Defaults are meant to work out of the box on any cluster. The full list of options lives in values.yaml, is validated by values.schema.json at install time, and is documented in the Values section below. Override it with your own values file:

helm install voicestudio obeone/voicestudio -f my-values.yaml

Administrator key

VoiceStudio requires an administrator API key, and the web UI asks for it on first use. The pod reads it from the Secret <fullname>-api-key (key api-key) and waits until it exists. Create it before or right after installing:

kubectl create secret generic voicestudio-api-key \
  --from-literal=api-key="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"

Alternatively set secrets.api-key.enabled=true and pass the value with --set-string secrets.api-key.stringData.api-key=....

GPU acceleration

The default image is the CUDA build, which falls back to CPU when no GPU is visible. For an NVIDIA GPU, request it in both requests and limits, and set the RuntimeClass if your cluster needs one:

defaultPodOptions:
  runtimeClassName: nvidia
controllers:
  main:
    containers:
      main:
        resources:
          requests:
            nvidia.com/gpu: 1
          limits:
            nvidia.com/gpu: 1

For an AMD GPU, switch to the ROCm image (image.tag: "0.5.6-rocm") and request amd.com/gpu through the AMD device plugin.

Image pull fails with a digest mismatch

The image carries a single PyTorch layer of about 4 GB. If the pull fails with unexpected commit digest (the download was cut short), switch to the Docker Hub mirror, which publishes the same image with identical tags:

controllers:
  main:
    containers:
      main:
        image:
          repository: docker.io/palashdeb/omnivoice-studio

Upgrading

helm repo update
helm upgrade voicestudio obeone/voicestudio

Each release lists its changes in the Artifact Hub changelog; give it a look before jumping across several chart versions.

Uninstalling

helm uninstall voicestudio

PersistentVolumeClaims created by the chart are kept around: delete them manually if you also want the data gone.

Requirements

Kubernetes: >=1.31.0-0

Repository Name Version
https://bjw-s-labs.github.io/helm-charts common 5.2.1

Values

Key Type Default Description
controllers.main.containers.main.env object {"HF_HOME":"/app/omnivoice_data/huggingface","OMNIVOICE_API_KEY":{"valueFrom":{"secretKeyRef":{"key":"api-key","name":"-api-key"}}},"OMNIVOICE_BIND_HOST":"0.0.0.0","OMNIVOICE_DATA_DIR":"/app/omnivoice_data","OMNIVOICE_SERVER_MODE":"1","PYTHONUNBUFFERED":"1"} Environment of the VoiceStudio backend.
controllers.main.containers.main.env.OMNIVOICE_API_KEY object {"valueFrom":{"secretKeyRef":{"key":"api-key","name":"-api-key"}}} Administrator API key, REQUIRED: settings, diagnostics and other admin actions are refused without it, and the web UI asks for it (the upstream Compose file will not start without one). Read from the <fullname>-api-key Secret, which you either create yourself (see NOTES) or let the chart create via secrets.api-key below. The pod stays in CreateContainerConfigError until it exists.
controllers.main.containers.main.image.pullPolicy string "IfNotPresent"  
controllers.main.containers.main.image.repository string "ghcr.io/debpalash/voicestudio" Container image. Mirrored on Docker Hub as palashdeb/omnivoice-studio with identical tags.
controllers.main.containers.main.image.tag string "" Image tag. Defaults to the chart’s appVersion (CUDA build, which also runs CPU-only when no NVIDIA GPU is present). For AMD GPUs use the ROCm variant, e.g. “0.5.6-rocm”.
controllers.main.containers.main.probes.liveness.custom bool true  
controllers.main.containers.main.probes.liveness.enabled bool true  
controllers.main.containers.main.probes.liveness.spec.failureThreshold int 5  
controllers.main.containers.main.probes.liveness.spec.httpGet.path string "/health"  
controllers.main.containers.main.probes.liveness.spec.httpGet.port int 3900  
controllers.main.containers.main.probes.liveness.spec.periodSeconds int 30  
controllers.main.containers.main.probes.liveness.spec.timeoutSeconds int 10  
controllers.main.containers.main.probes.readiness.custom bool true  
controllers.main.containers.main.probes.readiness.enabled bool true  
controllers.main.containers.main.probes.readiness.spec.failureThreshold int 3  
controllers.main.containers.main.probes.readiness.spec.httpGet.path string "/health"  
controllers.main.containers.main.probes.readiness.spec.httpGet.port int 3900  
controllers.main.containers.main.probes.readiness.spec.periodSeconds int 10  
controllers.main.containers.main.probes.readiness.spec.timeoutSeconds int 5  
controllers.main.containers.main.probes.startup.custom bool true  
controllers.main.containers.main.probes.startup.enabled bool true  
controllers.main.containers.main.probes.startup.spec.failureThreshold int 90  
controllers.main.containers.main.probes.startup.spec.httpGet.path string "/health"  
controllers.main.containers.main.probes.startup.spec.httpGet.port int 3900  
controllers.main.containers.main.probes.startup.spec.periodSeconds int 10  
controllers.main.containers.main.probes.startup.spec.timeoutSeconds int 5  
controllers.main.containers.main.resources object {"limits":{"memory":"8Gi"},"requests":{"cpu":"500m","memory":"2Gi"}} Resource envelope. Speech models are memory-hungry; no CPU limit so inference can burst. To use an NVIDIA GPU, add nvidia.com/gpu: 1 to BOTH requests and limits (and set runtimeClassName if your cluster needs it). For AMD, request amd.com/gpu: 1 with the ROCm image.
controllers.main.containers.main.securityContext.allowPrivilegeEscalation bool false  
controllers.main.containers.main.securityContext.capabilities.drop[0] string "ALL"  
controllers.main.pod.labels object {} Extra pod labels. Example for Sablier scale-to-zero on a shared GPU:
controllers.main.strategy string "Recreate"  
controllers.main.type string "deployment"  
defaultPodOptions object {"automountServiceAccountToken":false,"nodeSelector":{"kubernetes.io/arch":"amd64"},"runtimeClassName":"","securityContext":{"seccompProfile":{"type":"RuntimeDefault"}}} Pod-wide options applied to every controller in this chart.
defaultPodOptions.nodeSelector object {"kubernetes.io/arch":"amd64"} Node selection. Upstream only publishes linux/amd64 images (CUDA and ROCm alike), so the pod is pinned to amd64 nodes. Add a GPU host label here when you enable acceleration.
defaultPodOptions.runtimeClassName string "" RuntimeClass exposing the GPU to the pod (e.g. “nvidia”). Leave empty for CPU-only clusters, or for AMD GPUs exposed through a device plugin.
ingress object {"main":{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"chart-example.local","paths":[{"path":"/","pathType":"Prefix","service":{"identifier":"main","port":"http"}}]}],"tls":[{"hosts":["chart-example.local"],"secretName":"tls-chart-example-local"}]}} Ingress. Disabled by default; flip enabled and set a real host to expose the UI. The backend speaks plain HTTP and the admin key travels with requests, so terminate TLS at the ingress and never expose it unencrypted.
persistence object {"data":{"accessMode":"ReadWriteOnce","enabled":true,"globalMounts":[{"path":"/app/omnivoice_data"}],"size":"20Gi","type":"persistentVolumeClaim"},"dshm":{"globalMounts":[{"path":"/dev/shm"}],"medium":"Memory","sizeLimit":"1Gi","type":"emptyDir"}} Storage.
persistence.data object {"accessMode":"ReadWriteOnce","enabled":true,"globalMounts":[{"path":"/app/omnivoice_data"}],"size":"20Gi","type":"persistentVolumeClaim"} Everything VoiceStudio keeps: SQLite database, user voices, settings and the Hugging Face model cache (~4 GB on first run, more as you add engines).
persistence.data.globalMounts list [{"path":"/app/omnivoice_data"}] Reuse a pre-created PVC instead. existingClaim: “”
route object {"main":{"enabled":false,"hostnames":["chart-example.local"],"kind":"HTTPRoute","parentRefs":[{"name":"gateway","namespace":"gateway-system"}],"rules":[{"backendRefs":[{"identifier":"main","port":3900}],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}} Gateway API HTTPRoute, mirroring the Ingress above. Disabled by default: pick either Ingress or HTTPRoute, not both. Requires the Gateway API CRDs and an existing Gateway in the cluster.
route.main.enabled bool false Enable the HTTPRoute. Mutually exclusive with ingress.main.enabled.
route.main.hostnames list ["chart-example.local"] Hostnames served by this route.
route.main.kind string "HTTPRoute" Route kind. HTTPRoute, GRPCRoute, TCPRoute, TLSRoute or UDPRoute.
route.main.parentRefs list [{"name":"gateway","namespace":"gateway-system"}] Gateways this route attaches to.
route.main.rules list [{"backendRefs":[{"identifier":"main","port":3900}],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}] Routing rules. identifier refers to a Service defined above.
secrets object {"api-key":{"enabled":false,"stringData":{"api-key":""},"suffix":"api-key"}} Secrets managed by the chart.
secrets.api-key object {"enabled":false,"stringData":{"api-key":""},"suffix":"api-key"} Chart-managed administrator key, rendered as <fullname>-api-key. Disabled by default so the key never lands in a values file by accident: create the Secret out of band (see NOTES). If you enable it, pass the value at install time (--set-string secrets.api-key.stringData.api-key=...).
service object {"main":{"controller":"main","ports":{"http":{"port":3900,"protocol":"TCP","targetPort":3900},"worker":{"enabled":false,"port":7443,"protocol":"TCP","targetPort":7443}},"type":"ClusterIP"}} Service exposing the API and web UI inside the cluster.
service.main.ports.worker object {"enabled":false,"port":7443,"protocol":"TCP","targetPort":7443} TLS control plane for remote GPU workers. Disabled by default; enable it together with OMNIVOICE_WORKER_PORT only if you enroll workers.

Verifying the chart signature

Charts in this repository are signed with GPG and every release ships a provenance file. The public key is available at charts.obeone.cloud/public_key.gpg, fingerprint B9FE852F28888D27F8C9A11CD33E04CD22E335CE.

# Import the signing key into a legacy keyring (helm verifies with GnuPG v1 keyrings)
curl -fsSL https://charts.obeone.cloud/public_key.gpg | gpg --import
gpg --export > ~/.gnupg/pubring.gpg

# Pull the chart and check it against its provenance file
helm pull --verify obeone/voicestudio

Support

This is a personal chart repository, maintained on a best-effort basis. Bug reports and contributions are welcome on GitHub.


Autogenerated from chart metadata using helm-docs v1.14.2