diff --git a/Dockerfile_go b/Dockerfile_go new file mode 100644 index 0000000000..1c0e89f838 --- /dev/null +++ b/Dockerfile_go @@ -0,0 +1,222 @@ +# base stage +FROM ubuntu:24.04 AS base +USER root +SHELL ["/bin/bash", "-c"] + +ARG NEED_MIRROR=1 + +#Optional parameter +#If set NEED_MIRROR=1, and set GITEE_TOKEN="xxxxx" , donwload source from gitee. +#If don't set GITEE_TOKEN , download from github +#ARG GITEE_TOKEN="" + +WORKDIR /ragflow + +# copy models downloaded via download_deps.py +# layout.laws/manual/paper.onnx are byte-identical to layout.onnx, so we +# exclude them from the tar extract and symlink them to layout.onnx instead, +# saving ~219MB in the image. +RUN mkdir -p /ragflow/rag/res/deepdoc /root/.ragflow +RUN --mount=type=bind,from=infiniflow/ragflow_deps:latest,source=/huggingface.co,target=/huggingface.co \ + tar --exclude='.*' \ + --exclude='layout.laws.onnx' \ + --exclude='layout.manual.onnx' \ + --exclude='layout.paper.onnx' \ + -cf - \ + /huggingface.co/InfiniFlow/text_concat_xgb_v1.0 \ + /huggingface.co/InfiniFlow/deepdoc \ + | tar -xf - --strip-components=3 -C /ragflow/rag/res/deepdoc && \ + ln -s layout.onnx /ragflow/rag/res/deepdoc/layout.laws.onnx && \ + ln -s layout.onnx /ragflow/rag/res/deepdoc/layout.manual.onnx && \ + ln -s layout.onnx /ragflow/rag/res/deepdoc/layout.paper.onnx + +ENV DEBIAN_FRONTEND=noninteractive + +# Setup apt +RUN --mount=type=cache,id=ragflow_apt,target=/var/cache/apt,sharing=locked \ + if [ "$NEED_MIRROR" == "1" ]; then \ + # CI runners may inject a proxy whose TLS certificate is not trusted inside + # the fresh Ubuntu base image yet. Keep the Ubuntu mirror on HTTP here so + # the mirror switch remains usable before the full CA store is available. + sed -i 's|http://archive.ubuntu.com/ubuntu|http://mirrors.aliyun.com/ubuntu|g' /etc/apt/sources.list.d/ubuntu.sources; \ + sed -i 's|http://security.ubuntu.com/ubuntu|http://mirrors.aliyun.com/ubuntu|g' /etc/apt/sources.list.d/ubuntu.sources; \ + fi; \ + rm -f /etc/apt/apt.conf.d/docker-clean && \ + echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache && \ + chmod 1777 /tmp && \ + apt update && \ + #apt --no-install-recommends install -y ca-certificates \ + #libglib2.0-0 libglx-mesa0 libgl1 pkg-config libgdiplus default-jdk libatk-bridge2.0-0 \ + #libgtk-4-1 libnss3 xdg-utils libjemalloc-dev gnupg unzip curl wget git vim less \ + #ghostscript pandoc texlive texlive-latex-extra texlive-xetex texlive-lang-chinese \ + #fonts-freefont-ttf fonts-noto-cjk postgresql-client + + apt --no-install-recommends install -y ca-certificates libjemalloc2 curl vim unzip iproute2 && \ + rm -rf /var/lib/apt/lists/* + +# Download resource from GitHub to /usr/share/infinity +# Ship only the directories required by the runtime tokenizer: +# rag - base analyzer dictionaries (mandatory) +# opencc - Traditional/Simplified Chinese conversion +# wordnet - WordNet resources +RUN --mount=type=cache,id=ragflow_apt,target=/var/cache/apt,sharing=locked \ + apt-get update && \ + apt-get install -y --no-install-recommends git && \ + mkdir -p /usr/share/infinity/resource && \ + if [ "$NEED_MIRROR" == "1" ]; then \ + if [ -n "$GITEE_TOKEN" ]; then \ + git clone --depth 1 --single-branch "https://oauth2:${GITEE_TOKEN}@gitee.com/infiniflow/resource" /tmp/resource; \ + else \ + git clone --depth 1 --single-branch https://github.com/infiniflow/resource.git /tmp/resource; \ + fi; \ + else \ + git clone --depth 1 --single-branch https://github.com/infiniflow/resource.git /tmp/resource; \ + fi && \ + for d in rag opencc wordnet; do \ + cp -r "/tmp/resource/$d" /usr/share/infinity/resource/; \ + done && \ + rm -rf /tmp/resource && \ + apt-get purge -y git && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + +ARG NGINX_VERSION=1.31.3-1~noble +RUN --mount=type=cache,id=ragflow_apt,target=/var/cache/apt,sharing=locked \ + apt -o Acquire::Retries=5 update && \ + apt -o Acquire::Retries=5 install -y --no-install-recommends gnupg && \ + mkdir -p /etc/apt/keyrings && \ + curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor -o /etc/apt/keyrings/nginx-archive-keyring.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/mainline/ubuntu/ noble nginx" > /etc/apt/sources.list.d/nginx.list && \ + apt -o Acquire::Retries=5 update && \ + apt -o Acquire::Retries=5 install -y --no-install-recommends nginx=${NGINX_VERSION} && \ + apt-mark hold nginx && \ + apt-get purge -y gnupg && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + +#ENV PATH=/root/.local/bin:$PATH + +# NOTE: Node.js is intentionally NOT installed in `base`. The pure-Go backend +# serves the prebuilt static frontend via nginx and needs no Node runtime at +# runtime. Node.js is only required to *build* the frontend, so it lives +# exclusively in the `web-builder` stage and never reaches the final image. + + + +# ── cpp-builder stage ────────────────────────────────────────────── +# Compile C++ static library (librag_tokenizer_c_api.a) using the +# infinity_builder image which ships clang-20, cmake and other C++ +# tooling. This stage is independent from the base image so that the +# heavy C++ build toolchain does not bloat the final production image. +FROM infiniflow/infinity_builder:ubuntu22_clang20 AS cpp-builder +USER root +SHELL ["/bin/bash", "-c"] + +ARG NEED_MIRROR=1 +WORKDIR /ragflow + +COPY internal/binding/cpp internal/binding/cpp +COPY build.sh ./ + +RUN git config --global safe.directory "*" && \ + cd /ragflow && ./build.sh --cpp + +# ── go-builder stage ── +FROM infiniflow/github_action_runner:latest AS go-builder +USER root +SHELL ["/bin/bash", "-c"] +WORKDIR /ragflow + +COPY internal internal +COPY cmd cmd +COPY go.mod go.sum ./ +COPY build.sh ./ + +# Overwrite C++ build artifact from cpp-builder +COPY --from=cpp-builder \ + /ragflow/internal/binding/cpp/cmake-build-release/librag_tokenizer_c_api.a \ + /ragflow/internal/binding/cpp/cmake-build-release/librag_tokenizer_c_api.a + +RUN git config --global safe.directory "*" && \ + ./build.sh -s --go + + +# ── web-builder stage ── +# Builds the static frontend. Node.js is installed HERE only, so the runtime +# image (production, which extends `base`) never contains Node.js. +FROM base AS web-builder +USER root + +WORKDIR /ragflow + +# Install Node.js 22.x (Ubuntu 24.04's Node.js is too old) +RUN --mount=type=cache,id=ragflow_apt,target=/var/cache/apt,sharing=locked \ + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ + apt-get purge -y nodejs npm && \ + apt-get autoremove -y && \ + apt-get update && \ + apt-get install -y nodejs + +# Install frontend dependencies — depends only on package manifests so +# web source / docs changes don't invalidate this layer. +COPY web/package.json web/package-lock.json web/.npmrc ./web/ +RUN --mount=type=cache,id=ragflow_npm,target=/root/.npm,sharing=locked \ + cd web && NODE_OPTIONS="--max-old-space-size=8192" npm install + +# Copy full web source and docs for the frontend build. +COPY web web +COPY docs docs +RUN --mount=type=cache,id=ragflow_npm,target=/root/.npm,sharing=locked \ + cd web && NODE_OPTIONS="--max-old-space-size=8192" VITE_BUILD_SOURCEMAP=false VITE_MINIFY=esbuild npm run build + +RUN --mount=type=bind,source=.git,target=/ragflow/.git \ + --mount=type=cache,id=ragflow_apt,target=/var/cache/apt,sharing=locked \ + apt-get update && \ + apt-get install -y --no-install-recommends git && \ + version_info=$(git describe --tags --match=v* --first-parent --always) && \ + echo "$version_info" > /ragflow/VERSION && \ + apt-get purge -y git && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/* + +# production stage +FROM base AS production +USER root + +WORKDIR /ragflow + +# Copy the compiled Go backend binaries (set exec bits at copy time to avoid a redundant chmod layer) +COPY --from=go-builder --chmod=755 /ragflow/bin/ /ragflow/bin/ + +ENV PYTHONPATH=/ragflow/ + +COPY docker/service_conf.yaml.template ./conf/service_conf.yaml.template +COPY docker/entrypoint*.sh ./ +RUN chmod +x ./entrypoint*.sh + +# Copy nginx configuration for frontend serving +RUN mkdir -p /etc/nginx/conf.d /var/log/nginx + +COPY docker/nginx/nginx.conf docker/nginx/proxy.conf /etc/nginx/ +COPY docker/nginx/ragflow.conf.golang \ +# docker/nginx/ragflow.conf.python \ + docker/nginx/ragflow.conf.hybrid \ + /etc/nginx/conf.d/ + +RUN rm -f /etc/nginx/sites-enabled/default + + +COPY conf conf +COPY agent/templates agent/templates + + +# Copy compiled web pages +COPY --from=web-builder /ragflow/web/dist /ragflow/web/dist + +# Copy version info +COPY --from=web-builder /ragflow/VERSION /ragflow/VERSION + +# Set environment variables +ENV HF_ENDPOINT=https://hf-mirror.com + +ENTRYPOINT ["./entrypoint-go.sh"] diff --git a/docker/.env-go b/docker/.env-go new file mode 100644 index 0000000000..a498d02b54 --- /dev/null +++ b/docker/.env-go @@ -0,0 +1,405 @@ +# ----------------------------------------------------------------------------- +# SECURITY WARNING: DO NOT DEPLOY WITH DEFAULT PASSWORDS +# For non-local deployments, please change all passwords (ELASTIC_PASSWORD, +# MYSQL_PASSWORD, MINIO_PASSWORD, etc.) to strong, unique values. +# You can generate a random string using: openssl rand -hex 32 +# ----------------------------------------------------------------------------- + +# ------------------------------ +# docker env var for specifying vector db type at startup +# (based on the vector db type, the corresponding docker +# compose profile will be used) +# ------------------------------ +# The type of doc engine to use. +# Available options: +# - `elasticsearch` (default) +# - `infinity` (https://github.com/infiniflow/infinity) +# - `oceanbase` (https://github.com/oceanbase/oceanbase) +# - `opensearch` (https://github.com/opensearch-project/OpenSearch) +# - `seekdb` (https://github.com/oceanbase/seekdb) +# - `gaussdb` GaussDB Centralized / Distributed DocEngine +DOC_ENGINE=${DOC_ENGINE:-elasticsearch} + +# The business metadata database type used by DB_TYPE. +# Available options: mysql (default), postgres, gaussdb, oceanbase. +DB_TYPE=${DB_TYPE:-mysql} + +# Device on which deepdoc inference run. +# Available levels: +# - `cpu` (default) +# - `gpu` +DEVICE=${DEVICE:-cpu} + +# This controls only the bundled metadata service started by Compose; DB_TYPE +# independently selects the metadata backend used by RAGFlow. Keep `mysql` to +# start the in-cluster MySQL service. For external GaussDB, set both +# DB_TYPE=gaussdb and METADATA_DB_PROFILE=gaussdb so MySQL stays disabled. +METADATA_DB_PROFILE=${METADATA_DB_PROFILE:-mysql} +COMPOSE_PROFILES=${DOC_ENGINE},${DEVICE},metadata-${METADATA_DB_PROFILE} + +# The version of Elasticsearch. +STACK_VERSION=${STACK_VERSION:-8.11.3} + +# The hostname where the Elasticsearch service is exposed +ES_HOST=es01 + +# The port used to expose the Elasticsearch service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +ES_PORT=1200 + +# The password for Elasticsearch. +# WARNING: Change this for production! +ELASTIC_PASSWORD=infini_rag_flow + +# the hostname where OpenSearch service is exposed, set it not the same as elasticsearch +OS_PORT=1201 + +# The hostname where the OpenSearch service is exposed +OS_HOST=opensearch01 + +# The password for OpenSearch. +# At least one uppercase letter, one lowercase letter, one digit, and one special character +OPENSEARCH_PASSWORD=infini_rag_flow_OS_01 + +# The port used to expose the Kibana service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +# To enable kibana, you need to: +# 1. Ensure that COMPOSE_PROFILES includes kibana, for example: COMPOSE_PROFILES=${COMPOSE_PROFILES},kibana +# 2. Comment out or delete the following configurations of the es service in docker-compose-base.yml: xpack.security.enabled、xpack.security.http.ssl.enabled、xpack.security.transport.ssl.enabled (for details: https://www.elastic.co/docs/deploy-manage/security/self-auto-setup#stack-existing-settings-detected) +# 3. Adjust the es.hosts in conf/service_config.yaml or docker/service_conf.yaml.template to 'https://localhost:1200' +# 4. After the startup is successful, in the es container, execute the command to generate the kibana token: `bin/elasticsearch-create-enrollment-token -s kibana`, then you can use kibana normally +KIBANA_PORT=6601 + +# The maximum amount of the memory, in bytes, that a specific Docker container can use while running. +# Update it according to the available memory in the host machine. +MEM_LIMIT=8073741824 + +# The hostname where the Infinity service is exposed +INFINITY_HOST=infinity + +# Port to expose Infinity API to the host +INFINITY_THRIFT_PORT=23817 +INFINITY_HTTP_PORT=23820 +INFINITY_PSQL_PORT=5432 + +# The hostname where the SereneDB service is exposed. SereneDB speaks the +# PostgreSQL wire protocol, so DOC_ENGINE=serenedb connects over lib/pq/psycopg2. +SERENEDB_HOST=serenedb +# Port to expose SereneDB to the host +SERENEDB_PORT=7890 +# The password for SereneDB (POSTGRES_PASSWORD in the container) +SERENEDB_PASSWORD=infini_rag_flow + +# The hostname where the OceanBase service is exposed +OCEANBASE_HOST=oceanbase +# The port used to expose the OceanBase service +OCEANBASE_PORT=2881 +# The username for OceanBase +OCEANBASE_USER=root@ragflow +# The password for OceanBase +OCEANBASE_PASSWORD=infini_rag_flow +# The doc database of the OceanBase service to use +OCEANBASE_DOC_DBNAME=ragflow_doc + +# GaussDB DocEngine connection. RAGFlow does not start or manage GaussDB; +# configure an existing GaussDB instance here. +# GaussDB host. +GAUSSDB_HOST= +# GaussDB port. +GAUSSDB_PORT= +# GaussDB database name. +GAUSSDB_DATABASE=postgres +# GaussDB login user. +GAUSSDB_USER= +# GaussDB login password. +GAUSSDB_PASSWORD= +# GaussDB schema for RAGFlow DocEngine objects. +GAUSSDB_SCHEMA= + +# OceanBase container configuration +OB_CLUSTER_NAME=${OB_CLUSTER_NAME:-ragflow} +OB_TENANT_NAME=${OB_TENANT_NAME:-ragflow} +OB_SYS_PASSWORD=${OCEANBASE_PASSWORD:-infini_rag_flow} +OB_TENANT_PASSWORD=${OCEANBASE_PASSWORD:-infini_rag_flow} +OB_MEMORY_LIMIT=${OB_MEMORY_LIMIT:-10G} +OB_SYSTEM_MEMORY=${OB_SYSTEM_MEMORY:-2G} +OB_DATAFILE_SIZE=${OB_DATAFILE_SIZE:-20G} +OB_LOG_DISK_SIZE=${OB_LOG_DISK_SIZE:-20G} + +# The hostname where the SeekDB service is exposed +SEEKDB_HOST=seekdb +# The port used to expose the SeekDB service +SEEKDB_PORT=2881 +# The username for SeekDB +SEEKDB_USER=root +# The password for SeekDB +SEEKDB_PASSWORD=infini_rag_flow +# The doc database of the SeekDB service to use +SEEKDB_DOC_DBNAME=ragflow_doc +# SeekDB memory limit +SEEKDB_MEMORY_LIMIT=2G + +# The password for MySQL. +# WARNING: Change this for production! +MYSQL_PASSWORD=infini_rag_flow +# The hostname where the MySQL service is exposed +MYSQL_HOST=mysql +# The database of the MySQL service to use +MYSQL_DBNAME=rag_flow +# The port used to connect to MySQL from RAGFlow container. +# Change this if you use external MySQL. +MYSQL_PORT=3306 +# The port used to expose the MySQL service to the host machine, +# allowing EXTERNAL access to the MySQL database running inside the Docker container. +EXPOSE_MYSQL_PORT=3306 +# The maximum size of communication packets sent to the MySQL server +MYSQL_MAX_PACKET=1073741824 + +# External GaussDB metadata database settings, used when DB_TYPE=gaussdb. +# These are intentionally separate from the GAUSSDB_* DocEngine settings. +GAUSSDB_METADATA_HOST= +GAUSSDB_METADATA_PORT= +GAUSSDB_METADATA_USER= +GAUSSDB_METADATA_PASSWORD= +GAUSSDB_METADATA_DBNAME=rag_flow +GAUSSDB_METADATA_SCHEMA=public +GAUSSDB_METADATA_MAX_CONNECTIONS=100 +GAUSSDB_METADATA_STALE_TIMEOUT=30 + +# The hostname where the MinIO service is exposed +MINIO_HOST=minio +# The port used to expose the MinIO console interface to the host machine, +# allowing EXTERNAL access to the web-based console running inside the Docker container. +MINIO_CONSOLE_PORT=9001 +# The port used to expose the MinIO API service to the host machine, +# allowing EXTERNAL access to the MinIO object storage service running inside the Docker container. +MINIO_PORT=9000 +# The username for MinIO. +# When updated, you must revise the `minio.user` entry in service_conf.yaml accordingly. +MINIO_USER=rag_flow +# The password for MinIO. +# When updated, you must revise the `minio.password` entry in service_conf.yaml accordingly. +MINIO_PASSWORD=infini_rag_flow + +# The hostname where the Redis service is exposed +REDIS_HOST=redis +# The port used to expose the Redis service to the host machine, +# allowing EXTERNAL access to the Redis service running inside the Docker container. +REDIS_PORT=6379 +# The password for Redis. +REDIS_PASSWORD=infini_rag_flow + +NATS_HOST=nats +# Port used by RAGFlow's Go services to connect to NATS inside the container network. +# Do NOT change this unless you also change `nats.port` in conf/service_conf.yaml.template. +NATS_PORT=4222 +# Host-side port that maps to the NATS container port 4222. Change this to avoid +# clashing with a port already used on the host machine. This ONLY affects the +# published host port and is never read by RAGFlow's internal services. +EXPOSE_NATS_PORT=4222 + +# The hostname where the ClickHouse service is exposed +CLICKHOUSE_HOST=clickhouse +# Native TCP port used by RAGFlow's Go services to connect to ClickHouse inside +# the container network. Do NOT change this unless you also change `clickhouse.port` +# in conf/service_conf.yaml.template. +CLICKHOUSE_TCP_PORT=9000 +# Host-side port that maps to the ClickHouse container native TCP port 9000. Change +# this to avoid clashing with a port already used on the host machine. This ONLY +# affects the published host port and is never read by RAGFlow's internal services. +EXPOSE_CLICKHOUSE_TCP_PORT=9900 +# The port used to expose the ClickHouse HTTP service +CLICKHOUSE_HTTP_PORT=8123 +# The username for ClickHouse +CLICKHOUSE_USER=ragflow +# The password for ClickHouse +CLICKHOUSE_PASSWORD=infini_rag_flow +# The database for ClickHouse +CLICKHOUSE_DATABASE=ragflow + +# Jaeger (distributed tracing) +# Enable by adding `jaeger` to COMPOSE_PROFILES, e.g.: +# COMPOSE_PROFILES=${COMPOSE_PROFILES},jaeger +# Then update otel.host in service_conf.yaml to "jaeger". +JAEGER_VERSION=2.19.0 +JAEGER_OTLP_GRPC_PORT=4317 +JAEGER_OTLP_HTTP_PORT=4318 +JAEGER_UI_PORT=16686 + +# The port used to expose RAGFlow's HTTP API service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +SVR_WEB_HTTP_PORT=80 +SVR_WEB_HTTPS_PORT=443 +SVR_HTTP_PORT=9380 +ADMIN_SVR_HTTP_PORT=9381 +SVR_MCP_PORT=9382 +GO_HTTP_PORT=9384 +GO_ADMIN_PORT=9383 + +# API_PROXY_SCHEME=hybrid # go and python hybrid deploy mode +API_PROXY_SCHEME=go # use go server deployment +#API_PROXY_SCHEME=python # use pure python server deployment + +# Development-only: set to 1 to bypass host safety checks for test_db_connection and allow private/local database hosts. +# Do not enable in production. +ALLOW_ANY_HOST=0 + +# The RAGFlow Docker image to download. v0.22+ doesn't include embedding models. +RAGFLOW_IMAGE=infiniflow/ragflow:go-test-1 + +# If you cannot download the RAGFlow Docker image: +# RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:v0.27.0 +# RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:v0.27.0 +# +# - For the `nightly` edition, uncomment either of the following: +# RAGFLOW_IMAGE=swr.cn-north-4.myhuaweicloud.com/infiniflow/ragflow:nightly +# RAGFLOW_IMAGE=registry.cn-hangzhou.aliyuncs.com/infiniflow/ragflow:nightly + +# The embedding service image, model and port. +# Important: To enable the embedding service, you need to uncomment one of the following two lines: +# COMPOSE_PROFILES=${COMPOSE_PROFILES},tei-cpu +# COMPOSE_PROFILES=${COMPOSE_PROFILES},tei-gpu + +# The embedding service image: +TEI_IMAGE_CPU=infiniflow/text-embeddings-inference:cpu-1.8 +TEI_IMAGE_GPU=infiniflow/text-embeddings-inference:1.8 + +# The embedding service model: +# Available options: +# - `Qwen/Qwen3-Embedding-0.6B` (default, requires 25GB RAM/vRAM to load) +# - `BAAI/bge-m3` (requires 21GB RAM/vRAM to load) +# - `BAAI/bge-small-en-v1.5` (requires 1.2GB RAM/vRAM to load) +TEI_MODEL=${TEI_MODEL:-Qwen/Qwen3-Embedding-0.6B} + +# The embedding service port: +TEI_HOST=tei +# The port used to expose the TEI service to the host machine, +# allowing EXTERNAL access to the service running inside the Docker container. +TEI_PORT=6380 + +# The local time zone. +TZ=Asia/Shanghai + +# Uncomment the following line if you have limited access to huggingface.co: +# HF_ENDPOINT=https://hf-mirror.com + +# Optimizations for MacOS +# Uncomment the following line if your operating system is MacOS: +# MACOS=1 + +# The maximum file size limit (in bytes) for each upload to your dataset or RAGFlow's File system. +# To change the 1GB file size limit, uncomment the line below and update as needed. +# MAX_CONTENT_LENGTH=1073741824 +# After updating, ensure `client_max_body_size` in nginx/nginx.conf is updated accordingly. +# Note that neither `MAX_CONTENT_LENGTH` nor `client_max_body_size` sets the maximum size for files uploaded to an agent. +# See https://ragflow.io/docs/dev/begin_component for details. + +# Controls how many documents are processed in a single batch. +# Defaults to 4 if DOC_BULK_SIZE is not explicitly set. +DOC_BULK_SIZE=${DOC_BULK_SIZE:-4} + +# Defines the number of items to process per batch when generating embeddings. +# Defaults to 16 if EMBEDDING_BATCH_SIZE is not set in the environment. +EMBEDDING_BATCH_SIZE=${EMBEDDING_BATCH_SIZE:-16} + +# Log level for the RAGFlow's own and imported packages. +# Available levels: +# - `DEBUG` +# - `INFO` (default) +# - `WARNING` +# - `ERROR` +# For example, the following line changes the log level of `ragflow.es_conn` to `DEBUG`: +# LOG_LEVELS=ragflow.es_conn=DEBUG + +# aliyun OSS configuration +# STORAGE_IMPL=OSS +# ACCESS_KEY=xxx +# SECRET_KEY=eee +# ENDPOINT=http://oss-cn-hangzhou.aliyuncs.com +# REGION=cn-hangzhou +# BUCKET=ragflow65536 +# + +# A user registration switch: +# - Enable registration: 1 +# - Disable registration: 0 +REGISTER_ENABLED=1 +ENABLE_REGISTER=1 + +# ----------------------------------------------------------------------------- +# Sandbox +# ----------------------------------------------------------------------------- +# Sandbox provider type and runtime settings are configured in Admin > Sandbox +# Settings. + +# Enable sandbox support. +# SANDBOX_ENABLED=1 +# COMPOSE_PROFILES=${COMPOSE_PROFILES},sandbox + +# Shared sandbox settings +# The MinIO bucket name for storing sandbox-generated artifacts. +# SANDBOX_ARTIFACT_BUCKET=sandbox-artifacts + +# Number of days before sandbox artifacts are automatically deleted. +# SANDBOX_ARTIFACT_EXPIRE_DAYS=7 + +# Self-managed deployment defaults +# These values are used by the `sandbox` compose profile and shown in Admin as +# deployment defaults for the self-managed provider. +# Pull the required base images before running: +# docker pull infiniflow/sandbox-base-nodejs:latest +# docker pull infiniflow/sandbox-base-python:latest +# Default runtime images include: +# - Node.js base image: axios +# - Python base image: requests, numpy, pandas +# SANDBOX_EXECUTOR_MANAGER_IMAGE=${SANDBOX_EXECUTOR_MANAGER_IMAGE:-infiniflow/sandbox-executor-manager:latest} +# SANDBOX_EXECUTOR_MANAGER_POOL_SIZE=${SANDBOX_EXECUTOR_MANAGER_POOL_SIZE:-3} +# SANDBOX_BASE_PYTHON_IMAGE=${SANDBOX_BASE_PYTHON_IMAGE:-infiniflow/sandbox-base-python:latest} +# SANDBOX_BASE_NODEJS_IMAGE=${SANDBOX_BASE_NODEJS_IMAGE:-infiniflow/sandbox-base-nodejs:latest} +# SANDBOX_EXECUTOR_MANAGER_PORT=${SANDBOX_EXECUTOR_MANAGER_PORT:-9385} +# SANDBOX_ENABLE_SECCOMP=false +# SANDBOX_MAX_MEMORY=256m # b, k, m, g +# SANDBOX_TIMEOUT=10s # s, m, 1m30s + +# ----------------------------------------------------------------------------- +# Sandbox End +# ----------------------------------------------------------------------------- + +# Enable DocLing +USE_DOCLING=false + +# Enable Mineru +# Uncommenting these lines will automatically add MinerU to the model provider whenever possible. +# More details see https://ragflow.io/docs/faq#how-to-use-mineru-to-parse-pdf-documents. +# MINERU_DELETE_OUTPUT=0 # keep output directory +# MINERU_BACKEND=pipeline # or another backend you prefer + +# pptx support +DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 + +# crypto utils +# RAGFLOW_CRYPTO_ENABLED=true +# RAGFLOW_CRYPTO_ALGORITHM=aes-256-cbc # one of aes-256-cbc, aes-128-cbc, sm4-cbc +# RAGFLOW_CRYPTO_KEY=ragflow-crypto-key + + +# Used for ThreadPoolExecutor +THREAD_POOL_MAX_WORKERS=128 + +#Option to disable login form for SSO +DISABLE_PASSWORD_LOGIN=false + +# ----------------------------------------------------------------------------- +# DeepDoc OSS Vision Service +# ----------------------------------------------------------------------------- +# URL for the deepdoc vision API (DLA, OCR, TSR) served by OSS ONNX models. +# The `deepdoc` service defined in docker-compose.yml provides this endpoint. +# When unset, the parser falls back to inline ONNX Runtime inference. + +# Comment existing COMPOSE_PROFILES and uncomment below if need deepdoc service. +# COMPOSE_PROFILES=${DOC_ENGINE},${DEVICE},deepdoc + +# DEEPDOC_URL=http://deepdoc:9390 + +# Docker image for the OSS deepdoc service. CPU-only; uses ONNX Runtime. +# DEEPDOC_IMAGE=deepdoc_oss:latest diff --git a/docker/docker-compose-go.yml b/docker/docker-compose-go.yml new file mode 100644 index 0000000000..aa8915c847 --- /dev/null +++ b/docker/docker-compose-go.yml @@ -0,0 +1,167 @@ +include: + - ./docker-compose-base.yml +# To ensure that the container processes the locally modified `service_conf.yaml.template` instead of the one included in its image, you need to mount the local `service_conf.yaml.template` to the container. +services: + deepdoc: + image: ${DEEPDOC_IMAGE:-deepdoc_oss:latest} + profiles: + - deepdoc + build: + context: .. + dockerfile: Dockerfile_deepdoc_oss + networks: + - ragflow + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9390/health"] + interval: 10s + timeout: 10s + retries: 60 + + ragflow-cpu: + depends_on: + mysql: + condition: service_healthy + required: false + profiles: + - cpu + image: ${RAGFLOW_IMAGE} + ulimits: + nofile: + soft: 65535 + hard: 65535 + nproc: + soft: 65535 + hard: 65535 + # Example configuration to set up an MCP server: + # command: + # - --enable-mcpserver + # - --mcp-host=0.0.0.0 + # - --mcp-port=9382 + # - --mcp-base-url=http://127.0.0.1:9380 + # - --mcp-script-path=/ragflow/mcp/server/server.py + # - --mcp-mode=self-host + # - --mcp-host-api-key=ragflow-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + # Optional transport flags for MCP (customize if needed). + # Host mode need to combined with --no-transport-streamable-http-enabled flag, namely, host+streamable-http is not supported yet. + # The following are enabled by default unless explicitly disabled with --no-. + # - --no-transport-sse-enabled # Disable legacy SSE endpoints (/sse and /messages/) + # - --no-transport-streamable-http-enabled # Disable Streamable HTTP transport (/mcp endpoint) + # - --no-json-response # Disable JSON response mode in Streamable HTTP transport (instead of SSE over HTTP) + + # Example configuration to start Admin server: + command: + - --enable-adminserver + #- --init-model-provider-tables + ports: + - ${SVR_WEB_HTTP_PORT}:80 + - ${SVR_WEB_HTTPS_PORT}:443 + - ${SVR_HTTP_PORT}:9380 + - ${ADMIN_SVR_HTTP_PORT}:9381 + - ${SVR_MCP_PORT}:9382 # entry for MCP (host_port:docker_port). The docker_port must match the value you set for `mcp-port` above. + - ${GO_HTTP_PORT}:9384 + - ${GO_ADMIN_PORT}:9383 + volumes: + - ./ragflow-logs:/ragflow/logs + # - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf + # - ./nginx/proxy.conf:/etc/nginx/proxy.conf + # - ./nginx/nginx.conf:/etc/nginx/nginx.conf + - ./service_conf.yaml.template:/ragflow/conf/service_conf.yaml.template + - ./entrypoint-go.sh:/ragflow/entrypoint.sh + env_file: .env-go + networks: + - ragflow + restart: unless-stopped + # https://docs.docker.com/engine/daemon/prometheus/#create-a-prometheus-configuration + # If you use Docker Desktop, the --add-host flag is optional. This flag ensures that the host's internal IP is exposed to the Prometheus container. + extra_hosts: + - "host.docker.internal:host-gateway" + + ragflow-gpu: + depends_on: + mysql: + condition: service_healthy + required: false + profiles: + - gpu + image: ${RAGFLOW_IMAGE} + ulimits: + nofile: + soft: 65535 + hard: 65535 + nproc: + soft: 65535 + hard: 65535 + # Example configuration to set up an MCP server: + # command: + # - --enable-mcpserver + # - --mcp-host=0.0.0.0 + # - --mcp-port=9382 + # - --mcp-base-url=http://127.0.0.1:9380 + # - --mcp-script-path=/ragflow/mcp/server/server.py + # - --mcp-mode=self-host + # - --mcp-host-api-key=ragflow-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + # Optional transport flags for MCP (customize if needed). + # Host mode need to combined with --no-transport-streamable-http-enabled flag, namely, host+streamable-http is not supported yet. + # The following are enabled by default unless explicitly disabled with --no-. + # - --no-transport-sse-enabled # Disable legacy SSE endpoints (/sse and /messages/) + # - --no-transport-streamable-http-enabled # Disable Streamable HTTP transport (/mcp endpoint) + # - --no-json-response # Disable JSON response mode in Streamable HTTP transport (instead of SSE over HTTP) + + # Example configuration to start Admin server: + command: + - --enable-adminserver + ports: + - ${SVR_WEB_HTTP_PORT}:80 + - ${SVR_WEB_HTTPS_PORT}:443 + - ${SVR_HTTP_PORT}:9380 + - ${ADMIN_SVR_HTTP_PORT}:9381 + - ${SVR_MCP_PORT}:9382 # entry for MCP (host_port:docker_port). The docker_port must match the value you set for `mcp-port` above. + volumes: + - ./ragflow-logs:/ragflow/logs + # - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf + # - ./nginx/proxy.conf:/etc/nginx/proxy.conf + # - ./nginx/nginx.conf:/etc/nginx/nginx.conf + - ./service_conf.yaml.template:/ragflow/conf/service_conf.yaml.template + - ./entrypoint.sh:/ragflow/entrypoint.sh + env_file: .env-go + networks: + - ragflow + restart: unless-stopped + # https://docs.docker.com/engine/daemon/prometheus/#create-a-prometheus-configuration + # If you use Docker Desktop, the --add-host flag is optional. This flag ensures that the host's internal IP is exposed to the Prometheus container. + extra_hosts: + - "host.docker.internal:host-gateway" + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + + + # executor: + # depends_on: + # mysql: + # condition: service_healthy + # image: ${RAGFLOW_IMAGE} + # volumes: + # - ./ragflow-logs:/ragflow/logs + # - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf + # env_file: .env + # entrypoint: "/ragflow/entrypoint_task_executor.sh 1 3" + # networks: + # - ragflow + # restart: unless-stopped + # # https://docs.docker.com/engine/daemon/prometheus/#create-a-prometheus-configuration + # # If you're using Docker Desktop, the --add-host flag is optional. This flag makes sure that the host's internal IP gets exposed to the Prometheus container. + # extra_hosts: + # - "host.docker.internal:host-gateway" + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: all + # capabilities: [gpu] diff --git a/docker/entrypoint-go.sh b/docker/entrypoint-go.sh new file mode 100755 index 0000000000..2c3fd8a640 --- /dev/null +++ b/docker/entrypoint-go.sh @@ -0,0 +1,366 @@ +#!/usr/bin/env bash + +set -e + +echo "Start RAGFlow cluster, version: " +cat /ragflow/VERSION + +# ----------------------------------------------------------------------------- +# Usage and command-line argument parsing +# ----------------------------------------------------------------------------- +function usage() { + echo "Usage: $0 [OPTIONS]" + echo + echo " --disable-webserver Disables the web server (nginx + ragflow_server)." + echo " --disable-taskexecutor Disables task executor workers." + echo " --disable-datasync Disables synchronization of datasource workers." + echo " --enable-mcpserver Enables the MCP server." + echo " --enable-adminserver Enables the Admin server." + echo " --init-model-provider-tables Run model provider table migrations and exit." + echo " --init-superuser Initializes the superuser." + echo " --consumer-no-beg= Start range for consumers (if using range-based)." + echo " --consumer-no-end= End range for consumers (if using range-based)." + echo " --workers= Number of task executors to run (if range is not used)." + echo " --host-id= Unique ID for the host (defaults to \`hostname\`)." + echo " --mcp-host= Address the MCP server binds to (default: 127.0.0.1)." + echo " --mcp-port= Port the MCP server listens on (default: 9382)." + echo " --mcp-base-url= RAGFlow base URL the MCP server calls (default: http://127.0.0.1:9380)." + echo " --mcp-script-path= MCP server entry script (default: /ragflow/mcp/server/server.py)." + echo " --mcp-mode= MCP server mode (default: self-host)." + echo " --mcp-host-api-key= API key required when --mcp-mode=self-host." + echo " --no-transport-sse-enabled Disables the MCP SSE transport." + echo " --no-transport-streamable-http-enabled Disables the MCP streamable HTTP transport. Disabling" + echo " both transports re-enables this one, since the server" + echo " requires at least one." + echo " --no-json-response Disables JSON responses from the MCP server." + echo + echo "Examples:" + echo " $0 --disable-taskexecutor" + echo " $0 --disable-webserver --consumer-no-beg=0 --consumer-no-end=5" + echo " $0 --disable-webserver --workers=2 --host-id=myhost123" + echo " $0 --enable-mcpserver" + echo " $0 --enable-adminserver" + echo " $0 --init-superuser" + exit 1 +} + +ENABLE_WEBSERVER=1 # Default to enable web server +ENABLE_TASKEXECUTOR=1 # Default to enable task executor +ENABLE_DATASYNC=1 +ENABLE_MCP_SERVER=0 +ENABLE_ADMIN_SERVER=0 # Default close admin server +INIT_SUPERUSER_ARGS="" # Default to not initialize superuser +INIT_MODEL_PROVIDER_TABLES=0 +CONSUMER_NO_BEG=0 +CONSUMER_NO_END=0 +WORKERS=1 + +MCP_HOST="127.0.0.1" +MCP_PORT=9382 +MCP_BASE_URL="http://127.0.0.1:9380" +MCP_SCRIPT_PATH="/ragflow/mcp/server/server.py" +MCP_MODE="self-host" +MCP_HOST_API_KEY="" +MCP_TRANSPORT_SSE_FLAG="--transport-sse-enabled" +MCP_TRANSPORT_STREAMABLE_HTTP_FLAG="--transport-streamable-http-enabled" +MCP_JSON_RESPONSE_FLAG="--json-response" + +# ----------------------------------------------------------------------------- +# Host ID logic: +# 1. By default, use the system hostname if length <= 32 +# 2. Otherwise, use the full MD5 hash of the hostname (32 hex chars) +# ----------------------------------------------------------------------------- +CURRENT_HOSTNAME="$(hostname)" +if [ ${#CURRENT_HOSTNAME} -le 32 ]; then + DEFAULT_HOST_ID="$CURRENT_HOSTNAME" +else + DEFAULT_HOST_ID="$(echo -n "$CURRENT_HOSTNAME" | md5sum | cut -d ' ' -f 1)" +fi + +HOST_ID="$DEFAULT_HOST_ID" + +# Parse arguments +for arg in "$@"; do + case $arg in + --disable-webserver) + ENABLE_WEBSERVER=0 + shift + ;; + --disable-taskexecutor) + ENABLE_TASKEXECUTOR=0 + shift + ;; + --disable-datasync) + ENABLE_DATASYNC=0 + shift + ;; + --enable-mcpserver) + ENABLE_MCP_SERVER=1 + shift + ;; + --enable-adminserver) + ENABLE_ADMIN_SERVER=1 + shift + ;; + --init-model-provider-tables) + INIT_MODEL_PROVIDER_TABLES=1 + shift + ;; + --init-superuser) + INIT_SUPERUSER_ARGS="--init-superuser" + shift + ;; + --mcp-host=*) + MCP_HOST="${arg#*=}" + shift + ;; + --mcp-port=*) + MCP_PORT="${arg#*=}" + shift + ;; + --mcp-base-url=*) + MCP_BASE_URL="${arg#*=}" + shift + ;; + --mcp-mode=*) + MCP_MODE="${arg#*=}" + shift + ;; + --mcp-host-api-key=*) + MCP_HOST_API_KEY="${arg#*=}" + shift + ;; + --mcp-script-path=*) + MCP_SCRIPT_PATH="${arg#*=}" + shift + ;; + --no-transport-sse-enabled) + MCP_TRANSPORT_SSE_FLAG="--no-transport-sse-enabled" + shift + ;; + --no-transport-streamable-http-enabled) + MCP_TRANSPORT_STREAMABLE_HTTP_FLAG="--no-transport-streamable-http-enabled" + shift + ;; + --no-json-response) + MCP_JSON_RESPONSE_FLAG="--no-json-response" + shift + ;; + --consumer-no-beg=*) + CONSUMER_NO_BEG="${arg#*=}" + shift + ;; + --consumer-no-end=*) + CONSUMER_NO_END="${arg#*=}" + shift + ;; + --workers=*) + WORKERS="${arg#*=}" + shift + ;; + --host-id=*) + HOST_ID="${arg#*=}" + shift + ;; + *) + usage + ;; + esac +done + +# ----------------------------------------------------------------------------- +# Replace env variables in the service_conf.yaml file +# ----------------------------------------------------------------------------- +CONF_DIR="/ragflow/conf" +TEMPLATE_FILE="${CONF_DIR}/service_conf.yaml.template" +CONF_FILE="${CONF_DIR}/service_conf.yaml" + +rm -f "${CONF_FILE}" +DEF_ENV_VALUE_PATTERN="\$\{([^:]+):-([^}]+)\}" +while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" =~ DEF_ENV_VALUE_PATTERN ]]; then + varname="${BASH_REMATCH[1]}" + default="${BASH_REMATCH[2]}" + + if [ -n "${!varname}" ]; then + eval "echo \"$line"\" >> "${CONF_FILE}" + else + echo "$line" | sed -E "s/\\\$\{[^:]+:-([^}]+)\}/\1/g" >> "${CONF_FILE}" + fi + else + eval "echo \"$line\"" >> "${CONF_FILE}" + fi +done < "${TEMPLATE_FILE}" + +export LD_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu/" +PY=python3 + +# ----------------------------------------------------------------------------- +# Select Nginx Configuration based on API_PROXY_SCHEME +# ----------------------------------------------------------------------------- +NGINX_CONF_DIR="/etc/nginx/conf.d" +if [ -n "$API_PROXY_SCHEME" ]; then + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]]; then + cp -f "$NGINX_CONF_DIR/ragflow.conf.hybrid" "$NGINX_CONF_DIR/ragflow.conf" + echo "Applied nginx config: ragflow.conf.hybrid" + elif [[ "${API_PROXY_SCHEME}" == "go" ]]; then + cp -f "$NGINX_CONF_DIR/ragflow.conf.golang" "$NGINX_CONF_DIR/ragflow.conf" + echo "Applied nginx config: ragflow.conf.golang (default)" + else + cp -f "$NGINX_CONF_DIR/ragflow.conf.python" "$NGINX_CONF_DIR/ragflow.conf" + echo "Applied nginx config: ragflow.conf.python" + fi +else + # Default to python backend + cp -f "$NGINX_CONF_DIR/ragflow.conf.python" "$NGINX_CONF_DIR/ragflow.conf" + echo "Default: applied nginx config: ragflow.conf.python" +fi + +# ----------------------------------------------------------------------------- +# Function(s) +# ----------------------------------------------------------------------------- + +function task_exe() { + local consumer_id="$1" + local host_id="$2" + + JEMALLOC_PATH="$(pkg-config --variable=libdir jemalloc)/libjemalloc.so" + while true; do + LD_PRELOAD="$JEMALLOC_PATH" \ + "$PY" rag/svr/task_executor.py -i "${host_id}_${consumer_id}" -t "common" & + wait; + sleep 1; + done +} + +function start_mcp_server() { + echo "Starting MCP Server on ${MCP_HOST}:${MCP_PORT} with base URL ${MCP_BASE_URL}..." + "$PY" "${MCP_SCRIPT_PATH}" \ + --host="${MCP_HOST}" \ + --port="${MCP_PORT}" \ + --base-url="${MCP_BASE_URL}" \ + --mode="${MCP_MODE}" \ + --api-key="${MCP_HOST_API_KEY}" \ + "${MCP_TRANSPORT_SSE_FLAG}" \ + "${MCP_TRANSPORT_STREAMABLE_HTTP_FLAG}" \ + "${MCP_JSON_RESPONSE_FLAG}" & +} + +function ensure_docling() { + [[ "${USE_DOCLING}" == "true" ]] || { echo "[docling] disabled by USE_DOCLING"; return 0; } + DOCLING_PIN="${DOCLING_VERSION:-==2.71.0}" + "$PY" -c "import importlib.util,sys; sys.exit(0 if importlib.util.find_spec('docling') else 1)" \ + || uv pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --extra-index-url https://pypi.org/simple --no-cache-dir "docling${DOCLING_PIN}" +} + +function ensure_db_init() { + echo "Initializing database tables..." + "$PY" -c "from api.db.db_models import init_database_tables as init_web_db; init_web_db()" + echo "Database tables initialized." +} + +# ----------------------------------------------------------------------------- +# Start components based on flags +# ----------------------------------------------------------------------------- +#ensure_docling +#ensure_db_init + +run_with_restart() { + local process_name="$1" + shift + + while true; do + echo "Attempt to start ${process_name}..." + set +e + "$@" + local exit_code=$? + set -e + echo "${process_name} exited with code ${exit_code}. Restarting in 1 second..." + sleep 1 + done +} + +if [[ "${INIT_MODEL_PROVIDER_TABLES}" -eq 1 ]]; then + DB_TYPE_NORMALIZED="${DB_TYPE:-mysql}" + DB_TYPE_NORMALIZED="${DB_TYPE_NORMALIZED,,}" + if [[ "${DB_TYPE_NORMALIZED}" == "gaussdb" || "${DB_TYPE_NORMALIZED}" == "gauss" ]]; then + # This migration script contains MySQL-only SQL and cannot run against + # a GaussDB metadata database. + echo "Skipping MySQL-specific model provider table migrations for DB_TYPE=${DB_TYPE:-mysql}." + else + tools/scripts/run_migrations.sh + fi +fi + +if [[ "${ENABLE_ADMIN_SERVER}" -eq 1 ]]; then + + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]] || [[ "${API_PROXY_SCHEME}" == "python" ]]; then + echo "Attempt to start Admin python server..." + run_with_restart "Admin python server" "$PY" admin/server/admin_server.py & + fi + + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]] || [[ "${API_PROXY_SCHEME}" == "go" ]]; then + echo "Starting Admin go server..." + run_with_restart "Admin go server" bin/ragflow_server --admin & + fi +fi + +if [[ "${ENABLE_WEBSERVER}" -eq 1 ]]; then + echo "Starting nginx..." + /usr/sbin/nginx -c /etc/nginx/nginx.conf + + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]] || [[ "${API_PROXY_SCHEME}" == "python" ]]; then + echo "Attempt to start RAGFlow python server..." + run_with_restart "RAGFlow python server" "$PY" api/ragflow_server.py ${INIT_SUPERUSER_ARGS} & + fi + + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]] || [[ "${API_PROXY_SCHEME}" == "go" ]]; then + echo "Starting RAGFlow go server..." + run_with_restart "RAGFlow go server" bin/ragflow_server --api & + fi +fi + +if [[ "${ENABLE_DATASYNC}" -eq 1 ]]; then + echo "Starting data sync..." + run_with_restart "RAGFlow go server" bin/ragflow_server --syncer & +fi + +#if [[ "${ENABLE_MCP_SERVER}" -eq 1 ]]; then +# start_mcp_server +#fi + + +if [[ "${ENABLE_TASKEXECUTOR}" -eq 1 ]]; then + if [[ "${CONSUMER_NO_END}" -gt "${CONSUMER_NO_BEG}" ]]; then + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]] || [[ "${API_PROXY_SCHEME}" == "python" ]]; then + echo "Starting python task executors on host '${HOST_ID}' for IDs in [${CONSUMER_NO_BEG}, ${CONSUMER_NO_END})..." + for (( i=CONSUMER_NO_BEG; i