@ourlu/assistant-sdk 0.2.3 → 0.2.5

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 (51) hide show
  1. package/dist/iife/audio.v1.028c93fe.js +160 -0
  2. package/dist/iife/audio.v1.051ececf.js +183 -0
  3. package/dist/iife/audio.v1.200db1a6.js +208 -0
  4. package/dist/iife/audio.v1.20858b08.js +191 -0
  5. package/dist/iife/audio.v1.2690e445.js +179 -0
  6. package/dist/iife/audio.v1.2742ff12.js +188 -0
  7. package/dist/iife/audio.v1.70af81b3.js +191 -0
  8. package/dist/iife/audio.v1.95146620.js +1 -1
  9. package/dist/iife/audio.v1.b330baaf.js +166 -0
  10. package/dist/iife/audio.v1.bb9c2d88.js +181 -0
  11. package/dist/iife/audio.v1.ea7571b2.js +182 -0
  12. package/dist/iife/audio.v1.fc0aa8af.js +191 -0
  13. package/dist/iife/audio.v1.js +107 -95
  14. package/dist/iife/engine.v1.2b5bb43b.js +735 -0
  15. package/dist/iife/engine.v1.3b09dc20.js +3 -3
  16. package/dist/iife/engine.v1.56074e5a.js +769 -0
  17. package/dist/iife/engine.v1.61c10e6c.js +770 -0
  18. package/dist/iife/engine.v1.773fc15d.js +2 -2
  19. package/dist/iife/engine.v1.80d2230f.js +770 -0
  20. package/dist/iife/engine.v1.940ba9ea.js +764 -0
  21. package/dist/iife/engine.v1.99a33ee2.js +767 -0
  22. package/dist/iife/engine.v1.9ca6b7ec.js +756 -0
  23. package/dist/iife/engine.v1.a1f7dea2.js +764 -0
  24. package/dist/iife/engine.v1.c0c00bd0.js +721 -0
  25. package/dist/iife/engine.v1.c127656e.js +820 -0
  26. package/dist/iife/engine.v1.c54c9a1a.js +770 -0
  27. package/dist/iife/engine.v1.d1052e81.js +770 -0
  28. package/dist/iife/engine.v1.f6d23a0f.js +770 -0
  29. package/dist/iife/engine.v1.js +135 -36
  30. package/dist/iife/loader.v1.js +5 -1
  31. package/dist/iife/signalement.v1.d321dfde.js +518 -0
  32. package/dist/iife/signalement.v1.js +518 -0
  33. package/dist/iife/ui.v1.00abf020.js +895 -0
  34. package/dist/iife/ui.v1.5d2d4504.js +942 -0
  35. package/dist/iife/ui.v1.6afac75f.js +944 -0
  36. package/dist/iife/ui.v1.6becaa84.js +895 -0
  37. package/dist/iife/ui.v1.6c9e4995.js +895 -0
  38. package/dist/iife/ui.v1.7fb4db0b.js +935 -0
  39. package/dist/iife/ui.v1.88bf5494.js +898 -0
  40. package/dist/iife/ui.v1.923a4e6d.js +937 -0
  41. package/dist/iife/ui.v1.9bfe2815.js +942 -0
  42. package/dist/iife/ui.v1.a8cfe724.js +900 -0
  43. package/dist/iife/ui.v1.c58e1d58.js +959 -0
  44. package/dist/iife/ui.v1.cdfe9a45.js +919 -0
  45. package/dist/iife/ui.v1.e007c7c4.js +926 -0
  46. package/dist/iife/ui.v1.e24ba2bd.js +903 -0
  47. package/dist/iife/ui.v1.f1d8e998.js +903 -0
  48. package/dist/iife/ui.v1.fc52b520.js +895 -0
  49. package/dist/iife/ui.v1.js +154 -147
  50. package/dist/iife/widget-manifest.json +4 -3
  51. package/package.json +2 -1
