import io from django.contrib import admin from django.contrib import messages from django.core.management import call_command from django.http import HttpResponseRedirect from django.urls import path, reverse from django.utils.html import format_html from .models import TrainingJob, NameVocab, GeneratedPerson class GeneratedPersonInline(admin.TabularInline): model = GeneratedPerson extra = 0 fields = ( 'first_name', 'last_name', 'username', 'username_locked', 'birth_date', 'gender', 'confidence', 'generated_at' ) readonly_fields = ( 'first_name', 'last_name', 'username', 'username_locked', 'birth_date', 'gender', 'confidence', 'generated_at' ) can_delete = False show_change_link = True @admin.register(TrainingJob) class TrainingJobAdmin(admin.ModelAdmin): list_display = ( 'id', 'task_id', 'status', 'model_type', 'model_file_exists', 'generated_person_count', 'accuracy', 'created_at', 'completed_at', ) list_filter = ('status', 'model_type', 'created_at') search_fields = ('task_id', 'error_message') readonly_fields = ( 'task_id', 'created_at', 'started_at', 'completed_at', 'model_version', 'model_file_exists', 'generated_person_count', ) actions = ( 'generate_100_statistical_action', 'generate_100_llm_action', 'generate_1000_statistical_action', 'generate_1000_llm_action', ) inlines = (GeneratedPersonInline,) fieldsets = ( ('Görev Bilgisi', { 'fields': ('task_id', 'status', 'created_at', 'started_at', 'completed_at') }), ('Model', { 'fields': ('model_type', 'model_version', 'model_path', 'model_file_exists') }), ('Uretilen Kayitlar', { 'fields': ('generated_person_count',) }), ('Metrikler', { 'fields': ('accuracy', 'precision', 'recall', 'f1_score') }), ('Go Servisi', { 'fields': ('go_service_notified',) }), ('Hata', { 'fields': ('error_message',), 'classes': ('collapse',) }), ) def model_file_exists(self, obj): return bool(obj.model_path and __import__('os').path.exists(obj.model_path)) model_file_exists.boolean = True model_file_exists.short_description = 'Model dosyasi var' def generated_person_count(self, obj): return obj.generated_persons.count() generated_person_count.short_description = 'Uretilen kisi sayisi' def _run_generate_persons(self, request, queryset, count, use_llm): total_jobs = queryset.count() ok_jobs = 0 for job in queryset: try: out = io.StringIO() kwargs = { 'count': count, 'job_id': job.pk, 'stdout': out, } if use_llm: kwargs['use_llm'] = True else: kwargs['no_llm'] = True call_command('generate_persons', **kwargs) ok_jobs += 1 except Exception as exc: self.message_user( request, f'Job id={job.pk} icin uretim hatasi: {exc}', level=messages.ERROR, ) mode = 'LLM (fallback ile)' if use_llm else 'Istatistiksel' self.message_user( request, f'Uretim tamamlandi. Mod: {mode}. Basarili job: {ok_jobs}/{total_jobs}. Her job icin {count} kayit.', level=messages.SUCCESS, ) @admin.action(description='Secili job(lar) icin 100 kisi uret (Istatistiksel)') def generate_100_statistical_action(self, request, queryset): self._run_generate_persons(request, queryset, count=100, use_llm=False) @admin.action(description='Secili job(lar) icin 100 kisi uret (LLM + fallback)') def generate_100_llm_action(self, request, queryset): self._run_generate_persons(request, queryset, count=100, use_llm=True) @admin.action(description='Secili job(lar) icin 1000 kisi uret (Istatistiksel)') def generate_1000_statistical_action(self, request, queryset): self._run_generate_persons(request, queryset, count=1000, use_llm=False) @admin.action(description='Secili job(lar) icin 1000 kisi uret (LLM + fallback)') def generate_1000_llm_action(self, request, queryset): self._run_generate_persons(request, queryset, count=1000, use_llm=True) @admin.register(NameVocab) class NameVocabAdmin(admin.ModelAdmin): list_display = ('name', 'name_type', 'gender', 'origin', 'frequency') list_filter = ('origin', 'name_type', 'gender') search_fields = ('name',) ordering = ('origin', '-frequency') @admin.register(GeneratedPerson) class GeneratedPersonAdmin(admin.ModelAdmin): list_display = ( 'first_name', 'last_name', 'username', 'username_locked', 'birth_date', 'gender', 'confidence', 'generated_at', 'username_ops' ) list_filter = ('gender', 'username_locked', 'generated_at') search_fields = ('first_name', 'last_name', 'username') readonly_fields = ('generated_at',) actions = ('regenerate_username_action', 'lock_username_action', 'unlock_username_action') def get_urls(self): urls = super().get_urls() custom_urls = [ path( '/regenerate-username/', self.admin_site.admin_view(self.regenerate_username_view), name='namecreate_generatedperson_regenerate_username', ), path( '/toggle-username-lock/', self.admin_site.admin_view(self.toggle_username_lock_view), name='namecreate_generatedperson_toggle_username_lock', ), ] return custom_urls + urls def regenerate_username_view(self, request, person_id): person = self.get_object(request, person_id) if person is None: self.message_user(request, 'Kayit bulunamadi.', level=messages.ERROR) return HttpResponseRedirect('../') if person.username_locked: self.message_user(request, 'Username kilitli. Once kilidi acin.', level=messages.WARNING) return HttpResponseRedirect('../../') old_username = person.username person.regenerate_username(save=True) self.message_user( request, f'Username guncellendi: {old_username} -> {person.username}', level=messages.SUCCESS, ) return HttpResponseRedirect('../../') def toggle_username_lock_view(self, request, person_id): person = self.get_object(request, person_id) if person is None: self.message_user(request, 'Kayit bulunamadi.', level=messages.ERROR) return HttpResponseRedirect('../') person.username_locked = not person.username_locked person.save(update_fields=['username_locked']) state = 'kilitlendi' if person.username_locked else 'kilidi acildi' self.message_user(request, f'Username {state}.', level=messages.SUCCESS) return HttpResponseRedirect('../../') def username_ops(self, obj): regen_url = reverse('admin:namecreate_generatedperson_regenerate_username', args=[obj.pk]) lock_url = reverse('admin:namecreate_generatedperson_toggle_username_lock', args=[obj.pk]) lock_label = 'Kilidi ac' if obj.username_locked else 'Kilitle' return format_html( 'Yeniden uret ' '{}', regen_url, lock_url, lock_label, ) username_ops.short_description = 'Islemler' @admin.action(description='Secili kayitlarda username yeniden uret') def regenerate_username_action(self, request, queryset): used_usernames = set( GeneratedPerson.objects.exclude(username='').values_list('username', flat=True) ) updated = 0 skipped = 0 for person in queryset: if person.username_locked: skipped += 1 continue used_usernames.discard(person.username) person.regenerate_username(used_usernames=used_usernames, force=True, save=True) updated += 1 self.message_user( request, f'{updated} kayitta username yeniden uretildi. Kilitli oldugu icin atlanan: {skipped}.' ) @admin.action(description='Secili kayitlarda username kilitle') def lock_username_action(self, request, queryset): count = queryset.update(username_locked=True) self.message_user(request, f'{count} kayitta username kilitlendi.') @admin.action(description='Secili kayitlarda username kilidini ac') def unlock_username_action(self, request, queryset): count = queryset.update(username_locked=False) self.message_user(request, f'{count} kayitta username kilidi acildi.')