stiff
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:
Dmitry 2026-01-24 21:01:46 +03:00
parent 44f56e0554
commit 30ce68a949
3 changed files with 33 additions and 14 deletions

View file

@ -13,13 +13,15 @@ export const voiceServiceApi = {
* @param voice Voice identifier (optional, defaults to 'alloy')
* @param language Language code (optional)
* @param instructions Instructions for speech generation (optional)
* @param model Model identifier (optional)
* @returns Object ID and presigned URL
*/
async generateTTS(
text: string,
voice?: string,
language?: string,
instructions?: string
instructions?: string,
model?: string
): Promise<GenerateTTSResponse> {
const response = await adminApiClient.post<GenerateTTSResponse>(
'/api/v2/media/generate-tts',
@ -28,6 +30,7 @@ export const voiceServiceApi = {
voice: voice || 'alloy',
...(language && { language }),
...(instructions && { instructions }),
...(model && { model }),
}
)

View file

@ -43,6 +43,7 @@ export function CardVoicesManager({
const [dialogVoice, setDialogVoice] = useState('alloy')
const [dialogLanguage, setDialogLanguage] = useState('es')
const [dialogInstructions, setDialogInstructions] = useState('pronunciar la frase claramente')
const [dialogModel, setDialogModel] = useState('gpt-4o-mini-tts')
// Load voices for the card
const { data: voicesData, isLoading, refetch } = useQuery({
@ -124,6 +125,7 @@ export function CardVoicesManager({
setDialogVoice('alloy')
setDialogLanguage('es')
setDialogInstructions('pronunciar la frase claramente')
setDialogModel('gpt-4o-mini-tts')
setShowTTSDialog(true)
}
@ -146,12 +148,13 @@ export function CardVoicesManager({
const voice = dialogVoice || 'alloy'
const language = dialogLanguage || 'es'
const instructions = dialogInstructions || undefined
const model = dialogModel || undefined
console.log('🔄 CardVoicesManager: Requesting TTS generation', { text, voice, language, instructions })
console.log('🔄 CardVoicesManager: Requesting TTS generation', { text, voice, language, instructions, model })
// Generate TTS via backend API
// Backend calls voice-service (which handles caching) and saves to MinIO
const ttsResponse = await voiceServiceApi.generateTTS(text, voice, language, instructions)
const ttsResponse = await voiceServiceApi.generateTTS(text, voice, language, instructions, model)
console.log('✅ CardVoicesManager: TTS generated and saved to MinIO', {
objectId: ttsResponse.objectId
})
@ -311,16 +314,27 @@ export function CardVoicesManager({
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="dialog-instructions">Instructions</Label>
<Textarea
id="dialog-instructions"
value={dialogInstructions}
onChange={(e) => setDialogInstructions(e.target.value)}
placeholder="pronunciar la frase claramente"
className="min-h-[80px]"
disabled={isGeneratingTTS}
/>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="dialog-model">Model</Label>
<Input
id="dialog-model"
value={dialogModel}
onChange={(e) => setDialogModel(e.target.value)}
placeholder="gpt-4o-mini-tts"
disabled={isGeneratingTTS}
/>
</div>
<div className="space-y-2">
<Label htmlFor="dialog-instructions">Instructions</Label>
<Input
id="dialog-instructions"
value={dialogInstructions}
onChange={(e) => setDialogInstructions(e.target.value)}
placeholder="pronunciar la frase claramente"
disabled={isGeneratingTTS}
/>
</div>
</div>
</div>
<DialogFooter>

View file

@ -511,13 +511,14 @@ class MediaApiV2 {
final voice = json['voice'] as String?;
final language = json['language'] as String?;
final instructions = json['instructions'] as String?;
final model = json['model'] as String?;
if (text == null || text.trim().isEmpty) {
return _badRequest('Text is required');
}
print(
'🔄 MediaApiV2: Requesting TTS from voice-service: text="${text.substring(0, text.length > 50 ? 50 : text.length)}", voice="${voice ?? 'default'}", language="${language ?? 'not provided'}", instructions="${instructions != null ? instructions.substring(0, instructions.length > 50 ? 50 : instructions.length) : 'not provided'}"',
'🔄 MediaApiV2: Requesting TTS from voice-service: text="${text.substring(0, text.length > 50 ? 50 : text.length)}", voice="${voice ?? 'default'}", language="${language ?? 'not provided'}", instructions="${instructions != null ? instructions.substring(0, instructions.length > 50 ? 50 : instructions.length) : 'not provided'}", model="${model ?? 'not provided'}"',
);
// Call voice-service
@ -529,6 +530,7 @@ class MediaApiV2 {
'format': 'mp3',
if (language != null) 'language': language,
if (instructions != null) 'instructions': instructions,
if (model != null) 'model': model,
},
options: dio.Options(
responseType: dio.ResponseType.bytes,