Files
descrybe/docs/mock-llm.md
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

8.7 KiB
Raw Blame History

Mock LLM (OpenAI-compatible stub for CI / local processing)

Tiny local Chat Completions server that exercises Descrybes real processing.OpenAIClient path without production API keys or Green Chat.

Item Value
Command apps/api/cmd/mock-llm
Default listen 127.0.0.1:18767
Base URL http://127.0.0.1:18767/v1
Model id mock-llm
API key local-test (placeholder; Completer requires non-empty)
Responses processing.HeuristicCompleter (deterministic JSON for enhance)

Do not use the A1 tenant. Prefer demo@descrybe.localPlatform Demo (demo-user.md, safe-test-fixtures.md).

Related: green-chat-llm.md (real local/LAN model), local-llm-tuning.md, e2e-processing.md.


Start

cd apps/api
go run ./cmd/mock-llm -addr 127.0.0.1:18767
# defaults: key=local-test model=mock-llm
# env overrides: MOCK_LLM_API_KEY, MOCK_LLM_MODEL

Health: GET http://127.0.0.1:18767/healthz{"status":"ok","service":"mock-llm",...}.

Smoke:

curl.exe -sS http://127.0.0.1:18767/v1/models -H "Authorization: Bearer local-test"
# POST /v1/chat/completions with JSON messages (same shape as OpenAI)

Endpoints:

Method Path Notes
GET /healthz No auth
GET /v1/models Bearer required
POST /v1/chat/completions Bearer; assistant content from HeuristicCompleter
POST /v1/embeddings Bearer; tiny fixed vector for role probes

Loopback is allowed by OpenAIClient dial policy (localhost / 127.0.0.1).


Config keys

Process-env platform fallback (root .env — restart api + worker after change):

OPENAI_API_KEY=local-test
OPENAI_BASE_URL=http://127.0.0.1:18767/v1
OPENAI_MODEL=mock-llm
# optional tuning
# PROCESSING_RPM=60
# PROCESSING_MAX_RETRIES=3

Preferred for a single tenant: company admin → /integrations/ai → custom OpenAI-compatible:

  • Base URL: http://127.0.0.1:18767/v1
  • Model: mock-llm
  • API key: local-test

OPENAI_API_KEY must be non-empty or the Completer stays disabled (Enabled()).

Unset OPENAI_* → worker skips AI enhance (or uses heuristic only if explicitly wired). Mock-llm is for proving the HTTP Completer path.


How processing tests should call it

1. Unit / package tests (no process)

Prefer in-process stubs — already used:

  • stubCompleter in processing/steps_test.go
  • HeuristicCompleter for offline enhance shapes
  • httptest.NewServer + NewOpenAIClient(..., srv.URL+"/v1", ...) as in aiprovider/platform_role_test.go

go test ./cmd/mock-llm covers health, auth, enhance JSON, and an OpenAIClient round-trip against the stub handlers.

2. Integration / E2E (worker + API)

  1. Start mock-llm (above).
  2. Set OPENAI_* or configure /integrations/ai on Platform Demo (not A1).
  3. Ensure demo plan has can_use_ai=true and credits (free-tier.md).
  4. Run API + worker so the worker inherits env (or uses dashboard BYOK).
  5. Enqueue enhance_only (or full) for a demo product:
# After CSRF + login as demo@descrybe.local (cookie jar):
# POST /api/processing/jobs {"raw_product_ids":["…"],"processing_type":"enhance_only"}
# Poll GET /api/processing/jobs/{id} until completed
# Expect ai_enhance step done; gpt/step log shows OpenAI-compatible usage (not openai_not_configured)

Worker log should show OpenAI configured with base=http://127.0.0.1:18767/v1 model=mock-llm, not “platform OpenAI unset”.

3. CI

  • Default CI: keep unit tests with stubCompleter / httptest (no long-lived process).
  • Optional job: go run ./cmd/mock-llm in background → set OPENAI_* → run a narrow processing smoke. Do not commit real keys; use local-test.

Translation + processing verification

Two independent axes — do not confuse them:

Axis What it controls Where
UI locale Dashboard chrome strings localStorage key descrybe-ui-locale (en es fr de it pt nl pl ja) — pps/web/src/lib/i18n/locales.ts
Content language AI/product titles & descriptions Company /settings → Content Language (companies.language) — allowlist in content-languages.ts / company/language.go

