Add SearXNG web search for current information
- Add searxng.py service for web queries via SearXNG API - Integrate search into ai_chat.py with AI-driven search decisions - AI determines if query needs current info, then searches automatically - Add SEARXNG_URL, SEARXNG_ENABLED, SEARXNG_MAX_RESULTS config options - Update documentation in README.md, CLAUDE.md, and .env.example
This commit is contained in:
@@ -7,7 +7,7 @@ import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from daemon_boyfriend.config import settings
|
||||
from daemon_boyfriend.services import AIService, ConversationManager, Message
|
||||
from daemon_boyfriend.services import AIService, ConversationManager, Message, SearXNGService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -71,6 +71,9 @@ class AIChatCog(commands.Cog):
|
||||
self.bot = bot
|
||||
self.ai_service = AIService()
|
||||
self.conversations = ConversationManager()
|
||||
self.search_service: SearXNGService | None = None
|
||||
if settings.searxng_enabled and settings.searxng_url:
|
||||
self.search_service = SearXNGService(settings.searxng_url)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.Message) -> None:
|
||||
@@ -138,10 +141,23 @@ class AIChatCog(commands.Cog):
|
||||
# Add current message to history for the API call
|
||||
messages = history + [Message(role="user", content=user_message)]
|
||||
|
||||
# Check if we should search the web
|
||||
search_context = await self._maybe_search(user_message)
|
||||
|
||||
# Build system prompt with search context if available
|
||||
system_prompt = self.ai_service.get_system_prompt()
|
||||
if search_context:
|
||||
system_prompt += (
|
||||
"\n\n--- Web Search Results ---\n"
|
||||
"Use the following current information from the web to help answer the user's question. "
|
||||
"Cite sources when relevant.\n\n"
|
||||
f"{search_context}"
|
||||
)
|
||||
|
||||
# Generate response
|
||||
response = await self.ai_service.chat(
|
||||
messages=messages,
|
||||
system_prompt=self.ai_service.get_system_prompt(),
|
||||
system_prompt=system_prompt,
|
||||
)
|
||||
|
||||
# Save the exchange to history
|
||||
@@ -154,6 +170,64 @@ class AIChatCog(commands.Cog):
|
||||
|
||||
return response.content
|
||||
|
||||
async def _maybe_search(self, query: str) -> str | None:
|
||||
"""Determine if a search is needed and perform it.
|
||||
|
||||
Args:
|
||||
query: The user's message
|
||||
|
||||
Returns:
|
||||
Formatted search results or None if search not needed/available
|
||||
"""
|
||||
if not self.search_service:
|
||||
return None
|
||||
|
||||
# Ask the AI if this query needs current information
|
||||
decision_prompt = (
|
||||
"You are a search decision assistant. Your ONLY job is to decide if the user's "
|
||||
"question requires current/real-time information from the internet.\n\n"
|
||||
"Respond with ONLY 'SEARCH: <query>' if a web search would help answer the question "
|
||||
"(replace <query> with optimal search terms), or 'NO_SEARCH' if the question can be "
|
||||
"answered with general knowledge.\n\n"
|
||||
"Examples that NEED search:\n"
|
||||
"- Current events, news, recent happenings\n"
|
||||
"- Current weather, stock prices, sports scores\n"
|
||||
"- Latest version of software, current documentation\n"
|
||||
"- Information about specific people, companies, or products that may have changed\n"
|
||||
"- 'What time is it in Tokyo?' or any real-time data\n\n"
|
||||
"Examples that DON'T need search:\n"
|
||||
"- General knowledge, science, math, history\n"
|
||||
"- Coding help, programming concepts\n"
|
||||
"- Personal advice, opinions, creative writing\n"
|
||||
"- Explanations of concepts or 'how does X work'"
|
||||
)
|
||||
|
||||
try:
|
||||
decision = await self.ai_service.chat(
|
||||
messages=[Message(role="user", content=query)],
|
||||
system_prompt=decision_prompt,
|
||||
)
|
||||
|
||||
response_text = decision.content.strip()
|
||||
|
||||
if response_text.startswith("SEARCH:"):
|
||||
search_query = response_text[7:].strip()
|
||||
logger.info(f"AI decided to search for: {search_query}")
|
||||
|
||||
results = await self.search_service.search(
|
||||
query=search_query,
|
||||
max_results=settings.searxng_max_results,
|
||||
)
|
||||
|
||||
if results:
|
||||
return self.search_service.format_results_for_context(results)
|
||||
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Search decision/execution failed: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def setup(bot: commands.Bot) -> None:
|
||||
"""Load the AI Chat cog."""
|
||||
|
||||
Reference in New Issue
Block a user