From a324bf439674d054412057917e07f9ee41e41f77 Mon Sep 17 00:00:00 2001 From: hikariming Date: Mon, 9 Feb 2026 23:45:39 +0800 Subject: [PATCH 1/2] add docker config --- docker/.env.cpu.example | 22 ++++++ docker/.env.example | 52 ++++++++++++ docker/README.md | 117 +++++++++++++++++++++++++++ docker/config/kb_config.json | 21 +++++ docker/docker-compose.cpu.yml | 84 ++++++++++++++++++++ docker/docker-compose.yml | 144 ++++++++++++++++++++++++++++++++++ ui/backend/app.py | 42 ++++++++++ ui/frontend/main.js | 82 ++++++++++++++++--- 8 files changed, 552 insertions(+), 12 deletions(-) create mode 100644 docker/.env.cpu.example create mode 100644 docker/.env.example create mode 100644 docker/README.md create mode 100644 docker/config/kb_config.json create mode 100644 docker/docker-compose.cpu.yml create mode 100644 docker/docker-compose.yml diff --git a/docker/.env.cpu.example b/docker/.env.cpu.example new file mode 100644 index 00000000..47bf3cc8 --- /dev/null +++ b/docker/.env.cpu.example @@ -0,0 +1,22 @@ +# CPU-only compose vars +UI_PORT=5050 +MILVUS_PORT=19530 +MILVUS_METRICS_PORT=9091 +MINIO_API_PORT=9000 +MINIO_CONSOLE_PORT=9001 +MINIO_ROOT_USER=minioadmin +MINIO_ROOT_PASSWORD=minioadmin + +# ---------------------------- +# UI defaults for external LLM/Embedding providers +# These values auto-fill in the UI settings panel. +# ---------------------------- +# ULTRARAG_UI_DEFAULT_AI_PROVIDER options: openai | custom | azure | anthropic +ULTRARAG_UI_DEFAULT_AI_PROVIDER=openai +ULTRARAG_UI_DEFAULT_AI_BASE_URL=https://api.openai.com/v1 +ULTRARAG_UI_DEFAULT_AI_API_KEY= +ULTRARAG_UI_DEFAULT_AI_MODEL=gpt-5-mini + +ULTRARAG_UI_DEFAULT_EMB_BASE_URL=https://api.openai.com/v1 +ULTRARAG_UI_DEFAULT_EMB_API_KEY= +ULTRARAG_UI_DEFAULT_EMB_MODEL_NAME=text-embedding-3-small diff --git a/docker/.env.example b/docker/.env.example new file mode 100644 index 00000000..930171ec --- /dev/null +++ b/docker/.env.example @@ -0,0 +1,52 @@ +# ---------------------------- +# UltraRAG UI +# ---------------------------- +UI_PORT=5050 + +# ---------------------------- +# Milvus / MinIO ports (host) +# ---------------------------- +MILVUS_PORT=19530 +MILVUS_METRICS_PORT=9091 +MINIO_API_PORT=9000 +MINIO_CONSOLE_PORT=9001 +MINIO_ROOT_USER=minioadmin +MINIO_ROOT_PASSWORD=minioadmin + +# ---------------------------- +# LLM (vLLM OpenAI-compatible API) +# ---------------------------- +# Example: +# LLM_MODEL_PATH=Qwen/Qwen3-8B +# LLM_MODEL_NAME=qwen3-8b +LLM_MODEL_PATH=Qwen/Qwen3-8B +LLM_MODEL_NAME=qwen3-8b +LLM_DTYPE=auto +LLM_MAX_MODEL_LEN=32768 +LLM_GPU_MEMORY_UTILIZATION=0.9 +LLM_API_PORT=8000 + +# ---------------------------- +# Embedding (vLLM OpenAI-compatible API) +# ---------------------------- +# Example: +# EMB_MODEL_PATH=Qwen/Qwen3-Embedding-0.6B +# EMB_MODEL_NAME=qwen-embedding +EMB_MODEL_PATH=Qwen/Qwen3-Embedding-0.6B +EMB_MODEL_NAME=qwen-embedding +EMB_DTYPE=auto +EMB_GPU_MEMORY_UTILIZATION=0.8 +EMB_API_PORT=8001 + +# ---------------------------- +# UI defaults (auto-filled in settings panel) +# ---------------------------- +# ULTRARAG_UI_DEFAULT_AI_PROVIDER options: openai | custom | azure | anthropic +ULTRARAG_UI_DEFAULT_AI_PROVIDER=custom +ULTRARAG_UI_DEFAULT_AI_BASE_URL=http://vllm-llm:8000/v1 +ULTRARAG_UI_DEFAULT_AI_API_KEY=dummy +ULTRARAG_UI_DEFAULT_AI_MODEL=qwen3-8b + +ULTRARAG_UI_DEFAULT_EMB_BASE_URL=http://vllm-emb:8000/v1 +ULTRARAG_UI_DEFAULT_EMB_API_KEY=dummy +ULTRARAG_UI_DEFAULT_EMB_MODEL_NAME=qwen-embedding diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..71228450 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,117 @@ +# UltraRAG One-Click Compose + +This folder provides two compose setups: + +- `docker-compose.yml` (GPU): UI + Milvus + vLLM(LLM) + vLLM(Embedding) +- `docker-compose.cpu.yml` (CPU-only): UI + Milvus (no vLLM) + +GPU setup includes: + +- UltraRAG UI +- Milvus (standalone with etcd + minio) +- vLLM OpenAI-compatible LLM endpoint +- vLLM OpenAI-compatible Embedding endpoint + +## 1) Prepare env + +```bash +cd /Users/rqq/UltraRAG/docker +cp .env.example .env +``` + +Edit `.env` at least for these fields: + +- `LLM_MODEL_PATH` +- `LLM_MODEL_NAME` +- `EMB_MODEL_PATH` +- `EMB_MODEL_NAME` +- Optional UI auto-fill defaults: + - `ULTRARAG_UI_DEFAULT_AI_BASE_URL` + - `ULTRARAG_UI_DEFAULT_AI_MODEL` + - `ULTRARAG_UI_DEFAULT_EMB_BASE_URL` + - `ULTRARAG_UI_DEFAULT_EMB_MODEL_NAME` + +## 2) Start all services + +```bash +docker compose up -d --build +``` + +Open UI: + +- [http://localhost:5050](http://localhost:5050) + +## 3) Recommended UI settings + +Inside UltraRAG UI: + +- Knowledge Base -> Milvus URI should be `tcp://milvus-standalone:19530` + - Already pre-mounted from `docker/config/kb_config.json`. +- Embedding config: + - `Base URL`: `http://vllm-emb:8000/v1` + - `Model Name`: same as `EMB_MODEL_NAME` in `.env` + - `API Key`: optional (for local vLLM you can use any non-empty value if required by UI) +- AI assistant / generation config: + - `Base URL`: `http://vllm-llm:8000/v1` + - `Model`: same as `LLM_MODEL_NAME` in `.env` + - `API Key`: optional (for local vLLM you can use any non-empty value) + +## 4) Stop + +```bash +docker compose down +``` + +To remove volumes too: + +```bash +docker compose down -v +``` + +## Notes + +- `vllm-llm` and `vllm-emb` require NVIDIA GPU + working Docker GPU runtime. +- First startup may take a long time due to model/image downloads. +- Persistent data is under `docker/volumes/`. + +--- + +## CPU-only setup (no vLLM) + +If your machine has no NVIDIA GPU, use this flow. + +### 1) Prepare env + +```bash +cd /Users/rqq/UltraRAG/docker +cp .env.cpu.example .env +``` + +### 2) Start CPU stack + +```bash +docker compose -f docker-compose.cpu.yml up -d --build +``` + +Open UI: + +- [http://localhost:5050](http://localhost:5050) + +### 3) UI settings for CPU mode + +- Knowledge Base -> Milvus URI: + - `tcp://milvus-standalone:19530` + - Already pre-mounted from `docker/config/kb_config.json`. +- Embedding and Generation models: + - Use external OpenAI-compatible API (OpenAI/Azure/other hosted endpoint). + - You can prefill UI via `.env`: + - `ULTRARAG_UI_DEFAULT_AI_*` + - `ULTRARAG_UI_DEFAULT_EMB_*` + - In UI you can still manually change provider `Base URL`, `Model`, `API Key`. + - CPU compose does not start local vLLM endpoints. + +### 4) Stop CPU stack + +```bash +docker compose -f docker-compose.cpu.yml down +``` diff --git a/docker/config/kb_config.json b/docker/config/kb_config.json new file mode 100644 index 00000000..c36d30d5 --- /dev/null +++ b/docker/config/kb_config.json @@ -0,0 +1,21 @@ +{ + "milvus": { + "uri": "tcp://milvus-standalone:19530", + "token": "", + "id_field_name": "id", + "vector_field_name": "vector", + "text_field_name": "contents", + "id_max_length": 64, + "text_max_length": 60000, + "metric_type": "IP", + "index_params": { + "index_type": "AUTOINDEX", + "metric_type": "IP" + }, + "search_params": { + "metric_type": "IP", + "params": {} + }, + "index_chunk_size": 1000 + } +} diff --git a/docker/docker-compose.cpu.yml b/docker/docker-compose.cpu.yml new file mode 100644 index 00000000..64d6d71b --- /dev/null +++ b/docker/docker-compose.cpu.yml @@ -0,0 +1,84 @@ +services: + ultrarag-ui: + build: + context: .. + dockerfile: Dockerfile.base-cpu + container_name: ultrarag-ui-cpu + restart: unless-stopped + env_file: + - .env + environment: + PYTHONUNBUFFERED: "1" + command: + - ultrarag + - show + - ui + - --admin + - --port + - "5050" + - --host + - 0.0.0.0 + ports: + - "${UI_PORT:-5050}:5050" + volumes: + - ../data:/ultrarag/data + - ../output:/ultrarag/output + - ../logs:/ultrarag/logs + - ./config/kb_config.json:/ultrarag/data/knowledge_base/kb_config.json + depends_on: + - milvus-standalone + networks: + - ultrarag-net + + etcd: + container_name: ultrarag-etcd-cpu + image: quay.io/coreos/etcd:v3.5.12 + restart: unless-stopped + command: > + etcd + --advertise-client-urls=http://etcd:2379 + --listen-client-urls=http://0.0.0.0:2379 + --data-dir=/etcd + volumes: + - ./volumes/etcd:/etcd + networks: + - ultrarag-net + + minio: + container_name: ultrarag-minio-cpu + image: minio/minio:RELEASE.2024-12-18T13-15-44Z + restart: unless-stopped + environment: + MINIO_ROOT_USER: "${MINIO_ROOT_USER:-minioadmin}" + MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD:-minioadmin}" + command: minio server /minio_data --console-address ":9001" + ports: + - "${MINIO_API_PORT:-9000}:9000" + - "${MINIO_CONSOLE_PORT:-9001}:9001" + volumes: + - ./volumes/minio:/minio_data + networks: + - ultrarag-net + + milvus-standalone: + container_name: ultrarag-milvus-cpu + image: milvusdb/milvus:v2.5.4 + restart: unless-stopped + command: ["milvus", "run", "standalone"] + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "${MILVUS_PORT:-19530}:19530" + - "${MILVUS_METRICS_PORT:-9091}:9091" + volumes: + - ./volumes/milvus:/var/lib/milvus + depends_on: + - etcd + - minio + networks: + - ultrarag-net + +networks: + ultrarag-net: + name: ultrarag-net diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..9dc1a85b --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,144 @@ +services: + ultrarag-ui: + build: + context: .. + dockerfile: Dockerfile + container_name: ultrarag-ui + restart: unless-stopped + env_file: + - .env + environment: + PYTHONUNBUFFERED: "1" + command: + - ultrarag + - show + - ui + - --admin + - --port + - "5050" + - --host + - 0.0.0.0 + ports: + - "${UI_PORT:-5050}:5050" + volumes: + - ../data:/ultrarag/data + - ../output:/ultrarag/output + - ../logs:/ultrarag/logs + - ./config/kb_config.json:/ultrarag/data/knowledge_base/kb_config.json + depends_on: + - milvus-standalone + - vllm-llm + - vllm-emb + networks: + - ultrarag-net + + etcd: + container_name: ultrarag-etcd + image: quay.io/coreos/etcd:v3.5.12 + restart: unless-stopped + command: > + etcd + --advertise-client-urls=http://etcd:2379 + --listen-client-urls=http://0.0.0.0:2379 + --data-dir=/etcd + volumes: + - ./volumes/etcd:/etcd + networks: + - ultrarag-net + + minio: + container_name: ultrarag-minio + image: minio/minio:RELEASE.2024-12-18T13-15-44Z + restart: unless-stopped + environment: + MINIO_ROOT_USER: "${MINIO_ROOT_USER:-minioadmin}" + MINIO_ROOT_PASSWORD: "${MINIO_ROOT_PASSWORD:-minioadmin}" + command: minio server /minio_data --console-address ":9001" + ports: + - "${MINIO_API_PORT:-9000}:9000" + - "${MINIO_CONSOLE_PORT:-9001}:9001" + volumes: + - ./volumes/minio:/minio_data + networks: + - ultrarag-net + + milvus-standalone: + container_name: ultrarag-milvus + image: milvusdb/milvus:v2.5.4 + restart: unless-stopped + command: ["milvus", "run", "standalone"] + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "${MILVUS_PORT:-19530}:19530" + - "${MILVUS_METRICS_PORT:-9091}:9091" + volumes: + - ./volumes/milvus:/var/lib/milvus + depends_on: + - etcd + - minio + networks: + - ultrarag-net + + vllm-llm: + container_name: ultrarag-vllm-llm + image: vllm/vllm-openai:latest + restart: unless-stopped + env_file: + - .env + gpus: all + ipc: host + ports: + - "${LLM_API_PORT:-8000}:8000" + command: + - --host + - 0.0.0.0 + - --port + - "8000" + - --model + - "${LLM_MODEL_PATH}" + - --served-model-name + - "${LLM_MODEL_NAME}" + - --dtype + - "${LLM_DTYPE:-auto}" + - --max-model-len + - "${LLM_MAX_MODEL_LEN:-32768}" + - --gpu-memory-utilization + - "${LLM_GPU_MEMORY_UTILIZATION:-0.9}" + - --trust-remote-code + networks: + - ultrarag-net + + vllm-emb: + container_name: ultrarag-vllm-emb + image: vllm/vllm-openai:latest + restart: unless-stopped + env_file: + - .env + gpus: all + ipc: host + ports: + - "${EMB_API_PORT:-8001}:8000" + command: + - --host + - 0.0.0.0 + - --port + - "8000" + - --task + - embed + - --model + - "${EMB_MODEL_PATH}" + - --served-model-name + - "${EMB_MODEL_NAME}" + - --dtype + - "${EMB_DTYPE:-auto}" + - --gpu-memory-utilization + - "${EMB_GPU_MEMORY_UTILIZATION:-0.8}" + - --trust-remote-code + networks: + - ultrarag-net + +networks: + ultrarag-net: + name: ultrarag-net diff --git a/ui/backend/app.py b/ui/backend/app.py index a1e6a2ee..c98c9643 100644 --- a/ui/backend/app.py +++ b/ui/backend/app.py @@ -31,6 +31,14 @@ LLMS_DOC_CACHE = None +def _read_ui_env_default(name: str, fallback: str = "") -> str: + """Read UI default value from environment and normalize whitespace.""" + value = os.getenv(name, fallback) + if value is None: + return fallback + return str(value).strip() + + def load_llms_doc() -> str: """Load docs/llms.txt once and cache it for system prompt usage.""" global LLMS_DOC_CACHE @@ -171,6 +179,40 @@ def get_app_mode() -> Response: """ return jsonify({"admin_mode": app.config.get("ADMIN_MODE", False)}) + @app.route("/api/defaults/ai", methods=["GET"]) + def get_ai_defaults() -> Response: + """Return UI default AI/Embedding settings from environment variables.""" + ai_provider = _read_ui_env_default("ULTRARAG_UI_DEFAULT_AI_PROVIDER", "openai") + if ai_provider not in {"openai", "custom", "azure", "anthropic"}: + ai_provider = "openai" + + payload = { + "ai": { + "provider": ai_provider, + "baseUrl": _read_ui_env_default( + "ULTRARAG_UI_DEFAULT_AI_BASE_URL", "https://api.openai.com/v1" + ), + "apiKey": _read_ui_env_default("ULTRARAG_UI_DEFAULT_AI_API_KEY", ""), + "model": _read_ui_env_default( + "ULTRARAG_UI_DEFAULT_AI_MODEL", "gpt-5-mini" + ), + }, + "embedding": { + "api_key": _read_ui_env_default( + "ULTRARAG_UI_DEFAULT_EMB_API_KEY", "" + ), + "base_url": _read_ui_env_default( + "ULTRARAG_UI_DEFAULT_EMB_BASE_URL", + "https://api.openai.com/v1", + ), + "model_name": _read_ui_env_default( + "ULTRARAG_UI_DEFAULT_EMB_MODEL_NAME", + "text-embedding-3-small", + ), + }, + } + return jsonify(payload) + @app.route("/api/templates", methods=["GET"]) def list_templates() -> Response: """List available pipeline templates. diff --git a/ui/frontend/main.js b/ui/frontend/main.js index 54429121..7d3a5923 100644 --- a/ui/frontend/main.js +++ b/ui/frontend/main.js @@ -1093,6 +1093,18 @@ window.saveDbConfig = async function () { const CHUNK_CONFIG_STORAGE_KEY = "ultrarag_chunk_config"; const INDEX_CONFIG_STORAGE_KEY = "ultrarag_index_config"; +const AI_SETTINGS_STORAGE_KEY = "ultrarag_ai_settings"; +const DEFAULT_INDEX_CONFIG = { + api_key: "", + base_url: "https://api.openai.com/v1", + model_name: "text-embedding-3-small" +}; +const DEFAULT_AI_SETTINGS = { + provider: "openai", + baseUrl: "https://api.openai.com/v1", + apiKey: "", + model: "gpt-5-mini" +}; // Load Chunk configuration from localStorage function loadChunkConfigFromStorage() { @@ -1192,12 +1204,9 @@ window.saveChunkConfig = function () { // --- Index (Embedding) Configuration Logic --- // ========================================== +const storedIndexConfig = loadIndexConfigFromStorage(); // 1. Define default configuration state (try to restore from localStorage) -let indexConfigState = loadIndexConfigFromStorage() || { - api_key: "", - base_url: "https://api.openai.com/v1", - model_name: "text-embedding-3-small" -}; +let indexConfigState = { ...DEFAULT_INDEX_CONFIG, ...(storedIndexConfig || {}) }; // 2. Open configuration modal (echo current state) window.openIndexConfigModal = function () { @@ -8440,15 +8449,49 @@ const aiState = { lastUserMessage: null, lastContextSnapshot: null, settings: { - provider: 'openai', - baseUrl: 'https://api.openai.com/v1', - apiKey: '', - model: 'gpt-5-mini' + ...DEFAULT_AI_SETTINGS }, messages: [], conversationHistory: [] }; +let cachedUiDefaults = null; +let uiDefaultsLoaded = false; + +async function fetchUIDefaults() { + if (uiDefaultsLoaded) return cachedUiDefaults; + try { + const resp = await fetch('/api/defaults/ai'); + if (!resp.ok) { + uiDefaultsLoaded = true; + return null; + } + const payload = await resp.json(); + cachedUiDefaults = (payload && typeof payload === 'object') ? payload : null; + } catch (e) { + console.warn('Failed to load UI defaults:', e); + cachedUiDefaults = null; + } + uiDefaultsLoaded = true; + return cachedUiDefaults; +} + +function applyEnvDefaultsToIndex(indexDefaults) { + if (!indexDefaults || typeof indexDefaults !== 'object') return; + + // Respect existing localStorage settings; only fill missing values. + const hasSavedIndex = !!storedIndexConfig; + if (!hasSavedIndex || !indexConfigState.api_key) { + indexConfigState.api_key = indexDefaults.api_key || indexConfigState.api_key; + } + if (!hasSavedIndex || !indexConfigState.base_url) { + indexConfigState.base_url = indexDefaults.base_url || indexConfigState.base_url; + } + if (!hasSavedIndex || !indexConfigState.model_name) { + indexConfigState.model_name = indexDefaults.model_name || indexConfigState.model_name; + } +} + const AI_WELCOME_HTML = `
@@ -8488,7 +8531,7 @@ const AI_WELCOME_HTML = `
`; -function initAIAssistant() { +async function initAIAssistant() { const trigger = document.getElementById('ai-assistant-trigger'); const panel = document.getElementById('ai-assistant-panel'); const sidebarBtn = document.getElementById('navbar-ai-btn'); @@ -8504,6 +8547,19 @@ function initAIAssistant() { if (!panel || (!trigger && !sidebarBtn)) return; + const uiDefaults = await fetchUIDefaults(); + if (uiDefaults && typeof uiDefaults === 'object') { + const aiDefaults = uiDefaults.ai || {}; + aiState.settings = { + ...aiState.settings, + provider: aiDefaults.provider || aiState.settings.provider, + baseUrl: aiDefaults.baseUrl || aiState.settings.baseUrl, + apiKey: aiDefaults.apiKey || aiState.settings.apiKey, + model: aiDefaults.model || aiState.settings.model + }; + applyEnvDefaultsToIndex(uiDefaults.embedding || {}); + } + loadAISettings(); updateAIConnectionStatus(); loadAIConversation(); @@ -8731,15 +8787,17 @@ function initAISettingsPanel() { function loadAISettings() { try { - const saved = localStorage.getItem('ultrarag_ai_settings'); + const saved = localStorage.getItem(AI_SETTINGS_STORAGE_KEY); if (saved) { const parsed = JSON.parse(saved); aiState.settings = { ...aiState.settings, ...parsed }; updateAIConnectionStatus(); + return true; } } catch (e) { console.error('Failed to load AI settings:', e); } + return false; } function saveAISettings(options = {}) { @@ -8758,7 +8816,7 @@ function saveAISettings(options = {}) { }; try { - localStorage.setItem('ultrarag_ai_settings', JSON.stringify(aiState.settings)); + localStorage.setItem(AI_SETTINGS_STORAGE_KEY, JSON.stringify(aiState.settings)); if (statusEl && !silent) { statusEl.textContent = t('builder_ai_settings_saved_success'); From e2b9418c880750451831b8d51e325dc16852c6dd Mon Sep 17 00:00:00 2001 From: hikariming Date: Tue, 10 Feb 2026 20:39:12 +0800 Subject: [PATCH 2/2] chore: ignore docker/volumes directory --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 0c5774d4..ec603c54 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ servers/*/server.yaml # Python package metadata src/*.egg-info/ + +# Docker volumes +docker/volumes/