141 lines
4.8 KiB
TypeScript
141 lines
4.8 KiB
TypeScript
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);
|
|
}
|
|
}),
|
|
);
|