fix: Prevent context manager conflict in hierarchical_search
## Problem
"generator didn't stop after throw()" error when hierarchical_search
falls back to simple_search. Both functions use 'with get_weaviate_client()',
creating nested context managers on the same generator.
## Solution
- Use ValueError("FALLBACK_TO_SIMPLE") signal instead of calling simple_search()
inside the context manager
- Catch ValueError in except block and call simple_search() outside context
- Applied to all 3 fallback points:
1. No Weaviate client
2. No summaries found (Stage 1)
3. No sections after filtering
## Result
Fallback now works correctly without context manager conflicts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -317,16 +317,8 @@ def hierarchical_search(
|
|||||||
try:
|
try:
|
||||||
with get_weaviate_client() as client:
|
with get_weaviate_client() as client:
|
||||||
if client is None:
|
if client is None:
|
||||||
# Fallback to simple search only if not forced
|
# Return early if forced, otherwise signal fallback
|
||||||
if not force_hierarchical:
|
if force_hierarchical:
|
||||||
results = simple_search(query, limit, author_filter, work_filter)
|
|
||||||
return {
|
|
||||||
"mode": "simple",
|
|
||||||
"results": results,
|
|
||||||
"total_chunks": len(results),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# Forced hierarchical with no client
|
|
||||||
return {
|
return {
|
||||||
"mode": "hierarchical",
|
"mode": "hierarchical",
|
||||||
"sections": [],
|
"sections": [],
|
||||||
@@ -334,6 +326,8 @@ def hierarchical_search(
|
|||||||
"total_chunks": 0,
|
"total_chunks": 0,
|
||||||
"fallback_reason": "Weaviate client unavailable",
|
"fallback_reason": "Weaviate client unavailable",
|
||||||
}
|
}
|
||||||
|
# Set flag to fallback outside context manager
|
||||||
|
raise ValueError("FALLBACK_TO_SIMPLE")
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════
|
||||||
# STAGE 1: Search Summary collection for relevant sections
|
# STAGE 1: Search Summary collection for relevant sections
|
||||||
@@ -352,15 +346,7 @@ def hierarchical_search(
|
|||||||
|
|
||||||
if not summaries_result.objects:
|
if not summaries_result.objects:
|
||||||
# No summaries found
|
# No summaries found
|
||||||
if not force_hierarchical:
|
if force_hierarchical:
|
||||||
# Auto-detection: fallback to simple search
|
|
||||||
results = simple_search(query, limit, author_filter, work_filter)
|
|
||||||
return {
|
|
||||||
"mode": "simple",
|
|
||||||
"results": results,
|
|
||||||
"total_chunks": len(results),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# Forced hierarchical: return empty hierarchical result
|
# Forced hierarchical: return empty hierarchical result
|
||||||
return {
|
return {
|
||||||
"mode": "hierarchical",
|
"mode": "hierarchical",
|
||||||
@@ -369,6 +355,8 @@ def hierarchical_search(
|
|||||||
"total_chunks": 0,
|
"total_chunks": 0,
|
||||||
"fallback_reason": f"Aucune section pertinente trouvée (0/{sections_limit} summaries)",
|
"fallback_reason": f"Aucune section pertinente trouvée (0/{sections_limit} summaries)",
|
||||||
}
|
}
|
||||||
|
# Signal fallback outside context manager
|
||||||
|
raise ValueError("FALLBACK_TO_SIMPLE")
|
||||||
|
|
||||||
# Extract section data
|
# Extract section data
|
||||||
sections_data = []
|
sections_data = []
|
||||||
@@ -418,15 +406,7 @@ def hierarchical_search(
|
|||||||
|
|
||||||
if not sections_data:
|
if not sections_data:
|
||||||
# No sections match filters
|
# No sections match filters
|
||||||
if not force_hierarchical:
|
if force_hierarchical:
|
||||||
# Auto-detection: fallback to simple search
|
|
||||||
results = simple_search(query, limit, author_filter, work_filter)
|
|
||||||
return {
|
|
||||||
"mode": "simple",
|
|
||||||
"results": results,
|
|
||||||
"total_chunks": len(results),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# Forced hierarchical: return empty hierarchical result
|
# Forced hierarchical: return empty hierarchical result
|
||||||
filters_str = f"author={author_filter}" if author_filter else ""
|
filters_str = f"author={author_filter}" if author_filter else ""
|
||||||
if work_filter:
|
if work_filter:
|
||||||
@@ -438,6 +418,8 @@ def hierarchical_search(
|
|||||||
"total_chunks": 0,
|
"total_chunks": 0,
|
||||||
"fallback_reason": f"Aucune section ne correspond aux filtres ({filters_str})",
|
"fallback_reason": f"Aucune section ne correspond aux filtres ({filters_str})",
|
||||||
}
|
}
|
||||||
|
# Signal fallback outside context manager
|
||||||
|
raise ValueError("FALLBACK_TO_SIMPLE")
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════
|
||||||
# STAGE 2: Search Chunk collection filtered by sections
|
# STAGE 2: Search Chunk collection filtered by sections
|
||||||
@@ -497,6 +479,18 @@ def hierarchical_search(
|
|||||||
"total_chunks": len(all_chunks),
|
"total_chunks": len(all_chunks),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
# Check if this is our fallback signal
|
||||||
|
if str(e) == "FALLBACK_TO_SIMPLE":
|
||||||
|
# Fallback to simple search (outside context manager)
|
||||||
|
results = simple_search(query, limit, author_filter, work_filter)
|
||||||
|
return {
|
||||||
|
"mode": "simple",
|
||||||
|
"results": results,
|
||||||
|
"total_chunks": len(results),
|
||||||
|
}
|
||||||
|
# Re-raise if not our signal
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erreur recherche hiérarchique: {e}")
|
print(f"Erreur recherche hiérarchique: {e}")
|
||||||
# Fallback to simple search on error (unless forced)
|
# Fallback to simple search on error (unless forced)
|
||||||
|
|||||||
Reference in New Issue
Block a user