Files
AI_portal/README.md
Ondřej Glaser 48cef99257 Initial portal commit: landing + 9 AI-powered apps
Apps:
- dwg-rooms: extract room numbers from DWG/DXF
- dwg-counting: count symbols in PDF drawings (OpenCV template matching)
- contract-check: review PDF contracts against a checklist (Claude vision + Tesseract OCR fallback)
- email-drafter: bullet notes → polished Czech/English business emails
- invoice-extractor: PDF/image invoice → structured data → Excel
- translator: Czech-first translator across 19 languages with tone control
- vv-check: find inconsistent unit prices across VV sheets in one workbook
- vv-compare: diff original vs new VV files (changes / added / removed)
- feature-request: portal users submit ideas + sample files

Infrastructure:
- LiteLLM gateway with per-app virtual keys + budgets
- Langfuse observability
- Geist font, shared theme, cross-subdomain back link + theme sync via cookie/URL
- Caddy reverse proxy on *.klas.chat
2026-05-13 15:25:04 +02:00

2.3 KiB

AI Portal

Internal landing page that fronts a stack of AI tools (chat + workflow apps), all routed through company API keys with per-user budgets and observability.

See AI_PORTAL_HANDOFF.md for full architecture and rationale.

Phase 0 — what's running

  • Landing page (Next.js 16 + Auth.js v5) — this repo, landing/
  • Open WebUI — already running on host (127.0.0.1:8080)
  • Dify stack — already running (docker_default network, nginx on :443/:8090)
  • LiteLLM — already running on localai network (:4000)
  • Langfuse — not yet (compose stub left in docker-compose.yml)

Local dev

cd landing
cp ../.env.example ../.env       # then edit secrets
pnpm install
pnpm dev                         # http://localhost:3000

Set at minimum:

  • AUTH_SECRETopenssl rand -base64 32
  • DEV_PORTAL_PASSWORD — any string; gates the dev login

Production-style run (Docker)

From the portal/ directory:

docker compose up -d --build

The landing service binds to 127.0.0.1:3010. Caddy on the host fronts it at https://ai.klas.chat.

Auth

Two providers, both wired through Auth.js v5:

  1. Microsoft Entra ID — production. Activated automatically when AUTH_MICROSOFT_ENTRA_ID_ID and AUTH_MICROSOFT_ENTRA_ID_SECRET are set.
  2. Dev Credentials — single shared password from DEV_PORTAL_PASSWORD. Used only while Entra is not provisioned. Both can coexist; the login page shows whichever is configured.

All routes except /login and /api/auth/* are gated by proxy.ts.

Adding a new tile

Edit landing/src/data/apps.json and add an entry:

{
  "id": "my-app",
  "title": "My App",
  "description": "What it does in one line.",
  "category": "Documents",
  "icon": "FileText",
  "accent": "blue",
  "href": "https://dify.klas.chat/app/<id>"
}

Icon names come from lucide-react. Accents: violet, blue, cyan, emerald, amber, rose. Use "href": "#" to mark a tile as "Coming soon".

What's next (post Phase 0)

  1. Wire Open WebUI to use LiteLLM as its OpenAI-compatible endpoint.
  2. Configure Dify model providers to point at LiteLLM (so spend is attributed).
  3. Stand up Langfuse (uncomment in docker-compose.yml).
  4. Map per-user identity → LiteLLM virtual keys.
  5. Provision Microsoft Entra app registration; flip prod auth on.