Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
64 changes: 64 additions & 0 deletions application/open-webui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Use CrateDB with Open WebUI

## About

A complete end-to-end rig including CrateDB, CrateDB MCPO, and Open WebUI.

[Open WebUI] is an extensible, feature-rich, and user-friendly self-hosted AI
platform designed to operate entirely offline. It supports various LLM runners
like Ollama and OpenAI-compatible APIs, with built-in inference engine for RAG,
making it a powerful AI deployment solution.

CrateDB MCPO is a wrapper around CrateDB MCP, publishing the exposed tools via
OpenAPI, to connect it to Open WebUI.

## What's inside

- `.env`: The dotenv file defines `OPENAI_API_KEY` for `compose.yml` and `OPEN_WEBUI_URL` for `setup.sh`.
- `compose.yml`: The service composition file defines three services: CrateDB, CrateDB MCPO, and Open WebUI.
Use it with `docker compose` or `podman compose`.
- `setup.Dockerfile`: Container runtime definition for `setup.sh`, including all requirements.
- `setup.sh`: Program that configures Open WebUI via HTTP API.
- `tool-servers.json`: JSON snippet for configuring the CrateDB MCPO server through `/api/v1/configs/tool_servers`.

## Operate

Configure the API key for OpenAI as environment variable, or define it within
the `.env` file.
```shell
export OPENAI_API_KEY=<your_openapi_key>
```

Spin up the software stack.
```shell
docker compose up -d
```

## Usage

You can access the services and their resources on those URLs.

- CrateDB: http://localhost:4200/
- CrateDB MCPO: http://localhost:5200/docs, http://localhost:5200/openapi.json
- Open WebUI: http://localhost:6200/, http://localhost:6200/docs

## Configure

To make the ensemble work well, you need to configure a few bits on the Open WebUI
user interface after ramping up the rig.

- Make sure to enable the "CrateDB" tool on the left side of the query prompt,
behind the "More (`+`)" button.
- Make sure to enable "Function Calling: Native" within the flyout widget about
"Chat Controls", to be opened in the top right corner of the screen.
- If you like, you can dial down to "Temperature: 0.5".

## Example questions

Enjoy conversations with CrateDB and its documentation.

- Text-to-SQL: What is the average value for sensor 1?
- Knowledgebase: How do I use CrateDB with SQLAlchemy?


[Open WebUI]: https://docs.openwebui.com/
6 changes: 6 additions & 0 deletions application/open-webui/backlog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Open WebUI / MCPO backlog

- `compose.yml`: The MCPO OCI currently does not include `curl`.
Improve healthcheck after adding it.
- Add example questions to general instructions à la "If the user asks about questions
to use here, enumerate those items: [...]"
124 changes: 124 additions & 0 deletions application/open-webui/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Use CrateDB with Open WebUI
#
# https://cratedb.com/docs/
# https://docs.openwebui.com/getting-started/quick-start
---
networks:
llm-demo:
name: llm-demo
driver: bridge

volumes:
cratedb:
open-webui:

services:

# -------
# CrateDB
# -------
cratedb:
image: docker.io/crate/crate:6.0.0
environment:
CRATE_HEAP_SIZE: 2g
ports:
- "4200:4200"
- "5432:5432"
command: [
"crate",
"-Cdiscovery.type=single-node",
"-Ccluster.routing.allocation.disk.threshold_enabled=false",
]
networks:
- llm-demo
volumes:
- cratedb:/data
healthcheck:
test: [ "CMD", "curl", "--fail", "http://localhost:4200" ]
start_period: 3s
interval: 10s

# ------------
# CrateDB MCPO
# ------------
cratedb-mcpo:
image: ghcr.io/crate/cratedb-mcpo:0.0.5
environment:
CRATEDB_CLUSTER_URL: http://crate:crate@cratedb:4200/
ports:
- "5200:8000"
networks:
- llm-demo
#healthcheck:
# test: [ "CMD", "curl", "--fail", "http://localhost:8000/docs" ]
# start_period: 3s
# interval: 10s

# ----------
# Open WebUI
# ----------
open-webui:
image: ghcr.io/open-webui/open-webui:0.6.18
# https://docs.openwebui.com/getting-started/env-configuration
# https://docs.openwebui.com/getting-started/api-endpoints/#swagger-documentation-links
environment:
# From `.env` file.
OPENAI_API_KEY:
# Defined here.
ENABLE_SIGNUP: False
ENABLE_LOGIN_FORM: False
WEBUI_AUTH: False
DEFAULT_MODELS: "gpt-4.1"
DEFAULT_USER_ROLE: "admin"
ENABLE_CHANNELS: True
RESPONSE_WATERMARK: "This text is AI generated"
WEBUI_NAME: "CrateDB LLM Cockpit"
BYPASS_MODEL_ACCESS_CONTROL: True
ENABLE_OLLAMA_API: False
ENABLE_OPENAI_API: True
ENABLE_DIRECT_CONNECTIONS: True
ENV: "dev"
ports:
- "6200:8080"
networks:
- llm-demo
volumes:
- open-webui:/app/backend/data
healthcheck:
test: [ "CMD", "curl", "--fail", "http://localhost:8080" ]
start_period: 3s
interval: 10s
timeout: 90s
retries: 60

