feat: add language selection combobox and update TTS dialog for improved language handling

This commit is contained in:
JSC
2025-09-21 15:20:12 +02:00
parent 7ac979a4f4
commit 7faf2d38ab
7 changed files with 141 additions and 45 deletions

View File

@@ -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,

View File

@@ -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>

View File

@@ -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)

View File

@@ -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'