Skip to content

Commit 91ce088

Browse files
committed
add get_llm_provider_model for free tier
1 parent 10a1f34 commit 91ce088

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.2.1 on 2025-06-14 03:39
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('curation', '0010_llmservice_llmusage'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='llmusage',
15+
name='date',
16+
field=models.DateTimeField(auto_now_add=True, help_text='사용 날짜'),
17+
),
18+
]

pythonkr_backend/curation/models.py

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
from .utils import get_summary_from_url, translate_to_korean, categorize_summary
44
import readtime
55
import os
6-
from datetime import timedelta
6+
from datetime import timedelta, datetime
7+
from django.utils import timezone
8+
import pytz
79

810

911
def rss_item_upload_path(instance, filename):
@@ -434,14 +436,148 @@ class LLMService(models.Model):
434436
def __str__(self):
435437
return f"{self.get_provider_display()} (Priority: {self.priority})"
436438

439+
@classmethod
440+
def get_llm_provider_model(cls):
441+
"""
442+
Calculate today's usage and return available provider and model based on priority.
443+
Returns tuple: (provider, model_name) or (None, None) if no models available.
444+
"""
445+
# Model configurations with daily limits
446+
MODEL_CONFIGS = {
447+
'google-gla:gemini-2.5-pro-preview-06-05': {
448+
'daily_requests': 25,
449+
'rpm': 5,
450+
'tpm': 250000,
451+
'daily_tokens': 1000000,
452+
'provider': 'gemini'
453+
},
454+
'google-gla:gemini-2.5-flash-preview-05-20': {
455+
'daily_requests': 500,
456+
'rpm': 10,
457+
'tpm': 250000,
458+
'daily_tokens': None, # Not specified
459+
'provider': 'gemini'
460+
},
461+
'openai:gpt-4.5-preview-2025-02-27': {
462+
'daily_tokens': 250000, # Combined with gpt-4.1-2025-04-14
463+
'provider': 'openai',
464+
'combined_with': ['openai:gpt-4.1-2025-04-14']
465+
},
466+
'openai:gpt-4.1-2025-04-14': {
467+
'daily_tokens': 250000, # Combined with gpt-4.5-preview-2025-02-27
468+
'provider': 'openai',
469+
'combined_with': ['openai:gpt-4.5-preview-2025-02-27']
470+
},
471+
'openai:gpt-4.1-mini-2025-04-14': {
472+
'daily_tokens': 2500000,
473+
'provider': 'openai'
474+
},
475+
'anthropic:claude-3-5-haiku-latest': {
476+
'provider': 'claude'
477+
},
478+
'anthropic:claude-sonnet-4-0': {
479+
'provider': 'claude'
480+
}
481+
}
482+
483+
# Get active services ordered by priority
484+
active_services = cls.objects.filter(is_active=True).order_by('priority')
485+
486+
for service in active_services:
487+
available_models = cls._get_available_models_for_provider(service.provider, MODEL_CONFIGS)
488+
if available_models:
489+
return service.provider, available_models[0]
490+
491+
return None, None
492+
493+
@classmethod
494+
def _get_available_models_for_provider(cls, provider, model_configs):
495+
"""Get available models for a specific provider based on usage limits."""
496+
available_models = []
497+
498+
if provider == 'gemini':
499+
# Check Google Gemini models with Pacific Time reset
500+
pacific_tz = pytz.timezone('US/Pacific')
501+
now_pacific = timezone.now().astimezone(pacific_tz)
502+
start_of_day_pacific = now_pacific.replace(hour=0, minute=0, second=0, microsecond=0)
503+
start_of_day_utc = start_of_day_pacific.astimezone(pytz.UTC)
504+
505+
for model_key, config in model_configs.items():
506+
if not model_key.startswith('google-gla:'):
507+
continue
508+
509+
model_name = model_key.split(':', 1)[1]
510+
today_usage = LLMUsage.objects.filter(
511+
model_name=model_key,
512+
date__gte=start_of_day_utc
513+
).aggregate(
514+
total_tokens=models.Sum(models.F('input_tokens') + models.F('output_tokens')),
515+
total_requests=models.Count('id')
516+
)
517+
518+
total_tokens = today_usage['total_tokens'] or 0
519+
total_requests = today_usage['total_requests'] or 0
520+
521+
# Check daily limits
522+
if config.get('daily_requests') and total_requests >= config['daily_requests']:
523+
continue
524+
if config.get('daily_tokens') and total_tokens >= config['daily_tokens']:
525+
continue
526+
527+
available_models.append(model_name)
528+
529+
elif provider == 'openai':
530+
# Check OpenAI models with UTC midnight reset
531+
today_start = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
532+
533+
# Handle combined quota models (gpt-4.5 and gpt-4.1)
534+
combined_models = ['openai:gpt-4.5-preview-2025-02-27', 'openai:gpt-4.1-2025-04-14']
535+
combined_usage = LLMUsage.objects.filter(
536+
model_name__in=combined_models,
537+
date__gte=today_start
538+
).aggregate(
539+
total_tokens=models.Sum(models.F('input_tokens') + models.F('output_tokens'))
540+
)
541+
combined_tokens = combined_usage['total_tokens'] or 0
542+
543+
# Check individual models
544+
for model_key, config in model_configs.items():
545+
if not model_key.startswith('openai:'):
546+
continue
547+
548+
model_name = model_key.split(':', 1)[1]
549+
550+
if model_key in combined_models:
551+
# Check combined quota
552+
if combined_tokens < 250000:
553+
available_models.append(model_name)
554+
else:
555+
# Check individual quota (gpt-4.1-mini)
556+
today_usage = LLMUsage.objects.filter(
557+
model_name=model_key,
558+
date__gte=today_start
559+
).aggregate(
560+
total_tokens=models.Sum(models.F('input_tokens') + models.F('output_tokens'))
561+
)
562+
total_tokens = today_usage['total_tokens'] or 0
563+
564+
if total_tokens < config['daily_tokens']:
565+
available_models.append(model_name)
566+
567+
elif provider == 'claude':
568+
# Claude as fallback - assume always available
569+
available_models = ['claude-sonnet-4-0']
570+
571+
return available_models
572+
437573
class Meta:
438574
verbose_name = "LLM Service"
439575
verbose_name_plural = "LLM Services"
440576
ordering = ['priority']
441577

442578

443579
class LLMUsage(models.Model):
444-
date = models.DateField(
580+
date = models.DateTimeField(
445581
auto_now_add=True,
446582
help_text="사용 날짜"
447583
)

0 commit comments

Comments
 (0)