lang
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
ac92935b78
commit
03e1e0b478
3 changed files with 14 additions and 9 deletions
|
|
@ -11,17 +11,20 @@ export const voiceServiceApi = {
|
||||||
* Backend calls voice-service, which handles caching, and saves to MinIO
|
* Backend calls voice-service, which handles caching, and saves to MinIO
|
||||||
* @param text Text to convert to speech
|
* @param text Text to convert to speech
|
||||||
* @param voice Voice identifier (optional, defaults to 'alloy')
|
* @param voice Voice identifier (optional, defaults to 'alloy')
|
||||||
|
* @param language Language code (optional)
|
||||||
* @returns Object ID and presigned URL
|
* @returns Object ID and presigned URL
|
||||||
*/
|
*/
|
||||||
async generateTTS(
|
async generateTTS(
|
||||||
text: string,
|
text: string,
|
||||||
voice?: string
|
voice?: string,
|
||||||
|
language?: string
|
||||||
): Promise<GenerateTTSResponse> {
|
): Promise<GenerateTTSResponse> {
|
||||||
const response = await adminApiClient.post<GenerateTTSResponse>(
|
const response = await adminApiClient.post<GenerateTTSResponse>(
|
||||||
'/api/v2/media/generate-tts',
|
'/api/v2/media/generate-tts',
|
||||||
{
|
{
|
||||||
text,
|
text,
|
||||||
voice: voice || 'alloy',
|
voice: voice || 'alloy',
|
||||||
|
...(language && { language }),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export function CardVoicesManager({
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [showAddForm, setShowAddForm] = useState(false)
|
const [showAddForm, setShowAddForm] = useState(false)
|
||||||
const [newAudio, setNewAudio] = useState<string | undefined>(undefined)
|
const [newAudio, setNewAudio] = useState<string | undefined>(undefined)
|
||||||
const [newLanguage, setNewLanguage] = useState('en')
|
const [newLanguage, setNewLanguage] = useState('es')
|
||||||
const [isGeneratingTTS, setIsGeneratingTTS] = useState(false)
|
const [isGeneratingTTS, setIsGeneratingTTS] = useState(false)
|
||||||
|
|
||||||
// Load voices for the card
|
// Load voices for the card
|
||||||
|
|
@ -65,7 +65,7 @@ export function CardVoicesManager({
|
||||||
// Auto-close form and reset after successful addition
|
// Auto-close form and reset after successful addition
|
||||||
setShowAddForm(false)
|
setShowAddForm(false)
|
||||||
setNewAudio(undefined)
|
setNewAudio(undefined)
|
||||||
setNewLanguage('en')
|
setNewLanguage('es')
|
||||||
},
|
},
|
||||||
onError: (error: unknown) => {
|
onError: (error: unknown) => {
|
||||||
console.error('❌ CardVoicesManager: addVoiceMutation.onError', error)
|
console.error('❌ CardVoicesManager: addVoiceMutation.onError', error)
|
||||||
|
|
@ -111,14 +111,14 @@ export function CardVoicesManager({
|
||||||
try {
|
try {
|
||||||
const text = cardOriginal.trim()
|
const text = cardOriginal.trim()
|
||||||
// Use default voice 'alloy' for TTS generation
|
// Use default voice 'alloy' for TTS generation
|
||||||
// Language (newLanguage) is used only when saving the voice to the card
|
// Language (newLanguage) is used for both TTS generation and saving the voice to the card
|
||||||
const voice = 'alloy'
|
const voice = 'alloy'
|
||||||
|
|
||||||
console.log('🔄 CardVoicesManager: Requesting TTS generation', { text, voice })
|
console.log('🔄 CardVoicesManager: Requesting TTS generation', { text, voice, language: newLanguage })
|
||||||
|
|
||||||
// Generate TTS via backend API
|
// Generate TTS via backend API
|
||||||
// Backend calls voice-service (which handles caching) and saves to MinIO
|
// Backend calls voice-service (which handles caching) and saves to MinIO
|
||||||
const ttsResponse = await voiceServiceApi.generateTTS(text, voice)
|
const ttsResponse = await voiceServiceApi.generateTTS(text, voice, newLanguage)
|
||||||
console.log('✅ CardVoicesManager: TTS generated and saved to MinIO', {
|
console.log('✅ CardVoicesManager: TTS generated and saved to MinIO', {
|
||||||
objectId: ttsResponse.objectId
|
objectId: ttsResponse.objectId
|
||||||
})
|
})
|
||||||
|
|
@ -126,7 +126,7 @@ export function CardVoicesManager({
|
||||||
// Add voice to card using the objectId from backend
|
// Add voice to card using the objectId from backend
|
||||||
await addVoiceMutation.mutateAsync({
|
await addVoiceMutation.mutateAsync({
|
||||||
voiceUrl: ttsResponse.objectId,
|
voiceUrl: ttsResponse.objectId,
|
||||||
language: newLanguage || 'en',
|
language: newLanguage || 'es',
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ CardVoicesManager: TTS generation failed', error)
|
console.error('❌ CardVoicesManager: TTS generation failed', error)
|
||||||
|
|
@ -224,7 +224,7 @@ export function CardVoicesManager({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowAddForm(false)
|
setShowAddForm(false)
|
||||||
setNewAudio(undefined)
|
setNewAudio(undefined)
|
||||||
setNewLanguage('en')
|
setNewLanguage('es')
|
||||||
}}
|
}}
|
||||||
disabled={disabled || addVoiceMutation.isPending}
|
disabled={disabled || addVoiceMutation.isPending}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -508,13 +508,14 @@ class MediaApiV2 {
|
||||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||||
final text = json['text'] as String?;
|
final text = json['text'] as String?;
|
||||||
final voice = json['voice'] as String?;
|
final voice = json['voice'] as String?;
|
||||||
|
final language = json['language'] as String?;
|
||||||
|
|
||||||
if (text == null || text.trim().isEmpty) {
|
if (text == null || text.trim().isEmpty) {
|
||||||
return _badRequest('Text is required');
|
return _badRequest('Text is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'🔄 MediaApiV2: Requesting TTS from voice-service: text="${text.substring(0, text.length > 50 ? 50 : text.length)}", voice="${voice ?? 'default'}"',
|
'🔄 MediaApiV2: Requesting TTS from voice-service: text="${text.substring(0, text.length > 50 ? 50 : text.length)}", voice="${voice ?? 'default'}", language="${language ?? 'not provided'}"',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Call voice-service
|
// Call voice-service
|
||||||
|
|
@ -524,6 +525,7 @@ class MediaApiV2 {
|
||||||
'text': text,
|
'text': text,
|
||||||
if (voice != null) 'voice': voice,
|
if (voice != null) 'voice': voice,
|
||||||
'format': 'mp3',
|
'format': 'mp3',
|
||||||
|
if (language != null) 'language': language,
|
||||||
},
|
},
|
||||||
options: dio.Options(
|
options: dio.Options(
|
||||||
responseType: dio.ResponseType.bytes,
|
responseType: dio.ResponseType.bytes,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue