reneco-advanced-input-module 0.0.1

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 (108) hide show
  1. package/.editorconfig +15 -0
  2. package/.prettierrc.json +13 -0
  3. package/LICENSE +21 -0
  4. package/api-key-inject.js +46 -0
  5. package/dist/cjs/app-globals-V2Kpy_OQ.js +8 -0
  6. package/dist/cjs/app-globals-V2Kpy_OQ.js.map +1 -0
  7. package/dist/cjs/file-uploader.voice-input-module.entry.cjs.js.map +1 -0
  8. package/dist/cjs/file-uploader_2.cjs.entry.js +1319 -0
  9. package/dist/cjs/file-uploader_2.cjs.entry.js.map +1 -0
  10. package/dist/cjs/index-BTSzTkSZ.js +1494 -0
  11. package/dist/cjs/index-BTSzTkSZ.js.map +1 -0
  12. package/dist/cjs/index.cjs.js +5 -0
  13. package/dist/cjs/index.cjs.js.map +1 -0
  14. package/dist/cjs/loader.cjs.js +16 -0
  15. package/dist/cjs/loader.cjs.js.map +1 -0
  16. package/dist/cjs/voice-input-module.cjs.js +28 -0
  17. package/dist/cjs/voice-input-module.cjs.js.map +1 -0
  18. package/dist/collection/collection-manifest.json +13 -0
  19. package/dist/collection/components/file-uploader/file-uploader.css +26 -0
  20. package/dist/collection/components/file-uploader/file-uploader.js +130 -0
  21. package/dist/collection/components/file-uploader/file-uploader.js.map +1 -0
  22. package/dist/collection/components/voice-input-module/voice-input-module.css +251 -0
  23. package/dist/collection/components/voice-input-module/voice-input-module.js +875 -0
  24. package/dist/collection/components/voice-input-module/voice-input-module.js.map +1 -0
  25. package/dist/collection/index.js +12 -0
  26. package/dist/collection/index.js.map +1 -0
  27. package/dist/collection/services/audio-recorder.service.js +66 -0
  28. package/dist/collection/services/audio-recorder.service.js.map +1 -0
  29. package/dist/collection/services/llm.service.js +193 -0
  30. package/dist/collection/services/llm.service.js.map +1 -0
  31. package/dist/collection/services/speech-to-text.service.js +62 -0
  32. package/dist/collection/services/speech-to-text.service.js.map +1 -0
  33. package/dist/collection/types/form-schema.types.js +2 -0
  34. package/dist/collection/types/form-schema.types.js.map +1 -0
  35. package/dist/collection/types/service-providers.types.js +2 -0
  36. package/dist/collection/types/service-providers.types.js.map +1 -0
  37. package/dist/collection/utils/schema-converter.js +422 -0
  38. package/dist/collection/utils/schema-converter.js.map +1 -0
  39. package/dist/components/file-uploader.d.ts +11 -0
  40. package/dist/components/file-uploader.js +9 -0
  41. package/dist/components/file-uploader.js.map +1 -0
  42. package/dist/components/file-uploader2.js +98 -0
  43. package/dist/components/file-uploader2.js.map +1 -0
  44. package/dist/components/index.d.ts +33 -0
  45. package/dist/components/index.js +4 -0
  46. package/dist/components/index.js.map +1 -0
  47. package/dist/components/voice-input-module.d.ts +11 -0
  48. package/dist/components/voice-input-module.js +1292 -0
  49. package/dist/components/voice-input-module.js.map +1 -0
  50. package/dist/esm/app-globals-DQuL1Twl.js +6 -0
  51. package/dist/esm/app-globals-DQuL1Twl.js.map +1 -0
  52. package/dist/esm/file-uploader.voice-input-module.entry.js.map +1 -0
  53. package/dist/esm/file-uploader_2.entry.js +1316 -0
  54. package/dist/esm/file-uploader_2.entry.js.map +1 -0
  55. package/dist/esm/index-jmc2yzBp.js +1487 -0
  56. package/dist/esm/index-jmc2yzBp.js.map +1 -0
  57. package/dist/esm/index.js +4 -0
  58. package/dist/esm/index.js.map +1 -0
  59. package/dist/esm/loader.js +14 -0
  60. package/dist/esm/loader.js.map +1 -0
  61. package/dist/esm/voice-input-module.js +24 -0
  62. package/dist/esm/voice-input-module.js.map +1 -0
  63. package/dist/index.cjs.js +1 -0
  64. package/dist/index.js +1 -0
  65. package/dist/types/components/file-uploader/file-uploader.d.ts +8 -0
  66. package/dist/types/components/voice-input-module/voice-input-module.d.ts +55 -0
  67. package/dist/types/components.d.ts +158 -0
  68. package/dist/types/index.d.ts +9 -0
  69. package/dist/types/services/audio-recorder.service.d.ts +9 -0
  70. package/dist/types/services/llm.service.d.ts +15 -0
  71. package/dist/types/services/speech-to-text.service.d.ts +11 -0
  72. package/dist/types/stencil-public-runtime.d.ts +1709 -0
  73. package/dist/types/types/form-schema.types.d.ts +70 -0
  74. package/dist/types/types/service-providers.types.d.ts +20 -0
  75. package/dist/types/utils/schema-converter.d.ts +22 -0
  76. package/dist/voice-input-module/file-uploader.voice-input-module.entry.esm.js.map +1 -0
  77. package/dist/voice-input-module/index.esm.js +2 -0
  78. package/dist/voice-input-module/index.esm.js.map +1 -0
  79. package/dist/voice-input-module/loader.esm.js.map +1 -0
  80. package/dist/voice-input-module/p-7b4f33ba.entry.js +2 -0
  81. package/dist/voice-input-module/p-7b4f33ba.entry.js.map +1 -0
  82. package/dist/voice-input-module/p-DQuL1Twl.js +2 -0
  83. package/dist/voice-input-module/p-DQuL1Twl.js.map +1 -0
  84. package/dist/voice-input-module/p-jmc2yzBp.js +3 -0
  85. package/dist/voice-input-module/p-jmc2yzBp.js.map +1 -0
  86. package/dist/voice-input-module/voice-input-module.esm.js +2 -0
  87. package/dist/voice-input-module/voice-input-module.esm.js.map +1 -0
  88. package/env-config.js +4 -0
  89. package/inject-env.js +20 -0
  90. package/package.json +37 -0
  91. package/readme.md +111 -0
  92. package/src/components/file-uploader/file-uploader.css +26 -0
  93. package/src/components/file-uploader/file-uploader.tsx +100 -0
  94. package/src/components/file-uploader/readme.md +31 -0
  95. package/src/components/voice-input-module/readme.md +114 -0
  96. package/src/components/voice-input-module/voice-input-module.css +251 -0
  97. package/src/components/voice-input-module/voice-input-module.tsx +731 -0
  98. package/src/components.d.ts +158 -0
  99. package/src/index.html +663 -0
  100. package/src/index.ts +12 -0
  101. package/src/services/audio-recorder.service.ts +74 -0
  102. package/src/services/llm.service.ts +221 -0
  103. package/src/services/speech-to-text.service.ts +72 -0
  104. package/src/types/form-schema.types.ts +78 -0
  105. package/src/types/service-providers.types.ts +22 -0
  106. package/src/utils/schema-converter.ts +494 -0
  107. package/stencil.config.ts +24 -0
  108. package/tsconfig.json +30 -0
