refactor(synapse): backend updates, add icons module, relocate playbooks to data/playbooks
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Executable
+44
@@ -0,0 +1,44 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
|
||||
_SEARCH_TRIGGERS = frozenset({
|
||||
# Time-sensitive single words
|
||||
"news", "weather", "today", "tonight", "yesterday", "price", "stock",
|
||||
# Phrases that imply freshness or external lookup
|
||||
"latest ", "right now", "this week", "this month", "recently",
|
||||
"who is ", "what is ", "when did ", "how much does", "how much is",
|
||||
"look up", "search for", "find out", "release date",
|
||||
"just released", "just announced", "just launched",
|
||||
"current version", "current price",
|
||||
})
|
||||
|
||||
|
||||
def needs_web_search(message: str) -> bool:
|
||||
lower = message.lower()
|
||||
return any(kw in lower for kw in _SEARCH_TRIGGERS)
|
||||
|
||||
|
||||
def web_search(query: str, max_results: int = 4) -> str:
|
||||
"""Search DuckDuckGo and return formatted result snippets.
|
||||
|
||||
Returns an empty string on any failure so callers can treat it as
|
||||
optional context — a failed search should never break a chat response.
|
||||
"""
|
||||
try:
|
||||
from duckduckgo_search import DDGS
|
||||
with DDGS() as ddgs:
|
||||
results = list(ddgs.text(query, max_results=max_results))
|
||||
if not results:
|
||||
return ""
|
||||
parts = []
|
||||
for i, r in enumerate(results, 1):
|
||||
title = r.get("title", "").strip()
|
||||
body = r.get("body", "").strip()
|
||||
href = r.get("href", "").strip()
|
||||
parts.append(f"{i}. **{title}**\n{body}\nSource: {href}")
|
||||
return "\n\n".join(parts)
|
||||
except Exception:
|
||||
return ""
|
||||
Reference in New Issue
Block a user