first commit
This commit is contained in:
0
namecreate/management/__init__.py
Normal file
0
namecreate/management/__init__.py
Normal file
0
namecreate/management/commands/__init__.py
Normal file
0
namecreate/management/commands/__init__.py
Normal file
204
namecreate/management/commands/generate_persons.py
Normal file
204
namecreate/management/commands/generate_persons.py
Normal 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ş"
|
||||
)
|
||||
125
namecreate/management/commands/seed_name_vocab.py
Normal file
125
namecreate/management/commands/seed_name_vocab.py
Normal file
@@ -0,0 +1,125 @@
|
||||
"""
|
||||
Türkçe kökenli isimler öncelikli olarak NameVocab tablosunu doldurur.
|
||||
Kullanım: python manage.py seed_name_vocab
|
||||
"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from namecreate.models import NameVocab
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Türkçe kökenli isimler — en yüksek öncelik
|
||||
# -----------------------------------------------------------------------
|
||||
TURKCE_ERKEK = [
|
||||
("Alp", 80), ("Alpay", 60), ("Alperen", 100), ("Altan", 70),
|
||||
("Aydın", 90), ("Baran", 85), ("Barış", 120), ("Batuhan", 95),
|
||||
("Berk", 75), ("Berkay", 80), ("Burak", 140), ("Çağan", 50),
|
||||
("Çağrı", 65), ("Deniz", 110), ("Doğan", 70), ("Doruk", 55),
|
||||
("Emre", 160), ("Enes", 90), ("Eren", 130), ("Erhan", 75),
|
||||
("Furkan", 85), ("Görkem", 60), ("Güven", 45), ("Haluk", 50),
|
||||
("İlker", 70), ("Kaan", 95), ("Kadir", 80), ("Kerem", 100),
|
||||
("Koral", 45), ("Korhan", 50), ("Mert", 130), ("Oğuz", 75),
|
||||
("Onur", 90), ("Orkun", 55), ("Selim", 85), ("Sercan", 70),
|
||||
("Serdar", 80), ("Soner", 65), ("Tarık", 75), ("Tuna", 50),
|
||||
("Tunahan", 60), ("Uğur", 85), ("Umut", 100), ("Ufuk", 55),
|
||||
("Volkan", 80), ("Yiğit", 90), ("Yunus", 95), ("Zafer", 60),
|
||||
]
|
||||
|
||||
TURKCE_KADIN = [
|
||||
("Aslı", 110), ("Aylin", 100), ("Aynur", 75), ("Ayşen", 65),
|
||||
("Banu", 70), ("Bahar", 90), ("Başak", 80), ("Belgin", 55),
|
||||
("Bengü", 50), ("Berrak", 60), ("Burcu", 95), ("Büşra", 85),
|
||||
("Cansu", 100), ("Ceren", 120), ("Çiğdem", 80), ("Deniz", 90),
|
||||
("Ebru", 95), ("Elçin", 65), ("Elif", 150), ("Esra", 110),
|
||||
("Ezgi", 100), ("Gizem", 90), ("Gül", 75), ("Gülşen", 55),
|
||||
("Güneş", 50), ("Hande", 85), ("İlayda", 75), ("İpek", 80),
|
||||
("Melike", 90), ("Meltem", 95), ("Merve", 130), ("Nilay", 80),
|
||||
("Nur", 70), ("Özge", 100), ("Pınar", 90), ("Seda", 85),
|
||||
("Selin", 100), ("Sibel", 80), ("Simge", 75), ("Tuğba", 85),
|
||||
("Tülay", 60), ("Ülkü", 50), ("Yasemin", 110), ("Zeynep", 120),
|
||||
("Zümra", 55),
|
||||
]
|
||||
|
||||
# Türkçe soyisimler
|
||||
TURKCE_SOYISIM = [
|
||||
("Yılmaz", 200), ("Kaya", 180), ("Demir", 170), ("Çelik", 150),
|
||||
("Şahin", 140), ("Yıldız", 130), ("Arslan", 120), ("Doğan", 115),
|
||||
("Kılıç", 110), ("Aslan", 105), ("Çetin", 100), ("Bulut", 95),
|
||||
("Aydın", 90), ("Özdemir", 90), ("Demirci", 85), ("Güler", 80),
|
||||
("Erdoğan", 75), ("Çakır", 75), ("Polat", 70), ("Koç", 70),
|
||||
("Acar", 65), ("Kurt", 65), ("Yavuz", 65), ("Ateş", 60),
|
||||
("Güneş", 60), ("Işık", 60), ("Karaca", 55), ("Türk", 55),
|
||||
("Özkan", 55), ("Bay", 50), ("Toker", 50), ("Şimşek", 50),
|
||||
("Akay", 45), ("Boz", 45), ("Deniz", 45), ("Ercan", 45),
|
||||
("Güçlü", 40), ("Kaplan", 40), ("Savaş", 40), ("Turan", 40),
|
||||
("Baş", 35), ("Çam", 35), ("Kara", 35), ("Taş", 35),
|
||||
("Dağ", 30), ("Duman", 30), ("Gür", 30), ("Köse", 30),
|
||||
("Uçar", 30), ("Yurt", 30),
|
||||
]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Batı kökenli isimler — ikinci öncelik
|
||||
# -----------------------------------------------------------------------
|
||||
BATI_ERKEK = [
|
||||
("Can", 110), ("Cem", 90), ("Cenk", 75), ("Sarp", 60),
|
||||
("Alper", 70), ("Enver", 55),
|
||||
]
|
||||
|
||||
BATI_KADIN = [
|
||||
("Ece", 100), ("Derya", 85), ("Sera", 60), ("Lara", 70),
|
||||
("Nisa", 80), ("Sena", 75),
|
||||
]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Arapça kökenli isimler — son öncelik (küçük liste)
|
||||
# -----------------------------------------------------------------------
|
||||
ARAPCA_ERKEK = [
|
||||
("Ahmet", 160), ("Ali", 150), ("Mehmet", 170), ("Hasan", 100),
|
||||
("Hüseyin", 95), ("İbrahim", 90), ("Mustafa", 140), ("Ömer", 80),
|
||||
]
|
||||
|
||||
ARAPCA_KADIN = [
|
||||
("Fatma", 120), ("Ayşe", 130), ("Hatice", 90), ("Havva", 70),
|
||||
("Meryem", 80), ("Rabia", 65),
|
||||
]
|
||||
|
||||
|
||||
def _bulk_create(entries, name_type, gender, origin):
|
||||
objs = []
|
||||
for name, freq in entries:
|
||||
objs.append(NameVocab(
|
||||
name=name,
|
||||
name_type=name_type,
|
||||
gender=gender,
|
||||
origin=origin,
|
||||
frequency=freq,
|
||||
))
|
||||
# ignore_conflicts: aynı kayıt varsa atla
|
||||
NameVocab.objects.bulk_create(objs, ignore_conflicts=True)
|
||||
return len(objs)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'NameVocab tablosunu Türkçe kökenli isimler öncelikli olarak doldurur'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
total = 0
|
||||
|
||||
# Türkçe — birinci öncelik
|
||||
total += _bulk_create(TURKCE_ERKEK, 'first', 'E', 'turkce')
|
||||
total += _bulk_create(TURKCE_KADIN, 'first', 'K', 'turkce')
|
||||
total += _bulk_create(TURKCE_SOYISIM, 'last', 'U', 'turkce')
|
||||
|
||||
# Batı — ikinci öncelik
|
||||
total += _bulk_create(BATI_ERKEK, 'first', 'E', 'bati')
|
||||
total += _bulk_create(BATI_KADIN, 'first', 'K', 'bati')
|
||||
|
||||
# Arapça — son öncelik
|
||||
total += _bulk_create(ARAPCA_ERKEK, 'first', 'E', 'arapca')
|
||||
total += _bulk_create(ARAPCA_KADIN, 'first', 'K', 'arapca')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'{total} isim işlendi. '
|
||||
f'Türkçe: {NameVocab.objects.filter(origin="turkce").count()}, '
|
||||
f'Batı: {NameVocab.objects.filter(origin="bati").count()}, '
|
||||
f'Arapça: {NameVocab.objects.filter(origin="arapca").count()}'
|
||||
))
|
||||
Reference in New Issue
Block a user