feat(nordagpt): integrate company_matcher — AI sees only matched companies, eliminates hallucinations
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-28 07:18:08 +01:00
parent da7fc02070
commit 929e0b919f

View File

@ -87,6 +87,14 @@ except ImportError:
SMART_ROUTER_AVAILABLE = False
logger.warning("Smart Router or Context Builder not available - using full context fallback")
# Import company matcher for pre-selecting relevant companies (eliminates hallucinations)
try:
from company_matcher import match_companies
COMPANY_MATCHER_AVAILABLE = True
except ImportError:
COMPANY_MATCHER_AVAILABLE = False
logger.warning("Company matcher not available - using full company list")
# Import memory service for user fact storage and prompt injection
try:
from memory_service import format_memory_for_prompt, extract_facts_async, summarize_conversation_async
@ -449,6 +457,16 @@ class NordaBizChatEngine:
context = self._build_conversation_context(db, conversation, user_message)
effective_thinking = thinking_level
# Company Matcher — replace full company list with matched subset
if COMPANY_MATCHER_AVAILABLE:
try:
matched = match_companies(user_message, user_context=user_context, max_results=15)
context['matched_companies'] = matched
context['all_companies'] = [] # Clear full list — use matched only
logger.info(f"Company matcher found {len(matched)} companies for query")
except Exception as e:
logger.warning(f"Company matcher failed: {e}, using full company list")
# Get AI response with cost tracking
response = self._query_ai(
context,
@ -1450,9 +1468,41 @@ W dyskusji [Artur Wiertel](link) pytał o moderację. Pełna treść: [moje uwag
import logging
logging.getLogger(__name__).warning(f"Feedback learning error: {e}")
# Add ALL companies in compact JSON format
if context.get('all_companies'):
# Build explicit whitelist of allowed company names + slugs
# Add companies to prompt — matched (preferred) or full list (fallback)
matched = context.get('matched_companies', [])
if matched:
system_prompt += "\n\n🏢 FIRMY Z BAZY IZBY PASUJĄCE DO ZAPYTANIA:\n"
system_prompt += "Poniżej znajdują się JEDYNE firmy, które możesz wymienić w odpowiedzi.\n"
system_prompt += "NIE WOLNO Ci wymyślać ani dodawać ŻADNYCH innych firm.\n"
system_prompt += "Każdą firmę podawaj jako link: [Nazwa Firmy](/company/slug)\n\n"
for c in matched:
system_prompt += f"### {c['name']} → [link](/company/{c['slug']})\n"
if c.get('category'):
system_prompt += f"Kategoria: {c['category']}\n"
if c.get('description'):
system_prompt += f"Opis: {c['description'][:400]}\n"
if c.get('services'):
system_prompt += f"Usługi: {c['services'][:300]}\n"
if c.get('structured_services'):
system_prompt += f"Oferta: {', '.join(c['structured_services'][:10])}\n"
if c.get('ai_insights'):
ins = c['ai_insights']
if ins.get('services_list'):
system_prompt += f"Specjalizacje: {', '.join(ins['services_list'][:8])}\n"
if ins.get('unique_selling_points'):
system_prompt += f"Wyróżniki: {', '.join(ins['unique_selling_points'][:5])}\n"
if c.get('google_rating') and c.get('google_reviews'):
system_prompt += f"Google: {c['google_rating']}/5 ({c['google_reviews']} opinii)\n"
if c.get('phone'):
system_prompt += f"Tel: {c['phone']}\n"
if c.get('website'):
system_prompt += f"WWW: {c['website']}\n"
if c.get('match_reasons'):
system_prompt += f"Dopasowanie: {', '.join(c['match_reasons'])}\n"
system_prompt += "\n"
system_prompt += f"POWYŻSZE {len(matched)} FIRM TO JEDYNE, KTÓRE MOŻESZ WYMIENIĆ.\n"
elif context.get('all_companies'):
# Fallback: old behavior with all companies (when company_matcher unavailable)
whitelist_lines = []
for c in context['all_companies']:
name = c.get('name', '')
@ -1773,6 +1823,16 @@ W dyskusji [Artur Wiertel](link) pytał o moderację. Pełna treść: [moje uwag
else:
context = self._build_conversation_context(db, conversation, user_message)
# Company Matcher — replace full company list with matched subset
if COMPANY_MATCHER_AVAILABLE:
try:
matched = match_companies(user_message, user_context=user_context, max_results=15)
context['matched_companies'] = matched
context['all_companies'] = [] # Clear full list — use matched only
logger.info(f"Company matcher (stream) found {len(matched)} companies for query")
except Exception as e:
logger.warning(f"Company matcher failed: {e}, using full company list")
# Build full prompt
full_prompt = self._build_full_prompt(context, user_message, user_context, thinking_level)