Skip to content

Commit 09be0c1

Browse files
authored
🐛 When the knowledge base is automatically summarized, other interfaces will be pended. #1684 #1755
2 parents a4f0a5c + 3d3fba6 commit 09be0c1

File tree

4 files changed

+375
-45
lines changed

4 files changed

+375
-45
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: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@
1313
from typing import Dict, List, Optional, Tuple
1414

1515
import numpy as np
16-
import yaml
1716
from jinja2 import Template, StrictUndefined
1817
from nexent.vector_database.base import VectorDatabaseCore
1918
from sklearn.cluster import KMeans
2019
from sklearn.metrics import silhouette_score
2120
from sklearn.metrics.pairwise import cosine_similarity
2221

2322
from consts.const import LANGUAGE
23+
from utils.prompt_template_utils import (
24+
get_document_summary_prompt_template,
25+
get_cluster_summary_reduce_prompt_template,
26+
get_cluster_summary_agent_prompt_template
27+
)
2428

2529
logger = logging.getLogger("document_vector_utils")
2630

@@ -548,14 +552,8 @@ def summarize_document(document_content: str, filename: str, language: str = LAN
548552
Document summary text
549553
"""
550554
try:
551-
# Select prompt file based on language
552-
if language == LANGUAGE["ZH"]:
553-
prompt_path = 'backend/prompts/document_summary_agent_zh.yaml'
554-
else:
555-
prompt_path = 'backend/prompts/document_summary_agent.yaml'
556-
557-
with open(prompt_path, 'r', encoding='utf-8') as f:
558-
prompts = yaml.safe_load(f)
555+
# Get prompt template from prompt_template_utils
556+
prompts = get_document_summary_prompt_template(language)
559557

560558
system_prompt = prompts.get('system_prompt', '')
561559
user_prompt_template = prompts.get('user_prompt', '')
@@ -626,14 +624,8 @@ def summarize_cluster(document_summaries: List[str], language: str = LANGUAGE["Z
626624
Cluster summary text
627625
"""
628626
try:
629-
# Select prompt file based on language
630-
if language == LANGUAGE["ZH"]:
631-
prompt_path = 'backend/prompts/cluster_summary_reduce_zh.yaml'
632-
else:
633-
prompt_path = 'backend/prompts/cluster_summary_reduce.yaml'
634-
635-
with open(prompt_path, 'r', encoding='utf-8') as f:
636-
prompts = yaml.safe_load(f)
627+
# Get prompt template from prompt_template_utils
628+
prompts = get_cluster_summary_reduce_prompt_template(language)
637629

638630
system_prompt = prompts.get('system_prompt', '')
639631
user_prompt_template = prompts.get('user_prompt', '')
@@ -938,9 +930,8 @@ def summarize_cluster_legacy(cluster_content: str, language: str = LANGUAGE["ZH"
938930
Cluster summary text
939931
"""
940932
try:
941-
prompt_path = 'backend/prompts/cluster_summary_agent.yaml'
942-
with open(prompt_path, 'r', encoding='utf-8') as f:
943-
prompts = yaml.safe_load(f)
933+
# Get prompt template from prompt_template_utils
934+
prompts = get_cluster_summary_agent_prompt_template(language)
944935

945936
system_prompt = prompts.get('system_prompt', '')
946937
user_prompt_template = prompts.get('user_prompt', '')

backend/utils/prompt_template_utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def get_prompt_template(template_type: str, language: str = LANGUAGE["ZH"], **kw
2121
- 'analyze_file': File analysis template
2222
- 'generate_title': Title generation template
2323
- 'file_processing_messages': File processing messages template
24+
- 'document_summary': Document summary template (Map stage)
25+
- 'cluster_summary_reduce': Cluster summary reduce template (Reduce stage)
26+
- 'cluster_summary_agent': Cluster summary agent template (legacy)
2427
language: Language code ('zh' or 'en')
2528
**kwargs: Additional parameters, for agent type need to pass is_manager parameter
2629
@@ -61,6 +64,18 @@ def get_prompt_template(template_type: str, language: str = LANGUAGE["ZH"], **kw
6164
'file_processing_messages': {
6265
LANGUAGE["ZH"]: 'backend/prompts/utils/file_processing_messages.yaml',
6366
LANGUAGE["EN"]: 'backend/prompts/utils/file_processing_messages_en.yaml'
67+
},
68+
'document_summary': {
69+
LANGUAGE["ZH"]: 'backend/prompts/document_summary_agent_zh.yaml',
70+
LANGUAGE["EN"]: 'backend/prompts/document_summary_agent.yaml'
71+
},
72+
'cluster_summary_reduce': {
73+
LANGUAGE["ZH"]: 'backend/prompts/cluster_summary_reduce_zh.yaml',
74+
LANGUAGE["EN"]: 'backend/prompts/cluster_summary_reduce.yaml'
75+
},
76+
'cluster_summary_agent': {
77+
LANGUAGE["ZH"]: 'backend/prompts/cluster_summary_agent.yaml',
78+
LANGUAGE["EN"]: 'backend/prompts/cluster_summary_agent.yaml'
6479
}
6580
}
6681

@@ -164,3 +179,42 @@ def get_file_processing_messages_template(language: str = 'zh') -> Dict[str, Any
164179
dict: Loaded file processing messages configuration
165180
"""
166181
return get_prompt_template('file_processing_messages', language)
182+
183+
184+
def get_document_summary_prompt_template(language: str = LANGUAGE["ZH"]) -> Dict[str, Any]:
185+
"""
186+
Get document summary prompt template (Map stage)
187+
188+
Args:
189+
language: Language code ('zh' or 'en')
190+
191+
Returns:
192+
dict: Loaded document summary prompt template configuration
193+
"""
194+
return get_prompt_template('document_summary', language)
195+
196+
197+
def get_cluster_summary_reduce_prompt_template(language: str = LANGUAGE["ZH"]) -> Dict[str, Any]:
198+
"""
199+
Get cluster summary reduce prompt template (Reduce stage)
200+
201+
Args:
202+
language: Language code ('zh' or 'en')
203+
204+
Returns:
205+
dict: Loaded cluster summary reduce prompt template configuration
206+
"""
207+
return get_prompt_template('cluster_summary_reduce', language)
208+
209+
210+
def get_cluster_summary_agent_prompt_template(language: str = LANGUAGE["ZH"]) -> Dict[str, Any]:
211+
"""
212+
Get cluster summary agent prompt template (legacy)
213+
214+
Args:
215+
language: Language code ('zh' or 'en')
216+
217+
Returns:
218+
dict: Loaded cluster summary agent prompt template configuration
219+
"""
220+
return get_prompt_template('cluster_summary_agent', language)

0 commit comments

Comments
 (0)