reneco-advanced-input-module 0.0.1-beta.2 → 0.0.2

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 (101) hide show
  1. package/dist/types/components/voice-input-module/voice-input-module.d.ts +4 -1
  2. package/dist/types/components.d.ts +4 -27
  3. package/dist/voice-input-module/index-Lt4F-TYq.js +4334 -0
  4. package/dist/voice-input-module/index-Lt4F-TYq.js.map +1 -0
  5. package/dist/voice-input-module/index.esm.js +12 -0
  6. package/dist/voice-input-module/index.esm.js.map +1 -1
  7. package/dist/voice-input-module/loader.esm.js.map +1 -1
  8. package/dist/voice-input-module/ocr-file-uploader.entry.esm.js.map +1 -0
  9. package/dist/{components/ocr-file-uploader2.js → voice-input-module/ocr-file-uploader.entry.js} +13 -28
  10. package/dist/voice-input-module/ocr-file-uploader.entry.js.map +1 -0
  11. package/dist/voice-input-module/voice-input-module.entry.esm.js.map +1 -0
  12. package/dist/voice-input-module/voice-input-module.entry.js +4467 -0
  13. package/dist/voice-input-module/voice-input-module.entry.js.map +1 -0
  14. package/dist/voice-input-module/voice-input-module.esm.js +49 -1
  15. package/dist/voice-input-module/voice-input-module.esm.js.map +1 -1
  16. package/package.json +2 -2
  17. package/www/build/index-Lt4F-TYq.js +4334 -0
  18. package/www/build/index-Lt4F-TYq.js.map +1 -0
  19. package/www/build/index.esm.js +12 -0
  20. package/www/build/index.esm.js.map +1 -1
  21. package/www/build/loader.esm.js.map +1 -1
  22. package/www/build/ocr-file-uploader.entry.esm.js.map +1 -0
  23. package/{dist/collection/components/ocr-file-uploader/ocr-file-uploader.js → www/build/ocr-file-uploader.entry.js} +18 -65
  24. package/www/build/ocr-file-uploader.entry.js.map +1 -0
  25. package/www/build/voice-input-module.entry.esm.js.map +1 -0
  26. package/www/build/voice-input-module.entry.js +4467 -0
  27. package/www/build/voice-input-module.entry.js.map +1 -0
  28. package/www/build/voice-input-module.esm.js +49 -1
  29. package/www/build/voice-input-module.esm.js.map +1 -1
  30. package/www/index.html +976 -227
  31. package/dist/cjs/app-globals-V2Kpy_OQ.js +0 -8
  32. package/dist/cjs/app-globals-V2Kpy_OQ.js.map +0 -1
  33. package/dist/cjs/index-BTSzTkSZ.js +0 -1494
  34. package/dist/cjs/index-BTSzTkSZ.js.map +0 -1
  35. package/dist/cjs/index.cjs.js +0 -5
  36. package/dist/cjs/index.cjs.js.map +0 -1
  37. package/dist/cjs/loader.cjs.js +0 -16
  38. package/dist/cjs/loader.cjs.js.map +0 -1
  39. package/dist/cjs/ocr-file-uploader.voice-input-module.entry.cjs.js.map +0 -1
  40. package/dist/cjs/ocr-file-uploader_2.cjs.entry.js +0 -1340
  41. package/dist/cjs/ocr-file-uploader_2.cjs.entry.js.map +0 -1
  42. package/dist/cjs/voice-input-module.cjs.js +0 -28
  43. package/dist/cjs/voice-input-module.cjs.js.map +0 -1
  44. package/dist/collection/collection-manifest.json +0 -13
  45. package/dist/collection/components/ocr-file-uploader/ocr-file-uploader.css +0 -26
  46. package/dist/collection/components/ocr-file-uploader/ocr-file-uploader.js.map +0 -1
  47. package/dist/collection/components/voice-input-module/voice-input-module.css +0 -286
  48. package/dist/collection/components/voice-input-module/voice-input-module.js +0 -897
  49. package/dist/collection/components/voice-input-module/voice-input-module.js.map +0 -1
  50. package/dist/collection/index.js +0 -12
  51. package/dist/collection/index.js.map +0 -1
  52. package/dist/collection/services/audio-recorder.service.js +0 -66
  53. package/dist/collection/services/audio-recorder.service.js.map +0 -1
  54. package/dist/collection/services/llm.service.js +0 -193
  55. package/dist/collection/services/llm.service.js.map +0 -1
  56. package/dist/collection/services/speech-to-text.service.js +0 -60
  57. package/dist/collection/services/speech-to-text.service.js.map +0 -1
  58. package/dist/collection/types/form-schema.types.js +0 -2
  59. package/dist/collection/types/form-schema.types.js.map +0 -1
  60. package/dist/collection/types/service-providers.types.js +0 -2
  61. package/dist/collection/types/service-providers.types.js.map +0 -1
  62. package/dist/collection/utils/schema-converter.js +0 -422
  63. package/dist/collection/utils/schema-converter.js.map +0 -1
  64. package/dist/components/index.js +0 -4
  65. package/dist/components/index.js.map +0 -1
  66. package/dist/components/ocr-file-uploader.d.ts +0 -11
  67. package/dist/components/ocr-file-uploader.js +0 -9
  68. package/dist/components/ocr-file-uploader.js.map +0 -1
  69. package/dist/components/ocr-file-uploader2.js.map +0 -1
  70. package/dist/components/voice-input-module.js +0 -1313
  71. package/dist/components/voice-input-module.js.map +0 -1
  72. package/dist/esm/app-globals-DQuL1Twl.js +0 -6
  73. package/dist/esm/app-globals-DQuL1Twl.js.map +0 -1
  74. package/dist/esm/index-jmc2yzBp.js +0 -1487
  75. package/dist/esm/index-jmc2yzBp.js.map +0 -1
  76. package/dist/esm/index.js +0 -4
  77. package/dist/esm/index.js.map +0 -1
  78. package/dist/esm/loader.js +0 -14
  79. package/dist/esm/loader.js.map +0 -1
  80. package/dist/esm/ocr-file-uploader.voice-input-module.entry.js.map +0 -1
  81. package/dist/esm/ocr-file-uploader_2.entry.js +0 -1337
  82. package/dist/esm/ocr-file-uploader_2.entry.js.map +0 -1
  83. package/dist/esm/voice-input-module.js +0 -24
  84. package/dist/esm/voice-input-module.js.map +0 -1
  85. package/dist/index.cjs.js +0 -1
  86. package/dist/index.js +0 -1
  87. package/dist/types/components/ocr-file-uploader/ocr-file-uploader.d.ts +0 -8
  88. package/dist/voice-input-module/ocr-file-uploader.voice-input-module.entry.esm.js.map +0 -1
  89. package/dist/voice-input-module/p-52e59129.entry.js +0 -2
  90. package/dist/voice-input-module/p-52e59129.entry.js.map +0 -1
  91. package/dist/voice-input-module/p-DQuL1Twl.js +0 -2
  92. package/dist/voice-input-module/p-DQuL1Twl.js.map +0 -1
  93. package/dist/voice-input-module/p-jmc2yzBp.js +0 -3
  94. package/dist/voice-input-module/p-jmc2yzBp.js.map +0 -1
  95. package/www/build/ocr-file-uploader.voice-input-module.entry.esm.js.map +0 -1
  96. package/www/build/p-52e59129.entry.js +0 -2
  97. package/www/build/p-52e59129.entry.js.map +0 -1
  98. package/www/build/p-DQuL1Twl.js +0 -2
  99. package/www/build/p-DQuL1Twl.js.map +0 -1
  100. package/www/build/p-jmc2yzBp.js +0 -3
  101. package/www/build/p-jmc2yzBp.js.map +0 -1
