Skip to content

Commit d5db7a8

Browse files
committed
🐛 When the knowledge base is automatically summarized, other interfaces will be pended.
[Specification Details] 1. Start the thread pool to execute k-means and LLM calls in automatic summarization. 2. Concatenate prompt path to absolute path.
1 parent bc22cac commit d5db7a8

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed

backend/services/vectordatabase_service.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,7 @@ async def summary_index_name(self,
741741
index_name: Name of the index to summarize
742742
batch_size: Number of documents to sample (default: 1000)
743743
vdb_core: VectorDatabaseCore instance
744+
user_id: ID of the user delete the knowledge base
744745
tenant_id: ID of the tenant
745746
language: Language of the summary (default: 'zh')
746747
model_id: Model ID for LLM summarization
@@ -762,32 +763,45 @@ async def summary_index_name(self,
762763
# Use new Map-Reduce approach
763764
sample_count = min(batch_size // 5, 200) # Sample reasonable number of documents
764765

765-
# Step 1: Get documents and calculate embeddings
766-
document_samples, doc_embeddings = process_documents_for_clustering(
767-
index_name=index_name,
768-
vdb_core=vdb_core,
769-
sample_doc_count=sample_count
770-
)
771-
772-
if not document_samples:
773-
raise Exception("No documents found in index.")
774-
775-
# Step 2: Cluster documents
776-
clusters = kmeans_cluster_documents(doc_embeddings, k=None)
777-
778-
# Step 3: Map-Reduce summarization
779-
cluster_summaries = summarize_clusters_map_reduce(
780-
document_samples=document_samples,
781-
clusters=clusters,
782-
language=language,
783-
doc_max_words=100,
784-
cluster_max_words=150,
785-
model_id=model_id,
786-
tenant_id=tenant_id
787-
)
766+
# Define a helper function to run all blocking operations in a thread pool
767+
def _generate_summary_sync():
768+
"""Synchronous function that performs all blocking operations"""
769+
# Step 1: Get documents and calculate embeddings
770+
document_samples, doc_embeddings = process_documents_for_clustering(
771+
index_name=index_name,
772+
vdb_core=vdb_core,
773+
sample_doc_count=sample_count
774+
)
775+
776+
if not document_samples:
777+
raise Exception("No documents found in index.")
778+
779+
# Step 2: Cluster documents (CPU-intensive operation)
780+
clusters = kmeans_cluster_documents(doc_embeddings, k=None)
781+
782+
# Step 3: Map-Reduce summarization (contains blocking LLM calls)
783+
cluster_summaries = summarize_clusters_map_reduce(
784+
document_samples=document_samples,
785+
clusters=clusters,
786+
language=language,
787+
doc_max_words=100,
788+
cluster_max_words=150,
789+
model_id=model_id,
790+
tenant_id=tenant_id
791+
)
792+
793+
# Step 4: Merge into final summary
794+
final_summary = merge_cluster_summaries(cluster_summaries)
795+
return final_summary
788796

789-
# Step 4: Merge into final summary
790-
final_summary = merge_cluster_summaries(cluster_summaries)
797+
# Run blocking operations in a thread pool to avoid blocking the event loop
798+
# Use get_running_loop() for better compatibility with modern asyncio
799+
try:
800+
loop = asyncio.get_running_loop()
801+
except RuntimeError:
802+
# Fallback for edge cases
803+
loop = asyncio.get_event_loop()
804+
final_summary = await loop.run_in_executor(None, _generate_summary_sync)
791805

792806
# Stream the result
793807
async def generate_summary():

backend/utils/document_vector_utils.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
4. Cluster summarization
1010
"""
1111
import logging
12+
import os
1213
import random
1314
from typing import Dict, List, Optional, Tuple
1415

@@ -25,6 +26,24 @@
2526
logger = logging.getLogger("document_vector_utils")
2627

2728

29+
def _get_prompt_absolute_path(relative_path: str) -> str:
30+
"""
31+
Get absolute path for prompt files.
32+
33+
Args:
34+
relative_path: Relative path like 'backend/prompts/xxx.yaml'
35+
36+
Returns:
37+
Absolute path to the prompt file
38+
"""
39+
# Get the directory of this file and construct absolute path
40+
current_dir = os.path.dirname(os.path.abspath(__file__))
41+
# Go up one level from utils to backend, then use the template path
42+
backend_dir = os.path.dirname(current_dir)
43+
absolute_path = os.path.join(backend_dir, relative_path.replace('backend/', ''))
44+
return absolute_path
45+
46+
2847
def get_documents_from_es(index_name: str, vdb_core: VectorDatabaseCore, sample_doc_count: int = 200) -> Dict[str, Dict]:
2948
"""
3049
Get document samples from Elasticsearch, aggregated by path_or_url
@@ -550,9 +569,9 @@ def summarize_document(document_content: str, filename: str, language: str = LAN
550569
try:
551570
# Select prompt file based on language
552571
if language == LANGUAGE["ZH"]:
553-
prompt_path = 'backend/prompts/document_summary_agent_zh.yaml'
572+
prompt_path = _get_prompt_absolute_path('backend/prompts/document_summary_agent_zh.yaml')
554573
else:
555-
prompt_path = 'backend/prompts/document_summary_agent.yaml'
574+
prompt_path = _get_prompt_absolute_path('backend/prompts/document_summary_agent.yaml')
556575

557576
with open(prompt_path, 'r', encoding='utf-8') as f:
558577
prompts = yaml.safe_load(f)
@@ -628,9 +647,9 @@ def summarize_cluster(document_summaries: List[str], language: str = LANGUAGE["Z
628647
try:
629648
# Select prompt file based on language
630649
if language == LANGUAGE["ZH"]:
631-
prompt_path = 'backend/prompts/cluster_summary_reduce_zh.yaml'
650+
prompt_path = _get_prompt_absolute_path('backend/prompts/cluster_summary_reduce_zh.yaml')
632651
else:
633-
prompt_path = 'backend/prompts/cluster_summary_reduce.yaml'
652+
prompt_path = _get_prompt_absolute_path('backend/prompts/cluster_summary_reduce.yaml')
634653

635654
with open(prompt_path, 'r', encoding='utf-8') as f:
636655
prompts = yaml.safe_load(f)
@@ -938,7 +957,7 @@ def summarize_cluster_legacy(cluster_content: str, language: str = LANGUAGE["ZH"
938957
Cluster summary text
939958
"""
940959
try:
941-
prompt_path = 'backend/prompts/cluster_summary_agent.yaml'
960+
prompt_path = _get_prompt_absolute_path('backend/prompts/cluster_summary_agent.yaml')
942961
with open(prompt_path, 'r', encoding='utf-8') as f:
943962
prompts = yaml.safe_load(f)
944963

0 commit comments

Comments
 (0)