reneco-advanced-input-module 0.0.25 → 0.0.27

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.
Files changed (35) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/voice-input-module.cjs.entry.js +73 -28
  3. package/dist/cjs/voice-input-module.cjs.entry.js.map +1 -1
  4. package/dist/cjs/voice-input-module.cjs.js +1 -1
  5. package/dist/cjs/voice-input-module.entry.cjs.js.map +1 -1
  6. package/dist/collection/components/voice-input-module/voice-input-module.css +26 -3
  7. package/dist/collection/components/voice-input-module/voice-input-module.js +65 -23
  8. package/dist/collection/components/voice-input-module/voice-input-module.js.map +1 -1
  9. package/dist/collection/services/llm.service.js +8 -4
  10. package/dist/collection/services/llm.service.js.map +1 -1
  11. package/dist/collection/types/form-schema.types.js.map +1 -1
  12. package/dist/components/voice-input-module.js +74 -28
  13. package/dist/components/voice-input-module.js.map +1 -1
  14. package/dist/esm/loader.js +1 -1
  15. package/dist/esm/voice-input-module.entry.js +73 -28
  16. package/dist/esm/voice-input-module.entry.js.map +1 -1
  17. package/dist/esm/voice-input-module.js +1 -1
  18. package/dist/types/components/voice-input-module/voice-input-module.d.ts +4 -0
  19. package/dist/types/types/form-schema.types.d.ts +1 -0
  20. package/dist/voice-input-module/p-20ef690a.entry.js +3 -0
  21. package/dist/voice-input-module/p-20ef690a.entry.js.map +1 -0
  22. package/dist/voice-input-module/voice-input-module.entry.esm.js.map +1 -1
  23. package/dist/voice-input-module/voice-input-module.esm.js +1 -1
  24. package/package.json +1 -1
  25. package/www/build/p-14ee7fca.js +2 -0
  26. package/www/build/p-20ef690a.entry.js +3 -0
  27. package/www/build/p-20ef690a.entry.js.map +1 -0
  28. package/www/build/voice-input-module.entry.esm.js.map +1 -1
  29. package/www/build/voice-input-module.esm.js +1 -1
  30. package/www/index.html +9 -9
  31. package/dist/voice-input-module/p-334644ec.entry.js +0 -3
  32. package/dist/voice-input-module/p-334644ec.entry.js.map +0 -1
  33. package/www/build/p-334644ec.entry.js +0 -3
  34. package/www/build/p-334644ec.entry.js.map +0 -1
  35. 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.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData });
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.updateDebugInfo('Form Filled', { filledSchema, extractedData: this.filledData });
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
- // processAudioContent manages isProcessing itself; await ensures we don't return early
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
@@ -435,12 +479,13 @@ export class VoiceFormRecorder {
435
479
  if (!originalField.Settings)
436
480
  originalField.Settings = {};
437
481
  originalField.Settings.Default_Value = field.value;
482
+ const rawConf = typeof field.confidence === 'number' ? field.confidence : parseFloat(field.confidence);
483
+ originalField.confidence = isNaN(rawConf) ? null : rawConf;
438
484
  }
439
485
  });
440
486
  }
441
487
  break;
442
488
  case "ecoll-veto":
443
- // console.log("TODO extractFilledData", filledData, updatedSchema);
444
489
  if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
445
490
  // Map AI response back to original schema structure
446
491
  filledData.fields.forEach((field) => {
@@ -449,6 +494,8 @@ export class VoiceFormRecorder {
449
494
  originalField = updatedSchema[1].items.find((child) => child.label === field.name);
450
495
  if (originalField && field.value !== undefined && field.value !== null && field.value !== '') {
451
496
  updatedSchema[2][originalField.name] = field.value;
497
+ const rawConf = typeof field.confidence === 'number' ? field.confidence : parseFloat(field.confidence);
498
+ originalField.confidence = isNaN(rawConf) ? null : rawConf;
452
499
  }
453
500
  });
454
501
  }