@@ -0,0 +1,191 @@
1
+ (function() {
2
+ "use strict";
3
+ var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
4
+ if (!runtime.utils) {
5
+ throw new Error("Widget runtime utils module must be loaded first.");
6
+ }
7
+
8
+ var resolveRecorderMimeType = runtime.utils.resolveRecorderMimeType;
9
+ var encodeArrayBufferToBase64 = runtime.utils.encodeArrayBufferToBase64;
10
+
11
+ function WidgetAudioManager(state, api, ui) {
12
+ this.state = state;
13
+ this.api = api;
14
+ this.ui = ui;
15
+ this.stream = null;
16
+ this.recorder = null;
17
+ this.chunks = [];
18
+ this._recording = false;
19
+ this._processing = false;
20
+ }
21
+
22
+ WidgetAudioManager.prototype.isSupported = function() {
23
+ return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && typeof MediaRecorder !== "undefined");
24
+ };
25
+
26
+ WidgetAudioManager.prototype.toggle = async function() {
27
+ if (this._processing) return;
28
+ if (this._recording) return this.stop();
29
+ return this.start();
30
+ };
31
+
32
+ WidgetAudioManager.prototype.start = async function() {
33
+ if (!this.isSupported() || this.state.sending || this._recording || this._processing) return;
34
+ this.ui.showError("");
35
+ this.ui.setInput("");
36
+ this.ui.setMicListening(true);
37
+ try {
38
+ this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
39
+ this.chunks = [];
40
+ var mimeType = resolveRecorderMimeType();
41
+ this.recorder = new MediaRecorder(this.stream, mimeType ? { mimeType: mimeType } : {});
42
+ var self = this;
43
+ this.recorder.ondataavailable = function(event) {
44
+ if (event.data && event.data.size > 0) self.chunks.push(event.data);
45
+ };
46
+ this.recorder.start(250);
47
+ this._recording = true;
48
+ this.state.listening = true;
49
+ } catch (error) {
50
+ this.cleanupMedia();
51
+ this._recording = false;
52
+ this.state.listening = false;
53
+ this.ui.setMicListening(false);
54
+ this.ui.showError("Erreur démarrage micro : " + (error.message || error));
55
+ }
56
+ };
57
+
58
+ WidgetAudioManager.prototype.stop = async function() {
59
+ if (!this._recording) return;
60
+ this._recording = false;
61
+ this._processing = true;
62
+ this.state.listening = false;
63
+ this.ui.setMicListening(false);
64
+ this.ui.setComposerDisabled(true);
65
+ this.ui.setInputPlaceholder("Transcription en cours…");
66
+ try {
67
+ var blobAndSession = await Promise.all([
68
+ this.collectRecordedBlob(),
69
+ this.api.ensureSession()
70
+ ]);
71
+ var blob = blobAndSession[0];
72
+ var sessionId = blobAndSession[1];
73
+ this.cleanupMedia();
74
+ if (!blob || blob.size === 0) {
75
+ this.ui.showError("Aucun audio enregistré.");
76
+ return;
77
+ }
78
+ var base64 = encodeArrayBufferToBase64(await blob.arrayBuffer());
79
+ var transcription = this.openTranscriptionListener(sessionId);
80
+ var audioSession = await this.api.startAudioSession(sessionId);
81
+ var audioSessionId = audioSession.audio_session_id || "";
82
+ await this.api.sendAudioChunk(sessionId, audioSessionId, base64);
83
+ transcription.setAudioSessionId(audioSessionId);
84
+ await transcription.connected;
85
+ await this.api.closeAudioSession(sessionId, audioSessionId);
86
+ var transcribedText = await transcription.result;
87
+ if (transcribedText) {
88
+ this.ui.setInput(transcribedText);
89
+ }
90
+ } catch (error) {
91
+ this.cleanupMedia();
92
+ this.ui.showError("Erreur transcription audio : " + (error.message || error));
93
+ } finally {
94
+ this._processing = false;
95
+ this.ui.setInputPlaceholder("");
96
+ this.ui.setComposerDisabled(false);
97
+ }
98
+ };
99
+
100
+ WidgetAudioManager.prototype.openTranscriptionListener = function(sessionId) {
101
+ var resolved = false;
102
+ var stopStream = null;
103
+ var expectedAudioSessionId = "";
104
+ var resolveResult, rejectResult, resolveConnected;
105
+ var resultPromise = new Promise(function(res, rej) { resolveResult = res; rejectResult = rej; });
106
+ var connectedPromise = new Promise(function(res) { resolveConnected = res; });
107
+ var timeout = setTimeout(function() {
108
+ if (!resolved) {
109
+ resolved = true;
110
+ if (stopStream) stopStream();
111
+ rejectResult(new Error("Transcription audio : délai dépassé."));
112
+ }
113
+ }, 30000);
114
+ function belongsToCurrentSession(payload) {
115
+ if (!expectedAudioSessionId) return true;
116
+ var payloadAudioId = payload && payload.audio_session_id ? payload.audio_session_id : "";
117
+ return !payloadAudioId || payloadAudioId === expectedAudioSessionId;
118
+ }
119
+ this.api.streamAudioDraft(sessionId, {
120
+ onDelta: function() {},
121
+ onComplete: function(payload) {
122
+ if (resolved || !belongsToCurrentSession(payload)) return;
123
+ resolved = true;
124
+ clearTimeout(timeout);
125
+ if (stopStream) stopStream();
126
+ resolveResult(payload && payload.text ? String(payload.text).trim() : "");
127
+ },
128
+ onError: function(payload) {
129
+ if (resolved || !belongsToCurrentSession(payload)) return;
130
+ resolved = true;
131
+ clearTimeout(timeout);
132
+ if (stopStream) stopStream();
133
+ rejectResult(new Error((payload && payload.message) || "Erreur transcription audio"));
134
+ },
135
+ onTransportError: function(message) {
136
+ if (resolved) return;
137
+ var normalized = String(message || "").toLowerCase();
138
+ var isAbort = normalized.indexOf("aborted") !== -1 || normalized.indexOf("aborterror") !== -1;
139
+ if (isAbort) return;
140
+ resolved = true;
141
+ clearTimeout(timeout);
142
+ if (stopStream) stopStream();
143
+ rejectResult(new Error(message || "Erreur stream audio"));
144
+ }
145
+ }).then(function(stop) {
146
+ stopStream = stop;
147
+ resolveConnected();
148
+ }).catch(function(err) {
149
+ resolveConnected();
150
+ if (!resolved) {
151
+ resolved = true;
152
+ clearTimeout(timeout);
153
+ rejectResult(err);
154
+ }
155
+ });
156
+ return {
157
+ connected: connectedPromise,
158
+ result: resultPromise,
159
+ setAudioSessionId: function(id) { expectedAudioSessionId = id; }
160
+ };
161
+ };
162
+
163
+ WidgetAudioManager.prototype.collectRecordedBlob = function() {
164
+ var self = this;
165
+ if (!this.recorder) return Promise.resolve(new Blob());
166
+ return new Promise(function(resolve) {
167
+ var recorder = self.recorder;
168
+ function done() {
169
+ var blob = new Blob(self.chunks, { type: recorder.mimeType || "audio/webm" });
170
+ resolve(blob);
171
+ }
172
+ if (recorder.state === "inactive") return done();
173
+ recorder.addEventListener("stop", done, { once: true });
174
+ recorder.stop();
175
+ });
176
+ };
177
+
178
+ WidgetAudioManager.prototype.cleanupMedia = function() {
179
+ if (this.recorder) {
180
+ this.recorder.ondataavailable = null;
181
+ this.recorder = null;
182
+ }
183
+ if (this.stream) {
184
+ this.stream.getTracks().forEach(function(track) { track.stop(); });
185
+ this.stream = null;
186
+ }
187
+ this.chunks = [];
188
+ };
189
+
190
+ runtime.WidgetAudioManager = WidgetAudioManager;
191
+ })();
@@ -40,6 +40,7 @@
40
40
  try {
41
41
  this.ui.showError("");
42
42
  this.clearDraftCleanup();
43
+ this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
43
44
  if (this.activeAudioSessionId && this.state.sessionId) {
44
45
  try {
45
46
  await this.api.closeAudioSession(this.state.sessionId, this.activeAudioSessionId);
@@ -56,7 +57,6 @@
56
57
  });
57
58
  var audioSession = await this.api.startAudioSession(sessionId);
58
59
  this.activeAudioSessionId = audioSession.audio_session_id || "";
59
- this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
60
60
  this.chunks = [];
61
61
  var mimeType = resolveRecorderMimeType();
62
62
  this.recorder = new MediaRecorder(this.stream, mimeType ? { mimeType: mimeType } : {});
@@ -0,0 +1,166 @@
1
+ (function() {
2
+ "use strict";
3
+ var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
4
+ if (!runtime.utils) {
5
+ throw new Error("Widget runtime utils module must be loaded first.");
6
+ }
7
+
8
+ var resolveRecorderMimeType = runtime.utils.resolveRecorderMimeType;
9
+ var encodeArrayBufferToBase64 = runtime.utils.encodeArrayBufferToBase64;
10
+
11
+ function WidgetAudioManager(state, api, ui) {
12
+ this.state = state;
13
+ this.api = api;
14
+ this.ui = ui;
15
+ this.stream = null;
16
+ this.recorder = null;
17
+ this.chunks = [];
18
+ this._recording = false;
19
+ this._processing = false;
20
+ }
21
+
22
+ WidgetAudioManager.prototype.isSupported = function() {
23
+ return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && typeof MediaRecorder !== "undefined");
24
+ };
25
+
26
+ WidgetAudioManager.prototype.toggle = async function() {
27
+ if (this._processing) return;
28
+ if (this._recording) return this.stop();
29
+ return this.start();
30
+ };
31
+
32
+ WidgetAudioManager.prototype.start = async function() {
33
+ if (!this.isSupported() || this.state.sending || this._recording || this._processing) return;
34
+ try {
35
+ this.ui.showError("");
36
+ this.ui.setInput("");
37
+ this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
38
+ this.chunks = [];
39
+ var mimeType = resolveRecorderMimeType();
40
+ this.recorder = new MediaRecorder(this.stream, mimeType ? { mimeType: mimeType } : {});
41
+ var self = this;
42
+ this.recorder.ondataavailable = function(event) {
43
+ if (event.data && event.data.size > 0) self.chunks.push(event.data);
44
+ };
45
+ this.recorder.start(250);
46
+ this._recording = true;
47
+ this.state.listening = true;
48
+ this.ui.setMicListening(true);
49
+ } catch (error) {
50
+ this.cleanupMedia();
51
+ this.state.listening = false;
52
+ this.ui.setMicListening(false);
53
+ this.ui.showError("Erreur démarrage micro : " + (error.message || error));
54
+ }
55
+ };
56
+
57
+ WidgetAudioManager.prototype.stop = async function() {
58
+ if (!this._recording) return;
59
+ this._recording = false;
60
+ this._processing = true;
61
+ this.state.listening = false;
62
+ this.ui.setMicListening(false);
63
+ this.ui.setComposerDisabled(true);
64
+ try {
65
+ var blob = await this.collectRecordedBlob();
66
+ this.cleanupMedia();
67
+ if (!blob || blob.size === 0) {
68
+ this.ui.showError("Aucun audio enregistré.");
69
+ return;
70
+ }
71
+ var base64 = encodeArrayBufferToBase64(await blob.arrayBuffer());
72
+ var sessionId = await this.api.ensureSession();
73
+ var audioSession = await this.api.startAudioSession(sessionId);
74
+ var audioSessionId = audioSession.audio_session_id || "";
75
+ await this.api.sendAudioChunk(sessionId, audioSessionId, base64);
76
+ var transcriptionPromise = this.waitForTranscription(sessionId, audioSessionId);
77
+ await this.api.closeAudioSession(sessionId, audioSessionId);
78
+ var transcribedText = await transcriptionPromise;
79
+ if (transcribedText) {
80
+ this.ui.setInput(transcribedText);
81
+ }
82
+ } catch (error) {
83
+ this.cleanupMedia();
84
+ this.ui.showError("Erreur transcription audio : " + (error.message || error));
85
+ } finally {
86
+ this._processing = false;
87
+ this.ui.setComposerDisabled(false);
88
+ }
89
+ };
90
+
91
+ WidgetAudioManager.prototype.waitForTranscription = function(sessionId, audioSessionId) {
92
+ var self = this;
93
+ return new Promise(function(resolve, reject) {
94
+ var resolved = false;
95
+ var timeout = setTimeout(function() {
96
+ if (!resolved) {
97
+ resolved = true;
98
+ if (stopStream) stopStream();
99
+ reject(new Error("Transcription audio : délai dépassé."));
100
+ }
101
+ }, 30000);
102
+ function belongsToCurrentSession(payload) {
103
+ if (!audioSessionId) return true;
104
+ var payloadAudioId = payload && payload.audio_session_id ? payload.audio_session_id : "";
105
+ return !payloadAudioId || payloadAudioId === audioSessionId;
106
+ }
107
+ var stopStream = null;
108
+ self.api.streamAudioDraft(sessionId, {
109
+ onDelta: function() {},
110
+ onComplete: function(payload) {
111
+ if (resolved || !belongsToCurrentSession(payload)) return;
112
+ resolved = true;
113
+ clearTimeout(timeout);
114
+ if (stopStream) stopStream();
115
+ resolve(payload && payload.text ? String(payload.text).trim() : "");
116
+ },
117
+ onError: function(payload) {
118
+ if (resolved || !belongsToCurrentSession(payload)) return;
119
+ resolved = true;
120
+ clearTimeout(timeout);
121
+ if (stopStream) stopStream();
122
+ reject(new Error((payload && payload.message) || "Erreur transcription audio"));
123
+ },
124
+ onTransportError: function(message) {
125
+ if (resolved) return;
126
+ var normalized = String(message || "").toLowerCase();
127
+ var isAbort = normalized.indexOf("aborted") !== -1 || normalized.indexOf("aborterror") !== -1;
128
+ if (isAbort) return;
129
+ resolved = true;
130
+ clearTimeout(timeout);
131
+ if (stopStream) stopStream();
132
+ reject(new Error(message || "Erreur stream audio"));
133
+ }
134
+ }).then(function(stop) { stopStream = stop; });
135
+ });
136
+ };
137
+
138
+ WidgetAudioManager.prototype.collectRecordedBlob = function() {
139
+ var self = this;
140
+ if (!this.recorder) return Promise.resolve(new Blob());
141
+ return new Promise(function(resolve) {
142
+ var recorder = self.recorder;
143
+ function done() {
144
+ var blob = new Blob(self.chunks, { type: recorder.mimeType || "audio/webm" });
145
+ resolve(blob);
146
+ }
147
+ if (recorder.state === "inactive") return done();
148
+ recorder.addEventListener("stop", done, { once: true });
149
+ recorder.stop();
150
+ });
151
+ };
152
+
153
+ WidgetAudioManager.prototype.cleanupMedia = function() {
154
+ if (this.recorder) {
155
+ this.recorder.ondataavailable = null;
156
+ this.recorder = null;
157
+ }
158
+ if (this.stream) {
159
+ this.stream.getTracks().forEach(function(track) { track.stop(); });
160
+ this.stream = null;
161
+ }
162
+ this.chunks = [];
163
+ };
164
+
165
+ runtime.WidgetAudioManager = WidgetAudioManager;
166
+ })();
@@ -0,0 +1,181 @@
1
+ (function() {
2
+ "use strict";
3
+ var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
4
+ if (!runtime.utils) {
5
+ throw new Error("Widget runtime utils module must be loaded first.");
6
+ }
7
+
8
+ var resolveRecorderMimeType = runtime.utils.resolveRecorderMimeType;
9
+ var encodeArrayBufferToBase64 = runtime.utils.encodeArrayBufferToBase64;
10
+
11
+ function WidgetAudioManager(state, api, ui) {
12
+ this.state = state;
13
+ this.api = api;
14
+ this.ui = ui;
15
+ this.stream = null;
16
+ this.recorder = null;
17
+ this.chunks = [];
18
+ this._recording = false;
19
+ this._processing = false;
20
+ }
21
+
22
+ WidgetAudioManager.prototype.isSupported = function() {
23
+ return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && typeof MediaRecorder !== "undefined");
24
+ };
25
+
26
+ WidgetAudioManager.prototype.toggle = async function() {
27
+ if (this._processing) return;
28
+ if (this._recording) return this.stop();
29
+ return this.start();
30
+ };
31
+
32
+ WidgetAudioManager.prototype.start = async function() {
33
+ if (!this.isSupported() || this.state.sending || this._recording || this._processing) return;
34
+ try {
35
+ this.ui.showError("");
36
+ this.ui.setInput("");
37
+ this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
38
+ this.chunks = [];
39
+ var mimeType = resolveRecorderMimeType();
40
+ this.recorder = new MediaRecorder(this.stream, mimeType ? { mimeType: mimeType } : {});
41
+ var self = this;
42
+ this.recorder.ondataavailable = function(event) {
43
+ if (event.data && event.data.size > 0) self.chunks.push(event.data);
44
+ };
45
+ this.recorder.start(250);
46
+ this._recording = true;
47
+ this.state.listening = true;
48
+ this.ui.setMicListening(true);
49
+ } catch (error) {
50
+ this.cleanupMedia();
51
+ this.state.listening = false;
52
+ this.ui.setMicListening(false);
53
+ this.ui.showError("Erreur démarrage micro : " + (error.message || error));
54
+ }
55
+ };
56
+
57
+ WidgetAudioManager.prototype.stop = async function() {
58
+ if (!this._recording) return;
59
+ this._recording = false;
60
+ this._processing = true;
61
+ this.state.listening = false;
62
+ this.ui.setMicListening(false);
63
+ this.ui.setComposerDisabled(true);
64
+ try {
65
+ var blob = await this.collectRecordedBlob();
66
+ this.cleanupMedia();
67
+ if (!blob || blob.size === 0) {
68
+ this.ui.showError("Aucun audio enregistré.");
69
+ return;
70
+ }
71
+ this.ui.setInputPlaceholder("Transcription en cours…");
72
+ var base64 = encodeArrayBufferToBase64(await blob.arrayBuffer());
73
+ var sessionId = await this.api.ensureSession();
74
+ var audioSession = await this.api.startAudioSession(sessionId);
75
+ var audioSessionId = audioSession.audio_session_id || "";
76
+ await this.api.sendAudioChunk(sessionId, audioSessionId, base64);
77
+ var transcription = this.openTranscriptionListener(sessionId, audioSessionId);
78
+ await transcription.connected;
79
+ await this.api.closeAudioSession(sessionId, audioSessionId);
80
+ var transcribedText = await transcription.result;
81
+ this.ui.setInputPlaceholder("");
82
+ if (transcribedText) {
83
+ this.ui.setInput(transcribedText);
84
+ }
85
+ } catch (error) {
86
+ this.cleanupMedia();
87
+ this.ui.showError("Erreur transcription audio : " + (error.message || error));
88
+ } finally {
89
+ this._processing = false;
90
+ this.ui.setInputPlaceholder("");
91
+ this.ui.setComposerDisabled(false);
92
+ }
93
+ };
94
+
95
+ WidgetAudioManager.prototype.openTranscriptionListener = function(sessionId, audioSessionId) {
96
+ var resolved = false;
97
+ var stopStream = null;
98
+ var resolveResult, rejectResult, resolveConnected;
99
+ var resultPromise = new Promise(function(res, rej) { resolveResult = res; rejectResult = rej; });
100
+ var connectedPromise = new Promise(function(res) { resolveConnected = res; });
101
+ var timeout = setTimeout(function() {
102
+ if (!resolved) {
103
+ resolved = true;
104
+ if (stopStream) stopStream();
105
+ rejectResult(new Error("Transcription audio : délai dépassé."));
106
+ }
107
+ }, 30000);
108
+ function belongsToCurrentSession(payload) {
109
+ if (!audioSessionId) return true;
110
+ var payloadAudioId = payload && payload.audio_session_id ? payload.audio_session_id : "";
111
+ return !payloadAudioId || payloadAudioId === audioSessionId;
112
+ }
113
+ this.api.streamAudioDraft(sessionId, {
114
+ onDelta: function() {},
115
+ onComplete: function(payload) {
116
+ if (resolved || !belongsToCurrentSession(payload)) return;
117
+ resolved = true;
118
+ clearTimeout(timeout);
119
+ if (stopStream) stopStream();
120
+ resolveResult(payload && payload.text ? String(payload.text).trim() : "");
121
+ },
122
+ onError: function(payload) {
123
+ if (resolved || !belongsToCurrentSession(payload)) return;
124
+ resolved = true;
125
+ clearTimeout(timeout);
126
+ if (stopStream) stopStream();
127
+ rejectResult(new Error((payload && payload.message) || "Erreur transcription audio"));
128
+ },
129
+ onTransportError: function(message) {
130
+ if (resolved) return;
131
+ var normalized = String(message || "").toLowerCase();
132
+ var isAbort = normalized.indexOf("aborted") !== -1 || normalized.indexOf("aborterror") !== -1;
133
+ if (isAbort) return;
134
+ resolved = true;
135
+ clearTimeout(timeout);
136
+ if (stopStream) stopStream();
137
+ rejectResult(new Error(message || "Erreur stream audio"));
138
+ }
139
+ }).then(function(stop) {
140
+ stopStream = stop;
141
+ resolveConnected();
142
+ }).catch(function(err) {
143
+ resolveConnected();
144
+ if (!resolved) {
145
+ resolved = true;
146
+ clearTimeout(timeout);
147
+ rejectResult(err);
148
+ }
149
+ });
150
+ return { connected: connectedPromise, result: resultPromise };
151
+ };
152
+
153
+ WidgetAudioManager.prototype.collectRecordedBlob = function() {
154
+ var self = this;
155
+ if (!this.recorder) return Promise.resolve(new Blob());
156
+ return new Promise(function(resolve) {
157
+ var recorder = self.recorder;
158
+ function done() {
159
+ var blob = new Blob(self.chunks, { type: recorder.mimeType || "audio/webm" });
160
+ resolve(blob);
161
+ }
162
+ if (recorder.state === "inactive") return done();
163
+ recorder.addEventListener("stop", done, { once: true });
164
+ recorder.stop();
165
+ });
166
+ };
167
+
168
+ WidgetAudioManager.prototype.cleanupMedia = function() {
169
+ if (this.recorder) {
170
+ this.recorder.ondataavailable = null;
171
+ this.recorder = null;
172
+ }
173
+ if (this.stream) {
174
+ this.stream.getTracks().forEach(function(track) { track.stop(); });
175
+ this.stream = null;
176
+ }
177
+ this.chunks = [];
178
+ };
179
+
180
+ runtime.WidgetAudioManager = WidgetAudioManager;
181
+ })();