Skip to content

Commit bd1d42d

Browse files
committed
add llmservice, llmusage
1 parent 919f5de commit bd1d42d

File tree

4 files changed

+151
-14
lines changed

4 files changed

+151
-14
lines changed

pythonkr_backend/curation/admin.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.contrib import admin, messages
2-
from .models import Article, Category, RSSFeed, RSSItem # Or combine imports
2+
from .models import Article, Category, RSSFeed, RSSItem, LLMService, LLMUsage
33

44

55
@admin.register(Category)
@@ -166,3 +166,50 @@ class RSSItemAdmin(admin.ModelAdmin):
166166

167167
def get_queryset(self, request):
168168
return super().get_queryset(request).select_related('feed')
169+
170+
171+
@admin.register(LLMService)
172+
class LLMServiceAdmin(admin.ModelAdmin):
173+
list_display = ('provider', 'priority', 'is_active', 'updated_at', 'created_at')
174+
list_filter = ('is_active', 'provider', 'created_at')
175+
search_fields = ('provider',)
176+
readonly_fields = ('created_at', 'updated_at')
177+
178+
fieldsets = (
179+
('Service Configuration', {
180+
'fields': ('provider', 'priority', 'is_active')
181+
}),
182+
('Metadata', {
183+
'fields': ('created_at', 'updated_at'),
184+
'classes': ('collapse',)
185+
}),
186+
)
187+
188+
189+
@admin.register(LLMUsage)
190+
class LLMUsageAdmin(admin.ModelAdmin):
191+
list_display = ('model_name', 'date', 'input_tokens', 'output_tokens', 'total_tokens', 'created_at')
192+
list_filter = ('date', 'model_name', 'created_at')
193+
search_fields = ('model_name',)
194+
readonly_fields = ('date', 'created_at')
195+
date_hierarchy = 'date'
196+
197+
fieldsets = (
198+
('Usage Information', {
199+
'fields': ('model_name', 'date', 'input_tokens', 'output_tokens')
200+
}),
201+
('Metadata', {
202+
'fields': ('created_at',),
203+
'classes': ('collapse',)
204+
}),
205+
)
206+
207+
@admin.display(description='Total Tokens')
208+
def total_tokens(self, obj):
209+
return obj.input_tokens + obj.output_tokens
210+
211+
def has_add_permission(self, request):
212+
return False
213+
214+
def has_change_permission(self, request, obj=None):
215+
return False
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Generated by Django 5.2.1 on 2025-06-13 05:53
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('curation', '0009_rssitem_crawled_at_rssitem_error_message'),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name='LLMService',
15+
fields=[
16+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17+
('provider', models.CharField(choices=[('openai', 'OpenAI'), ('claude', 'Claude'), ('gemini', 'Gemini')], help_text='LLM 서비스 제공자', max_length=20, unique=True)),
18+
('priority', models.PositiveIntegerField(help_text='우선순위 (1이 가장 높음)')),
19+
('is_active', models.BooleanField(default=True, help_text='서비스 활성화 여부')),
20+
('created_at', models.DateTimeField(auto_now_add=True)),
21+
('updated_at', models.DateTimeField(auto_now=True)),
22+
],
23+
options={
24+
'verbose_name': 'LLM Service',
25+
'verbose_name_plural': 'LLM Services',
26+
'ordering': ['priority'],
27+
},
28+
),
29+
migrations.CreateModel(
30+
name='LLMUsage',
31+
fields=[
32+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
33+
('date', models.DateField(auto_now_add=True, help_text='사용 날짜')),
34+
('model_name', models.CharField(help_text='사용된 모델명', max_length=100)),
35+
('input_tokens', models.PositiveIntegerField(help_text='입력 토큰 수')),
36+
('output_tokens', models.PositiveIntegerField(help_text='출력 토큰 수')),
37+
('created_at', models.DateTimeField(auto_now_add=True)),
38+
],
39+
options={
40+
'verbose_name': 'LLM Usage',
41+
'verbose_name_plural': 'LLM Usage',
42+
'ordering': ['-date', '-created_at'],
43+
},
44+
),
45+
]

pythonkr_backend/curation/models.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,61 @@ class CrawledContent(models.Model):
406406

407407
def __str__(self):
408408
return self.title or self.crawl_url.url
409+
410+
411+
class LLMService(models.Model):
412+
LLM_PROVIDER_CHOICES = [
413+
('openai', 'OpenAI'),
414+
('claude', 'Claude'),
415+
('gemini', 'Gemini'),
416+
]
417+
418+
provider = models.CharField(
419+
max_length=20,
420+
choices=LLM_PROVIDER_CHOICES,
421+
unique=True,
422+
help_text="LLM 서비스 제공자"
423+
)
424+
priority = models.PositiveIntegerField(
425+
help_text="우선순위 (1이 가장 높음)"
426+
)
427+
is_active = models.BooleanField(
428+
default=True,
429+
help_text="서비스 활성화 여부"
430+
)
431+
created_at = models.DateTimeField(auto_now_add=True)
432+
updated_at = models.DateTimeField(auto_now=True)
433+
434+
def __str__(self):
435+
return f"{self.get_provider_display()} (Priority: {self.priority})"
436+
437+
class Meta:
438+
verbose_name = "LLM Service"
439+
verbose_name_plural = "LLM Services"
440+
ordering = ['priority']
441+
442+
443+
class LLMUsage(models.Model):
444+
date = models.DateField(
445+
auto_now_add=True,
446+
help_text="사용 날짜"
447+
)
448+
model_name = models.CharField(
449+
max_length=100,
450+
help_text="사용된 모델명"
451+
)
452+
input_tokens = models.PositiveIntegerField(
453+
help_text="입력 토큰 수"
454+
)
455+
output_tokens = models.PositiveIntegerField(
456+
help_text="출력 토큰 수"
457+
)
458+
created_at = models.DateTimeField(auto_now_add=True)
459+
460+
def __str__(self):
461+
return f"{self.model_name} - {self.date} (In: {self.input_tokens}, Out: {self.output_tokens})"
462+
463+
class Meta:
464+
verbose_name = "LLM Usage"
465+
verbose_name_plural = "LLM Usage"
466+
ordering = ['-date', '-created_at']

pythonkr_backend/curation/tasks.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import logfire
2-
from celery import Celery
3-
from celery.signals import worker_init, beat_init
42

53
from celery import shared_task
64
import feedparser
@@ -13,17 +11,6 @@
1311

1412
logger = logging.getLogger(__name__)
1513

16-
17-
@worker_init.connect()
18-
def init_worker(*args, **kwargs):
19-
logfire.configure(service_name="worker")
20-
logfire.instrument_celery()
21-
22-
@beat_init.connect()
23-
def init_beat(*args, **kwargs):
24-
logfire.configure(service_name="beat")
25-
logfire.instrument_celery()
26-
2714
def crawl_all_rss_feeds():
2815
"""모든 활성화된 RSS 피드를 크롤링합니다."""
2916
active_feeds = RSSFeed.objects.filter(is_active=True)

0 commit comments

Comments
 (0)