123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
import { getZine, saveZine } from "@/lib/storage";
|
|
import type { PageOutline } from "@/lib/gemini";
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { zineId, pageNumber, currentOutline, feedback, style, tone } = body;
|
|
|
|
if (!zineId || !pageNumber || !currentOutline || !feedback) {
|
|
return NextResponse.json(
|
|
{ error: "Missing required fields" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
if (!apiKey) {
|
|
return NextResponse.json(
|
|
{ error: "GEMINI_API_KEY not configured" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
|
|
// Verify zine exists
|
|
const zine = await getZine(zineId);
|
|
if (!zine) {
|
|
return NextResponse.json(
|
|
{ error: "Zine not found" },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
// Update outline based on feedback using Gemini
|
|
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
|
|
|
|
const prompt = `You are refining a zine page based on user feedback.
|
|
|
|
Current page outline:
|
|
- Page Number: ${currentOutline.pageNumber}
|
|
- Type: ${currentOutline.type}
|
|
- Title: ${currentOutline.title}
|
|
- Key Points: ${currentOutline.keyPoints.join(", ")}
|
|
- Image Prompt: ${currentOutline.imagePrompt}
|
|
|
|
User feedback: "${feedback}"
|
|
|
|
Style: ${style}
|
|
Tone: ${tone}
|
|
|
|
Update the page outline to incorporate this feedback. Keep the same page number and type.
|
|
|
|
Return ONLY valid JSON (no markdown, no code blocks):
|
|
{
|
|
"pageNumber": ${currentOutline.pageNumber},
|
|
"type": "${currentOutline.type}",
|
|
"title": "Updated title if needed",
|
|
"keyPoints": ["Updated point 1", "Updated point 2"],
|
|
"imagePrompt": "Updated detailed image prompt incorporating the feedback"
|
|
}`;
|
|
|
|
const result = await model.generateContent(prompt);
|
|
const response = result.response.text();
|
|
|
|
// Parse the updated outline
|
|
let jsonStr = response;
|
|
if (response.includes("```")) {
|
|
const match = response.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
if (match) {
|
|
jsonStr = match[1];
|
|
}
|
|
}
|
|
|
|
const updatedOutline = JSON.parse(jsonStr.trim()) as PageOutline;
|
|
|
|
// Generate new image with updated outline
|
|
// Forward to generate-page endpoint logic
|
|
const generateResponse = await fetch(
|
|
new URL("/api/zine/generate-page", request.url),
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
zineId,
|
|
pageNumber,
|
|
outline: updatedOutline,
|
|
style,
|
|
tone,
|
|
}),
|
|
}
|
|
);
|
|
|
|
if (!generateResponse.ok) {
|
|
throw new Error("Failed to regenerate image");
|
|
}
|
|
|
|
const generateResult = await generateResponse.json();
|
|
|
|
// Update the zine outline
|
|
zine.outline[pageNumber - 1] = updatedOutline;
|
|
zine.updatedAt = new Date().toISOString();
|
|
await saveZine(zine);
|
|
|
|
return NextResponse.json({
|
|
pageNumber,
|
|
updatedOutline,
|
|
imageUrl: generateResult.imageUrl,
|
|
success: true,
|
|
});
|
|
} catch (error) {
|
|
console.error("Page regeneration error:", error);
|
|
return NextResponse.json(
|
|
{ error: error instanceof Error ? error.message : "Failed to regenerate page" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|