fix(nordagpt): catch full URL hallucinations + remove manual model selector
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

- Validator now catches https://nordabiznes.pl/company/slug (full URLs)
- Also catches /firma/ URLs as fallback
- Removed Flash/Pro model selector — Smart Router decides automatically
- Removed "Spróbuj Pro" hints from response badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-28 06:51:08 +01:00
parent 337f229a05
commit 87d4fde5c3
2 changed files with 8 additions and 40 deletions

View File

@ -198,9 +198,12 @@ class NordaBizChatEngine:
logger.warning(f"NordaGPT hallucination blocked: '{link_text}' (slug: '{slug}') not in DB")
return link_text # Keep text, remove link
text = re.sub(r'\[([^\]]+)\]\(/company/([a-z0-9-]+)\)', replace_link, text)
# Match both relative /company/slug AND absolute https://nordabiznes.pl/company/slug
text = re.sub(r'\[([^\]]+)\]\((?:https?://nordabiznes\.pl)?/company/([a-z0-9-]+)\)', replace_link, text)
# Also catch /firma/ in case AI uses old format
text = re.sub(r'\[([^\]]+)\]\((?:https?://nordabiznes\.pl)?/firma/([a-z0-9-]+)\)', replace_link, text)
# 2. Validate pill-style links
# 2. Validate pill-style links (HTML)
def replace_pill_link(match):
full_match = match.group(0)
slug = match.group(1)
@ -213,7 +216,8 @@ class NordaBizChatEngine:
logger.warning(f"NordaGPT hallucination blocked: pill link '{slug}' not in DB")
return link_text
text = re.sub(r'<a[^>]*href=["\']/company/([a-z0-9-]+)["\'][^>]*>(.*?)</a>', replace_pill_link, text)
text = re.sub(r'<a[^>]*href=["\'](?:https?://nordabiznes\.pl)?/company/([a-z0-9-]+)["\'][^>]*>(.*?)</a>', replace_pill_link, text)
text = re.sub(r'<a[^>]*href=["\'](?:https?://nordabiznes\.pl)?/firma/([a-z0-9-]+)["\'][^>]*>(.*?)</a>', replace_pill_link, text)
# 3. Remove plain-text mentions of fake companies (bold or plain)
# Catch patterns like "**Baumar**" or "Baumar" that appear as company names

View File

@ -1546,40 +1546,7 @@
</button>
<img src="{{ url_for('static', filename='img/nordagpt-icon.svg') }}" alt="NordaGPT" style="width: 32px; height: 32px;">
<h1>NordaGPT</h1>
<!-- Model Selection Toggle -->
<div class="thinking-toggle" id="modelToggle">
<button class="thinking-btn" onclick="toggleModelDropdown()" title="Wybierz model AI">
<span class="thinking-icon" id="modelIcon"></span>
<span class="thinking-label" id="modelLabel">Flash</span>
<svg class="thinking-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24" width="12" height="12">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</button>
<div class="thinking-dropdown" id="modelDropdown">
<div class="thinking-dropdown-header">
<strong>Tryb pracy AI</strong>
<p>Flash wystarczy do większości pytań</p>
</div>
<div class="thinking-option active" data-model="flash" onclick="setModel('flash')">
<div class="thinking-option-header">
<span class="thinking-option-icon"></span>
<span class="thinking-option-name">Flash</span>
<span class="thinking-option-badge">Zalecany</span>
</div>
<p class="thinking-option-desc">Szybki i inteligentny. Pytania o firmy, kontakty, usługi, branże.</p>
<span class="thinking-option-price">Wystarczający do większości pytań</span>
</div>
<div class="thinking-option" data-model="pro" onclick="setModel('pro')">
<div class="thinking-option-header">
<span class="thinking-option-icon">🧠</span>
<span class="thinking-option-name">Pro</span>
<span class="thinking-option-badge premium">Premium</span>
</div>
<p class="thinking-option-desc">Głębsza analiza, porównania, raporty. Dłuższe odpowiedzi.</p>
<span class="thinking-option-price">Zużywa limit ~4x szybciej niż Flash</span>
</div>
</div>
</div>
<!-- Model is now auto-selected by Smart Router -->
<!-- Usage bars -->
<div class="usage-bars-container" id="usageBarsContainer" title="Zużycie limitu AI">
<div class="usage-bar-mini" title="Twój limit dzienny">
@ -2547,9 +2514,6 @@ async function sendMessage() {
let badgeHTML = `<span class="thinking-badge-level">${modelLabel}</span>`;
if (cIcon && tLabel) badgeHTML += ` · ${cIcon} ${tLabel}`;
badgeHTML += ` · <span class="thinking-badge-time">${latencySec}s</span> · <span class="thinking-badge-cost">${costStr}</span>`;
if (currentModel === 'flash') {
badgeHTML += ` · <a href="#" class="pro-upgrade-hint" onclick="event.preventDefault(); setModel('pro');" title="Przełącz na Gemini 3 Pro dla lepszych odpowiedzi">Lepsze odpowiedzi? <strong>Spróbuj Pro</strong> 🧠</a>`;
}
infoBadge.innerHTML = badgeHTML;
streamContent.appendChild(infoBadge);
if (chunk.cost_usd) updateMonthlyCost(chunk.cost_usd);