Update Next.js configuration and package dependencies
All checks were successful
Deploy / deploy (push) Successful in 9m29s

- Modified redirects in next.config.ts to change the destination for "/sohbet" to "/listem".
- Added new dependencies in package.json: marked, motion, react-markdown, remark-breaks, remark-gfm, shiki, and use-stick-to-bottom.
- Updated pnpm-lock.yaml to reflect the new package versions and dependencies.
- Removed obsolete stack files for Flutter, Nuxt, Nuxt.js, React Native, and Svelte from the UI/UX Pro Max skill data.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-07-26 04:26:52 +03:00
parent 1d0328d8eb
commit 209d203fe8
59 changed files with 6599 additions and 1446 deletions

View File

@@ -8,11 +8,16 @@ import { listeOzetiCikar, type RaporSonuc } from "@/lib/ai/rapor";
import type { RaporParams } from "@/lib/rapor-havuzu";
import { secimOzeti } from "@/lib/sihirbaz";
import { PUAN_TURLERI } from "@/lib/db";
import { ACIK_SATIR } from "@/lib/rapor-maske";
const MAX_GECMIS = 12;
const MAX_MESAJ_UZUNLUK = 2000;
function sistemPromptu(opts: { params: RaporParams; listeOzeti: string }): string {
function sistemPromptu(opts: {
params: RaporParams;
listeOzeti: string;
kilitli?: boolean;
}): string {
const { params } = opts;
const secimVar =
(params.kategoriler?.length ?? 0) > 0 ||
@@ -29,6 +34,10 @@ 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.
- 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; "yüksek/orta/düşük ihtimal" dili kullan.
- Bilmediğin güncel veriyi uydurma; emin değilsen YÖK Atlas'a bakmasını söyle.
- Taban sıralamalarının her yıl değiştiğini gerektiğinde hatırlat.
@@ -39,6 +48,15 @@ KURALLAR:
`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.`,
);
}
if (secimVar) {
parcalar.push(
`ADAYIN SİHİRBAZ SEÇİMLERİ:\n${secimOzeti({
@@ -140,11 +158,67 @@ export async function POST(request: NextRequest) {
}
const kullaniciMesajId = harcama.messageId!;
// Paketsiz kullanıcının prompt'una yalnızca açık satırlar girer — aksi
// halde danışman kilitli listeyi sözle sızdırabilir.
const kullanici = await appDb.query.user.findFirst({
where: eq(schema.user.id, session.user.id),
columns: { hasPaket: true },
});
const kilitli = !kullanici?.hasPaket;
const tamOzet = listeOzetiCikar(
rapor.result as RaporSonuc,
(rapor.params as RaporParams).sira,
);
const listeOzeti = kilitli
? [
...tamOzet.split("\n").slice(0, ACIK_SATIR),
`… kalan ${24 - ACIK_SATIR} tercih kilitli.`,
].join("\n")
: tamOzet;
const system = sistemPromptu({
params: rapor.params as RaporParams,
listeOzeti: listeOzetiCikar(rapor.result as RaporSonuc),
listeOzeti,
kilitli,
});
// Dev'de API key yoksa danışman mock cevap stream'ler (prod'da asla)
if (
process.env.NODE_ENV !== "production" &&
!process.env.ANTHROPIC_API_KEY &&
!process.env.ANTHROPIC_AUTH_TOKEN
) {
const mockEncoder = new TextEncoder();
const mockUserId = session.user.id;
const cevap =
`(Dev mock — ANTHROPIC_API_KEY tanımlı değil.) Sorunu aldım: "${mesaj.slice(0, 120)}". ` +
`Gerçek danışman burada listen ve seçimlerin bağlamında yanıt verecek. ` +
`${SORUMLULUK_REDDI}`;
const mockReadable = new ReadableStream({
async start(controller) {
for (const parca of cevap.split(/(?<= )/)) {
controller.enqueue(mockEncoder.encode(parca));
await new Promise((r) => setTimeout(r, 25));
}
await appDb.insert(schema.chatMessages).values({
id: crypto.randomUUID(),
userId: mockUserId,
role: "assistant",
content: cevap,
createdAt: new Date(),
});
controller.close();
},
});
return new Response(mockReadable, {
headers: {
"Content-Type": "text/plain; charset=utf-8",
"X-Content-Type-Options": "nosniff",
"Cache-Control": "no-store",
},
});
}
let client;
try {
client = getAnthropic();