Spaces:
Running
Running
Update flare-ui/src/app/services/conversation-manager.service.ts
Browse files
flare-ui/src/app/services/conversation-manager.service.ts
CHANGED
@@ -440,84 +440,105 @@ export class ConversationManagerService implements OnDestroy {
|
|
440 |
try {
|
441 |
// Validate audio data
|
442 |
if (!message['data']) {
|
443 |
-
console.warn('TTS audio message missing data');
|
444 |
return;
|
445 |
}
|
446 |
|
447 |
-
//
|
448 |
-
console.log('TTS chunk received:', {
|
|
|
|
|
449 |
dataLength: message['data'].length,
|
450 |
-
dataPreview: message['data'].substring(0, 50),
|
451 |
isLast: message['is_last'],
|
452 |
mimeType: message['mime_type']
|
453 |
});
|
454 |
|
455 |
// Accumulate audio chunks (already base64)
|
456 |
this.audioQueue.push(message['data']);
|
|
|
457 |
|
458 |
if (message['is_last']) {
|
|
|
|
|
459 |
try {
|
460 |
// All chunks received, combine and create audio blob
|
461 |
const combinedBase64 = this.audioQueue.join('');
|
462 |
-
console.log('Combined audio data:', {
|
463 |
totalLength: combinedBase64.length,
|
464 |
-
|
|
|
465 |
});
|
466 |
|
467 |
// Validate base64
|
|
|
468 |
if (!this.isValidBase64(combinedBase64)) {
|
469 |
throw new Error('Invalid base64 data received');
|
470 |
}
|
|
|
471 |
|
472 |
const audioBlob = this.base64ToBlob(combinedBase64, message['mime_type'] || 'audio/mpeg');
|
473 |
const audioUrl = URL.createObjectURL(audioBlob);
|
|
|
474 |
|
475 |
// Update last message with audio URL
|
476 |
const messages = this.messagesSubject.value;
|
477 |
if (messages.length > 0 && messages[messages.length - 1].role === 'assistant') {
|
478 |
messages[messages.length - 1].audioUrl = audioUrl;
|
479 |
this.messagesSubject.next([...messages]);
|
|
|
|
|
|
|
480 |
}
|
481 |
|
482 |
// Clear queue
|
483 |
this.audioQueue = [];
|
|
|
484 |
|
485 |
-
console.log('β
Audio
|
486 |
} catch (error) {
|
487 |
-
console.error('Error creating audio blob:', error);
|
|
|
488 |
this.audioQueue = [];
|
489 |
}
|
490 |
}
|
491 |
} catch (error) {
|
492 |
-
console.error('Error handling TTS audio:', error);
|
493 |
this.audioQueue = []; // Clear queue on error
|
494 |
}
|
495 |
}
|
496 |
|
497 |
private isValidBase64(str: string): boolean {
|
498 |
try {
|
|
|
|
|
499 |
// Check if string contains only valid base64 characters
|
500 |
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
501 |
if (!base64Regex.test(str)) {
|
|
|
502 |
return false;
|
503 |
}
|
504 |
|
505 |
// Try to decode to verify
|
506 |
-
atob(str);
|
|
|
507 |
return true;
|
508 |
} catch (e) {
|
|
|
509 |
return false;
|
510 |
}
|
511 |
}
|
512 |
|
513 |
private base64ToBlob(base64: string, mimeType: string): Blob {
|
514 |
try {
|
515 |
-
console.log('Converting base64 to blob:', {
|
516 |
-
|
517 |
mimeType: mimeType
|
518 |
});
|
519 |
|
520 |
const byteCharacters = atob(base64);
|
|
|
|
|
521 |
const byteNumbers = new Array(byteCharacters.length);
|
522 |
|
523 |
for (let i = 0; i < byteCharacters.length; i++) {
|
@@ -527,16 +548,20 @@ export class ConversationManagerService implements OnDestroy {
|
|
527 |
const byteArray = new Uint8Array(byteNumbers);
|
528 |
const blob = new Blob([byteArray], { type: mimeType });
|
529 |
|
530 |
-
console.log('Blob created:', {
|
531 |
size: blob.size,
|
532 |
-
type: blob.type
|
|
|
533 |
});
|
534 |
|
535 |
return blob;
|
536 |
} catch (error) {
|
537 |
-
console.error('Error converting base64 to blob:', error);
|
538 |
-
console.
|
539 |
-
|
|
|
|
|
|
|
540 |
throw new Error('Failed to convert audio data');
|
541 |
}
|
542 |
}
|
|
|
440 |
try {
|
441 |
// Validate audio data
|
442 |
if (!message['data']) {
|
443 |
+
console.warn('β TTS audio message missing data');
|
444 |
return;
|
445 |
}
|
446 |
|
447 |
+
// Detailed log
|
448 |
+
console.log('π΅ TTS chunk received:', {
|
449 |
+
chunkIndex: message['chunk_index'],
|
450 |
+
totalChunks: message['total_chunks'],
|
451 |
dataLength: message['data'].length,
|
452 |
+
dataPreview: message['data'].substring(0, 50) + '...',
|
453 |
isLast: message['is_last'],
|
454 |
mimeType: message['mime_type']
|
455 |
});
|
456 |
|
457 |
// Accumulate audio chunks (already base64)
|
458 |
this.audioQueue.push(message['data']);
|
459 |
+
console.log(`π¦ Audio queue size: ${this.audioQueue.length} chunks`);
|
460 |
|
461 |
if (message['is_last']) {
|
462 |
+
console.log('π§ Processing final audio chunk...');
|
463 |
+
|
464 |
try {
|
465 |
// All chunks received, combine and create audio blob
|
466 |
const combinedBase64 = this.audioQueue.join('');
|
467 |
+
console.log('β
Combined audio data:', {
|
468 |
totalLength: combinedBase64.length,
|
469 |
+
queueSize: this.audioQueue.length,
|
470 |
+
preview: combinedBase64.substring(0, 100) + '...'
|
471 |
});
|
472 |
|
473 |
// Validate base64
|
474 |
+
console.log('π Validating base64...');
|
475 |
if (!this.isValidBase64(combinedBase64)) {
|
476 |
throw new Error('Invalid base64 data received');
|
477 |
}
|
478 |
+
console.log('β
Base64 validation passed');
|
479 |
|
480 |
const audioBlob = this.base64ToBlob(combinedBase64, message['mime_type'] || 'audio/mpeg');
|
481 |
const audioUrl = URL.createObjectURL(audioBlob);
|
482 |
+
console.log('π§ Audio URL created:', audioUrl);
|
483 |
|
484 |
// Update last message with audio URL
|
485 |
const messages = this.messagesSubject.value;
|
486 |
if (messages.length > 0 && messages[messages.length - 1].role === 'assistant') {
|
487 |
messages[messages.length - 1].audioUrl = audioUrl;
|
488 |
this.messagesSubject.next([...messages]);
|
489 |
+
console.log('β
Audio URL attached to assistant message');
|
490 |
+
} else {
|
491 |
+
console.warn('β οΈ No assistant message found to attach audio');
|
492 |
}
|
493 |
|
494 |
// Clear queue
|
495 |
this.audioQueue = [];
|
496 |
+
console.log('π§Ή Audio queue cleared');
|
497 |
|
498 |
+
console.log('β
Audio processing completed successfully');
|
499 |
} catch (error) {
|
500 |
+
console.error('β Error creating audio blob:', error);
|
501 |
+
console.error('Queue size was:', this.audioQueue.length);
|
502 |
this.audioQueue = [];
|
503 |
}
|
504 |
}
|
505 |
} catch (error) {
|
506 |
+
console.error('β Error handling TTS audio:', error);
|
507 |
this.audioQueue = []; // Clear queue on error
|
508 |
}
|
509 |
}
|
510 |
|
511 |
private isValidBase64(str: string): boolean {
|
512 |
try {
|
513 |
+
console.log(`π Checking base64 validity for ${str.length} chars`);
|
514 |
+
|
515 |
// Check if string contains only valid base64 characters
|
516 |
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
517 |
if (!base64Regex.test(str)) {
|
518 |
+
console.error('β Base64 regex test failed');
|
519 |
return false;
|
520 |
}
|
521 |
|
522 |
// Try to decode to verify
|
523 |
+
const decoded = atob(str);
|
524 |
+
console.log(`β
Base64 decode successful, decoded length: ${decoded.length}`);
|
525 |
return true;
|
526 |
} catch (e) {
|
527 |
+
console.error('β Base64 validation error:', e);
|
528 |
return false;
|
529 |
}
|
530 |
}
|
531 |
|
532 |
private base64ToBlob(base64: string, mimeType: string): Blob {
|
533 |
try {
|
534 |
+
console.log('π Converting base64 to blob:', {
|
535 |
+
base64Length: base64.length,
|
536 |
mimeType: mimeType
|
537 |
});
|
538 |
|
539 |
const byteCharacters = atob(base64);
|
540 |
+
console.log(`π Decoded to ${byteCharacters.length} bytes`);
|
541 |
+
|
542 |
const byteNumbers = new Array(byteCharacters.length);
|
543 |
|
544 |
for (let i = 0; i < byteCharacters.length; i++) {
|
|
|
548 |
const byteArray = new Uint8Array(byteNumbers);
|
549 |
const blob = new Blob([byteArray], { type: mimeType });
|
550 |
|
551 |
+
console.log('β
Blob created:', {
|
552 |
size: blob.size,
|
553 |
+
type: blob.type,
|
554 |
+
sizeKB: (blob.size / 1024).toFixed(2) + ' KB'
|
555 |
});
|
556 |
|
557 |
return blob;
|
558 |
} catch (error) {
|
559 |
+
console.error('β Error converting base64 to blob:', error);
|
560 |
+
console.error('Input details:', {
|
561 |
+
base64Length: base64.length,
|
562 |
+
base64Preview: base64.substring(0, 100) + '...',
|
563 |
+
mimeType: mimeType
|
564 |
+
});
|
565 |
throw new Error('Failed to convert audio data');
|
566 |
}
|
567 |
}
|