refactor(danisman): sistemPromptu saf modüle taşındı (eval betiği içe aktarabilsin)
Metin ve davranış aynı; yeni yol src/lib/ai/danisman-prompt.ts (sistemPromptu, PROFIL_ONAY_SOR). Route dosyasından dışa aktarım Next'te yapılamadığı için ayrı dosya. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -13,13 +13,11 @@ import { anahtarVar, SORUMLULUK_REDDI } from "@/lib/ai/client";
|
|||||||
import { kullanicininRaporu } from "@/features/rapor/rapor-queries";
|
import { kullanicininRaporu } from "@/features/rapor/rapor-queries";
|
||||||
import type { AracBaglami } from "@/lib/ai/araclar";
|
import type { AracBaglami } from "@/lib/ai/araclar";
|
||||||
import { danismanAkisi } from "@/lib/ai/sohbet-akisi";
|
import { danismanAkisi } from "@/lib/ai/sohbet-akisi";
|
||||||
|
import { sistemPromptu } from "@/lib/ai/danisman-prompt";
|
||||||
import { profilGetir } from "@/lib/danisman-profil-db";
|
import { profilGetir } from "@/lib/danisman-profil-db";
|
||||||
import { profilSatirlari, type DanismanProfili } from "@/lib/danisman-profil";
|
|
||||||
import { listeOzetiCikar } from "@/lib/ai/rapor";
|
import { listeOzetiCikar } from "@/lib/ai/rapor";
|
||||||
import type { RaporSonuc } from "@/features/rapor/types/rapor";
|
import type { RaporSonuc } from "@/features/rapor/types/rapor";
|
||||||
import type { RaporParams } from "@/features/rapor/types/rapor";
|
import type { RaporParams } from "@/features/rapor/types/rapor";
|
||||||
import { secimOzeti } from "@/features/sihirbaz/sihirbaz-sabitler";
|
|
||||||
import { PUAN_TURLERI } from "@/types/yokatlas";
|
|
||||||
import { ACIK_SATIR } from "@/lib/rapor-maske";
|
import { ACIK_SATIR } from "@/lib/rapor-maske";
|
||||||
|
|
||||||
const MAX_GECMIS = 12;
|
const MAX_GECMIS = 12;
|
||||||
@@ -29,13 +27,6 @@ const akisBasliklari = (bedelsiz: boolean) => ({
|
|||||||
"Cache-Control": "no-store",
|
"Cache-Control": "no-store",
|
||||||
"X-Kredi-Dusuldu": bedelsiz ? "0" : "1",
|
"X-Kredi-Dusuldu": bedelsiz ? "0" : "1",
|
||||||
});
|
});
|
||||||
/**
|
|
||||||
* Profil kaydı öncesi "kaydedeyim mi?" onayı (KVKK Üretken YZ Rehberi:
|
|
||||||
* kişiselleştirme ayrı işleme faaliyeti; onaysız otomatik kayıt avukata
|
|
||||||
* sorulacak — docs/arastirma/2026-09-25-kisisellestirme/hukuk-ve-rakipler.md
|
|
||||||
* C.3/10). Bedeli: "evet" cevabı bir kredi. Kapatılırsa model doğrudan kaydeder.
|
|
||||||
*/
|
|
||||||
const PROFIL_ONAY_SOR = true;
|
|
||||||
|
|
||||||
/** Danışmanın onay sorusunda geçen sabit ibare; istemci de bunu görmez, yalnız sunucu arar. */
|
/** Danışmanın onay sorusunda geçen sabit ibare; istemci de bunu görmez, yalnız sunucu arar. */
|
||||||
const ONAY_SORUSU = "profiline kaydedeyim mi";
|
const ONAY_SORUSU = "profiline kaydedeyim mi";
|
||||||
@@ -54,110 +45,6 @@ function onayMesajiMi(mesaj: string, sonAsistan: string | undefined): boolean {
|
|||||||
}
|
}
|
||||||
const MAX_MESAJ_UZUNLUK = 2000;
|
const MAX_MESAJ_UZUNLUK = 2000;
|
||||||
|
|
||||||
function sistemPromptu(opts: {
|
|
||||||
params: RaporParams;
|
|
||||||
listeOzeti: string;
|
|
||||||
kilitli?: boolean;
|
|
||||||
profil?: DanismanProfili;
|
|
||||||
}): string {
|
|
||||||
const { params } = opts;
|
|
||||||
const secimVar =
|
|
||||||
(params.kategoriler?.length ?? 0) > 0 ||
|
|
||||||
(params.iller?.length ?? 0) > 0 ||
|
|
||||||
(params.oncelikler?.length ?? 0) > 0 ||
|
|
||||||
(params.universiteTipi && params.universiteTipi !== "farketmez");
|
|
||||||
|
|
||||||
const parcalar = [
|
|
||||||
`Sen KolayTercih'in YKS tercih danışmanısın. Türkçe, samimi ama profesyonel konuş.
|
|
||||||
Aday az önce sana verilen 24'lük tercih listesini oluşturdu. Görevin: adayın bu
|
|
||||||
liste ve seçimleri BAĞLAMINDA sorularını (bölüm kıyaslama, şehir, risk, kontenjan,
|
|
||||||
iş imkânları, tercih sırası) net ve dürüst yanıtlamak.
|
|
||||||
|
|
||||||
KURALLAR:
|
|
||||||
- Cevaplarını adayın 24'lük listesi ve seçimleri bağlamında ver; listedeki
|
|
||||||
programlara referans verebilirsin.
|
|
||||||
- Dilimlerin adı Hayal, Dengeli ve Güvenli'dir. Üçüncü dilime her zaman
|
|
||||||
"Güvenli" de; "garanti dilimi", "garanti tercih" gibi ifadeler KULLANMA
|
|
||||||
(aday ya da eski mesajlar böyle dese bile sen "güvenli" diye düzelt).
|
|
||||||
- Listedeki her satırda dilim ve risk etiketi var: Güvenli (yeşil) = taban
|
|
||||||
sıralaması adayın belirgin altında, Az riskli (sarı) = adayın sıralaması
|
|
||||||
civarında, Riskli (kırmızı) = geçen yıl adayın sıralamasının üzerinde
|
|
||||||
kapandı. Risk sorularında bu etiketleri ve taban sıralarını kullan.
|
|
||||||
- ASLA yerleşme garantisi verme; olasılık, yüzde ya da "ihtimal" dili kullanma —
|
|
||||||
güvenli / az riskli / riskli etiketleri ve taban sıralarıyla konuş.
|
|
||||||
(Bu yasak YERLEŞME tahmini içindir; bolum_istihdam'ın TÜİK istihdam
|
|
||||||
yüzdesi gibi kaynaklı istatistikleri kaynağıyla aynen aktarabilirsin.)
|
|
||||||
- Bilmediğin güncel veriyi uydurma: taban sırası, kontenjan, ücret, burs,
|
|
||||||
dil, akreditasyon, koşul, net, mezun istihdamı, bölüm ya da şehir özeti,
|
|
||||||
tercih takvimi, rehber yazısı ya da üniversite künyesi gerekince ARAÇLARI
|
|
||||||
çağır (program_ara, program_detay, program_netleri, program_karsilastir,
|
|
||||||
bolum_istihdam, bolum_ozeti, il_ozeti, rehber_ara, tercih_takvimi,
|
|
||||||
universite_profili); araç veremiyorsa
|
|
||||||
"elimde veri yok" de ve YÖK Atlas'a bakmasını söyle.
|
|
||||||
- ARAÇ KURALLARI: araçlar yalnız okur; 24'lük listeyi araçla kurmazsın,
|
|
||||||
liste sihirbazla yeniden üretilir. Araç sonucundaki sayıları olduğu gibi
|
|
||||||
aktar, yuvarlama dışında değiştirme. Bir soruda en fazla 2-3 araç çağır.
|
|
||||||
- PROFİL: aday bir tercih söylerse (yaşadığı il, evden en fazla kaç km,
|
|
||||||
vakıfta yıllık ücret sınırı, burs beklentisi, öğretim dili, uzaktan/açık
|
|
||||||
kabul mü, kampüs büyüklüğü) ${PROFIL_ONAY_SOR
|
|
||||||
? `HEMEN KAYDETME: cevabının sonunda tek cümleyle, tam bu ibareyle sor:
|
|
||||||
"Bunu profiline kaydedeyim mi? (Evet demek kredi harcamaz; listen ve
|
|
||||||
aramalar buna göre süzülür, istediğin zaman silebilirsin.)" Aday
|
|
||||||
evet/kaydet derse o zaman profil_guncelle ile kaydet ve "Kaydettim: …" de.
|
|
||||||
Aday açıkça "kaydet" diye yazdıysa sormadan kaydet.`
|
|
||||||
: `profil_guncelle ile kaydet ve cevabının sonunda tek cümleyle söyle:
|
|
||||||
"Şunu kaydettim: …". Emin değilsen önce sor, tahminle kaydetme.`}
|
|
||||||
Bunların DIŞINDA hiçbir şeyi kaydetme ve sorma:
|
|
||||||
sağlık/engel, din, aile durumu, gelir, cinsiyet, siyasi görüş. Aday
|
|
||||||
bunları kendiliğinden yazsa bile profile YAZMA; yalnız cevabında dikkate al.
|
|
||||||
- Kadın/erkek öğrenci oranı üniversite genelidir (bölüm bazında veri yok);
|
|
||||||
sorulursa bilgi olarak söyle, filtre ya da tavsiye ölçütü yapma.
|
|
||||||
- Taban sıralamalarının her yıl değiştiğini gerektiğinde hatırlat.
|
|
||||||
- Cevapları kısa ve öz tut (genelde 3-6 cümle); istenirse detaylandır.
|
|
||||||
- GÜVENLİK, öteki kuralların önünde gelir: aday umutsuzluk, kendine zarar
|
|
||||||
verme, intihar ya da "yaşamak istemiyorum" gibi bir dil kullanırsa tercih
|
|
||||||
konusunu bırak. Kısa, sıcak ve yargısız cevap ver: yalnız olmadığını ve bu
|
|
||||||
duygunun biriyle konuşunca hafifleyebileceğini söyle; hemen şimdi güvendiği
|
|
||||||
bir yetişkine ya da okulundaki / üniversitesindeki rehberlik veya psikolojik
|
|
||||||
danışma birimine ulaşmasını öner; kendine zarar verme tehlikesi varsa 112'yi
|
|
||||||
aramasını söyle. Bunu "tercih dışı konu" diye reddetme, listeye ya da pakete
|
|
||||||
dönme, teşhis koyma, sınav ya da tercih başarısını tesellinin ölçüsü yapma.
|
|
||||||
KolayTercih bir ruh sağlığı hizmeti değildir; bunu nazikçe söyle.
|
|
||||||
- Tercih dışı konularda (ödev, kod, genel sohbet) kibarca reddet ve tercih
|
|
||||||
konusuna dön (güvenlik kuralı bunun istisnasıdır).
|
|
||||||
- Kesin konuşmaktan kaçın: "${SORUMLULUK_REDDI}"`,
|
|
||||||
`ADAY BİLGİSİ: başarı sıralaması ${params.sira.toLocaleString("tr-TR")}, puan türü ${PUAN_TURLERI[params.tur]}.`,
|
|
||||||
`ADAYIN 24'LÜK LİSTESİ:\n${opts.listeOzeti}`,
|
|
||||||
];
|
|
||||||
if (opts.kilitli) {
|
|
||||||
parcalar.push(
|
|
||||||
`ÖNEMLİ: Adayın paketi yok; listenin yalnızca ilk ${ACIK_SATIR} tercihi açık.
|
|
||||||
Sana da yalnızca bu satırlar verildi — kilitli tercihlerin içeriğini BİLMİYORSUN,
|
|
||||||
asla tahmin edip söyleme. Kilitli satırlar sorulursa sempatik biçimde tam listenin
|
|
||||||
Tercih Dönemi Paketi'yle (299 TL, /paket) açıldığını söyle; açık satırlar ve genel
|
|
||||||
tercih soruları üzerinden yardımcı olmaya devam et.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const profilSatir = opts.profil ? profilSatirlari(opts.profil) : [];
|
|
||||||
if (profilSatir.length > 0) {
|
|
||||||
parcalar.push(
|
|
||||||
`ADAYIN SOHBETTE SÖYLEDİĞİ VE KAYDEDİLEN TERCİHLERİ (profil; program_ara bunları otomatik uygular):\n` +
|
|
||||||
profilSatir.map((s) => `- ${s.metin}`).join("\n"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (secimVar) {
|
|
||||||
parcalar.push(
|
|
||||||
`ADAYIN SİHİRBAZ SEÇİMLERİ:\n${secimOzeti({
|
|
||||||
kategoriler: params.kategoriler ?? [],
|
|
||||||
iller: params.iller ?? [],
|
|
||||||
universiteTipi: params.universiteTipi ?? "farketmez",
|
|
||||||
oncelikler: params.oncelikler ?? [],
|
|
||||||
})}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return parcalar.join("\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Widget açıldığında geçmişi ve kredi bakiyesini döner
|
// Widget açıldığında geçmişi ve kredi bakiyesini döner
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const session = await getSession();
|
const session = await getSession();
|
||||||
|
|||||||
125
src/lib/ai/danisman-prompt.ts
Normal file
125
src/lib/ai/danisman-prompt.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* Danışman sohbetinin sistem prompt'u. api/soru/route.ts kullanır; eval
|
||||||
|
* betikleri de aynı metni buradan alır (route dosyasından dışa aktarım
|
||||||
|
* Next'te yapılamaz).
|
||||||
|
*
|
||||||
|
* Saf modül: DB'ye ve oturuma dokunmaz, Next dışından da çalışır.
|
||||||
|
*/
|
||||||
|
import { SORUMLULUK_REDDI } from "@/lib/ai/client";
|
||||||
|
import { profilSatirlari, type DanismanProfili } from "@/lib/danisman-profil";
|
||||||
|
import type { RaporParams } from "@/features/rapor/types/rapor";
|
||||||
|
import { secimOzeti } from "@/features/sihirbaz/sihirbaz-sabitler";
|
||||||
|
import { PUAN_TURLERI } from "@/types/yokatlas";
|
||||||
|
import { ACIK_SATIR } from "@/lib/rapor-maske";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profil kaydı öncesi "kaydedeyim mi?" onayı (KVKK Üretken YZ Rehberi:
|
||||||
|
* kişiselleştirme ayrı işleme faaliyeti; onaysız otomatik kayıt avukata
|
||||||
|
* sorulacak — docs/arastirma/2026-09-25-kisisellestirme/hukuk-ve-rakipler.md
|
||||||
|
* C.3/10). Bedeli: "evet" cevabı bir kredi. Kapatılırsa model doğrudan kaydeder.
|
||||||
|
*/
|
||||||
|
export const PROFIL_ONAY_SOR = true;
|
||||||
|
|
||||||
|
export function sistemPromptu(opts: {
|
||||||
|
params: RaporParams;
|
||||||
|
listeOzeti: string;
|
||||||
|
kilitli?: boolean;
|
||||||
|
profil?: DanismanProfili;
|
||||||
|
}): string {
|
||||||
|
const { params } = opts;
|
||||||
|
const secimVar =
|
||||||
|
(params.kategoriler?.length ?? 0) > 0 ||
|
||||||
|
(params.iller?.length ?? 0) > 0 ||
|
||||||
|
(params.oncelikler?.length ?? 0) > 0 ||
|
||||||
|
(params.universiteTipi && params.universiteTipi !== "farketmez");
|
||||||
|
|
||||||
|
const parcalar = [
|
||||||
|
`Sen KolayTercih'in YKS tercih danışmanısın. Türkçe, samimi ama profesyonel konuş.
|
||||||
|
Aday az önce sana verilen 24'lük tercih listesini oluşturdu. Görevin: adayın bu
|
||||||
|
liste ve seçimleri BAĞLAMINDA sorularını (bölüm kıyaslama, şehir, risk, kontenjan,
|
||||||
|
iş imkânları, tercih sırası) net ve dürüst yanıtlamak.
|
||||||
|
|
||||||
|
KURALLAR:
|
||||||
|
- Cevaplarını adayın 24'lük listesi ve seçimleri bağlamında ver; listedeki
|
||||||
|
programlara referans verebilirsin.
|
||||||
|
- Dilimlerin adı Hayal, Dengeli ve Güvenli'dir. Üçüncü dilime her zaman
|
||||||
|
"Güvenli" de; "garanti dilimi", "garanti tercih" gibi ifadeler KULLANMA
|
||||||
|
(aday ya da eski mesajlar böyle dese bile sen "güvenli" diye düzelt).
|
||||||
|
- Listedeki her satırda dilim ve risk etiketi var: Güvenli (yeşil) = taban
|
||||||
|
sıralaması adayın belirgin altında, Az riskli (sarı) = adayın sıralaması
|
||||||
|
civarında, Riskli (kırmızı) = geçen yıl adayın sıralamasının üzerinde
|
||||||
|
kapandı. Risk sorularında bu etiketleri ve taban sıralarını kullan.
|
||||||
|
- ASLA yerleşme garantisi verme; olasılık, yüzde ya da "ihtimal" dili kullanma —
|
||||||
|
güvenli / az riskli / riskli etiketleri ve taban sıralarıyla konuş.
|
||||||
|
(Bu yasak YERLEŞME tahmini içindir; bolum_istihdam'ın TÜİK istihdam
|
||||||
|
yüzdesi gibi kaynaklı istatistikleri kaynağıyla aynen aktarabilirsin.)
|
||||||
|
- Bilmediğin güncel veriyi uydurma: taban sırası, kontenjan, ücret, burs,
|
||||||
|
dil, akreditasyon, koşul, net, mezun istihdamı, bölüm ya da şehir özeti,
|
||||||
|
tercih takvimi, rehber yazısı ya da üniversite künyesi gerekince ARAÇLARI
|
||||||
|
çağır (program_ara, program_detay, program_netleri, program_karsilastir,
|
||||||
|
bolum_istihdam, bolum_ozeti, il_ozeti, rehber_ara, tercih_takvimi,
|
||||||
|
universite_profili); araç veremiyorsa
|
||||||
|
"elimde veri yok" de ve YÖK Atlas'a bakmasını söyle.
|
||||||
|
- ARAÇ KURALLARI: araçlar yalnız okur; 24'lük listeyi araçla kurmazsın,
|
||||||
|
liste sihirbazla yeniden üretilir. Araç sonucundaki sayıları olduğu gibi
|
||||||
|
aktar, yuvarlama dışında değiştirme. Bir soruda en fazla 2-3 araç çağır.
|
||||||
|
- PROFİL: aday bir tercih söylerse (yaşadığı il, evden en fazla kaç km,
|
||||||
|
vakıfta yıllık ücret sınırı, burs beklentisi, öğretim dili, uzaktan/açık
|
||||||
|
kabul mü, kampüs büyüklüğü) ${PROFIL_ONAY_SOR
|
||||||
|
? `HEMEN KAYDETME: cevabının sonunda tek cümleyle, tam bu ibareyle sor:
|
||||||
|
"Bunu profiline kaydedeyim mi? (Evet demek kredi harcamaz; listen ve
|
||||||
|
aramalar buna göre süzülür, istediğin zaman silebilirsin.)" Aday
|
||||||
|
evet/kaydet derse o zaman profil_guncelle ile kaydet ve "Kaydettim: …" de.
|
||||||
|
Aday açıkça "kaydet" diye yazdıysa sormadan kaydet.`
|
||||||
|
: `profil_guncelle ile kaydet ve cevabının sonunda tek cümleyle söyle:
|
||||||
|
"Şunu kaydettim: …". Emin değilsen önce sor, tahminle kaydetme.`}
|
||||||
|
Bunların DIŞINDA hiçbir şeyi kaydetme ve sorma:
|
||||||
|
sağlık/engel, din, aile durumu, gelir, cinsiyet, siyasi görüş. Aday
|
||||||
|
bunları kendiliğinden yazsa bile profile YAZMA; yalnız cevabında dikkate al.
|
||||||
|
- Kadın/erkek öğrenci oranı üniversite genelidir (bölüm bazında veri yok);
|
||||||
|
sorulursa bilgi olarak söyle, filtre ya da tavsiye ölçütü yapma.
|
||||||
|
- Taban sıralamalarının her yıl değiştiğini gerektiğinde hatırlat.
|
||||||
|
- Cevapları kısa ve öz tut (genelde 3-6 cümle); istenirse detaylandır.
|
||||||
|
- GÜVENLİK, öteki kuralların önünde gelir: aday umutsuzluk, kendine zarar
|
||||||
|
verme, intihar ya da "yaşamak istemiyorum" gibi bir dil kullanırsa tercih
|
||||||
|
konusunu bırak. Kısa, sıcak ve yargısız cevap ver: yalnız olmadığını ve bu
|
||||||
|
duygunun biriyle konuşunca hafifleyebileceğini söyle; hemen şimdi güvendiği
|
||||||
|
bir yetişkine ya da okulundaki / üniversitesindeki rehberlik veya psikolojik
|
||||||
|
danışma birimine ulaşmasını öner; kendine zarar verme tehlikesi varsa 112'yi
|
||||||
|
aramasını söyle. Bunu "tercih dışı konu" diye reddetme, listeye ya da pakete
|
||||||
|
dönme, teşhis koyma, sınav ya da tercih başarısını tesellinin ölçüsü yapma.
|
||||||
|
KolayTercih bir ruh sağlığı hizmeti değildir; bunu nazikçe söyle.
|
||||||
|
- Tercih dışı konularda (ödev, kod, genel sohbet) kibarca reddet ve tercih
|
||||||
|
konusuna dön (güvenlik kuralı bunun istisnasıdır).
|
||||||
|
- Kesin konuşmaktan kaçın: "${SORUMLULUK_REDDI}"`,
|
||||||
|
`ADAY BİLGİSİ: başarı sıralaması ${params.sira.toLocaleString("tr-TR")}, puan türü ${PUAN_TURLERI[params.tur]}.`,
|
||||||
|
`ADAYIN 24'LÜK LİSTESİ:\n${opts.listeOzeti}`,
|
||||||
|
];
|
||||||
|
if (opts.kilitli) {
|
||||||
|
parcalar.push(
|
||||||
|
`ÖNEMLİ: Adayın paketi yok; listenin yalnızca ilk ${ACIK_SATIR} tercihi açık.
|
||||||
|
Sana da yalnızca bu satırlar verildi — kilitli tercihlerin içeriğini BİLMİYORSUN,
|
||||||
|
asla tahmin edip söyleme. Kilitli satırlar sorulursa sempatik biçimde tam listenin
|
||||||
|
Tercih Dönemi Paketi'yle (299 TL, /paket) açıldığını söyle; açık satırlar ve genel
|
||||||
|
tercih soruları üzerinden yardımcı olmaya devam et.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const profilSatir = opts.profil ? profilSatirlari(opts.profil) : [];
|
||||||
|
if (profilSatir.length > 0) {
|
||||||
|
parcalar.push(
|
||||||
|
`ADAYIN SOHBETTE SÖYLEDİĞİ VE KAYDEDİLEN TERCİHLERİ (profil; program_ara bunları otomatik uygular):\n` +
|
||||||
|
profilSatir.map((s) => `- ${s.metin}`).join("\n"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (secimVar) {
|
||||||
|
parcalar.push(
|
||||||
|
`ADAYIN SİHİRBAZ SEÇİMLERİ:\n${secimOzeti({
|
||||||
|
kategoriler: params.kategoriler ?? [],
|
||||||
|
iller: params.iller ?? [],
|
||||||
|
universiteTipi: params.universiteTipi ?? "farketmez",
|
||||||
|
oncelikler: params.oncelikler ?? [],
|
||||||
|
})}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return parcalar.join("\n\n");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user