Files
ALwrity/frontend/src/components/shared/AudioSettingsModal.tsx
ajaysi b134e9dc7e Added video studio router and endpoints. Added research router and endpoints. Added youtube router and endpoints. Added onboarding utils router and endpoints. Added onboarding utils service. Added onboarding utils models. Added onboarding utils routes. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils. Added onboarding utils utils.
2026-01-01 17:56:25 +05:30

682 lines
31 KiB
TypeScript

import React, { useEffect, useState, useMemo } from "react";
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Stack,
Box,
Typography,
Slider,
Select,
MenuItem,
FormControl,
InputLabel,
FormControlLabel,
Checkbox,
Tooltip,
IconButton,
alpha,
TextField,
} from "@mui/material";
import { HelpOutline as HelpOutlineIcon, Close as CloseIcon, VolumeUp } from "@mui/icons-material";
import { Button } from "@mui/material";
// Import language-aware voice mapping (optional - only used in YouTube Creator context)
let getVoicesForLanguage: ((language?: string) => any[]) | undefined;
try {
const youtubeConstants = require('../../components/YouTubeCreator/constants');
getVoicesForLanguage = youtubeConstants.getVoicesForLanguage;
} catch {
// Not in YouTube Creator context - will use fallback English voices
getVoicesForLanguage = undefined;
}
export type AudioGenerationSettings = {
voiceId: string;
speed: number;
volume: number;
pitch: number;
emotion: string;
englishNormalization: boolean;
sampleRate?: number;
bitrate: number;
channel: "1" | "2";
format: "mp3" | "wav" | "pcm" | "flac";
languageBoost?: string;
enableSyncMode: boolean;
};
interface AudioSettingsModalProps {
open: boolean;
onClose: () => void;
onApplySettings: (settings: AudioGenerationSettings) => void;
initialSettings: AudioGenerationSettings;
isGenerating?: boolean;
sceneTitle?: string;
isRegenerating?: boolean;
language?: string; // Language code (e.g., 'en', 'es', 'fr') - used to filter voice options
}
// Import language-aware voice mapping (fallback to English voices if not in YouTube Creator context)
// This will be dynamically loaded based on language prop
const EMOTION_OPTIONS = ["happy", "sad", "angry", "fearful", "disgusted", "surprised", "neutral"];
const SAMPLE_RATE_OPTIONS = [8000, 16000, 22050, 24000, 32000, 44100];
const BITRATE_OPTIONS = [32000, 64000, 128000, 256000];
const LANGUAGE_BOOST_OPTIONS = [
"auto",
"English",
"Chinese",
"Chinese,Yue",
"Arabic",
"Russian",
"Spanish",
"French",
"Portuguese",
"German",
"Turkish",
"Dutch",
"Ukrainian",
"Vietnamese",
"Indonesian",
"Japanese",
"Italian",
"Korean",
"Thai",
"Polish",
"Romanian",
"Greek",
"Czech",
"Finnish",
"Hindi",
];
export const AudioSettingsModal: React.FC<AudioSettingsModalProps> = ({
open,
onClose,
onApplySettings,
initialSettings,
isGenerating = false,
sceneTitle,
isRegenerating = false,
language,
}) => {
const [settings, setSettings] = useState<AudioGenerationSettings>(initialSettings);
// Fallback English voices (used when language-aware mapping is not available)
const ENGLISH_VOICES_FALLBACK = [
{ id: "Wise_Woman", name: "Wise Woman", personality: "Authoritative, trustworthy female voice - perfect for educational content and expert narration" },
{ id: "Friendly_Person", name: "Friendly Person", personality: "Warm, approachable voice - great for welcoming introductions and customer-facing content" },
{ id: "Inspirational_girl", name: "Inspirational Girl", personality: "Motivational, uplifting female voice - ideal for inspirational and motivational content" },
{ id: "Deep_Voice_Man", name: "Deep Voice Man", personality: "Powerful, commanding male voice - excellent for serious topics and authoritative delivery" },
{ id: "Calm_Woman", name: "Calm Woman", personality: "Soothing, composed female voice - perfect for meditation, relaxation, or sensitive topics" },
{ id: "Casual_Guy", name: "Casual Guy", personality: "Relaxed, conversational male voice - great for vlogs, tutorials, and informal content" },
{ id: "Lively_Girl", name: "Lively Girl", personality: "Energetic, enthusiastic female voice - ideal for exciting announcements and upbeat content" },
{ id: "Patient_Man", name: "Patient Man", personality: "Gentle, understanding male voice - perfect for explanations and patient guidance" },
{ id: "Young_Knight", name: "Young Knight", personality: "Brave, confident male voice - great for adventure, gaming, and heroic narratives" },
{ id: "Determined_Man", name: "Determined Man", personality: "Strong, resolute male voice - excellent for motivational speeches and determined delivery" },
{ id: "Lovely_Girl", name: "Lovely Girl", personality: "Sweet, charming female voice - ideal for storytelling and gentle narratives" },
{ id: "Decent_Boy", name: "Decent Boy", personality: "Honest, sincere male voice - perfect for testimonials and personal stories" },
{ id: "Imposing_Manner", name: "Imposing Manner", personality: "Formal, dignified male voice - great for corporate content and official announcements" },
{ id: "Elegant_Man", name: "Elegant Man", personality: "Refined, sophisticated male voice - ideal for luxury, premium content" },
{ id: "Abbess", name: "Abbess", personality: "Spiritual, serene female voice - perfect for meditation, philosophy, or contemplative content" },
{ id: "Sweet_Girl_2", name: "Sweet Girl 2", personality: "Gentle, melodic female voice - excellent for children's content and soft storytelling" },
{ id: "Exuberant_Girl", name: "Exuberant Girl", personality: "Joyful, expressive female voice - ideal for celebrations and happy announcements" },
];
// Get language-specific voices (use language-aware mapping if available, fallback to English)
const VOICE_OPTIONS = useMemo(() => {
if (getVoicesForLanguage && language) {
return getVoicesForLanguage(language);
}
return ENGLISH_VOICES_FALLBACK;
}, [language]);
const handleApply = () => {
onApplySettings(settings);
};
return (
<Dialog
open={open}
onClose={onClose}
maxWidth="md"
fullWidth
PaperProps={{
sx: {
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
color: "white",
},
}}
>
<DialogTitle>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Box>
<Typography variant="h6" sx={{ fontWeight: 600, mb: 0.5 }}>
{isRegenerating ? 'Regenerate Audio' : 'Generate Audio'} - Voice Settings
</Typography>
{sceneTitle && (
<Typography variant="body2" sx={{ opacity: 0.8 }}>
Configure voice settings for "{sceneTitle}"
</Typography>
)}
</Box>
<IconButton onClick={onClose} size="small" sx={{ color: "rgba(255,255,255,0.7)" }}>
<CloseIcon />
</IconButton>
</Stack>
<Typography variant="body2" sx={{ opacity: 0.7, mt: 1 }}>
{isRegenerating
? 'Customize voice settings to regenerate your audio narration with different characteristics.'
: 'Choose voice settings to generate high-quality audio narration for your scene.'
}
</Typography>
</DialogTitle>
<DialogContent>
<Stack spacing={3} sx={{ mt: 1 }}>
{/* Voice Selection */}
<Box>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 1 }}>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
Voice Selection
</Typography>
<Tooltip title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
Voice Selection Guide
</Typography>
{language && language !== 'en' && (
<Typography variant="caption" sx={{ display: 'block', mb: 0.5, color: '#4ade80' }}>
🌍 <strong>Language-specific voices</strong> are shown for {language.toUpperCase()} content. These voices provide native pronunciation and accent.
</Typography>
)}
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
Choose a voice that matches your content's personality and target audience.
</Typography>
{(!language || language === 'en') && (
<>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>YouTube/Vlogging</strong>: Casual Guy (default), Friendly Person - conversational and engaging
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Educational/Tutorials</strong>: Wise Woman, Deep Voice Man - authoritative and trustworthy
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Motivational</strong>: Inspirational Girl, Determined Man - energetic and inspiring
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Relaxing/Storytelling</strong>: Calm Woman, Lovely Girl - soothing and gentle
</Typography>
<Typography variant="caption" sx={{ display: 'block' }}>
<strong>Default:</strong> Casual Guy - optimized for engaging YouTube narration.
</Typography>
</>
)}
</Box>
} arrow placement="right">
<IconButton size="small" sx={{ color: "rgba(255,255,255,0.5)" }}>
<HelpOutlineIcon fontSize="small" />
</IconButton>
</Tooltip>
</Stack>
{language && language !== 'en' && (
<Typography variant="caption" sx={{ opacity: 0.8, mb: 1, display: 'block', color: '#4ade80' }}>
🌍 Showing {language.toUpperCase()} language-specific voices for native pronunciation
</Typography>
)}
<FormControl fullWidth>
<Select
value={settings.voiceId}
onChange={(e) => setSettings({ ...settings, voiceId: e.target.value })}
sx={{
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
}}
>
{VOICE_OPTIONS.map((voice) => (
<MenuItem key={voice.id} value={voice.id}>
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, color: "white" }}>
{voice.name}
</Typography>
<Typography variant="caption" sx={{ color: "rgba(255,255,255,0.7)", display: "block", fontSize: "0.7rem" }}>
{voice.personality}
</Typography>
</Box>
</MenuItem>
))}
</Select>
</FormControl>
</Box>
{/* Speed / Volume / Pitch */}
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Box sx={{ flex: 1 }}>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 0.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
Speaking Speed ({settings.speed.toFixed(2)})
</Typography>
<Tooltip title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
Natural Speaking Pace
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>0.8-1.0</strong>: Slow, deliberate (educational, complex topics)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>1.1-1.2</strong>: Natural, engaging (recommended for YouTube)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>1.3-1.5</strong>: Fast, energetic (exciting, promotional content)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mt: 0.5 }}>
<strong>Default:</strong> 1.15 - Optimized for engaging YouTube narration.
</Typography>
</Box>
} arrow placement="right">
<HelpOutlineIcon fontSize="small" sx={{ color: "rgba(255,255,255,0.5)" }} />
</Tooltip>
</Stack>
<Slider
value={settings.speed}
min={0.5}
max={2.0}
step={0.05}
onChange={(_, v) => setSettings({ ...settings, speed: v as number })}
sx={{ color: "#4ade80" }}
/>
<Typography variant="caption" sx={{ opacity: 0.7 }}>
0.5 = Slower (narrative) • 1.0 = Normal • 2.0 = Faster (energetic)
</Typography>
</Box>
<Box sx={{ flex: 1 }}>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 0.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
Volume Level ({settings.volume.toFixed(1)})
</Typography>
<Tooltip title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
Audio Loudness
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>0.1-0.5</strong>: Very soft, intimate whisper
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>0.8-1.2</strong>: Normal speaking volume
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>1.5-10.0</strong>: Loud, commanding presence
</Typography>
<Typography variant="caption" sx={{ display: 'block', mt: 0.5 }}>
<strong>Note:</strong> Very high volumes may cause distortion.
</Typography>
</Box>
} arrow placement="right">
<HelpOutlineIcon fontSize="small" sx={{ color: "rgba(255,255,255,0.5)" }} />
</Tooltip>
</Stack>
<Slider
value={settings.volume}
min={0.1}
max={10.0}
step={0.1}
onChange={(_, v) => setSettings({ ...settings, volume: v as number })}
sx={{ color: "#fbbf24" }}
/>
<Typography variant="caption" sx={{ opacity: 0.7 }}>
0.1 = Very soft • 1.0 = Normal • 10.0 = Very loud
</Typography>
</Box>
<Box sx={{ flex: 1 }}>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 0.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
Voice Pitch ({settings.pitch})
</Typography>
<Tooltip title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
Voice Tone & Character
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>-12 to -6</strong>: Deep, authoritative (male voices, serious content)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>-2 to +2</strong>: Natural, conversational range
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>+3 to +12</strong>: Bright, energetic (female voices, upbeat content)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mt: 0.5 }}>
<strong>Tip:</strong> Small adjustments (±2) sound most natural.
</Typography>
</Box>
} arrow placement="right">
<HelpOutlineIcon fontSize="small" sx={{ color: "rgba(255,255,255,0.5)" }} />
</Tooltip>
</Stack>
<Slider
value={settings.pitch}
min={-12}
max={12}
step={0.5}
onChange={(_, v) => setSettings({ ...settings, pitch: v as number })}
sx={{ color: "#f87171" }}
/>
<Typography variant="caption" sx={{ opacity: 0.7 }}>
-12 = Very deep • 0 = Normal • +12 = Very high
</Typography>
</Box>
</Stack>
{/* Emotion */}
<Box>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 1 }}>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
Emotional Delivery
</Typography>
<Tooltip title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
Voice Emotional Expression
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
Choose the emotional tone that matches your content:
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Happy</strong>: Warm, enthusiastic delivery
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Neutral</strong>: Professional, straightforward tone
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Sad</strong>: Somber, reflective delivery
</Typography>
<Typography variant="caption" sx={{ display: 'block', mb: 0.5 }}>
• <strong>Angry</strong>: Forceful, urgent tone (use sparingly)
</Typography>
<Typography variant="caption" sx={{ display: 'block', mt: 0.5 }}>
<strong>Recommendation:</strong> Happy/Neutral for most educational content.
</Typography>
</Box>
} arrow placement="right">
<IconButton size="small" sx={{ color: "rgba(255,255,255,0.5)" }}>
<HelpOutlineIcon fontSize="small" />
</IconButton>
</Tooltip>
</Stack>
<FormControl fullWidth>
<Select
value={settings.emotion}
onChange={(e) => setSettings({ ...settings, emotion: e.target.value })}
sx={{
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
}}
>
{EMOTION_OPTIONS.map((emotion) => (
<MenuItem key={emotion} value={emotion}>
{emotion.charAt(0).toUpperCase() + emotion.slice(1)}
</MenuItem>
))}
</Select>
</FormControl>
<Typography variant="caption" sx={{ opacity: 0.7, mt: 0.5, display: "block" }}>
Select the emotional tone. "Happy" provides natural, engaging delivery for most YouTube content.
</Typography>
</Box>
{/* Language & Normalization */}
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Box sx={{ flex: 1 }}>
<FormControlLabel
control={
<Checkbox
checked={settings.englishNormalization}
onChange={(e) => setSettings({ ...settings, englishNormalization: e.target.checked })}
sx={{ color: "rgba(255,255,255,0.7)" }}
/>
}
label={
<Typography variant="body2" sx={{ color: "white" }}>
English text normalization
</Typography>
}
/>
<Typography variant="caption" sx={{ opacity: 0.7 }}>
Improves pronunciation of numbers (42 "forty-two"), dates, currencies, and technical terms. Recommended for most English content.
</Typography>
</Box>
<Box sx={{ flex: 1 }}>
<TextField
select
fullWidth
label="Language boost"
value={settings.languageBoost || "auto"}
onChange={(e) => setSettings({ ...settings, languageBoost: e.target.value })}
InputLabelProps={{ sx: { color: "rgba(255,255,255,0.7)" } }}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& fieldset": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover fieldset": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused fieldset": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
},
}}
>
{LANGUAGE_BOOST_OPTIONS.map((option) => (
<MenuItem key={option} value={option}>
{option}
</MenuItem>
))}
</TextField>
<Typography variant="caption" sx={{ opacity: 0.7, mt: 0.5, display: "block" }}>
Improves pronunciation accuracy for content in specific languages or regional dialects. Use "auto" for automatic detection.
</Typography>
</Box>
</Stack>
{/* Quality Settings */}
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Box sx={{ flex: 1 }}>
<TextField
select
fullWidth
label="Sample rate"
value={settings.sampleRate || 24000}
onChange={(e) => setSettings({ ...settings, sampleRate: Number(e.target.value) })}
InputLabelProps={{ sx: { color: "rgba(255,255,255,0.7)" } }}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& fieldset": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover fieldset": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused fieldset": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
},
}}
>
{SAMPLE_RATE_OPTIONS.map((rate) => (
<MenuItem key={rate} value={rate}>
{rate} Hz
</MenuItem>
))}
</TextField>
<Typography variant="caption" sx={{ opacity: 0.7, mt: 0.5, display: "block" }}>
Sample rate affects audio clarity. 24kHz is optimal for voice content - higher values increase file size without noticeable improvement.
</Typography>
</Box>
<Box sx={{ flex: 1 }}>
<TextField
select
fullWidth
label="Bitrate"
value={settings.bitrate}
onChange={(e) => setSettings({ ...settings, bitrate: Number(e.target.value) })}
InputLabelProps={{ sx: { color: "rgba(255,255,255,0.7)" } }}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& fieldset": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover fieldset": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused fieldset": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
},
}}
>
{BITRATE_OPTIONS.map((bitrate) => (
<MenuItem key={bitrate} value={bitrate}>
{bitrate / 1000} kbps
</MenuItem>
))}
</TextField>
<Typography variant="caption" sx={{ opacity: 0.7, mt: 0.5, display: "block" }}>
Audio quality vs file size trade-off. 128kbps provides excellent voice quality with reasonable file sizes.
</Typography>
</Box>
</Stack>
{/* Format & Channel */}
<Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
<Box sx={{ flex: 1 }}>
<TextField
select
fullWidth
label="Channel"
value={settings.channel}
onChange={(e) => setSettings({ ...settings, channel: e.target.value as "1" | "2" })}
InputLabelProps={{ sx: { color: "rgba(255,255,255,0.7)" } }}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& fieldset": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover fieldset": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused fieldset": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
},
}}
>
<MenuItem value="1">Mono (smaller files, standard for voice)</MenuItem>
<MenuItem value="2">Stereo (wider sound, larger files)</MenuItem>
</TextField>
</Box>
<Box sx={{ flex: 1 }}>
<TextField
select
fullWidth
label="Format"
value={settings.format}
onChange={(e) => setSettings({ ...settings, format: e.target.value as "mp3" | "wav" | "pcm" | "flac" })}
InputLabelProps={{ sx: { color: "rgba(255,255,255,0.7)" } }}
sx={{
"& .MuiOutlinedInput-root": {
backgroundColor: alpha("#ffffff", 0.1),
color: "white",
"& fieldset": { borderColor: "rgba(255,255,255,0.3)" },
"&:hover fieldset": { borderColor: "rgba(255,255,255,0.4)" },
"&.Mui-focused fieldset": { borderColor: "#ffffff" },
"& .MuiSvgIcon-root": { color: "rgba(255,255,255,0.7)" },
},
}}
>
<MenuItem value="mp3">MP3 (compressed, widely supported)</MenuItem>
<MenuItem value="wav">WAV (uncompressed, highest quality)</MenuItem>
<MenuItem value="pcm">PCM (raw data, specialized use)</MenuItem>
<MenuItem value="flac">FLAC (lossless, large files)</MenuItem>
</TextField>
</Box>
</Stack>
{/* Sync Mode */}
<Box>
<FormControlLabel
control={
<Checkbox
checked={settings.enableSyncMode}
onChange={(e) => setSettings({ ...settings, enableSyncMode: e.target.checked })}
sx={{ color: "rgba(255,255,255,0.7)" }}
/>
}
label={
<Typography variant="body2" sx={{ color: "white" }}>
Enable sync mode (recommended)
</Typography>
}
/>
<Typography variant="caption" sx={{ opacity: 0.7 }}>
When enabled, waits for generation to complete before proceeding. Recommended for reliable audio delivery.
</Typography>
</Box>
{/* Pro Tips */}
<Box sx={{ mt: 2, p: 2, bgcolor: alpha("#ffffff", 0.05), borderRadius: 1, border: "1px solid rgba(255,255,255,0.1)" }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 1, color: "white" }}>
💡 Human-Like Audio Tips
</Typography>
<Typography variant="caption" sx={{ opacity: 0.8, display: "block", mb: 0.5 }}>
<strong>Voice Choice</strong>: "Casual_Guy" provides natural, conversational delivery perfect for YouTube
</Typography>
<Typography variant="caption" sx={{ opacity: 0.8, display: "block", mb: 0.5 }}>
<strong>Speed</strong>: 1.15 provides engaging pace - not too slow, not too fast, just right for viewers
</Typography>
<Typography variant="caption" sx={{ opacity: 0.8, display: "block", mb: 0.5 }}>
<strong>Emotion</strong>: "Happy" creates natural, positive delivery that keeps viewers engaged
</Typography>
<Typography variant="caption" sx={{ opacity: 0.8, display: "block", mb: 0.5 }}>
<strong>Quality</strong>: 128kbps MP3 provides professional quality with optimal file sizes
</Typography>
<Typography variant="caption" sx={{ opacity: 0.8, display: "block" }}>
<strong>Enhancement</strong>: English normalization improves pronunciation of numbers, dates, and technical terms
</Typography>
</Box>
</Stack>
</DialogContent>
<DialogActions sx={{ p: 3, pt: 2 }}>
<Button
onClick={onClose}
disabled={isGenerating}
sx={{ color: "rgba(255,255,255,0.7)" }}
>
Cancel
</Button>
<Button
onClick={handleApply}
variant="contained"
disabled={isGenerating}
startIcon={isGenerating ? undefined : <VolumeUp />}
sx={{
backgroundColor: "#4ade80",
"&:hover": { backgroundColor: "#22c55e" },
"&:disabled": { backgroundColor: "rgba(255,255,255,0.2)" },
}}
>
{isGenerating ? "Generating..." : "Apply Settings & Generate"}
</Button>
</DialogActions>
</Dialog>
);
};