Skip to content
Merged
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
6 changes: 6 additions & 0 deletions backend/apps/file_management_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from consts.exceptions import FileTooLargeException, NotFoundException, UnsupportedFileTypeException
from consts.model import ProcessParams
from apps.permission_utils import require_knowledge_base_edit_permission
from services.file_management_service import upload_to_minio, upload_files_impl, \
get_file_url_impl, get_file_stream_impl, delete_file_impl, list_files_impl, \
resolve_preview_file, get_preview_stream, check_file_access, check_file_access_batch, \
Expand Down Expand Up @@ -102,6 +103,8 @@ async def upload_files(
detail="No files in the request")

user_id, tenant_id = get_current_user_id(authorization)
if index_name:
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
errors, uploaded_file_paths, uploaded_filenames = await upload_files_impl(
destination, file, folder, index_name, user_id, uploader_tenant_id=tenant_id
)
Expand Down Expand Up @@ -144,6 +147,9 @@ async def process_files(
index_name: index name in elasticsearch
destination: 'local' or 'minio'
"""
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)

process_params = ProcessParams(
chunking_strategy=chunking_strategy,
source_type=destination,
Expand Down
11 changes: 9 additions & 2 deletions backend/apps/knowledge_summary_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from nexent.vector_database.base import VectorDatabaseCore

from consts.model import ChangeSummaryRequest
from apps.permission_utils import require_knowledge_base_edit_permission
from services.vectordatabase_service import ElasticSearchService, get_vector_db_core
from utils.auth_utils import get_current_user_id, get_current_user_info
from utils.config_utils import tenant_config_manager
Expand All @@ -28,8 +29,9 @@ async def auto_summary(
):
"""Summary Elasticsearch index_name by model"""
try:
_, tenant_id, language = get_current_user_info(
user_id, tenant_id, language = get_current_user_info(
authorization, http_request)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
service = ElasticSearchService()

# Get model_id from tenant config if not provided
Expand All @@ -53,6 +55,8 @@ async def auto_summary(
language=language,
model_id=model_id
)
except HTTPException:
raise
except Exception as e:
logger.error(
f"Knowledge base summary generation failed: {e}", exc_info=True)
Expand All @@ -73,9 +77,12 @@ def change_summary(
):
"""Summary Elasticsearch index_name by user"""
try:
user_id = get_current_user_id(authorization)[0]
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
summary_result = change_summary_request.summary_result
return ElasticSearchService().change_summary(index_name=index_name, summary_result=summary_result, user_id=user_id)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500, detail=f"Knowledge base summary update failed: {str(e)}")
Expand Down
3 changes: 2 additions & 1 deletion backend/apps/model_managment_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ async def manage_check_model_health(

result = await check_model_connectivity(
request.display_name,
request.tenant_id
request.tenant_id,
request.model_type
)
return JSONResponse(status_code=HTTPStatus.OK, content={
"message": "Successfully checked model connectivity",
Expand Down
18 changes: 18 additions & 0 deletions backend/apps/permission_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from http import HTTPStatus

from fastapi import HTTPException

from services.vectordatabase_service import ElasticSearchService


def require_knowledge_base_edit_permission(index_name: str, user_id: str, tenant_id: str) -> None:
try:
ElasticSearchService.require_knowledge_base_edit_permission(
index_name=index_name,
user_id=user_id,
tenant_id=tenant_id,
)
except ValueError as exc:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=str(exc))
except PermissionError as exc:
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=str(exc))
28 changes: 26 additions & 2 deletions backend/apps/vectordatabase_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from utils.file_management_utils import get_all_files_status
from database.knowledge_db import get_index_name_by_knowledge_name, get_knowledge_record
from database.model_management_db import get_model_by_model_id
from apps.permission_utils import require_knowledge_base_edit_permission

router = APIRouter(prefix="/indices")
service = ElasticSearchService()
Expand Down Expand Up @@ -125,9 +126,12 @@
logger.debug(f"Received request to delete knowledge base: {index_name}")
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
# Call the centralized full deletion service
result = await ElasticSearchService.full_delete_knowledge_base(index_name, vdb_core, user_id)
return result
except HTTPException:
raise
except Exception as e:
logger.error(
f"Error during API call to delete index '{index_name}': {str(e)}", exc_info=True)
Expand All @@ -147,6 +151,7 @@
user_id, auth_tenant_id = get_current_user_id(authorization)
# Use explicit tenant_id if provided, otherwise fall back to auth tenant_id
tenant_id = request.get("tenant_id") or auth_tenant_id
require_knowledge_base_edit_permission(index_name, user_id, auth_tenant_id)

# Extract update fields
knowledge_name = request.get("knowledge_name")
Expand Down Expand Up @@ -197,6 +202,7 @@
"""Update the auto-summary frequency for a knowledge base."""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
summary_frequency = request.get("summary_frequency")

valid_frequencies = VALID_SUMMARY_FREQUENCIES
Expand Down Expand Up @@ -337,6 +343,7 @@
"""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)

