import express from 'express';
import cors from 'cors';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
import { generateDadJoke } from './jokeGenerator.js';
import { generateImage } from './imageGenerator.js';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const PORT = process.env.PORT || 3000;
const WEB_BASE_URL = process.env.WEB_BASE_URL || `http://localhost:${PORT}`;
// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname, '../../web')));
// Store for jokes and images (in production, use a database)
const jokeStore = new Map<string, { joke: string; imageUrl: string; createdAt: Date }>();
// Serve the main page
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../../web/index.html'));
});
// Serve the test page
app.get('/simple-test.html', (req, res) => {
res.sendFile(path.join(__dirname, '../../web/simple-test.html'));
});
// API endpoint to generate a dad joke with visualization
app.post('/api/generate-joke', async (req, res) => {
try {
const { topic, rating } = req.body;
console.log(`🎭 Generating ${rating} Dad Joke - Topic: ${topic || 'random'}`);
// Generate the Dad Joke
const joke = await generateDadJoke(topic, rating || 'PG-13');
// Generate the Image
const imageUrl = await generateImage(joke, topic, rating);
// Generate a unique ID for this joke
const jokeId = Math.random().toString(36).substring(2, 15);
// Store the joke data
jokeStore.set(jokeId, {
joke,
imageUrl,
createdAt: new Date(),
});
const pageUrl = `${WEB_BASE_URL}/joke/${jokeId}`;
res.json({
success: true,
jokeId,
pageUrl,
joke,
imageUrl,
topic: topic || 'random',
rating: rating || 'PG-13'
});
} catch (error) {
console.error('Error generating dad joke:', error);
res.status(500).json({
error: 'Failed to generate dad joke',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
});
// API endpoint to create a new joke page
app.post('/api/create-joke-page', async (req, res) => {
try {
const { joke, imageUrl } = req.body;
if (!joke || !imageUrl) {
return res.status(400).json({ error: 'Joke and imageUrl are required' });
}
// Generate a unique ID for this joke
const jokeId = Math.random().toString(36).substring(2, 15);
// Store the joke data
jokeStore.set(jokeId, {
joke,
imageUrl,
createdAt: new Date(),
});
const pageUrl = `${WEB_BASE_URL}/joke/${jokeId}`;
res.json({
success: true,
jokeId,
pageUrl,
joke,
imageUrl
});
} catch (error) {
console.error('Error creating joke page:', error);
res.status(500).json({ error: 'Failed to create joke page' });
}
});
// Serve individual joke pages
app.get('/joke/:jokeId', (req, res) => {
const { jokeId } = req.params;
const jokeData = jokeStore.get(jokeId);
if (!jokeData) {
return res.status(404).send('Joke not found');
}
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dad Joke Visualizer</title>
<style>
body {
font-family: 'Comic Sans MS', cursive, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
margin: 0;
padding: 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.container {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
max-width: 800px;
text-align: center;
animation: slideIn 0.8s ease-out;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
h1 {
color: #333;
margin-bottom: 30px;
font-size: 2.5em;
text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
}
.joke-text {
font-size: 1.8em;
color: #555;
margin-bottom: 30px;
line-height: 1.6;
padding: 20px;
background: #f8f9fa;
border-radius: 15px;
border-left: 5px solid #ffd700;
}
.joke-image {
max-width: 100%;
height: auto;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
margin-bottom: 30px;
}
.back-button {
background: #667eea;
color: white;
padding: 15px 30px;
border: none;
border-radius: 25px;
font-size: 1.2em;
cursor: pointer;
text-decoration: none;
display: inline-block;
transition: background 0.3s ease;
}
.back-button:hover {
background: #5a6fd8;
}
.timestamp {
color: #888;
font-size: 0.9em;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>🎭 Dad Joke Visualizer</h1>
<div class="joke-text">"${jokeData.joke}"</div>
<img src="${jokeData.imageUrl}" alt="Dad Joke Visualization" class="joke-image">
<a href="/" class="back-button">Generate Another Joke</a>
<div class="timestamp">Created: ${jokeData.createdAt.toLocaleString()}</div>
</div>
</body>
</html>
`;
res.send(html);
});
// Start the server
export async function startWebServer(): Promise<void> {
return new Promise((resolve) => {
app.listen(PORT, () => {
console.log(`Web server running at ${WEB_BASE_URL}`);
resolve();
});
});
}
export async function createWebPage(joke: string, imageUrl: string): Promise<string> {
try {
const response = await fetch(`${WEB_BASE_URL}/api/create-joke-page`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ joke, imageUrl }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.pageUrl;
} catch (error) {
console.error('Error creating web page:', error);
throw new Error(`Failed to create web page: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}