"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.bookRoutes = void 0; const express_1 = require("express"); const axios_1 = __importDefault(require("axios")); const genreTemplates_js_1 = require("../prompts/genreTemplates.js"); exports.bookRoutes = (0, express_1.Router)(); // Get all available genre templates exports.bookRoutes.get('/genres', (req, res) => { const genres = Object.entries(genreTemplates_js_1.genreTemplates).map(([key, template]) => ({ id: key, name: template.name, description: template.description, icon: template.icon })); res.json({ genres }); }); // Get a specific genre template exports.bookRoutes.get('/genres/:genreId', (req, res) => { const { genreId } = req.params; const template = genreTemplates_js_1.genreTemplates[genreId]; if (!template) { return res.status(404).json({ error: 'Genre not found' }); } res.json({ template }); }); // Generate book outline based on genre and idea exports.bookRoutes.post('/outline', async (req, res) => { try { const { genre, idea, title, language } = req.body; const targetLang = language && language.startsWith('es') ? 'Spanish' : 'English'; if (!genre || !idea) { return res.status(400).json({ error: 'genre and idea are required' }); } const template = genreTemplates_js_1.genreTemplates[genre]; if (!template) { return res.status(400).json({ error: 'Invalid genre' }); } const prompt = `${template.prompts.outline} Book Title: ${title || 'Untitled'} Core Idea: ${idea} Generate a detailed chapter outline following the structure: ${template.structure.join(' → ')} IMPORTANT: The response MUST be written in ${targetLang}. All text values (title, logline, chapter summaries, etc) must be translated to ${targetLang}. Keep the exact JSON KEYS in English. Return the response in JSON format: { "title": "Book Title", "genre": "${genre}", "logline": "One sentence summary", "chapters": [ {"number": 1, "title": "Chapter Title", "summary": "Brief description"}, ... ] }`; const response = await axios_1.default.post('https://openrouter.ai/api/v1/chat/completions', { model: 'nvidia/nemotron-3-nano-30b-a3b:free', // Free model on OpenRouter messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 2000 }, { headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://creabook.app', 'X-Title': 'CreaBook' } }); const content = response.data.choices[0].message.content; console.log('=== Outline AI Response ==='); console.log('Raw content:', content); // Try to parse JSON from response let outline; const jsonMatch = content.match(/\{[\s\S]*\}/); if (jsonMatch) { try { outline = JSON.parse(jsonMatch[0]); console.log('Parsed outline:', outline); } catch (parseError) { console.error('JSON parse error:', parseError); outline = { raw: content, error: 'Failed to parse JSON' }; } } else { console.error('No JSON object found in response'); outline = { raw: content, error: 'No JSON found' }; } res.json({ outline }); } catch (error) { console.error('Outline generation error:', error); res.status(500).json({ error: 'Failed to generate outline', details: error instanceof Error ? error.message : String(error) }); } }); // Generate a chapter based on outline exports.bookRoutes.post('/chapter', async (req, res) => { try { const { genre, chapterTitle, chapterSummary, previousContent, language } = req.body; const targetLang = language && language.startsWith('es') ? 'Spanish' : 'English'; if (!genre || !chapterTitle || !chapterSummary) { return res.status(400).json({ error: 'genre, chapterTitle, and chapterSummary are required' }); } const template = genreTemplates_js_1.genreTemplates[genre]; let prompt = `${template.prompts.chapter} Chapter: ${chapterTitle} Summary: ${chapterSummary} Tone: ${template.defaults.tone} POV: ${template.defaults.pov} IMPORTANT: The entire chapter content MUST be written strictly in ${targetLang}. `; if (previousContent) { prompt += `\n\nPrevious content for context:\n${previousContent.substring(0, 2000)}...`; } const response = await axios_1.default.post('https://openrouter.ai/api/v1/chat/completions', { model: 'nvidia/nemotron-3-nano-30b-a3b:free', messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 3000 }, { headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://creabook.app', 'X-Title': 'CreaBook' } }); const content = response.data.choices[0].message.content; res.json({ content, chapterTitle }); } catch (error) { console.error('Chapter generation error:', error); res.status(500).json({ error: 'Failed to generate chapter', details: error instanceof Error ? error.message : String(error) }); } }); // Expand or refine text exports.bookRoutes.post('/expand', async (req, res) => { try { const { text, instruction = 'Expand and improve this text', language } = req.body; const targetLang = language && language.startsWith('es') ? 'Spanish' : 'English'; if (!text) { return res.status(400).json({ error: 'text is required' }); } const prompt = `${instruction}: Original text: ${text} Provide an expanded and improved version. IMPORTANT: Write the expanded text entirely in ${targetLang}:`; const response = await axios_1.default.post('https://openrouter.ai/api/v1/chat/completions', { model: 'nvidia/nemotron-3-nano-30b-a3b:free', messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 2000 }, { headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://creabook.app', 'X-Title': 'CreaBook' } }); const content = response.data.choices[0].message.content; res.json({ expanded: content }); } catch (error) { console.error('Expand error:', error); res.status(500).json({ error: 'Failed to expand text', details: error instanceof Error ? error.message : String(error) }); } }); // Generate character suggestions exports.bookRoutes.post('/characters', async (req, res) => { try { const { genre, storyIdea, language } = req.body; const targetLang = language && language.startsWith('es') ? 'Spanish' : 'English'; if (!genre || !storyIdea) { return res.status(400).json({ error: 'genre and storyIdea are required' }); } const template = genreTemplates_js_1.genreTemplates[genre]; const prompt = `Based on this ${genre} story idea, suggest 3-5 main characters. Story Idea: ${storyIdea} Genre conventions: ${template.description} IMPORTANT: Write the names, traits, motivation, and backstory values completely in ${targetLang}. Keep the required JSON keys strictly in English. Return ONLY a valid JSON array with this exact format: [ { "name": "Character Name", "role": "protagonist|antagonist|supporting", "traits": ["trait1", "trait2"], "motivation": "What drives them", "backstory": "Brief backstory" } ] Do not include any text outside the JSON array.`; console.log('=== Character Generation Prompt ==='); console.log(prompt); const response = await axios_1.default.post('https://openrouter.ai/api/v1/chat/completions', { model: 'nvidia/nemotron-3-nano-30b-a3b:free', messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 1500 }, { headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://creabook.app', 'X-Title': 'CreaBook' } }); const content = response.data.choices[0].message.content; console.log('=== Character AI Response ==='); console.log('Raw content:', content); let characters; const jsonMatch = content.match(/\[[\s\S]*\]/); if (jsonMatch) { try { characters = JSON.parse(jsonMatch[0]); console.log('Parsed characters:', characters); } catch (parseError) { console.error('JSON parse error:', parseError); characters = { raw: content, error: 'Failed to parse JSON' }; } } else { console.error('No JSON array found in response'); characters = { raw: content, error: 'No JSON array found' }; } res.json({ characters }); } catch (error) { console.error('Character generation error:', error); res.status(500).json({ error: 'Failed to generate characters', details: error instanceof Error ? error.message : String(error) }); } }); // Generate plot suggestions exports.bookRoutes.post('/plot', async (req, res) => { try { const { genre, currentPlot, issue, language } = req.body; const targetLang = language && language.startsWith('es') ? 'Spanish' : 'English'; if (!genre || !currentPlot) { return res.status(400).json({ error: 'genre and currentPlot are required' }); } const template = genreTemplates_js_1.genreTemplates[genre]; const prompt = `Help develop the plot for this ${genre} story: Current Plot: ${currentPlot} ${issue ? `Specific Issue: ${issue}` : 'Suggest plot developments and twists.'} Consider genre conventions: ${template.description} Structure: ${template.structure.join(' → ')} IMPORTANT: Provide all specific, actionable plot suggestions completely in ${targetLang}:`; const response = await axios_1.default.post('https://openrouter.ai/api/v1/chat/completions', { model: 'nvidia/nemotron-3-nano-30b-a3b:free', messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 1500 }, { headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, 'Content-Type': 'application/json', 'HTTP-Referer': 'https://creabook.app', 'X-Title': 'CreaBook' } }); const content = response.data.choices[0].message.content; res.json({ suggestions: content }); } catch (error) { console.error('Plot suggestion error:', error); res.status(500).json({ error: 'Failed to generate plot suggestions', details: error instanceof Error ? error.message : String(error) }); } }); //# sourceMappingURL=books.js.map