import React from 'react'; import { Box, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, TextField, MenuItem, FormControlLabel, Checkbox, Slider, Chip, } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { SectionProps } from './types'; import { textFieldStyles, accordionStyles } from './styles'; import { IMAGE_PROVIDERS, AUDIO_PROVIDERS, COMMON_IMAGE_SIZES } from './constants'; export const GenerationSettingsSection: React.FC = ({ state }) => { const imageDisabled = !state.enableIllustration; const audioDisabled = !state.enableNarration; const videoDisabled = !state.enableVideoNarration; const disabledStyles = (disabled: boolean) => disabled ? { opacity: 0.4, pointerEvents: 'none', } : undefined; const renderHeading = (title: string, disabled: boolean) => ( {title} {disabled && } ); return ( Generation Settings Configure image, video, and audio generation options for your story. {/* Image Generation Settings */} }> {renderHeading('Image Generation Settings', imageDisabled)} state.setImageProvider(e.target.value || null)} helperText="Select the image generation provider. Leave as 'Auto' to use the default." sx={textFieldStyles} disabled={imageDisabled} > {IMAGE_PROVIDERS.map((provider) => ( {provider.label} ))} { const [width, height] = e.target.value.split('x').map(Number); state.setImageWidth(width); state.setImageHeight(height); }} helperText="Select a common image size or set custom dimensions below." sx={textFieldStyles} disabled={imageDisabled} > {COMMON_IMAGE_SIZES.map((size) => ( {size.label} ))} state.setImageWidth(Number(e.target.value))} inputProps={{ min: 256, max: 2048, step: 64 }} helperText="Image width in pixels (256-2048)" sx={textFieldStyles} disabled={imageDisabled} /> state.setImageHeight(Number(e.target.value))} inputProps={{ min: 256, max: 2048, step: 64 }} helperText="Image height in pixels (256-2048)" sx={textFieldStyles} disabled={imageDisabled} /> state.setImageModel(e.target.value || null)} placeholder="Leave empty to use default model" helperText="Specific model to use for image generation (optional)" sx={textFieldStyles} disabled={imageDisabled} /> {/* Video Generation Settings */} }> {renderHeading('Video Generation Settings', videoDisabled)} state.setVideoFps(Number(e.target.value))} inputProps={{ min: 15, max: 60, step: 1 }} helperText="Video frame rate (15-60 fps). Higher values create smoother video but larger files." sx={textFieldStyles} disabled={videoDisabled} /> Transition Duration: {state.videoTransitionDuration.toFixed(1)}s state.setVideoTransitionDuration(value as number)} min={0} max={2} step={0.1} marks={[ { value: 0, label: '0s' }, { value: 1, label: '1s' }, { value: 2, label: '2s' }, ]} valueLabelDisplay="auto" disabled={videoDisabled} /> Duration of transitions between scenes in seconds {/* Audio Generation Settings */} }> {renderHeading('Audio Generation Settings', audioDisabled)} state.setAudioProvider(e.target.value)} helperText="Text-to-speech provider for narration" sx={textFieldStyles} disabled={audioDisabled} > {AUDIO_PROVIDERS.map((provider) => ( {provider.label} ))} state.setAudioLang(e.target.value)} placeholder="en" helperText="Language code for text-to-speech (e.g., 'en' for English, 'es' for Spanish)" sx={textFieldStyles} disabled={audioDisabled} /> {state.audioProvider === 'gtts' && ( state.setAudioSlow(e.target.checked)} disabled={audioDisabled} /> } label="Slow Speech (gTTS only)" /> )} {state.audioProvider === 'pyttsx3' && ( Speech Rate: {state.audioRate} words/min state.setAudioRate(value as number)} min={50} max={300} step={10} marks={[ { value: 50, label: '50' }, { value: 150, label: '150' }, { value: 300, label: '300' }, ]} valueLabelDisplay="auto" disabled={audioDisabled} /> Speech rate in words per minute (pyttsx3 only) )} ); };