From c508c888aa416519ecd266c4128e5a5d9adc28ff Mon Sep 17 00:00:00 2001 From: Desktop Date: Wed, 12 Nov 2025 18:43:32 +0500 Subject: [PATCH] Enhance image size configuration and integration settings. Default image sizes are now set based on provider and model, with options for featured, desktop, and mobile images. Updated frontend to allow selectable image sizes in settings. --- backend/igny8_core/ai/tasks.py | 16 +- .../modules/system/integration_views.py | 19 +++ frontend/src/App.tsx | 7 +- frontend/src/main.tsx | 5 +- frontend/src/pages/Settings/Integration.tsx | 155 +++++++++++++++--- 5 files changed, 165 insertions(+), 37 deletions(-) diff --git a/backend/igny8_core/ai/tasks.py b/backend/igny8_core/ai/tasks.py index 3c5fbd02..7b99992c 100644 --- a/backend/igny8_core/ai/tasks.py +++ b/backend/igny8_core/ai/tasks.py @@ -185,8 +185,9 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None image_format = config.get('image_format', 'webp') desktop_enabled = config.get('desktop_enabled', True) mobile_enabled = config.get('mobile_enabled', True) - # Determine featured image size based on provider - featured_image_size = '1280x832' if provider == 'runware' else '1024x1024' + # Get image sizes from config, with fallback defaults + featured_image_size = config.get('featured_image_size') or ('1280x832' if provider == 'runware' else '1024x1024') + desktop_image_size = config.get('desktop_image_size') or '1024x1024' logger.info(f"[process_image_generation_queue] Settings loaded:") logger.info(f" - Provider: {provider}") @@ -457,8 +458,15 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None } ) - # Use featured size for featured images, default for others - image_size = featured_image_size if image.image_type == 'featured' else '1024x1024' + # Use appropriate size based on image type + if image.image_type == 'featured': + image_size = featured_image_size + elif image.image_type == 'desktop': + image_size = desktop_image_size + elif image.image_type == 'mobile': + image_size = '512x512' # Fixed mobile size + else: # in_article or other + image_size = '1024x1024' # Default for in-article images result = ai_core.generate_image( prompt=formatted_prompt, diff --git a/backend/igny8_core/modules/system/integration_views.py b/backend/igny8_core/modules/system/integration_views.py index fbcc85bf..ce09ea1a 100644 --- a/backend/igny8_core/modules/system/integration_views.py +++ b/backend/igny8_core/modules/system/integration_views.py @@ -617,6 +617,19 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): config.setdefault('image_format', 'webp') config.setdefault('desktop_enabled', True) config.setdefault('mobile_enabled', True) + + # Set default image sizes based on provider/model + provider = config.get('provider', 'openai') + model = config.get('model', 'dall-e-3') + + if not config.get('featured_image_size'): + if provider == 'runware': + config['featured_image_size'] = '1280x832' + else: # openai + config['featured_image_size'] = '1024x1024' + + if not config.get('desktop_image_size'): + config['desktop_image_size'] = '1024x1024' # Get or create integration settings logger.info(f"[save_settings] Attempting get_or_create for {integration_type} with account {account.id}") @@ -746,6 +759,10 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): # Get model - try 'model' first, then 'imageModel' as fallback model = config.get('model') or config.get('imageModel') or 'dall-e-3' + # Set defaults for image sizes if not present + provider = config.get('provider', 'openai') + default_featured_size = '1280x832' if provider == 'runware' else '1024x1024' + return Response({ 'success': True, 'config': { @@ -756,6 +773,8 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): 'image_format': config.get('image_format', 'webp'), 'desktop_enabled': config.get('desktop_enabled', True), 'mobile_enabled': config.get('mobile_enabled', True), + 'featured_image_size': config.get('featured_image_size', default_featured_size), + 'desktop_image_size': config.get('desktop_image_size', '1024x1024'), } }, status=status.HTTP_200_OK) except IntegrationSettings.DoesNotExist: diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 04ec4ef9..c1e44265 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,5 +1,6 @@ import { Suspense, lazy } from "react"; import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router"; +import { HelmetProvider } from "react-helmet-async"; import AppLayout from "./layout/AppLayout"; import { ScrollToTop } from "./components/common/ScrollToTop"; import ProtectedRoute from "./components/auth/ProtectedRoute"; @@ -106,8 +107,9 @@ export default function App() { - - + + + {/* Auth Routes - Public */} } /> } /> @@ -486,6 +488,7 @@ export default function App() { {/* Fallback Route */} } /> + ); diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 2c6f003c..be1ae153 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -5,7 +5,6 @@ import "./styles/igny8-colors.css"; /* IGNY8 custom colors - separate from TailA import "swiper/swiper-bundle.css"; import "flatpickr/dist/flatpickr.css"; import App from "./App.tsx"; -import { AppWrapper } from "./components/common/PageMeta.tsx"; import { ThemeProvider } from "./context/ThemeContext.tsx"; import { ToastProvider } from "./components/ui/toast/ToastContainer.tsx"; import { HeaderMetricsProvider } from "./context/HeaderMetricsContext.tsx"; @@ -17,9 +16,7 @@ createRoot(document.getElementById("root")!).render( - - - + diff --git a/frontend/src/pages/Settings/Integration.tsx b/frontend/src/pages/Settings/Integration.tsx index b5619da6..3a151cef 100644 --- a/frontend/src/pages/Settings/Integration.tsx +++ b/frontend/src/pages/Settings/Integration.tsx @@ -63,6 +63,8 @@ interface IntegrationConfig { image_format?: string; // 'webp', 'jpg', 'png' desktop_enabled?: boolean; mobile_enabled?: boolean; + featured_image_size?: string; // e.g., '1280x832', '1024x1024' + desktop_image_size?: string; // e.g., '1024x1024', '512x512' } export default function Integration() { @@ -91,6 +93,8 @@ export default function Integration() { image_format: 'webp', // 'webp', 'jpg', 'png' desktop_enabled: true, mobile_enabled: true, + featured_image_size: '1024x1024', // Default, will be set based on provider/model + desktop_image_size: '1024x1024', // Default, will be set based on provider/model }, }); @@ -382,17 +386,26 @@ export default function Integration() { // For image_generation, map service to provider and ensure all settings are included let configToSave = { ...config }; if (selectedIntegration === 'image_generation') { + // Determine default sizes based on provider/model + const currentService = config.service || 'openai'; + const currentModel = currentService === 'openai' ? (config.model || 'dall-e-3') : (config.runwareModel || 'runware:97@1'); + const availableSizes = getImageSizes(currentService, currentModel); + const defaultFeaturedSize = availableSizes.length > 0 ? availableSizes[0].value : '1024x1024'; + const defaultDesktopSize = availableSizes.length > 0 ? availableSizes[0].value : '1024x1024'; + configToSave = { ...config, provider: config.service || config.provider || 'openai', // Map service to provider for backend // Ensure model is set correctly based on service - model: config.service === 'openai' ? (config.model || 'dall-e-3') : (config.service === 'runware' ? (config.runwareModel || 'runware:97@1') : config.model), + model: currentService === 'openai' ? (config.model || 'dall-e-3') : (currentService === 'runware' ? (config.runwareModel || 'runware:97@1') : config.model), // Ensure all image settings have defaults image_type: config.image_type || 'realistic', max_in_article_images: config.max_in_article_images || 2, image_format: config.image_format || 'webp', desktop_enabled: config.desktop_enabled !== undefined ? config.desktop_enabled : true, mobile_enabled: config.mobile_enabled !== undefined ? config.mobile_enabled : true, + featured_image_size: config.featured_image_size || defaultFeaturedSize, + desktop_image_size: config.desktop_image_size || defaultDesktopSize, }; } @@ -480,6 +493,33 @@ export default function Integration() { return []; }; + // Get available image sizes with prices based on provider and model + const getImageSizes = useCallback((provider: string, model: string) => { + if (provider === 'runware') { + return [ + { value: '1280x832', label: '1280×832 pixels - $0.009', price: 0.009 }, + { value: '1024x1024', label: '1024×1024 pixels - $0.009', price: 0.009 }, + { value: '512x512', label: '512×512 pixels - $0.006', price: 0.006 }, + ]; + } else if (provider === 'openai') { + if (model === 'dall-e-2') { + return [ + { value: '256x256', label: '256×256 pixels - $0.016', price: 0.016 }, + { value: '512x512', label: '512×512 pixels - $0.018', price: 0.018 }, + { value: '1024x1024', label: '1024×1024 pixels - $0.02', price: 0.02 }, + ]; + } else if (model === 'dall-e-3') { + return [ + { value: '1024x1024', label: '1024×1024 pixels - $0.04', price: 0.04 }, + ]; + } + } + // Default fallback + return [ + { value: '1024x1024', label: '1024×1024 pixels', price: 0 }, + ]; + }, []); + const getSettingsFields = useCallback((integrationId: string): FormField[] => { const config = integrations[integrationId]; @@ -666,6 +706,41 @@ export default function Integration() { return []; }, [integrations]); + // Update image sizes when service/model changes + useEffect(() => { + if (selectedIntegration !== 'image_generation' || !showSettingsModal) return; + + const config = integrations[selectedIntegration]; + if (!config) return; + + const service = config.service || 'openai'; + const model = service === 'openai' ? (config.model || 'dall-e-3') : (config.runwareModel || 'runware:97@1'); + const availableSizes = getImageSizes(service, model); + + if (availableSizes.length > 0) { + const defaultSize = availableSizes[0].value; + const currentFeaturedSize = config.featured_image_size; + const currentDesktopSize = config.desktop_image_size; + + // Check if current sizes are valid for the new provider/model + const validSizes = availableSizes.map(s => s.value); + const needsUpdate = + !currentFeaturedSize || !validSizes.includes(currentFeaturedSize) || + !currentDesktopSize || !validSizes.includes(currentDesktopSize); + + if (needsUpdate) { + setIntegrations({ + ...integrations, + [selectedIntegration]: { + ...config, + featured_image_size: validSizes.includes(currentFeaturedSize || '') ? currentFeaturedSize : defaultSize, + desktop_image_size: validSizes.includes(currentDesktopSize || '') ? currentDesktopSize : defaultSize, + }, + }); + } + } + }, [integrations[selectedIntegration]?.service, integrations[selectedIntegration]?.model, integrations[selectedIntegration]?.runwareModel, selectedIntegration, showSettingsModal, getImageSizes]); + // Memoize custom body for image generation modal to prevent infinite loops const imageGenerationCustomBody = useMemo(() => { if (selectedIntegration !== 'image_generation' || !showSettingsModal) return undefined; @@ -726,47 +801,73 @@ export default function Integration() { Max Images - {/* Featured Image (full width) */} + {/* Featured Image (full width) - Selectable */}
-
-
-
Featured Image
-
1280×832 pixels
-
+
+
Featured Image
Always Enabled
+
+ { + setIntegrations({ + ...integrations, + [selectedIntegration]: { + ...integrations[selectedIntegration], + featured_image_size: value, + }, + }); + }} + className="w-full" + /> +
{/* Row 2: Desktop & Mobile Images (2 columns) */}
- {/* Desktop Images Checkbox */} -
- { - setIntegrations({ - ...integrations, - [selectedIntegration]: { - ...integrations[selectedIntegration], - desktop_enabled: checked, - }, - }); - }} - /> -
+ {/* Desktop Images Checkbox with Size Selector */} +
+
+ { + setIntegrations({ + ...integrations, + [selectedIntegration]: { + ...integrations[selectedIntegration], + desktop_enabled: checked, + }, + }); + }} + /> -
- 1024×1024 pixels -
+ {integrations[selectedIntegration]?.desktop_enabled !== false && ( + { + setIntegrations({ + ...integrations, + [selectedIntegration]: { + ...integrations[selectedIntegration], + desktop_image_size: value, + }, + }); + }} + className="w-full" + /> + )}
- {/* Mobile Images Checkbox */} + {/* Mobile Images Checkbox - Fixed to 512x512 */}
- 960×1280 pixels + 512×512 pixels