""" NameVocab tablosundan ağırlıklı örneklemeyle kişi verisi üretir. - Doğum tarihi: 20 yaş ve üstü (bugüne göre) - Türkçe isimler frekans ağırlıklı olarak önce gelir - Üretilen kayıtlar GeneratedPerson tablosuna kaydedilir Kullanım: python manage.py generate_persons # 1000 kişi python manage.py generate_persons --count 500 # 500 kişi python manage.py generate_persons --clear # önce tabloyu temizle """ import random import calendar from datetime import date from django.core.management.base import BaseCommand, CommandError from namecreate.models import NameVocab, GeneratedPerson, TrainingJob from namecreate.username_utils import build_unique_username from namecreate.llm_generator import generate_people_with_llm # Bugün: 27 Mart 2026 — 20 yaş ve üstü → en geç 27 Mart 2006 doğum MAX_BIRTH_YEAR = date.today().year - 20 # 2006 MIN_BIRTH_YEAR = 1940 def _weighted_pick(queryset): """Frequency değerlerine göre ağırlıklı rastgele seçim.""" names = list(queryset.values_list('name', 'frequency')) if not names: raise CommandError("NameVocab tablosu boş. Önce 'seed_name_vocab' komutunu çalıştırın.") population = [n for n, _ in names] weights = [f for _, f in names] return random.choices(population, weights=weights, k=1)[0] def _random_birth_date(): """20 yaş ve üstü rastgele doğum tarihi üretir.""" year = random.randint(MIN_BIRTH_YEAR, MAX_BIRTH_YEAR) month = random.randint(1, 12) # Ayın son gününü doğru hesapla (şubat, 30/31 gün farkları) _, max_day = calendar.monthrange(year, month) # 2006 doğumsa mart ayı sonrasında doğanlar henüz 20 yaşında değil if year == MAX_BIRTH_YEAR: today = date.today() if month > today.month: month = random.randint(1, today.month) if month == today.month: _, max_day = calendar.monthrange(year, month) max_day = min(max_day, today.day) _, max_day = calendar.monthrange(year, month) day = random.randint(1, max_day) return date(year, month, day) class Command(BaseCommand): help = '1000 kişilik sahte isim/soyisim/doğum tarihi verisi üretir (20 yaş ve üstü)' def add_arguments(self, parser): parser.add_argument( '--count', type=int, default=1000, help='Üretilecek kişi sayısı (varsayılan: 1000)' ) parser.add_argument( '--clear', action='store_true', help='Üretmeden önce mevcut GeneratedPerson kayıtlarını sil' ) parser.add_argument( '--job-id', type=int, default=None, help='Bağlanacak TrainingJob ID (belirtilmezse en son tamamlanmış iş kullanılır)' ) parser.add_argument( '--use-llm', action='store_true', help='Uretimi LLM ile yapmayi dener; basarisiz olursa istatistiksel fallback yapar.' ) parser.add_argument( '--no-llm', action='store_true', help='LLM denemeyi kapatir, dogrudan istatistiksel uretim yapar.' ) parser.add_argument( '--llm-strict', action='store_true', help='LLM basarisiz olursa fallback yapma, komutu hata ile sonlandir.' ) def handle(self, *args, **options): count = options['count'] if options['clear']: deleted, _ = GeneratedPerson.objects.all().delete() self.stdout.write(self.style.WARNING(f'{deleted} eski kayıt silindi.')) # TrainingJob bağlantısını belirle job_id = options.get('job_id') if job_id: try: training_job = TrainingJob.objects.get(pk=job_id) except TrainingJob.DoesNotExist: raise CommandError(f'TrainingJob id={job_id} bulunamadı.') else: training_job = TrainingJob.objects.filter(status='completed').exclude( model_path=None ).order_by('-completed_at').first() if training_job is None: self.stdout.write(self.style.WARNING( 'Tamamlanmış (model dosyalı) TrainingJob bulunamadı. training_job=None olarak üretilecek.' )) else: self.stdout.write(f'TrainingJob kullanılıyor: id={training_job.pk} ({training_job.model_type})') # Erkek / kadın isimlerini bir kez çek male_first = NameVocab.objects.filter(name_type='first', gender='E') female_first = NameVocab.objects.filter(name_type='first', gender='K') last_names = NameVocab.objects.filter(name_type='last') if not male_first.exists() or not female_first.exists() or not last_names.exists(): raise CommandError( "NameVocab tablosu eksik. Önce 'python manage.py seed_name_vocab' komutunu çalıştırın." ) # Tüm ağırlıklı listeleri RAM'e al (1000 kayıt için yeterli) male_pool = list(male_first.values_list('name', 'frequency')) female_pool = list(female_first.values_list('name', 'frequency')) last_pool = list(last_names.values_list('name', 'frequency')) def pick(pool): names, weights = zip(*pool) return random.choices(names, weights=weights, k=1)[0] used_usernames = set(GeneratedPerson.objects.values_list('username', flat=True).exclude(username='')) persons = [] source = 'statistical' llm_rows = None use_llm = options.get('use_llm') or not options.get('no_llm') if use_llm: try: llm_rows = generate_people_with_llm(count=count, min_age=20) source = 'llm' except Exception as e: if options.get('llm_strict'): raise CommandError(f'LLM uretimi basarisiz: {e}') self.stdout.write(self.style.WARNING( f'LLM uretimi basarisiz ({e}). Istatistiksel fallback kullaniliyor.' )) if llm_rows: for row in llm_rows[:count]: first = row['first_name'] last = row['last_name'] gender = row['gender'] birth = row['birth_date'] username = build_unique_username(first, last, birth, used_usernames) persons.append(GeneratedPerson( first_name=first, last_name=last.upper(), username=username, birth_date=birth, gender=gender, confidence=None, training_job=training_job, )) missing = count - len(persons) for _ in range(missing): gender = random.choice(['E', 'K']) first = pick(male_pool if gender == 'E' else female_pool) last = pick(last_pool) birth = _random_birth_date() username = build_unique_username(first, last, birth, used_usernames) persons.append(GeneratedPerson( first_name=first, last_name=last.upper(), # soyisim büyük harf username=username, birth_date=birth, gender=gender, confidence=None, training_job=training_job, )) GeneratedPerson.objects.bulk_create(persons) self.stdout.write(self.style.SUCCESS( f'\n{count} kişi başarıyla üretildi ve kaydedildi.' )) self.stdout.write(f' Kaynak: {source}') self.stdout.write( f" Erkek: {sum(1 for p in persons if p.gender == 'E')} | " f"Kadın: {sum(1 for p in persons if p.gender == 'K')}" ) self.stdout.write( f" Doğum aralığı: {MIN_BIRTH_YEAR} – {MAX_BIRTH_YEAR} (20 yaş ve üstü)" ) # Örnek 5 kayıt göster self.stdout.write('\nİlk 5 örnek:') for p in persons[:5]: age = date.today().year - p.birth_date.year - ( (date.today().month, date.today().day) < (p.birth_date.month, p.birth_date.day) ) self.stdout.write( f" {p.first_name} {p.last_name} (@{p.username}) | {p.birth_date} | " f"{p.get_gender_display()} | {age} yaş" )