From d5347d47a17797ccd0baae835693c37e5a757318 Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Thu, 5 Mar 2026 01:01:24 +0800 Subject: [PATCH] Switch AI to gpt-4.1-nano + add OpenAI key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model: gpt-4.1-nano (~$0.10/1M input, $0.40/1M output) Priority: OpenAI (nano) → Gemini Flash (fallback) Both keys now in server docker-compose.yml --- .../src/app/api/automations/ai/route.ts | 57 ++++++++++--------- pledge-now-pay-later/src/lib/ai.ts | 13 +++-- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/pledge-now-pay-later/src/app/api/automations/ai/route.ts b/pledge-now-pay-later/src/app/api/automations/ai/route.ts index ae6bef4..85140d3 100644 --- a/pledge-now-pay-later/src/app/api/automations/ai/route.ts +++ b/pledge-now-pay-later/src/app/api/automations/ai/route.ts @@ -2,46 +2,47 @@ import { NextRequest, NextResponse } from "next/server" import prisma from "@/lib/prisma" import { getUser } from "@/lib/session" -const GEMINI_KEY = process.env.GEMINI_API_KEY const OPENAI_KEY = process.env.OPENAI_API_KEY -const HAS_AI = !!(GEMINI_KEY || OPENAI_KEY) +const GEMINI_KEY = process.env.GEMINI_API_KEY +const HAS_AI = !!(OPENAI_KEY || GEMINI_KEY) +const OPENAI_MODEL = "gpt-4.1-nano" async function chat(messages: Array<{ role: string; content: string }>, maxTokens = 600): Promise { if (!HAS_AI) return "" - // Prefer Gemini (free), fall back to OpenAI - if (GEMINI_KEY) { + // Prefer OpenAI (gpt-4.1-nano), fall back to Gemini + if (OPENAI_KEY) { try { - const systemMsg = messages.find(m => m.role === "system")?.content || "" - const contents = messages.filter(m => m.role !== "system").map(m => ({ - role: m.role === "assistant" ? "model" : "user", - parts: [{ text: m.content }], - })) - const res = await fetch( - `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_KEY}`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - systemInstruction: systemMsg ? { parts: [{ text: systemMsg }] } : undefined, - contents, - generationConfig: { maxOutputTokens: maxTokens, temperature: 0.8 }, - }), - } - ) + const res = await fetch("https://api.openai.com/v1/chat/completions", { + method: "POST", + headers: { "Content-Type": "application/json", Authorization: `Bearer ${OPENAI_KEY}` }, + body: JSON.stringify({ model: OPENAI_MODEL, messages, max_tokens: maxTokens, temperature: 0.8 }), + }) const data = await res.json() - return data.candidates?.[0]?.content?.parts?.[0]?.text || "" + return data.choices?.[0]?.message?.content || "" } catch { return "" } } try { - const res = await fetch("https://api.openai.com/v1/chat/completions", { - method: "POST", - headers: { "Content-Type": "application/json", Authorization: `Bearer ${OPENAI_KEY}` }, - body: JSON.stringify({ model: "gpt-4o-mini", messages, max_tokens: maxTokens, temperature: 0.8 }), - }) + const systemMsg = messages.find(m => m.role === "system")?.content || "" + const contents = messages.filter(m => m.role !== "system").map(m => ({ + role: m.role === "assistant" ? "model" : "user", + parts: [{ text: m.content }], + })) + const res = await fetch( + `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_KEY}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + systemInstruction: systemMsg ? { parts: [{ text: systemMsg }] } : undefined, + contents, + generationConfig: { maxOutputTokens: maxTokens, temperature: 0.8 }, + }), + } + ) const data = await res.json() - return data.choices?.[0]?.message?.content || "" + return data.candidates?.[0]?.content?.parts?.[0]?.text || "" } catch { return "" } } diff --git a/pledge-now-pay-later/src/lib/ai.ts b/pledge-now-pay-later/src/lib/ai.ts index 0f7815c..0e76758 100644 --- a/pledge-now-pay-later/src/lib/ai.ts +++ b/pledge-now-pay-later/src/lib/ai.ts @@ -4,9 +4,10 @@ * Falls back to smart heuristics when no API key is set */ -const GEMINI_KEY = process.env.GEMINI_API_KEY const OPENAI_KEY = process.env.OPENAI_API_KEY -const HAS_AI = !!(GEMINI_KEY || OPENAI_KEY) +const GEMINI_KEY = process.env.GEMINI_API_KEY +const HAS_AI = !!(OPENAI_KEY || GEMINI_KEY) +const OPENAI_MODEL = "gpt-4.1-nano" // ~$0.10/1M input, ~$0.40/1M output interface ChatMessage { role: "system" | "user" | "assistant" @@ -16,9 +17,9 @@ interface ChatMessage { async function chat(messages: ChatMessage[], maxTokens = 300): Promise { if (!HAS_AI) return "" - // Prefer Gemini (free), fall back to OpenAI - if (GEMINI_KEY) return chatGemini(messages, maxTokens) - return chatOpenAI(messages, maxTokens) + // Prefer OpenAI (gpt-4.1-nano), fall back to Gemini + if (OPENAI_KEY) return chatOpenAI(messages, maxTokens) + return chatGemini(messages, maxTokens) } async function chatGemini(messages: ChatMessage[], maxTokens: number): Promise { @@ -63,7 +64,7 @@ async function chatOpenAI(messages: ChatMessage[], maxTokens: number): Promise