Switch AI to gpt-4.1-nano + add OpenAI key
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
This commit is contained in:
@@ -2,15 +2,27 @@ import { NextRequest, NextResponse } from "next/server"
|
|||||||
import prisma from "@/lib/prisma"
|
import prisma from "@/lib/prisma"
|
||||||
import { getUser } from "@/lib/session"
|
import { getUser } from "@/lib/session"
|
||||||
|
|
||||||
const GEMINI_KEY = process.env.GEMINI_API_KEY
|
|
||||||
const OPENAI_KEY = process.env.OPENAI_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<string> {
|
async function chat(messages: Array<{ role: string; content: string }>, maxTokens = 600): Promise<string> {
|
||||||
if (!HAS_AI) return ""
|
if (!HAS_AI) return ""
|
||||||
|
|
||||||
// Prefer Gemini (free), fall back to OpenAI
|
// Prefer OpenAI (gpt-4.1-nano), fall back to Gemini
|
||||||
if (GEMINI_KEY) {
|
if (OPENAI_KEY) {
|
||||||
|
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: OPENAI_MODEL, messages, max_tokens: maxTokens, temperature: 0.8 }),
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
return data.choices?.[0]?.message?.content || ""
|
||||||
|
} catch { return "" }
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const systemMsg = messages.find(m => m.role === "system")?.content || ""
|
const systemMsg = messages.find(m => m.role === "system")?.content || ""
|
||||||
const contents = messages.filter(m => m.role !== "system").map(m => ({
|
const contents = messages.filter(m => m.role !== "system").map(m => ({
|
||||||
@@ -32,17 +44,6 @@ async function chat(messages: Array<{ role: string; content: string }>, maxToken
|
|||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
return data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
return data.candidates?.[0]?.content?.parts?.[0]?.text || ""
|
||||||
} catch { return "" }
|
} 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 data = await res.json()
|
|
||||||
return data.choices?.[0]?.message?.content || ""
|
|
||||||
} catch { return "" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
* Falls back to smart heuristics when no API key is set
|
* 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 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 {
|
interface ChatMessage {
|
||||||
role: "system" | "user" | "assistant"
|
role: "system" | "user" | "assistant"
|
||||||
@@ -16,9 +17,9 @@ interface ChatMessage {
|
|||||||
async function chat(messages: ChatMessage[], maxTokens = 300): Promise<string> {
|
async function chat(messages: ChatMessage[], maxTokens = 300): Promise<string> {
|
||||||
if (!HAS_AI) return ""
|
if (!HAS_AI) return ""
|
||||||
|
|
||||||
// Prefer Gemini (free), fall back to OpenAI
|
// Prefer OpenAI (gpt-4.1-nano), fall back to Gemini
|
||||||
if (GEMINI_KEY) return chatGemini(messages, maxTokens)
|
if (OPENAI_KEY) return chatOpenAI(messages, maxTokens)
|
||||||
return chatOpenAI(messages, maxTokens)
|
return chatGemini(messages, maxTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chatGemini(messages: ChatMessage[], maxTokens: number): Promise<string> {
|
async function chatGemini(messages: ChatMessage[], maxTokens: number): Promise<string> {
|
||||||
@@ -63,7 +64,7 @@ async function chatOpenAI(messages: ChatMessage[], maxTokens: number): Promise<s
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${OPENAI_KEY}`,
|
Authorization: `Bearer ${OPENAI_KEY}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ model: "gpt-4o-mini", messages, max_tokens: maxTokens, temperature: 0.7 }),
|
body: JSON.stringify({ model: OPENAI_MODEL, messages, max_tokens: maxTokens, temperature: 0.7 }),
|
||||||
})
|
})
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
return data.choices?.[0]?.message?.content || ""
|
return data.choices?.[0]?.message?.content || ""
|
||||||
|
|||||||
Reference in New Issue
Block a user