AI Console is the customer-facing portal in front of a LiquidCompute install. It turns a private GreenThread cluster into something that looks and feels like OpenAI or ElevenLabs: customers sign in, discover models, mint API keys, try them in playgrounds, watch their usage — and integrate against an OpenAI-compatible /v1/* endpoint that proxies to the engine underneath.
It is optional — install it when you want to expose the platform to non-platform-team users (paying customers, partners, internal product teams) with proper auth, audit, and quota.
What's in the box
| Workload | Role |
|---|---|
| backend | Go API. Two route families: /api/* for the React SPA (cookie auth) and /v1/* OpenAI-compatible endpoints (bearer token = user's API key, or session cookie). Embeds migrations; runs them on boot. |
| frontend | nginx + React SPA. Login, dashboard, model catalog, chat / voice-chat / STT / TTS playgrounds, API Keys, Usage, Audit Log, Admin. |
| postgres | External — the chart does not bundle one. Bring your own (CloudNativePG, RDS, the LiquidCompute Postgres, anything that speaks Postgres ≥ 14). |
Key concepts
Users + admin
A single admin user is seeded on first boot from admin.defaultEmail / admin.defaultPassword (or an admin.existingSecret). All subsequent users are created via the Admin UI. Passwords are bcrypt-hashed; sessions live in Postgres so logins survive backend restarts.
API keys
Each user mints any number of API keys from the API Keys page. Keys are prefixed (sk-…) and shown once at creation. Requests to /v1/* authenticate with Authorization: Bearer sk-… and the key's owner is recorded in the audit log.
Playgrounds
Browser-side UIs that call the same /v1/* endpoints customers use. The chat playground hits /v1/chat/completions, voice-chat hits /v1/audio/{transcriptions,speech}, and so on. Streaming responses render token-by-token in the UI.
Usage + audit
Every /v1/* call is recorded (user, key, model, prompt + completion tokens, latency, status). The Usage page rolls these up by user / model / time. The Audit Log shows the raw event stream for incident review.
Install
AI Console needs an external Postgres URL and a LiquidCompute (or other OpenAI-compatible) upstream.
Pull credentials + Secrets
The chart and images live on licence.greenthread.ai (see Licensing › Pulling charts and images). If you already ran helm registry login for the engine install you can skip that step. The remaining setup:
kubectl create namespace ai-console
# 1. Image-pull Secret for the licence registry.
kubectl create secret docker-registry greenthread-registry \
-n ai-console \
--docker-server=licence.greenthread.ai \
--docker-username=licence \
--docker-password=<your-licence-token>
# 2. Postgres DSN.
kubectl create secret generic ai-console-db -n ai-console \
--from-literal=url='postgres://aic:pw@postgres.db.svc.cluster.local:5432/ai_console?sslmode=disable'
# 3. Admin seed (read once on first boot, then ignored).
kubectl create secret generic ai-console-admin -n ai-console \
--from-literal=email='admin@example.com' \
--from-literal=password='<generate-a-password>'
Helm install
helm upgrade --install ai-console \
oci://licence.greenthread.ai/greenthread/charts/ai-console \
--namespace ai-console \
--set 'imagePullSecrets[0].name=greenthread-registry' \
--set 'image.registry=licence.greenthread.ai/greenthread' \
--set 'image.repository=ai-console' \
--set 'database.existingSecret.name=ai-console-db' \
--set 'database.existingSecret.key=url' \
--set 'admin.existingSecret.name=ai-console-admin' \
--set 'upstream.baseUrl=http://liquidcompute-lc-proxy.liquidcompute-system:8080' \
--set 'ingress.enabled=true' \
--set 'ingress.className=nginx' \
--set 'ingress.host=platform.example.com' \
--set 'ingress.certManager.enabled=true' \
--set 'ingress.certManager.clusterIssuer=letsencrypt-production' \
--set 'apiIngress.enabled=true' \
--set 'apiIngress.className=nginx' \
--set 'apiIngress.host=api.example.com' \
--set 'apiIngress.certManager.enabled=true' \
--set 'apiIngress.certManager.clusterIssuer=letsencrypt-production'
The image.registry + image.repository overrides combine into licence.greenthread.ai/greenthread/ai-console/{backend,frontend}:tag — the AI Console chart appends /backend and /frontend for the two workloads.
| Value | Purpose |
|---|---|
database.existingSecret.{name,key} | Secret + key whose value is the full postgres://… URL. Alternative: database.url inline (chart creates the Secret). |
admin.existingSecret.{name,emailKey,passwordKey} | First-boot admin seed. After the first row in users, this is ignored. |
upstream.baseUrl | URL the backend proxies /v1/* to. Usually lc-proxy in-cluster. |
upstream.apiKey | Optional. Bearer key the backend sends upstream — leave empty when lc-proxy doesn't require auth. |
ingress.host | Console hostname (platform.example.com). |
apiIngress.host | Optional second hostname that exposes only /v1/* on its own cert — gives external SDK users a clean URL (api.example.com). |
The split between ingress (the console) and apiIngress (just /v1/*) is for UX, not security — both hit the same backend pod. Customers point their SDKs at api.example.com and never see the console domain.
Verify
$ kubectl get pods -n ai-console
NAME READY STATUS AGE
ai-console-backend-68ff688d6c-sjw98 1/1 Running 24h
ai-console-frontend-58c58645c6-zq8sw 1/1 Running 25h
$ kubectl get ingress -n ai-console
NAME CLASS HOSTS ADDRESS PORTS AGE
ai-console nginx platform.example.com 203.0.113.10 80, 443 25h
ai-console-api nginx api.example.com 203.0.113.10 80, 443 25h
# Health check
curl -k https://platform.example.com/api/healthz
# → {"ok":true}
Using the API
Once a user mints an API key in the console, they can hit /v1/* exactly like OpenAI:
from openai import OpenAI
client = OpenAI(
base_url="https://api.example.com/v1",
api_key="sk-...",
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
The model field is the upstream HuggingFace ID, exactly like OpenAI's API. Discover what's available with GET /v1/models. The backend authenticates the key, records the request, and proxies upstream to lc-proxy.
Audio
# Speech to text
with open("recording.wav", "rb") as f:
transcript = client.audio.transcriptions.create(
model="openai/whisper-large-v3-turbo",
file=f,
)
# Text to speech
audio = client.audio.speech.create(
model="fishaudio/s2-pro",
voice="alloy",
input="Hello, world!",
)
Where to next
- LiquidCompute — the layer AI Console proxies to
- GreenThread engine — the engine underneath
- Inference API — the
/v1/*surface customers see