@@ -458,11 +505,14 @@ export class VoiceFormRecorder {
458
505
  if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
459
506
  Object.entries(filledData.fields).forEach(([fieldID, field]) => {
460
507
  if (field.value !== undefined && field.value !== null && field.value !== '') {
508
+ const rawConf = typeof field.confidence === 'number' ? field.confidence : parseFloat(field.confidence);
509
+ const confidence = isNaN(rawConf) ? null : rawConf;
461
510
  if (field.id) {
462
511
  const schemaField = updatedSchema.fields[field.id];
463
512
  if (schemaField) {
464
513
  schemaField.value = field.value;
465
514
  schemaField.default = field.value;
515
+ schemaField.confidence = confidence;
466
516
  }
467
517
  }
468
518
  else {
@@ -472,6 +522,7 @@ export class VoiceFormRecorder {
472
522
  if (schemaField.title === fieldName) {
473
523
  schemaField.value = field.value;
474
524
  schemaField.default = field.value;
525
+ schemaField.confidence = confidence;
475
526
  break;
476
527
  }
477
528
  }
@@ -481,15 +532,12 @@ export class VoiceFormRecorder {
481
532
  }
482
533
  break;
483
534
  }
484
- // console.log("extractFilledData result", updatedSchema);
485
535
  return updatedSchema;
486
536
  }
487
537
  async trimSchemaForAI(schema) {
488
538
  var _a, _b;
489
- // console.log("trimSchemaForAI", schema);
490
539
  switch (this.context) {
491
540
  case "ecoteka":
492
- // console.log("TODO trimSchemaForAI", schema)
493
541
  case "ng":
494
542
  const trimmed = { fields: [] };
495
543
  schema.Children.forEach((child) => {
@@ -508,10 +556,8 @@ export class VoiceFormRecorder {
508
556
  }
509
557
  trimmed.fields.push(fieldData);
510
558
  });
511
- // console.log("Schema apres transformation, contexte NG:", trimmed);
512
559
  return trimmed;
513
560
  case "ecoll-veto":
514
- // console.log("TODO trimSchemaForAI", schema)
515
561
  const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
516
562
  if (mergedItemsSchema) {
517
563
  const trimmedSchema = {
@@ -558,7 +604,6 @@ export class VoiceFormRecorder {
558
604
  default: '',
559
605
  };
560
606
  });
561
- // console.log("Schema apres transformation, contexte Track:", trimmedSchema);
562
607
  return trimmedSchema;
563
608
  }
564
609
  case "track":
@@ -755,13 +800,11 @@ export class VoiceFormRecorder {
755
800
  return (h("div", { class: "form-preview" }, h("div", { class: "form-preview-title" }, title), h("form", { class: "voice-filled-form" }, this.renderFormFields())));
756
801
  }
757
802
  renderFormFields() {
758
- // console.log("renderFormFields", this.parsedSchema);
759
803
  if (!this.parsedSchema)
760
804
  return null;
761
805
  const largeFieldTypes = ['select', 'multiselect', 'classification', 'thesaurus', 'position'];
762
806
  switch (this.context) {
763
807
  case "ecoteka":
764
- // console.log("TODO renderFormFields", this.parsedSchema);
765
808
  case "ng":
766
809
  return this.parsedSchema.Children.map((child) => {
767
810
  var _a, _b, _c;
@@ -773,7 +816,7 @@ export class VoiceFormRecorder {
773
816
  const isRequired = child.Required || false;
774
817
  const fieldValue = (_b = child.Settings) === null || _b === void 0 ? void 0 : _b.Default_Value;
775
818
  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, {
819
+ 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
820
  type: fieldType,
778
821
  title: fieldLabel,
779
822
  required: isRequired,
@@ -781,8 +824,6 @@ export class VoiceFormRecorder {
781
824
  }, fieldValue)));
782
825
  }).filter(Boolean);
783
826
  case "ecoll-veto":
784
- // NOTE STEP 2
785
- // console.log("TODO renderFormFields", this.parsedSchema);
786
827
  const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
787
828
  return Object.entries(mergedItemsSchema).map(([key, field]) => {
788
829
  var _a, _b;
@@ -813,7 +854,7 @@ export class VoiceFormRecorder {
813
854
  // console.error("Error fetching classification data:", error);
814
855
  // }
815
856
  // }
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))));
857
+ 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
858
  });
818
859
  case "track":
819
860
  default:
@@ -822,7 +863,7 @@ export class VoiceFormRecorder {
822
863
  if (field.type === 'header') {
823
864
  return (h("div", { class: "form-header", key: fieldName }, field.title || fieldName));
824
865
  }
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))));
866
+ 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
867
  });
827
868
  }
828
869
  }
@@ -1281,6 +1322,7 @@ export class VoiceFormRecorder {
1281
1322
  "hasTransientError": {},
1282
1323
  "transcription": {},
1283
1324
  "filledData": {},
1325
+ "confidenceScores": {},
1284
1326
  "debugInfo": {},
1285
1327
  "isReadonlyMode": {},
1286
1328
  "isInitializing": {}