@@ -1,1337 +0,0 @@
1
- import { r as registerInstance, h, c as createEvent } from './index-jmc2yzBp.js';
2
-
3
- const ocrFileUploaderCss = ".upload-container{display:inline-block;cursor:pointer;width:50px;height:50px}.upload-button{display:flex;align-items:center;justify-content:center;transition:transform 0.2s ease, box-shadow 0.2s ease;user-select:none}.upload-button svg{width:50px;height:50px;stroke:#44ee44}.upload-button:hover svg{transform:scale(1.05);stroke:#33dd33}";
4
-
5
- const OcrFileUploader = class {
6
- constructor(hostRef) {
7
- registerInstance(this, hostRef);
8
- this.batch = false;
9
- this.triggerUpload = () => {
10
- this.fileInput.click();
11
- };
12
- this.handleFileChange = async (event) => {
13
- const input = event.target;
14
- if (!input.files || input.files.length === 0)
15
- return;
16
- const file = input.files[0];
17
- // Here you can handle the file upload to your API
18
- console.log('Selected file:', file);
19
- const formData = new FormData();
20
- formData.append('file', file);
21
- if (this.batch) {
22
- try {
23
- const response = await fetch('http://127.0.0.1:5001/api/convert-to-xml', {
24
- method: 'POST',
25
- body: formData
26
- });
27
- if (!response.ok) {
28
- console.error("There has been an error!:", response);
29
- throw new Error(`HTTP error! status: ${response.status}`);
30
- }
31
- // get the file as a blob
32
- const blob = await response.blob();
33
- // create a download link
34
- const url = window.URL.createObjectURL(blob);
35
- const a = document.createElement('a');
36
- a.href = url;
37
- a.download = 'result-' + Date.now().toString() + '.xlsx'; // filename
38
- document.body.appendChild(a);
39
- a.click();
40
- a.remove();
41
- window.URL.revokeObjectURL(url);
42
- }
43
- catch (err) {
44
- console.error(err);
45
- alert('Error uploading file');
46
- }
47
- }
48
- else {
49
- try {
50
- const response = await fetch('http://127.0.0.1:5001/api/convert-to-json', {
51
- method: 'POST',
52
- body: formData
53
- });
54
- if (!response.ok) {
55
- console.error("There has been an error!:", response);
56
- throw new Error(`HTTP error! status: ${response.status}`);
57
- }
58
- const data = await response.json();
59
- console.log('Upload successful:', data);
60
- if (this.callback && data[0] && data[0].content) {
61
- this.callback(data[0].content);
62
- }
63
- }
64
- catch (err) {
65
- console.error(err);
66
- alert('Error uploading file');
67
- }
68
- }
69
- };
70
- }
71
- render() {
72
- return (h("div", { key: '07c2e2b8467309e2f37b4f2bfc8338a6e7d1bd70', class: "upload-container", onClick: this.triggerUpload }, h("input", { key: '8695e980896c48212fe7d9ad7572151af2ef3e0f', type: "file", ref: el => (this.fileInput = el), onChange: this.handleFileChange, style: { display: 'none' } }), h("div", { key: '57124a873b9e3e799f7417a4658cc8897a5ad1f5', class: "upload-button" }, h("svg", { key: '5b0edb9ec28e727cd51849a3537ee8545cea2c6a', viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { key: '34ae339754cf34da6e835cb3de50b26668abed7d', d: "M13.5 3H12H8C6.34315 3 5 4.34315 5 6V18C5 19.6569 6.34315 21 8 21H12M13.5 3L19 8.625M13.5 3V7.625C13.5 8.17728 13.9477 8.625 14.5 8.625H19M19 8.625V11.8125", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { key: 'a11dc06e9724e1a6b7bdfd6b7594ab2b9eb38013', d: "M17.5 21L17.5 15M17.5 15L20 17.5M17.5 15L15 17.5", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })))));
73
- }
74
- };
75
- OcrFileUploader.style = ocrFileUploaderCss;
76
-
77
- class AudioRecorderService {
78
- constructor() {
79
- this.mediaRecorder = null;
80
- this.audioChunks = [];
81
- this.stream = null;
82
- }
83
- async startRecording() {
84
- try {
85
- // Check if the API exists before calling
86
- if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
87
- console.error('Failed to start recording:', 'Microphone access is not supported in this browser or the page is not served over HTTPS/localhost.');
88
- return; // Exit gracefully instead of throwing
89
- }
90
- this.stream = await navigator.mediaDevices.getUserMedia({
91
- audio: {
92
- echoCancellation: true,
93
- noiseSuppression: true,
94
- autoGainControl: true
95
- }
96
- });
97
- this.audioChunks = [];
98
- this.mediaRecorder = new MediaRecorder(this.stream, {
99
- mimeType: 'audio/webm;codecs=opus'
100
- });
101
- this.mediaRecorder.ondataavailable = (event) => {
102
- if (event.data && event.data.size > 0) {
103
- this.audioChunks.push(event.data);
104
- }
105
- };
106
- this.mediaRecorder.start(100); // Collect data every 100ms
107
- }
108
- catch (error) {
109
- console.error('Failed to start recording:', error);
110
- }
111
- }
112
- async stopRecording() {
113
- return new Promise((resolve, reject) => {
114
- if (!this.mediaRecorder) {
115
- reject(new Error('No active recording found'));
116
- return;
117
- }
118
- this.mediaRecorder.onstop = () => {
119
- const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });
120
- this.cleanup();
121
- resolve(audioBlob);
122
- };
123
- this.mediaRecorder.onerror = (event) => {
124
- reject(new Error(`Recording error: ${event}`));
125
- };
126
- this.mediaRecorder.stop();
127
- });
128
- }
129
- isRecording() {
130
- var _a;
131
- return ((_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.state) === 'recording';
132
- }
133
- cleanup() {
134
- if (this.stream) {
135
- this.stream.getTracks().forEach(track => track.stop());
136
- this.stream = null;
137
- }
138
- this.mediaRecorder = null;
139
- this.audioChunks = [];
140
- }
141
- }
142
-
143
- class WhisperSpeechToTextService {
144
- constructor(config) {
145
- // Get API key from config or environment
146
- this.apiKey = (config === null || config === void 0 ? void 0 : config.apiKey) || this.getEnvironmentVariable('OPENAI_API_KEY') || '';
147
- this.baseUrl = (config === null || config === void 0 ? void 0 : config.baseUrl) || 'https://api.openai.com/v1';
148
- if (!this.apiKey) {
149
- throw new Error('OpenAI API key is required for Whisper service');
150
- }
151
- }
152
- getEnvironmentVariable(name) {
153
- // In browser environment, we might get env vars through other means
154
- if (typeof process !== 'undefined' && process.env) {
155
- return process.env[name];
156
- }
157
- // Check if it's available as a global variable or through other means
158
- return window[name] || undefined;
159
- }
160
- async transcribe(audioContent, lang = 'en') {
161
- var _a;
162
- try {
163
- const formData = new FormData();
164
- formData.append('file', audioContent);
165
- formData.append('model', 'gpt-4o-transcribe'); // >>> tronque le texte ?
166
- // formData.append('model', 'gpt-4o-mini-transcribe');// >>> tronque le texte ?
167
- // formData.append('model', 'whisper-1');
168
- formData.append('language', lang);
169
- formData.append('response_format', 'json');
170
- formData.append('max_output_tokens', '2000');
171
- const response = await fetch(`${this.baseUrl}/audio/transcriptions`, {
172
- method: 'POST',
173
- headers: {
174
- 'Authorization': `Bearer ${this.apiKey}`,
175
- },
176
- body: formData,
177
- });
178
- if (!response.ok) {
179
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
180
- throw new Error(`Transcription failed: ${((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message) || response.statusText}`);
181
- }
182
- const result = await response.json();
183
- return result.text || '';
184
- }
185
- catch (error) {
186
- throw new Error(`Speech-to-text transcription failed: ${error.message}`);
187
- }
188
- }
189
- }
190
- class SpeechToTextServiceFactory {
191
- static create(config) {
192
- var _a;
193
- const provider = ((_a = config.speechToText) === null || _a === void 0 ? void 0 : _a.provider) || 'whisper';
194
- switch (provider) {
195
- case 'whisper':
196
- return new WhisperSpeechToTextService(config.speechToText);
197
- default:
198
- throw new Error(`Unsupported speech-to-text provider: ${provider}`);
199
- }
200
- }
201
- }
202
-
203
- class OpenAILLMService {
204
- constructor(config) {
205
- // Get API key from config or environment
206
- this.apiKey = (config === null || config === void 0 ? void 0 : config.apiKey) || this.getEnvironmentVariable('OPENAI_API_KEY') || '';
207
- // the newest OpenAI model is "gpt-4.1-mini". do not change this unless explicitly requested by the user
208
- // this.model = config?.model || 'gpt-4.1-mini';
209
- this.model = (config === null || config === void 0 ? void 0 : config.model) || 'gpt-4.1';
210
- this.baseUrl = (config === null || config === void 0 ? void 0 : config.baseUrl) || 'https://api.openai.com/v1';
211
- if (!this.apiKey) {
212
- throw new Error('OpenAI API key is required for LLM service');
213
- }
214
- }
215
- getEnvironmentVariable(name) {
216
- // In browser environment, we might get env vars through other means
217
- if (typeof process !== 'undefined' && process.env) {
218
- return process.env[name];
219
- }
220
- // Check if it's available as a global variable or through other means
221
- return window[name] || undefined;
222
- }
223
- getOptimizeFieldsDescription(schema) {
224
- return Object.values(schema).map((field) => {
225
- var _a;
226
- return `- ${(_a = field.name) !== null && _a !== void 0 ? _a : field.title} ` +
227
- `(${field.type}` +
228
- `${field.required ? ', required' : ''}` +
229
- `${field.readonly ? ', readonly' : ''}` +
230
- `${field.min && field.min !== "" ? ', min=' + field.min : ''}` +
231
- `${field.max && field.max !== "" ? ', max=' + field.max : ''}` +
232
- `)` +
233
- `${field.options ? ` - options: ${field.options.join(', ')}` : ''}`;
234
- }).join('\n');
235
- }
236
- async fillFormFromTranscription(transcription, schema) {
237
- return this.fillForm(transcription, schema, true);
238
- }
239
- async fillFormFromJson(json, schema) {
240
- return this.fillForm(json, schema, false);
241
- }
242
- async fillForm(data, schema, dataIsTranscription = true) {
243
- var _a, _b;
244
- try {
245
- // Handle complex schema format with fields array
246
- if ((schema === null || schema === void 0 ? void 0 : schema.fields) || (schema === null || schema === void 0 ? void 0 : schema.schema)) {
247
- const finalSchema = (schema === null || schema === void 0 ? void 0 : schema.fields) || (schema === null || schema === void 0 ? void 0 : schema.schema);
248
- const systemPrompt = `You are an expert form-filling assistant. You will receive a voice transcription and form field definitions. Your task is to extract values from the spoken content.
249
- Rules:
250
- 1. Only extract values that can be confidently determined from the transcription
251
- 2. Respect field types (string, number, datetime, boolean, select)
252
- 3. For datetime fields, use ISO format (YYYY-MM-DDTHH:MM)
253
- 4. For date fields, use the following format: DD/MM/YYY
254
- 5. For boolean fields, interpret yes/no, true/false, positive/negative responses
255
- 6. For select fields, use exact option values from the provided choices
256
- 7. Only include fields where relevant information is found
257
- 8. The current GMT datetime is ${new Date().toGMTString()}
258
- 9. Respect the constraints written between parenthesis for readonly status (readonly fields must not be filled with values), min and max values, whatever the transcription says
259
-
260
- Respond with JSON in this exact format: {"fields": [{"name": "field_name", "value": "extracted_value"}]}`;
261
- let userPrompt = `
262
- Voice transcription: "${data}"
263
-
264
- Form fields:
265
- ${this.getOptimizeFieldsDescription(finalSchema)}
266
-
267
- Please extract values from the Transcription for these fields.
268
- `;
269
- //TODO
270
- // const userPrompt = (
271
- // dataIsTranscription
272
- // ?
273
- // `Voice transcription: "${data}"`
274
- // :
275
- // `Json datas: "${JSON.stringify(data)}"`
276
- // )+`
277
- // Form fields:
278
- // ${this.getOptimizeFieldsDescription(finalSchema)}
279
- // Please extract values from the ` +
280
- // (
281
- // dataIsTranscription
282
- // ?
283
- // `Transcription`
284
- // :
285
- // `Json generated file`
286
- // )+` for these fields.`;
287
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
288
- method: 'POST',
289
- headers: {
290
- 'Content-Type': 'application/json',
291
- 'Authorization': `Bearer ${this.apiKey}`,
292
- },
293
- body: JSON.stringify({
294
- model: this.model,
295
- messages: [
296
- { role: 'system', content: systemPrompt },
297
- { role: 'user', content: userPrompt }
298
- ],
299
- response_format: { type: 'json_object' },
300
- temperature: 0.1,
301
- }),
302
- });
303
- if (!response.ok) {
304
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
305
- throw new Error(`LLM API failed: ${((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message) || response.statusText}`);
306
- }
307
- const result = await response.json();
308
- return JSON.parse(result.choices[0].message.content);
309
- }
310
- // Handle simple schema format (backward compatibility)
311
- const systemPrompt = `You are an expert form-filling assistant. You will receive a voice transcription and a JSON form schema. Your task is to intelligently fill the form fields based on the spoken content.
312
- Rules:
313
- 1. Only fill fields that can be confidently determined from the transcription
314
- 2. Respect field types (string, number, date, boolean, select)
315
- 3. For datetime fields, use ISO format (YYYY-MM-DDTHH:MM)
316
- 4. For date fields, use the following format: DD/MM/YYY
317
- 5. For boolean fields, interpret yes/no, true/false, positive/negative responses
318
- 6. For select fields, match the closest option from the provided choices
319
- 7. Leave fields empty if no relevant information is found
320
- 8. Return the same schema structure with 'default' values filled
321
- 9. The current GMT datetime is ${new Date().toGMTString()}
322
- 10. Respect the constraints written between parenthesis for readonly status (readonly fields must not be filled with values), min and max values, whatever the transcription says
323
-
324
- Respond with JSON in this exact format: {"schema": {...}}`;
325
- let userPrompt = `
326
- Voice transcription: "${data}"
327
-
328
- Form schema to fill:
329
- ${JSON.stringify(schema, null, 2)}
330
-
331
- Please fill the form fields based on the Transcription and return the schema with default values populated.
332
- `;
333
- // const userPrompt = (
334
- // dataIsTranscription
335
- // ?
336
- // `Voice transcription: "${data}"`
337
- // :
338
- // `Json datas: "${JSON.stringify(data)}"`
339
- // )+`
340
- // Form schema to fill:
341
- // ${JSON.stringify(schema, null, 2)}
342
- // Please fill the form fields based on the ` +
343
- // (
344
- // dataIsTranscription
345
- // ?
346
- // `Transcription`
347
- // :
348
- // `Json generated file`
349
- // )+` nd return the schema with default values populated.`;
350
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
351
- method: 'POST',
352
- headers: {
353
- 'Content-Type': 'application/json',
354
- 'Authorization': `Bearer ${this.apiKey}`,
355
- },
356
- body: JSON.stringify({
357
- model: this.model,
358
- messages: [
359
- { role: 'system', content: systemPrompt },
360
- { role: 'user', content: userPrompt }
361
- ],
362
- response_format: { type: 'json_object' },
363
- temperature: 0.1, // Low temperature for consistency
364
- }),
365
- });
366
- if (!response.ok) {
367
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
368
- throw new Error(`LLM API failed: ${((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.message) || response.statusText}`);
369
- }
370
- const result = await response.json();
371
- const filledSchema = JSON.parse(result.choices[0].message.content);
372
- // Validate that the response has the correct structure
373
- if (!filledSchema.schema) {
374
- throw new Error('Invalid response format from LLM service');
375
- }
376
- return filledSchema;
377
- }
378
- catch (error) {
379
- throw new Error(`Form filling failed: ${error.message}`);
380
- }
381
- }
382
- }
383
- class LLMServiceFactory {
384
- static create(config) {
385
- var _a;
386
- const provider = ((_a = config.llm) === null || _a === void 0 ? void 0 : _a.provider) || 'openai';
387
- switch (provider) {
388
- case 'openai':
389
- return new OpenAILLMService(config.llm);
390
- default:
391
- throw new Error(`Unsupported LLM provider: ${provider}`);
392
- }
393
- }
394
- }
395
-
396
- class SchemaConverter {
397
- /**
398
- * Convert XML form definition to JSON schema
399
- */
400
- static convertXmlToJsonLegacy(xmlForm) {
401
- try {
402
- const parser = new DOMParser();
403
- const xmlDoc = parser.parseFromString(xmlForm, 'text/xml');
404
- if (xmlDoc.querySelector('parsererror')) {
405
- throw new Error('Invalid XML format');
406
- }
407
- const schema = {
408
- schema: {}
409
- };
410
- // Extract form title and description
411
- const formElement = xmlDoc.querySelector('form');
412
- if (formElement) {
413
- schema.title = formElement.getAttribute('title') || undefined;
414
- schema.description = formElement.getAttribute('description') || undefined;
415
- }
416
- // Process input fields
417
- const inputs = xmlDoc.querySelectorAll('input, select, textarea');
418
- inputs.forEach(input => {
419
- const name = input.getAttribute('name');
420
- if (!name)
421
- return;
422
- const field = {
423
- type: this.mapXmlTypeToJsonTypeLegacy(input.tagName.toLowerCase(), input.getAttribute('type')),
424
- title: input.getAttribute('title') || input.getAttribute('placeholder') || name,
425
- description: input.getAttribute('description') || undefined,
426
- required: input.hasAttribute('required'),
427
- default: input.getAttribute('value') || undefined
428
- };
429
- // Handle select options
430
- if (input.tagName.toLowerCase() === 'select') {
431
- const options = Array.from(input.querySelectorAll('option')).map(option => option.textContent || option.getAttribute('value') || '');
432
- if (options.length > 0) {
433
- field.options = options;
434
- }
435
- }
436
- // Handle validation attributes
437
- const min = input.getAttribute('min');
438
- const max = input.getAttribute('max');
439
- const pattern = input.getAttribute('pattern');
440
- if (min)
441
- field.min = parseFloat(min);
442
- if (max)
443
- field.max = parseFloat(max);
444
- if (pattern)
445
- field.pattern = pattern;
446
- schema.schema[name] = field;
447
- });
448
- return schema;
449
- }
450
- catch (error) {
451
- throw new Error(`XML to JSON conversion failed: ${error.message}`);
452
- }
453
- }
454
- /**
455
- * Convert JSON schema to XML form definition
456
- */
457
- static convertJsonToXmlLegacy(jsonForm) {
458
- try {
459
- const doc = document.implementation.createDocument('', '', null);
460
- const form = doc.createElement('form');
461
- if (jsonForm.title) {
462
- form.setAttribute('title', jsonForm.title);
463
- }
464
- if (jsonForm.description) {
465
- form.setAttribute('description', jsonForm.description);
466
- }
467
- Object.entries(jsonForm.schema).forEach(([fieldName, field]) => {
468
- var _a;
469
- // Inject default value from root if present
470
- const valueFromRoot = jsonForm[fieldName];
471
- const fieldWithDefault = Object.assign(Object.assign({}, field), { default: (_a = field.default) !== null && _a !== void 0 ? _a : valueFromRoot // field.default has priority
472
- });
473
- const element = this.createXmlElementLegacy(doc, fieldName, fieldWithDefault);
474
- if (element) {
475
- form.appendChild(element);
476
- }
477
- });
478
- doc.appendChild(form);
479
- const serializer = new XMLSerializer();
480
- return serializer.serializeToString(doc);
481
- }
482
- catch (error) {
483
- throw new Error(`JSON to XML conversion failed: ${error.message}`);
484
- }
485
- }
486
- static mapXmlTypeToJsonTypeLegacy(tagName, type) {
487
- switch (tagName) {
488
- case 'select':
489
- return 'select';
490
- case 'textarea':
491
- return 'string';
492
- case 'input':
493
- switch (type) {
494
- case 'number':
495
- case 'range':
496
- return 'number';
497
- case 'date':
498
- case 'datetime-local':
499
- case 'time':
500
- return 'date';
501
- case 'checkbox':
502
- return 'boolean';
503
- default:
504
- return 'string';
505
- }
506
- default:
507
- return 'string';
508
- }
509
- }
510
- static createXmlElementLegacy(doc, fieldName, field) {
511
- let element;
512
- switch (field.type) {
513
- case 'select':
514
- element = doc.createElement('select');
515
- if (field.options) {
516
- field.options.forEach(option => {
517
- const optionElement = doc.createElement('option');
518
- optionElement.setAttribute('value', option);
519
- optionElement.textContent = option;
520
- // Set selected if it matches the default value
521
- if (field.default !== undefined && field.default === option) {
522
- optionElement.setAttribute('selected', 'true');
523
- }
524
- element.appendChild(optionElement);
525
- });
526
- }
527
- break;
528
- case 'boolean':
529
- element = doc.createElement('input');
530
- element.setAttribute('type', 'checkbox');
531
- if (field.default === true || field.default === 'true') {
532
- element.setAttribute('checked', 'true');
533
- }
534
- break;
535
- case 'number':
536
- element = doc.createElement('input');
537
- element.setAttribute('type', 'number');
538
- if (field.min !== undefined)
539
- element.setAttribute('min', field.min.toString());
540
- if (field.max !== undefined)
541
- element.setAttribute('max', field.max.toString());
542
- if (field.default !== undefined)
543
- element.setAttribute('value', field.default.toString());
544
- break;
545
- case 'date':
546
- element = doc.createElement('input');
547
- element.setAttribute('type', 'date');
548
- if (field.default !== undefined)
549
- element.setAttribute('value', field.default.toString());
550
- break;
551
- default: // string, text, etc.
552
- element = doc.createElement('input');
553
- element.setAttribute('type', 'text');
554
- if (field.default !== undefined)
555
- element.setAttribute('value', field.default.toString());
556
- }
557
- element.setAttribute('name', fieldName);
558
- element.setAttribute('title', field.title);
559
- if (field.description) {
560
- element.setAttribute('description', field.description);
561
- }
562
- if (field.required) {
563
- element.setAttribute('required', 'true');
564
- }
565
- if (field.pattern) {
566
- element.setAttribute('pattern', field.pattern);
567
- }
568
- return element;
569
- }
570
- /**
571
- * Convert new XML form definition to JSON schema
572
- */
573
- static async convertXmlToJson(xmlForm, classificationRootURL = "http://localhost", lang = 'en') {
574
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
575
- try {
576
- const parser = new DOMParser();
577
- const xmlDoc = parser.parseFromString(xmlForm, 'text/xml');
578
- if (xmlDoc.querySelector('parsererror')) {
579
- throw new Error('Invalid XML format');
580
- }
581
- // Root Xforms element (optional)
582
- const xforms = xmlDoc.querySelector('Xforms');
583
- if (!xforms)
584
- throw new Error('No Xforms root element found');
585
- const fields = xforms.querySelectorAll('Fields');
586
- if (fields.length === 0)
587
- throw new Error('No Fields elements found');
588
- const schema = {
589
- fields: {}
590
- };
591
- for (const fieldEl of Array.from(fields)) {
592
- // Read key info
593
- const name = (_b = (_a = fieldEl.querySelector('SystemName')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim();
594
- if (!name)
595
- return;
596
- const helpText = (_d = (_c = fieldEl.querySelector('HelpText')) === null || _c === void 0 ? void 0 : _c.textContent) === null || _d === void 0 ? void 0 : _d.trim();
597
- const defaultValue = (_e = fieldEl.querySelector('DefaultValue')) === null || _e === void 0 ? void 0 : _e.textContent;
598
- const enabledText = ((_g = (_f = fieldEl.querySelector('Enabled')) === null || _f === void 0 ? void 0 : _f.textContent) === null || _g === void 0 ? void 0 : _g.trim().toLowerCase()) || 'true';
599
- const isEnabled = enabledText === 'true';
600
- // keep as memory
601
- const field_ID = (_h = fieldEl.querySelector('ID')) === null || _h === void 0 ? void 0 : _h.textContent;
602
- const field_TFie_PK_ID = (_j = fieldEl.querySelector('TFie_PK_ID')) === null || _j === void 0 ? void 0 : _j.textContent;
603
- const field_TVal_PK_ID = (_k = fieldEl.querySelector('TVal_PK_ID')) === null || _k === void 0 ? void 0 : _k.textContent;
604
- const field_TFIn_PK_ID = (_l = fieldEl.querySelector('TFIn_PK_ID')) === null || _l === void 0 ? void 0 : _l.textContent;
605
- const field_isForm = (_m = fieldEl.querySelector('isForm')) === null || _m === void 0 ? void 0 : _m.textContent;
606
- const field_LabelText = (_o = fieldEl.querySelector('LabelText')) === null || _o === void 0 ? void 0 : _o.textContent;
607
- const field_SystemName = (_p = fieldEl.querySelector('SystemName')) === null || _p === void 0 ? void 0 : _p.textContent;
608
- const field_CssStyle = (_q = fieldEl.querySelector('CssStyle')) === null || _q === void 0 ? void 0 : _q.textContent;
609
- const field_ControlType = ((_r = fieldEl.querySelector('ControlType')) === null || _r === void 0 ? void 0 : _r.textContent) || 'TextBox';
610
- const field_ValidationRequired = (_s = fieldEl.querySelector('ValidationRequired')) === null || _s === void 0 ? void 0 : _s.textContent;
611
- const field_ValidationMin = (_t = fieldEl.querySelector('ValidationMin')) === null || _t === void 0 ? void 0 : _t.textContent;
612
- const field_ValidationMax = (_u = fieldEl.querySelector('ValidationMax')) === null || _u === void 0 ? void 0 : _u.textContent;
613
- const field_Mask = (_v = fieldEl.querySelector('Mask')) === null || _v === void 0 ? void 0 : _v.textContent;
614
- const field_TypeId = (_w = fieldEl.querySelector('TypeId')) === null || _w === void 0 ? void 0 : _w.textContent;
615
- const field_Unit = (_x = fieldEl.querySelector('Unit')) === null || _x === void 0 ? void 0 : _x.textContent;
616
- const field_TFie_Fullpath = (_y = fieldEl.querySelector('TFie_Fullpath')) === null || _y === void 0 ? void 0 : _y.textContent;
617
- const field_TVal_FK_Parent_ID = (_z = fieldEl.querySelector('TVal_FK_Parent_ID')) === null || _z === void 0 ? void 0 : _z.textContent;
618
- const field = {
619
- type: this.mapControlTypeToJsonType(field_ControlType),
620
- title: field_LabelText,
621
- description: helpText,
622
- required: (field_ValidationRequired === null || field_ValidationRequired === void 0 ? void 0 : field_ValidationRequired.toLowerCase()) === 'required',
623
- default: defaultValue || undefined,
624
- realType: field_ControlType,
625
- Enabled: isEnabled,
626
- ID: field_ID,
627
- TFie_PK_ID: field_TFie_PK_ID,
628
- TVal_PK_ID: field_TVal_PK_ID,
629
- TFIn_PK_ID: field_TFIn_PK_ID,
630
- isForm: field_isForm,
631
- LabelText: field_LabelText,
632
- SystemName: field_SystemName,
633
- CssStyle: field_CssStyle,
634
- ControlType: field_ControlType,
635
- ValidationRequired: field_ValidationRequired,
636
- ValidationMin: field_ValidationMin,
637
- ValidationMax: field_ValidationMax,
638
- Mask: field_Mask,
639
- TypeId: field_TypeId,
640
- Unit: field_Unit,
641
- TFie_Fullpath: field_TFie_Fullpath,
642
- TVal_FK_Parent_ID: field_TVal_FK_Parent_ID
643
- };
644
- // Handle select options
645
- if (field.type.toLowerCase() === 'select') {
646
- try {
647
- const response = await fetch(`${classificationRootURL}/ng/api/v1/classification/getList/${field.ControlType.toLowerCase() == 'termpicker' ? "Position" : "Thesaurus"}/?StartNodeID=${field_TypeId}`);
648
- if (!response.ok)
649
- throw new Error(`HTTP error! status: ${response.status}`);
650
- const data = await response.json();
651
- if (Array.isArray(data)) {
652
- const options = data.map(item => ({
653
- value: item.ID,
654
- label: item.System_Name
655
- }));
656
- if (options.length > 0) {
657
- field.pickerOptions = options;
658
- // TODO on degage les quotes simples temporairement, a corriger
659
- field.options = options.map(option => option.label.replace("'", ""));
660
- }
661
- }
662
- else {
663
- console.error("Unexpected API response format:", data);
664
- }
665
- }
666
- catch (error) {
667
- console.error("Error fetching classification data:", error);
668
- }
669
- }
670
- if (field_ValidationMin)
671
- field.min = parseFloat(field_ValidationMin);
672
- if (field_ValidationMax)
673
- field.max = parseFloat(field_ValidationMax);
674
- if (field_Mask)
675
- field.pattern = field_Mask;
676
- // Optional: Add any other fields you want to track, e.g. min, max, pattern (not clearly in your XML)
677
- // You could also add the raw ControlType for round-trip fidelity if you want
678
- schema.fields[field_ID] = field;
679
- }
680
- return schema;
681
- }
682
- catch (error) {
683
- throw new Error(`XML to JSON conversion failed: ${error.message}`);
684
- }
685
- }
686
- /**
687
- * Convert JSON schema back to your new XML form definition format
688
- */
689
- static convertJsonToXml(jsonForm) {
690
- try {
691
- const doc = document.implementation.createDocument('', '', null);
692
- const xforms = doc.createElement('Xforms');
693
- Object.entries((jsonForm.schema ? jsonForm.schema : jsonForm.fields)).forEach(([fieldID, field]) => {
694
- const fieldEl = doc.createElement('Fields');
695
- const fieldToUse = field;
696
- // Set all subelements based on your XML structure
697
- // ID, PK IDs etc are missing here, so omit or generate dummy
698
- // <SystemName>
699
- const systemNameEl = doc.createElement('SystemName');
700
- systemNameEl.textContent = fieldToUse.SystemName;
701
- fieldEl.appendChild(systemNameEl);
702
- // <LabelText>
703
- const labelEl = doc.createElement('LabelText');
704
- labelEl.textContent = fieldToUse.title || fieldID;
705
- fieldEl.appendChild(labelEl);
706
- // <HelpText>
707
- const helpEl = doc.createElement('HelpText');
708
- helpEl.textContent = fieldToUse.description;
709
- fieldEl.appendChild(helpEl);
710
- // <ControlType>
711
- const controlTypeEl = doc.createElement('ControlType');
712
- controlTypeEl.textContent = fieldToUse.realType;
713
- fieldEl.appendChild(controlTypeEl);
714
- // <ValidationRequired>
715
- const validationEl = doc.createElement('ValidationRequired');
716
- validationEl.textContent = fieldToUse.required ? 'Required' : 'Not Required';
717
- fieldEl.appendChild(validationEl);
718
- // <DefaultValue>
719
- const defaultEl = doc.createElement('DefaultValue');
720
- const valueEl = doc.createElement('Value');
721
- if (jsonForm[fieldID] !== undefined) {
722
- defaultEl.textContent = jsonForm[fieldID].toString();
723
- valueEl.textContent = jsonForm[fieldID].toString();
724
- }
725
- else {
726
- defaultEl.textContent = fieldToUse.default || fieldToUse.value;
727
- valueEl.textContent = fieldToUse.value || fieldToUse.default;
728
- }
729
- fieldEl.appendChild(defaultEl);
730
- fieldEl.appendChild(valueEl);
731
- // <Enabled>
732
- const enabledEl = doc.createElement('Enabled');
733
- enabledEl.textContent = fieldToUse.Enabled === false ? 'False' : 'True';
734
- fieldEl.appendChild(enabledEl);
735
- // Add <isForm> Field to distinguish Field or Header etc
736
- const isFormEl = doc.createElement('isForm');
737
- isFormEl.textContent = fieldToUse.isForm;
738
- fieldEl.appendChild(isFormEl);
739
- if (fieldToUse.type === 'header') {
740
- const headerEl = doc.createElement('Header');
741
- headerEl.textContent = fieldToUse.title;
742
- fieldEl.appendChild(headerEl);
743
- }
744
- const idEl = doc.createElement('ID');
745
- idEl.textContent = fieldToUse.ID;
746
- fieldEl.appendChild(idEl);
747
- const tfiePkIdEl = doc.createElement('TFie_PK_ID');
748
- tfiePkIdEl.textContent = fieldToUse.TFie_PK_ID;
749
- fieldEl.appendChild(tfiePkIdEl);
750
- const tvalPkIdEl = doc.createElement('TVal_PK_ID');
751
- tvalPkIdEl.textContent = fieldToUse.TVal_PK_ID;
752
- fieldEl.appendChild(tvalPkIdEl);
753
- const tfInPkIdEl = doc.createElement('TFIn_PK_ID');
754
- tfInPkIdEl.textContent = fieldToUse.TFIn_PK_ID;
755
- fieldEl.appendChild(tfInPkIdEl);
756
- const cssStyleEl = doc.createElement('CssStyle');
757
- cssStyleEl.textContent = fieldToUse.CssStyle;
758
- fieldEl.appendChild(cssStyleEl);
759
- const typeIdEl = doc.createElement('TypeId');
760
- typeIdEl.textContent = fieldToUse.TypeId;
761
- fieldEl.appendChild(typeIdEl);
762
- const unitEl = doc.createElement('Unit');
763
- unitEl.textContent = fieldToUse.Unit;
764
- fieldEl.appendChild(unitEl);
765
- const tfieFullPathEl = doc.createElement('TFie_Fullpath');
766
- tfieFullPathEl.textContent = fieldToUse.TFie_Fullpath;
767
- fieldEl.appendChild(tfieFullPathEl);
768
- const tvalFkParentIdEl = doc.createElement('TVal_FK_Parent_ID');
769
- tvalFkParentIdEl.textContent = fieldToUse.TVal_FK_Parent_ID;
770
- fieldEl.appendChild(tvalFkParentIdEl);
771
- const validationMinEl = doc.createElement('ValidationMin');
772
- validationMinEl.textContent = fieldToUse.ValidationMin;
773
- fieldEl.appendChild(validationMinEl);
774
- const validationMaxEl = doc.createElement('ValidationMax');
775
- validationMaxEl.textContent = fieldToUse.ValidationMax;
776
- fieldEl.appendChild(validationMaxEl);
777
- const maskEl = doc.createElement('Mask');
778
- maskEl.textContent = fieldToUse.Mask;
779
- fieldEl.appendChild(maskEl);
780
- // Append to Xforms root
781
- xforms.appendChild(fieldEl);
782
- });
783
- doc.appendChild(xforms);
784
- const serializer = new XMLSerializer();
785
- return serializer.serializeToString(doc);
786
- }
787
- catch (error) {
788
- throw new Error(`JSON to XML conversion failed: ${error.message}`);
789
- }
790
- }
791
- static mapControlTypeToJsonType(controlType) {
792
- // Map your ControlType XML field to JSON field types
793
- switch (controlType.toLowerCase()) {
794
- case 'textbox':
795
- case 'text':
796
- return 'string';
797
- case 'datepicker':
798
- return 'date';
799
- case 'thesauruspicker':
800
- case 'thesauruspicker-ddl':
801
- case 'termpicker':
802
- return 'select';
803
- case 'dbpicker':
804
- return 'dbpicker'; // custom type if needed
805
- case 'header':
806
- return 'header'; // special type to handle header elements
807
- case 'checkbox':
808
- return 'boolean';
809
- case 'realpicker':
810
- return 'number';
811
- default:
812
- return 'string';
813
- }
814
- }
815
- }
816
-
817
- const voiceInputModuleCss = ":host{display:block;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif}.row-audio-area{display:flex;flex-direction:row}.voice-recorder-container{display:flex;flex-direction:column;align-items:center;gap:1rem;padding:1rem;border:1px solid #e5e7eb;border-radius:0.5rem;background:#ffffff;max-width:100px;margin:0 auto}.voice-recorder-container-debug{display:flex;flex-direction:column;align-items:center;gap:1rem;padding:1rem;border:1px solid #e5e7eb;border-radius:0.5rem;background:#ffffff;max-width:800px;margin:0 auto}.upload-record-container{display:inline-block;cursor:pointer;width:50px;height:50px}.upload-record-button{display:flex;align-items:center;justify-content:center;transition:transform 0.2s ease, box-shadow 0.2s ease;user-select:none}.upload-record-button svg{width:50px;height:50px;stroke:#4444ee}.upload-record-button svg path{fill:#4444ee}.upload-record-button:hover svg{transform:scale(1.05);stroke:#4444ee}.record-button{display:flex;align-items:center;justify-content:center;width:50px;height:50px;border:none;border-radius:50%;background:#ee4444;color:white;cursor:pointer;transition:all 0.2s ease;position:relative;overflow:hidden}.record-button:hover:not(:disabled){background:#dd3333;transform:scale(1.05)}.record-button:disabled{opacity:0.6;cursor:not-allowed}.record-button.recording{background:#dd3333;animation:pulse 1.5s infinite}.record-button.processing{background:#3b82f6}@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(239, 68, 68, 0.7)}70%{box-shadow:0 0 0 10px rgba(239, 68, 68, 0)}100%{box-shadow:0 0 0 0 rgba(239, 68, 68, 0)}}.record-icon{width:24px;height:24px;fill:currentColor}.status-text{font-size:0.875rem;color:#6b7280;text-align:center;min-height:1.25rem}.status-text.error{color:#ee4444}.status-text.success{color:#10b981}.debug-panel{width:100%;margin-top:1rem;padding:1rem;background:#f9fafb;border:1px solid #e5e7eb;border-radius:0.375rem;font-family:'Monaco', 'Menlo', 'Ubuntu Mono', monospace;font-size:0.75rem}.debug-title{font-weight:600;margin-bottom:0.5rem;color:#374151}.debug-content{white-space:pre-wrap;word-break:break-word;color:#6b7280;max-height:200px;overflow-y:auto}.permissions-warning{padding:0.75rem;background:#fef3c7;border:1px solid #f59e0b;border-radius:0.375rem;color:#92400e;font-size:0.875rem;text-align:center}.form-preview{width:100%;margin-top:1rem;padding:1rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:0.375rem}.form-preview-title{font-weight:600;margin-bottom:0.5rem;color:#1e293b}.form-field{margin-bottom:0.5rem;font-size:0.875rem}.field-name{font-weight:500;color:#475569}.field-value{color:#64748b;margin-left:0.5rem}.field-value.filled{color:#059669;font-weight:500}.voice-filled-form{display:flex;flex-direction:column;gap:1rem;margin-top:1rem}.form-group{display:flex;flex-direction:column;gap:0.25rem}.form-label{font-weight:500;color:#374151;font-size:0.875rem}.required{color:#ee4444;margin-left:0.125rem}.form-input{padding:0.5rem;border:1px solid #d1d5db;border-radius:0.375rem;font-size:0.875rem;transition:border-color 0.2s ease}.form-input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59, 130, 246, 0.1)}.form-checkbox{width:auto;padding:0;margin:0}select.form-input{background-color:white;cursor:pointer}input[type=\"date\"].form-input{cursor:pointer}.readonly-select{background:#f9fafb;border:1px solid #d1d5db;border-radius:0.375rem;padding:0.5rem}.select-placeholder{font-size:0.875rem;color:#6b7280;margin-bottom:0.5rem}.select-options-list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:0.25rem}.select-option{background:#e5e7eb;padding:0.25rem 0.5rem;border-radius:0.25rem;font-size:0.875rem;color:#374151}";
818
-
819
- const VoiceFormRecorder = class {
820
- constructor(hostRef) {
821
- registerInstance(this, hostRef);
822
- this.formFilled = createEvent(this, "formFilled");
823
- this.recordingStateChanged = createEvent(this, "recordingStateChanged");
824
- this.formJson = '{}';
825
- this.serviceConfig = '{}';
826
- this.context = undefined;
827
- this.classificationRootUrl = 'http://localhost';
828
- this.language = 'en';
829
- this.inputTypes = [];
830
- this.debug = false;
831
- this.renderForm = false;
832
- this.displayStatus = false;
833
- this.isRecording = false;
834
- this.isProcessing = false;
835
- this.hasError = false;
836
- this.transcription = '';
837
- this.filledData = null;
838
- this.debugInfo = {};
839
- this.isReadonlyMode = true; // Start in readonly preview mode
840
- this.triggerAudioRecordUpload = () => {
841
- this.fileInputAudioRecord.click();
842
- };
843
- this.handleAudioRecordChange = async (event) => {
844
- const input = event.target;
845
- if (!input.files || input.files.length === 0)
846
- return;
847
- const file = input.files[0];
848
- // Here you can handle the file upload to your API
849
- console.log('Selected file:', file);
850
- this.processAudioContent(file);
851
- };
852
- this.audioRecorder = new AudioRecorderService();
853
- }
854
- componentWillLoad() {
855
- this.initializeServices();
856
- }
857
- initializeServices() {
858
- try {
859
- if (!this.context) {
860
- this.hasError = true;
861
- const errorMessage = (this.language == 'en' ? `Initialization error: context is '${this.context}'` : `Erreur d'initialisation: le contexte est '${this.context}'`);
862
- this.statusMessage = errorMessage;
863
- this.updateDebugInfo(errorMessage, { error: errorMessage });
864
- }
865
- else {
866
- // Parse form schema
867
- this.parsedSchema = JSON.parse(this.formJson || '{}');
868
- // Parse service configuration
869
- this.parsedConfig = JSON.parse(this.serviceConfig || '{}');
870
- // Add API key to config if provided via prop
871
- if (this.apiKey) {
872
- 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 }) });
873
- }
874
- // Initialize services
875
- this.speechToTextService = SpeechToTextServiceFactory.create(this.parsedConfig);
876
- this.llmService = LLMServiceFactory.create(this.parsedConfig);
877
- this.updateDebugInfo('Initialized', {
878
- schema: this.parsedSchema,
879
- config: this.parsedConfig
880
- });
881
- this.hasError = false;
882
- this.statusMessage = (this.language == 'en' ? 'Click to start recording' : 'Cliquer pour enregistrer');
883
- if (this.inputTypes.length === 0) {
884
- this.inputTypes = ['voice'];
885
- }
886
- }
887
- }
888
- catch (error) {
889
- this.hasError = true;
890
- this.statusMessage = (this.language == 'en' ? `Initialization error: ${error.message}` : `Erreur d'initialisation: ${error.message}`);
891
- this.updateDebugInfo('Initialization Error', { error: error.message });
892
- }
893
- }
894
- updateDebugInfo(action, data) {
895
- if (this.debug) {
896
- this.debugInfo = Object.assign(Object.assign({}, this.debugInfo), { [action]: {
897
- timestamp: new Date().toISOString(),
898
- data
899
- } });
900
- }
901
- }
902
- async handleRecordClick() {
903
- if (this.isProcessing)
904
- return;
905
- if (this.isRecording) {
906
- await this.stopRecordingAndProcess();
907
- }
908
- else {
909
- await this.startRecording();
910
- }
911
- }
912
- async startRecording() {
913
- try {
914
- this.hasError = false;
915
- this.statusMessage = (this.language == 'en' ? 'Starting recording...' : `Enregistrement ...`);
916
- this.updateDebugInfo('Start Recording Attempt', {});
917
- await this.audioRecorder.startRecording();
918
- this.isRecording = true;
919
- this.statusMessage = (this.language == 'en' ? 'Recording... Click to stop' : 'Enregistrement ... Cliquer pour stopper');
920
- this.updateDebugInfo('Recording Started', {});
921
- this.recordingStateChanged.emit({
922
- isRecording: true,
923
- state: 'recording'
924
- });
925
- }
926
- catch (error) {
927
- this.hasError = true;
928
- this.statusMessage = (this.language == 'en' ? `Recording failed: ${error.message}` : `Echec de l'enregistrement : ${error.message}`);
929
- this.updateDebugInfo('Recording Error', { error: error.message });
930
- this.formFilled.emit({
931
- success: false,
932
- error: error.message
933
- });
934
- }
935
- }
936
- async processJsonForm(jsonForm) {
937
- console.log("processJsonForm", jsonForm);
938
- try {
939
- this.isProcessing = true;
940
- this.statusMessage = (this.language == 'en' ? 'Processing json...' : `Traitement du json ...`);
941
- // Fill form using LLM
942
- this.statusMessage = (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
943
- const trimmedSchema = this.trimSchemaForAI(this.parsedSchema);
944
- const filledSchema = await this.llmService.fillFormFromJson(jsonForm, trimmedSchema);
945
- // Extract filled data
946
- this.filledData = this.extractFilledData(filledSchema);
947
- this.updateDebugInfo('Form Filled', {
948
- filledSchema,
949
- extractedData: this.filledData
950
- });
951
- this.parsedSchema = this.filledData;
952
- this.statusMessage = (this.language == 'en' ? 'Form completed!' : 'Formulaire remplis !');
953
- this.hasError = false;
954
- // Emit success event
955
- this.formFilled.emit({
956
- success: true,
957
- data: this.filledData,
958
- jsonForm: jsonForm
959
- });
960
- }
961
- catch (error) {
962
- this.hasError = true;
963
- this.statusMessage = (this.language == 'en' ? `Processing failed: ${error.message}` : `Erreur de traitement : ${error.message}`);
964
- this.formFilled.emit({
965
- success: false,
966
- error: error.message,
967
- jsonForm: jsonForm
968
- });
969
- }
970
- finally {
971
- this.isProcessing = false;
972
- }
973
- }
974
- async processAudioContent(audioFile) {
975
- this.updateDebugInfo('Audio Captured', {
976
- size: audioFile.size,
977
- type: audioFile.type
978
- });
979
- // Transcribe audio
980
- this.statusMessage = (this.language == 'en' ? 'Transcribing speech...' : 'Transcription du texte ...');
981
- const transcription = await this.speechToTextService.transcribe(audioFile, this.language);
982
- this.transcription = transcription;
983
- this.updateDebugInfo('Transcription Complete', { transcription });
984
- if (!transcription.trim()) {
985
- throw new Error('No speech detected in the recording');
986
- }
987
- // Fill form using LLM
988
- this.statusMessage = (this.language == 'en' ? 'Filling form fields...' : 'Remplissage du formulaire ...');
989
- const trimmedSchema = this.trimSchemaForAI(this.parsedSchema);
990
- const filledSchema = await this.llmService.fillFormFromTranscription(transcription, trimmedSchema);
991
- // Extract filled data
992
- this.filledData = this.extractFilledData(filledSchema);
993
- this.updateDebugInfo('Form Filled', {
994
- filledSchema,
995
- extractedData: this.filledData
996
- });
997
- this.parsedSchema = this.filledData;
998
- this.statusMessage = (this.language == 'en' ? 'Form completed!' : 'Formulaire remplis !');
999
- this.hasError = false;
1000
- // Emit success event
1001
- this.formFilled.emit({
1002
- success: true,
1003
- data: this.filledData,
1004
- transcription: transcription
1005
- });
1006
- }
1007
- async stopRecordingAndProcess() {
1008
- try {
1009
- this.isRecording = false;
1010
- this.isProcessing = true;
1011
- this.statusMessage = (this.language == 'en' ? 'Processing audio...' : `Traitement de l'audio ...`);
1012
- this.updateDebugInfo('Stop Recording', {});
1013
- this.recordingStateChanged.emit({
1014
- isRecording: false,
1015
- state: 'processing'
1016
- });
1017
- // Stop recording and get audio blob
1018
- const audioBlob = await this.audioRecorder.stopRecording();
1019
- const audioContent = new File([audioBlob], 'audio.webm', { type: 'audio/webm' });
1020
- this.processAudioContent(audioContent);
1021
- }
1022
- catch (error) {
1023
- this.hasError = true;
1024
- this.statusMessage = (this.language == 'en' ? `Processing failed: ${error.message}` : `Erreur de traitement : ${error.message}`);
1025
- this.updateDebugInfo('Processing Error', { error: error.message });
1026
- this.formFilled.emit({
1027
- success: false,
1028
- error: error.message,
1029
- transcription: this.transcription
1030
- });
1031
- }
1032
- finally {
1033
- this.isProcessing = false;
1034
- this.recordingStateChanged.emit({
1035
- isRecording: false,
1036
- state: 'idle'
1037
- });
1038
- }
1039
- }
1040
- extractFilledData(filledData) {
1041
- // console.log("extractFilledData", filledData);
1042
- const updatedSchema = JSON.parse(JSON.stringify(this.parsedSchema));
1043
- switch (this.context) {
1044
- case "ecoteka":
1045
- // console.log("TODO extractFilledData", filledData);
1046
- case "ng":
1047
- if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
1048
- // Map AI response back to original schema structure
1049
- filledData.fields.forEach((field) => {
1050
- const originalField = updatedSchema.Children.find((child) => { var _a; return child.System_Name === field.name || ((_a = child.Settings) === null || _a === void 0 ? void 0 : _a.Label) === field.name; });
1051
- if (originalField && field.value !== undefined && field.value !== null && field.value !== '') {
1052
- if (!originalField.Settings)
1053
- originalField.Settings = {};
1054
- originalField.Settings.Default_Value = field.value;
1055
- }
1056
- });
1057
- }
1058
- break;
1059
- case "ecoll-veto":
1060
- // console.log("TODO extractFilledData", filledData, updatedSchema);
1061
- if (filledData === null || filledData === void 0 ? void 0 : filledData.fields) {
1062
- // Map AI response back to original schema structure
1063
- filledData.fields.forEach((field) => {
1064
- let originalField = updatedSchema[0].items.find((child) => child.label === field.name);
1065
- if (!originalField)
1066
- originalField = updatedSchema[1].items.find((child) => child.label === field.name);
1067
- if (originalField && field.value !== undefined && field.value !== null && field.value !== '') {
1068
- updatedSchema[2][originalField.name] = field.value;
1069
- }
1070
- });
1071
- }
1072
- break;
1073
- case "track":
1074
- default:
1075
- Object.entries(filledData.fields).forEach(([fieldID, field]) => {
1076
- if (field.default !== undefined && field.default !== null && field.default !== '') {
1077
- updatedSchema[fieldID] = field.default;
1078
- }
1079
- if (field.value !== undefined && field.value !== null && field.value !== '') {
1080
- for (const key in updatedSchema.fields) {
1081
- const schemaField = updatedSchema.fields[key];
1082
- if (schemaField.title === field.name) {
1083
- schemaField.value = field.value || field.default;
1084
- schemaField.default = field.value || field.default;
1085
- break; // stop after finding the first match
1086
- }
1087
- }
1088
- }
1089
- });
1090
- break;
1091
- }
1092
- // console.log("extractFilledData result", updatedSchema);
1093
- return updatedSchema;
1094
- }
1095
- trimSchemaForAI(schema) {
1096
- var _a, _b;
1097
- // console.log("trimSchemaForAI", schema);
1098
- switch (this.context) {
1099
- case "ecoteka":
1100
- // console.log("TODO trimSchemaForAI", schema)
1101
- case "ng":
1102
- const trimmed = { fields: [] };
1103
- schema.Children.forEach((child) => {
1104
- var _a;
1105
- if (!child.System_Name || !child.Type)
1106
- return;
1107
- const fieldData = {
1108
- name: child.Label || ((_a = child.Settings) === null || _a === void 0 ? void 0 : _a.Label) || child.System_Name,
1109
- type: this.mapFieldType(child.Type)
1110
- };
1111
- // Add options for classification/select fields
1112
- const selectTypes = ['InputClassification', 'select'];
1113
- if (selectTypes.includes(child.Type) && child.Children && child.Children.length > 0) {
1114
- fieldData.options = child.Children.map((option) => option.System_Name || option.Label || option.toString());
1115
- }
1116
- console.log("fieldData", fieldData);
1117
- trimmed.fields.push(fieldData);
1118
- });
1119
- // console.log("Schema apres transformation, contexte NG:", trimmed);
1120
- return trimmed;
1121
- case "ecoll-veto":
1122
- // console.log("TODO trimSchemaForAI", schema)
1123
- const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
1124
- if (mergedItemsSchema) {
1125
- const trimmedSchema = {
1126
- title: 'Form Name',
1127
- description: 'Form Description',
1128
- schema: {}
1129
- };
1130
- Object.entries(mergedItemsSchema).forEach(([key, field]) => {
1131
- const fieldName = field.name;
1132
- const fieldType = this.mapFieldType(field.type);
1133
- const fieldLabel = field.label || fieldName;
1134
- trimmedSchema.schema[fieldName] = {
1135
- type: fieldType,
1136
- title: fieldLabel,
1137
- options: field.options,
1138
- readonly: field.readonly === true,
1139
- default: '',
1140
- };
1141
- });
1142
- // console.log("Schema apres transformation, contexte Track:", trimmedSchema);
1143
- return trimmedSchema;
1144
- }
1145
- case "track":
1146
- default:
1147
- // Handle simple schema format (backward compatibility)
1148
- 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) {
1149
- const trimmedSchema = {
1150
- title: schema.title,
1151
- description: schema.description,
1152
- schema: {}
1153
- };
1154
- 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;
1155
- Object.entries(finalSchema).forEach(([fieldName, field]) => {
1156
- trimmedSchema.schema[fieldName] = {
1157
- type: field.type,
1158
- title: field.title,
1159
- options: field.options,
1160
- readonly: field.Enabled === false,
1161
- default: field.DefaultValue,
1162
- pattern: field.Mask,
1163
- min: field.ValidationMin,
1164
- max: field.ValidationMax
1165
- };
1166
- });
1167
- // console.log("Schema apres transformation, contexte Track:", trimmedSchema);
1168
- return trimmedSchema;
1169
- }
1170
- break;
1171
- }
1172
- return schema;
1173
- }
1174
- mapFieldType(type) {
1175
- const typeMapping = {
1176
- 'InputAutocomplete': 'string',
1177
- 'InputInteger': 'number',
1178
- 'InputTextArea': 'string',
1179
- 'InputDateTimePicker': 'datetime',
1180
- 'InputDecimal': 'number',
1181
- 'InputClassification': 'select',
1182
- 'InputCheckbox': 'boolean',
1183
- 'InputTextTranslation': 'string',
1184
- 'thesaurus': 'string',
1185
- 'position': 'string',
1186
- 'text': 'string',
1187
- 'textarea': 'string',
1188
- 'number': 'number',
1189
- 'date': 'date',
1190
- 'datetime': 'datetime',
1191
- 'select': 'select',
1192
- 'checkbox': 'checkbox'
1193
- };
1194
- return typeMapping[type] || 'string';
1195
- }
1196
- // Utility methods exposed as public API
1197
- async convertXmlToJson(xmlForm) {
1198
- return SchemaConverter.convertXmlToJson(xmlForm, this.classificationRootUrl, this.language);
1199
- }
1200
- async convertJsonToXml(jsonForm) {
1201
- return SchemaConverter.convertJsonToXml(jsonForm);
1202
- }
1203
- // Utility methods exposed as public API
1204
- async convertXmlToJsonLegacy(xmlForm) {
1205
- return SchemaConverter.convertXmlToJsonLegacy(xmlForm);
1206
- }
1207
- async convertJsonToXmlLegacy(jsonForm) {
1208
- return SchemaConverter.convertJsonToXmlLegacy(jsonForm);
1209
- }
1210
- renderUploadButton() {
1211
- if (!this.inputTypes.includes('ocr'))
1212
- return;
1213
- return (h("ocr-file-uploader", { batch: false, callback: (data) => { this.processJsonForm(data); } }));
1214
- }
1215
- renderUploadRecordButton() {
1216
- return (h("div", { class: "upload-record-container", onClick: this.triggerAudioRecordUpload }, h("input", { type: "file", ref: el => (this.fileInputAudioRecord = el), onChange: this.handleAudioRecordChange, style: { display: 'none' } }), h("div", { class: 'upload-record-button' }, h("svg", { width: "800px", height: "800px", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M12 2.75C6.89137 2.75 2.75 6.89137 2.75 12C2.75 17.1086 6.89137 21.25 12 21.25C12.6345 21.25 13.2534 21.1862 13.8508 21.065C14.2567 20.9826 14.6526 21.2448 14.735 21.6508C14.8174 22.0567 14.5551 22.4526 14.1492 22.535C13.4541 22.6761 12.7353 22.75 12 22.75C6.06294 22.75 1.25 17.9371 1.25 12C1.25 6.06294 6.06294 1.25 12 1.25C17.9371 1.25 22.75 6.06294 22.75 12C22.75 12.7353 22.6761 13.4541 22.535 14.1492C22.4526 14.5551 22.0567 14.8174 21.6508 14.735C21.2448 14.6526 20.9826 14.2567 21.065 13.8508C21.1862 13.2534 21.25 12.6345 21.25 12C21.25 6.89137 17.1086 2.75 12 2.75ZM12.7676 8.52584C12.7661 8.53409 12.7604 8.56729 12.7564 8.64336C12.7502 8.76101 12.75 8.91982 12.75 9.17082C12.75 9.27795 12.7501 9.33904 12.7518 9.38529C12.7528 9.41425 12.7542 9.42649 12.7546 9.42955C12.7662 9.48945 12.7993 9.54303 12.8477 9.58021C12.8502 9.58194 12.8606 9.58864 12.886 9.60252C12.9266 9.62468 12.9812 9.65209 13.0771 9.7L14.3938 10.3584C14.6183 10.4706 14.7604 10.5414 14.8684 10.5885C14.9382 10.6189 14.9705 10.6287 14.9785 10.631C15.0885 10.6405 15.1917 10.5767 15.2324 10.4742C15.2339 10.4659 15.2396 10.4327 15.2436 10.3566C15.2498 10.239 15.25 10.0802 15.25 9.82918C15.25 9.72205 15.2499 9.66096 15.2482 9.61471C15.2472 9.58575 15.2458 9.57351 15.2454 9.57045C15.2338 9.51055 15.2007 9.45697 15.1523 9.41979C15.1498 9.41805 15.1394 9.41136 15.114 9.39748C15.0734 9.37533 15.0188 9.34791 14.9229 9.3L13.6062 8.64164C13.3817 8.52939 13.2396 8.45859 13.1316 8.41151C13.0617 8.38107 13.0295 8.37131 13.0215 8.36896C12.9115 8.35945 12.8083 8.42327 12.7676 8.52584ZM12.75 11.2135L13.7396 11.7083C13.9425 11.8098 14.1204 11.8987 14.269 11.9635C14.4199 12.0293 14.5988 12.097 14.7972 12.1202C15.6037 12.2142 16.3689 11.7413 16.6454 10.978C16.7134 10.7901 16.7328 10.5998 16.7415 10.4355C16.75 10.2735 16.75 10.0747 16.75 9.8479V9.82918C16.75 9.81565 16.75 9.80205 16.75 9.78837C16.7503 9.62647 16.7505 9.45474 16.7188 9.28904C16.638 8.86674 16.4045 8.48898 16.0629 8.22783C15.9289 8.12535 15.7752 8.04877 15.6303 7.97658C15.618 7.97048 15.6059 7.96441 15.5938 7.95836L14.2603 7.29164C14.0575 7.19022 13.8796 7.10128 13.731 7.03647C13.5801 6.97071 13.4012 6.90297 13.2028 6.87982C12.3963 6.78575 11.6311 7.25868 11.3546 8.02203C11.2866 8.20986 11.2672 8.40019 11.2585 8.56454C11.2519 8.68919 11.2504 8.83571 11.2501 9L11.25 9.11944C11.25 9.13026 11.25 9.14115 11.25 9.1521V9.17082C11.25 9.18435 11.25 9.19795 11.25 9.21163C11.2499 9.23918 11.2499 9.26701 11.25 9.29505V12.5499C10.875 12.3581 10.4501 12.25 10 12.25C8.48122 12.25 7.25 13.4812 7.25 15C7.25 16.5188 8.48122 17.75 10 17.75C11.5188 17.75 12.75 16.5188 12.75 15V11.2135ZM11.25 15C11.25 14.3096 10.6904 13.75 10 13.75C9.30964 13.75 8.75 14.3096 8.75 15C8.75 15.6904 9.30964 16.25 10 16.25C10.6904 16.25 11.25 15.6904 11.25 15ZM17.4697 14.4697C17.7626 14.1768 18.2374 14.1768 18.5303 14.4697L21.0303 16.9697C21.3232 17.2626 21.3232 17.7374 21.0303 18.0303C20.7374 18.3232 20.2626 18.3232 19.9697 18.0303L18.75 16.8107V22C18.75 22.4142 18.4142 22.75 18 22.75C17.5858 22.75 17.25 22.4142 17.25 22V16.8107L16.0303 18.0303C15.7374 18.3232 15.2626 18.3232 14.9697 18.0303C14.6768 17.7374 14.6768 17.2626 14.9697 16.9697L17.4697 14.4697Z" })))));
1217
- }
1218
- renderRecordButton() {
1219
- if (!this.inputTypes.includes('voice'))
1220
- return;
1221
- const buttonClass = [
1222
- 'record-button',
1223
- this.isRecording && 'recording',
1224
- this.isProcessing && 'processing'
1225
- ].filter(Boolean).join(' ');
1226
- const isDisabled = this.isProcessing || this.hasError;
1227
- 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" })))));
1228
- }
1229
- renderStatusMessage() {
1230
- const statusClass = [
1231
- 'status-text',
1232
- this.hasError && 'error',
1233
- this.filledData && !this.hasError && 'success'
1234
- ].filter(Boolean).join(' ');
1235
- return h("div", { class: statusClass }, this.statusMessage);
1236
- }
1237
- renderFormPreview() {
1238
- if (!this.parsedSchema)
1239
- return null;
1240
- const isPreview = this.isReadonlyMode && !this.filledData;
1241
- const title = isPreview ? 'Form Preview (Voice input to fill)' : 'Voice-Filled Form:';
1242
- return (h("div", { class: "form-preview" }, h("div", { class: "form-preview-title" }, title), h("form", { class: "voice-filled-form" }, this.renderFormFields())));
1243
- }
1244
- renderFormFields() {
1245
- // console.log("renderFormFields", this.parsedSchema);
1246
- if (!this.parsedSchema)
1247
- return null;
1248
- switch (this.context) {
1249
- case "ecoteka":
1250
- // console.log("TODO renderFormFields", this.parsedSchema);
1251
- case "ng":
1252
- return this.parsedSchema.Children.map((child) => {
1253
- var _a, _b, _c;
1254
- if (!child.System_Name || !child.Type)
1255
- return null;
1256
- const fieldName = child.System_Name;
1257
- const fieldType = this.mapFieldType(child.Type);
1258
- const fieldLabel = ((_a = child.Settings) === null || _a === void 0 ? void 0 : _a.Label) || child.System_Name;
1259
- const isRequired = child.Required || false;
1260
- const fieldValue = (_b = child.Settings) === null || _b === void 0 ? void 0 : _b.Default_Value;
1261
- return (h("div", { class: "form-group", key: fieldName }, h("label", { htmlFor: fieldName, class: "form-label" }, fieldLabel, isRequired && h("span", { class: "required" }, "*")), this.renderFormField(fieldName, {
1262
- type: fieldType,
1263
- title: fieldLabel,
1264
- required: isRequired,
1265
- options: (_c = child.Children) === null || _c === void 0 ? void 0 : _c.map((option) => option.System_Name || option.Label || option.toString())
1266
- }, fieldValue)));
1267
- }).filter(Boolean);
1268
- case "ecoll-veto":
1269
- // NOTE STEP 2
1270
- // console.log("TODO renderFormFields", this.parsedSchema);
1271
- const mergedItemsSchema = (this.parsedSchema[0].items).concat(this.parsedSchema[1].items);
1272
- return Object.entries(mergedItemsSchema).map(([key, field]) => {
1273
- var _a, _b;
1274
- const fieldName = field.name;
1275
- field.type = this.mapFieldType(field.type);
1276
- const fieldLabel = field.label || fieldName;
1277
- const isRequired = field.required || false;
1278
- const fieldValue = this.parsedSchema[2][fieldName];
1279
- 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))));
1280
- });
1281
- case "track":
1282
- default:
1283
- return Object.entries(this.parsedSchema.fields).map(([fieldName, field]) => {
1284
- var _a, _b;
1285
- 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))));
1286
- });
1287
- }
1288
- }
1289
- renderFormField(fieldName, field, value) {
1290
- var _a, _b;
1291
- const isReadonly = this.isReadonlyMode && !this.filledData;
1292
- const commonProps = {
1293
- id: fieldName,
1294
- name: fieldName,
1295
- class: 'form-input',
1296
- required: field.required,
1297
- disabled: isReadonly
1298
- };
1299
- switch (field.type) {
1300
- case 'select':
1301
- if (isReadonly) {
1302
- // In readonly mode, show all options as a list instead of dropdown
1303
- 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))))));
1304
- }
1305
- 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 :
1306
- _b.map(option => (h("option", { value: option, selected: value === option }, option)))));
1307
- case 'boolean':
1308
- return (h("input", Object.assign({}, commonProps, { type: "checkbox", class: "form-checkbox", checked: value === true || value === 'true' })));
1309
- case 'number':
1310
- return (h("input", Object.assign({}, commonProps, { type: "number", min: field.min, max: field.max, step: "any", value: value || '' })));
1311
- case 'date':
1312
- return (h("input", Object.assign({}, commonProps, { type: 'date', value: value ? (([d, m, y]) => `${y}-${m}-${d}`)(value.split("/")) : '' })));
1313
- case 'datetime':
1314
- return (h("input", Object.assign({}, commonProps, { type: 'datetime-local', value: value || '' })));
1315
- default: // string
1316
- return (h("input", Object.assign({}, commonProps, { type: "text", pattern: field.pattern, placeholder: field.description, value: value || '' })));
1317
- }
1318
- }
1319
- renderDebugPanel() {
1320
- if (!this.debug)
1321
- return null;
1322
- return (h("div", { class: "debug-panel" }, h("div", { class: "debug-title" }, "Debug Information:"), h("div", { class: "debug-content" }, JSON.stringify(this.debugInfo, null, 2))));
1323
- }
1324
- render() {
1325
- return (h("div", { key: '6316d3928829e102feab372fbd2e669a38239d84' }, h("div", { key: '65bebc70c371d8789566142dd27a1e102eeed0c3', class: "voice-recorder-container" + (this.debug || this.renderForm ? "-debug" : "") }, h("div", { key: 'c0926aa835ecc152bdbc5ac7779d9dfc7ea9b62f', class: "row-audio-area" }, this.renderRecordButton(), this.renderUploadRecordButton()), this.displayStatus ? this.renderStatusMessage() : "", this.renderUploadButton(), this.renderForm ? this.renderFormPreview() : "", this.debug ? this.renderDebugPanel() : "")));
1326
- }
1327
- static get watchers() { return {
1328
- "formJson": ["initializeServices"],
1329
- "serviceConfig": ["initializeServices"]
1330
- }; }
1331
- };
1332
- VoiceFormRecorder.style = voiceInputModuleCss;
1333
-
1334
- export { OcrFileUploader as ocr_file_uploader, VoiceFormRecorder as voice_input_module };
1335
- //# sourceMappingURL=ocr-file-uploader.voice-input-module.entry.js.map
1336
-
1337
- //# sourceMappingURL=ocr-file-uploader_2.entry.js.map