diff --git a/app.py b/app.py index 1fdeddd..910f6e5 100644 --- a/app.py +++ b/app.py @@ -4623,6 +4623,52 @@ def chat_send_message(conversation_id): # Get model from request or session (flash = default, pro = premium) model_choice = data.get('model') or session.get('chat_model', 'flash') + # Check Pro model limits (Flash is free - no limits) + if model_choice == 'pro': + # Users without limits (admins) + UNLIMITED_USERS = ['maciej.pienczyn@inpi.pl', 'artur.wiertel@waterm.pl'] + + if current_user.email not in UNLIMITED_USERS: + # Check daily and monthly limits for Pro + from database import AIApiCost + db_check = SessionLocal() + try: + # Daily limit: $2.00 + today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + daily_costs = db_check.query(AIApiCost).filter( + AIApiCost.user_id == current_user.id, + AIApiCost.timestamp >= today_start, + AIApiCost.model_name.like('%pro%') + ).all() + daily_total = sum(c.total_cost_usd or 0 for c in daily_costs) + + if daily_total >= 2.0: + return jsonify({ + 'success': False, + 'error': 'Osiągnięto dzienny limit Pro ($2.00). Spróbuj jutro lub użyj darmowego modelu Flash.', + 'limit_exceeded': 'daily', + 'daily_used': round(daily_total, 2) + }), 429 + + # Monthly limit: $20.00 + month_start = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0) + monthly_costs = db_check.query(AIApiCost).filter( + AIApiCost.user_id == current_user.id, + AIApiCost.timestamp >= month_start, + AIApiCost.model_name.like('%pro%') + ).all() + monthly_total = sum(c.total_cost_usd or 0 for c in monthly_costs) + + if monthly_total >= 20.0: + return jsonify({ + 'success': False, + 'error': 'Osiągnięto miesięczny limit Pro ($20.00). Użyj darmowego modelu Flash.', + 'limit_exceeded': 'monthly', + 'monthly_used': round(monthly_total, 2) + }), 429 + finally: + db_check.close() + # Map model choice to actual model name model_map = { 'flash': '3-flash', diff --git a/gemini_service.py b/gemini_service.py index 57e588c..36e99a7 100644 --- a/gemini_service.py +++ b/gemini_service.py @@ -58,13 +58,14 @@ THINKING_LEVELS = { } # Pricing per 1M tokens (USD) - updated 2026-01-29 +# Note: Flash on Free Tier = $0.00, Pro on Paid Tier = paid pricing GEMINI_PRICING = { 'gemini-2.5-flash': {'input': 0.30, 'output': 2.50, 'thinking': 0}, 'gemini-2.5-flash-lite': {'input': 0.10, 'output': 0.40, 'thinking': 0}, 'gemini-2.5-pro': {'input': 1.25, 'output': 10.00, 'thinking': 0}, 'gemini-2.0-flash': {'input': 0.10, 'output': 0.40, 'thinking': 0}, - 'gemini-3-flash-preview': {'input': 0.50, 'output': 3.00, 'thinking': 1.00}, - 'gemini-3-pro-preview': {'input': 2.00, 'output': 12.00, 'thinking': 4.00}, + 'gemini-3-flash-preview': {'input': 0.00, 'output': 0.00, 'thinking': 0.00}, # Free tier! + 'gemini-3-pro-preview': {'input': 2.00, 'output': 12.00, 'thinking': 4.00}, # Paid tier } @@ -82,12 +83,24 @@ class GeminiService: Initialize Gemini service. Args: - api_key: Google AI API key (reads from GOOGLE_GEMINI_API_KEY env if not provided) + api_key: Google AI API key (reads from env if not provided) model: Model to use ('flash', 'flash-lite', 'pro', '3-flash', '3-pro') thinking_level: Reasoning depth ('minimal', 'low', 'medium', 'high') include_thoughts: Whether to include thinking process in response (for debugging) + + API Keys (auto-selected by model): + - GOOGLE_GEMINI_API_KEY_FREE: Free tier for Flash models (no cost) + - GOOGLE_GEMINI_API_KEY: Paid tier for Pro models """ - self.api_key = api_key or os.getenv('GOOGLE_GEMINI_API_KEY') + # Auto-select API key based on model (Free tier for Flash, Paid for Pro) + if api_key: + self.api_key = api_key + elif model in ('3-pro', 'pro'): + # Pro models use paid tier + self.api_key = os.getenv('GOOGLE_GEMINI_API_KEY') + else: + # Flash models prefer free tier, fallback to paid + self.api_key = os.getenv('GOOGLE_GEMINI_API_KEY_FREE') or os.getenv('GOOGLE_GEMINI_API_KEY') # Debug: Log API key (masked) if self.api_key: diff --git a/templates/chat.html b/templates/chat.html index 77d1c3b..7e5d276 100755 --- a/templates/chat.html +++ b/templates/chat.html @@ -733,6 +733,16 @@ background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); } + .thinking-option-badge.free { + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + } + + .thinking-option-price.free { + color: #10b981; + font-weight: 500; + font-style: normal; + } + .thinking-option-price { display: block; font-size: 11px; @@ -1247,10 +1257,10 @@
Gemini Flash - Domyślny + Darmowy
-

Szybki i ekonomiczny. Dla prostych pytań o firmy, kontakty, wydarzenia.

- ~$0.05/pytanie +

Szybki i skuteczny. Dla większości pytań o firmy, kontakty, wydarzenia.

+ Bez opłat
@@ -1258,8 +1268,8 @@ Gemini Pro Premium
-

Głęboka analiza. Dla złożonych pytań, strategii, rekomendacji.

- ~$0.20/pytanie +

Głęboka analiza i rozumowanie. Dla złożonych pytań, strategii, rekomendacji.

+ ~$0.20/pytanie · limit: $2/dzień