feat(chat-ui): Add Flash Lite as 3rd model option in NordaGPT dropdown
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

Users can now choose between Flash Lite (fastest, 1000 RPD), Flash
(thinking mode, 20 RPD) and Pro (premium). Default changed to Flash Lite.
Badge shows actual model used for full transparency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-07 14:44:22 +01:00
parent 5bd1b149c7
commit 6b06ce2aa1
2 changed files with 58 additions and 34 deletions

View File

@ -44,8 +44,8 @@ def chat():
def chat_settings():
"""Get or update chat settings (model selection, monthly cost)"""
if request.method == 'GET':
# Get current model from session or default to flash
model = session.get('chat_model', 'flash')
# Get current model from session or default to flash-lite
model = session.get('chat_model', 'flash-lite')
# Calculate monthly cost for current user
monthly_cost = 0.0
@ -71,12 +71,12 @@ def chat_settings():
# POST - update settings
try:
data = request.get_json()
model = data.get('model', 'flash')
model = data.get('model', 'flash-lite')
# Validate model
valid_models = ['flash', 'pro']
valid_models = ['flash-lite', 'flash', 'pro']
if model not in valid_models:
model = 'flash'
model = 'flash-lite'
# Store in session
session['chat_model'] = model
@ -144,8 +144,8 @@ def chat_send_message(conversation_id):
finally:
db.close()
# Get model from request or session (flash = default, pro = premium)
model_choice = data.get('model') or session.get('chat_model', 'flash')
# Get model from request or session (flash-lite = default, flash = thinking, pro = premium)
model_choice = data.get('model') or session.get('chat_model', 'flash-lite')
# Check Pro model limits (Flash is free - no limits)
if model_choice == 'pro':
@ -192,19 +192,25 @@ def chat_send_message(conversation_id):
finally:
db_check.close()
# Map model choice to actual model name
# Map model choice to actual model name and thinking level
model_map = {
'flash': '3-flash',
'pro': '3-pro'
'flash-lite': 'flash-lite', # Gemini 2.5 Flash Lite - 1000 RPD, szybki
'flash': '3-flash', # Gemini 3 Flash - 20 RPD, thinking mode
'pro': '3-pro' # Gemini 3 Pro - 20 RPD, premium
}
model_key = model_map.get(model_choice, '3-flash')
thinking_map = {
'flash-lite': 'minimal',
'flash': 'high',
'pro': 'high'
}
model_key = model_map.get(model_choice, 'flash-lite')
chat_engine = NordaBizChatEngine(model=model_key)
response = chat_engine.send_message(
conversation_id=conversation_id,
user_message=message,
user_id=current_user.id,
thinking_level='minimal' if model_choice == 'flash' else 'high'
thinking_level=thinking_map.get(model_choice, 'minimal')
)
# Get actual cost from response

View File

