import random from django.conf import settings from django.db import models from django.utils import timezone from .username_utils import build_unique_username class NameVocab(models.Model): """Eğitim ve üretim için isim/soyisim sözlüğü. Türkçe kökenli isimler önceliklidir.""" ORIGIN_CHOICES = [ ('turkce', 'Türkçe'), # Birinci öncelik ('bati', 'Batı'), ('diger', 'Diğer'), ('arapca', 'Arapça'), # Son öncelik ] NAME_TYPE_CHOICES = [ ('first', 'İsim'), ('last', 'Soyisim'), ] GENDER_CHOICES = [ ('E', 'Erkek'), ('K', 'Kadın'), ('U', 'Unisex'), ] name = models.CharField(max_length=100, help_text='İsim veya soyisim') name_type = models.CharField(max_length=5, choices=NAME_TYPE_CHOICES) gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='U') origin = models.CharField( max_length=10, choices=ORIGIN_CHOICES, default='turkce', help_text='Türkçe kökenli isimler varsayılan ve önceliklidir', ) frequency = models.PositiveIntegerField( default=1, help_text='Veri setindeki görülme sıklığı — ağırlıklı seçimde kullanılır' ) class Meta: ordering = ['origin', '-frequency', 'name'] verbose_name = 'İsim Sözlüğü' verbose_name_plural = 'İsim Sözlüğü' unique_together = [('name', 'name_type', 'gender')] def __str__(self): return f"{self.name} ({self.get_name_type_display()}, {self.get_gender_display()}, {self.get_origin_display()})" class GeneratedPerson(models.Model): """Modelin ürettiği kişi kaydı.""" GENDER_CHOICES = [ ('E', 'Erkek'), ('K', 'Kadın'), ] training_job = models.ForeignKey( 'TrainingJob', on_delete=models.SET_NULL, null=True, blank=True, related_name='generated_persons', help_text='Bu kişiyi üreten model versiyonu', ) first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) username = models.CharField(max_length=150, blank=True, db_index=True) username_locked = models.BooleanField( default=False, help_text='Aciksa username yeniden uretilmez (force ile degistirilebilir).' ) birth_date = models.DateField() gender = models.CharField(max_length=1, choices=GENDER_CHOICES) confidence = models.FloatField( null=True, blank=True, help_text='Modelin seçim güven skoru (0-1)' ) generated_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-generated_at'] verbose_name = 'Üretilen Kişi' verbose_name_plural = 'Üretilen Kişiler' def __str__(self): return f"{self.first_name} {self.last_name} ({self.birth_date})" def regenerate_username(self, used_usernames=None, force=False, save=True): """Kayit icin yeni bir username uretir. Mevcut username her zaman degisir.""" if self.username_locked and not force: return self.username if used_usernames is None: used_usernames = set( GeneratedPerson.objects.exclude(pk=self.pk).exclude(username='').values_list('username', flat=True) ) # Mevcut username'i yasak listesine ekle ve rastgele sonek ile basla # Boylece ayni base'e hic donulmez (ping-pong olmaz) if self.username: used_usernames.add(self.username) suffix_min = getattr(settings, 'USERNAME_SUFFIX_MIN', 2) suffix_max = getattr(settings, 'USERNAME_SUFFIX_MAX', 999) self.username = build_unique_username( self.first_name, self.last_name, self.birth_date, used_usernames, _force_suffix=random.randint(suffix_min, suffix_max), ) if save: self.save(update_fields=['username']) return self.username class TrainingJob(models.Model): """Makine öğrenme model eğitim görevinin kaydı.""" STATUS_CHOICES = [ ('pending', 'Beklemede'), ('running', 'Eğitiliyor'), ('completed', 'Tamamlandı'), ('failed', 'Başarısız'), ] # Temel bilgiler task_id = models.CharField(max_length=255, unique=True, help_text='Celery task ID') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') created_at = models.DateTimeField(auto_now_add=True) started_at = models.DateTimeField(null=True, blank=True) completed_at = models.DateTimeField(null=True, blank=True) # Model bilgileri model_type = models.CharField(max_length=100, default='RandomForest') model_version = models.DateTimeField(default=timezone.now, help_text='Model versiyonu (timestamp)') model_path = models.CharField(max_length=500, null=True, blank=True) # Eğitim verisi features = models.JSONField( null=True, blank=True, help_text='2D liste: her satır bir örnek, her sütun bir özellik' ) labels = models.JSONField( null=True, blank=True, help_text='1D liste: her örneğin sınıf etiketi' ) feature_count = models.PositiveIntegerField( null=True, blank=True, help_text='Özellik (sütun) sayısı — ONNX tipi için kullanılır' ) sample_count = models.PositiveIntegerField( null=True, blank=True, help_text='Eğitim verisi satır sayısı' ) # Metrikler accuracy = models.FloatField(null=True, blank=True) precision = models.FloatField(null=True, blank=True) recall = models.FloatField(null=True, blank=True) f1_score = models.FloatField(null=True, blank=True) # Hata handling error_message = models.TextField(null=True, blank=True) # Go servisine sinyal go_service_notified = models.BooleanField(default=False) class Meta: ordering = ['-created_at'] verbose_name = 'Eğitim Görevi' verbose_name_plural = 'Eğitim Görevleri' def __str__(self): return f"{self.model_type} - {self.status} - {self.created_at}"