feat: alan eşlemesine fakülte sinyali + il adımında tüm iller
Sihirbazın alan çipleri artık YÖK Atlas'ın kendi verisiyle süzülüyor: kategoriBul program adı kurallarını fakülte kurallarıyla kesiştiriyor (Siber Güvenlik Müh. artık Hukuk değil, Siyaset Bilimi artık Fen değil). Aşırı geniş isim regexleri sıkılaştırıldı (bilim/güvenlik/programcı/çevre + gastronomi'nin içindeki "astronomi" tuzağı) — sayısalda Hukuk & Siyasal, sözelde Mühendislik çipi tamamen kalktı. İl adımındaki .slice(0,15) kırpması kaldırıldı: penceresinde programı olan TÜM iller listelenir; KKTC/yurtdışı kampüsler ayrı çip grubunda. Haritanın 15-limit yüzünden yanlış "program yok" grilemesi kendiliğinden düzeldi. Öncelik çiplerine şeffaflık notu eklendi (listeyi daraltmaz, AI'ya yön verir). /meraklisina şeması ve anlatımı aynı davranışla senkronlandı. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,8 @@ config:
|
|||||||
look: handDrawn
|
look: handDrawn
|
||||||
---
|
---
|
||||||
flowchart TD
|
flowchart TD
|
||||||
T("Sıralamanla açılan tüm programlar") --> A("1. adım · Alan seçimi<br/>yalnızca ulaşabildiğin alanlar listelenir")
|
T("Sıralamanla açılan tüm programlar") --> A("1. adım · Alan seçimi<br/>alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, yalnızca ulaşabildiklerin listelenir")
|
||||||
A --> B("2. adım · İl seçimi<br/>iller, seçtiğin alanlardaki program sayısına göre yeniden sayılır")
|
A --> B("2. adım · İl seçimi<br/>programı olan tüm iller, seçtiğin alanlardaki program sayısına göre yeniden sayılır")
|
||||||
B --> C("3. adım · Devlet / Vakıf<br/>sayılar hem alanı hem ili hesaba katar")
|
B --> C("3. adım · Devlet / Vakıf<br/>sayılar hem alanı hem ili hesaba katar")
|
||||||
C --> H("Aday havuzu<br/>elde kalan gerçek programlar")
|
C --> H("Aday havuzu<br/>elde kalan gerçek programlar")
|
||||||
H --> S{"Havuzda 24'ten az program mı kaldı?"}
|
H --> S{"Havuzda 24'ten az program mı kaldı?"}
|
||||||
@@ -42,7 +42,7 @@ export function HuniSemasi() {
|
|||||||
return (
|
return (
|
||||||
<ElCizimiSema
|
<ElCizimiSema
|
||||||
tanim={SEMA}
|
tanim={SEMA}
|
||||||
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla aday havuzuna daraltılır; havuz 24'ün altına düşerse filtreler gevşetilir, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda garanti olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
|
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla aday havuzuna daraltılır; alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, il adımında programı olan tüm iller listelenir; havuz 24'ün altına düşerse filtreler gevşetilir, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda garanti olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
|
||||||
figcaption={
|
figcaption={
|
||||||
<>
|
<>
|
||||||
Her adım havuzu biraz daha daraltır; yapay zekâ listeyi bu havuzun{" "}
|
Her adım havuzu biraz daha daraltır; yapay zekâ listeyi bu havuzun{" "}
|
||||||
|
|||||||
@@ -107,11 +107,14 @@ export function MeraklisinaIcerik() {
|
|||||||
“Yapay Zeka listemi kur” sihirbazındaki üç adım birbirinden
|
“Yapay Zeka listemi kur” sihirbazındaki üç adım birbirinden
|
||||||
bağımsız değildir. İlk adımda yalnızca{" "}
|
bağımsız değildir. İlk adımda yalnızca{" "}
|
||||||
<strong>sıralamanla ulaşabildiğin</strong>{" "}
|
<strong>sıralamanla ulaşabildiğin</strong>{" "}
|
||||||
alanlar listelenir; ikinci adımdaki iller, seçtiğin alanlardaki
|
alanlar listelenir — bir bölümün hangi alana girdiği, adına ve
|
||||||
program sayısına göre yeniden hesaplanır; üçüncü adımdaki
|
bağlı olduğu fakülteye bakılarak belirlenir. İkinci adımda
|
||||||
|
programı olan tüm iller, seçtiğin alanlardaki program sayısına
|
||||||
|
göre yeniden hesaplanarak listelenir; üçüncü adımdaki
|
||||||
devlet/vakıf sayıları da hem alan hem il seçimini hesaba katar.
|
devlet/vakıf sayıları da hem alan hem il seçimini hesaba katar.
|
||||||
Adımlar bitince elde kalan gerçek programlar bir{" "}
|
Seçtiğin il ve devlet/vakıf tercihi, sonuç sayfasındaki ücretsiz
|
||||||
<strong>aday havuzu</strong>{" "}
|
tabloya da uygulanır. Adımlar bitince elde kalan gerçek
|
||||||
|
programlar bir <strong>aday havuzu</strong>{" "}
|
||||||
olur ve yapay zekâya öyle gider: ona boş bir sayfa değil, bu havuz
|
olur ve yapay zekâya öyle gider: ona boş bir sayfa değil, bu havuz
|
||||||
verilir. Aşağıdaki şema akışın tamamını gösterir — havuz
|
verilir. Aşağıdaki şema akışın tamamını gösterir — havuz
|
||||||
24'ün altına düşerse filtrelerin nasıl gevşetildiği, yine de
|
24'ün altına düşerse filtrelerin nasıl gevşetildiği, yine de
|
||||||
|
|||||||
@@ -93,6 +93,16 @@ export function SihirbazAdimlar({
|
|||||||
() => [...canliFacetler.iller].sort((a, b) => b.adet - a.adet),
|
() => [...canliFacetler.iller].sort((a, b) => b.adet - a.adet),
|
||||||
[canliFacetler.iller],
|
[canliFacetler.iller],
|
||||||
);
|
);
|
||||||
|
// Türkiye illeri ana çip grubu; KKTC/yurtdışı kampüsler haritada olmadığı
|
||||||
|
// için ayrı alt grupta listelenir.
|
||||||
|
const turkiyeIlleri = useMemo(
|
||||||
|
() => siraliIller.filter((i) => HARITA_ILLERI.has(i.il)),
|
||||||
|
[siraliIller],
|
||||||
|
);
|
||||||
|
const disIller = useMemo(
|
||||||
|
() => siraliIller.filter((i) => !HARITA_ILLERI.has(i.il)),
|
||||||
|
[siraliIller],
|
||||||
|
);
|
||||||
const haritaIlleri = useMemo(
|
const haritaIlleri = useMemo(
|
||||||
() => canliFacetler.iller.filter((i) => HARITA_ILLERI.has(i.il)),
|
() => canliFacetler.iller.filter((i) => HARITA_ILLERI.has(i.il)),
|
||||||
[canliFacetler.iller],
|
[canliFacetler.iller],
|
||||||
@@ -258,13 +268,14 @@ export function SihirbazAdimlar({
|
|||||||
|
|
||||||
{/* Çipler birincil seçim yolu (haritadaki küçük iller mobilde
|
{/* Çipler birincil seçim yolu (haritadaki küçük iller mobilde
|
||||||
güvenilir dokunma hedefi değil); iller seçili kategorilere göre
|
güvenilir dokunma hedefi değil); iller seçili kategorilere göre
|
||||||
süzülmüş, program sayısına göre sıralı listelenir. */}
|
süzülmüş, program sayısına göre sıralı listelenir. Penceresinde
|
||||||
|
programı olan TÜM iller görünür (kırpma yok). */}
|
||||||
<div
|
<div
|
||||||
className={`mt-4 flex flex-wrap gap-2 ${
|
className={`mt-4 flex max-h-56 flex-wrap gap-2 overflow-y-auto sm:max-h-none sm:overflow-visible ${
|
||||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{siraliIller.map((i) => (
|
{turkiyeIlleri.map((i) => (
|
||||||
<Cip
|
<Cip
|
||||||
key={i.il}
|
key={i.il}
|
||||||
secili={iller.includes(i.il)}
|
secili={iller.includes(i.il)}
|
||||||
@@ -276,6 +287,30 @@ export function SihirbazAdimlar({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{disIller.length > 0 ? (
|
||||||
|
<div className="mt-4">
|
||||||
|
<p className="mb-2 text-xs font-semibold tracking-wide text-slate-400 uppercase">
|
||||||
|
KKTC & Yurt Dışı
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
className={`flex flex-wrap gap-2 ${
|
||||||
|
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{disIller.map((i) => (
|
||||||
|
<Cip
|
||||||
|
key={i.il}
|
||||||
|
secili={iller.includes(i.il)}
|
||||||
|
onClick={() => listeDegistir(iller, setIller, i.il, 5)}
|
||||||
|
>
|
||||||
|
{trBaslikDuzeni(i.il)}
|
||||||
|
<span className="ml-1.5 text-xs opacity-70">{i.adet}</span>
|
||||||
|
</Cip>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{iller.length > 0 ? (
|
{iller.length > 0 ? (
|
||||||
<div className="mt-3 flex flex-wrap items-center gap-2">
|
<div className="mt-3 flex flex-wrap items-center gap-2">
|
||||||
<span className="text-xs font-semibold text-slate-400">
|
<span className="text-xs font-semibold text-slate-400">
|
||||||
@@ -359,6 +394,10 @@ export function SihirbazAdimlar({
|
|||||||
</Cip>
|
</Cip>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<p className="mt-2 text-xs text-slate-500">
|
||||||
|
Öncelikler yapay zekânın gerekçelerine ve program seçimine yön
|
||||||
|
verir; listeyi daraltmaz.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TransitionPanel>
|
</TransitionPanel>
|
||||||
|
|||||||
@@ -196,31 +196,38 @@ export function rankWindowFacets(
|
|||||||
|
|
||||||
const satirlar = db
|
const satirlar = db
|
||||||
.prepare(
|
.prepare(
|
||||||
`SELECT isim, il, unitur FROM programs
|
`SELECT isim, fakulte, il, unitur FROM programs
|
||||||
WHERE tur = ? AND onlisans = ? AND ${EFEKTIF_SIRA} IS NOT NULL
|
WHERE tur = ? AND onlisans = ? AND ${EFEKTIF_SIRA} IS NOT NULL
|
||||||
AND ${EFEKTIF_SIRA} >= ?`
|
AND ${EFEKTIF_SIRA} >= ?`
|
||||||
)
|
)
|
||||||
.all(tur, onlisans, altSinir) as {
|
.all(tur, onlisans, altSinir) as {
|
||||||
isim: string;
|
isim: string;
|
||||||
|
fakulte: string | null;
|
||||||
il: string | null;
|
il: string | null;
|
||||||
unitur: string | null;
|
unitur: string | null;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
// isim → kategori eşlemesi pahalı (12 regex); tekrar eden isimler için önbellek
|
// isim+fakülte → kategori eşlemesi pahalı (regexler); tekrar edenler için önbellek
|
||||||
const kategoriCache = new Map<string, string[]>();
|
const kategoriCache = new Map<string, string[]>();
|
||||||
const kategorileriGetir = (isim: string): string[] => {
|
const kategorileriGetir = (
|
||||||
let k = kategoriCache.get(isim);
|
isim: string,
|
||||||
|
fakulte: string | null
|
||||||
|
): string[] => {
|
||||||
|
const anahtar = `${isim}|${fakulte ?? ""}`;
|
||||||
|
let k = kategoriCache.get(anahtar);
|
||||||
if (!k) {
|
if (!k) {
|
||||||
k = kategoriBul(isim);
|
k = kategoriBul(isim, fakulte);
|
||||||
kategoriCache.set(isim, k);
|
kategoriCache.set(anahtar, k);
|
||||||
}
|
}
|
||||||
return k;
|
return k;
|
||||||
};
|
};
|
||||||
|
|
||||||
const seciliKategoriler = secim.kategoriler ?? [];
|
const seciliKategoriler = secim.kategoriler ?? [];
|
||||||
const kategoriUyar = (isim: string) =>
|
const kategoriUyar = (isim: string, fakulte: string | null) =>
|
||||||
seciliKategoriler.length === 0 ||
|
seciliKategoriler.length === 0 ||
|
||||||
kategorileriGetir(isim).some((k) => seciliKategoriler.includes(k));
|
kategorileriGetir(isim, fakulte).some((k) =>
|
||||||
|
seciliKategoriler.includes(k)
|
||||||
|
);
|
||||||
const seciliIller = new Set(secim.iller ?? []);
|
const seciliIller = new Set(secim.iller ?? []);
|
||||||
const ilUyar = (il: string | null) =>
|
const ilUyar = (il: string | null) =>
|
||||||
seciliIller.size === 0 || (il != null && seciliIller.has(il));
|
seciliIller.size === 0 || (il != null && seciliIller.has(il));
|
||||||
@@ -230,12 +237,12 @@ export function rankWindowFacets(
|
|||||||
let devlet = 0;
|
let devlet = 0;
|
||||||
let vakif = 0;
|
let vakif = 0;
|
||||||
|
|
||||||
for (const { isim, il, unitur } of satirlar) {
|
for (const { isim, fakulte, il, unitur } of satirlar) {
|
||||||
// 1. adım: kategoriler yalnızca pencereye bağlı (filtre uygulanmaz)
|
// 1. adım: kategoriler yalnızca pencereye bağlı (filtre uygulanmaz)
|
||||||
for (const k of kategorileriGetir(isim)) {
|
for (const k of kategorileriGetir(isim, fakulte)) {
|
||||||
kategoriSay.set(k, (kategoriSay.get(k) ?? 0) + 1);
|
kategoriSay.set(k, (kategoriSay.get(k) ?? 0) + 1);
|
||||||
}
|
}
|
||||||
if (!kategoriUyar(isim)) continue;
|
if (!kategoriUyar(isim, fakulte)) continue;
|
||||||
// 2. adım: iller seçili kategorilerle süzülür
|
// 2. adım: iller seçili kategorilerle süzülür
|
||||||
if (il) ilSay.set(il, (ilSay.get(il) ?? 0) + 1);
|
if (il) ilSay.set(il, (ilSay.get(il) ?? 0) + 1);
|
||||||
if (!ilUyar(il)) continue;
|
if (!ilUyar(il)) continue;
|
||||||
@@ -251,10 +258,11 @@ export function rankWindowFacets(
|
|||||||
.filter((k) => k.adet >= 3) // gürültüyü ele
|
.filter((k) => k.adet >= 3) // gürültüyü ele
|
||||||
.sort((a, b) => b.adet - a.adet);
|
.sort((a, b) => b.adet - a.adet);
|
||||||
|
|
||||||
|
// Penceredeki programı olan TÜM iller döner (81 il + KKTC/yurtdışı);
|
||||||
|
// sıralama/gruplama UI'da yapılır. Kırpma yok: kullanıcı her ili görebilmeli.
|
||||||
const iller = [...ilSay.entries()]
|
const iller = [...ilSay.entries()]
|
||||||
.map(([il, adet]) => ({ il, adet }))
|
.map(([il, adet]) => ({ il, adet }))
|
||||||
.sort((a, b) => b.adet - a.adet)
|
.sort((a, b) => b.adet - a.adet);
|
||||||
.slice(0, 15);
|
|
||||||
|
|
||||||
const uniturler: { grup: UniturGrubu; adet: number }[] = [];
|
const uniturler: { grup: UniturGrubu; adet: number }[] = [];
|
||||||
if (devlet > 0) uniturler.push({ grup: "devlet", adet: devlet });
|
if (devlet > 0) uniturler.push({ grup: "devlet", adet: devlet });
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const KATEGORI_KURALLARI: { kategori: Kategori; kural: RegExp }[] = [
|
|||||||
{
|
{
|
||||||
kategori: "Mühendislik & Teknoloji",
|
kategori: "Mühendislik & Teknoloji",
|
||||||
kural:
|
kural:
|
||||||
/mühendis|yazılım|bilgisayar|bilişim|elektrik|elektronik|mekatronik|makine|makina|otomotiv|inşaat|endüstri|metalurji|malzeme|maden|jeoloji|jeofizik|petrol|enerji|robot|yapay zeka|yapay zekâ|siber|ağ teknolojileri|kontrol|otomasyon|uçak|havacılık|uzay|gemi|deniz ulaştırma|teknoloji|teknolojisi|programcı|elektrik-elektronik|nükleer|tekstil müh/,
|
/mühendis|yazılım|bilgisayar|bilişim|elektrik|elektronik|mekatronik|makine|makina|otomotiv|inşaat|endüstri|metalurji|malzeme|maden|jeoloji|jeofizik|petrol|enerji|robot|yapay zeka|yapay zekâ|siber|ağ teknolojileri|kontrol|otomasyon|uçak|havacılık|uzay|gemi|deniz ulaştırma|teknoloji|teknolojisi|bilgisayar programcı|elektrik-elektronik|nükleer|tekstil müh/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Sağlık & Tıp",
|
kategori: "Sağlık & Tıp",
|
||||||
@@ -35,13 +35,15 @@ const KATEGORI_KURALLARI: { kategori: Kategori; kural: RegExp }[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Hukuk & Siyasal",
|
kategori: "Hukuk & Siyasal",
|
||||||
|
// "güvenlik" bilinçli olarak dar: jenerik hali Siber/Sosyal/Bilgi
|
||||||
|
// Güvenliği'ni yanlışlıkla bu kategoriye alıyordu.
|
||||||
kural:
|
kural:
|
||||||
/hukuk|adalet|siyaset|kamu yönetim|uluslararası ilişki|siyasal|güvenlik|ceza infaz|milletlerarası|diplomasi/,
|
/hukuk|adalet|siyaset|kamu yönetim|uluslararası ilişki|siyasal|özel güvenlik|ceza infaz|milletlerarası|diplomasi/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "İktisat & İşletme",
|
kategori: "İktisat & İşletme",
|
||||||
kural:
|
kural:
|
||||||
/işletme|iktisat|ekonomi|maliye|muhasebe|finans|bankacılık|sigortacılık|dış ticaret|lojistik|pazarlama|yönetim bilişim|insan kaynak|çalışma ekonomisi|uluslararası ticaret|bankacılık ve sigortacılık|halkla ilişkiler|reklamcılık|emlak|menkul|gümrük|büro yönetim|yönetici asistan/,
|
/işletme|iktisat|iktisadi|ekonomi|maliye|muhasebe|finans|bankacılık|sigortacılık|sosyal güvenlik|dış ticaret|elektronik ticaret|lojistik|pazarlama|yönetim bilişim|havacılık yönetimi|enerji yönetimi|bilgi yönetimi|insan kaynak|çalışma ekonomisi|uluslararası ticaret|bankacılık ve sigortacılık|halkla ilişkiler|reklamcılık|emlak|menkul|gümrük|büro yönetim|yönetici asistan/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Eğitim & Öğretmenlik",
|
kategori: "Eğitim & Öğretmenlik",
|
||||||
@@ -55,13 +57,15 @@ const KATEGORI_KURALLARI: { kategori: Kategori; kural: RegExp }[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Fen & Temel Bilimler",
|
kategori: "Fen & Temel Bilimler",
|
||||||
|
// Jenerik "bilim" yok: "Siyaset Bilimi" / "İletişim Bilimleri" /
|
||||||
|
// "Dilbilimi" gibi programları yanlışlıkla Fen yapıyordu.
|
||||||
kural:
|
kural:
|
||||||
/matematik|fizik|kimya|biyoloji|istatistik|moleküler|genetik|biyoteknoloji|astronomi|aktüerya|fen bilim|bilim/,
|
/matematik|fizik|kimya|biyoloji|istatistik|moleküler|genetik|biyoteknoloji|\bastronomi|aktüerya|fen bilim|veri bilim|adli bilim/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Sosyal & Beşeri Bilimler",
|
kategori: "Sosyal & Beşeri Bilimler",
|
||||||
kural:
|
kural:
|
||||||
/sosyoloji|tarih|coğrafya|felsefe|edebiyat|dil ve edebiyat|filoloji|arkeoloji|antropoloji|ilahiyat|din kültürü|dilbilim|sosyal hizmet|mütercim|çeviribilim|tercümanlık|türk dili|dünya dilleri|sanat tarihi|halkbilim|dinî/,
|
/sosyoloji|tarih|coğrafya|felsefe|edebiyat|dil ve edebiyat|filoloji|arkeoloji|antropoloji|ilahiyat|din kültürü|dilbilim|sosyal hizmet|sosyal bilim|islam|mütercim|çeviribilim|tercümanlık|türk dili|dünya dilleri|sanat tarihi|halkbilim|dinî/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Sanat, Medya & İletişim",
|
kategori: "Sanat, Medya & İletişim",
|
||||||
@@ -79,24 +83,108 @@ const KATEGORI_KURALLARI: { kategori: Kategori; kural: RegExp }[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
kategori: "Tarım & Doğa",
|
kategori: "Tarım & Doğa",
|
||||||
|
// "çevre" bağlamlı: jenerik hali "İç Mimarlık ve Çevre Tasarımı"nı
|
||||||
|
// yanlışlıkla Tarım'a alıyordu.
|
||||||
kural:
|
kural:
|
||||||
/ziraat|tarım|tarla|bahçe|bitki|hayvan|su ürünleri|gıda|orman|çevre|balıkçılık|peyzaj|tohum|toprak|zootekni/,
|
/ziraat|tarım|tarla|bahçe|bitki|hayvan|su ürünleri|gıda|orman|çevre müh|çevre sağlığı|çevre koruma|çevre temizli|çevresel|balıkçılık|peyzaj|tohum|toprak|zootekni/,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Verilen program adının girdiği tüm kategorileri döner (0..n). */
|
// YÖK Atlas'ın kendi alan sinyali: programın bağlı olduğu fakülte adı.
|
||||||
export function kategoriBul(isim: string): Kategori[] {
|
// Lisansta güçlü ("Mühendislik Fakültesi", "Hukuk Fakültesi"); önlisansta
|
||||||
const lower = isim.toLocaleLowerCase("tr-TR");
|
// jenerik ("... Meslek Yüksekokulu") olduğundan hiçbir kurala eşleşmez ve
|
||||||
|
// isim kuralları tek başına devrede kalır. Bir fakülte birden çok kategoriye
|
||||||
|
// eşlenebilir (ör. Fen-Edebiyat → Fen + Sosyal); program bazında ayrım
|
||||||
|
// isim∩fakülte kesişimiyle yapılır (bkz. kategoriBul).
|
||||||
|
const FAKULTE_KURALLARI: { kategori: Kategori; kural: RegExp }[] = [
|
||||||
|
{
|
||||||
|
kategori: "Mühendislik & Teknoloji",
|
||||||
|
kural: /mühendis|teknoloji|bilişim|havacılık ve uzay|denizcilik|uygulamalı bilimler/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Sağlık & Tıp",
|
||||||
|
kural: /tıp|sağlık|diş|eczacılık|hemşirelik|veteriner|spor bilim/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Hukuk & Siyasal",
|
||||||
|
kural: /hukuk|siyasal|iktisadi|idari|güvenlik/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "İktisat & İşletme",
|
||||||
|
kural: /iktisadi|işletme|yönetim|ticaret|bankacılık|uygulamalı bilimler|finans/,
|
||||||
|
},
|
||||||
|
{ kategori: "Eğitim & Öğretmenlik", kural: /eğitim/ },
|
||||||
|
{
|
||||||
|
kategori: "Mimarlık & Tasarım",
|
||||||
|
kural: /mimarlık|tasarım|güzel sanatlar/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Fen & Temel Bilimler",
|
||||||
|
kural: /\bfen\b|fen-edebiyat|doğa bilimleri|temel bilimler/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Sosyal & Beşeri Bilimler",
|
||||||
|
kural:
|
||||||
|
/edebiyat|fen-edebiyat|insan ve toplum|sosyal bilim|ilahiyat|islami|beşeri/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Sanat, Medya & İletişim",
|
||||||
|
kural: /iletişim|güzel sanatlar|sanat|konservatuvar|müzik/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kategori: "Psikoloji & Danışmanlık",
|
||||||
|
kural: /insan ve toplum|edebiyat|fen-edebiyat|sosyal bilim|eğitim/,
|
||||||
|
},
|
||||||
|
{ kategori: "Turizm & Gastronomi", kural: /turizm|gastronomi/ },
|
||||||
|
{
|
||||||
|
kategori: "Tarım & Doğa",
|
||||||
|
kural: /ziraat|orman|su ürünleri|tarım|doğa bilimleri|veteriner/,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function eslesenKategoriler(
|
||||||
|
kurallar: { kategori: Kategori; kural: RegExp }[],
|
||||||
|
metin: string,
|
||||||
|
): Kategori[] {
|
||||||
|
const lower = metin.toLocaleLowerCase("tr-TR");
|
||||||
const sonuc: Kategori[] = [];
|
const sonuc: Kategori[] = [];
|
||||||
for (const { kategori, kural } of KATEGORI_KURALLARI) {
|
for (const { kategori, kural } of kurallar) {
|
||||||
if (kural.test(lower)) sonuc.push(kategori);
|
if (kural.test(lower)) sonuc.push(kategori);
|
||||||
}
|
}
|
||||||
return sonuc;
|
return sonuc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verilen programın girdiği tüm kategorileri döner (0..n).
|
||||||
|
*
|
||||||
|
* Fakülte verilirse isim∩fakülte kesişimi alınır: "Siber Güvenlik
|
||||||
|
* Mühendisliği" isimden {Mühendislik, Hukuk} çıkarken Mühendislik
|
||||||
|
* Fakültesi'nde olduğu için Hukuk elenir. Kesişim boşsa ya da fakülte
|
||||||
|
* hiçbir kurala eşleşmiyorsa (jenerik MYO adları) isim kuralları geçerlidir;
|
||||||
|
* fakültesiz çağrı bugüne kadarki davranışla birebir aynıdır.
|
||||||
|
*/
|
||||||
|
export function kategoriBul(
|
||||||
|
isim: string,
|
||||||
|
fakulte?: string | null,
|
||||||
|
): Kategori[] {
|
||||||
|
const isimKats = eslesenKategoriler(KATEGORI_KURALLARI, isim);
|
||||||
|
if (fakulte && isimKats.length > 0) {
|
||||||
|
const fakulteKats = eslesenKategoriler(FAKULTE_KURALLARI, fakulte);
|
||||||
|
if (fakulteKats.length > 0) {
|
||||||
|
const kesisim = isimKats.filter((k) => fakulteKats.includes(k));
|
||||||
|
if (kesisim.length > 0) return kesisim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isimKats;
|
||||||
|
}
|
||||||
|
|
||||||
/** Bir programın seçili kategorilerden en az biriyle eşleşip eşleşmediği. */
|
/** Bir programın seçili kategorilerden en az biriyle eşleşip eşleşmediği. */
|
||||||
export function kategoriEslesir(isim: string, secililer: string[]): boolean {
|
export function kategoriEslesir(
|
||||||
|
isim: string,
|
||||||
|
secililer: string[],
|
||||||
|
fakulte?: string | null,
|
||||||
|
): boolean {
|
||||||
if (secililer.length === 0) return true;
|
if (secililer.length === 0) return true;
|
||||||
const kats = kategoriBul(isim);
|
const kats = kategoriBul(isim, fakulte);
|
||||||
return kats.some((k) => secililer.includes(k));
|
return kats.some((k) => secililer.includes(k));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export function havuzOlustur(params: RaporParams): HavuzSonuc {
|
|||||||
|
|
||||||
const kategoriFiltre = (havuz: AdayProgram[]) =>
|
const kategoriFiltre = (havuz: AdayProgram[]) =>
|
||||||
kategoriler.length > 0
|
kategoriler.length > 0
|
||||||
? havuz.filter((p) => kategoriEslesir(p.isim, kategoriler))
|
? havuz.filter((p) => kategoriEslesir(p.isim, kategoriler, p.fakulte))
|
||||||
: havuz;
|
: havuz;
|
||||||
|
|
||||||
// 1. Tam filtre: iller + üniversite tipi (SQL), kategori (JS)
|
// 1. Tam filtre: iller + üniversite tipi (SQL), kategori (JS)
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ export function tercihDegerlendir(
|
|||||||
const olumlu: string[] = [];
|
const olumlu: string[] = [];
|
||||||
const celiskiler: string[] = [];
|
const celiskiler: string[] = [];
|
||||||
|
|
||||||
|
// Manuel liste satırında fakülte taşınmıyor (ProgramListeSatiri bilinçli
|
||||||
|
// omit ediyor); eşleşme yalnızca isim kurallarıyla yapılır.
|
||||||
if (kategoriEslesir(program.isim, profil.secimler.kategoriler)) {
|
if (kategoriEslesir(program.isim, profil.secimler.kategoriler)) {
|
||||||
olumlu.push("İlgi alanlarınla uyumlu");
|
olumlu.push("İlgi alanlarınla uyumlu");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user