first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:26:46 +03:00
commit 2be3a313ad
55 changed files with 3609 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
"""
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ş"
)