diff --git a/server/ai.mjs b/server/ai.mjs index a8095d4..f7a06fd 100644 --- a/server/ai.mjs +++ b/server/ai.mjs @@ -16,6 +16,12 @@ const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'; export const PROVIDERS = { + glmflash: { + label: 'GLM 5.3 Flash', provider: 'Z.ai', envKey: 'ZAI_API_KEY', + model: () => process.env.GLM_FLASH_MODEL || 'glm-5.3-flash', + or: () => process.env.GLM_FLASH_OR_MODEL || 'z-ai/glm-5.3-flash', + url: 'https://api.z.ai/api/paas/v4/chat/completions', style: 'openai', + }, glm: { label: 'GLM', provider: 'Z.ai', envKey: 'ZAI_API_KEY', model: () => process.env.GLM_MODEL || 'glm-5.3', @@ -213,7 +219,7 @@ function extractJson(raw) { /** Zinciri sırayla dener; ilk başarılı sonucu döndürür. */ export async function analyzeSpec({ text, fileName, tender, chain }) { - const order = (Array.isArray(chain) && chain.length ? chain : ['glm', 'deepseek', 'gemini', 'grok', 'gpt', 'claude']) + const order = (Array.isArray(chain) && chain.length ? chain : ['glmflash', 'glm', 'deepseek', 'gemini', 'grok', 'gpt', 'claude']) .filter((id) => PROVIDERS[id]); const userPrompt = buildUserPrompt({ text, fileName, tender }); const attempts = []; diff --git a/src/context/AppContext.jsx b/src/context/AppContext.jsx index 0fe370c..3d61842 100644 --- a/src/context/AppContext.jsx +++ b/src/context/AppContext.jsx @@ -192,6 +192,7 @@ export const AppProvider = ({ children }) => { // AI Model Yönetimi (admin panelden seçilebilir + fallback zinciri) // --------------------------------------------------------------------------- const AI_MODEL_CATALOG = [ + { id: 'glmflash', label: 'GLM 5.3 Flash', provider: 'Z.ai', or: 'z-ai/glm-5.3-flash', model: 'glm-5.3-flash', renk: 'blue' }, { id: 'glm', label: 'GLM Latest', provider: 'Z.ai', or: '~z-ai/glm-latest', model: 'glm-5.3', renk: 'blue' }, { id: 'deepseek', label: 'DeepSeek V4 Flash Latest', provider: 'DeepSeek', or: '~deepseek/deepseek-v4-flash-latest', model: 'deepseek-chat', renk: 'indigo' }, { id: 'gemini', label: 'Gemini Flash Latest', provider: 'Google', or: '~google/gemini-flash-latest', model: 'gemini-flash-latest', renk: 'amber' }, @@ -200,13 +201,24 @@ export const AppProvider = ({ children }) => { { id: 'claude', label: 'Claude Opus Latest', provider: 'Anthropic', or: '~anthropic/claude-opus-latest', model: 'claude-opus-5', renk: 'orange' } ]; - // Varsayılan fallback zinciri: GLM (birincil) → DeepSeek → Gemini + // Varsayılan fallback zinciri: GLM 5.3 Flash (birincil) → GLM Latest → DeepSeek → Gemini + const VARSAYILAN_ZINCIR = ['glmflash', 'glm', 'deepseek', 'gemini']; + const ZINCIR_SURUM = 2; // artırıldığında kayıtlı zincire yeni birincil eklenir + const [aiModelConfig, setAiModelConfig] = useState(() => { const saved = localStorage.getItem('ihaleist_ai_model_config'); if (saved) { - try { return JSON.parse(saved); } catch { /* yoksay */ } + try { + const cfg = JSON.parse(saved); + // Geçiş: yeni birincil model eklendiyse kayıtlı zincirin başına al + if ((cfg.surum || 1) < ZINCIR_SURUM) { + const chain = Array.isArray(cfg.chain) ? cfg.chain : []; + return { ...cfg, surum: ZINCIR_SURUM, chain: ['glmflash', ...chain.filter((id) => id !== 'glmflash')] }; + } + return cfg; + } catch { /* yoksay */ } } - return { chain: ['glm', 'deepseek', 'gemini'] }; + return { chain: VARSAYILAN_ZINCIR, surum: ZINCIR_SURUM }; }); useEffect(() => {