Secure backend for uploading documents (TXT/PDF) and running semantic search over your private library using pgvector. It provides JWT-authenticated APIs for document management plus vector search/query endpoints.
- Go API (Chi + GORM): auth, document upload, parsing, background processing, search/query.
- Python embedding CLI (
fastembed): chunks text and produces embeddings that are stored in Postgres/pgvector. - Postgres + pgvector: stores document metadata and chunk embeddings; supports similarity search via
<=>.
flowchart LR
client[Client] --> api[Go_API_Chi]
api --> storage[Local_Uploads]
api --> db[(Postgres_pgvector)]
api --> py[Python_Embedding_CLI_fastembed]
py --> api
Flow (upload → searchable):
POST /api/documentsuploads a file and triggers async processing.- Backend extracts plain text (TXT/PDF), chunks it, calls the Python CLI to embed chunks, then stores vectors in
document_chunks. POST /api/searchandPOST /api/queryembed the query and run pgvector similarity search.
- Backend: Go (Chi, GORM)
- Embeddings: Python (
fastembed, modelBAAI/bge-small-en-v1.5) - Database: Postgres + pgvector (
ankane/pgvector) - Containerization: Docker + Docker Compose
Choose one of the following setups:
- Docker-first (recommended):
- Docker Desktop (or Docker Engine + Compose v2)
- Local dev (no containers):
- Go 1.25+
- Python 3.12+
- Postgres with
vectorextension (or run DB via Docker only)
From the repo root (where docker-compose.yml lives):
docker compose up -d --build
docker compose psAPI will be available at:
http://localhost:8080- Health check:
http://localhost:8080/health
docker compose downRemove volumes too (DB data + uploads + model cache):
docker compose down -vThis is useful if you want hot iteration in Go while keeping Postgres in Docker.
docker compose up -d dbBackend loads .env (optional) from backend/.env.
Recommended minimal values:
DB_HOST=localhostDB_PORT=5432DB_USER=postgresDB_PASSWORD=postgresDB_NAME=aidocdbJWT_SECRET=<some-long-random-string>
Embedding CLI configuration:
PYTHON_PATH=python3(default)SCRIPT_PATH=/absolute/or/relative/path/to/embedding-service/app/main.py
Note:
EMBEDDING_SERVICE_URLis not used in the current implementation (embeddings are generated via CLI execution, not HTTP).
cd backend
go mod tidy
go run cmd/api/main.gocurl -s http://localhost:8080/healthcurl -s -X POST http://localhost:8080/api/register \
-H "Content-Type: application/json" \
-d '{"username":"rohan","email":"rohan@example.com","password":"Pass@123"}'
curl -s -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"email":"rohan@example.com","password":"Pass@123"}'If you have jq installed:
TOKEN=$(curl -s -X POST http://localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"email":"rohan@example.com","password":"Pass@123"}' | jq -r '.token')echo "Company policy: Employees can work remotely 2 days per week." > sample.txt
curl -s -X POST http://localhost:8080/api/documents \
-H "Authorization: Bearer $TOKEN" \
-F "document=@sample.txt"curl -s -X POST http://localhost:8080/api/search \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"remote work policy"}'
curl -s -X POST http://localhost:8080/api/query \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"How many remote days are allowed?"}'PORT: API port (default8080)DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME: Postgres connectionJWT_SECRET: secret used to sign JWTs (change for production)
PYTHON_PATH: python interpreter used by the Go backend (defaultpython3)SCRIPT_PATH: path to embedding CLI script (default in container:/app/embedding-service/app/main.py)
backend/: Go API servicecmd/api/main.go: entrypoint & route wiringinternal/: handlers, middleware, services, repositories, modelspkg/: utilities, database, parsing/extraction
embedding-service/: Python embedding CLI code and requirementsdocker-compose.yml: local stack (Postgres + backend)Dockerfile: production-style multi-stage build for backend (Go + Python runtime)
Run Docker commands from repo root and use Compose:
docker compose up -d --buildfastembed downloads the model on first use. Compose mounts model_cache to persist it across restarts.
docker compose logs -f backend
docker compose logs -f dbAPI contract lives in:
backend/api/openapi.yaml
- CORS is currently permissive; lock it down for production.
- Replace default DB creds + set a strong
JWT_SECRETbefore any real deployment.