version: '3.8' services: portainer: image: portainer/portainer-ce:latest container_name: portainer restart: always ports: - "8000:8000" - "9000:9000" - "9443:9443" volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data environment: - TZ=Europe/Tallinn networks: - ai_network postgres: image: kartoza/postgis:16 container_name: postgres_postgis restart: always ports: - "5432:5432" environment: POSTGRES_USER: ai_user POSTGRES_PASSWORD: ai_secure_pass_2026 POSTGRES_DB: research_db POSTGRES_INITDB_ARGS: "-c shared_buffers=256MB -c max_connections=200" PGDATA: /var/lib/postgresql/data/pgdata TZ: Europe/Tallinn volumes: - postgres_data:/var/lib/postgresql/data - ./init-db:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U ai_user -d research_db"] interval: 10s timeout: 5s retries: 5 networks: - ai_network mariadb: image: mariadb:11 container_name: mariadb restart: always ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: ai_root_pass_2026 MYSQL_DATABASE: research_mariadb MYSQL_USER: ai_mariadb_user MYSQL_PASSWORD: ai_mariadb_pass_2026 TZ: Europe/Tallinn volumes: - mariadb_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uai_mariadb_user", "-pai_mariadb_pass_2026"] interval: 10s timeout: 5s retries: 5 networks: - ai_network weaviate: image: semitechnologies/weaviate:latest container_name: weaviate restart: always ports: - "8080:8080" - "50051:50051" environment: QUERY_DEFAULTS_LIMIT: 25 AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true' PERSISTENCE_DATA_PATH: '/var/lib/weaviate' DEFAULT_VECTORIZER_MODULE: 'none' CLUSTER_HOSTNAME: 'weaviate' volumes: - weaviate_data:/var/lib/weaviate networks: - ai_network ollama: image: ollama/ollama:rocm container_name: ollama restart: always ports: - "11434:11434" volumes: - ollama_data:/root/.ollama - /models/ollama:/models environment: - OLLAMA_LLM_LIBRARY=rocm - HSA_OVERRIDE_GFX_VERSION=11.0.0 - HCC_AMDGPU_TARGET=gfx1100 - OLLAMA_HOST=0.0.0.0:11434 devices: - /dev/kfd:/dev/kfd - /dev/dri:/dev/dri networks: - ai_network # ═══════════════════════════════════════════════════════════ # HEALTHCHECK - Vajalik Open WebUI depends_on jaoks # ═══════════════════════════════════════════════════════════ healthcheck: test: ["CMD-SHELL", "ollama list || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 45s # ═══════════════════════════════════════════════════════════════════════════════ # SEARXNG - Privaatne metaotsingumotor (Google, Bing, DuckDuckGo, arXiv, PubMed) # ═══════════════════════════════════════════════════════════════════════════════ searxng: image: searxng/searxng:latest container_name: searxng restart: always ports: - "8888:8080" volumes: - /data/docker/searxng:/etc/searxng:rw environment: - SEARXNG_BASE_URL=http://100.87.1.24:8888/ - SEARXNG_SECRET=searxng_secret_key_change_me_2026_random_string - TZ=Europe/Tallinn - SEARXNG_LIMITER=false networks: - ai_network healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 30s # ═══════════════════════════════════════════════════════════════ # OPEN WEBUI - Professionaalne LLM liides # ═══════════════════════════════════════════════════════════════ open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui restart: always ports: - "3000:8080" volumes: - open-webui_data:/app/backend/data - /data/docker/open-webui/open-webui-uploads:/app/backend/data/uploads - /data/docker/open-webui/open-webui-docs:/app/backend/data/docs environment: # ═══════════════════════════════════════════════════════════ # PÕHISEADED # ═══════════════════════════════════════════════════════════ - WEBUI_SECRET_KEY=ai_webui_secret_2026_change_me_to_random_string - TZ=Europe/Tallinn - OLLAMA_BASE_URL=http://ollama:11434 - OPENAI_API_BASE_URLS=http://100.87.1.24:8070/v1 - OPENAI_API_KEYS=sk-dummy-key-not-required # ═══════════════════════════════════════════════════════════ # WEBSOCKET & STREAMING # ═══════════════════════════════════════════════════════════ - ENABLE_CHAT_STREAMING=true - WEBSOCKET_MANAGER_ENABLED=true - POLLING_INTERVAL=500 # ═══════════════════════════════════════════════════════════ # RAG & EMBEDDINGS (ILMA VECTOR_DB MUUTUJATA!) # ═══════════════════════════════════════════════════════════ - ENABLE_RAG_WEB_SEARCH=true - RAG_EMBEDDING_ENGINE=ollama - RAG_EMBEDDING_MODEL=nomic-embed-text:latest - CHUNK_SIZE=2000 - CHUNK_OVERLAP=200 - RAG_TOP_K=10 - RAG_RELEVANCE_THRESHOLD=0.5 - PDF_EXTRACT_IMAGES=true - ENABLE_RAG_LOCAL_WEB_FETCH=true # ═══════════════════════════════════════════════════════════ # WEB SEARCH (SearXNG integratsioon) # ═══════════════════════════════════════════════════════════ #- RAG_WEB_SEARCH_ENGINE=duckduckgo - RAG_WEB_SEARCH_ENGINE=searxng #- SEARXNG_QUERY_URL=http://searxng:8080/search?q=&categories=general,science - SEARXNG_QUERY_URL=http://searxng:8080/search?q=&format=json&categories=general,news,science - RAG_WEB_SEARCH_RESULT_COUNT=5 - RAG_WEB_SEARCH_CONCURRENT_REQUESTS=8 # ═══════════════════════════════════════════════════════════ # WEAVIATE - KOMMENTEERITUD VÄLJA # ═══════════════════════════════════════════════════════════ # - VECTOR_DB=weaviate # <- EEMALDA SEE RIDA! # - WEAVIATE_HOST=weaviate # <- EEMALDA # - WEAVIATE_PORT=8080 # <- EEMALDA # - WEAVIATE_GRPC_HOST=weaviate # <- EEMALDA # - WEAVIATE_GRPC_PORT=50051 # <- EEMALDA # - WEAVIATE_USE_AUTH=false # <- EEMALDA # - WEAVIATE_TIMEOUT=30 # <- EEMALDA # ═══════════════════════════════════════════════════════════ # AUTENTIMINE # ═══════════════════════════════════════════════════════════ - WEBUI_AUTH=true - ENABLE_SIGNUP=false - DEFAULT_USER_ROLE=user - ENABLE_LOGIN_FORM=true - ENABLE_API_KEY=true # ═══════════════════════════════════════════════════════════ # FAILID # ═══════════════════════════════════════════════════════════ - UPLOAD_DIR=/app/backend/data/uploads - ENABLE_IMAGE_GENERATION=false - ENABLE_FILE_UPLOAD=true - FILE_UPLOAD_MAX_SIZE=100 - FILE_UPLOAD_ALLOWED_TYPES=.pdf,.txt,.md,.csv,.json,.xml # ═══════════════════════════════════════════════════════════ # VESTLUSED # ═══════════════════════════════════════════════════════════ - ENABLE_MESSAGE_RATING=true - ENABLE_COMMUNITY_SHARING=false - ENABLE_ADMIN_EXPORT=true - ENABLE_ADMIN_CHAT_ACCESS=false - CHAT_CONTEXT_WINDOW=8192 - TASK_MODEL=qwen2.5:7b - TASK_MODEL_EXTERNAL=http://100.87.1.24:8070/v1 # ═══════════════════════════════════════════════════════════ # CORS & MUUD # ═══════════════════════════════════════════════════════════ - CORS_ALLOW_ORIGIN=* - AUDIO_STT_ENGINE=whisper - AUDIO_TTS_ENGINE=openedai-speech - AUDIO_STT_OPENAI_API_BASE_URL=http://100.87.1.24:8070/v1 - ENABLE_MODEL_FILTER=true - BYPASS_MODEL_ACCESS_CONTROL=false - SHOW_ADMIN_DETAILS=true - GLOBAL_LOG_LEVEL=INFO - WEBUI_SESSION_COOKIE_SECURE=false - WEBUI_SESSION_COOKIE_SAME_SITE=lax - DATABASE_URL=postgresql://ai_user:ai_secure_pass_2026@postgres:5432/openwebui_db depends_on: ollama: condition: service_healthy postgres: condition: service_healthy networks: - ai_network extra_hosts: - "host.docker.internal:host-gateway" healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 60s jupyter: image: jupyter/datascience-notebook:latest container_name: jupyter restart: always ports: - "8887:8888" environment: - JUPYTER_ENABLE_LAB=yes - JUPYTER_TOKEN=ai_server_2026 - TZ=Europe/Tallinn volumes: - /data/docker/jupyter/notebooks:/home/jovyan/work - /data/docker/jupyter/data:/home/jovyan/data - jupyter_data:/home/jovyan/.jupyter networks: - ai_network command: start-notebook.sh --NotebookApp.token='ai_server_2026' --NotebookApp.allow_root=True rocm-pytorch: image: rocm/pytorch:latest container_name: rocm_pytorch restart: always ports: - "8889:8888" - "6006:6006" environment: - HSA_OVERRIDE_GFX_VERSION=11.5.1 - PYTORCH_ROCM_ARCH=gfx1151 - ROCM_HOME=/opt/rocm - TZ=Europe/Tallinn - TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 devices: - /dev/kfd:/dev/kfd - /dev/dri:/dev/dri volumes: - /data/docker/jupyter/pytorch-workspace:/workspace - /data/docker/jupyter/models:/models - /data/docker/jupyter/data:/data - rocm_pytorch_data:/root/.cache working_dir: /workspace cap_add: - SYS_PTRACE security_opt: - seccomp=unconfined ipc: host shm_size: 8G group_add: - video networks: - ai_network command: > bash -c "pip install jupyter notebook tensorboard transformers datasets huggingface_hub scikit-learn pandas psycopg2-binary && jupyter notebook --ip=0.0.0.0 --port=8888 --no-browser --allow-root --NotebookApp.token='ai_pytorch_2026'" rag-api: build: context: /opt/docker-compose/main/Dockerfile/rag-api dockerfile: Dockerfile container_name: rag_api restart: always ports: - "8072:8000" environment: LLAMA_CPP_URL: http://100.87.1.24:8070/completion WEAVIATE_HOST: weaviate WEAVIATE_HTTP_PORT: 8080 WEAVIATE_URL: http://weaviate:8080 WEAVIATE_CLASS: ScientificArticle DB_HOST: postgres DB_PORT: 5432 DB_NAME: pdf_research DB_USER: osm DB_PASSWORD: osm OLLAMA_URL: http://ollama:11434 TZ: Europe/Tallinn MARIADB_HOST: mariadb MARIADB_PORT: 3306 MARIADB_DB: research_mariadb MARIADB_USER: ai_mariadb_user MARIADB_PASSWORD: ai_mariadb_pass_2026 volumes: - /data/docker/rag-api/src:/app/src depends_on: - weaviate - ollama - postgres networks: - ai_network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/docs"] interval: 30s timeout: 10s retries: 3 start_period: 40s volumes: portainer_data: driver: local postgres_data: driver: local weaviate_data: driver: local ollama_data: driver: local jupyter_data: driver: local rocm_pytorch_data: driver: local mariadb_data: driver: local open-webui_data: driver: local networks: ai_network: driver: bridge