wondersheets/server/index.js

165 lines
4.9 KiB
JavaScript

import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { GoogleGenerativeAI } from '@google/generative-ai';
import { getPromptForActivity } from './prompts.js';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const port = 3001;
app.use(cors());
app.use(express.json());
// Initialize Gemini API
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');
// ============================================
// GALLERY STORAGE - Recent 6 generations
// ============================================
const GALLERY_FILE = path.join(__dirname, 'gallery.json');
const MAX_GALLERY_SIZE = 6;
// Load gallery from file
function loadGallery() {
try {
if (fs.existsSync(GALLERY_FILE)) {
const data = fs.readFileSync(GALLERY_FILE, 'utf8');
return JSON.parse(data);
}
} catch (error) {
console.error('Error loading gallery:', error);
}
return [];
}
// Save gallery to file
function saveGallery(gallery) {
try {
fs.writeFileSync(GALLERY_FILE, JSON.stringify(gallery, null, 2));
} catch (error) {
console.error('Error saving gallery:', error);
}
}
// Add item to gallery (keeps only recent 6)
function addToGallery(item) {
const gallery = loadGallery();
// Add new item at the beginning
gallery.unshift({
...item,
id: Date.now(),
createdAt: new Date().toISOString()
});
// Keep only the most recent 6
while (gallery.length > MAX_GALLERY_SIZE) {
gallery.pop();
}
saveGallery(gallery);
return gallery;
}
// ============================================
// API ENDPOINTS
// ============================================
// Get recent gallery items
app.get('/api/gallery', (req, res) => {
try {
const gallery = loadGallery();
res.json(gallery);
} catch (error) {
console.error('Gallery fetch error:', error);
res.status(500).json({ error: 'Failed to fetch gallery' });
}
});
app.post('/api/surprise', async (req, res) => {
try {
if (!process.env.GEMINI_API_KEY) {
return res.status(500).json({ error: 'Missing API Key' });
}
const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
const prompt = `
Generate ONE creative, fun, specific theme for a children's worksheet (e.g. "Space-Rex Coding", "Underwater Hamster Tea Party").
Pick a random age between 3 and 7.
Pick a random activity type from: coloring, numbers, writing, find-way, counting.
Return JSON ONLY:
{
"theme": "string",
"age": number,
"section": "string"
}
`;
const result = await model.generateContent(prompt);
const text = result.response.text();
const jsonStr = text.replace(/```json/g, '').replace(/```/g, '').trim();
res.json(JSON.parse(jsonStr));
} catch (error) {
console.error('Surprise error:', error);
res.status(500).json({ error: 'Failed' });
}
});
app.post('/api/generate', async (req, res) => {
try {
const { theme, age, sections } = req.body;
console.log('Received generation request:', { theme, age, sections });
if (!process.env.GEMINI_API_KEY) {
console.warn('Missing GEMINI_API_KEY');
return res.status(500).json({ error: 'Server configuration error: Missing API Key' });
}
const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
// Get the activity-specific prompt for the first section
const activityType = sections[0] || 'coloring';
const prompt = getPromptForActivity(activityType, theme, age);
console.log(`Using specialized prompt for activity: ${activityType}`);
const result = await model.generateContent(prompt);
const response = await result.response;
const text = response.text();
// Cleanup markdown code blocks if present
const jsonStr = text.replace(/```json/g, '').replace(/```/g, '').trim();
const data = JSON.parse(jsonStr);
if (!data.title || !data.sections || !Array.isArray(data.sections)) {
throw new Error('Invalid generation format');
}
// Save to gallery
const galleryItem = {
...data,
age,
activityType
};
addToGallery(galleryItem);
console.log('Added to gallery, current size:', loadGallery().length);
res.json(data);
} catch (error) {
console.error('Generation error:', error);
res.status(500).json({ error: 'Failed to generate content' });
}
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});