forked from innovacion/playground
Initial commit
This commit is contained in:
115
frontend/components/image-config.tsx
Normal file
115
frontend/components/image-config.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
'use client';
|
||||
|
||||
import { aspectRatioSizes, isValidAspectRatio } from '@/lib/google-ai';
|
||||
|
||||
interface ImageConfigProps {
|
||||
model: string;
|
||||
aspectRatio: string;
|
||||
onAspectRatioChange: (ratio: string) => void;
|
||||
numberOfImages: number;
|
||||
onNumberOfImagesChange: (num: number) => void;
|
||||
negativePrompt: string;
|
||||
onNegativePromptChange: (prompt: string) => void;
|
||||
safetyLevel: 'block_none' | 'block_some' | 'block_most';
|
||||
onSafetyLevelChange: (level: 'block_none' | 'block_some' | 'block_most') => void;
|
||||
}
|
||||
|
||||
export function ImageConfig({
|
||||
model,
|
||||
aspectRatio,
|
||||
onAspectRatioChange,
|
||||
numberOfImages,
|
||||
onNumberOfImagesChange,
|
||||
negativePrompt,
|
||||
onNegativePromptChange,
|
||||
safetyLevel,
|
||||
onSafetyLevelChange,
|
||||
}: ImageConfigProps) {
|
||||
const availableRatios = Object.keys(aspectRatioSizes);
|
||||
const size = aspectRatioSizes[aspectRatio];
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Configuración de Imagen</h3>
|
||||
|
||||
{/* Aspect Ratio */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Aspect Ratio
|
||||
</label>
|
||||
<div className="grid grid-cols-5 gap-2">
|
||||
{availableRatios.map((ratio) => (
|
||||
<button
|
||||
key={ratio}
|
||||
onClick={() => onAspectRatioChange(ratio)}
|
||||
disabled={!isValidAspectRatio(model, ratio) && !model.startsWith('gemini')}
|
||||
className={`
|
||||
px-3 py-2 text-xs rounded-lg font-medium transition-all
|
||||
${aspectRatio === ratio
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-secondary hover:bg-accent'
|
||||
}
|
||||
${!isValidAspectRatio(model, ratio) && !model.startsWith('gemini')
|
||||
? 'opacity-50 cursor-not-allowed'
|
||||
: ''
|
||||
}
|
||||
`}
|
||||
>
|
||||
{ratio}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{size && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Dimensiones: {size.width}x{size.height}px
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Número de imágenes */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Número de imágenes: {numberOfImages}
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="1"
|
||||
max="4"
|
||||
value={numberOfImages}
|
||||
onChange={(e) => onNumberOfImagesChange(parseInt(e.target.value))}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Negative Prompt */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Negative Prompt (opcional)
|
||||
</label>
|
||||
<textarea
|
||||
value={negativePrompt}
|
||||
onChange={(e) => onNegativePromptChange(e.target.value)}
|
||||
placeholder="Elementos que NO quieres en la imagen..."
|
||||
className="w-full px-3 py-2 bg-secondary border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary resize-none"
|
||||
rows={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Safety Level */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Nivel de Seguridad
|
||||
</label>
|
||||
<select
|
||||
value={safetyLevel}
|
||||
onChange={(e) => onSafetyLevelChange(e.target.value as any)}
|
||||
className="w-full px-3 py-2 bg-secondary border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
>
|
||||
<option value="block_none">Sin bloqueo</option>
|
||||
<option value="block_some">Bloqueo moderado</option>
|
||||
<option value="block_most">Bloqueo alto</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user