@ -1248,8 +1248,8 @@
<!-- 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>
<span class="thinking-icon" id="modelIcon">💨</span>
<span class="thinking-label" id="modelLabel">Flash Lite</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>
@ -1259,22 +1259,31 @@
<strong>Model AI</strong>
<p>Wybierz model dopasowany do pytania</p>
</div>
<div class="thinking-option active" data-model="flash" onclick="setModel('flash')">
<div class="thinking-option active" data-model="flash-lite" onclick="setModel('flash-lite')">
<div class="thinking-option-header">
<span class="thinking-option-icon"></span>
<span class="thinking-option-name">Gemini Flash</span>
<span class="thinking-option-icon">💨</span>
<span class="thinking-option-name">Flash Lite</span>
<span class="thinking-option-badge free">Darmowy</span>
</div>
<p class="thinking-option-desc">Szybki i skuteczny. Dla większości pytań o firmy, kontakty, wydarzenia.</p>
<span class="thinking-option-price free">Bez opłat</span>
<p class="thinking-option-desc">Najszybszy. Dla prostych pytań o firmy, kontakty, wydarzenia.</p>
<span class="thinking-option-price free">Bez opłat · 1000 zapytań/dzień</span>
</div>
<div class="thinking-option" 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 free">Darmowy</span>
</div>
<p class="thinking-option-desc">Thinking mode — głębsze rozumowanie. Dla złożonych pytań o firmy i strategię.</p>
<span class="thinking-option-price free">Bez opłat · 20 zapytań/dzień</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">Gemini Pro</span>
<span class="thinking-option-name">Pro</span>
<span class="thinking-option-badge premium">Premium</span>
</div>
<p class="thinking-option-desc">Głęboka analiza i rozumowanie. Dla złożonych pytań, strategii, rekomendacji.</p>
<p class="thinking-option-desc">Najlepsza analiza i rozumowanie. Dla strategii, rekomendacji, raportów.</p>
<span class="thinking-option-price">~$0.20/pytanie · limit: $2/dzień</span>
</div>
</div>
@ -1309,18 +1318,23 @@
<div class="model-current">
<h3>Dostępne modele AI</h3>
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;">
<div class="model-badge-large" style="flex: 1; min-width: 200px; background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border: 2px solid #22c55e;">
<span class="model-name">⚡ Gemini 3 Flash</span>
<div class="model-badge-large" style="flex: 1; min-width: 150px; background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border: 2px solid #22c55e;">
<span class="model-name">💨 Flash Lite</span>
<span class="model-provider" style="color: #22c55e;">DARMOWY</span>
</div>
<div class="model-badge-large" style="flex: 1; min-width: 200px; background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); border: 2px solid #a855f7;">
<span class="model-name">🧠 Gemini 3 Pro</span>
<div class="model-badge-large" style="flex: 1; min-width: 150px; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border: 2px solid #3b82f6;">
<span class="model-name">⚡ Flash</span>
<span class="model-provider" style="color: #3b82f6;">DARMOWY</span>
</div>
<div class="model-badge-large" style="flex: 1; min-width: 150px; background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); border: 2px solid #a855f7;">
<span class="model-name">🧠 Pro</span>
<span class="model-provider" style="color: #a855f7;">PREMIUM</span>
</div>
</div>
<p class="model-description">
Najnowsza generacja modeli Google z zaawansowanym rozumowaniem (thinking mode).
<strong>Flash</strong> jest szybki i darmowy. <strong>Pro</strong> oferuje głębszą analizę dla złożonych pytań.
<strong>Flash Lite</strong> — najszybszy, 1000 zapytań/dzień.
<strong>Flash</strong> — thinking mode, głębsze rozumowanie.
<strong>Pro</strong> — najlepsza analiza dla złożonych pytań.
</p>
</div>
@ -1440,7 +1454,7 @@
<div class="model-benefits">
<h3>✨ Co działa w NordaGPT?</h3>
<ul>
<li><strong>Wybór modelu</strong> — Flash (darmowy, szybki) lub Pro (premium, głębsza analiza)</li>
<li><strong>Wybór modelu</strong> — Flash Lite (najszybszy), Flash (thinking mode) lub Pro (premium)</li>
<li><strong>Baza {{ COMPANY_COUNT }} firm</strong> — pełna wiedza o członkach Izby</li>
<li><strong>Forum i wydarzenia</strong> — dostęp do dyskusji i kalendarza</li>
<li><strong>Linki w odpowiedziach</strong> — bezpośrednie odnośniki do profili firm i osób</li>
@ -1537,14 +1551,15 @@
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
let currentConversationId = null;
let conversations = [];
let currentModel = 'flash'; // Default model (flash = ekonomiczny)
let currentModel = 'flash-lite'; // Default model (flash-lite = najszybszy, 1000 RPD)
let monthlyUsageCost = 0; // Koszt miesięczny użytkownika
// ============================================
// Model Selection Toggle Functions
// ============================================
const MODEL_CONFIG = {
'flash': { label: 'Flash', icon: '⚡', desc: 'Szybki' },
'flash-lite': { label: 'Flash Lite', icon: '💨', desc: 'Najszybszy' },
'flash': { label: 'Flash', icon: '⚡', desc: 'Thinking' },
'pro': { label: 'Pro', icon: '🧠', desc: 'Analiza' }
};
@ -1677,13 +1692,13 @@ async function loadModelSettings() {
const response = await fetch('/api/chat/settings');
const data = await response.json();
if (data.success) {
// Always start with Flash (free, fast) - ignore saved preference
currentModel = 'flash';
const config = MODEL_CONFIG['flash'];
// Always start with Flash Lite (free, fastest, 1000 RPD) - ignore saved preference
currentModel = 'flash-lite';
const config = MODEL_CONFIG['flash-lite'];
document.getElementById('modelLabel').textContent = config.label;
document.getElementById('modelIcon').textContent = config.icon;
document.querySelectorAll('.thinking-option').forEach(opt => {
opt.classList.toggle('active', opt.dataset.model === 'flash');
opt.classList.toggle('active', opt.dataset.model === 'flash-lite');
});
// Load monthly cost
if (data.monthly_cost !== undefined) {
@ -1963,9 +1978,12 @@ function addMessage(role, content, animate = true, techInfo = null) {
// Model labels
const modelLabels = {
'flash-lite': '💨 Flash Lite',
'flash': '⚡ Flash',
'pro': '🧠 Pro',
'gemini-2.5-flash-lite': '💨 Flash Lite',
'gemini-3-flash-preview': '⚡ Flash',
'gemini-2.5-flash': '⚡ Flash 2.5',
'gemini-3-pro-preview': '🧠 Pro'
};
const modelLabel = modelLabels[modelName] || modelName;