import { Response, Router } from 'express'; import type { Router as RouterType } from 'express'; import { randomUUID } from 'crypto'; import { ImageGenService } from '../services/ImageGenService'; import { validateTextToImageRequest, logTextToImageRequest } from '../middleware/jsonValidation'; import { autoEnhancePrompt, logEnhancementResult } from '../middleware/promptEnhancement'; import { asyncHandler } from '../middleware/errorHandler'; import { validateApiKey } from '../middleware/auth/validateApiKey'; import { requireProjectKey } from '../middleware/auth/requireProjectKey'; import { rateLimitByApiKey } from '../middleware/auth/rateLimiter'; import { GenerateImageResponse } from '../types/api'; export const textToImageRouter: RouterType = Router(); let imageGenService: ImageGenService; /** * POST /api/text-to-image - Generate image from text prompt only (JSON) */ textToImageRouter.post( '/text-to-image', // Authentication middleware validateApiKey, requireProjectKey, rateLimitByApiKey, // JSON validation middleware logTextToImageRequest, validateTextToImageRequest, // Auto-enhancement middleware (optional) autoEnhancePrompt, logEnhancementResult, // Main handler asyncHandler(async (req: any, res: Response) => { // Initialize service if not already done if (!imageGenService) { const apiKey = process.env['GEMINI_API_KEY']; if (!apiKey) { return res.status(500).json({ success: false, message: 'Server configuration error', error: 'GEMINI_API_KEY not configured', } as GenerateImageResponse); } imageGenService = new ImageGenService(apiKey); } const timestamp = new Date().toISOString(); const requestId = req.requestId; const { prompt, aspectRatio, meta } = req.body; // Extract org/project slugs from validated API key const orgSlug = req.apiKey?.organizationSlug || undefined; const projectSlug = req.apiKey?.projectSlug!; // Guaranteed by requireProjectKey middleware // Generate imageId (UUID) - this will be the filename in storage const imageId = randomUUID(); console.log( `[${timestamp}] [${requestId}] Starting text-to-image generation process for org:${orgSlug}, project:${projectSlug}`, ); try { // Generate the image (no reference images for this endpoint) console.log( `[${timestamp}] [${requestId}] Calling ImageGenService.generateImage() (text-only)`, ); const result = await imageGenService.generateImage({ prompt, imageId, ...(aspectRatio && { aspectRatio }), orgSlug, projectSlug, ...(meta && { meta }), }); // Log the result console.log(`[${timestamp}] [${requestId}] Text-to-image generation completed:`, { success: result.success, model: result.model, imageId: result.imageId, hasError: !!result.error, }); // Send response if (result.success) { const successResponse: GenerateImageResponse = { success: true, message: 'Image generated successfully', data: { filename: result.imageId!, filepath: result.filepath!, ...(result.url && { url: result.url }), ...(result.description && { description: result.description }), model: result.model, generatedAt: timestamp, ...(result.geminiParams && { geminiParams: result.geminiParams }), ...(req.enhancedPrompt && { promptEnhancement: { originalPrompt: req.originalPrompt, enhancedPrompt: req.enhancedPrompt, detectedLanguage: req.enhancementMetadata?.detectedLanguage, appliedTemplate: req.enhancementMetadata?.appliedTemplate, enhancements: req.enhancementMetadata?.enhancements || [], }, }), }, }; console.log(`[${timestamp}] [${requestId}] Sending success response`); return res.status(200).json(successResponse); } else { const errorResponse: GenerateImageResponse = { success: false, message: 'Image generation failed', error: result.error || 'Unknown error occurred', }; console.log(`[${timestamp}] [${requestId}] Sending error response: ${result.error}`); return res.status(500).json(errorResponse); } } catch (error) { console.error( `[${timestamp}] [${requestId}] Unhandled error in text-to-image endpoint:`, error, ); const errorResponse: GenerateImageResponse = { success: false, message: 'Image generation failed', error: error instanceof Error ? error.message : 'Unknown error occurred', }; return res.status(500).json(errorResponse); } }), );