fix(api): handle blank search text

Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
phernandez
2026-05-04 13:35:13 -05:00
parent 7f9fc80e27
commit 3589e21278
6 changed files with 63 additions and 27 deletions
@@ -4,6 +4,8 @@ This router uses external_id UUIDs for stable, API-friendly routing.
V1 uses string-based project names which are less efficient and less stable.
"""
import asyncio
from fastapi import APIRouter, HTTPException, Path
import logfire
@@ -74,8 +76,10 @@ async def search(
page=page,
page_size=page_size,
):
results = await search_service.search(query, limit=page_size, offset=offset)
total = await search_service.count(query)
results, total = await asyncio.gather(
search_service.search(query, limit=page_size, offset=offset),
search_service.count(query),
)
except SemanticSearchDisabledError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except SemanticDependenciesMissingError as exc:
@@ -1012,12 +1012,7 @@ class PostgresSearchRepository(SearchRepositoryBase):
min_similarity: Optional[float] = None,
) -> int:
"""Count indexed content matching the Postgres FTS query."""
mode = (
retrieval_mode.value
if isinstance(retrieval_mode, SearchRetrievalMode)
else str(retrieval_mode)
)
if mode != SearchRetrievalMode.FTS.value:
if retrieval_mode != SearchRetrievalMode.FTS:
return await super().count(
search_text=search_text,
permalink=permalink,
@@ -261,6 +261,9 @@ class SearchRepositoryBase(ABC):
min_similarity: Optional[float] = None,
) -> int:
"""Count results for retrieval modes that cannot use a backend COUNT query."""
# Trigger: vector and hybrid modes rank after embedding lookup, filtering, and fusion.
# Why: that scoring pipeline is not expressible as a portable database COUNT query.
# Outcome: fetch the bounded candidate set and count the final in-memory results.
results = await self.search(
search_text=search_text,
permalink=permalink,
@@ -1031,12 +1031,7 @@ class SQLiteSearchRepository(SearchRepositoryBase):
min_similarity: Optional[float] = None,
) -> int:
"""Count indexed content matching the SQLite FTS query."""
mode = (
retrieval_mode.value
if isinstance(retrieval_mode, SearchRetrievalMode)
else str(retrieval_mode)
)
if mode != SearchRetrievalMode.FTS.value:
if retrieval_mode != SearchRetrievalMode.FTS:
return await super().count(
search_text=search_text,
permalink=permalink,
+4 -4
View File
@@ -155,10 +155,10 @@ class SearchService:
tags = query.tags
# Support tag:<tag> shorthand by mapping to tags filter.
if search_text:
text = search_text.strip()
if text.lower().startswith("tag:"):
tag_values = re.split(r"[,\s]+", text[4:].strip())
if search_text is not None:
search_text = search_text.strip() or None
if search_text and search_text.lower().startswith("tag:"):
tag_values = re.split(r"[,\s]+", search_text[4:].strip())
parsed_tags = [t for t in tag_values if t]
if parsed_tags:
tags = parsed_tags