model_id = request.get("model_id")
if not model_id:
Expand Down Expand Up @@ -456,6 +463,7 @@
"""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)

# Get the knowledge base record to retrieve the saved embedding model
knowledge_record = get_knowledge_record({'index_name': index_name})
Expand All @@ -477,6 +485,8 @@
large_mode=large_mode,
model_id=saved_embedding_model_id,
)
except HTTPException:
raise
except Exception as e:
error_msg = str(e)
logger.error(f"Error indexing documents: {error_msg}")
Expand Down Expand Up @@ -519,10 +529,13 @@
"full: delete ES documents, MinIO source, and Redis task records"
),
),
vdb_core: VectorDatabaseCore = Depends(get_vector_db_core)
vdb_core: VectorDatabaseCore = Depends(get_vector_db_core),

Check warning on line 532 in backend/apps/vectordatabase_app.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use "Annotated" type hints for FastAPI dependency injection

See more on https://sonarcloud.io/project/issues?id=ModelEngine-Group_nexent&issues=AZ9qseKxyDqngZFMjC2w&open=AZ9qseKxyDqngZFMjC2w&pullRequest=3441
authorization: Optional[str] = Header(None),

Check warning on line 533 in backend/apps/vectordatabase_app.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use "Annotated" type hints for FastAPI dependency injection

See more on https://sonarcloud.io/project/issues?id=ModelEngine-Group_nexent&issues=AZ9qseKxyDqngZFMjC2x&open=AZ9qseKxyDqngZFMjC2x&pullRequest=3441
):
"""Delete a document by scope: source file only or full removal from the index."""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
result = await ElasticSearchService.delete_document_by_scope(
index_name, path_or_url, scope, vdb_core
)
Expand Down Expand Up @@ -567,6 +580,8 @@
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail=str(exc)
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
Expand Down Expand Up @@ -701,6 +716,7 @@
"""Create a manual chunk."""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
result = ElasticSearchService.create_chunk(
index_name=index_name,
chunk_request=payload,
Expand All @@ -714,6 +730,8 @@
status_code=HTTPStatus.NOT_FOUND,
detail=str(e)
)
except HTTPException:
raise
except Exception as exc:
logger.error(
"Error creating chunk for index %s: %s", index_name, exc, exc_info=True
Expand All @@ -736,6 +754,7 @@
"""Update an existing chunk."""
try:
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
result = ElasticSearchService.update_chunk(
index_name=index_name,
chunk_id=chunk_id,
Expand All @@ -750,6 +769,8 @@
status_code=HTTPStatus.NOT_FOUND,
detail=str(e)
)
except HTTPException:
raise
except Exception as exc:
logger.error(
"Error updating chunk %s for index %s: %s",
Expand All @@ -773,7 +794,8 @@
):
"""Delete a chunk."""
try:
get_current_user_id(authorization)
user_id, tenant_id = get_current_user_id(authorization)
require_knowledge_base_edit_permission(index_name, user_id, tenant_id)
result = ElasticSearchService.delete_chunk(
index_name=index_name,
chunk_id=chunk_id,
Expand All @@ -785,6 +807,8 @@
status_code=HTTPStatus.NOT_FOUND,
detail=str(e)
)
except HTTPException:
raise
except Exception as exc:
logger.error(
"Error deleting chunk %s for index %s: %s",
Expand Down
4 changes: 4 additions & 0 deletions backend/consts/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,10 @@ class ManageTenantModelHealthcheckRequest(BaseModel):
"""Request model for checking model connectivity in a specific tenant (admin/manage operation)"""
tenant_id: str = Field(..., min_length=1, description="Target tenant ID to check model connectivity")
display_name: str = Field(..., description="Display name of the model to check")
model_type: Optional[str] = Field(
None,
description="Model type to disambiguate models with the same display name",
)


class ManageBatchCreateModelsRequest(BaseModel):
Expand Down
12 changes: 6 additions & 6 deletions backend/database/model_management_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,12 @@ def get_model_by_display_name(display_name: str, tenant_id: str, model_type: str
"""
filters = {'display_name': display_name}

if model_type in ["multiEmbedding", "multi_embedding"]:
filters['model_type'] = "multi_embedding"
elif model_type == "embedding":
filters['model_type'] = "embedding"
if model_type:
filters['model_type'] = (
"multi_embedding"
if model_type in ["multiEmbedding", "multi_embedding"]
else model_type
)

records = get_model_records(filters, tenant_id)
if not records:
Expand Down Expand Up @@ -358,5 +360,3 @@ def get_model_by_name_factory(model_name: str, model_factory: str, tenant_id: st
}
records = get_model_records(filters, tenant_id)
return records[0] if records else None


11 changes: 9 additions & 2 deletions backend/services/model_health_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,13 @@ async def check_model_connectivity(display_name: str, tenant_id: str, model_type
"connect_status": ModelConnectStatusEnum.UNAVAILABLE.value}
logger.error(f"Error checking model connectivity: {str(e)}")
update_model_record(model["model_id"], update_data)
raise e
if isinstance(e, ValueError):
raise e
return {
"connectivity": False,
"model_name": model_name,
"error": str(e),
}

if connectivity:
logger.info(
Expand All @@ -367,10 +373,11 @@ async def check_model_connectivity(display_name: str, tenant_id: str, model_type
if ssl_verify_fallback:
update_data["ssl_verify"] = False
update_model_record(model["model_id"], update_data)
return {
result = {
"connectivity": connectivity,
"model_name": model_name,
}
return result
except Exception as e:
logger.error(f"Error checking model connectivity: {str(e)}")
if 'model' in locals() and model:
Expand Down
Loading
Loading