A. Translation (UI + content language)

Use demo@descrybe.local (not A1).

  1. Web up (PUBLIC_API_URL / WEB_ORIGIN from root .env.example).
  2. Login → open language switcher (or set localStorage.setItem("descrybe-ui-locale","fr") then reload) — expect French chrome, not raw amespace.key paths; missing keys fall back to English.
  3. /settings → Content Language → pick e.g. de or sl → save — company payload / GET /api/me shows the new language.
  4. Optional checks: web pm run check; Go company.ParseLanguage / IsAllowedLanguage.

Root .env.example documents both locale lists (comments only — not process-env).

B. Processing against mock-llm

  1. cd apps/api && go run ./cmd/mock-llm -addr 127.0.0.1:18767
  2. Uncomment mock OPENAI_* in a private root .env (placeholders only — see .env.example) or set /integrations/ai on Platform Demo.
  3. Restart api + worker if using process env.
  4. Smoke stub: curl.exe -sS http://127.0.0.1:18767/v1/models -H "Authorization: Bearer local-test"
  5. Package tests: go test ./cmd/mock-llm -count=1
  6. Enqueue enhance (Integration / E2E section above) on a demo product — poll until i_enhance is done.
  7. Optional: change content language, re-run enhance, confirm job still completes (heuristic mock text is language-agnostic; real Green Chat honors content language in prompts).

Checklist copy lives in root .env.example under Locales and LLM test provider.


Failure modes (processing + mock-llm)

Prefer a temporary probe (closed port / wrong key / httptest timeout) over changing demo BYOK. If you stop mock-llm, restore it before leaving the session.

Mode How to induce (safe) Completer / job behavior User-facing note (after TruncateError)
Provider down Point client at closed port 127.0.0.1:18768, or briefly stop mock-llm ai_enhance failed; job item still completes with passthrough title/description AI provider unreachable — check base URL and that the service is running
Bad API key OPENAI_API_KEY=wrong-key against live mock-llm (or /integrations/ai test with wrong key) Non-retryable 401; enhance fails; passthrough copy AI provider rejected the API key
Timeout Short HTTPClient.Timeout / context.DeadlineExceeded (unit: TestRunSteps_enhanceViaHTTPLLMTimeout) Retries then fail; passthrough copy; step failed AI provider timed out — try again or check provider load
Upstream 5xx Mock returns 502 + message Retries then fail; note keeps provider message when present e.g. green-chat unavailable (retry prefix stripped)
Platform unset Empty OPENAI_API_KEY and no company BYOK Step skipped (not failed) ai_enhance: skipped (platform OpenAI unset; …)
Free plan AllowAI=false Step skipped Free-plan upgrade note

Package coverage: go test ./internal/processing -run 'HTTPLLM|mockLLM|TruncateError_classifies' -count=1.

Do not permanently change Platform Demo /integrations/ai or root .env OPENAI_* for failure probes — use closed-port clients, stubs, or a short mock-llm stop.

Restore mock-llm (after a stop)

# Confirm down
curl.exe -sS http://127.0.0.1:18767/healthz
# Start again
cd apps/api
go run ./cmd/mock-llm -addr 127.0.0.1:18767
# Expect healthz status=ok; key/model defaults: local-test / mock-llm
curl.exe -sS http://127.0.0.1:18767/healthz
curl.exe -sS http://127.0.0.1:18767/v1/models -H "Authorization: Bearer local-test"

If api/worker were started with OPENAI_BASE_URL=http://127.0.0.1:18767/v1 and OPENAI_API_KEY=local-test, no .env change is needed after restore. If you temporarily pointed a non-demo test company at a bad base URL, set it back to http://127.0.0.1:18767/v1 + local-test (or clear BYOK to use platform env).


What this is / is not

Is Is not
OpenAI Chat Completions wire format for local/CI A real GGUF / Ollama / Green Chat model
Deterministic enhance JSON via HeuristicCompleter Substitute for production model quality
Safe placeholder key local-test Something to commit as a secret

For a real tiny local model, point the same OPENAI_* keys at Ollama/LM Studio/Green Chat (OPENAI_BASE_URL=http://127.0.0.1:PORT/v1) — see green-chat-llm.md.