import { NextRequest, NextResponse } from 'next/server'
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY
const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'
/**
* Generate random book details using AI
* NOTE: This is an internal system function and does not count against user's AI usage limits
* It uses a small, efficient model (gemini-2.5-flash) for a single, short generation task
*/
export async function POST(req: NextRequest) {
try {
const availableGenres = [
'Fantasy', 'Science Fiction', 'Mystery', 'Romance', 'Thriller', 'Horror',
'Historical Fiction', 'Contemporary Fiction', 'Young Adult', "Children's",
'Biography', 'Memoir', 'Self-Help', 'Business', 'Health', 'Travel',
'Poetry', 'Drama', 'Comedy', 'Adventure', 'Crime', 'Western',
'Dystopian', 'Paranormal', 'Urban Fantasy', 'Epic Fantasy'
];
// Generate multiple random seeds for maximum variety
const timestamp = Date.now()
const randomSeed1 = Math.random().toString(36).substring(2, 15)
const randomSeed2 = Math.random().toString(36).substring(2, 15)
const randomSeed3 = Math.floor(Math.random() * 10000)
const randomSeed4 = Math.floor(Math.random() * 1000000)
// Create a unique seed combination
const uniqueSeed = `${timestamp}-${randomSeed1}-${randomSeed2}-${randomSeed3}-${randomSeed4}`
// Randomly select different prompt variations to increase variety
const promptVariations = [
`Create a completely unique book idea. Use seed: ${uniqueSeed}`,
`Generate a random story concept. Random identifier: ${uniqueSeed}`,
`Invent a new book with seed: ${uniqueSeed}`,
`Design a unique narrative. Random code: ${uniqueSeed}`,
`Craft an original book idea. Unique ID: ${uniqueSeed}`,
`Develop a fresh story concept. Seed value: ${uniqueSeed}`,
`Conceive a novel book idea. Random token: ${uniqueSeed}`,
`Formulate a unique tale. Identifier: ${uniqueSeed}`,
`Construct an original story. Random seed: ${uniqueSeed}`,
`Devise a new book concept. Unique code: ${uniqueSeed}`
]
const randomPrompt = promptVariations[Math.floor(Math.random() * promptVariations.length)]
// Randomly select different temperature and top_p values for more variety
const temperatures = [0.8, 0.9, 1.0, 0.95, 0.85]
const topPs = [0.8, 0.9, 0.95, 0.85, 0.75]
const randomTemp = temperatures[Math.floor(Math.random() * temperatures.length)]
const randomTopP = topPs[Math.floor(Math.random() * topPs.length)]
// Add random constraints to force different types of stories
const storyConstraints = [
'Focus on contemporary real-world settings',
'Emphasize historical periods and events',
'Create fantasy worlds with unique magic systems',
'Explore psychological and emotional themes',
'Focus on adventure and exploration',
'Emphasize mystery and detective work',
'Create romantic and relationship-focused stories',
'Explore horror and supernatural elements',
'Focus on business and professional life',
'Emphasize family and generational stories'
]
const randomConstraint = storyConstraints[Math.floor(Math.random() * storyConstraints.length)]
const response = await fetch(OPENROUTER_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
'Content-Type': 'application/json',
'HTTP-Referer': process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000',
'X-Title': 'Bookwiz Book Generator'
},
body: JSON.stringify({
model: 'google/gemini-2.5-flash-preview',
messages: [
{
role: 'system',
content: `You are a creative writing assistant. Generate a completely unique and original book idea.
Available genres: ${availableGenres.join(', ')}
CRITICAL REQUIREMENTS:
- Title must be completely original and creative
- Description should be 1-2 sentences maximum
- Select 1-3 genres from the provided list
- Make it unique - avoid any clichés or common tropes
- No additional text, just the JSON object
- Each response must be different from any previous response
- AVOID: quantum, cartographer, chrono, symbiosis, directive, echo, chirurgeon, temporal, multiverse, probability fields, glass, crystal, shimmering, crystalline
- AVOID: overly complex sci-fi concepts, focus on accessible but creative ideas
- AVOID: repetitive patterns or similar-sounding titles
- PREFER: simple, memorable titles that are easy to understand
- PREFER: diverse vocabulary and different word choices
${randomConstraint}
Respond with ONLY a valid JSON object in this exact format:
{
"title": "Your Unique Book Title",
"description": "A compelling 1-2 sentence premise.",
"genres": ["Genre1", "Genre2"]
}`
},
{
role: 'user',
content: randomPrompt
}
],
max_tokens: 200,
temperature: randomTemp,
top_p: randomTopP,
frequency_penalty: 0.8, // Increased to reduce repetition
presence_penalty: 0.8 // Increased to encourage new content
})
})
if (!response.ok) {
console.error('OpenRouter API error:', await response.text())
throw new Error(`OpenRouter API error: ${response.status}`)
}
const data = await response.json()
const content = data.choices?.[0]?.message?.content
if (!content) {
throw new Error('No content received from AI')
}
try {
// Try to extract JSON from the response (in case there's extra text)
let jsonContent = content.trim()
// Find JSON object in the response
const jsonMatch = jsonContent.match(/\{[\s\S]*\}/)
if (jsonMatch) {
jsonContent = jsonMatch[0]
}
// Parse the JSON response
const bookIdea = JSON.parse(jsonContent)
// Validate the response structure
if (!bookIdea.title || !bookIdea.description || !Array.isArray(bookIdea.genres)) {
throw new Error('Invalid response structure')
}
// Ensure genres are valid
const validGenres = bookIdea.genres.filter((genre: string) =>
availableGenres.includes(genre)
)
return NextResponse.json({
title: bookIdea.title,
description: bookIdea.description,
genres: validGenres.length > 0 ? validGenres : ['Fantasy']
})
} catch (parseError) {
// If AI fails, try again with a different approach
throw new Error('AI response parsing failed, will retry')
}
} catch (error) {
console.error('Error generating book idea:', error)
// Return a simple error response - let the frontend handle retries
return NextResponse.json(
{ error: 'Failed to generate book idea. Please try again.' },
{ status: 500 }
)
}
}