Add retry logic and stricter version detection for weak search results
Retries with a refined query when no version number appears alongside release context words (latest/stable/released/current) in snippets. Exposes retried flag in response and history. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -8,6 +9,9 @@ import httpx
|
|||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
VERSION_PATTERN = re.compile(r'\bv?\d+\.\d+[\.\d]*\b')
|
||||||
|
VERSION_CONTEXT = re.compile(r'\b(latest|stable|current|released?|new version)\b', re.IGNORECASE)
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [sam] %(message)s")
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [sam] %(message)s")
|
||||||
logger = logging.getLogger("sam")
|
logger = logging.getLogger("sam")
|
||||||
|
|
||||||
@@ -51,6 +55,28 @@ async def search_web(query: str, max_results: int) -> list[dict]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _has_version(results: list[dict]) -> bool:
|
||||||
|
for r in results:
|
||||||
|
text = r.get("snippet", "") + " " + r.get("title", "")
|
||||||
|
if VERSION_PATTERN.search(text) and VERSION_CONTEXT.search(text):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def search_with_retry(query: str, max_results: int) -> tuple[list[dict], bool]:
|
||||||
|
"""Search SearXNG, retrying with a refined query if no version number found in results.
|
||||||
|
Returns (results, retried)."""
|
||||||
|
results = await search_web(query, max_results)
|
||||||
|
if _has_version(results):
|
||||||
|
return results, False
|
||||||
|
retry_query = query + " latest release version changelog"
|
||||||
|
logger.info(f"no version found in results — retrying: '{retry_query}'")
|
||||||
|
retry_results = await search_web(retry_query, max_results)
|
||||||
|
seen_urls = {r["url"] for r in results}
|
||||||
|
merged = results + [r for r in retry_results if r["url"] not in seen_urls]
|
||||||
|
return merged[:max_results], True
|
||||||
|
|
||||||
|
|
||||||
async def ollama_synthesize(prompt: str, model: str) -> str:
|
async def ollama_synthesize(prompt: str, model: str) -> str:
|
||||||
payload = {
|
payload = {
|
||||||
"model": model,
|
"model": model,
|
||||||
@@ -163,11 +189,11 @@ async def research(req: ResearchRequest):
|
|||||||
logger.info(f"research: query='{req.query}' max_results={req.max_results} model={model}")
|
logger.info(f"research: query='{req.query}' max_results={req.max_results} model={model}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = await search_web(req.query, req.max_results)
|
results, retried = await search_with_retry(req.query, req.max_results)
|
||||||
except httpx.HTTPError as e:
|
except httpx.HTTPError as e:
|
||||||
raise HTTPException(status_code=502, detail=f"SearXNG error: {e}")
|
raise HTTPException(status_code=502, detail=f"SearXNG error: {e}")
|
||||||
|
|
||||||
logger.info(f"got {len(results)} results from SearXNG")
|
logger.info(f"got {len(results)} results from SearXNG (retried={retried})")
|
||||||
|
|
||||||
prompt = build_prompt(req.query, results, req.instructions)
|
prompt = build_prompt(req.query, results, req.instructions)
|
||||||
|
|
||||||
@@ -195,6 +221,7 @@ async def research(req: ResearchRequest):
|
|||||||
"query": req.query,
|
"query": req.query,
|
||||||
"model": model,
|
"model": model,
|
||||||
"summary_chars": len(summary),
|
"summary_chars": len(summary),
|
||||||
|
"retried": retried,
|
||||||
}
|
}
|
||||||
save_history(history_entry)
|
save_history(history_entry)
|
||||||
(out_dir / "index.html").write_text(render_html(load_history()))
|
(out_dir / "index.html").write_text(render_html(load_history()))
|
||||||
@@ -214,4 +241,5 @@ async def research(req: ResearchRequest):
|
|||||||
"summary": summary,
|
"summary": summary,
|
||||||
"model": model,
|
"model": model,
|
||||||
"timestamp": timestamp,
|
"timestamp": timestamp,
|
||||||
|
"retried": retried,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user