Local‑LLM
Sign in

Setup guide

The API speaks OpenAI's protocol. Use the official OpenAI SDKs; only the base URL and the sign-in change.

1. Your settings

Put these into your project's .env (never into git). The secret comes from your project page — it is shown once when you create it.

LLM_BASE_URL=https://llm.andreaskra.com/v1
LLM_TOKEN_URL=https://llm.andreaskra.com/oauth/token
LLM_CLIENT_ID=cl_…
LLM_CLIENT_SECRET=cs_…

Ask for models by their alias — usually default, fast and embed. GET /v1/models lists what you can use.

2. How sign-in works

Your client id and secret are exchanged for a short-lived access token (OAuth 2.1 client_credentials, valid 15 minutes), which goes in the Authorization: Bearer header. The snippets below do this for you and renew the token automatically.

3. Python

Install the OpenAI SDK and our small sign-in helper (its only dependencies are httpx and pyjwt):

pip install openai httpx "pyjwt[crypto]"

Download llm_client.zip, unzip the llm_client folder into your project, then:

import os
from openai import OpenAI
from llm_client import oauth_http_client

llm = OpenAI(
    base_url=os.environ["LLM_BASE_URL"],
    api_key="unused",  # the helper sets the real Authorization header
    http_client=oauth_http_client(
        os.environ["LLM_TOKEN_URL"], os.environ["LLM_CLIENT_ID"], os.environ["LLM_CLIENT_SECRET"]
    ),
)

for chunk in llm.chat.completions.create(
    model="default", stream=True,
    messages=[{"role": "user", "content": "Hello!"}],
):
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

4. TypeScript / Node

Download llm-client.ts (one file, no dependencies) into your project, then:

import OpenAI from "openai";
import { oauthFetch } from "./llm-client";

const llm = new OpenAI({
  baseURL: process.env.LLM_BASE_URL,
  apiKey: "unused",
  fetch: oauthFetch({
    tokenUrl: process.env.LLM_TOKEN_URL!,
    clientId: process.env.LLM_CLIENT_ID!,
    clientSecret: process.env.LLM_CLIENT_SECRET!,
  }),
});

const answer = await llm.chat.completions.create({
  model: "default",
  messages: [{ role: "user", content: "Hello!" }],
});

5. curl

TOKEN=$(curl -s -u "$LLM_CLIENT_ID:$LLM_CLIENT_SECRET" -d grant_type=client_credentials \
  https://llm.andreaskra.com/oauth/token | python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')

curl -s https://llm.andreaskra.com/v1/chat/completions -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"model": "default", "messages": [{"role": "user", "content": "Hello!"}]}'

6. Things to know

SituationWhat happens
The GPU server is offlineA request waits up to 30 s (header X-Queue-Timeout, max 120), then 503 worker_unavailable with Retry-After. The OpenAI SDKs retry this twice by themselves.
Token limit reached429 token_limit_exceeded; Retry-After says when capacity frees up. Limits are rolling: the last 5 hours and the last 7 days, prompt + completion tokens.
Long answersSet max_tokens to bound an answer. Generation stops after X-Request-Timeout (default 600 s).
Work that can waitPOST /v1/jobs with {"endpoint": "/v1/chat/completions", "body": {…}} queues the request even while the GPU is off; poll GET /v1/jobs/{id}.
A leaked secretGenerate a new one on your project page — the old one stops working immediately.