reneco-advanced-input-module 0.0.25 → 0.0.26
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 +65 -28
- 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.css +26 -3
- package/dist/collection/components/voice-input-module/voice-input-module.js +57 -23
- package/dist/collection/components/voice-input-module/voice-input-module.js.map +1 -1
- package/dist/collection/services/llm.service.js +8 -4
- package/dist/collection/services/llm.service.js.map +1 -1
- package/dist/collection/types/form-schema.types.js.map +1 -1
- package/dist/components/voice-input-module.js +66 -28
- 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 +65 -28
- 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 +4 -0
- package/dist/types/types/form-schema.types.d.ts +1 -0
- package/dist/voice-input-module/p-f14c05d0.entry.js +3 -0
- package/dist/voice-input-module/p-f14c05d0.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-4e26fbbb.js +2 -0
- package/www/build/p-f14c05d0.entry.js +3 -0
- package/www/build/p-f14c05d0.entry.js.map +1 -0
- 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 +9 -9
- package/dist/voice-input-module/p-334644ec.entry.js +0 -3
- package/dist/voice-input-module/p-334644ec.entry.js.map +0 -1
- package/www/build/p-334644ec.entry.js +0 -3
- package/www/build/p-334644ec.entry.js.map +0 -1
- package/www/build/p-dfdcd9a6.js +0 -2
|
@@ -59,9 +59,6 @@
|
|
|
59
59
|
transform: scale(1.05);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
.upload-record-button svg path {
|
|
63
|
-
/* Color applied via inline style from theme */
|
|
64
|
-
}
|
|
65
62
|
|
|
66
63
|
.record-button {
|
|
67
64
|
display: flex;
|
|
@@ -341,6 +338,32 @@ input[type="date"].form-input {
|
|
|
341
338
|
user-select: none;
|
|
342
339
|
}
|
|
343
340
|
|
|
341
|
+
/* Confidence score badges */
|
|
342
|
+
.confidence-badge {
|
|
343
|
+
display: inline-flex;
|
|
344
|
+
align-items: center;
|
|
345
|
+
margin-left: 4px;
|
|
346
|
+
padding: 1px 5px;
|
|
347
|
+
border-radius: 3px;
|
|
348
|
+
font-size: 0.65rem;
|
|
349
|
+
font-weight: 700;
|
|
350
|
+
vertical-align: middle;
|
|
351
|
+
line-height: 1.4;
|
|
352
|
+
cursor: help;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.confidence-medium {
|
|
356
|
+
background: #fef3c7;
|
|
357
|
+
color: #92400e;
|
|
358
|
+
border: 1px solid #fde68a;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.confidence-low {
|
|
362
|
+
background: #fee2e2;
|
|
363
|
+
color: #991b1b;
|
|
364
|
+
border: 1px solid #fca5a5;
|
|
365
|
+
}
|
|
366
|
+
|
|
344
367
|
/* Skeleton loading state */
|
|
345
368
|
@keyframes skeleton-shimmer {
|
|
346
369
|
0% { background-position: -200% 0; }
|
|
@@ -40,6 +40,7 @@ export class VoiceFormRecorder {
|
|
|
40
40
|
this.hasTransientError = false;
|
|
41
41
|
this.transcription = '';
|
|
42
42
|
this.filledData = null;
|
|
43
|
+
this.confidenceScores = null;
|
|
43
44
|
this.debugInfo = {};
|
|
44
45
|
this.isReadonlyMode = true; // Start in readonly preview mode
|
|
45
46
|
this.isInitializing = true;
|
|
@@ -287,6 +288,7 @@ export class VoiceFormRecorder {
|
|
|
287
288
|
return;
|
|
288
289
|
this.isProcessing = true;
|
|
289
290
|
this.hasTransientError = false;
|
|
291
|
+
this.confidenceScores = null;
|
|
290
292
|
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.processing) || (this.language == 'en' ? 'Processing document...' : 'Traitement du document ...');
|
|
291
293
|
try {
|
|
292
294
|
const extractedData = (ocrData === null || ocrData === void 0 ? void 0 : ocrData.content) || ocrData;
|
|
@@ -304,10 +306,11 @@ export class VoiceFormRecorder {
|
|
|
304
306
|
throw Object.assign(new Error(llmError.message), { phase: 'llm' });
|
|
305
307
|
}
|
|
306
308
|
this.filledData = this.extractFilledData(filledSchema);
|
|
307
|
-
this.
|
|
309
|
+
this.confidenceScores = this.extractConfidenceScores(filledSchema);
|
|
310
|
+
this.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData, confidence: this.confidenceScores });
|
|
308
311
|
this.parsedSchema = this.filledData;
|
|
309
312
|
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire rempli !');
|
|
310
|
-
this.formFilled.emit({ success: true, data: this.filledData, jsonForm });
|
|
313
|
+
this.formFilled.emit({ success: true, data: this.filledData, jsonForm, confidence: this.confidenceScores });
|
|
311
314
|
}
|
|
312
315
|
catch (error) {
|
|
313
316
|
console.error('OCR processing error:', error);
|
|
@@ -326,6 +329,7 @@ export class VoiceFormRecorder {
|
|
|
326
329
|
return;
|
|
327
330
|
this.isProcessing = true;
|
|
328
331
|
this.hasTransientError = false;
|
|
332
|
+
this.confidenceScores = null;
|
|
329
333
|
this.updateDebugInfo('Audio Captured', { size: audioFile.size, type: audioFile.type });
|
|
330
334
|
try {
|
|
331
335
|
// Validate audio file before sending to API
|
|
@@ -346,7 +350,6 @@ export class VoiceFormRecorder {
|
|
|
346
350
|
this.formFilled.emit({ success: false, error: 'Audio file too large' });
|
|
347
351
|
return;
|
|
348
352
|
}
|
|
349
|
-
// Step 1: Transcription
|
|
350
353
|
let transcription;
|
|
351
354
|
try {
|
|
352
355
|
this.statusMessage = ((_a = this.parsedTheme.texts) === null || _a === void 0 ? void 0 : _a.transcribing) || (this.language == 'en' ? 'Transcribing speech...' : 'Transcription du texte ...');
|
|
@@ -365,7 +368,6 @@ export class VoiceFormRecorder {
|
|
|
365
368
|
this.formFilled.emit({ success: false, error: 'No speech detected', transcription: '' });
|
|
366
369
|
return;
|
|
367
370
|
}
|
|
368
|
-
// Step 2: LLM form filling
|
|
369
371
|
let filledSchema;
|
|
370
372
|
try {
|
|
371
373
|
this.statusMessage = ((_b = this.parsedTheme.texts) === null || _b === void 0 ? void 0 : _b.filling) || (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
|
|
@@ -376,10 +378,11 @@ export class VoiceFormRecorder {
|
|
|
376
378
|
throw Object.assign(new Error(llmError.message), { phase: 'llm' });
|
|
377
379
|
}
|
|
378
380
|
this.filledData = this.extractFilledData(filledSchema);
|
|
379
|
-
this.
|
|
381
|
+
this.confidenceScores = this.extractConfidenceScores(filledSchema);
|
|
382
|
+
this.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData, confidence: this.confidenceScores });
|
|
380
383
|
this.parsedSchema = this.filledData;
|
|
381
384
|
this.statusMessage = ((_c = this.parsedTheme.texts) === null || _c === void 0 ? void 0 : _c.completed) || (this.language == 'en' ? 'Form completed!' : 'Formulaire rempli !');
|
|
382
|
-
this.formFilled.emit({ success: true, data: this.filledData, transcription });
|
|
385
|
+
this.formFilled.emit({ success: true, data: this.filledData, transcription, confidence: this.confidenceScores });
|
|
383
386
|
}
|
|
384
387
|
catch (error) {
|
|
385
388
|
console.error('Audio processing error:', error);
|
|
@@ -403,7 +406,8 @@ export class VoiceFormRecorder {
|
|
|
403
406
|
try {
|
|
404
407
|
const audioBlob = await this.audioRecorder.stopRecording();
|
|
405
408
|
const audioContent = new File([audioBlob], 'audio.wav', { type: 'audio/wav' });
|
|
406
|
-
//
|
|
409
|
+
// Reset isProcessing so the guard inside processAudioContent doesn't block this internal call
|
|
410
|
+
this.isProcessing = false;
|
|
407
411
|
await this.processAudioContent(audioContent);
|
|
408
412
|
}
|
|
409
413
|
catch (error) {
|
|
@@ -420,12 +424,52 @@ export class VoiceFormRecorder {
|
|
|
420
424
|
this.recordingStateChanged.emit({ isRecording: false, state: 'idle' });
|
|
421
425
|
}
|
|
422
426
|
}
|
|
427
|
+
extractConfidenceScores(filledData) {
|
|
428
|
+
const scores = {};
|
|
429
|
+
if (!filledData)
|
|
430
|
+
return scores;
|
|
431
|
+
// Fields array format: [{"id": "...", "name": "...", "value": "...", "confidence": 0.87}]
|
|
432
|
+
if (filledData.fields && Array.isArray(filledData.fields)) {
|
|
433
|
+
filledData.fields.forEach((field) => {
|
|
434
|
+
const raw = typeof field.confidence === 'number' ? field.confidence : parseFloat(field.confidence);
|
|
435
|
+
if (!isNaN(raw)) {
|
|
436
|
+
const clamped = Math.min(0.99, Math.max(0.01, Math.round(raw * 100) / 100));
|
|
437
|
+
// Store under both id and name so label-based lookups always work
|
|
438
|
+
if (field.id)
|
|
439
|
+
scores[field.id] = clamped;
|
|
440
|
+
if (field.name)
|
|
441
|
+
scores[field.name] = clamped;
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
// Simple schema format: {"schema": {...}, "confidence": {"field_name": 0.87}}
|
|
446
|
+
if (filledData.confidence && typeof filledData.confidence === 'object') {
|
|
447
|
+
Object.entries(filledData.confidence).forEach(([k, v]) => {
|
|
448
|
+
const raw = typeof v === 'number' ? v : parseFloat(v);
|
|
449
|
+
if (!isNaN(raw)) {
|
|
450
|
+
scores[k] = Math.min(0.99, Math.max(0.01, Math.round(raw * 100) / 100));
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return scores;
|
|
455
|
+
}
|
|
456
|
+
getFieldConfidence(primary, fallback) {
|
|
457
|
+
var _a, _b;
|
|
458
|
+
if (!this.confidenceScores)
|
|
459
|
+
return null;
|
|
460
|
+
return (_a = this.confidenceScores[primary]) !== null && _a !== void 0 ? _a : (fallback ? ((_b = this.confidenceScores[fallback]) !== null && _b !== void 0 ? _b : null) : null);
|
|
461
|
+
}
|
|
462
|
+
renderConfidenceIndicator(confidence) {
|
|
463
|
+
if (confidence === null || confidence >= 0.95)
|
|
464
|
+
return null;
|
|
465
|
+
const pct = Math.round(confidence * 100);
|
|
466
|
+
const isApproximate = confidence >= 0.85;
|
|
467
|
+
return (h("span", { class: `confidence-badge ${isApproximate ? 'confidence-medium' : 'confidence-low'}`, title: this.language === 'en' ? `Confidence: ${pct}%` : `Confiance : ${pct}%` }, pct, "%"));
|
|
468
|
+
}
|
|
423
469
|
extractFilledData(filledData) {
|
|
424
|
-
// console.log("extractFilledData", filledData);
|
|
425
470
|
const updatedSchema = JSON.parse(JSON.stringify(this.parsedSchema));
|
|
426
471
|
switch (this.context) {
|
|
427
472
|
case "ecoteka":
|
|
428
|
-
// console.log("TODO extractFilledData", filledData);
|
|
429
473
|
case "ng":
|
|
430
474
|
if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
|
|
431
475
|
// Map AI response back to original schema structure
|
|
@@ -440,7 +484,6 @@ export class VoiceFormRecorder {
|
|
|
440
484
|
}
|
|
441
485
|
break;
|
|
442
486
|
case "ecoll-veto":
|
|
443
|
-
// console.log("TODO extractFilledData", filledData, updatedSchema);
|
|
444
487
|
if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
|
|
445
488
|
// Map AI response back to original schema structure
|
|
446
489
|
filledData.fields.forEach((field) => {
|
|
@@ -481,15 +524,12 @@ export class VoiceFormRecorder {
|
|
|
481
524
|
}
|
|
482
525
|
break;
|
|
483
526
|
}
|
|
484
|
-
// console.log("extractFilledData result", updatedSchema);
|
|
485
527
|
return updatedSchema;
|
|
486
528
|
}
|
|
487
529
|
async trimSchemaForAI(schema) {
|
|
488
530
|
var _a, _b;
|
|
489
|
-
// console.log("trimSchemaForAI", schema);
|
|
490
531
|
switch (this.context) {
|
|
491
532
|
case "ecoteka":
|
|
492
|
-
// console.log("TODO trimSchemaForAI", schema)
|
|
493
533
|
case "ng":
|
|
494
534
|
const trimmed = { fields: [] };
|
|
495
535
|
schema.Children.forEach((child) => {
|
|
@@ -508,10 +548,8 @@ export class VoiceFormRecorder {
|
|
|
508
548
|
}
|
|
509
549
|
trimmed.fields.push(fieldData);
|
|
510
550
|
});
|
|
511
|
-
// console.log("Schema apres transformation, contexte NG:", trimmed);
|
|
512
551
|
return trimmed;
|
|
513
552
|
case "ecoll-veto":
|
|
514
|
-
// console.log("TODO trimSchemaForAI", schema)
|
|
515
553
|
const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
|
|
516
554
|
if (mergedItemsSchema) {
|
|
517
555
|
const trimmedSchema = {
|
|
@@ -558,7 +596,6 @@ export class VoiceFormRecorder {
|
|
|
558
596
|
default: '',
|
|
559
597
|
};
|
|
560
598
|
});
|
|
561
|
-
// console.log("Schema apres transformation, contexte Track:", trimmedSchema);
|
|
562
599
|
return trimmedSchema;
|
|
563
600
|
}
|
|
564
601
|
case "track":
|
|
@@ -755,13 +792,11 @@ export class VoiceFormRecorder {
|
|
|
755
792
|
return (h("div", { class: "form-preview" }, h("div", { class: "form-preview-title" }, title), h("form", { class: "voice-filled-form" }, this.renderFormFields())));
|
|
756
793
|
}
|
|
757
794
|
renderFormFields() {
|
|
758
|
-
// console.log("renderFormFields", this.parsedSchema);
|
|
759
795
|
if (!this.parsedSchema)
|
|
760
796
|
return null;
|
|
761
797
|
const largeFieldTypes = ['select', 'multiselect', 'classification', 'thesaurus', 'position'];
|
|
762
798
|
switch (this.context) {
|
|
763
799
|
case "ecoteka":
|
|
764
|
-
// console.log("TODO renderFormFields", this.parsedSchema);
|
|
765
800
|
case "ng":
|
|
766
801
|
return this.parsedSchema.Children.map((child) => {
|
|
767
802
|
var _a, _b, _c;
|
|
@@ -773,7 +808,7 @@ export class VoiceFormRecorder {
|
|
|
773
808
|
const isRequired = child.Required || false;
|
|
774
809
|
const fieldValue = (_b = child.Settings) === null || _b === void 0 ? void 0 : _b.Default_Value;
|
|
775
810
|
const isLargeField = largeFieldTypes.includes(fieldType) || (child.Children && child.Children.length > 5);
|
|
776
|
-
return (h("div", { class: isLargeField ? "form-group full-width" : "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*")), this.renderFormField(fieldName, {
|
|
811
|
+
return (h("div", { class: isLargeField ? "form-group full-width" : "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*"), this.renderConfidenceIndicator(this.getFieldConfidence(fieldLabel, fieldName))), this.renderFormField(fieldName, {
|
|
777
812
|
type: fieldType,
|
|
778
813
|
title: fieldLabel,
|
|
779
814
|
required: isRequired,
|
|
@@ -781,8 +816,6 @@ export class VoiceFormRecorder {
|
|
|
781
816
|
}, fieldValue)));
|
|
782
817
|
}).filter(Boolean);
|
|
783
818
|
case "ecoll-veto":
|
|
784
|
-
// NOTE STEP 2
|
|
785
|
-
// console.log("TODO renderFormFields", this.parsedSchema);
|
|
786
819
|
const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
|
|
787
820
|
return Object.entries(mergedItemsSchema).map(([key, field]) => {
|
|
788
821
|
var _a, _b;
|
|
@@ -813,7 +846,7 @@ export class VoiceFormRecorder {
|
|
|
813
846
|
// console.error("Error fetching classification data:", error);
|
|
814
847
|
// }
|
|
815
848
|
// }
|
|
816
|
-
return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*")), this.renderFormField(fieldName, field, ((_b = (_a = this.filledData) === null || _a === void 0 ? void 0 : _a[fieldName]) !== null && _b !== void 0 ? _b : fieldValue))));
|
|
849
|
+
return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*"), this.renderConfidenceIndicator(this.getFieldConfidence(fieldLabel, fieldName))), this.renderFormField(fieldName, field, ((_b = (_a = this.filledData) === null || _a === void 0 ? void 0 : _a[fieldName]) !== null && _b !== void 0 ? _b : fieldValue))));
|
|
817
850
|
});
|
|
818
851
|
case "track":
|
|
819
852
|
default:
|
|
@@ -822,7 +855,7 @@ export class VoiceFormRecorder {
|
|
|
822
855
|
if (field.type === 'header') {
|
|
823
856
|
return (h("div", { class: "form-header", key: fieldName }, field.title || fieldName));
|
|
824
857
|
}
|
|
825
|
-
return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, field.title || fieldName, field.required && h("span", { class: "required" }, "*")), this.renderFormField(fieldName, field, ((_b = (_a = this.filledData) === null || _a === void 0 ? void 0 : _a[fieldName]) !== null && _b !== void 0 ? _b : field.value))));
|
|
858
|
+
return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, field.title || fieldName, field.required && h("span", { class: "required" }, "*"), this.renderConfidenceIndicator(this.getFieldConfidence(fieldName))), this.renderFormField(fieldName, field, ((_b = (_a = this.filledData) === null || _a === void 0 ? void 0 : _a[fieldName]) !== null && _b !== void 0 ? _b : field.value))));
|
|
826
859
|
});
|
|
827
860
|
}
|
|
828
861
|
}
|
|
@@ -1281,6 +1314,7 @@ export class VoiceFormRecorder {
|
|
|
1281
1314
|
"hasTransientError": {},
|
|
1282
1315
|
"transcription": {},
|
|
1283
1316
|
"filledData": {},
|
|
1317
|
+
"confidenceScores": {},
|
|
1284
1318
|
"debugInfo": {},
|
|
1285
1319
|
"isReadonlyMode": {},
|
|
1286
1320
|
"isInitializing": {}
|