Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
12 changes: 6 additions & 6 deletions backend/apps/northbound_knowledge_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from fastapi import APIRouter, Body, File, Form, Path, Path as PathParam, Query, Request, HTTPException, UploadFile
from fastapi.responses import JSONResponse, RedirectResponse, StreamingResponse

from consts.const import ASSET_OWNER_TENANT_ID, VectorDatabaseType
from consts.const import ASSET_OWNER_TENANT_ID
from consts.exceptions import (
LimitExceededError,
UnauthorizedError,
Expand Down Expand Up @@ -65,7 +65,7 @@ async def get_list_indices(
"""
try:
ctx = await _require_asset_owner_context(request)
vdb_core = get_vector_db_core(db_type=VectorDatabaseType.ELASTICSEARCH)
vdb_core = get_vector_db_core()
return ElasticSearchService.list_indices(
pattern, True, ctx.tenant_id, ctx.user_id, vdb_core
)
Expand Down Expand Up @@ -111,7 +111,7 @@ async def create_new_index(
"""
try:
ctx = await _require_asset_owner_context(request)
vdb_core = get_vector_db_core(db_type=VectorDatabaseType.ELASTICSEARCH)
vdb_core = get_vector_db_core()

ingroup_permission = None
group_ids = None
Expand Down Expand Up @@ -163,7 +163,7 @@ async def delete_index(
logger.debug("Received northbound request to delete knowledge base")
try:
ctx = await _require_asset_owner_context(request)
vdb_core = get_vector_db_core(db_type=VectorDatabaseType.ELASTICSEARCH)
vdb_core = get_vector_db_core()
return await ElasticSearchService.full_delete_knowledge_base(
index_name, vdb_core, ctx.user_id
)
Expand Down Expand Up @@ -195,7 +195,7 @@ async def get_index_files(
"""
try:
ctx = await _require_asset_owner_context(request)
vdb_core = get_vector_db_core(db_type=VectorDatabaseType.ELASTICSEARCH)
vdb_core = get_vector_db_core()
logger.debug(
"Listing files for index %s, tenant_id=%s, user_id=%s",
index_name,
Expand Down Expand Up @@ -370,7 +370,7 @@ async def delete_documents(
"""Delete a document by scope. Restricted to asset administrators."""
try:
await _require_asset_owner_context(request)
vdb_core = get_vector_db_core(db_type=VectorDatabaseType.ELASTICSEARCH)
vdb_core = get_vector_db_core()
logger.debug(
"Deleting documents for index %s scope=%s", index_name, scope
)
Expand Down
7 changes: 7 additions & 0 deletions backend/consts/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@
class VectorDatabaseType(str, Enum):
ELASTICSEARCH = "elasticsearch"
DATAMATE = "datamate"
QDRANT = "qdrant"


# Elasticsearch Configuration
VECTOR_DATABASE_TYPE = os.getenv("VECTOR_DATABASE_TYPE", VectorDatabaseType.ELASTICSEARCH.value)
ES_HOST = os.getenv("ELASTICSEARCH_HOST")
ES_API_KEY = os.getenv("ELASTICSEARCH_API_KEY")
ES_PASSWORD = os.getenv("ELASTIC_PASSWORD")
ES_USERNAME = "elastic"
ELASTICSEARCH_SERVICE = os.getenv("ELASTICSEARCH_SERVICE")

# Qdrant
QDRANT_URL = os.getenv("QDRANT_URL")
QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
QDRANT_TIMEOUT = float(os.getenv("QDRANT_TIMEOUT", "20"))

# Data Processing Service Configuration
DATA_PROCESS_SERVICE = os.getenv("DATA_PROCESS_SERVICE")
CLIP_MODEL_PATH = os.getenv("CLIP_MODEL_PATH")
Expand Down
22 changes: 18 additions & 4 deletions backend/services/vectordatabase_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from nexent.vector_database.base import VectorDatabaseCore
from nexent.vector_database.elasticsearch_core import ElasticSearchCore
from nexent.vector_database.datamate_core import DataMateCore
from nexent.vector_database.qdrant_core import QdrantCore

from consts.const import (
ASSET_OWNER_TENANT_ID,
Expand All @@ -37,6 +38,10 @@
LANGUAGE,
PERMISSION_EDIT,
PERMISSION_READ,
QDRANT_API_KEY,
QDRANT_TIMEOUT,
QDRANT_URL,
VECTOR_DATABASE_TYPE,
VectorDatabaseType,
)
from consts.model import ChunkCreateRequest, ChunkUpdateRequest
Expand Down Expand Up @@ -237,7 +242,7 @@ def get_embedding_model_by_index_name(tenant_id: str, index_name: str) -> tuple[


def get_vector_db_core(
db_type: VectorDatabaseType = VectorDatabaseType.ELASTICSEARCH, tenant_id: Optional[str] = None,
db_type: Optional[VectorDatabaseType] = None, tenant_id: Optional[str] = None,
) -> VectorDatabaseCore:
"""
Return a VectorDatabaseCore implementation based on the requested type.
Expand All @@ -252,15 +257,24 @@ def get_vector_db_core(
Raises:
ValueError: If the requested database type is not supported.
"""
if db_type == VectorDatabaseType.ELASTICSEARCH:
selected_db_type = db_type or VectorDatabaseType(VECTOR_DATABASE_TYPE)

if selected_db_type == VectorDatabaseType.ELASTICSEARCH:
return ElasticSearchCore(
host=ES_HOST,
api_key=ES_API_KEY,
verify_certs=False,
ssl_show_warn=False,
)

if db_type == VectorDatabaseType.DATAMATE:
if selected_db_type == VectorDatabaseType.QDRANT:
return QdrantCore(
url=QDRANT_URL,
api_key=QDRANT_API_KEY,
timeout=QDRANT_TIMEOUT,
)

if selected_db_type == VectorDatabaseType.DATAMATE:
if tenant_id:
datamate_url = tenant_config_manager.get_app_config(
DATAMATE_URL, tenant_id=tenant_id)
Expand All @@ -271,7 +285,7 @@ def get_vector_db_core(
else:
raise ValueError("tenant_id must be provided for DataMate")

raise ValueError(f"Unsupported vector database type: {db_type}")
raise ValueError(f"Unsupported vector database type: {selected_db_type}")


def _rethrow_or_plain(exc: Exception) -> None:
Expand Down
4 changes: 3 additions & 1 deletion deploy/common/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ deployment_compute_docker_ports() {
fi

if deployment_csv_contains "$DEPLOYMENT_COMPONENTS" "infrastructure"; then
ports+=(9210 9310 5434 6379 9010 9011)
ports+=(9210 9310 6333 5434 6379 9010 9011)
fi
if deployment_csv_contains "$DEPLOYMENT_COMPONENTS" "application"; then
ports+=(5010 5014 5011 5015 5013 3000)
Expand Down Expand Up @@ -1674,6 +1674,7 @@ deployment_apply_image_source() {
export NEXENT_DATA_PROCESS_IMAGE="${NEXENT_DATA_PROCESS_IMAGE:-nexent/nexent-data-process:$version}"
export NEXENT_MCP_DOCKER_IMAGE="${NEXENT_MCP_DOCKER_IMAGE:-nexent/nexent-mcp:$version}"
export ELASTICSEARCH_IMAGE="${ELASTICSEARCH_IMAGE:-docker.elastic.co/elasticsearch/elasticsearch:8.17.4}"
export QDRANT_IMAGE="${QDRANT_IMAGE:-qdrant/qdrant:v1.18.2}"
export POSTGRESQL_IMAGE="${POSTGRESQL_IMAGE:-postgres:15-alpine}"
export REDIS_IMAGE="${REDIS_IMAGE:-redis:alpine}"
export MINIO_IMAGE="${MINIO_IMAGE:-quay.io/minio/minio:RELEASE.2023-12-20T01-00-02Z}"
Expand Down Expand Up @@ -1787,6 +1788,7 @@ deployment_render_docker_env() {
printf 'NEXENT_DATA_PROCESS_IMAGE="%s"\n' "$NEXENT_DATA_PROCESS_IMAGE"
printf 'NEXENT_MCP_DOCKER_IMAGE="%s"\n' "$NEXENT_MCP_DOCKER_IMAGE"
printf 'ELASTICSEARCH_IMAGE="%s"\n' "$ELASTICSEARCH_IMAGE"
printf 'QDRANT_IMAGE="%s"\n' "$QDRANT_IMAGE"
printf 'POSTGRESQL_IMAGE="%s"\n' "$POSTGRESQL_IMAGE"
printf 'REDIS_IMAGE="%s"\n' "$REDIS_IMAGE"
printf 'MINIO_IMAGE="%s"\n' "$MINIO_IMAGE"
Expand Down
14 changes: 14 additions & 0 deletions deploy/docker/compose/docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ services:
max-size: "100m" # Maximum size of a single log file
max-file: "3" # Maximum number of log files to keep

nexent-qdrant:
image: ${QDRANT_IMAGE}
container_name: nexent-qdrant
volumes:
- ${ROOT_DIR}/qdrant:/qdrant/storage
networks:
- nexent
restart: always
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"

nexent-postgresql:
image: ${POSTGRESQL_IMAGE}
container_name: nexent-postgresql
Expand Down
16 changes: 16 additions & 0 deletions deploy/docker/compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ services:
max-size: "100m" # Maximum size of a single log file
max-file: "3" # Maximum number of log files to keep

nexent-qdrant:
image: ${QDRANT_IMAGE}
container_name: nexent-qdrant
volumes:
- ${ROOT_DIR}/qdrant:/qdrant/storage
ports:
- "6333:6333" # HTTP API
networks:
- nexent
restart: always
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"

nexent-postgresql:
image: ${POSTGRESQL_IMAGE}
container_name: nexent-postgresql
Expand Down
2 changes: 1 addition & 1 deletion deploy/docker/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,7 @@ deploy_infrastructure() {
INFRA_SERVICES=""

if deployment_csv_contains "$DEPLOYMENT_COMPONENTS" "infrastructure"; then
INFRA_SERVICES="nexent-elasticsearch nexent-postgresql nexent-minio redis"
INFRA_SERVICES="nexent-elasticsearch nexent-qdrant nexent-postgresql nexent-minio redis"
fi

# Add openssh-server if Terminal tool container is enabled
Expand Down
6 changes: 6 additions & 0 deletions deploy/env/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ TABLE_TRANSFORMER_MODEL_PATH=/opt/models/table-transformer-structure-recognition
UNSTRUCTURED_DEFAULT_MODEL_INITIALIZE_PARAMS_JSON_PATH=/opt/models/yolox/config.json

# Elasticsearch Service
VECTOR_DATABASE_TYPE=elasticsearch
ELASTICSEARCH_HOST=http://nexent-elasticsearch:9200
ELASTIC_PASSWORD=nexent@2025

# Qdrant Service
QDRANT_URL=http://nexent-qdrant:6333
QDRANT_API_KEY=
QDRANT_TIMEOUT=20

# Elasticsearch Memory Configuration
ES_JAVA_OPTS="-Xms2g -Xmx2g"

Expand Down
1 change: 1 addition & 0 deletions deploy/env/image-source.general.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ NEXENT_DATA_PROCESS_IMAGE=nexent/nexent-data-process:${APP_VERSION}
NEXENT_MCP_DOCKER_IMAGE=nexent/nexent-mcp:${APP_VERSION}

ELASTICSEARCH_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:8.17.4
QDRANT_IMAGE=qdrant/qdrant:v1.18.2
POSTGRESQL_IMAGE=postgres:15-alpine
REDIS_IMAGE=redis:alpine
MINIO_IMAGE=quay.io/minio/minio:RELEASE.2023-12-20T01-00-02Z
Expand Down
1 change: 1 addition & 0 deletions deploy/env/image-source.mainland.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ NEXENT_DATA_PROCESS_IMAGE=ccr.ccs.tencentyun.com/nexent-hub/nexent-data-process:
NEXENT_MCP_DOCKER_IMAGE=ccr.ccs.tencentyun.com/nexent-hub/nexent-mcp:${APP_VERSION}

ELASTICSEARCH_IMAGE=elastic.m.daocloud.io/elasticsearch/elasticsearch:8.17.4
QDRANT_IMAGE=docker.m.daocloud.io/qdrant/qdrant:v1.18.2
POSTGRESQL_IMAGE=docker.m.daocloud.io/postgres:15-alpine
REDIS_IMAGE=docker.m.daocloud.io/redis:alpine
MINIO_IMAGE=quay.m.daocloud.io/minio/minio:RELEASE.2023-12-20T01-00-02Z
Expand Down
4 changes: 4 additions & 0 deletions deploy/k8s/helm/nexent/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ dependencies:
version: 0.1.0
repository: "file://./charts/nexent-elasticsearch"
condition: nexent-elasticsearch.enabled
- name: nexent-qdrant
version: 0.1.0
repository: "file://./charts/nexent-qdrant"
condition: nexent-qdrant.enabled
- name: nexent-postgresql
version: 0.1.0
repository: "file://./charts/nexent-postgresql"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ data:
# Deployment version
DEPLOYMENT_VERSION: {{ .Values.global.deploymentVersion | quote }}

# Elasticsearch Service
# Vector Database Services
VECTOR_DATABASE_TYPE: {{ .Values.config.vectorDatabase.type | quote }}
ELASTICSEARCH_HOST: {{ .Values.config.elasticsearch.host | quote }}
ES_JAVA_OPTS: {{ .Values.config.elasticsearch.javaOpts | quote }}
ES_DISK_WATERMARK_LOW: {{ .Values.config.elasticsearch.diskWatermarkLow | quote }}
ES_DISK_WATERMARK_HIGH: {{ .Values.config.elasticsearch.diskWatermarkHigh | quote }}
ES_DISK_WATERMARK_FLOOD_STAGE: {{ .Values.config.elasticsearch.diskWatermarkFloodStage | quote }}
QDRANT_URL: {{ .Values.config.qdrant.url | quote }}
QDRANT_TIMEOUT: {{ .Values.config.qdrant.timeout | quote }}

# Service URLs (internal)
CONFIG_SERVICE_URL: {{ .Values.config.services.configUrl | quote }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ data:
{{- if .Values.secrets.elasticsearchApiKey }}
ELASTICSEARCH_API_KEY: {{ .Values.secrets.elasticsearchApiKey | b64enc | quote }}
{{- end }}
{{- if .Values.secrets.qdrantApiKey }}
QDRANT_API_KEY: {{ .Values.secrets.qdrantApiKey | b64enc | quote }}
{{- end }}

NEXENT_POSTGRES_PASSWORD: {{ .Values.secrets.postgresPassword | b64enc | quote }}

Expand Down
6 changes: 6 additions & 0 deletions deploy/k8s/helm/nexent/charts/nexent-common/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@
endpoint: "http://nexent-minio:9000"
region: "cn-north-1"
defaultBucket: "nexent"
vectorDatabase:
type: "elasticsearch"
elasticsearch:
host: "http://nexent-elasticsearch:9200"
javaOpts: "-Xms2g -Xmx2g"
diskWatermarkLow: "85%"
diskWatermarkHigh: "90%"
diskWatermarkFloodStage: "95%"
qdrant:
url: "http://nexent-qdrant:6333"

Check warning on line 66 in deploy/k8s/helm/nexent/charts/nexent-common/values.yaml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure that using clear-text protocols is safe here.

See more on https://sonarcloud.io/project/issues?id=ModelEngine-Group_nexent&issues=AZ9Ihp7SdKxjF4VD55Po&open=AZ9Ihp7SdKxjF4VD55Po&pullRequest=3398
timeout: "20"
skipProxy: "true"
umask: "0022"
isDeployedByKubernetes: "true"
Expand Down Expand Up @@ -189,6 +194,7 @@
secrets:
elasticPassword: "nexent@2025"
elasticsearchApiKey: ""
qdrantApiKey: ""
postgresPassword: "nexent@4321"
minio:
rootUser: "nexent"
Expand Down
10 changes: 10 additions & 0 deletions deploy/k8s/helm/nexent/charts/nexent-qdrant/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v2
name: nexent-qdrant
description: Qdrant vector database for Nexent
type: application
version: 0.1.0
appVersion: "v1.18.2"
keywords:
- nexent
- qdrant
- vector-database
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nexent-qdrant
namespace: {{ .Values.global.namespace }}
labels:
app: nexent-qdrant
annotations:
"helm.sh/hook-weight": "-1"
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: nexent-qdrant
template:
metadata:
labels:
app: nexent-qdrant
spec:
securityContext:
fsGroup: 1000
containers:
- name: qdrant
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 6333
name: http
volumeMounts:
- name: qdrant-data
mountPath: /qdrant/storage
resources:
requests:
memory: {{ .Values.resources.requests.memory }}
cpu: {{ .Values.resources.requests.cpu }}
limits:
memory: {{ .Values.resources.limits.memory }}
cpu: {{ .Values.resources.limits.cpu }}
livenessProbe:
tcpSocket:
port: 6333
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
tcpSocket:
port: 6333
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: qdrant-data
persistentVolumeClaim:
claimName: {{ default "nexent-qdrant" .Values.persistence.existingClaim }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: nexent-qdrant
namespace: {{ .Values.global.namespace }}
labels:
app: nexent-qdrant
spec:
type: {{ default "ClusterIP" .Values.service.type }}
ports:
- port: 6333
targetPort: 6333
name: http
{{- if and (eq (default "ClusterIP" .Values.service.type) "NodePort") .Values.service.nodePorts.http }}
nodePort: {{ .Values.service.nodePorts.http }}
{{- end }}
selector:
app: nexent-qdrant
Loading