fix(havuz): B5 — gevşeyen filtreye uyan programlar havuzda kalsın [KARAR]
İl gevşeyince havuz baştan, ilsiz kuruluyordu; seçili ildeki programlar sıraya en yakın 20'ye giremezse listeden tamamen düşüyordu (Kayseri 1/60, Trabzon 0/25) — prompt ise "seçili illere öncelik ver" diyordu. Artık gevşetmenin her basamağında seçime uyan programlar önce alınır, boşluk sıraya en yakın diğer programlarla dolar. Aynı kural alan ve danışman profili gevşediğinde de geçerli (tek yardımcı: oncelikliBirlestir). Kırpma sonrası havuz yine dilim sırasında, dilim içinde yakından uzağa dizilir. Kanıt (havuzda seçili ildeki program, önce → sonra): p12 Kayseri 1 → 9, p13 Trabzon 0 → 4, b06 Düzce 2 → 10, a09 Konya 2 → 3. Gevşetme basamağı ve liste uzunluğu hiçbir profilde değişmedi. /meraklisina şeması, 4. bölüm anlatımı ve aria-label aynı kuralla güncellendi. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -128,11 +128,14 @@ export function dilimHedefiHesapla(havuz: AdayProgram[]): DilimHedef {
|
||||
// modellerde prefill + isabet maliyeti yüksek (ölçüm: 6 Ağu 2026).
|
||||
const PROMPT_LIMIT_DILIM = 20;
|
||||
|
||||
const DILIM_SIRASI: Record<Dilim, number> = { hayal: 0, dengeli: 1, garanti: 2 };
|
||||
|
||||
/**
|
||||
* Dilim sırasını koruyarak her dilimden en fazla n aday bırakır. Havuz tek
|
||||
* dilime yığılmışsa (ör. çok iyi derece: neredeyse hepsi güvenli) n'e kırpmak
|
||||
* listeyi 24'ün altına düşürürdü; o durumda eksik, adayı kalan dilimlerden
|
||||
* tamamlanır — yeterli program varken liste 24'ten kısa kalmaz.
|
||||
* Her dilimden en fazla n aday bırakır; dizideki sıra önceliktir (öndeki
|
||||
* kalır). Havuz tek dilime yığılmışsa (ör. çok iyi derece: neredeyse hepsi
|
||||
* güvenli) n'e kırpmak listeyi 24'ün altına düşürürdü; o durumda eksik, adayı
|
||||
* kalan dilimlerden tamamlanır — yeterli program varken liste 24'ten kısa
|
||||
* kalmaz. Sonuç dilim sırasına ve dilim içinde yakından uzağa dizilir.
|
||||
*/
|
||||
function dilimBasinaKirp(havuz: AdayProgram[], n: number): AdayProgram[] {
|
||||
const mevcut = dilimSay(havuz);
|
||||
@@ -143,7 +146,34 @@ function dilimBasinaKirp(havuz: AdayProgram[], n: number): AdayProgram[] {
|
||||
};
|
||||
eksigiDagit(pay, mevcut, Math.min(HEDEF, havuz.length));
|
||||
const sayac: DilimHedef = { hayal: 0, dengeli: 0, garanti: 0 };
|
||||
return havuz.filter((p) => ++sayac[p.dilim] <= pay[p.dilim]);
|
||||
// hayal: sınıra en yakın (en büyük taban) önce; diğerleri en küçük taban önce
|
||||
const yakinlik = (p: AdayProgram) =>
|
||||
p.dilim === "hayal" ? -(p.efektifSira ?? 0) : (p.efektifSira ?? 0);
|
||||
return havuz
|
||||
.filter((p) => ++sayac[p.dilim] <= pay[p.dilim])
|
||||
.sort(
|
||||
(a, b) =>
|
||||
DILIM_SIRASI[a.dilim] - DILIM_SIRASI[b.dilim] ||
|
||||
yakinlik(a) - yakinlik(b),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Katmanları öncelik sırasıyla, tekrarsız birleştirir. Gevşetmede kullanılır:
|
||||
* gevşeyen filtreye UYAN programlar önce gelir ve kırpmada korunur, kalan
|
||||
* boşluk sonraki katmanlardan (sıraya en yakın diğer programlar) dolar.
|
||||
*/
|
||||
function oncelikliBirlestir(...katmanlar: AdayProgram[][]): AdayProgram[] {
|
||||
const gorulen = new Set<string>();
|
||||
const sonuc: AdayProgram[] = [];
|
||||
for (const katman of katmanlar) {
|
||||
for (const p of katman) {
|
||||
if (gorulen.has(p.id)) continue;
|
||||
gorulen.add(p.id);
|
||||
sonuc.push(p);
|
||||
}
|
||||
}
|
||||
return sonuc;
|
||||
}
|
||||
|
||||
function dilimEkle(r: {
|
||||
@@ -167,6 +197,8 @@ function dilimEkle(r: {
|
||||
*
|
||||
* Süzgeçlerin hepsi dilimin TAMAMINA uygulanır, kırpma en sonda yapılır:
|
||||
* "24'ten az" kararı o alanda/ilde gerçekten kaç program olduğuna bakar.
|
||||
* Bir filtre gevşediğinde ona uyan programlar havuzdan düşmez: önce onlar
|
||||
* alınır, boşluk sıraya en yakın diğer programlarla dolar.
|
||||
*/
|
||||
export function havuzOlustur(
|
||||
params: RaporParams,
|
||||
@@ -196,6 +228,8 @@ export function havuzOlustur(
|
||||
// liste yine kurulur, gevşetme yapay zekâya ve adaya söylenir.
|
||||
const suzgec = profilSuzgeci(profil, iller.length > 0);
|
||||
const profilGevsetildi: Gevsetilen[] = [];
|
||||
// Profil gevşerse profile uyan (24'ten az) programlar yine en önde tutulur
|
||||
let profilliFiltreli: AdayProgram[] = [];
|
||||
if (suzgec.ozellik || suzgec.iller) {
|
||||
const profilliHam = ilFiltre(
|
||||
dilimEkle(
|
||||
@@ -206,7 +240,7 @@ export function havuzOlustur(
|
||||
),
|
||||
iller.length > 0 ? iller : suzgec.iller,
|
||||
);
|
||||
const profilliFiltreli = kategoriFiltre(profilliHam);
|
||||
profilliFiltreli = kategoriFiltre(profilliHam);
|
||||
if (profilliFiltreli.length >= HEDEF) {
|
||||
return {
|
||||
havuz: dilimBasinaKirp(profilliFiltreli, PROMPT_LIMIT_DILIM),
|
||||
@@ -222,35 +256,40 @@ export function havuzOlustur(
|
||||
);
|
||||
const tamHam = ilFiltre(ilsizHam, iller);
|
||||
const tamFiltreli = kategoriFiltre(tamHam);
|
||||
const kirp = (...katmanlar: AdayProgram[][]) =>
|
||||
dilimBasinaKirp(
|
||||
oncelikliBirlestir(profilliFiltreli, ...katmanlar),
|
||||
PROMPT_LIMIT_DILIM,
|
||||
);
|
||||
if (tamFiltreli.length >= HEDEF) {
|
||||
return {
|
||||
havuz: dilimBasinaKirp(tamFiltreli, PROMPT_LIMIT_DILIM),
|
||||
gevsetildi: profilGevsetildi,
|
||||
};
|
||||
return { havuz: kirp(tamFiltreli), gevsetildi: profilGevsetildi };
|
||||
}
|
||||
|
||||
// 2. Kategori gevşet: aynı illerdeki kategori-dışı programlarla doldur
|
||||
// 2. Kategori gevşet: seçili alandakiler kalır, boşluk aynı illerdeki
|
||||
// kategori-dışı programlarla dolar
|
||||
if (kategoriler.length > 0 && tamHam.length >= HEDEF) {
|
||||
return {
|
||||
havuz: dilimBasinaKirp(tamHam, PROMPT_LIMIT_DILIM),
|
||||
havuz: kirp(tamFiltreli, tamHam),
|
||||
gevsetildi: [...profilGevsetildi, "kategori"],
|
||||
};
|
||||
}
|
||||
|
||||
// 3. İl gevşet: il filtresini kaldırıp kategoriye geri dön
|
||||
// 3. İl gevşet: seçili ildekiler kalır, boşluk aynı kategorideki başka
|
||||
// illerin programlarıyla dolar
|
||||
const gevsetildi: Gevsetilen[] = [...profilGevsetildi];
|
||||
if (iller.length > 0) gevsetildi.push("il");
|
||||
const ilsizFiltreli = kategoriFiltre(ilsizHam);
|
||||
if (ilsizFiltreli.length >= HEDEF) {
|
||||
return {
|
||||
havuz: dilimBasinaKirp(ilsizFiltreli, PROMPT_LIMIT_DILIM),
|
||||
gevsetildi,
|
||||
};
|
||||
return { havuz: kirp(tamFiltreli, ilsizFiltreli), gevsetildi };
|
||||
}
|
||||
|
||||
// 4. Hem il hem kategori gevşet: elde ne varsa
|
||||
// 4. Hem il hem kategori gevşet: önce iki seçime de uyanlar, sonra alana
|
||||
// uyanlar, sonra ile uyanlar, en son elde ne varsa
|
||||
if (kategoriler.length > 0) gevsetildi.push("kategori");
|
||||
return { havuz: dilimBasinaKirp(ilsizHam, PROMPT_LIMIT_DILIM), gevsetildi };
|
||||
return {
|
||||
havuz: kirp(tamFiltreli, ilsizFiltreli, tamHam, ilsizHam),
|
||||
gevsetildi,
|
||||
};
|
||||
}
|
||||
|
||||
// Prompt'a veri penceresinin tamamı değil son 4 yılı gider (yeniden eskiye):
|
||||
|
||||
Reference in New Issue
Block a user