AI katmanını OpenRouter tek kapısına geçir ve rapor üretimini hızlandır
All checks were successful
Deploy / deploy (push) Successful in 9m30s
All checks were successful
Deploy / deploy (push) Successful in 9m30s
- Tüm AI akışı OpenRouter üzerinden (openai SDK, varsayılan model deepseek/deepseek-v4-flash, OPENROUTER_MODEL ile değiştirilebilir); Anthropic/Gemini/lokal sağlayıcı seçimi ve SDK'ları kaldırıldı. - Rapor: aday havuzu dilim başına 20 (60 program, ~8k token prompt); AI şeması sabit uzunluklu üç liste (hayal 5 / dengeli 13 / garanti 6 — dağılım şema düzeyinde zorlanır), sıra + dilim + riskNotu + trendOzeti gerçek sıra geçmişinden deterministik üretilir; 184 sn → ~12 sn. - Sohbet: akış ortası zaman aşımı artık sessizce yutulmaz (kesik cevap tam cevap gibi kaydedilmiyordu, kredi iadesi çalışmıyordu); istemci hata anında durumu sunucudan senkronlar, boş balon bırakmaz. - aiHataMesaji, openai SDK'nın .name'i "Error" kalan abort/timeout hatalarını da yakalar; meraklisina şeması yeni akışla senkronlandı. - CI: OPENROUTER_API_KEY / OPENROUTER_MODEL secret'ları; eski AI secret'ları kaldırıldı. next.config serverExternalPackages sadeleşti. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,64 +1,52 @@
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
import OpenAI from "openai";
|
||||
|
||||
export type Saglayici = "anthropic" | "gemini";
|
||||
|
||||
/** AI_SAGLAYICI env'i ile seçilir; tanımsızsa hangi anahtar varsa o kullanılır. */
|
||||
export function saglayici(): Saglayici {
|
||||
const secim = process.env.AI_SAGLAYICI?.trim().toLowerCase();
|
||||
if (secim === "gemini" || secim === "anthropic") return secim;
|
||||
return process.env.GEMINI_API_KEY ? "gemini" : "anthropic";
|
||||
}
|
||||
|
||||
/** Seçili sağlayıcının anahtarı tanımlı mı (mock moduna düşülecek mi)? */
|
||||
export function anahtarVar(): boolean {
|
||||
return saglayici() === "gemini"
|
||||
? Boolean(process.env.GEMINI_API_KEY)
|
||||
: Boolean(process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN);
|
||||
}
|
||||
|
||||
// Model seçimi (bilinçli):
|
||||
// Anthropic — rapor tek seferlik ve yüksek değerli -> Opus 4.8;
|
||||
// sohbet kredi başına marj hassas -> Haiku 4.5 (kullanıcı kararı, 22 Tem 2026).
|
||||
// Gemini — ücretsiz katmanda yalnızca Flash ailesi açık (Pro'da kota 0),
|
||||
// bu yüzden rapor ve sohbet aynı modeli kullanır; ayrım thinking seviyesinde.
|
||||
const MODELLER: Record<Saglayici, { rapor: string; sohbet: string }> = {
|
||||
anthropic: { rapor: "claude-opus-4-8", sohbet: "claude-haiku-4-5" },
|
||||
gemini: { rapor: "gemini-3.6-flash", sohbet: "gemini-3.6-flash" },
|
||||
};
|
||||
// Tüm AI akışı OpenRouter üzerinden tek kapıdan gider (kullanıcı kararı,
|
||||
// 7 Ağu 2026 — önceki Anthropic/Gemini/lokal sağlayıcı seçimi kaldırıldı).
|
||||
// Model .env'den değiştirilebilir; rapor ve sohbet istenirse ayrışabilir.
|
||||
const VARSAYILAN_MODEL = "deepseek/deepseek-v4-flash";
|
||||
|
||||
export function raporModeli(): string {
|
||||
return MODELLER[saglayici()].rapor;
|
||||
return (
|
||||
process.env.OPENROUTER_RAPOR_MODEL?.trim() ||
|
||||
process.env.OPENROUTER_MODEL?.trim() ||
|
||||
VARSAYILAN_MODEL
|
||||
);
|
||||
}
|
||||
|
||||
export function sohbetModeli(): string {
|
||||
return MODELLER[saglayici()].sohbet;
|
||||
return (
|
||||
process.env.OPENROUTER_SOHBET_MODEL?.trim() ||
|
||||
process.env.OPENROUTER_MODEL?.trim() ||
|
||||
VARSAYILAN_MODEL
|
||||
);
|
||||
}
|
||||
|
||||
const globalForAi = globalThis as unknown as {
|
||||
__anthropic?: Anthropic;
|
||||
__gemini?: GoogleGenAI;
|
||||
};
|
||||
|
||||
export function getAnthropic(): Anthropic {
|
||||
if (!process.env.ANTHROPIC_API_KEY && !process.env.ANTHROPIC_AUTH_TOKEN) {
|
||||
throw new Error("AI_KEY_MISSING");
|
||||
}
|
||||
if (!globalForAi.__anthropic) {
|
||||
globalForAi.__anthropic = new Anthropic();
|
||||
}
|
||||
return globalForAi.__anthropic;
|
||||
/** API anahtarı tanımlı mı (mock moduna düşülecek mi)? */
|
||||
export function anahtarVar(): boolean {
|
||||
return Boolean(process.env.OPENROUTER_API_KEY);
|
||||
}
|
||||
|
||||
export function getGemini(): GoogleGenAI {
|
||||
const apiKey = process.env.GEMINI_API_KEY;
|
||||
const globalForAi = globalThis as unknown as { __openrouter?: OpenAI };
|
||||
|
||||
export function getOpenRouter(): OpenAI {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("AI_KEY_MISSING");
|
||||
}
|
||||
if (!globalForAi.__gemini) {
|
||||
globalForAi.__gemini = new GoogleGenAI({ apiKey });
|
||||
if (!globalForAi.__openrouter) {
|
||||
globalForAi.__openrouter = new OpenAI({
|
||||
baseURL: "https://openrouter.ai/api/v1",
|
||||
apiKey,
|
||||
// Tek retry otoritesi cagri.ts'teki geciciHatadaTekrarla
|
||||
maxRetries: 0,
|
||||
// OpenRouter panelindeki kullanım dökümünde uygulama atfı (opsiyonel)
|
||||
defaultHeaders: {
|
||||
"HTTP-Referer": "https://kolaytercih.com",
|
||||
"X-Title": "KolayTercih",
|
||||
},
|
||||
});
|
||||
}
|
||||
return globalForAi.__gemini;
|
||||
return globalForAi.__openrouter;
|
||||
}
|
||||
|
||||
export const SORUMLULUK_REDDI =
|
||||
|
||||
Reference in New Issue
Block a user