reneco-advanced-input-module 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/voice-input-module.cjs.entry.js +208 -93
- package/dist/cjs/voice-input-module.cjs.entry.js.map +1 -1
- package/dist/cjs/voice-input-module.cjs.js +1 -1
- package/dist/cjs/voice-input-module.entry.cjs.js.map +1 -1
- package/dist/collection/components/voice-input-module/voice-input-module.js +209 -93
- package/dist/collection/components/voice-input-module/voice-input-module.js.map +1 -1
- package/dist/components/voice-input-module.js +209 -93
- package/dist/components/voice-input-module.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/voice-input-module.entry.js +208 -93
- package/dist/esm/voice-input-module.entry.js.map +1 -1
- package/dist/esm/voice-input-module.js +1 -1
- package/dist/types/components/voice-input-module/voice-input-module.d.ts +3 -0
- package/dist/voice-input-module/{p-0e2b9ca0.entry.js → p-920964b2.entry.js} +3 -3
- package/dist/voice-input-module/p-920964b2.entry.js.map +1 -0
- package/dist/voice-input-module/voice-input-module.entry.esm.js.map +1 -1
- package/dist/voice-input-module/voice-input-module.esm.js +1 -1
- package/package.json +1 -1
- package/www/build/{p-0e2b9ca0.entry.js → p-920964b2.entry.js} +3 -3
- package/www/build/p-920964b2.entry.js.map +1 -0
- package/www/build/{p-812b92c7.js → p-cbf8974a.js} +1 -1
- package/www/build/voice-input-module.entry.esm.js.map +1 -1
- package/www/build/voice-input-module.esm.js +1 -1
- package/www/index.html +1 -1
- package/dist/voice-input-module/p-0e2b9ca0.entry.js.map +0 -1
- package/www/build/p-0e2b9ca0.entry.js.map +0 -1
package/dist/esm/loader.js
CHANGED
|
@@ -5,7 +5,7 @@ import { g as globalScripts } from './app-globals-DQuL1Twl.js';
|
|
|
5
5
|
const defineCustomElements = async (win, options) => {
|
|
6
6
|
if (typeof window === 'undefined') return undefined;
|
|
7
7
|
await globalScripts();
|
|
8
|
-
return bootstrapLazy([["ocr-file-uploader",[[257,"ocr-file-uploader",{"batch":[4],"callback":[16],"jsonSchema":[1,"json-schema"],"theme":[1],"parsedTheme":[32]},null,{"theme":["parseTheme"]}]]],["voice-input-module",[[257,"voice-input-module",{"formJson":[1,"form-json"],"serviceConfig":[1,"service-config"],"apiKey":[1,"api-key"],"apiProxyUrl":[1,"api-proxy-url"],"transcriptionModel":[1,"transcription-model"],"completionModel":[1,"completion-model"],"transcriptionProvider":[1,"transcription-provider"],"completionProvider":[1,"completion-provider"],"context":[1],"classificationRootUrl":[1,"classification-root-url"],"language":[1],"inputTypes":[1,"input-types"],"theme":[1],"debug":[4],"renderForm":[4,"render-form"],"displayStatus":[4,"display-status"],"isRecording":[32],"isProcessing":[32],"statusMessage":[32],"hasError":[32],"transcription":[32],"filledData":[32],"debugInfo":[32],"isReadonlyMode":[32],"convertXmlToJson":[64],"convertJsonToXml":[64],"convertXmlToJsonLegacy":[64],"convertJsonToXmlLegacy":[64]},null,{"formJson":["initializeServices"],"serviceConfig":["initializeServices"],"theme":["initializeServices"],"transcriptionProvider":["initializeServices"],"completionProvider":["initializeServices"],"transcriptionModel":["initializeServices"],"completionModel":["initializeServices"]}]]]], options);
|
|
8
|
+
return bootstrapLazy([["ocr-file-uploader",[[257,"ocr-file-uploader",{"batch":[4],"callback":[16],"jsonSchema":[1,"json-schema"],"theme":[1],"parsedTheme":[32]},null,{"theme":["parseTheme"]}]]],["voice-input-module",[[257,"voice-input-module",{"formJson":[1,"form-json"],"serviceConfig":[1,"service-config"],"apiKey":[1,"api-key"],"apiProxyUrl":[1,"api-proxy-url"],"transcriptionModel":[1,"transcription-model"],"completionModel":[1,"completion-model"],"transcriptionProvider":[1,"transcription-provider"],"completionProvider":[1,"completion-provider"],"context":[1],"classificationRootUrl":[1,"classification-root-url"],"language":[1],"inputTypes":[1,"input-types"],"theme":[1],"debug":[4],"renderForm":[4,"render-form"],"displayStatus":[4,"display-status"],"isRecording":[32],"isProcessing":[32],"statusMessage":[32],"hasError":[32],"hasTransientError":[32],"transcription":[32],"filledData":[32],"debugInfo":[32],"isReadonlyMode":[32],"convertXmlToJson":[64],"convertJsonToXml":[64],"convertXmlToJsonLegacy":[64],"convertJsonToXmlLegacy":[64]},null,{"formJson":["initializeServices"],"serviceConfig":["initializeServices"],"theme":["initializeServices"],"transcriptionProvider":["initializeServices"],"completionProvider":["initializeServices"],"transcriptionModel":["initializeServices"],"completionModel":["initializeServices"]}]]]], options);
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export { defineCustomElements };
|
|
@@ -4362,6 +4362,7 @@ const VoiceFormRecorder = class {
|
|
|
4362
4362
|
this.isRecording = false;
|
|
4363
4363
|
this.isProcessing = false;
|
|
4364
4364
|
this.hasError = false;
|
|
4365
|
+
this.hasTransientError = false;
|
|
4365
4366
|
this.transcription = '';
|
|
4366
4367
|
this.filledData = null;
|
|
4367
4368
|
this.debugInfo = {};
|
|
@@ -4374,7 +4375,21 @@ const VoiceFormRecorder = class {
|
|
|
4374
4375
|
if (!input.files || input.files.length === 0)
|
|
4375
4376
|
return;
|
|
4376
4377
|
const file = input.files[0];
|
|
4377
|
-
this.
|
|
4378
|
+
const isEn = this.language === 'en';
|
|
4379
|
+
// Validate file type
|
|
4380
|
+
const validAudioTypes = /^audio\//;
|
|
4381
|
+
const validAudioExtensions = /\.(mp3|wav|webm|m4a|ogg|flac|aac|opus)$/i;
|
|
4382
|
+
if (!validAudioTypes.test(file.type) && !validAudioExtensions.test(file.name)) {
|
|
4383
|
+
this.hasTransientError = true;
|
|
4384
|
+
this.statusMessage = isEn
|
|
4385
|
+
? `Invalid file type: "${file.name}". Please select an audio file.`
|
|
4386
|
+
: `Type de fichier invalide : "${file.name}". Veuillez sélectionner un fichier audio.`;
|
|
4387
|
+
input.value = '';
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
// Reset the input so the same file can be re-selected after an error
|
|
4391
|
+
input.value = '';
|
|
4392
|
+
await this.processAudioContent(file);
|
|
4378
4393
|
};
|
|
4379
4394
|
this.audioRecorder = new AudioRecorderService();
|
|
4380
4395
|
}
|
|
@@ -4434,6 +4449,7 @@ const VoiceFormRecorder = class {
|
|
|
4434
4449
|
config: this.parsedConfig
|
|
4435
4450
|
});
|
|
4436
4451
|
this.hasError = false;
|
|
4452
|
+
this.hasTransientError = false;
|
|
4437
4453
|
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.idle) || (this.language == 'en' ? 'Select an input method' : 'Sélectionner une méthode de saisie');
|
|
4438
4454
|
if (this.parsedInputTypes.length === 0) {
|
|
4439
4455
|
this.inputTypes = 'voice';
|
|
@@ -4454,6 +4470,91 @@ const VoiceFormRecorder = class {
|
|
|
4454
4470
|
} });
|
|
4455
4471
|
}
|
|
4456
4472
|
}
|
|
4473
|
+
getMicErrorMessage(error) {
|
|
4474
|
+
var _a, _b;
|
|
4475
|
+
const isEn = this.language === 'en';
|
|
4476
|
+
const errorName = error.name || '';
|
|
4477
|
+
if (errorName === 'NotAllowedError' || errorName === 'PermissionDeniedError') {
|
|
4478
|
+
return isEn
|
|
4479
|
+
? 'Microphone access denied. Allow microphone access in your browser settings and try again.'
|
|
4480
|
+
: "Accès au microphone refusé. Autorisez l'accès au microphone dans les paramètres du navigateur et réessayez.";
|
|
4481
|
+
}
|
|
4482
|
+
if (errorName === 'NotFoundError' || errorName === 'DevicesNotFoundError') {
|
|
4483
|
+
return isEn
|
|
4484
|
+
? 'No microphone found. Please connect a microphone and try again.'
|
|
4485
|
+
: 'Aucun microphone trouvé. Connectez un microphone et réessayez.';
|
|
4486
|
+
}
|
|
4487
|
+
if (errorName === 'NotReadableError' || errorName === 'TrackStartError') {
|
|
4488
|
+
return isEn
|
|
4489
|
+
? 'Microphone is busy or unavailable. Close other apps using the microphone and try again.'
|
|
4490
|
+
: 'Le microphone est occupé ou indisponible. Fermez les autres applications utilisant le microphone et réessayez.';
|
|
4491
|
+
}
|
|
4492
|
+
if (errorName === 'AbortError') {
|
|
4493
|
+
return isEn
|
|
4494
|
+
? 'Microphone access was interrupted. Please try again.'
|
|
4495
|
+
: "L'accès au microphone a été interrompu. Veuillez réessayer.";
|
|
4496
|
+
}
|
|
4497
|
+
if (errorName === 'OverconstrainedError') {
|
|
4498
|
+
return isEn
|
|
4499
|
+
? 'Microphone does not support the required audio settings.'
|
|
4500
|
+
: 'Le microphone ne supporte pas les paramètres audio requis.';
|
|
4501
|
+
}
|
|
4502
|
+
if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('HTTPS')) || ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('not supported'))) {
|
|
4503
|
+
return isEn
|
|
4504
|
+
? 'Microphone access requires HTTPS or localhost.'
|
|
4505
|
+
: "L'accès au microphone nécessite HTTPS ou localhost.";
|
|
4506
|
+
}
|
|
4507
|
+
return isEn ? `Microphone error: ${error.message}` : `Erreur microphone : ${error.message}`;
|
|
4508
|
+
}
|
|
4509
|
+
getReadableErrorMessage(error, phase) {
|
|
4510
|
+
const isEn = this.language === 'en';
|
|
4511
|
+
const msg = error.message || '';
|
|
4512
|
+
if (/401|unauthorized|invalid.{0,20}(api )?key|authentication failed/i.test(msg)) {
|
|
4513
|
+
return isEn
|
|
4514
|
+
? 'Authentication failed: invalid API key. Check your configuration.'
|
|
4515
|
+
: "Échec d'authentification : clé API invalide. Vérifiez votre configuration.";
|
|
4516
|
+
}
|
|
4517
|
+
if (/403|forbidden/i.test(msg)) {
|
|
4518
|
+
return isEn
|
|
4519
|
+
? 'Access denied: check your API permissions.'
|
|
4520
|
+
: 'Accès refusé : vérifiez vos permissions API.';
|
|
4521
|
+
}
|
|
4522
|
+
if (/429|rate.{0,10}limit|too many requests/i.test(msg)) {
|
|
4523
|
+
return isEn
|
|
4524
|
+
? 'Rate limit exceeded. Please wait a moment and try again.'
|
|
4525
|
+
: 'Limite de requêtes dépassée. Veuillez attendre quelques secondes et réessayer.';
|
|
4526
|
+
}
|
|
4527
|
+
if (/404|not found/i.test(msg)) {
|
|
4528
|
+
return isEn
|
|
4529
|
+
? 'API endpoint not found. Check your proxy URL configuration.'
|
|
4530
|
+
: "Endpoint API introuvable. Vérifiez l'URL de votre proxy.";
|
|
4531
|
+
}
|
|
4532
|
+
if (/5\d\d|server error|internal server|bad gateway|service unavailable/i.test(msg)) {
|
|
4533
|
+
return isEn
|
|
4534
|
+
? 'Server error. Please try again in a moment.'
|
|
4535
|
+
: 'Erreur serveur. Veuillez réessayer dans un instant.';
|
|
4536
|
+
}
|
|
4537
|
+
if (/network|failed to fetch|err_connection|connection refused/i.test(msg)) {
|
|
4538
|
+
return isEn
|
|
4539
|
+
? 'Network error: check your connection and proxy server.'
|
|
4540
|
+
: 'Erreur réseau : vérifiez votre connexion et le serveur proxy.';
|
|
4541
|
+
}
|
|
4542
|
+
if (/json|parse error|unexpected token|invalid response/i.test(msg)) {
|
|
4543
|
+
return isEn
|
|
4544
|
+
? 'Unexpected response from AI service. Please try again.'
|
|
4545
|
+
: 'Réponse inattendue du service IA. Veuillez réessayer.';
|
|
4546
|
+
}
|
|
4547
|
+
if (phase === 'transcription') {
|
|
4548
|
+
return isEn ? `Transcription failed: ${msg}` : `Échec de la transcription : ${msg}`;
|
|
4549
|
+
}
|
|
4550
|
+
if (phase === 'llm') {
|
|
4551
|
+
return isEn ? `Form filling failed: ${msg}` : `Échec du remplissage du formulaire : ${msg}`;
|
|
4552
|
+
}
|
|
4553
|
+
if (phase === 'ocr') {
|
|
4554
|
+
return isEn ? `OCR processing failed: ${msg}` : `Échec du traitement OCR : ${msg}`;
|
|
4555
|
+
}
|
|
4556
|
+
return isEn ? `Processing error: ${msg}` : `Erreur de traitement : ${msg}`;
|
|
4557
|
+
}
|
|
4457
4558
|
async handleRecordClick() {
|
|
4458
4559
|
if (this.isProcessing)
|
|
4459
4560
|
return;
|
|
@@ -4467,7 +4568,7 @@ const VoiceFormRecorder = class {
|
|
|
4467
4568
|
async startRecording() {
|
|
4468
4569
|
var _a;
|
|
4469
4570
|
try {
|
|
4470
|
-
this.
|
|
4571
|
+
this.hasTransientError = false;
|
|
4471
4572
|
this.statusMessage = (this.language == 'en' ? 'Starting recording...' : `Enregistrement ...`);
|
|
4472
4573
|
this.updateDebugInfo('Start Recording Attempt', {});
|
|
4473
4574
|
await this.audioRecorder.startRecording();
|
|
@@ -4480,8 +4581,8 @@ const VoiceFormRecorder = class {
|
|
|
4480
4581
|
});
|
|
4481
4582
|
}
|
|
4482
4583
|
catch (error) {
|
|
4483
|
-
this.
|
|
4484
|
-
this.statusMessage =
|
|
4584
|
+
this.hasTransientError = true;
|
|
4585
|
+
this.statusMessage = this.getMicErrorMessage(error);
|
|
4485
4586
|
this.updateDebugInfo('Recording Error', { error: error.message });
|
|
4486
4587
|
this.formFilled.emit({
|
|
4487
4588
|
success: false,
|
|
@@ -4491,40 +4592,36 @@ const VoiceFormRecorder = class {
|
|
|
4491
4592
|
}
|
|
4492
4593
|
async processJsonForm(ocrData) {
|
|
4493
4594
|
var _a, _b, _c;
|
|
4595
|
+
this.isProcessing = true;
|
|
4596
|
+
this.hasTransientError = false;
|
|
4597
|
+
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.processing) || (this.language == 'en' ? 'Processing document...' : 'Traitement du document ...');
|
|
4494
4598
|
try {
|
|
4495
|
-
this.isProcessing = true;
|
|
4496
|
-
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.processing) || (this.language == 'en' ? 'Processing json...' : `Traitement du json ...`);
|
|
4497
|
-
// Extract content from OCR format
|
|
4498
4599
|
const extractedData = (ocrData === null || ocrData === void 0 ? void 0 : ocrData.content) || ocrData;
|
|
4499
4600
|
const jsonForm = JSON.stringify(extractedData);
|
|
4500
|
-
|
|
4601
|
+
if (!extractedData) {
|
|
4602
|
+
throw Object.assign(new Error('OCR returned no data'), { phase: 'ocr' });
|
|
4603
|
+
}
|
|
4501
4604
|
this.statusMessage = ((_b = this.parsedTheme.texts) === null || _b === void 0 ? void 0 : _b.filling) || (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
|
|
4502
4605
|
const trimmedSchema = await this.trimSchemaForAI(this.parsedSchema);
|
|
4503
|
-
|
|
4504
|
-
|
|
4606
|
+
let filledSchema;
|
|
4607
|
+
try {
|
|
4608
|
+
filledSchema = await this.llmService.fillFormFromJson(jsonForm, trimmedSchema);
|
|
4609
|
+
}
|
|
4610
|
+
catch (llmError) {
|
|
4611
|
+
throw Object.assign(new Error(llmError.message), { phase: 'llm' });
|
|
4612
|
+
}
|
|
4505
4613
|
this.filledData = this.extractFilledData(filledSchema);
|
|
4506
|
-
this.updateDebugInfo('Form Filled', {
|
|
4507
|
-
filledSchema,
|
|
4508
|
-
extractedData: this.filledData
|
|
4509
|
-
});
|
|
4614
|
+
this.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData });
|
|
4510
4615
|
this.parsedSchema = this.filledData;
|
|
4511
|
-
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire
|
|
4512
|
-
this.
|
|
4513
|
-
// Emit success event
|
|
4514
|
-
this.formFilled.emit({
|
|
4515
|
-
success: true,
|
|
4516
|
-
data: this.filledData,
|
|
4517
|
-
jsonForm: jsonForm
|
|
4518
|
-
});
|
|
4616
|
+
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire rempli !');
|
|
4617
|
+
this.formFilled.emit({ success: true, data: this.filledData, jsonForm });
|
|
4519
4618
|
}
|
|
4520
4619
|
catch (error) {
|
|
4521
|
-
|
|
4522
|
-
this.
|
|
4523
|
-
this.
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
jsonForm: JSON.stringify(ocrData)
|
|
4527
|
-
});
|
|
4620
|
+
console.error('OCR processing error:', error);
|
|
4621
|
+
this.hasTransientError = true;
|
|
4622
|
+
this.statusMessage = this.getReadableErrorMessage(error, error.phase || 'llm');
|
|
4623
|
+
this.updateDebugInfo('OCR Processing Error', { phase: error.phase, error: error.message });
|
|
4624
|
+
this.formFilled.emit({ success: false, error: error.message, jsonForm: JSON.stringify(ocrData) });
|
|
4528
4625
|
}
|
|
4529
4626
|
finally {
|
|
4530
4627
|
this.isProcessing = false;
|
|
@@ -4532,83 +4629,100 @@ const VoiceFormRecorder = class {
|
|
|
4532
4629
|
}
|
|
4533
4630
|
async processAudioContent(audioFile) {
|
|
4534
4631
|
var _a, _b, _c;
|
|
4535
|
-
this.
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
});
|
|
4632
|
+
this.isProcessing = true;
|
|
4633
|
+
this.hasTransientError = false;
|
|
4634
|
+
this.updateDebugInfo('Audio Captured', { size: audioFile.size, type: audioFile.type });
|
|
4539
4635
|
try {
|
|
4540
|
-
//
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4636
|
+
// Validate audio file before sending to API
|
|
4637
|
+
const MAX_AUDIO_SIZE = 25 * 1024 * 1024; // 25MB (API limit)
|
|
4638
|
+
if (audioFile.size <= 44) { // WAV header alone is 44 bytes; effectively empty
|
|
4639
|
+
this.hasTransientError = true;
|
|
4640
|
+
this.statusMessage = this.language == 'en'
|
|
4641
|
+
? 'Recording is empty or too short. Please try again.'
|
|
4642
|
+
: "L'enregistrement est vide ou trop court. Veuillez réessayer.";
|
|
4643
|
+
this.formFilled.emit({ success: false, error: 'Empty or too short audio' });
|
|
4644
|
+
return;
|
|
4645
|
+
}
|
|
4646
|
+
if (audioFile.size > MAX_AUDIO_SIZE) {
|
|
4647
|
+
this.hasTransientError = true;
|
|
4648
|
+
this.statusMessage = this.language == 'en'
|
|
4649
|
+
? `File too large (${Math.round(audioFile.size / 1024 / 1024)}MB). Maximum is 25MB.`
|
|
4650
|
+
: `Fichier trop volumineux (${Math.round(audioFile.size / 1024 / 1024)}Mo). Maximum : 25Mo.`;
|
|
4651
|
+
this.formFilled.emit({ success: false, error: 'Audio file too large' });
|
|
4652
|
+
return;
|
|
4653
|
+
}
|
|
4654
|
+
// Step 1: Transcription
|
|
4655
|
+
let transcription;
|
|
4656
|
+
try {
|
|
4657
|
+
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.transcribing) || (this.language == 'en' ? 'Transcribing speech...' : 'Transcription du texte ...');
|
|
4658
|
+
transcription = await this.speechToTextService.transcribe(audioFile, this.language);
|
|
4659
|
+
this.transcription = transcription;
|
|
4660
|
+
this.updateDebugInfo('Transcription Complete', { transcription });
|
|
4661
|
+
}
|
|
4662
|
+
catch (transcriptionError) {
|
|
4663
|
+
throw Object.assign(new Error(transcriptionError.message), { phase: 'transcription' });
|
|
4664
|
+
}
|
|
4545
4665
|
if (!transcription.trim()) {
|
|
4546
|
-
|
|
4666
|
+
this.hasTransientError = true;
|
|
4667
|
+
this.statusMessage = this.language == 'en'
|
|
4668
|
+
? 'No speech detected. Please speak clearly and try again.'
|
|
4669
|
+
: 'Aucune parole détectée. Parlez clairement et réessayez.';
|
|
4670
|
+
this.formFilled.emit({ success: false, error: 'No speech detected', transcription: '' });
|
|
4671
|
+
return;
|
|
4672
|
+
}
|
|
4673
|
+
// Step 2: LLM form filling
|
|
4674
|
+
let filledSchema;
|
|
4675
|
+
try {
|
|
4676
|
+
this.statusMessage = ((_b = this.parsedTheme.texts) === null || _b === void 0 ? void 0 : _b.filling) || (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
|
|
4677
|
+
const trimmedSchema = await this.trimSchemaForAI(this.parsedSchema);
|
|
4678
|
+
filledSchema = await this.llmService.fillFormFromTranscription(transcription, trimmedSchema);
|
|
4679
|
+
}
|
|
4680
|
+
catch (llmError) {
|
|
4681
|
+
throw Object.assign(new Error(llmError.message), { phase: 'llm' });
|
|
4547
4682
|
}
|
|
4548
|
-
// Fill form using LLM
|
|
4549
|
-
this.statusMessage = ((_b = this.parsedTheme.texts) === null || _b === void 0 ? void 0 : _b.filling) || (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
|
|
4550
|
-
const trimmedSchema = await this.trimSchemaForAI(this.parsedSchema);
|
|
4551
|
-
const filledSchema = await this.llmService.fillFormFromTranscription(transcription, trimmedSchema);
|
|
4552
|
-
// Extract filled data
|
|
4553
4683
|
this.filledData = this.extractFilledData(filledSchema);
|
|
4554
|
-
this.updateDebugInfo('Form Filled', {
|
|
4555
|
-
filledSchema,
|
|
4556
|
-
extractedData: this.filledData
|
|
4557
|
-
});
|
|
4684
|
+
this.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData });
|
|
4558
4685
|
this.parsedSchema = this.filledData;
|
|
4559
|
-
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire
|
|
4560
|
-
this.
|
|
4561
|
-
// Emit success event
|
|
4562
|
-
this.formFilled.emit({
|
|
4563
|
-
success: true,
|
|
4564
|
-
data: this.filledData,
|
|
4565
|
-
transcription: transcription
|
|
4566
|
-
});
|
|
4686
|
+
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire rempli !');
|
|
4687
|
+
this.formFilled.emit({ success: true, data: this.filledData, transcription });
|
|
4567
4688
|
}
|
|
4568
4689
|
catch (error) {
|
|
4569
|
-
console.error('
|
|
4570
|
-
this.
|
|
4571
|
-
this.statusMessage =
|
|
4572
|
-
this.updateDebugInfo('
|
|
4573
|
-
this.formFilled.emit({
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
});
|
|
4690
|
+
console.error('Audio processing error:', error);
|
|
4691
|
+
this.hasTransientError = true;
|
|
4692
|
+
this.statusMessage = this.getReadableErrorMessage(error, error.phase || 'audio-upload');
|
|
4693
|
+
this.updateDebugInfo('Audio Processing Error', { phase: error.phase, error: error.message });
|
|
4694
|
+
this.formFilled.emit({ success: false, error: error.message, transcription: this.transcription });
|
|
4695
|
+
}
|
|
4696
|
+
finally {
|
|
4697
|
+
this.isProcessing = false;
|
|
4578
4698
|
}
|
|
4579
4699
|
}
|
|
4580
4700
|
async stopRecordingAndProcess() {
|
|
4581
4701
|
var _a;
|
|
4702
|
+
this.isRecording = false;
|
|
4703
|
+
this.isProcessing = true;
|
|
4704
|
+
this.hasTransientError = false;
|
|
4705
|
+
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.processing) || (this.language == 'en' ? 'Processing audio...' : `Traitement de l'audio ...`);
|
|
4706
|
+
this.updateDebugInfo('Stop Recording', {});
|
|
4707
|
+
this.recordingStateChanged.emit({ isRecording: false, state: 'processing' });
|
|
4582
4708
|
try {
|
|
4583
|
-
this.isRecording = false;
|
|
4584
|
-
this.isProcessing = true;
|
|
4585
|
-
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.processing) || (this.language == 'en' ? 'Processing audio...' : `Traitement de l'audio ...`);
|
|
4586
|
-
this.updateDebugInfo('Stop Recording', {});
|
|
4587
|
-
this.recordingStateChanged.emit({
|
|
4588
|
-
isRecording: false,
|
|
4589
|
-
state: 'processing'
|
|
4590
|
-
});
|
|
4591
|
-
// Stop recording and get audio blob
|
|
4592
4709
|
const audioBlob = await this.audioRecorder.stopRecording();
|
|
4593
4710
|
const audioContent = new File([audioBlob], 'audio.wav', { type: 'audio/wav' });
|
|
4594
|
-
|
|
4711
|
+
// processAudioContent manages isProcessing itself; await ensures we don't return early
|
|
4712
|
+
await this.processAudioContent(audioContent);
|
|
4595
4713
|
}
|
|
4596
4714
|
catch (error) {
|
|
4597
|
-
|
|
4598
|
-
this.
|
|
4599
|
-
this.
|
|
4600
|
-
this.
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
});
|
|
4715
|
+
// Only reached if audioRecorder.stopRecording() itself throws
|
|
4716
|
+
this.hasTransientError = true;
|
|
4717
|
+
this.isProcessing = false;
|
|
4718
|
+
this.statusMessage = (this.language == 'en'
|
|
4719
|
+
? `Failed to stop recording: ${error.message}`
|
|
4720
|
+
: `Impossible d'arrêter l'enregistrement : ${error.message}`);
|
|
4721
|
+
this.updateDebugInfo('Stop Recording Error', { error: error.message });
|
|
4722
|
+
this.formFilled.emit({ success: false, error: error.message, transcription: this.transcription });
|
|
4605
4723
|
}
|
|
4606
4724
|
finally {
|
|
4607
|
-
this.
|
|
4608
|
-
this.recordingStateChanged.emit({
|
|
4609
|
-
isRecording: false,
|
|
4610
|
-
state: 'idle'
|
|
4611
|
-
});
|
|
4725
|
+
this.recordingStateChanged.emit({ isRecording: false, state: 'idle' });
|
|
4612
4726
|
}
|
|
4613
4727
|
}
|
|
4614
4728
|
extractFilledData(filledData) {
|
|
@@ -4916,12 +5030,14 @@ const VoiceFormRecorder = class {
|
|
|
4916
5030
|
return (h$1("button", { class: buttonClass, style: buttonStyle, onClick: () => this.handleRecordClick(), disabled: isDisabled, "aria-label": this.isRecording ? 'Stop recording' : 'Start recording' }, this.isProcessing ? (h$1("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h$1("circle", { cx: "12", cy: "12", r: "3" }, h$1("animate", { attributeName: "r", values: "3;6;3", dur: "1s", repeatCount: "indefinite" }), h$1("animate", { attributeName: "opacity", values: "1;0.3;1", dur: "1s", repeatCount: "indefinite" })))) : this.isRecording ? (h$1("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h$1("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }))) : (h$1("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h$1("circle", { cx: "12", cy: "12", r: "8" })))));
|
|
4917
5031
|
}
|
|
4918
5032
|
renderStatusMessage() {
|
|
5033
|
+
const hasAnyError = this.hasError || this.hasTransientError;
|
|
4919
5034
|
const statusClass = [
|
|
4920
5035
|
'status-text',
|
|
4921
|
-
|
|
4922
|
-
this.filledData && !
|
|
5036
|
+
hasAnyError && 'error',
|
|
5037
|
+
this.filledData && !hasAnyError && 'success'
|
|
4923
5038
|
].filter(Boolean).join(' ');
|
|
4924
|
-
|
|
5039
|
+
const statusStyle = this.getStatusStyle();
|
|
5040
|
+
return h$1("div", { class: statusClass, style: statusStyle }, this.statusMessage);
|
|
4925
5041
|
}
|
|
4926
5042
|
renderFormPreview() {
|
|
4927
5043
|
if (!this.parsedSchema)
|
|
@@ -5094,8 +5210,7 @@ const VoiceFormRecorder = class {
|
|
|
5094
5210
|
}
|
|
5095
5211
|
render() {
|
|
5096
5212
|
const containerStyle = this.getContainerStyle();
|
|
5097
|
-
|
|
5098
|
-
return (h$1("div", { key: '8378e98f02e5b7482929d255c5ec12ff8c2731e4' }, h$1("div", { key: 'b8a0d873bd4e1b4c8936747c0919ac8c4c15301b', class: "voice-recorder-container" + (this.debug || this.renderForm ? "-debug" : ""), style: containerStyle }, h$1("div", { key: '86e7783e3686db378ee16aa91a640f33c3255923', class: "row-audio-area" }, this.renderRecordButton(), this.renderUploadRecordButton(), this.renderUploadButton()), this.displayStatus ? h$1("div", { class: "status-text", style: statusStyle }, this.statusMessage) : "", this.renderForm ? this.renderFormPreview() : "", this.debug ? this.renderDebugPanel() : "")));
|
|
5213
|
+
return (h$1("div", { key: 'd2eb6b74840a57809920b3dbba3fd7dfbeef8531' }, h$1("div", { key: 'e66e1d4fc23176f9024ca20413535440a8be3ce8', class: "voice-recorder-container" + (this.debug || this.renderForm ? "-debug" : ""), style: containerStyle }, h$1("div", { key: '57dd7b882771d1f0bd56a97bfd0a06ffee09428e', class: "row-audio-area" }, this.renderRecordButton(), this.renderUploadRecordButton(), this.renderUploadButton()), this.displayStatus ? this.renderStatusMessage() : "", this.renderForm ? this.renderFormPreview() : "", this.debug ? this.renderDebugPanel() : "")));
|
|
5099
5214
|
}
|
|
5100
5215
|
static get watchers() { return {
|
|
5101
5216
|
"formJson": ["initializeServices"],
|