@@ -0,0 +1,875 @@
1
+ import { h } from "@stencil/core";
2
+ import { AudioRecorderService } from "../../services/audio-recorder.service";
3
+ import { SpeechToTextServiceFactory } from "../../services/speech-to-text.service";
4
+ import { LLMServiceFactory } from "../../services/llm.service";
5
+ import { SchemaConverter } from "../../utils/schema-converter";
6
+ export class VoiceFormRecorder {
7
+ constructor() {
8
+ this.formJson = '{}';
9
+ this.serviceConfig = '{}';
10
+ this.context = undefined;
11
+ this.classificationRootUrl = 'http://localhost';
12
+ this.language = 'en';
13
+ this.voiceOrOcr = undefined;
14
+ this.debug = false;
15
+ this.renderForm = false;
16
+ this.displayStatus = false;
17
+ this.isRecording = false;
18
+ this.isProcessing = false;
19
+ this.hasError = false;
20
+ this.transcription = '';
21
+ this.filledData = null;
22
+ this.debugInfo = {};
23
+ this.isReadonlyMode = true; // Start in readonly preview mode
24
+ this.audioRecorder = new AudioRecorderService();
25
+ }
26
+ componentWillLoad() {
27
+ this.initializeServices();
28
+ }
29
+ initializeServices() {
30
+ try {
31
+ if (!this.context) {
32
+ this.hasError = true;
33
+ const errorMessage = (this.language == 'en' ? `Initialization error: context is '${this.context}'` : `Erreur d'initialisation: le contexte est '${this.context}'`);
34
+ this.statusMessage = errorMessage;
35
+ this.updateDebugInfo(errorMessage, { error: errorMessage });
36
+ }
37
+ else {
38
+ // Parse form schema
39
+ this.parsedSchema = JSON.parse(this.formJson || '{}');
40
+ // Parse service configuration
41
+ this.parsedConfig = JSON.parse(this.serviceConfig || '{}');
42
+ // Add API key to config if provided via prop
43
+ if (this.apiKey) {
44
+ this.parsedConfig = Object.assign(Object.assign({}, this.parsedConfig), { speechToText: Object.assign(Object.assign({}, this.parsedConfig.speechToText), { apiKey: this.apiKey }), llm: Object.assign(Object.assign({}, this.parsedConfig.llm), { apiKey: this.apiKey }) });
45
+ }
46
+ // Initialize services
47
+ this.speechToTextService = SpeechToTextServiceFactory.create(this.parsedConfig);
48
+ this.llmService = LLMServiceFactory.create(this.parsedConfig);
49
+ this.updateDebugInfo('Initialized', {
50
+ schema: this.parsedSchema,
51
+ config: this.parsedConfig
52
+ });
53
+ this.hasError = false;
54
+ this.statusMessage = (this.language == 'en' ? 'Click to start recording' : 'Cliquer pour enregistrer');
55
+ }
56
+ }
57
+ catch (error) {
58
+ this.hasError = true;
59
+ this.statusMessage = (this.language == 'en' ? `Initialization error: ${error.message}` : `Erreur d'initialisation: ${error.message}`);
60
+ this.updateDebugInfo('Initialization Error', { error: error.message });
61
+ }
62
+ }
63
+ updateDebugInfo(action, data) {
64
+ if (this.debug) {
65
+ this.debugInfo = Object.assign(Object.assign({}, this.debugInfo), { [action]: {
66
+ timestamp: new Date().toISOString(),
67
+ data
68
+ } });
69
+ }
70
+ }
71
+ async handleRecordClick() {
72
+ if (this.isProcessing)
73
+ return;
74
+ if (this.isRecording) {
75
+ await this.stopRecordingAndProcess();
76
+ }
77
+ else {
78
+ await this.startRecording();
79
+ }
80
+ }
81
+ async startRecording() {
82
+ try {
83
+ this.hasError = false;
84
+ this.statusMessage = (this.language == 'en' ? 'Starting recording...' : `Enregistrement ...`);
85
+ this.updateDebugInfo('Start Recording Attempt', {});
86
+ await this.audioRecorder.startRecording();
87
+ this.isRecording = true;
88
+ this.statusMessage = (this.language == 'en' ? 'Recording... Click to stop' : 'Enregistrement ... Cliquer pour stopper');
89
+ this.updateDebugInfo('Recording Started', {});
90
+ this.recordingStateChanged.emit({
91
+ isRecording: true,
92
+ state: 'recording'
93
+ });
94
+ }
95
+ catch (error) {
96
+ this.hasError = true;
97
+ this.statusMessage = (this.language == 'en' ? `Recording failed: ${error.message}` : `Echec de l'enregistrement : ${error.message}`);
98
+ this.updateDebugInfo('Recording Error', { error: error.message });
99
+ this.formFilled.emit({
100
+ success: false,
101
+ error: error.message
102
+ });
103
+ }
104
+ }
105
+ async processJsonForm(jsonForm) {
106
+ // console.log("processJsonForm", jsonForm);
107
+ try {
108
+ this.isProcessing = true;
109
+ this.statusMessage = (this.language == 'en' ? 'Processing json...' : `Traitement du json ...`);
110
+ // Fill form using LLM
111
+ this.statusMessage = (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
112
+ const trimmedSchema = this.trimSchemaForAI(this.parsedSchema);
113
+ const filledSchema = await this.llmService.fillFormFromJson(jsonForm, trimmedSchema);
114
+ // Extract filled data
115
+ this.filledData = this.extractFilledData(filledSchema);
116
+ this.updateDebugInfo('Form Filled', {
117
+ filledSchema,
118
+ extractedData: this.filledData
119
+ });
120
+ this.parsedSchema = this.filledData;
121
+ this.statusMessage = (this.language == 'en' ? 'Form completed!' : 'Formulaire remplis !');
122
+ this.hasError = false;
123
+ // Emit success event
124
+ this.formFilled.emit({
125
+ success: true,
126
+ data: this.filledData,
127
+ jsonForm: jsonForm
128
+ });
129
+ }
130
+ catch (error) {
131
+ this.hasError = true;
132
+ this.statusMessage = (this.language == 'en' ? `Processing failed: ${error.message}` : `Erreur de traitement : ${error.message}`);
133
+ this.formFilled.emit({
134
+ success: false,
135
+ error: error.message,
136
+ jsonForm: jsonForm
137
+ });
138
+ }
139
+ finally {
140
+ this.isProcessing = false;
141
+ }
142
+ }
143
+ async stopRecordingAndProcess() {
144
+ try {
145
+ this.isRecording = false;
146
+ this.isProcessing = true;
147
+ this.statusMessage = (this.language == 'en' ? 'Processing audio...' : `Traitement de l'audio ...`);
148
+ this.updateDebugInfo('Stop Recording', {});
149
+ this.recordingStateChanged.emit({
150
+ isRecording: false,
151
+ state: 'processing'
152
+ });
153
+ // Stop recording and get audio blob
154
+ const audioBlob = await this.audioRecorder.stopRecording();
155
+ this.updateDebugInfo('Audio Captured', {
156
+ size: audioBlob.size,
157
+ type: audioBlob.type
158
+ });
159
+ // Transcribe audio
160
+ this.statusMessage = (this.language == 'en' ? 'Transcribing speech...' : 'Transcription du texte ...');
161
+ const transcription = await this.speechToTextService.transcribe(audioBlob, this.language);
162
+ this.transcription = transcription;
163
+ this.updateDebugInfo('Transcription Complete', { transcription });
164
+ if (!transcription.trim()) {
165
+ throw new Error('No speech detected in the recording');
166
+ }
167
+ // Fill form using LLM
168
+ this.statusMessage = (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
169
+ const trimmedSchema = this.trimSchemaForAI(this.parsedSchema);
170
+ const filledSchema = await this.llmService.fillFormFromTranscription(transcription, trimmedSchema);
171
+ // Extract filled data
172
+ this.filledData = this.extractFilledData(filledSchema);
173
+ this.updateDebugInfo('Form Filled', {
174
+ filledSchema,
175
+ extractedData: this.filledData
176
+ });
177
+ this.parsedSchema = this.filledData;
178
+ this.statusMessage = (this.language == 'en' ? 'Form completed!' : 'Formulaire remplis !');
179
+ this.hasError = false;
180
+ // Emit success event
181
+ this.formFilled.emit({
182
+ success: true,
183
+ data: this.filledData,
184
+ transcription: transcription
185
+ });
186
+ }
187
+ catch (error) {
188
+ this.hasError = true;
189
+ this.statusMessage = (this.language == 'en' ? `Processing failed: ${error.message}` : `Erreur de traitement : ${error.message}`);
190
+ this.updateDebugInfo('Processing Error', { error: error.message });
191
+ this.formFilled.emit({
192
+ success: false,
193
+ error: error.message,
194
+ transcription: this.transcription
195
+ });
196
+ }
197
+ finally {
198
+ this.isProcessing = false;
199
+ this.recordingStateChanged.emit({
200
+ isRecording: false,
201
+ state: 'idle'
202
+ });
203
+ }
204
+ }
205
+ extractFilledData(filledData) {
206
+ // console.log("extractFilledData", filledData);
207
+ const updatedSchema = JSON.parse(JSON.stringify(this.parsedSchema));
208
+ switch (this.context) {
209
+ case "ng":
210
+ if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
211
+ // Map AI response back to original schema structure
212
+ filledData.fields.forEach((field) => {
213
+ const originalField = updatedSchema.Children.find((child) => child.System_Name === field.name);
214
+ if (originalField && field.value !== undefined && field.value !== null && field.value !== '') {
215
+ if (!originalField.Settings)
216
+ originalField.Settings = {};
217
+ originalField.Settings.Default_Value = field.value;
218
+ }
219
+ });
220
+ }
221
+ break;
222
+ case "ecoll-veto":
223
+ // console.log("TODO extractFilledData", filledData, updatedSchema);
224
+ if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
225
+ // Map AI response back to original schema structure
226
+ filledData.fields.forEach((field) => {
227
+ let originalField = updatedSchema[0].items.find((child) => child.label === field.name);
228
+ if (!originalField)
229
+ originalField = updatedSchema[1].items.find((child) => child.label === field.name);
230
+ if (originalField && field.value !== undefined && field.value !== null && field.value !== '') {
231
+ updatedSchema[2][originalField.name] = field.value;
232
+ }
233
+ });
234
+ }
235
+ break;
236
+ case "ecoteka":
237
+ // console.log("TODO extractFilledData", filledData);
238
+ break;
239
+ case "track":
240
+ default:
241
+ const data = {};
242
+ Object.entries(filledData.fields).forEach(([fieldID, field]) => {
243
+ if (field.default !== undefined && field.default !== null && field.default !== '') {
244
+ updatedSchema[fieldID] = field.default;
245
+ }
246
+ if (field.value !== undefined && field.value !== null && field.value !== '') {
247
+ for (const key in updatedSchema.fields) {
248
+ const schemaField = updatedSchema.fields[key];
249
+ if (schemaField.title === field.name) {
250
+ schemaField.value = field.value || field.default;
251
+ schemaField.default = field.value || field.default;
252
+ break; // stop after finding the first match
253
+ }
254
+ }
255
+ }
256
+ });
257
+ break;
258
+ }
259
+ // console.log("extractFilledData result", updatedSchema);
260
+ return updatedSchema;
261
+ }
262
+ trimSchemaForAI(schema) {
263
+ var _a, _b;
264
+ // console.log("trimSchemaForAI", schema);
265
+ switch (this.context) {
266
+ case 'ng':
267
+ const trimmed = { fields: [] };
268
+ schema.Children.forEach((child) => {
269
+ if (!child.System_Name || !child.Type)
270
+ return;
271
+ const fieldData = {
272
+ name: child.System_Name,
273
+ type: this.mapFieldType(child.Type)
274
+ };
275
+ // Add options for classification/select fields
276
+ if (child.Type === 'InputClassification' && child.Children && child.Children.length > 0) {
277
+ fieldData.options = child.Children.map((option) => option.System_Name || option.Label || option.toString());
278
+ }
279
+ trimmed.fields.push(fieldData);
280
+ });
281
+ // console.log("Schema apres transformation, contexte NG:", trimmed);
282
+ return trimmed;
283
+ case 'ecoll-veto':
284
+ // console.log("TODO trimSchemaForAI", schema)
285
+ const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
286
+ if (mergedItemsSchema) {
287
+ const trimmedSchema = {
288
+ title: 'Form Name',
289
+ description: 'Form Description',
290
+ schema: {}
291
+ };
292
+ Object.entries(mergedItemsSchema).forEach(([key, field]) => {
293
+ const fieldName = field.name;
294
+ const fieldType = this.mapFieldType(field.type);
295
+ const fieldLabel = field.label || fieldName;
296
+ const isRequired = field.required || false;
297
+ const fieldValue = ''; //TODO
298
+ trimmedSchema.schema[fieldName] = {
299
+ type: fieldType,
300
+ title: fieldLabel,
301
+ options: field.options,
302
+ readonly: field.readonly === true,
303
+ default: '',
304
+ };
305
+ });
306
+ // console.log("Schema apres transformation, contexte Track:", trimmedSchema);
307
+ return trimmedSchema;
308
+ }
309
+ case "ecoteka":
310
+ // console.log("TODO trimSchemaForAI", schema)
311
+ break;
312
+ case 'track':
313
+ default:
314
+ // Handle simple schema format (backward compatibility)
315
+ if ((_a = schema === null || schema === void 0 ? void 0 : schema.schema) !== null && _a !== void 0 ? _a : schema === null || schema === void 0 ? void 0 : schema.fields) {
316
+ const trimmedSchema = {
317
+ title: schema.title,
318
+ description: schema.description,
319
+ schema: {}
320
+ };
321
+ const finalSchema = (_b = schema === null || schema === void 0 ? void 0 : schema.schema) !== null && _b !== void 0 ? _b : schema === null || schema === void 0 ? void 0 : schema.fields;
322
+ Object.entries(finalSchema).forEach(([fieldName, field]) => {
323
+ trimmedSchema.schema[fieldName] = {
324
+ type: field.type,
325
+ title: field.title,
326
+ options: field.options,
327
+ readonly: field.Enabled === false,
328
+ default: field.DefaultValue,
329
+ pattern: field.Mask,
330
+ min: field.ValidationMin,
331
+ max: field.ValidationMax
332
+ };
333
+ });
334
+ // console.log("Schema apres transformation, contexte Track:", trimmedSchema);
335
+ return trimmedSchema;
336
+ }
337
+ break;
338
+ }
339
+ return schema;
340
+ }
341
+ mapFieldType(type) {
342
+ const typeMapping = {
343
+ 'InputAutocomplete': 'string',
344
+ 'InputInteger': 'number',
345
+ 'InputTextArea': 'string',
346
+ 'InputDateTimePicker': 'datetime',
347
+ 'InputDecimal': 'number',
348
+ 'InputClassification': 'select',
349
+ 'InputCheckbox': 'boolean',
350
+ 'InputTextTranslation': 'string',
351
+ 'thesaurus': 'string',
352
+ 'position': 'string',
353
+ 'text': 'string',
354
+ 'textarea': 'string',
355
+ 'number': 'number',
356
+ 'date': 'date',
357
+ 'datetime': 'datetime'
358
+ };
359
+ return typeMapping[type] || 'string';
360
+ }
361
+ // Utility methods exposed as public API
362
+ async convertXmlToJson(xmlForm) {
363
+ return SchemaConverter.convertXmlToJson(xmlForm, this.classificationRootUrl, this.language);
364
+ }
365
+ async convertJsonToXml(jsonForm) {
366
+ return SchemaConverter.convertJsonToXml(jsonForm);
367
+ }
368
+ // Utility methods exposed as public API
369
+ async convertXmlToJsonLegacy(xmlForm) {
370
+ return SchemaConverter.convertXmlToJsonLegacy(xmlForm);
371
+ }
372
+ async convertJsonToXmlLegacy(jsonForm) {
373
+ return SchemaConverter.convertJsonToXmlLegacy(jsonForm);
374
+ }
375
+ renderUploadButton() {
376
+ if (!['ocr', 'both'].includes(this.voiceOrOcr))
377
+ return;
378
+ return (h("file-uploader", { batch: false, callback: (data) => { this.processJsonForm(data); } }));
379
+ }
380
+ renderRecordButton() {
381
+ if (!['voice', 'both', undefined].includes(this.voiceOrOcr))
382
+ return;
383
+ const buttonClass = [
384
+ 'record-button',
385
+ this.isRecording && 'recording',
386
+ this.isProcessing && 'processing'
387
+ ].filter(Boolean).join(' ');
388
+ const isDisabled = this.isProcessing || this.hasError;
389
+ return (h("button", { class: buttonClass, onClick: () => this.handleRecordClick(), disabled: isDisabled, "aria-label": this.isRecording ? 'Stop recording' : 'Start recording' }, this.isProcessing ? (h("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h("circle", { cx: "12", cy: "12", r: "3" }, h("animate", { attributeName: "r", values: "3;6;3", dur: "1s", repeatCount: "indefinite" }), h("animate", { attributeName: "opacity", values: "1;0.3;1", dur: "1s", repeatCount: "indefinite" })))) : this.isRecording ? (h("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }))) : (h("svg", { class: "record-icon", viewBox: "0 0 24 24" }, h("circle", { cx: "12", cy: "12", r: "8" })))));
390
+ }
391
+ renderStatusMessage() {
392
+ const statusClass = [
393
+ 'status-text',
394
+ this.hasError && 'error',
395
+ this.filledData && !this.hasError && 'success'
396
+ ].filter(Boolean).join(' ');
397
+ return h("div", { class: statusClass }, this.statusMessage);
398
+ }
399
+ renderFormPreview() {
400
+ if (!this.parsedSchema)
401
+ return null;
402
+ const isPreview = this.isReadonlyMode && !this.filledData;
403
+ const title = isPreview ? 'Form Preview (Voice input to fill)' : 'Voice-Filled Form:';
404
+ return (h("div", { class: "form-preview" }, h("div", { class: "form-preview-title" }, title), h("form", { class: "voice-filled-form" }, this.renderFormFields())));
405
+ }
406
+ renderFormFields() {
407
+ // console.log("renderFormFields", this.parsedSchema);
408
+ if (!this.parsedSchema)
409
+ return null;
410
+ switch (this.context) {
411
+ case "ng":
412
+ return this.parsedSchema.Children.map((child) => {
413
+ var _a, _b, _c;
414
+ if (!child.System_Name || !child.Type)
415
+ return null;
416
+ const fieldName = child.System_Name;
417
+ const fieldType = this.mapFieldType(child.Type);
418
+ const fieldLabel = ((_a = child.Settings) === null || _a === void 0 ? void 0 : _a.Label) || child.System_Name;
419
+ const isRequired = child.Required || false;
420
+ const fieldValue = (_b = child.Settings) === null || _b === void 0 ? void 0 : _b.Default_Value;
421
+ return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*")), this.renderFormField(fieldName, {
422
+ type: fieldType,
423
+ title: fieldLabel,
424
+ required: isRequired,
425
+ options: (_c = child.Children) === null || _c === void 0 ? void 0 : _c.map((option) => option.System_Name || option.Label || option.toString())
426
+ }, fieldValue)));
427
+ }).filter(Boolean);
428
+ case "ecoll-veto":
429
+ // NOTE STEP 2
430
+ // console.log("TODO renderFormFields", this.parsedSchema);
431
+ const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
432
+ return Object.entries(mergedItemsSchema).map(([key, field]) => {
433
+ var _a, _b;
434
+ const fieldName = field.name;
435
+ field.type = this.mapFieldType(field.type);
436
+ const fieldLabel = field.label || fieldName;
437
+ const isRequired = field.required || false;
438
+ const fieldValue = this.parsedSchema[2][fieldName];
439
+ 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))));
440
+ });
441
+ case "ecoteka":
442
+ // console.log("TODO renderFormFields", this.parsedSchema);
443
+ break;
444
+ case "track":
445
+ default:
446
+ return Object.entries(this.parsedSchema.fields).map(([fieldName, field]) => {
447
+ var _a, _b;
448
+ 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))));
449
+ });
450
+ }
451
+ return null;
452
+ }
453
+ renderFormField(fieldName, field, value) {
454
+ var _a, _b;
455
+ const isReadonly = this.isReadonlyMode && !this.filledData;
456
+ const commonProps = {
457
+ id: fieldName,
458
+ name: fieldName,
459
+ class: 'form-input',
460
+ required: field.required,
461
+ disabled: isReadonly
462
+ };
463
+ switch (field.type) {
464
+ case 'select':
465
+ if (isReadonly) {
466
+ // In readonly mode, show all options as a list instead of dropdown
467
+ return (h("div", { class: "readonly-select" }, h("div", { class: "select-placeholder" }, "Available options:"), h("ul", { class: "select-options-list" }, (_a = field.options) === null || _a === void 0 ? void 0 : _a.map(option => (h("li", { class: "select-option" }, option))))));
468
+ }
469
+ return (h("select", { id: fieldName, name: fieldName, class: "form-input", required: field.required }, h("option", { value: "" }, "-- Select --"), (_b = field.options) === null || _b === void 0 ? void 0 :
470
+ _b.map(option => (h("option", { value: option, selected: value === option }, option)))));
471
+ case 'boolean':
472
+ return (h("input", Object.assign({}, commonProps, { type: "checkbox", class: "form-checkbox", checked: value === true || value === 'true' })));
473
+ case 'number':
474
+ return (h("input", Object.assign({}, commonProps, { type: "number", min: field.min, max: field.max, step: "any", value: value || '' })));
475
+ case 'date':
476
+ return (h("input", Object.assign({}, commonProps, { type: 'date', value: value ? (([d, m, y]) => `${y}-${m}-${d}`)(value.split("/")) : '' })));
477
+ case 'datetime':
478
+ return (h("input", Object.assign({}, commonProps, { type: 'datetime-local', value: value || '' })));
479
+ default: // string
480
+ return (h("input", Object.assign({}, commonProps, { type: "text", pattern: field.pattern, placeholder: field.description, value: value || '' })));
481
+ }
482
+ }
483
+ renderDebugPanel() {
484
+ if (!this.debug)
485
+ return null;
486
+ return (h("div", { class: "debug-panel" }, h("div", { class: "debug-title" }, "Debug Information:"), h("div", { class: "debug-content" }, JSON.stringify(this.debugInfo, null, 2))));
487
+ }
488
+ render() {
489
+ return (h("div", { key: '40d850c62945b71d22c1fcb6181c9e8aba0f2a05' }, h("div", { key: 'da8aa5b7f122471a8d4d49662d418bd925f1d84c', class: "voice-recorder-container" + (this.debug || this.renderForm ? "-debug" : "") }, this.renderRecordButton(), this.displayStatus ? this.renderStatusMessage() : "", this.renderUploadButton(), this.renderForm ? this.renderFormPreview() : "", this.debug ? this.renderDebugPanel() : "")));
490
+ }
491
+ static get is() { return "voice-input-module"; }
492
+ static get encapsulation() { return "shadow"; }
493
+ static get originalStyleUrls() {
494
+ return {
495
+ "$": ["voice-input-module.css"]
496
+ };
497
+ }
498
+ static get styleUrls() {
499
+ return {
500
+ "$": ["voice-input-module.css"]
501
+ };
502
+ }
503
+ static get properties() {
504
+ return {
505
+ "formJson": {
506
+ "type": "string",
507
+ "attribute": "form-json",
508
+ "mutable": false,
509
+ "complexType": {
510
+ "original": "string",
511
+ "resolved": "string",
512
+ "references": {}
513
+ },
514
+ "required": false,
515
+ "optional": false,
516
+ "docs": {
517
+ "tags": [],
518
+ "text": ""
519
+ },
520
+ "getter": false,
521
+ "setter": false,
522
+ "reflect": false,
523
+ "defaultValue": "'{}'"
524
+ },
525
+ "serviceConfig": {
526
+ "type": "string",
527
+ "attribute": "service-config",
528
+ "mutable": false,
529
+ "complexType": {
530
+ "original": "string",
531
+ "resolved": "string",
532
+ "references": {}
533
+ },
534
+ "required": false,
535
+ "optional": false,
536
+ "docs": {
537
+ "tags": [],
538
+ "text": ""
539
+ },
540
+ "getter": false,
541
+ "setter": false,
542
+ "reflect": false,
543
+ "defaultValue": "'{}'"
544
+ },
545
+ "apiKey": {
546
+ "type": "string",
547
+ "attribute": "api-key",
548
+ "mutable": false,
549
+ "complexType": {
550
+ "original": "string",
551
+ "resolved": "string",
552
+ "references": {}
553
+ },
554
+ "required": false,
555
+ "optional": false,
556
+ "docs": {
557
+ "tags": [],
558
+ "text": ""
559
+ },
560
+ "getter": false,
561
+ "setter": false,
562
+ "reflect": false
563
+ },
564
+ "context": {
565
+ "type": "string",
566
+ "attribute": "context",
567
+ "mutable": false,
568
+ "complexType": {
569
+ "original": "'track'|'ng'|'ecoll-veto'|'ecoteka'",
570
+ "resolved": "\"ecoll-veto\" | \"ecoteka\" | \"ng\" | \"track\"",
571
+ "references": {}
572
+ },
573
+ "required": false,
574
+ "optional": false,
575
+ "docs": {
576
+ "tags": [],
577
+ "text": ""
578
+ },
579
+ "getter": false,
580
+ "setter": false,
581
+ "reflect": false,
582
+ "defaultValue": "undefined"
583
+ },
584
+ "classificationRootUrl": {
585
+ "type": "string",
586
+ "attribute": "classification-root-url",
587
+ "mutable": false,
588
+ "complexType": {
589
+ "original": "string",
590
+ "resolved": "string",
591
+ "references": {}
592
+ },
593
+ "required": false,
594
+ "optional": false,
595
+ "docs": {
596
+ "tags": [],
597
+ "text": ""
598
+ },
599
+ "getter": false,
600
+ "setter": false,
601
+ "reflect": false,
602
+ "defaultValue": "'http://localhost'"
603
+ },
604
+ "language": {
605
+ "type": "string",
606
+ "attribute": "language",
607
+ "mutable": false,
608
+ "complexType": {
609
+ "original": "'fr'|'en'",
610
+ "resolved": "\"en\" | \"fr\"",
611
+ "references": {}
612
+ },
613
+ "required": false,
614
+ "optional": false,
615
+ "docs": {
616
+ "tags": [],
617
+ "text": ""
618
+ },
619
+ "getter": false,
620
+ "setter": false,
621
+ "reflect": false,
622
+ "defaultValue": "'en'"
623
+ },
624
+ "voiceOrOcr": {
625
+ "type": "string",
626
+ "attribute": "voice-or-ocr",
627
+ "mutable": false,
628
+ "complexType": {
629
+ "original": "'voice'|'ocr'|'both'",
630
+ "resolved": "\"both\" | \"ocr\" | \"voice\"",
631
+ "references": {}
632
+ },
633
+ "required": false,
634
+ "optional": false,
635
+ "docs": {
636
+ "tags": [],
637
+ "text": ""
638
+ },
639
+ "getter": false,
640
+ "setter": false,
641
+ "reflect": false,
642
+ "defaultValue": "undefined"
643
+ },
644
+ "debug": {
645
+ "type": "boolean",
646
+ "attribute": "debug",
647
+ "mutable": false,
648
+ "complexType": {
649
+ "original": "boolean",
650
+ "resolved": "boolean",
651
+ "references": {}
652
+ },
653
+ "required": false,
654
+ "optional": false,
655
+ "docs": {
656
+ "tags": [],
657
+ "text": ""
658
+ },
659
+ "getter": false,
660
+ "setter": false,
661
+ "reflect": false,
662
+ "defaultValue": "false"
663
+ },
664
+ "renderForm": {
665
+ "type": "boolean",
666
+ "attribute": "render-form",
667
+ "mutable": false,
668
+ "complexType": {
669
+ "original": "boolean",
670
+ "resolved": "boolean",
671
+ "references": {}
672
+ },
673
+ "required": false,
674
+ "optional": false,
675
+ "docs": {
676
+ "tags": [],
677
+ "text": ""
678
+ },
679
+ "getter": false,
680
+ "setter": false,
681
+ "reflect": false,
682
+ "defaultValue": "false"
683
+ },
684
+ "displayStatus": {
685
+ "type": "boolean",
686
+ "attribute": "display-status",
687
+ "mutable": false,
688
+ "complexType": {
689
+ "original": "boolean",
690
+ "resolved": "boolean",
691
+ "references": {}
692
+ },
693
+ "required": false,
694
+ "optional": false,
695
+ "docs": {
696
+ "tags": [],
697
+ "text": ""
698
+ },
699
+ "getter": false,
700
+ "setter": false,
701
+ "reflect": false,
702
+ "defaultValue": "false"
703
+ }
704
+ };
705
+ }
706
+ static get states() {
707
+ return {
708
+ "isRecording": {},
709
+ "isProcessing": {},
710
+ "statusMessage": {},
711
+ "hasError": {},
712
+ "transcription": {},
713
+ "filledData": {},
714
+ "debugInfo": {},
715
+ "isReadonlyMode": {}
716
+ };
717
+ }
718
+ static get events() {
719
+ return [{
720
+ "method": "formFilled",
721
+ "name": "formFilled",
722
+ "bubbles": true,
723
+ "cancelable": true,
724
+ "composed": true,
725
+ "docs": {
726
+ "tags": [],
727
+ "text": ""
728
+ },
729
+ "complexType": {
730
+ "original": "VoiceFormRecorderResult",
731
+ "resolved": "VoiceFormRecorderResult",
732
+ "references": {
733
+ "VoiceFormRecorderResult": {
734
+ "location": "import",
735
+ "path": "../../types/form-schema.types",
736
+ "id": "src/types/form-schema.types.ts::VoiceFormRecorderResult"
737
+ }
738
+ }
739
+ }
740
+ }, {
741
+ "method": "recordingStateChanged",
742
+ "name": "recordingStateChanged",
743
+ "bubbles": true,
744
+ "cancelable": true,
745
+ "composed": true,
746
+ "docs": {
747
+ "tags": [],
748
+ "text": ""
749
+ },
750
+ "complexType": {
751
+ "original": "{ isRecording: boolean; state: string }",
752
+ "resolved": "{ isRecording: boolean; state: string; }",
753
+ "references": {}
754
+ }
755
+ }];
756
+ }
757
+ static get methods() {
758
+ return {
759
+ "convertXmlToJson": {
760
+ "complexType": {
761
+ "signature": "(xmlForm: string) => Promise<FormSchemaFieldsOnly>",
762
+ "parameters": [{
763
+ "name": "xmlForm",
764
+ "type": "string",
765
+ "docs": ""
766
+ }],
767
+ "references": {
768
+ "Promise": {
769
+ "location": "global",
770
+ "id": "global::Promise"
771
+ },
772
+ "FormSchemaFieldsOnly": {
773
+ "location": "import",
774
+ "path": "../../types/form-schema.types",
775
+ "id": "src/types/form-schema.types.ts::FormSchemaFieldsOnly"
776
+ }
777
+ },
778
+ "return": "Promise<FormSchemaFieldsOnly>"
779
+ },
780
+ "docs": {
781
+ "text": "",
782
+ "tags": []
783
+ }
784
+ },
785
+ "convertJsonToXml": {
786
+ "complexType": {
787
+ "signature": "(jsonForm: FormSchemaFieldsOnlyExtended) => Promise<string>",
788
+ "parameters": [{
789
+ "name": "jsonForm",
790
+ "type": "FormSchemaFieldsOnlyExtended",
791
+ "docs": ""
792
+ }],
793
+ "references": {
794
+ "Promise": {
795
+ "location": "global",
796
+ "id": "global::Promise"
797
+ },
798
+ "FormSchemaFieldsOnlyExtended": {
799
+ "location": "import",
800
+ "path": "../../types/form-schema.types",
801
+ "id": "src/types/form-schema.types.ts::FormSchemaFieldsOnlyExtended"
802
+ }
803
+ },
804
+ "return": "Promise<string>"
805
+ },
806
+ "docs": {
807
+ "text": "",
808
+ "tags": []
809
+ }
810
+ },
811
+ "convertXmlToJsonLegacy": {
812
+ "complexType": {
813
+ "signature": "(xmlForm: string) => Promise<FormSchema>",
814
+ "parameters": [{
815
+ "name": "xmlForm",
816
+ "type": "string",
817
+ "docs": ""
818
+ }],
819
+ "references": {
820
+ "Promise": {
821
+ "location": "global",
822
+ "id": "global::Promise"
823
+ },
824
+ "FormSchema": {
825
+ "location": "import",
826
+ "path": "../../types/form-schema.types",
827
+ "id": "src/types/form-schema.types.ts::FormSchema"
828
+ }
829
+ },
830
+ "return": "Promise<FormSchema>"
831
+ },
832
+ "docs": {
833
+ "text": "",
834
+ "tags": []
835
+ }
836
+ },
837
+ "convertJsonToXmlLegacy": {
838
+ "complexType": {
839
+ "signature": "(jsonForm: FormSchema) => Promise<string>",
840
+ "parameters": [{
841
+ "name": "jsonForm",
842
+ "type": "FormSchema",
843
+ "docs": ""
844
+ }],
845
+ "references": {
846
+ "Promise": {
847
+ "location": "global",
848
+ "id": "global::Promise"
849
+ },
850
+ "FormSchema": {
851
+ "location": "import",
852
+ "path": "../../types/form-schema.types",
853
+ "id": "src/types/form-schema.types.ts::FormSchema"
854
+ }
855
+ },
856
+ "return": "Promise<string>"
857
+ },
858
+ "docs": {
859
+ "text": "",
860
+ "tags": []
861
+ }
862
+ }
863
+ };
864
+ }
865
+ static get watchers() {
866
+ return [{
867
+ "propName": "formJson",
868
+ "methodName": "initializeServices"
869
+ }, {
870
+ "propName": "serviceConfig",
871
+ "methodName": "initializeServices"
872
+ }];
873
+ }
874
+ }
875
+ //# sourceMappingURL=voice-input-module.js.map