| | import { NextRequest, NextResponse } from "next/server"; |
| | import { GoogleGenerativeAI } from "@google/generative-ai"; |
| | import { HistoryItem, HistoryPart } from "@/lib/types"; |
| |
|
| | |
| | const GEMINI_API_KEY = process.env.GEMINI_API_KEY || ""; |
| | const genAI = new GoogleGenerativeAI(GEMINI_API_KEY); |
| |
|
| | |
| | const MODEL_ID = "gemini-2.0-flash-exp"; |
| |
|
| | |
| | interface FormattedHistoryItem { |
| | role: "user" | "model"; |
| | parts: Array<{ |
| | text?: string; |
| | inlineData?: { data: string; mimeType: string }; |
| | }>; |
| | } |
| |
|
| | export async function POST(req: NextRequest) { |
| | try { |
| | |
| | const requestData = await req.json(); |
| | const { prompt, image: inputImage, history } = requestData; |
| |
|
| | if (!prompt) { |
| | return NextResponse.json( |
| | { error: "Prompt is required" }, |
| | { status: 400 } |
| | ); |
| | } |
| |
|
| | |
| | const model = genAI.getGenerativeModel({ |
| | model: MODEL_ID, |
| | generationConfig: { |
| | temperature: 1, |
| | topP: 0.95, |
| | topK: 40, |
| | |
| | responseModalities: ["Text", "Image"], |
| | }, |
| | }); |
| |
|
| | let result; |
| |
|
| | try { |
| | |
| | const formattedHistory = |
| | history && history.length > 0 |
| | ? history |
| | .map((item: HistoryItem) => { |
| | return { |
| | role: item.role, |
| | parts: item.parts |
| | .map((part: HistoryPart) => { |
| | if (part.text) { |
| | return { text: part.text }; |
| | } |
| | if (part.image && item.role === "user") { |
| | const imgParts = part.image.split(","); |
| | if (imgParts.length > 1) { |
| | return { |
| | inlineData: { |
| | data: imgParts[1], |
| | mimeType: part.image.includes("image/png") |
| | ? "image/png" |
| | : "image/jpeg", |
| | }, |
| | }; |
| | } |
| | } |
| | return { text: "" }; |
| | }) |
| | .filter((part) => Object.keys(part).length > 0), |
| | }; |
| | }) |
| | .filter((item: FormattedHistoryItem) => item.parts.length > 0) |
| | : []; |
| |
|
| | |
| | const chat = model.startChat({ |
| | history: formattedHistory, |
| | }); |
| |
|
| | |
| | const messageParts = []; |
| |
|
| | |
| | messageParts.push({ text: prompt }); |
| |
|
| | |
| | if (inputImage) { |
| | |
| | console.log("Processing image edit request"); |
| |
|
| | |
| | if (!inputImage.startsWith("data:")) { |
| | throw new Error("Invalid image data URL format"); |
| | } |
| |
|
| | const imageParts = inputImage.split(","); |
| | if (imageParts.length < 2) { |
| | throw new Error("Invalid image data URL format"); |
| | } |
| |
|
| | const base64Image = imageParts[1]; |
| | const mimeType = inputImage.includes("image/png") |
| | ? "image/png" |
| | : "image/jpeg"; |
| | console.log( |
| | "Base64 image length:", |
| | base64Image.length, |
| | "MIME type:", |
| | mimeType |
| | ); |
| |
|
| | |
| | messageParts.push({ |
| | inlineData: { |
| | data: base64Image, |
| | mimeType: mimeType, |
| | }, |
| | }); |
| | } |
| |
|
| | |
| | console.log("Sending message with", messageParts.length, "parts"); |
| | result = await chat.sendMessage(messageParts); |
| | } catch (error) { |
| | console.error("Error in chat.sendMessage:", error); |
| | throw error; |
| | } |
| |
|
| | const response = result.response; |
| |
|
| | let textResponse = null; |
| | let imageData = null; |
| | let mimeType = "image/png"; |
| |
|
| | |
| | if (response.candidates && response.candidates.length > 0) { |
| | const parts = response.candidates[0].content.parts; |
| | console.log("Number of parts in response:", parts.length); |
| |
|
| | for (const part of parts) { |
| | if ("inlineData" in part && part.inlineData) { |
| | |
| | imageData = part.inlineData.data; |
| | mimeType = part.inlineData.mimeType || "image/png"; |
| | console.log( |
| | "Image data received, length:", |
| | imageData.length, |
| | "MIME type:", |
| | mimeType |
| | ); |
| | } else if ("text" in part && part.text) { |
| | |
| | textResponse = part.text; |
| | console.log( |
| | "Text response received:", |
| | textResponse.substring(0, 50) + "..." |
| | ); |
| | } |
| | } |
| | } |
| |
|
| | |
| | return NextResponse.json({ |
| | image: imageData ? `data:${mimeType};base64,${imageData}` : null, |
| | description: textResponse, |
| | }); |
| | } catch (error) { |
| | console.error("Error generating image:", error); |
| | return NextResponse.json( |
| | { |
| | error: "Failed to generate image", |
| | details: error instanceof Error ? error.message : String(error), |
| | }, |
| | { status: 500 } |
| | ); |
| | } |
| | } |
| |
|