feat: add language selection combobox and update TTS dialog for improved language handling
This commit is contained in:
@@ -19,7 +19,6 @@ import {
|
||||
import { soundsService } from '@/lib/api/services/sounds'
|
||||
import { PLAYER_EVENTS, playerEvents } from '@/lib/events'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { formatDuration } from '@/utils/format-duration'
|
||||
import {
|
||||
ArrowRight,
|
||||
ArrowRightToLine,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Combobox, type ComboboxOption } from '@/components/ui/combobox'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
@@ -24,12 +25,12 @@ import { Loader2, Mic } from 'lucide-react'
|
||||
import { ttsService, type TTSProvider } from '@/lib/api/services/tts'
|
||||
import { TTS_EVENTS, ttsEvents } from '@/lib/events'
|
||||
import { toast } from 'sonner'
|
||||
import { getSortedLanguages, getLanguageDisplayName } from '@/lib/constants/gtts-languages'
|
||||
|
||||
interface FormData {
|
||||
text: string
|
||||
provider: string
|
||||
language?: string
|
||||
tld?: string
|
||||
slow?: boolean
|
||||
}
|
||||
|
||||
@@ -49,10 +50,16 @@ export function CreateTTSDialog({ open, onOpenChange }: CreateTTSDialogProps) {
|
||||
text: '',
|
||||
provider: 'gtts',
|
||||
language: 'en',
|
||||
tld: 'com',
|
||||
slow: false,
|
||||
})
|
||||
|
||||
// Prepare language options for combobox
|
||||
const languageOptions: ComboboxOption[] = getSortedLanguages().map((lang) => ({
|
||||
value: lang.code,
|
||||
label: getLanguageDisplayName(lang),
|
||||
searchValue: `${lang.name} ${lang.region || ''} ${lang.code}`.toLowerCase()
|
||||
}))
|
||||
|
||||
// Load providers when dialog opens
|
||||
useEffect(() => {
|
||||
if (open && !providers) {
|
||||
@@ -74,13 +81,13 @@ export function CreateTTSDialog({ open, onOpenChange }: CreateTTSDialogProps) {
|
||||
const generateTTS = async (data: FormData) => {
|
||||
try {
|
||||
setIsGenerating(true)
|
||||
const { text, provider, language, tld, slow } = data
|
||||
const { text, provider, language, slow } = data
|
||||
const response = await ttsService.generateTTS({
|
||||
text,
|
||||
provider,
|
||||
options: {
|
||||
...(language && { lang: language }),
|
||||
...(tld && { tld }),
|
||||
tld: 'com', // Always use .com TLD
|
||||
...(slow !== undefined && { slow }),
|
||||
},
|
||||
})
|
||||
@@ -134,7 +141,6 @@ export function CreateTTSDialog({ open, onOpenChange }: CreateTTSDialogProps) {
|
||||
text: '',
|
||||
provider: 'gtts',
|
||||
language: 'en',
|
||||
tld: 'com',
|
||||
slow: false,
|
||||
})
|
||||
setFormErrors({})
|
||||
@@ -220,42 +226,16 @@ export function CreateTTSDialog({ open, onOpenChange }: CreateTTSDialogProps) {
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="language">Language</Label>
|
||||
<Select
|
||||
<Combobox
|
||||
value={formData.language}
|
||||
onValueChange={(value) => setFormData(prev => ({ ...prev, language: value }))}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select language" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="max-h-60">
|
||||
{selectedProvider.supported_languages.map((lang) => (
|
||||
<SelectItem key={lang} value={lang}>
|
||||
{lang}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="tld">Top-level Domain</Label>
|
||||
<Select
|
||||
value={formData.tld}
|
||||
onValueChange={(value) => setFormData(prev => ({ ...prev, tld: value }))}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select TLD" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{['com', 'co.uk', 'com.au', 'ca', 'co.in', 'ie', 'co.za'].map((tld) => (
|
||||
<SelectItem key={tld} value={tld}>
|
||||
{tld}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
options={languageOptions}
|
||||
placeholder="Select language..."
|
||||
searchPlaceholder="Search languages..."
|
||||
emptyMessage="No language found."
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Different domains may have different voice characteristics
|
||||
Choose from {languageOptions.length} supported languages including regional variants
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState, useEffect, useCallback } from 'react'
|
||||
|
||||
import { ttsService, type TTSResponse } from '@/lib/api/services/tts'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
@@ -31,7 +30,7 @@ export function TTSList() {
|
||||
setIsLoading(true)
|
||||
setError(null)
|
||||
const data = await ttsService.getTTSHistory({ limit })
|
||||
setTTSHistory(data)
|
||||
setTTSHistory(data.tts)
|
||||
} catch (err) {
|
||||
setError('Failed to load TTS history')
|
||||
console.error('Failed to fetch TTS history:', err)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AlertCircle, Calendar, CheckCircle, Clock, Loader, Mic, Trash2, Volume2, XCircle } from 'lucide-react'
|
||||
import { Calendar, CheckCircle, Clock, Loader, Mic, Trash2, Volume2, XCircle } from 'lucide-react'
|
||||
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
Reference in New Issue
Block a user