From 08f4ec22b0f3d0d4bce7f169dc53dd4e279e1d45 Mon Sep 17 00:00:00 2001 From: bilalgursen Date: Mon, 5 Oct 2026 01:05:19 +0300 Subject: [PATCH] =?UTF-8?q?fix(danisman):=20M3=20(7)=20=E2=80=94=20modele?= =?UTF-8?q?=20giden=20pencere=20tutarl=C4=B1=20olsun?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cevapsız kalmış (iade edilmiş) sorular art arda user mesajı olarak, sayıyla kesilen pencere de danışman mesajıyla başlayarak gidiyordu. modelPenceresi baştaki danışman mesajlarını atar, art arda aynı rolü tek mesajda birleştirir. Pencere sorgusuna rowid sıralaması eklendi (created_at saniye çözünürlüklü). Co-Authored-By: Claude Fable 5.1 --- src/app/api/soru/route.ts | 15 ++++++--------- src/lib/ai/sohbet-gecmisi.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 src/lib/ai/sohbet-gecmisi.ts diff --git a/src/app/api/soru/route.ts b/src/app/api/soru/route.ts index 592dc61..1aeba7a 100644 --- a/src/app/api/soru/route.ts +++ b/src/app/api/soru/route.ts @@ -1,4 +1,4 @@ -import { eq, desc } from "drizzle-orm"; +import { eq, desc, sql } from "drizzle-orm"; import type { NextRequest } from "next/server"; import { getSession } from "@/lib/session"; import { appDb, schema } from "@/lib/appdb"; @@ -14,6 +14,7 @@ import { kullanicininRaporu, sohbetGecmisiGetir } from "@/features/rapor/rapor-q import type { AracBaglami } from "@/lib/ai/araclar"; import { danismanAkisi } from "@/lib/ai/sohbet-akisi"; import { sistemPromptu } from "@/lib/ai/danisman-prompt"; +import { modelPenceresi } from "@/lib/ai/sohbet-gecmisi"; import { profilGetir } from "@/lib/danisman-profil-db"; import { listeOzetiCikar } from "@/lib/ai/rapor"; import type { RaporSonuc } from "@/features/rapor/types/rapor"; @@ -109,7 +110,7 @@ export async function POST(request: NextRequest) { .select() .from(schema.chatMessages) .where(eq(schema.chatMessages.userId, session.user.id)) - .orderBy(desc(schema.chatMessages.createdAt)) + .orderBy(desc(schema.chatMessages.createdAt), sql`rowid DESC`) .limit(MAX_GECMIS), appDb.query.user.findFirst({ where: eq(schema.user.id, session.user.id), @@ -234,13 +235,9 @@ export async function POST(request: NextRequest) { ); } - const mesajlar = [ - ...gecmis.map((m) => ({ - role: m.role as "user" | "assistant", - content: m.content, - })), - { role: "user" as const, content: mesaj }, - ]; + // Cevapsız kalmış (iade edilmiş) sorular ve danışmanla başlayan pencere + // modele bozuk sıra göndermesin + const mesajlar = modelPenceresi(gecmis, mesaj); const userId = session.user.id; const cevabiKaydet = (metin: string) => diff --git a/src/lib/ai/sohbet-gecmisi.ts b/src/lib/ai/sohbet-gecmisi.ts new file mode 100644 index 0000000..5f45e1f --- /dev/null +++ b/src/lib/ai/sohbet-gecmisi.ts @@ -0,0 +1,29 @@ +/** + * Danışman sohbet geçmişinin saf kuralları (api/soru/route.ts kullanır). + * + * Saf modül: DB'ye ve oturuma dokunmaz, Next dışından da çalışır. + */ + +export type SohbetMesaji = { role: "user" | "assistant"; content: string }; + +/** + * Modele giden mesaj penceresi: kayıtlı geçmiş + yeni soru. Kayıt her zaman + * soru-cevap çifti değildir — hata/iade sonrası kullanıcı mesajı cevapsız + * kalır, pencere de sayıyla kesildiği için danışman mesajıyla başlayabilir. + * Burada düzeltilir: baştaki danışman mesajları atılır, art arda aynı rolden + * gelenler tek mesajda birleşir (yinelenen metin bir kez yazılır). Sonuç + * hep user ile başlar, roller sırayla değişir ve yeni soruyla biter. + */ +export function modelPenceresi(gecmis: SohbetMesaji[], yeniSoru: string): SohbetMesaji[] { + const gruplar: { role: SohbetMesaji["role"]; parcalar: string[] }[] = []; + for (const m of [...gecmis, { role: "user" as const, content: yeniSoru }]) { + const son = gruplar.at(-1); + if (!son && m.role === "assistant") continue; + if (son?.role === m.role) { + if (!son.parcalar.includes(m.content)) son.parcalar.push(m.content); + } else { + gruplar.push({ role: m.role, parcalar: [m.content] }); + } + } + return gruplar.map((g) => ({ role: g.role, content: g.parcalar.join("\n\n") })); +}