Files
descrybe/docs/green-chat-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

252 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Green Chat → Descrybe v2 (OpenAI-compatible)
Use LAN **green-chat** (`systemd` unit `green-chat.service`, binary `/usr/local/bin/ge chat ser` / `ge chat serve`) as Descrybes LLM the same way you would use OpenAI.
Descrybe already speaks OpenAI Chat Completions via one shared client (`processing.OpenAIClient`). **Preferred setup:** company admin → **`/integrations/ai`** (custom OpenAI-compatible base URL + key, or a popular provider). Optional process-env `OPENAI_*` remains a platform fallback when the company uses mode **internal**.
| Feature | Process | Path |
|---------|---------|------|
| Product AI enhance | **worker** | Completer → `POST {base}/chat/completions` |
| Campaign email AI | **API** | same Completer |
| SEO meta AI | **API** | same Completer |
| Brand voice | API/worker | Brand kit `PromptBlock()` injected into those Completer prompts (no separate LLM call) |
Config resolve: `apps/api/internal/aiprovider` (company BYOK) → optional `OPENAI_*` from `apps/api/internal/config`
Client: `apps/api/internal/processing/openai.go`
Wiring: `cmd/worker/main.go`, `internal/httpapi/server.go`
**Do not commit real API keys, tokens, or production LAN endpoints.** Use a single **root** `.env` for bootstrap secrets — do not duplicate `apps/api/.env`.
For **CI / local processing without a real model**, use the OpenAI-compatible stub: **[mock-llm.md](mock-llm.md)** (`go run ./cmd/mock-llm`). Prefer tenant **`demo@descrybe.local`** (not A1).
---
## Setup (preferred: dashboard)
1. Ensure root `.env` has `APP_ENCRYPTION_KEY` (secrets at rest) and the API + worker are running.
2. Sign in as a **company admin****`/integrations/ai`**.
3. Choose **custom** (or a popular provider), set base URL to `http://GREEN_HOST:PORT/v1`, model id from `GET /v1/models`, paste API key, enable, **Test**.
4. Restart is **not** required for dashboard-saved keys (unlike process env).
## Optional env fallback (`OPENAI_*`)
When the company leaves AI mode **internal**, the platform Completer can use process env:
| Variable | Default | Role |
|----------|---------|------|
| `OPENAI_API_KEY` | _(empty)_ | Bearer token. **Must be non-empty** to enable the platform fallback Completer. Use the key from green-chat drop-ins, or any placeholder (e.g. `local`) if the server ignores auth. |
| `OPENAI_BASE_URL` | `https://api.openai.com/v1` | Root **including** `/v1`. Client appends `/chat/completions`. |
| `OPENAI_MODEL` | `gpt-4o-mini` | Model id from green-chat `GET /v1/models` (often a GGUF path/name, not `gpt-4o-mini`). |
| `PROCESSING_RPM` | `60` | Client-side spacing between calls |
| `PROCESSING_MAX_RETRIES` | `3` | Retries on 429 / 5xx / transport errors |
There is no `OPENAI_API_BASE` — use **`OPENAI_BASE_URL`**.
Typical Green Chat path:
```text
POST http://GREEN_HOST:PORT/v1/chat/completions
└──────── OPENAI_BASE_URL ────────┘└── client appends ──┘
```
Also useful: `GET /v1/models`, and often `GET /health`.
### Example root `.env` (placeholders only — optional fallback)
Put these in the **repo root** `.env` only if you need platform-env fallback. Prefer `/integrations/ai`. Restart **both** API and worker after env changes.
```env
OPENAI_API_KEY=YOUR_GREEN_API_KEY_OR_local
OPENAI_BASE_URL=http://192.168.x.x:PORT/v1
OPENAI_MODEL=YOUR_MODEL_ID_FROM_v1_models
```
PowerShell (session only):
```powershell
$env:OPENAI_API_KEY = "YOUR_GREEN_API_KEY_OR_local"
$env:OPENAI_BASE_URL = "http://192.168.x.x:PORT/v1"
$env:OPENAI_MODEL = "YOUR_MODEL_ID_FROM_v1_models"
```
Free plan blocks AI credits (`can_use_ai=false`). Use a paid/demo company with credits for real smoke tests — see [free-tier.md](free-tier.md) and [demo-user.md](demo-user.md).
---
## Discover IP, port, path, and API key ON THE GREEN MACHINE
Run these on the Linux host that runs `green-chat` (SSH as a user that can `sudo` where needed).
### Unit + drop-ins
```bash
sudo systemctl cat green-chat
sudo systemctl cat green-chat.service.d/99-gemma4.conf
sudo systemctl cat green-chat.service.d/runtime.conf
```
Also useful:
```bash
sudo systemctl status green-chat --no-pager -l
ls -la /etc/systemd/system/green-chat.service.d/
sudo systemctl show green-chat -p Environment -p EnvironmentFiles -p ExecStart -p MainPID
```
Look for listen host/port, `--model` / `MODEL=`, and anything named `API_KEY` / `OPENAI_*` / `AUTH` / `TOKEN`. **Do not paste real secrets into git or chat logs.**
### Listen address and LAN IP
```bash
ss -tlnp | grep -E 'ge|green|chat'
hostname -I
sudo journalctl -u green-chat -n 50 --no-pager
```
| Bind you see | Meaning |
|--------------|---------|
| `0.0.0.0:PORT` or `*:PORT` | Reachable from Windows on the LAN (if firewall allows) |
| `127.0.0.1:PORT` only | **Not** reachable from other machines — rebind to `0.0.0.0` (or add a reverse proxy) |
Default Green Engine chat port is often **8767** (`GE_CHAT_PORT` / `--port`); your drop-ins may override it. Always trust `ss` / the unit over assumptions.
### API key
```bash
# Unit environment (may include keys — redact before sharing)
sudo systemctl show green-chat -p Environment --no-pager
sudo systemctl show green-chat -p EnvironmentFiles --no-pager
# Grep drop-ins / nearby config (redact output)
grep -RInE 'API_KEY|OPENAI|BEARER|TOKEN|AUTH' \
/etc/systemd/system/green-chat.service.d/ 2>/dev/null | head -40
```
If green-chat does not require auth, Descrybe still needs a **non-empty** `OPENAI_API_KEY` (e.g. `local`) so the Completer turns on.
### Model id
```bash
# From drop-ins
grep -RInE 'model|gemma|MODEL' /etc/systemd/system/green-chat.service.d/ 2>/dev/null
# Or from the running server (on the green host)
curl -sS -H "Authorization: Bearer YOUR_KEY_OR_local" \
"http://127.0.0.1:PORT/v1/models"
```
Use the `data[].id` value as `OPENAI_MODEL`.
### Loopback smoke test (on green host)
```bash
PORT=CHANGEME
KEY='YOUR_GREEN_API_KEY_OR_local'
MODEL='CHANGEME'
curl -sS -w "\nHTTP %{http_code}\n" \
-H "Authorization: Bearer $KEY" \
"http://127.0.0.1:${PORT}/v1/models"
curl -sS -w "\nHTTP %{http_code}\n" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "{\"model\":\"${MODEL}\",\"messages\":[{\"role\":\"user\",\"content\":\"Say hi in one word.\"}],\"temperature\":0.2}" \
"http://127.0.0.1:${PORT}/v1/chat/completions"
```
Expect HTTP 200 and `choices[0].message.content`.
### Firewall (green host)
```bash
sudo ufw status || true
# Example once PORT is known (restrict to your LAN):
# sudo ufw allow from 192.168.0.0/16 to any port PORT proto tcp
```
If loopback works but Windows does not: fix **bind** (`0.0.0.0`) and/or **firewall** first.
---
## Smoke test FROM Windows (Laragon)
Replace placeholders with values from the green host. This PC is typically on `192.168.50.x`.
```powershell
$GreenIP = "192.168.x.x" # from hostname -I on green machine
$Port = "PORT" # from ss / unit (often 8767)
$Key = "YOUR_GREEN_API_KEY_OR_local"
$Model = "YOUR_MODEL_ID"
Test-NetConnection -ComputerName $GreenIP -Port $Port
curl.exe -sS -w "`nHTTP %{http_code}`n" `
-H "Authorization: Bearer $Key" `
"http://${GreenIP}:${Port}/v1/models"
curl.exe -sS -w "`nHTTP %{http_code}`n" `
-H "Authorization: Bearer $Key" `
-H "Content-Type: application/json" `
-d "{\"model\":\"$Model\",\"messages\":[{\"role\":\"user\",\"content\":\"Say hi in one word.\"}],\"temperature\":0.2}" `
"http://${GreenIP}:${Port}/v1/chat/completions"
```
Then configure **`/integrations/ai`** (preferred) or set root `.env` `OPENAI_*` and start both processes:
```powershell
cd f:\laragon\www\_MY\descrybe-v2
.\scripts\run-api.ps1 # campaigns + SEO AI
.\scripts\run-api.ps1 worker # product AI enhance (other terminal)
```
Root `.env` is loaded by `loadDotEnv` / `scripts/run-api.ps1` — do not recreate `apps/api/.env`. Prefer `/integrations/ai` for new setups ([UNCERTAIN] env platform OpenAI fallback may be removed later).
### App-level checks (after AI config + worker up)
| Surface | How |
|---------|-----|
| Campaign AI | `POST /api/campaigns/{id}/generate` with `{"mode":"ai"}` (paid/demo company) |
| SEO AI | `POST /api/seo/apply` with `{"product_id":"…","mode":"ai"}` |
| Processing | Worker running; start a job that runs enhance; notes must not say `openai_not_configured` |
| Brand | Fill brand kit; AI generate/enhance should reflect voice (same Completer) |
Email **send** (Resend/SMTP / `EMAIL_DRY_RUN`) is separate from Green Chat; AI only affects **copy generation**.
---
## Reachability checklist (this workstation)
Run when Green Chat IP/port is unknown or LAN calls fail:
1. On green: `sudo systemctl cat green-chat` (+ drop-ins above) → port, bind, model, key env names.
2. On green: `ss -tlnp | grep -E 'ge|green|chat'` → confirm `0.0.0.0` (not only `127.0.0.1`).
3. On green: `hostname -I` → LAN IP for Windows `.env`.
4. On green: loopback `curl` to `/v1/models` and `/v1/chat/completions`.
5. On green: firewall allows your Windows host (or LAN) to that TCP port.
6. On Windows: `Test-NetConnection GREEN_IP -Port PORT`, then the curl smoke tests.
7. Configure AI in **`/integrations/ai`** (or optional root `.env` `OPENAI_API_KEY` / `OPENAI_BASE_URL=http://GREEN_IP:PORT/v1` / `OPENAI_MODEL`).
8. Ensure API + worker are running; retest campaign/SEO/processing on a **non-Free** company.
### Probe notes (2026-08-04, Laragon PC `192.168.50.119`)
| Target | Result |
|--------|--------|
| Process env `OPENAI_*` | Unset |
| DNS `green` / `green-chat` / `gemma` | No resolution |
| LAN neighbors (`192.168.50.39`, `.100`, `.143`, `.181`) on default chat ports (`8767`, `8080`, …) | **No** OpenAI-compatible green-chat endpoint reachable |
| Open ports seen | `.143:8443`/`:9000` (not chat API); `.181:80`/`:443`; `.100:80` — not usable as `/v1/chat/completions` |
| Local `http://127.0.0.1:8767` (`ge chat serve` on this PC) | **OK**`GET /v1/models` 200; `POST /v1/chat/completions` 200 (`Hello.`) |
**Conclusion:** Descrybe wiring is ready. Remote gemma4 `green-chat` IP/port/key must come from the discovery commands on that host (likely loopback-bound or firewalled today).
---
## Related
- [ai-full-smoke.md](ai-full-smoke.md) — full AI feature pass/fail against LAN Green Chat
- [local-llm-tuning.md](local-llm-tuning.md) — weak-model prompt/JSON/token defaults
- [process-and-sell-summary.md](process-and-sell-summary.md) — `OPENAI_*` table
- [ops-runtime.md](ops-runtime.md) — worker / credits
- [free-tier.md](free-tier.md) / [demo-user.md](demo-user.md) — AI gates and demo credits