- src/lib/ai/araclar.ts: OpenAI uyumlu 4 araç; sorgu araçları yalnız okur (yokatlas.db + program_ozellik + YÖK İstatistik + URAP), sayı uydurma yok. profil_guncelle yalnız 7 tanımlı alanı yazar (evIl, maxKm, ucretUst, burs, dil, ogretimTuru, kampus); sağlık/din/gelir/cinsiyet şemada yok (KVKK §8). Profil süzgeci sonucu sıfırlarsa profilsiz tekrar denenip modele söylenir. - src/lib/ai/cagri.ts: sohbetAkisiAraclarla — stream'de tool_calls biriktirme, en fazla 4 tur, son tur araç kapalı; sağlayıcı reddederse düz sohbete düşer. - src/lib/danisman-profil.ts (saf şema + metinler), danisman-profil-db.ts, drizzle 0005 danisman_profil tablosu, /api/soru/profil GET+DELETE. - /api/soru: profil prompt'a girer, araç kuralları eklendi. - Sohbet başlığı altında 'Kaydettiklerim' çipleri (tek tıkla sil); listem sayfası profili sunucudan indirir. Analitiğe yalnız alan adı gider. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
import "server-only";
|
||
import { eq } from "drizzle-orm";
|
||
import { appDb, schema } from "@/lib/appdb";
|
||
import {
|
||
PROFIL_SEMASI,
|
||
profilTemizle,
|
||
type DanismanProfili,
|
||
type ProfilAlani,
|
||
} from "@/lib/danisman-profil";
|
||
|
||
/** Kullanıcının danışman profili; satır yoksa boş nesne. Bozuk alanlar düşer. */
|
||
export async function profilGetir(userId: string): Promise<DanismanProfili> {
|
||
const satir = await appDb.query.danismanProfil.findFirst({
|
||
where: eq(schema.danismanProfil.userId, userId),
|
||
columns: { alanlar: true },
|
||
});
|
||
return profilTemizle(satir?.alanlar);
|
||
}
|
||
|
||
/**
|
||
* Tek alanı yazar (deger null → alan silinir). Değer şemadan geçmezse hata
|
||
* fırlatır; çağıran taraf (araç) bunu modele "kaydedilmedi" diye döner.
|
||
*/
|
||
export async function profilAlanYaz(
|
||
userId: string,
|
||
alan: ProfilAlani,
|
||
deger: unknown,
|
||
): Promise<DanismanProfili> {
|
||
const mevcut = await profilGetir(userId);
|
||
const yeni: Record<string, unknown> = { ...mevcut };
|
||
if (deger === null || deger === undefined) {
|
||
delete yeni[alan];
|
||
} else {
|
||
const dogrulama = PROFIL_SEMASI.shape[alan].safeParse(deger);
|
||
if (!dogrulama.success) {
|
||
throw new Error(`Geçersiz değer: ${alan}`);
|
||
}
|
||
yeni[alan] = dogrulama.data;
|
||
}
|
||
const alanlar = PROFIL_SEMASI.parse(yeni);
|
||
const now = new Date();
|
||
await appDb
|
||
.insert(schema.danismanProfil)
|
||
.values({ userId, alanlar, updatedAt: now })
|
||
.onConflictDoUpdate({
|
||
target: schema.danismanProfil.userId,
|
||
set: { alanlar, updatedAt: now },
|
||
});
|
||
return alanlar;
|
||
}
|
||
|
||
export async function profilSil(userId: string): Promise<void> {
|
||
await appDb
|
||
.delete(schema.danismanProfil)
|
||
.where(eq(schema.danismanProfil.userId, userId));
|
||
}
|