File size: 5,687 Bytes
faee5d2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | import { NextRequest, NextResponse } from "next/server";
import { GoogleGenerativeAI } from "@google/generative-ai";
import { HistoryItem, HistoryPart } from "@/lib/types";
// Initialize the Google Gen AI client with your API key
const GEMINI_API_KEY = process.env.GEMINI_API_KEY || "";
const genAI = new GoogleGenerativeAI(GEMINI_API_KEY);
// Define the model ID for Gemini 2.0 Flash experimental
const MODEL_ID = "gemini-2.0-flash-exp";
// Define interface for the formatted history item
interface FormattedHistoryItem {
role: "user" | "model";
parts: Array<{
text?: string;
inlineData?: { data: string; mimeType: string };
}>;
}
export async function POST(req: NextRequest) {
try {
// Parse JSON request instead of FormData
const requestData = await req.json();
const { prompt, image: inputImage, history } = requestData;
if (!prompt) {
return NextResponse.json(
{ error: "Prompt is required" },
{ status: 400 }
);
}
// Get the model with the correct configuration
const model = genAI.getGenerativeModel({
model: MODEL_ID,
generationConfig: {
temperature: 1,
topP: 0.95,
topK: 40,
// @ts-expect-error - Gemini API JS is missing this type
responseModalities: ["Text", "Image"],
},
});
let result;
try {
// Convert history to the format expected by Gemini API
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), // Remove empty parts
};
})
.filter((item: FormattedHistoryItem) => item.parts.length > 0) // Remove items with no parts
: [];
// Create a chat session with the formatted history
const chat = model.startChat({
history: formattedHistory,
});
// Prepare the current message parts
const messageParts = [];
// Add the text prompt
messageParts.push({ text: prompt });
// Add the image if provided
if (inputImage) {
// For image editing
console.log("Processing image edit request");
// Check if the image is a valid data URL
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
);
// Add the image to message parts
messageParts.push({
inlineData: {
data: base64Image,
mimeType: mimeType,
},
});
}
// Send the message to the chat
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";
// Process the response
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) {
// Get the image data
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) {
// Store the text
textResponse = part.text;
console.log(
"Text response received:",
textResponse.substring(0, 50) + "..."
);
}
}
}
// Return just the base64 image and description as JSON
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 }
);
}
}
|