Mirrors /opt/ai-apps/eh-search/ on the server, including the full FastAPI app (intent routing, FTS+fuzzy+substring hybrid, multi-source federation across vehicles + blog + brands + pages + static + tag bridge), SQL schema (Postgres materialized view with german_unaccent text search, pg_trgm for fuzzy), Dockerfile and compose. Sanitized the hardcoded password in sql/01_init.sql — replaced with REPLACE_ME_BEFORE_APPLYING placeholder since this repo is public. The eh-search service binds only on the private network (10.0.0.8:8200) and is reachable only via Pegasus nginx proxy at /api/search. Refs OP#1094 OP#1105 OP#1112 OP#1116 OP#1117
50 lines
1.5 KiB
Python
50 lines
1.5 KiB
Python
"""Autocomplete / Suggest endpoint (Typ 11)."""
|
|
from app import db
|
|
from app.schemas import SuggestItem
|
|
|
|
|
|
async def top_brands(limit: int = 10) -> list[SuggestItem]:
|
|
rows = await db.fetch(
|
|
"SELECT brand, count(*) AS cnt FROM search_vehicles "
|
|
"WHERE brand IS NOT NULL GROUP BY brand ORDER BY cnt DESC LIMIT $1",
|
|
limit,
|
|
)
|
|
return [
|
|
SuggestItem(text=r["brand"], type="brand", count=r["cnt"])
|
|
for r in rows
|
|
]
|
|
|
|
|
|
async def prefix_suggest(prefix: str, limit: int = 8) -> list[SuggestItem]:
|
|
"""Brand + model prefix matching, case-insensitive."""
|
|
pattern = f"{prefix.lower()}%"
|
|
|
|
# Brands first
|
|
brand_rows = await db.fetch(
|
|
"SELECT brand, count(*) AS cnt FROM search_vehicles "
|
|
"WHERE LOWER(brand) LIKE $1 GROUP BY brand ORDER BY cnt DESC LIMIT $2",
|
|
pattern,
|
|
limit,
|
|
)
|
|
items = [
|
|
SuggestItem(text=r["brand"], type="brand", count=r["cnt"])
|
|
for r in brand_rows
|
|
]
|
|
|
|
# Then models if room
|
|
remaining = limit - len(items)
|
|
if remaining > 0:
|
|
model_rows = await db.fetch(
|
|
"SELECT DISTINCT brand || ' ' || model AS text, count(*) AS cnt "
|
|
"FROM search_vehicles "
|
|
"WHERE model IS NOT NULL AND LOWER(model) LIKE $1 "
|
|
"GROUP BY brand, model ORDER BY cnt DESC LIMIT $2",
|
|
pattern,
|
|
remaining,
|
|
)
|
|
items.extend(
|
|
SuggestItem(text=r["text"], type="model", count=r["cnt"])
|
|
for r in model_rows
|
|
)
|
|
|
|
return items
|