Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
14 changes: 14 additions & 0 deletions lending-poc/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.git
.venv
**/.venv
**/.venv-windows
**/surya-env
**/node_modules
**/__pycache__
document_processing
field_mapping_poc
gateway
frontend
scripts
docs
*.log
18 changes: 18 additions & 0 deletions lending-poc/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=lending_poc
POSTGRES_HOST_PORT=55439
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:55439/lending_poc
ENCRYPTION_KEY=changeme-generate-a-base64-fernet-key
DEBUG=true

# Selects the surya-inference/ocr variant docker-compose.yml runs: "cpu"
# (default, always works) or "gpu" (requires an NVIDIA GPU + NVIDIA
# Container Toolkit / WSL GPU passthrough on the host).
COMPOSE_PROFILES=cpu

# Model used by the translation and field_mapping services via Ollama.
# Must be pulled into the ollama container first:
# docker compose exec ollama ollama pull <model>
OLLAMA_MODEL=gemma4:e4b-it-qat
# OLLAMA_HOST=http://ollama:11434
7 changes: 6 additions & 1 deletion lending-poc/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ __pycache__/
*.pyo
.venv/
.env
**/.env
*.egg-info/
dist/
build/
.mypy_cache/
.pytest_cache/
.ruff_cache/
venv/
venv/
**/.venv/
.venv-windows/
local.env
*.log
4 changes: 2 additions & 2 deletions lending-poc/Database_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pip install -e ".[dev]"
Create a `.env` file in the project root:

```bash
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:55432/lending_poc
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:55439/lending_poc
ENCRYPTION_KEY=<32-byte base64 key>
DEBUG=true
```
Expand All @@ -39,7 +39,7 @@ python3 -c "import base64, os; print(base64.b64encode(os.urandom(32)).decode())"
docker compose up -d db
```

This starts Postgres with pgvector on host port `55432` (mapped from container port `5432`), and waits until it reports healthy.
This starts Postgres with pgvector on host port `55439` (mapped from container port `5432`), and waits until it reports healthy.

## 4. Run database migrations

Expand Down
140 changes: 140 additions & 0 deletions lending-poc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Lending POC

Lending POC — FastAPI backend + PostgreSQL (pgvector), plus a document
processing pipeline (OCR, translation, field mapping) fronted by a gateway,
and a React frontend. This guide covers running the **entire stack in
Docker**.

For running the `app` service natively against a containerized DB only
(e.g. for backend development with hot-reload outside Docker), see
[Database_setup.md](Database_setup.md).

## Prerequisites

- [Docker](https://docs.docker.com/get-docker/) and Docker Compose v2
(`docker compose version`)
- Git
- **Optional, for GPU acceleration**: an NVIDIA GPU, the
[NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html),
and (on Windows) WSL2 with GPU passthrough enabled

## 1. Clone and configure environment

```bash
git clone <repo-url>
cd lending-poc
cp .env.example .env
```

Generate a real `ENCRYPTION_KEY` — the app uses it to encrypt sensitive
database fields, and the placeholder value in `.env.example` is not a valid
key:

```bash
python3 -c "import base64, os; print(base64.b64encode(os.urandom(32)).decode())"
```

Paste the result into `ENCRYPTION_KEY=` in `.env`.

Leave `COMPOSE_PROFILES=cpu` as-is unless you have a working GPU setup —
see [Using a GPU](#using-a-gpu) below.

## 2. Start the stack

```bash
docker compose up --build -d
```

This builds and starts every service: `db`, `app`, `ollama`, `field_mapping`,
`translation`, `surya-inference` + `ocr`, `gateway`, and `frontend`.

The first run takes a while — Ollama and Surya both download models on
first use. Watch progress with:

```bash
docker compose logs -f
```

## 3. Run database migrations

The `app` container doesn't run migrations automatically on startup:

```bash
docker compose exec app alembic -c db/alembic.ini upgrade head
```

## 4. Pull the Ollama model

Needed by the `translation` and `field_mapping` services:

```bash
docker compose exec ollama ollama pull gemma4:e4b-it-qat
```

(Substitute whatever `OLLAMA_MODEL` is set to in `.env` if you changed it.
If you're running the GPU profile, use `ollama-gpu` instead of `ollama` in
the command above.)

## 5. Verify it's running

| Service | URL | Notes |
|---|---|---|
| Frontend | http://localhost:5173 | Main UI |
| Gateway | http://localhost:8080 | Fronts OCR / translation / field-mapping |
| App (backend API) | http://localhost:8000 | Docs at `/docs`; health at `/health` |
| Postgres | localhost:55439 | pgvector-enabled |
| OCR | http://localhost:8010 | Not normally called directly |
| Translation | http://localhost:8001 | Not normally called directly |
| Field mapping | http://localhost:8002 | Not normally called directly |
| Surya inference | http://localhost:8500 | OCR's inference backend |

There are effectively two subsystems sharing this compose file: the
`app` + `db` lending backend, and a separate OCR/translation/field-mapping
pipeline fronted by `gateway`. The frontend talks to the gateway for
document processing and to the app for everything else.

## Using a GPU

`surya-inference`/`ocr` and `ollama` each come in a CPU and a GPU variant,
selected by `COMPOSE_PROFILES` in `.env`:

- `COMPOSE_PROFILES=cpu` (default) — always works, no GPU required.
- `COMPOSE_PROFILES=gpu` — requires an NVIDIA GPU on the host plus the
NVIDIA Container Toolkit (and, on Windows, WSL2 GPU passthrough).

To switch:

```bash
# in .env
COMPOSE_PROFILES=gpu
```

```bash
docker compose up --build -d
```

Both GPU containers detect GPU access at startup and fall back to CPU
automatically if it isn't actually usable — but `docker compose up` will
fail to create the containers at all if the toolkit isn't installed,
since the GPU device reservation can't be satisfied.

Ollama's own image auto-detects CUDA at runtime with no separate build, so
switching the profile is enough for it; `surya-inference`/`ocr` are built
from CUDA base images specifically for the `gpu` profile (see
[docker-compose.yml](docker-compose.yml) and
[document_processing/ocr/README.md](document_processing/ocr/README.md)
for details).

## Stopping and cleanup

```bash
docker compose down
```

Add `-v` to also delete the named volumes (`pgdata`, `ollama_models`,
`surya_models`) — this wipes the database and downloaded models, so only
do this if you want a clean slate:

```bash
docker compose down -v
```
2 changes: 1 addition & 1 deletion lending-poc/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra="ignore" lets pydantic-settings skip env vars not declared on Settings (e.g. POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_HOST_PORT, COMPOSE_PROFILES — used by docker-compose, not read by the app). Without it, pydantic's default extra="forbid" would raise ValidationError on startup since those keys aren't fields on the model.
Tradeoff: a typo in a key we do care about (e.g. DATABASE_URL) would also be silently ignored rather than erroring.


APP_NAME: str = "lending-poc"
APP_VERSION: str = "0.1.0"
Expand Down
Loading