Enhance error handling and user experience in AI-related features
Some checks failed
Deploy / deploy (push) Failing after 38m47s

- Introduced a mechanism to save partially generated responses in case of errors, ensuring users do not lose their input.
- Updated the RevizyonKutusu component to utilize a persistent request ID for retrying failed requests without double charging credits.
- Improved the Sayfalama component to support client-side pagination without changing the URL, enhancing user navigation.
- Added a timeout for AI generation requests to ensure credits are refunded in case of prolonged processing.
- Refactored various components for better clarity and responsiveness, including updates to the BolumProgramListesi and ListePaneli components.
This commit is contained in:
bilalgursen
2026-08-03 14:12:06 +03:00
parent c2aba25814
commit a5c2bcbc4d
13 changed files with 384 additions and 180 deletions

View File

@@ -61,9 +61,17 @@ async function geciciHatadaTekrarla<T>(
throw sonHata;
}
/**
* Tek yapılandırılmış üretim çağrısının üst süre sınırı. Süre, çağıranın
* (server action) platform limitinden önce dolmalı ki hata iade kodunun
* çalışabildiği pencerede fırlasın — fonksiyon dışarıdan öldürülürse
* harcanan kredi iade edilemiyor.
*/
const URETIM_ZAMAN_ASIMI_MS = 50_000;
/**
* Şemaya uyan tek seferlik çıktı üretir. Şemaya uymayan yanıtta null döner
* (çağıran taraf yeniden dener).
* (çağıran taraf yeniden dener). Zaman aşımında abort hatası fırlar.
*/
export async function yapilandirilmisUret<T extends z.ZodType>(opts: {
system: string;
@@ -71,12 +79,16 @@ export async function yapilandirilmisUret<T extends z.ZodType>(opts: {
sema: T;
maxTokens: number;
}): Promise<z.infer<T> | null> {
// Tek sinyal tüm iç denemeleri kapsar: süre dolunca bekleyen retry'lar da
// anında düşer, toplam süre sınırın üstüne çıkamaz.
const sinyal = AbortSignal.timeout(URETIM_ZAMAN_ASIMI_MS);
if (saglayici() === "gemini") {
const yanit = await geciciHatadaTekrarla(() =>
getGemini().models.generateContent({
model: raporModeli(),
contents: opts.kullanici,
config: {
abortSignal: sinyal,
systemInstruction: opts.system,
maxOutputTokens: opts.maxTokens,
responseMimeType: "application/json",
@@ -95,14 +107,17 @@ export async function yapilandirilmisUret<T extends z.ZodType>(opts: {
}
}
const yanit = await getAnthropic().messages.parse({
model: raporModeli(),
max_tokens: opts.maxTokens,
thinking: { type: "adaptive" },
system: opts.system,
messages: [{ role: "user", content: opts.kullanici }],
output_config: { format: zodOutputFormat(opts.sema) },
});
const yanit = await getAnthropic().messages.parse(
{
model: raporModeli(),
max_tokens: opts.maxTokens,
thinking: { type: "adaptive" },
system: opts.system,
messages: [{ role: "user", content: opts.kullanici }],
output_config: { format: zodOutputFormat(opts.sema) },
},
{ signal: sinyal },
);
return yanit.parsed_output ?? null;
}