# -----
# Setup
# -----
setup:
build:
context: .
dockerfile: setup.Dockerfile
command: bash /app/setup.sh
networks:
- llm-demo
depends_on:
open-webui:
condition: service_healthy

# -------
# Bundler
# -------
# Wait for all defined services to be fully available by probing their health
# status, even when using `docker compose up --detach`.
# https://marcopeg.com/2019/docker-compose-healthcheck/
start-dependencies:
image: docker.io/dadarek/wait-for-dependencies
depends_on:
cratedb:
condition: service_healthy
#cratedb-mcpo:
# condition: service_healthy
open-webui:
condition: service_healthy
setup:
condition: service_completed_successfully
25 changes: 25 additions & 0 deletions application/open-webui/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
DROP TABLE IF EXISTS time_series_data;

CREATE TABLE IF NOT EXISTS time_series_data (
timestamp TIMESTAMP,
value DOUBLE,
location STRING,
sensor_id INT
);

INSERT INTO time_series_data (timestamp, value, location, sensor_id)
VALUES
('2023-09-14T00:00:00', 10.5, 'Sensor A', 1),
('2023-09-14T01:00:00', 15.2, 'Sensor A', 1),
('2023-09-14T02:00:00', 18.9, 'Sensor A', 1),
('2023-09-14T03:00:00', 12.7, 'Sensor B', 2),
('2023-09-14T04:00:00', 17.3, 'Sensor B', 2),
('2023-09-14T05:00:00', 20.1, 'Sensor B', 2),
('2023-09-14T06:00:00', 22.5, 'Sensor A', 1),
('2023-09-14T07:00:00', 18.3, 'Sensor A', 1),
('2023-09-14T08:00:00', 16.8, 'Sensor A', 1),
('2023-09-14T09:00:00', 14.6, 'Sensor B', 2),
('2023-09-14T10:00:00', 13.2, 'Sensor B', 2),
('2023-09-14T11:00:00', 11.7, 'Sensor B', 2);

REFRESH TABLE time_series_data;
34 changes: 34 additions & 0 deletions application/open-webui/setup.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
FROM python:3.13-slim-bookworm

# Configure operating system.
ENV DEBIAN_FRONTEND=noninteractive
ENV TERM=linux

RUN set -e \
&& apt-get update \
&& apt-get --yes install --no-install-recommends --no-install-suggests curl jq \
&& rm -rf /var/lib/apt/lists/*

# Install and configure `uv`.
# Guidelines that have been followed.
# - https://hynek.me/articles/docker-uv/

# Install the `uv` package manager.
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY --from=ghcr.io/astral-sh/uv:latest /uvx /usr/local/bin/uvx

# - Tell uv to byte-compile packages for faster application startups.
# - Silence uv complaining about not being able to use hard links.
# - Prevent uv from accidentally downloading isolated Python builds.
# - Install packages into the system Python environment.
ENV \
UV_COMPILE_BYTECODE=true \
UV_LINK_MODE=copy \
UV_PYTHON_DOWNLOADS=never \
UV_SYSTEM_PYTHON=true

RUN uv pip install crash cratedb-mcp httpie

RUN mkdir /app
WORKDIR /app
COPY .env setup.sh *.json *.sql /app/
38 changes: 38 additions & 0 deletions application/open-webui/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash

# Configure Open WebUI via HTTP API.

# Runtime options.
set -e
set -x

# Load variables.
source .env

# Sign in to receive JWT token.
token=$( http --ignore-stdin POST ${OPEN_WEBUI_URL}/api/v1/auths/signin email= password= | jq -r .token )
echo "JWT token: ${token}"

# Inquire health.
http --ignore-stdin ${OPEN_WEBUI_URL}/health

# Inquire available models.
#http ${OPEN_WEBUI_URL}/api/models Authorization:"Bearer $token"

# List available tools.
http --ignore-stdin ${OPEN_WEBUI_URL}/api/v1/tools/ Authorization:"Bearer $token"

# Configure system prompt.
http --ignore-stdin ${OPEN_WEBUI_URL}/api/v1/users/user/settings/update Authorization:"Bearer $token" ui[system]="$( cratedb-mcp show-prompt )" ui[notificationEnabled]="true"

# Configure CrateDB MCPO server.
http --ignore-stdin ${OPEN_WEBUI_URL}/api/v1/configs/tool_servers Authorization:"Bearer $token" "@tool-servers.json"

# Configure chat model.
http --ignore-stdin ${OPEN_WEBUI_URL}/api/v1/configs/models Authorization:"Bearer $token" DEFAULT_MODELS="gpt-4.1" MODEL_ORDER_LIST="[]"

# Configure embedding model.
http --ignore-stdin ${OPEN_WEBUI_URL}/api/v1/retrieval/embedding/update Authorization:"Bearer $token" embedding_engine="openai" embedding_model="text-embedding-3-small"

# Provision database
crash --hosts ${CRATEDB_URL} < init.sql
18 changes: 18 additions & 0 deletions application/open-webui/tool-servers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"TOOL_SERVER_CONNECTIONS": [
{
"url": "http://cratedb-mcpo:8000",
"path": "openapi.json",
"auth_type": "bearer",
"key": "",
"config": {
"enable": true,
"access_control": null
},
"info": {
"name": "CrateDB",
"description": "CrateDB Text-to-SQL and documentation inquiry."
}
}
]
}