Files
chat_backend/README.md
T
westfarn d1660792ad
Unit Tests / test (push) Successful in 13s
Dockerize chat_backend + Ollama LAN + DB file storage (#6) (#7)
## Summary

Implements [chat_backend#6](#6) Part A:

- **uv** packaging (`pyproject.toml` + `uv.lock`), Docker/compose (dev + prod), entrypoint/validate-env, Gitea unit-test + auto-deploy workflows (mirror `scha`)
- Env-driven Django settings (`DJANGO_*`, `DATABASE_URL`, CSRF/CORS)
- **`OLLAMA_BASE_URL`** wired through all Ollama/LangChain clients (prod → `http://10.0.0.128:11434`)
- **DatabaseStorage** — prompt/document file blobs in Postgres (`StoredFile`), not container FS; RAG materializes temp paths for loaders
- ASGI via `gunicorn` + `UvicornWorker` (HTTP + WebSockets)

Companion server-infra PR registers `app_catalog` / `host_apps` (port **8003**).

## Test plan

- [ ] `uv sync && cd llm_be && SKIP_RAG_INIT=1 uv run python manage.py test`
- [ ] `docker compose build && docker compose up` against bundled Postgres
- [ ] Confirm Ollama calls use `OLLAMA_BASE_URL` (not hardcoded localhost)
- [ ] Upload a document / prompt file → row in `chat_backend_storedfile`, no disk under `media/`
- [ ] After server-infra merge + secret/Postgres/NPM: deploy via `deploy.sh --app chat_backend --env prod`Reviewed-on: #7
2026-07-25 05:23:33 -07:00

152 lines
5.3 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.
# Chat Backend
Django + Channels API for AIML Operations chat (`chatbackend.aimloperations.com`).
Packaging via `uv`; production deploy via `server-infra`.
Companion frontend: [`chat_web_app`](https://git.aimloperations.com/ai_ml_operations/chat_web_app)
(node-static, not Docker).
Ticket: [chat_backend#6](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/6)
## Layout
```text
chat_backend/ ← repo root (Dockerfile, compose, pyproject, .gitea)
├── llm_be/ ← Django project root (manage.py)
│ ├── manage.py
│ ├── llm_be/ ← settings, urls, asgi/wsgi
│ └── chat_backend/ ← app (models, consumers, services, storage)
├── scripts/
│ ├── docker-entrypoint.sh
│ └── validate-env.sh
├── docker-compose.yml ← local/CI (bundled Postgres)
└── docker-compose.prod.yml ← server-infra (external DATABASE_URL)
```
## Local development
### Prerequisites
- Python 3.12+
- [uv](https://docs.astral.sh/uv/)
- Docker + Docker Compose (optional, recommended)
- Ollama reachable at `OLLAMA_BASE_URL` for LLM features
### uv (host)
```bash
cp .env.example .env
uv sync
cd llm_be
uv run python manage.py migrate
uv run python manage.py runserver 0.0.0.0:8003
```
Without `DATABASE_URL` / `DB_HOST`, settings fall back to SQLite (`llm_be/db.sqlite3`).
Tests (skip live-Ollama classifier cases):
```bash
cd llm_be
SKIP_RAG_INIT=1 uv run python manage.py test
```
### Docker (dev, bundled Postgres)
```bash
docker compose up --build
```
App: http://localhost:8003 — Postgres via bundled `db`
(`postgres://chat_backend:chat_backend@db:5432/chat_backend`).
Compose does **not** read host `DATABASE_URL` (avoids CI/prod leaks); override
with `COMPOSE_DATABASE_URL` if needed.
## Environment variables
| Variable | Dev default | Prod required | Notes |
|----------|-------------|---------------|-------|
| `DJANGO_ENV` | `dev` | `prod` / `beta` | |
| `DJANGO_SECRET_KEY` | insecure default | yes | Must be real in prod/beta |
| `DJANGO_DEBUG` | true when `dev` | `false` | |
| `DJANGO_ALLOWED_HOSTS` | localhost + chat hosts | yes | Comma-separated |
| `DJANGO_CSRF_TRUSTED_ORIGINS` | derived from hosts | optional | Full origins |
| `DATABASE_URL` | SQLite fallback | yes | Shared Postgres in prod |
| `WEB_PORT` | n/a (compose maps 8003) | `8003` | Host port for prod compose |
| `OLLAMA_BASE_URL` | `http://127.0.0.1:11434` | yes | GPU host in prod: `http://10.0.0.128:11434` |
| `OLLAMA_MODEL` / `OLLAMA_EMBED_MODEL` | from `DEBUG` | optional | Override model names |
| `EMAIL_HOST_*` | empty | yes (prod/beta) | SMTP2GO |
| `CAPTCHA_SECRET_KEY` | empty | recommended | |
| `CORS_ALLOWED_ORIGINS` | local + chat FE | set in prod | Frontend origin |
| `USE_TLS_PROXY` | false (dev) | true behind NPM | Sets `SECURE_PROXY_SSL_HEADER` |
| `GUNICORN_WORKERS` / `GUNICORN_BIND` | 2 / `0.0.0.0:8000` | optional | Entrypoint |
| `SKIP_RAG_INIT` | unset | CI/migrate often `1` | Skip Chroma/Ollama boot work |
Templates: `.env.example` (local), `.env.prod.example` (control-node secret).
Control-node secret path (server-infra on ai-server-4080):
```text
~/Documents/secrets/chat_backend/chat_backend_prod.env
```
Validate with:
```bash
./scripts/validate-env.sh ~/Documents/secrets/chat_backend/chat_backend_prod.env
```
If `DATABASE_URL` password contains `$`, escape each as `$$` for Compose.
## Ollama
All clients (`ollama.Client`, `OllamaLLM`, `OllamaEmbeddings`, `ChatOllama`) use
`OLLAMA_BASE_URL` — never hardcoded localhost in deployed code.
| Env | Typical URL |
|-----|-------------|
| Local (Ollama on same machine) | `http://127.0.0.1:11434` |
| prod / beta (containers on adama/roslin/ai-server) | `http://10.0.0.128:11434` |
Firewall / Ollama listen on ai-server-4080 must allow `10.0.0.0/24``:11434`.
## File storage
Prompt attachments and workspace documents use **`DatabaseStorage`**
(`chat_backend.StoredFile` BinaryField in Postgres). Blobs are **not** written
to the container filesystem under `media/`.
RAG loaders that need a path materialize a short-lived temp file, then delete it.
Chromas vector index may still use a volume (`chroma_db`); that is embeddings
metadata, not the original upload.
## Production (docker-compose.prod.yml)
- Single `web` service; **no** bundled DB — `DATABASE_URL` → shared Postgres (`10.0.0.230`).
- Host port from `WEB_PORT` (catalog: **8003**; beta reserved **8013**).
- Entrypoint: wait DB → migrate → collectstatic → `gunicorn` + `UvicornWorker`
(ASGI for HTTP **and** WebSockets).
- Active/active on **adama + roslin + ai-server-4080**; NPM balances upstreams.
- Deployed by:
```bash
~/Documents/repos/server-infra/scripts/deploy.sh \
--app chat_backend --env prod --ref <sha>
```
## CI / CD (Gitea Actions)
| Workflow | Trigger | Action |
|----------|---------|--------|
| `unittests.yml` | push + PR → `master` | `uv sync` + `manage.py test` |
| `ci.yml` | PR → `master` | same unit tests |
| `deploy.yml` | after Unit Tests succeeds on `master` **push** | docker build + tests on **ephemeral compose Postgres**`deploy.sh` |
Deploy never runs on PRs.
## Security note
Secrets previously hardcoded in `settings.py` (email password, captcha, Django
secret) must live only in the control-node env file. Rotate anything that was
ever committed; never commit `.env` or `~/Documents/secrets/`.