IMage genartion service and models revamp - #Migration Runs

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-03 20:08:16 +00:00
parent a70f8cdd01
commit f518e1751b
15 changed files with 817 additions and 287 deletions

View File

@@ -60,12 +60,9 @@ interface IntegrationConfig {
runwareModel?: string; // Runware model: 'runware:97@1', etc.
// Image generation settings
image_type?: string; // 'realistic', 'artistic', 'cartoon'
max_in_article_images?: number; // 1-5
max_in_article_images?: number; // 1-4
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'
featured_image_size?: string; // e.g., '1280x768', '1024x1024' - auto-determined by model
}
export default function Integration() {
@@ -90,12 +87,9 @@ export default function Integration() {
model: 'dall-e-3', // OpenAI model if service is 'openai'
runwareModel: 'runware:97@1', // Runware model if service is 'runware'
image_type: 'realistic', // 'realistic', 'artistic', 'cartoon'
max_in_article_images: 2, // 1-5
max_in_article_images: 2, // 1-4
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
featured_image_size: '1280x768', // Default, auto-determined by model
},
});
@@ -373,10 +367,7 @@ export default function Integration() {
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,
};
}
@@ -435,12 +426,19 @@ export default function Integration() {
};
// Get available image sizes with prices based on provider and model
// Note: Sizes are now auto-determined - square (1024x1024) and landscape (model-specific)
const getImageSizes = useCallback((provider: string, model: string) => {
if (provider === 'runware') {
// Model-specific landscape sizes, square is always 1024x1024
const MODEL_LANDSCAPE_SIZES: Record<string, { value: string; label: string }> = {
'runware:97@1': { value: '1280x768', label: '1280×768 pixels' }, // Hi Dream Full
'bria:10@1': { value: '1344x768', label: '1344×768 pixels' }, // Bria 3.2
'google:4@2': { value: '1376x768', label: '1376×768 pixels' }, // Nano Banana
};
const landscapeSize = MODEL_LANDSCAPE_SIZES[model] || { value: '1280x768', label: '1280×768 pixels' };
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 },
{ value: landscapeSize.value, label: `${landscapeSize.label} - Landscape`, price: 0.009 },
{ value: '1024x1024', label: '1024×1024 pixels - Square', price: 0.009 },
];
} else if (provider === 'openai') {
if (model === 'dall-e-2') {
@@ -552,8 +550,9 @@ export default function Integration() {
});
},
options: [
{ value: 'runware:97@1', label: 'Hi Dream Full - Standard' },
{ value: 'civitai:618692@691639', label: 'Bria 3.2 - Premium' },
{ value: 'runware:97@1', label: 'Hi Dream Full - Basic' },
{ value: 'bria:10@1', label: 'Bria 3.2 - Quality' },
{ value: 'google:4@2', label: 'Nano Banana - Premium' },
],
});
}
@@ -633,23 +632,19 @@ export default function Integration() {
const availableSizes = getImageSizes(service, model);
if (availableSizes.length > 0) {
const defaultSize = availableSizes[0].value;
const defaultSize = availableSizes[0].value; // First option is landscape (featured image default)
const currentFeaturedSize = config.featured_image_size;
const currentDesktopSize = config.desktop_image_size;
// Check if current sizes are valid for the new provider/model
// Check if current featured size is valid for the new provider/model
const validSizes = availableSizes.map(s => s.value);
const needsUpdate =
!currentFeaturedSize || !validSizes.includes(currentFeaturedSize) ||
!currentDesktopSize || !validSizes.includes(currentDesktopSize);
const needsUpdate = !currentFeaturedSize || !validSizes.includes(currentFeaturedSize);
if (needsUpdate) {
setIntegrations({
...integrations,
[selectedIntegration]: {
...config,
featured_image_size: validSizes.includes(currentFeaturedSize || '') ? currentFeaturedSize : defaultSize,
desktop_image_size: validSizes.includes(currentDesktopSize || '') ? currentDesktopSize : defaultSize,
featured_image_size: defaultSize,
},
});
}
@@ -743,67 +738,15 @@ export default function Integration() {
</div>
</div>
{/* Row 2: Desktop & Mobile Images (2 columns) */}
<div className="grid grid-cols-2 gap-4">
{/* Desktop Images Checkbox with Size Selector */}
<div className="p-3 rounded-lg border border-gray-200 dark:border-gray-700 space-y-2">
<div className="flex items-center gap-3">
<Checkbox
checked={integrations[selectedIntegration]?.desktop_enabled !== false}
onChange={(checked) => {
setIntegrations({
...integrations,
[selectedIntegration]: {
...integrations[selectedIntegration],
desktop_enabled: checked,
},
});
}}
/>
<Label className="font-medium text-gray-700 dark:text-gray-300">
Desktop Images
</Label>
</div>
{integrations[selectedIntegration]?.desktop_enabled !== false && (
<SelectDropdown
options={getImageSizes(service, service === 'openai' ? (integrations[selectedIntegration]?.model || 'dall-e-3') : (integrations[selectedIntegration]?.runwareModel || 'runware:97@1'))}
value={integrations[selectedIntegration]?.desktop_image_size || '1024x1024'}
onChange={(value) => {
setIntegrations({
...integrations,
[selectedIntegration]: {
...integrations[selectedIntegration],
desktop_image_size: value,
},
});
}}
className="w-full"
/>
)}
</div>
{/* Mobile Images Checkbox - Fixed to 512x512 */}
<div className="flex items-center gap-3 p-3 rounded-lg border border-gray-200 dark:border-gray-700">
<Checkbox
checked={integrations[selectedIntegration]?.mobile_enabled !== false}
onChange={(checked) => {
setIntegrations({
...integrations,
[selectedIntegration]: {
...integrations[selectedIntegration],
mobile_enabled: checked,
},
});
}}
/>
<div>
<Label className="font-medium text-gray-700 dark:text-gray-300">
Mobile Images
</Label>
<div className="text-xs text-gray-500 dark:text-gray-400">
512×512 pixels
</div>
</div>
{/* Row 2: Image Size Info */}
<div className="p-3 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<div className="text-sm text-blue-700 dark:text-blue-300">
<strong>Image Sizes (auto-determined):</strong>
<ul className="mt-1 list-disc list-inside text-xs space-y-1">
<li>Featured image: Landscape ({getImageSizes(service, service === 'openai' ? (integrations[selectedIntegration]?.model || 'dall-e-3') : (integrations[selectedIntegration]?.runwareModel || 'runware:97@1'))[0]?.label.split(' - ')[0] || 'model-specific'})</li>
<li>In-article images: Alternating pattern (Square Landscape Square Landscape)</li>
<li>Square: 1024×1024 pixels (universal)</li>
</ul>
</div>
</div>
@@ -921,8 +864,9 @@ export default function Integration() {
? (() => {
// Map model ID to display name
const modelDisplayNames: Record<string, string> = {
'runware:97@1': 'Hi Dream Full - Standard',
'civitai:618692@691639': 'Bria 3.2 - Premium',
'runware:97@1': 'Hi Dream Full - Basic',
'bria:10@1': 'Bria 3.2 - Quality',
'google:4@2': 'Nano Banana - Premium',
};
return modelDisplayNames[integrations.image_generation.runwareModel] || integrations.image_generation.runwareModel;
})()

View File

@@ -86,21 +86,26 @@ export default function SiteSettings() {
image_type: 'realistic' as 'realistic' | 'artistic' | 'cartoon',
max_in_article_images: 2,
image_format: 'webp' as 'webp' | 'jpg' | 'png',
desktop_enabled: true,
mobile_enabled: true,
featured_image_size: '1024x1024',
desktop_image_size: '1024x1024',
});
const [imageSettingsLoading, setImageSettingsLoading] = useState(false);
const [imageSettingsSaving, setImageSettingsSaving] = useState(false);
// Image quality to config mapping
// Updated to use new Runware models via API
const QUALITY_TO_CONFIG: Record<string, { service: 'openai' | 'runware'; model: string }> = {
standard: { service: 'openai', model: 'dall-e-2' },
premium: { service: 'openai', model: 'dall-e-3' },
best: { service: 'runware', model: 'runware:97@1' },
best: { service: 'runware', model: 'runware:97@1' }, // Uses model-specific landscape size
};
// Runware model choices with descriptions
const RUNWARE_MODEL_CHOICES = [
{ value: 'runware:97@1', label: 'Hi Dream Full - Basic', description: 'Fast & affordable' },
{ value: 'bria:10@1', label: 'Bria 3.2 - Quality', description: 'Commercial-safe, licensed data' },
{ value: 'google:4@2', label: 'Nano Banana - Premium', description: 'Best quality, text rendering' },
];
const getQualityFromConfig = (service?: string, model?: string): 'standard' | 'premium' | 'best' => {
if (service === 'runware') return 'best';
if (model === 'dall-e-3') return 'premium';
@@ -109,10 +114,11 @@ export default function SiteSettings() {
const getImageSizes = (provider: string, model: string) => {
if (provider === 'runware') {
// Model-specific sizes - featured uses landscape, in-article alternates
// Sizes shown are for featured image (landscape)
return [
{ value: '1280x832', label: '1280×832 pixels' },
{ value: '1024x1024', label: '1024×1024 pixels' },
{ value: '512x512', label: '512×512 pixels' },
{ value: '1280x768', label: '1280×768 (Landscape)' },
{ value: '1024x1024', label: '1024×1024 (Square)' },
];
} else if (provider === 'openai') {
if (model === 'dall-e-2') {
@@ -230,16 +236,14 @@ export default function SiteSettings() {
const validSizes = sizes.map(s => s.value);
const needsFeaturedUpdate = !validSizes.includes(imageSettings.featured_image_size);
const needsDesktopUpdate = !validSizes.includes(imageSettings.desktop_image_size);
if (needsFeaturedUpdate || needsDesktopUpdate) {
if (needsFeaturedUpdate) {
setImageSettings(prev => ({
...prev,
service: config.service,
provider: config.service,
model: config.model,
featured_image_size: needsFeaturedUpdate ? defaultSize : prev.featured_image_size,
desktop_image_size: needsDesktopUpdate ? defaultSize : prev.desktop_image_size,
}));
} else {
setImageSettings(prev => ({
@@ -438,10 +442,7 @@ export default function SiteSettings() {
image_type: imageData.image_type || 'realistic',
max_in_article_images: imageData.max_in_article_images || 2,
image_format: imageData.image_format || 'webp',
desktop_enabled: imageData.desktop_enabled !== false,
mobile_enabled: imageData.mobile_enabled !== false,
featured_image_size: imageData.featured_image_size || '1024x1024',
desktop_image_size: imageData.desktop_image_size || '1024x1024',
});
}
} catch (error: any) {
@@ -464,10 +465,7 @@ export default function SiteSettings() {
image_type: imageSettings.image_type,
max_in_article_images: imageSettings.max_in_article_images,
image_format: imageSettings.image_format,
desktop_enabled: imageSettings.desktop_enabled,
mobile_enabled: imageSettings.mobile_enabled,
featured_image_size: imageSettings.featured_image_size,
desktop_image_size: imageSettings.desktop_image_size,
};
await fetchAPI('/v1/system/settings/integrations/image_generation/save/', {
@@ -1023,7 +1021,7 @@ export default function SiteSettings() {
<div className="p-4 rounded-lg border border-gray-200 dark:border-gray-700 bg-gradient-to-r from-purple-500 to-brand-500 text-white">
<div className="flex items-center justify-between mb-3">
<div className="font-medium">Featured Image Size</div>
<div className="text-xs bg-white/20 px-2 py-1 rounded">Always Enabled</div>
<div className="text-xs bg-white/20 px-2 py-1 rounded">Landscape (Model-specific)</div>
</div>
<SelectDropdown
options={availableImageSizes}
@@ -1031,42 +1029,13 @@ export default function SiteSettings() {
onChange={(value) => setImageSettings({ ...imageSettings, featured_image_size: value })}
className="w-full [&_.igny8-select-styled]:bg-white/10 [&_.igny8-select-styled]:border-white/20 [&_.igny8-select-styled]:text-white"
/>
<p className="text-xs text-white/70 mt-2">
In-article images alternate: Square (1024×1024) Landscape Square Landscape
</p>
</div>
</div>
{/* Row 3: Desktop & Mobile Images */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-4 rounded-lg border border-gray-200 dark:border-gray-700 space-y-3">
<div className="flex items-center gap-3">
<Checkbox
checked={imageSettings.desktop_enabled}
onChange={(checked) => setImageSettings({ ...imageSettings, desktop_enabled: checked })}
/>
<Label className="font-medium text-gray-700 dark:text-gray-300">Desktop Images</Label>
</div>
{imageSettings.desktop_enabled && (
<SelectDropdown
options={availableImageSizes}
value={imageSettings.desktop_image_size}
onChange={(value) => setImageSettings({ ...imageSettings, desktop_image_size: value })}
className="w-full"
/>
)}
</div>
<div className="flex items-center gap-3 p-4 rounded-lg border border-gray-200 dark:border-gray-700">
<Checkbox
checked={imageSettings.mobile_enabled}
onChange={(checked) => setImageSettings({ ...imageSettings, mobile_enabled: checked })}
/>
<div>
<Label className="font-medium text-gray-700 dark:text-gray-300">Mobile Images</Label>
<div className="text-xs text-gray-500 dark:text-gray-400">512×512 pixels</div>
</div>
</div>
</div>
{/* Row 4: Max Images & Format */}
{/* Row 3: Max Images & Format */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label className="mb-2">Max In-Article Images</Label>
@@ -1076,12 +1045,14 @@ export default function SiteSettings() {
{ value: '2', label: '2 Images' },
{ value: '3', label: '3 Images' },
{ value: '4', label: '4 Images' },
{ value: '5', label: '5 Images' },
]}
value={String(imageSettings.max_in_article_images)}
onChange={(value) => setImageSettings({ ...imageSettings, max_in_article_images: parseInt(value) })}
className="w-full"
/>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
Images 1 & 3: Square | Images 2 & 4: Landscape
</p>
</div>
<div>