import "server-only"; import { desc, eq, sql } from "drizzle-orm"; import { appDb, schema } from "@/lib/appdb"; import { anahtarVar } from "@/lib/ai/client"; import { programOzellikleriGetir } from "@/lib/program-ozellik"; import { varyantEtiketi } from "@/lib/program-varyant"; import type { RaporSonuc } from "./types/rapor"; // Rapor feature'ının sorgu kapısı: kayıtlı rapor, sohbet geçmişi ve girişsiz // tadımlık seçimi buradan okunur. // Girişsiz tadımlık satırı — batch üretilmiş havuzdan seçilir, LLM'e gitmez. export { tadimlikSec } from "@/lib/tadimlik-havuzu"; // Kullanıcının kayıtlı raporunu okuyan TEK kapı. Rapor tablosunu okuyan her // yer (sayfalar, action'lar, soru API'si) buradan geçmeli; doğrudan // appDb.query.reports.findFirst kullanma. // // Neden: dev'de API anahtarı yokken üretilen mock rapor DB'ye kaydediliyor // (akışın tamamı anahtarsız test edilebilsin diye — bilinçli). Ama anahtar // sonradan eklenince kullanıcı başına tek rapor kuralı yüzünden o bayat mock, // gerçek Yapay Zeka çıktısıymış gibi servis edilmeye devam ediyordu. Gerçek AI // aktifken mock üretimi bir rapor "yok" sayılır; kullanıcı yeni (gerçek) // listeyi üretir ve kayıt üzerine yazılır. function bayatMockMu(sonuc: RaporSonuc): boolean { const mockUretimi = sonuc.devMock === true || // devMock alanı eklenmeden önce kaydedilmiş mock raporlar sonuc.genelDegerlendirme?.startsWith("(Dev mock"); if (!mockUretimi) return false; const mockHalaAktif = process.env.NODE_ENV !== "production" && !anahtarVar(); return !mockHalaAktif; } export async function kullanicininRaporu(userId: string) { const satir = await appDb.query.reports.findFirst({ where: eq(schema.reports.userId, userId), }); if (satir?.result && bayatMockMu(satir.result as RaporSonuc)) return null; if (satir?.result) varyantlariEkle(satir.result as RaporSonuc); return satir ?? null; } // Kayıtlı raporun program satırlarına burs/dil/öğretim türü etiketi (okuma // anında, tek sorgu): rapor JSON'u üretim anında bunu taşımıyor, eski // kayıtlar da bu yoldan kazanır. yokatlas.db salt okunur; app.db'ye yazılmaz. function varyantlariEkle(sonuc: RaporSonuc): void { const idler = Object.keys(sonuc.programlar ?? {}); if (idler.length === 0) return; const ozellikler = programOzellikleriGetir(idler); for (const id of idler) { const o = ozellikler[id]; sonuc.programlar[id].varyant = o ? varyantEtiketi(o) : null; } } /** * Kullanıcının danışman sohbet geçmişi: en YENİ 100 mesaj, eskiden yeniye. * created_at saniye çözünürlüklü; aynı saniyedeki soru-cevap sırası rowid ile * korunur. */ export async function sohbetGecmisiGetir(userId: string) { const satirlar = await appDb .select({ id: schema.chatMessages.id, role: schema.chatMessages.role, content: schema.chatMessages.content, meta: schema.chatMessages.meta, }) .from(schema.chatMessages) .where(eq(schema.chatMessages.userId, userId)) .orderBy(desc(schema.chatMessages.createdAt), sql`rowid DESC`) .limit(100); return satirlar.reverse(); }