diff --git a/app.py b/app.py
index 93b5c06..1fdeddd 100644
--- a/app.py
+++ b/app.py
@@ -4517,33 +4517,51 @@ def chat():
@csrf.exempt
@login_required
def chat_settings():
- """Get or update chat settings (thinking level)"""
+ """Get or update chat settings (model selection, monthly cost)"""
if request.method == 'GET':
- # Get current thinking level from session or default
- thinking_level = session.get('thinking_level', 'high')
+ # Get current model from session or default to flash
+ model = session.get('chat_model', 'flash')
+
+ # Calculate monthly cost for current user
+ monthly_cost = 0.0
+ try:
+ from database import AIApiCost
+ db = SessionLocal()
+ # Get first day of current month
+ first_day = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
+ costs = db.query(AIApiCost).filter(
+ AIApiCost.user_id == current_user.id,
+ AIApiCost.timestamp >= first_day
+ ).all()
+ monthly_cost = sum(c.total_cost_usd or 0 for c in costs)
+ db.close()
+ except Exception as e:
+ logger.warning(f"Error calculating monthly cost: {e}")
+
return jsonify({
'success': True,
- 'thinking_level': thinking_level
+ 'model': model,
+ 'monthly_cost': round(monthly_cost, 4)
})
# POST - update settings
try:
data = request.get_json()
- thinking_level = data.get('thinking_level', 'high')
+ model = data.get('model', 'flash')
- # Validate thinking level
- valid_levels = ['minimal', 'low', 'medium', 'high']
- if thinking_level not in valid_levels:
- thinking_level = 'high'
+ # Validate model
+ valid_models = ['flash', 'pro']
+ if model not in valid_models:
+ model = 'flash'
# Store in session
- session['thinking_level'] = thinking_level
+ session['chat_model'] = model
- logger.info(f"User {current_user.id} set thinking_level to: {thinking_level}")
+ logger.info(f"User {current_user.id} set chat_model to: {model}")
return jsonify({
'success': True,
- 'thinking_level': thinking_level
+ 'model': model
})
except Exception as e:
@@ -4602,24 +4620,28 @@ def chat_send_message(conversation_id):
finally:
db.close()
- # Get thinking level from request or session
- thinking_level = data.get('thinking_level') or session.get('thinking_level', 'high')
+ # Get model from request or session (flash = default, pro = premium)
+ model_choice = data.get('model') or session.get('chat_model', 'flash')
- chat_engine = NordaBizChatEngine()
+ # Map model choice to actual model name
+ model_map = {
+ 'flash': '3-flash',
+ 'pro': '3-pro'
+ }
+ model_key = model_map.get(model_choice, '3-flash')
+
+ 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=thinking_level
+ thinking_level='minimal' if model_choice == 'flash' else 'high'
)
- # Get free tier usage stats for today
- free_tier_stats = get_free_tier_usage()
-
- # Calculate theoretical cost (Gemini 2.0 Flash pricing)
+ # Get actual cost from response
tokens_in = response.tokens_input or 0
tokens_out = response.tokens_output or 0
- theoretical_cost = (tokens_in / 1_000_000) * 0.075 + (tokens_out / 1_000_000) * 0.30
+ actual_cost = response.cost_usd or 0.0
return jsonify({
'success': True,
@@ -4628,24 +4650,12 @@ def chat_send_message(conversation_id):
'created_at': response.created_at.isoformat(),
# Technical metadata
'tech_info': {
- 'model': gemini_service.get_gemini_service().model_name if gemini_service.get_gemini_service() else 'gemini-3-flash-preview',
- 'thinking_level': thinking_level,
- 'thinking_enabled': gemini_service.get_gemini_service().thinking_enabled if gemini_service.get_gemini_service() else True,
- 'data_source': 'PostgreSQL (150 firm Norda Biznes)',
- 'architecture': 'Full DB Context + Thinking Mode',
+ 'model': model_choice,
'tokens_input': tokens_in,
'tokens_output': tokens_out,
'tokens_total': tokens_in + tokens_out,
'latency_ms': response.latency_ms or 0,
- 'theoretical_cost_usd': round(theoretical_cost, 6),
- 'actual_cost_usd': 0.0, # Paid tier but tracked
- 'free_tier': {
- 'is_free': False,
- 'daily_limit': 10000, # Gemini paid tier
- 'requests_today': free_tier_stats['requests_today'],
- 'tokens_today': free_tier_stats['tokens_today'],
- 'remaining': max(0, 10000 - free_tier_stats['requests_today'])
- }
+ 'cost_usd': round(actual_cost, 6)
}
})
diff --git a/nordabiz_chat.py b/nordabiz_chat.py
index 613da82..d1ebd07 100644
--- a/nordabiz_chat.py
+++ b/nordabiz_chat.py
@@ -86,21 +86,29 @@ class NordaBizChatEngine:
Helps users find companies, services, and business partners.
"""
- def __init__(self, gemini_api_key: Optional[str] = None, use_global_service: bool = True):
+ def __init__(self, gemini_api_key: Optional[str] = None, use_global_service: bool = True, model: str = None):
"""
Initialize Norda Biznes Chat Engine
Args:
gemini_api_key: Google Gemini API key (uses env var if not provided)
use_global_service: Use global gemini_service for automatic cost tracking (default: True)
+ model: Model key ('3-flash', '3-pro') - if provided, creates new service with this model
"""
self.use_global_service = use_global_service
+ self.requested_model = model
if use_global_service:
- # Use global gemini_service for automatic cost tracking to ai_api_costs table
- self.gemini_service = gemini_service.get_gemini_service()
- # Get model name from global service (currently Gemini 3 Flash Preview)
- self.model_name = self.gemini_service.model_name if self.gemini_service else "gemini-3-flash-preview"
+ if model:
+ # Create new service with requested model
+ from gemini_service import GeminiService
+ self.gemini_service = GeminiService(model=model)
+ self.model_name = self.gemini_service.model_name
+ else:
+ # Use global gemini_service for automatic cost tracking to ai_api_costs table
+ self.gemini_service = gemini_service.get_gemini_service()
+ # Get model name from global service (currently Gemini 3 Flash Preview)
+ self.model_name = self.gemini_service.model_name if self.gemini_service else "gemini-3-flash-preview"
self.model = None
# Initialize tokenizer for cost calculation (still needed for per-message tracking)
diff --git a/templates/chat.html b/templates/chat.html
index 0c25501..77d1c3b 100755
--- a/templates/chat.html
+++ b/templates/chat.html
@@ -311,6 +311,11 @@
font-style: italic;
}
+ .thinking-badge-cost {
+ color: #f59e0b;
+ font-weight: 500;
+ }
+
/* Klikalne linki jako kolorowe badge'y */
.message-content a {
display: inline-block;
@@ -724,6 +729,49 @@
font-weight: 500;
}
+ .thinking-option-badge.premium {
+ background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
+ }
+
+ .thinking-option-price {
+ display: block;
+ font-size: 11px;
+ color: #6b7280;
+ margin-top: 4px;
+ font-style: italic;
+ }
+
+ /* Monthly Cost Badge */
+ .monthly-cost-badge {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ background: rgba(255,255,255,0.15);
+ padding: 6px 12px;
+ border-radius: var(--radius-md);
+ font-size: 12px;
+ margin-left: var(--spacing-sm);
+ }
+
+ .monthly-cost-badge .cost-icon {
+ font-size: 14px;
+ }
+
+ .monthly-cost-badge .cost-label {
+ opacity: 0.8;
+ }
+
+ .monthly-cost-badge .cost-value {
+ font-weight: 600;
+ color: #fef08a;
+ }
+
+ @media (max-width: 768px) {
+ .monthly-cost-badge .cost-label {
+ display: none;
+ }
+ }
+
.thinking-option-desc {
color: var(--text-secondary);
font-size: var(--font-size-xs);
@@ -1181,45 +1229,46 @@
🤖
NordaGPT
-
-
-
-