@lovelace_lol/polymer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +226 -0
  2. package/dist/index.d.ts +2603 -0
  3. package/dist/index.js +1031 -0
  4. package/dist/test.cjs +1519 -0
  5. package/dist/worker/agency-worker.js +972 -0
  6. package/dist/worker/manifest.edn +1 -0
  7. package/package.json +57 -0
  8. package/shadow-cljs.edn +173 -0
  9. package/src/polymer/animation/agency.cljs +84 -0
  10. package/src/polymer/animation/domain.cljs +110 -0
  11. package/src/polymer/animation/planner.cljs +88 -0
  12. package/src/polymer/animation/runtime.cljs +137 -0
  13. package/src/polymer/animation/scheduler.cljs +178 -0
  14. package/src/polymer/animation/service.cljs +981 -0
  15. package/src/polymer/animation/state.cljs +112 -0
  16. package/src/polymer/blink/agency.cljs +131 -0
  17. package/src/polymer/blink/planner.cljs +115 -0
  18. package/src/polymer/blink/scheduler.cljs +90 -0
  19. package/src/polymer/blink/snippet.cljs +50 -0
  20. package/src/polymer/blink/state.cljs +102 -0
  21. package/src/polymer/camera_context/agency.cljs +132 -0
  22. package/src/polymer/camera_context/domain.cljs +186 -0
  23. package/src/polymer/camera_context/planner.cljs +50 -0
  24. package/src/polymer/camera_context/scheduler.cljs +113 -0
  25. package/src/polymer/camera_context/state.cljs +121 -0
  26. package/src/polymer/character.cljs +471 -0
  27. package/src/polymer/conversation/agency.cljs +83 -0
  28. package/src/polymer/conversation/domain.cljs +35 -0
  29. package/src/polymer/conversation/effector.cljs +130 -0
  30. package/src/polymer/conversation/planner.cljs +178 -0
  31. package/src/polymer/conversation/scheduler.cljs +202 -0
  32. package/src/polymer/conversation/service.cljs +329 -0
  33. package/src/polymer/conversation/state.cljs +186 -0
  34. package/src/polymer/core.cljs +172 -0
  35. package/src/polymer/eye_head/agency.cljs +75 -0
  36. package/src/polymer/eye_head/domain.cljs +133 -0
  37. package/src/polymer/eye_head/goap.cljs +106 -0
  38. package/src/polymer/eye_head/scheduler.cljs +176 -0
  39. package/src/polymer/eye_head/service.cljs +259 -0
  40. package/src/polymer/eye_head/snippet.cljs +92 -0
  41. package/src/polymer/eye_head/state.cljs +167 -0
  42. package/src/polymer/gaze/agency.cljs +85 -0
  43. package/src/polymer/gaze/domain.cljs +211 -0
  44. package/src/polymer/gaze/goap.cljs +208 -0
  45. package/src/polymer/gaze/scheduler.cljs +184 -0
  46. package/src/polymer/gaze/state.cljs +202 -0
  47. package/src/polymer/gesture/agency.cljs +185 -0
  48. package/src/polymer/gesture/goap.cljs +461 -0
  49. package/src/polymer/gesture/scheduler.cljs +122 -0
  50. package/src/polymer/gesture/snippet.cljs +198 -0
  51. package/src/polymer/gesture/state.cljs +273 -0
  52. package/src/polymer/lipsync/agency.cljs +593 -0
  53. package/src/polymer/lipsync/articulation/jaw.cljs +258 -0
  54. package/src/polymer/lipsync/articulation/snippet.cljs +605 -0
  55. package/src/polymer/lipsync/articulation/tongue.cljs +418 -0
  56. package/src/polymer/lipsync/articulation/visemes.cljs +429 -0
  57. package/src/polymer/lipsync/goap.cljs +132 -0
  58. package/src/polymer/lipsync/pronunciation/effector.cljs +51 -0
  59. package/src/polymer/lipsync/scheduler.cljs +302 -0
  60. package/src/polymer/lipsync/state.cljs +202 -0
  61. package/src/polymer/nlp/phonemes.cljs +164 -0
  62. package/src/polymer/prosodic/agency.cljs +196 -0
  63. package/src/polymer/prosodic/goap.cljs +122 -0
  64. package/src/polymer/prosodic/scheduler.cljs +99 -0
  65. package/src/polymer/prosodic/snippet.cljs +106 -0
  66. package/src/polymer/prosodic/state.cljs +139 -0
  67. package/src/polymer/runtime/embody.cljs +117 -0
  68. package/src/polymer/runtime/embody_wasm.cljs +177 -0
  69. package/src/polymer/runtime/rust_embody_host.cljs +645 -0
  70. package/src/polymer/society.cljs +239 -0
  71. package/src/polymer/stream.cljs +130 -0
  72. package/src/polymer/transcription/agency.cljs +69 -0
  73. package/src/polymer/transcription/domain.cljs +68 -0
  74. package/src/polymer/transcription/effector.cljs +611 -0
  75. package/src/polymer/transcription/planner.cljs +203 -0
  76. package/src/polymer/transcription/scheduler.cljs +225 -0
  77. package/src/polymer/transcription/service.cljs +209 -0
  78. package/src/polymer/transcription/state.cljs +239 -0
  79. package/src/polymer/tts/agency.cljs +503 -0
  80. package/src/polymer/tts/azure.cljs +290 -0
  81. package/src/polymer/tts/planner.cljs +178 -0
  82. package/src/polymer/tts/runtime.cljs +624 -0
  83. package/src/polymer/tts/scheduler.cljs +162 -0
  84. package/src/polymer/tts/state.cljs +191 -0
  85. package/src/polymer/worker.cljs +70 -0
@@ -0,0 +1,611 @@
1
+ (ns polymer.transcription.effector)
2
+
3
+ ;; This namespace is the only Transcription code allowed to touch browser
4
+ ;; recognition, microphone, AudioContext, or animation-frame APIs. The planner
5
+ ;; proposes work and the scheduler invokes this private effector.
6
+
7
+ (defn runtime-value
8
+ [runtime key]
9
+ (cond
10
+ (map? runtime) (get runtime key)
11
+ runtime (aget runtime (name key))
12
+ :else nil))
13
+
14
+ (defn recognition-constructor
15
+ []
16
+ (let [win (when (exists? js/window) js/window)]
17
+ (or (when win (aget win "SpeechRecognition"))
18
+ (when win (aget win "webkitSpeechRecognition")))))
19
+
20
+ (defn create-recognition
21
+ [runtime]
22
+ (if-let [factory (runtime-value runtime :createRecognition)]
23
+ (factory)
24
+ (when-let [ctor (recognition-constructor)]
25
+ (ctor.))))
26
+
27
+ (defn create-audio-context
28
+ [runtime]
29
+ (if-let [factory (runtime-value runtime :createAudioContext)]
30
+ (factory)
31
+ (let [win (when (exists? js/window) js/window)
32
+ ctor (or (when win (aget win "AudioContext"))
33
+ (when win (aget win "webkitAudioContext")))]
34
+ (when ctor
35
+ (ctor.)))))
36
+
37
+ (defn media-devices
38
+ []
39
+ (let [navigator (when (exists? js/navigator) js/navigator)]
40
+ (when navigator (.-mediaDevices navigator))))
41
+
42
+ (defn apply-config!
43
+ [recognition config]
44
+ (when recognition
45
+ (set! (.-lang recognition) (:lang config))
46
+ (set! (.-continuous recognition) (boolean (:continuous config)))
47
+ (set! (.-interimResults recognition) (boolean (:interimResults config)))
48
+ (set! (.-maxAlternatives recognition) (:maxAlternatives config))))
49
+
50
+ (defn result-commands
51
+ [event session-id provider-token interim-results?]
52
+ (let [results (.-results event)
53
+ start (or (.-resultIndex event) 0)
54
+ total (if results (.-length results) 0)]
55
+ (loop [index start
56
+ commands []]
57
+ (if (< index total)
58
+ (let [result (aget results index)
59
+ alternative (when result (aget result 0))
60
+ text (when alternative (.-transcript alternative))
61
+ confidence (when alternative (.-confidence alternative))
62
+ final? (boolean (when result (.-isFinal result)))]
63
+ (recur (inc index)
64
+ (cond-> commands
65
+ (and text (or final? interim-results?))
66
+ (conj {:type (if final? "providerFinal" "providerPartial")
67
+ :text text
68
+ :confidence (if (number? confidence) confidence 1)
69
+ :source "webSpeech"
70
+ :sessionId session-id
71
+ :providerToken provider-token}))))
72
+ commands))))
73
+
74
+ (defn clear-handler!
75
+ [recognition handler-name]
76
+ (when recognition
77
+ (aset recognition handler-name nil)))
78
+
79
+ (defn detach-handlers!
80
+ [recognition]
81
+ (doseq [handler-name ["onstart" "onresult" "onerror" "onend"]]
82
+ (clear-handler! recognition handler-name)))
83
+
84
+ (defn disconnect!
85
+ [node]
86
+ (when node
87
+ (try
88
+ (.disconnect node)
89
+ (catch :default _ nil))))
90
+
91
+ (defn stop-media-stream!
92
+ [stream]
93
+ (when stream
94
+ (doseq [track (array-seq (.getTracks stream))]
95
+ (try
96
+ (.stop track)
97
+ (catch :default _ nil)))))
98
+
99
+ (defn read-level
100
+ [analyser data]
101
+ (if (and analyser data)
102
+ (do
103
+ (.getByteTimeDomainData analyser data)
104
+ (let [length (.-length data)]
105
+ (loop [index 0
106
+ sum 0]
107
+ (if (< index length)
108
+ (let [sample (/ (- (aget data index) 128) 128)]
109
+ (recur (inc index) (+ sum (* sample sample))))
110
+ (js/Math.sqrt (/ sum (max 1 length)))))))
111
+ 0))
112
+
113
+ (defn live-track
114
+ [stream]
115
+ (when stream
116
+ (some #(when (= "live" (.-readyState %)) %)
117
+ (array-seq (.getAudioTracks stream)))))
118
+
119
+ (defn create-effector
120
+ [{:keys [dispatch get-state runtime]}]
121
+ (let [recognition (atom nil)
122
+ active-token (atom 0)
123
+ failed-tokens (atom #{})
124
+ retry-timer (atom nil)
125
+ disposed? (atom false)
126
+ mic-stream (atom nil)
127
+ mic-request (atom nil)
128
+ analysis-context (atom nil)
129
+ mic-analyser (atom nil)
130
+ mic-analyser-data (atom nil)
131
+ mic-source-node (atom nil)
132
+ reference-track (atom nil)
133
+ reference-analyser (atom nil)
134
+ reference-analyser-data (atom nil)
135
+ reference-source-node (atom nil)
136
+ reference-update-token (atom 0)
137
+ agent-speaking? (atom false)
138
+ interruption-frame (atom nil)
139
+ interruption-candidate-start (atom nil)
140
+ interruption-latched? (atom false)
141
+ last-debug-at (atom 0)]
142
+ (letfn [(current-config []
143
+ (:config (get-state)))
144
+
145
+ (current-token? [token]
146
+ (and (not @disposed?)
147
+ (= token @active-token)))
148
+
149
+ (cancel-retry! []
150
+ (when-let [timer @retry-timer]
151
+ (js/clearTimeout timer)
152
+ (reset! retry-timer nil)))
153
+
154
+ (invalidate-provider! []
155
+ (swap! active-token inc)
156
+ (reset! failed-tokens #{}))
157
+
158
+ (retire-current-provider! [instance token]
159
+ (when (and (= instance @recognition)
160
+ (current-token? token))
161
+ (swap! active-token inc)
162
+ (reset! recognition nil)
163
+ (detach-handlers! instance)
164
+ true))
165
+
166
+ (abort-retired-provider! [instance]
167
+ (try
168
+ (when-let [abort (aget instance "abort")]
169
+ (.call abort instance))
170
+ (catch :default _ nil)))
171
+
172
+ (request-frame! [callback]
173
+ (if-let [request-frame (runtime-value runtime :requestAnimationFrame)]
174
+ (request-frame callback)
175
+ (let [win (when (exists? js/window) js/window)]
176
+ (when (and win (.-requestAnimationFrame win))
177
+ (.requestAnimationFrame win callback)))))
178
+
179
+ (cancel-frame! [frame]
180
+ (if-let [cancel-frame (runtime-value runtime :cancelAnimationFrame)]
181
+ (cancel-frame frame)
182
+ (let [win (when (exists? js/window) js/window)]
183
+ (when (and win (.-cancelAnimationFrame win))
184
+ (.cancelAnimationFrame win frame)))))
185
+
186
+ (clock-ms []
187
+ (let [performance (when (exists? js/performance) js/performance)]
188
+ (if performance (.now performance) (.now js/Date))))
189
+
190
+ (stop-interruption-monitoring! []
191
+ (when-let [frame @interruption-frame]
192
+ (cancel-frame! frame)
193
+ (reset! interruption-frame nil))
194
+ (reset! interruption-candidate-start nil))
195
+
196
+ (schedule-interruption-frame! [tick]
197
+ (when-let [frame (request-frame! tick)]
198
+ (reset! interruption-frame frame)))
199
+
200
+ (start-interruption-monitoring! []
201
+ (stop-interruption-monitoring!)
202
+ (when (and @agent-speaking?
203
+ (:interruptDetectionEnabled (current-config)))
204
+ (letfn [(tick []
205
+ (reset! interruption-frame nil)
206
+ (if (or @disposed?
207
+ (not @agent-speaking?)
208
+ (not (:interruptDetectionEnabled
209
+ (current-config))))
210
+ (stop-interruption-monitoring!)
211
+ (let [config (current-config)
212
+ live-reference? (and @reference-track
213
+ (= "live"
214
+ (.-readyState
215
+ @reference-track))
216
+ @reference-analyser)]
217
+ (if (and (:requireAgentReferenceForInterruption config)
218
+ (not live-reference?))
219
+ (do
220
+ (reset! interruption-candidate-start nil)
221
+ (schedule-interruption-frame! tick))
222
+ (let [microphone-level
223
+ (read-level @mic-analyser @mic-analyser-data)
224
+ reference-level
225
+ (if live-reference?
226
+ (read-level @reference-analyser
227
+ @reference-analyser-data)
228
+ 0)
229
+ required-level
230
+ (js/Math.max
231
+ (:interruptionVolumeThreshold config)
232
+ (+ (* reference-level
233
+ (:interruptionReferenceScale config))
234
+ (:interruptionReferenceOffset config)))
235
+ interrupt? (>= microphone-level
236
+ required-level)
237
+ now (clock-ms)]
238
+ (when (and (:interruptionDebugLogging config)
239
+ (>= (- now @last-debug-at) 500))
240
+ (reset! last-debug-at now)
241
+ (js/console.debug
242
+ "[Transcription] Interruption levels"
243
+ #js {:microphoneLevel microphone-level
244
+ :referenceLevel reference-level
245
+ :requiredLevel required-level
246
+ :shouldInterrupt interrupt?
247
+ :hasAgentReference live-reference?}))
248
+ (if (and interrupt?
249
+ (not @interruption-latched?))
250
+ (if-let [candidate-start
251
+ @interruption-candidate-start]
252
+ (when (>= (- now candidate-start)
253
+ (:interruptionHoldMs config))
254
+ (reset! interruption-latched? true)
255
+ (dispatch
256
+ {:type "providerAudioInterruption"
257
+ :timestamp (.now js/Date)
258
+ :microphoneLevel microphone-level
259
+ :referenceLevel reference-level
260
+ :requiredLevel required-level}))
261
+ (reset! interruption-candidate-start now))
262
+ (when-not interrupt?
263
+ (reset! interruption-candidate-start nil)))
264
+ (schedule-interruption-frame! tick))))))]
265
+ (schedule-interruption-frame! tick))))
266
+
267
+ (ensure-analysis-context! []
268
+ (if @disposed?
269
+ (.resolve js/Promise nil)
270
+ (try
271
+ (when (or (nil? @analysis-context)
272
+ (= "closed" (.-state @analysis-context)))
273
+ (reset! analysis-context (create-audio-context runtime)))
274
+ (let [context @analysis-context]
275
+ (if (and context (= "suspended" (.-state context)))
276
+ (-> (.resume context)
277
+ (.then (fn [_] context))
278
+ (.catch (fn [_] context)))
279
+ (.resolve js/Promise context)))
280
+ (catch :default error
281
+ (.reject js/Promise error)))))
282
+
283
+ (ensure-microphone-analyser! []
284
+ (-> (ensure-analysis-context!)
285
+ (.then
286
+ (fn [context]
287
+ (when (and (not @disposed?) context @mic-stream)
288
+ (let [track (live-track @mic-stream)
289
+ old-source @mic-source-node
290
+ old-track (when old-source
291
+ (live-track
292
+ (aget old-source "mediaStream")))]
293
+ (when (and track (not= track old-track))
294
+ (disconnect! old-source)
295
+ (disconnect! @mic-analyser)
296
+ (let [source (.createMediaStreamSource
297
+ context @mic-stream)
298
+ analyser (.createAnalyser context)]
299
+ (set! (.-fftSize analyser) 2048)
300
+ (set! (.-smoothingTimeConstant analyser) 0.65)
301
+ (.connect source analyser)
302
+ (reset! mic-source-node source)
303
+ (reset! mic-analyser analyser)
304
+ (reset! mic-analyser-data
305
+ (js/Uint8Array.
306
+ (.-fftSize analyser)))))))))))
307
+
308
+ (request-microphone! []
309
+ (if-let [get-user-media (runtime-value runtime :getUserMedia)]
310
+ (.resolve js/Promise (get-user-media))
311
+ (if-let [media (media-devices)]
312
+ (let [supported (if (.-getSupportedConstraints media)
313
+ (.getSupportedConstraints media)
314
+ #js {})
315
+ constraints
316
+ (clj->js
317
+ (cond-> {:echoCancellation true
318
+ :noiseSuppression true
319
+ :autoGainControl true}
320
+ (boolean (aget supported "voiceIsolation"))
321
+ (assoc :voiceIsolation true)))]
322
+ (-> (.getUserMedia media #js {:audio constraints})
323
+ (.catch (fn [_]
324
+ (.getUserMedia media #js {:audio true})))))
325
+ ;; Worker and Node tests have no mediaDevices. Recognition can
326
+ ;; still start through an injected provider.
327
+ (.resolve js/Promise nil))))
328
+
329
+ (ensure-microphone-stream! []
330
+ (cond
331
+ @disposed?
332
+ (.resolve js/Promise nil)
333
+
334
+ (live-track @mic-stream)
335
+ (-> (ensure-microphone-analyser!)
336
+ (.then (fn [_] @mic-stream)))
337
+
338
+ @mic-request
339
+ (:promise @mic-request)
340
+
341
+ :else
342
+ (let [token (js-obj)
343
+ requested
344
+ (-> (request-microphone!)
345
+ (.then
346
+ (fn [stream]
347
+ (if @disposed?
348
+ (do
349
+ (stop-media-stream! stream)
350
+ nil)
351
+ (do
352
+ (reset! mic-stream stream)
353
+ (-> (ensure-microphone-analyser!)
354
+ (.then
355
+ (fn [_]
356
+ (if @disposed?
357
+ (do
358
+ (when (= stream @mic-stream)
359
+ (reset! mic-stream nil))
360
+ (stop-media-stream! stream)
361
+ nil)
362
+ stream)))))))))
363
+ settled
364
+ (-> requested
365
+ (.then
366
+ (fn [stream]
367
+ (when (identical? token (:token @mic-request))
368
+ (reset! mic-request nil))
369
+ stream))
370
+ (.catch
371
+ (fn [error]
372
+ (when (identical? token (:token @mic-request))
373
+ (reset! mic-request nil))
374
+ (throw error))))]
375
+ (reset! mic-request {:token token :promise settled})
376
+ settled)))
377
+
378
+ (replace-reference-analyser! [track]
379
+ (let [token (swap! reference-update-token inc)]
380
+ (reset! reference-track track)
381
+ (disconnect! @reference-source-node)
382
+ (disconnect! @reference-analyser)
383
+ (reset! reference-source-node nil)
384
+ (reset! reference-analyser nil)
385
+ (reset! reference-analyser-data nil)
386
+ (when (and track (= "live" (.-readyState track)))
387
+ (-> (ensure-analysis-context!)
388
+ (.then
389
+ (fn [context]
390
+ (when (and context
391
+ (not @disposed?)
392
+ (= token @reference-update-token)
393
+ (= track @reference-track)
394
+ (= "live" (.-readyState track)))
395
+ (let [stream-constructor
396
+ (or (runtime-value runtime :createMediaStream)
397
+ (when (exists? js/MediaStream)
398
+ (fn [tracks]
399
+ (js/MediaStream. tracks))))
400
+ stream (when stream-constructor
401
+ (stream-constructor #js [track]))]
402
+ (when stream
403
+ (let [source (.createMediaStreamSource
404
+ context stream)
405
+ analyser (.createAnalyser context)]
406
+ (set! (.-fftSize analyser) 2048)
407
+ (set! (.-smoothingTimeConstant analyser) 0.65)
408
+ (.connect source analyser)
409
+ (if (and (= token @reference-update-token)
410
+ (= track @reference-track)
411
+ (= "live" (.-readyState track)))
412
+ (do
413
+ (reset! reference-source-node source)
414
+ (reset! reference-analyser analyser)
415
+ (reset! reference-analyser-data
416
+ (js/Uint8Array.
417
+ (.-fftSize analyser))))
418
+ (do
419
+ (disconnect! source)
420
+ (disconnect! analyser)))))))))
421
+ (.catch (fn [_] nil))))
422
+ (when @agent-speaking?
423
+ (start-interruption-monitoring!))))
424
+
425
+ (sync-agent-speaking! [speaking?]
426
+ (reset! agent-speaking? (boolean speaking?))
427
+ (reset! interruption-latched? false)
428
+ (reset! interruption-candidate-start nil)
429
+ (if @agent-speaking?
430
+ (-> (ensure-microphone-analyser!)
431
+ (.then (fn [_]
432
+ (start-interruption-monitoring!)))
433
+ (.catch (fn [_] nil)))
434
+ (stop-interruption-monitoring!)))
435
+
436
+ (stop-provider! [method-name]
437
+ (cancel-retry!)
438
+ (stop-interruption-monitoring!)
439
+ (let [instance @recognition]
440
+ (invalidate-provider!)
441
+ (reset! recognition nil)
442
+ (when instance
443
+ (detach-handlers! instance)
444
+ (try
445
+ (when-let [method (aget instance method-name)]
446
+ (.call method instance))
447
+ (catch :default _ nil)))
448
+ (.resolve js/Promise nil)))
449
+
450
+ (fail-provider! [instance token session-id message]
451
+ (when (and (current-token? token)
452
+ (not (contains? @failed-tokens token)))
453
+ (swap! failed-tokens conj token)
454
+ (when (retire-current-provider! instance token)
455
+ (abort-retired-provider! instance)
456
+ (dispatch {:type "providerError"
457
+ :message message
458
+ :sessionId session-id
459
+ :providerToken token}))))
460
+
461
+ (start-recognition-instance! [instance track]
462
+ (if track
463
+ (try
464
+ (.start instance track)
465
+ (catch :default _
466
+ (.start instance)))
467
+ (.start instance)))
468
+
469
+ (start-provider! [session-id config]
470
+ (cancel-retry!)
471
+ (if @disposed?
472
+ (.resolve js/Promise nil)
473
+ (if-let [instance (create-recognition runtime)]
474
+ (let [token (swap! active-token inc)
475
+ begin! (fn [stream]
476
+ (when (current-token? token)
477
+ (try
478
+ (start-recognition-instance!
479
+ instance (live-track stream))
480
+ (catch :default error
481
+ (fail-provider!
482
+ instance token session-id
483
+ (or (.-message error)
484
+ "speech-recognition-start-error"))))))]
485
+ (reset! recognition instance)
486
+ (apply-config! instance config)
487
+ (set! (.-onstart instance)
488
+ (fn []
489
+ (when (current-token? token)
490
+ (dispatch {:type "providerStarted"
491
+ :sessionId session-id
492
+ :providerToken token})
493
+ (when @agent-speaking?
494
+ (start-interruption-monitoring!)))))
495
+ (set! (.-onresult instance)
496
+ (fn [event]
497
+ (when (current-token? token)
498
+ (doseq [command
499
+ (result-commands
500
+ event
501
+ session-id
502
+ token
503
+ (get-in (get-state)
504
+ [:config :interimResults]))]
505
+ (dispatch command)))))
506
+ (set! (.-onerror instance)
507
+ (fn [event]
508
+ (fail-provider!
509
+ instance
510
+ token
511
+ session-id
512
+ (or (.-error event)
513
+ "speech-recognition-error"))))
514
+ (set! (.-onend instance)
515
+ (fn []
516
+ (when (retire-current-provider! instance token)
517
+ (stop-interruption-monitoring!)
518
+ (dispatch {:type "providerEnded"
519
+ :sessionId session-id
520
+ :providerToken token}))))
521
+ (if (or (runtime-value runtime :getUserMedia)
522
+ (media-devices))
523
+ (-> (ensure-microphone-stream!)
524
+ (.then begin!)
525
+ (.catch
526
+ (fn [error]
527
+ (fail-provider!
528
+ instance token session-id
529
+ (or (.-message error)
530
+ "microphone-start-error"))))
531
+ (.then (fn [_] nil)))
532
+ (do
533
+ (begin! nil)
534
+ (.resolve js/Promise nil))))
535
+ (do
536
+ (dispatch {:type "providerError"
537
+ :message "Web Speech recognition is not available"
538
+ :sessionId session-id})
539
+ (.resolve js/Promise nil)))))
540
+
541
+ (retry-provider! [session-id delay-ms]
542
+ (cancel-retry!)
543
+ (when @recognition
544
+ (stop-provider! "abort"))
545
+ (reset! retry-timer
546
+ (js/setTimeout
547
+ (fn []
548
+ (reset! retry-timer nil)
549
+ (let [current-state (get-state)]
550
+ (when (and (not @disposed?)
551
+ (:active current-state)
552
+ (= session-id (:sessionId current-state)))
553
+ (-> (start-provider!
554
+ session-id (:config current-state))
555
+ (.catch (fn [_] nil))))))
556
+ delay-ms))
557
+ nil)
558
+
559
+ (dispose-browser-resources! []
560
+ (stop-interruption-monitoring!)
561
+ (swap! reference-update-token inc)
562
+ (reset! reference-track nil)
563
+ (stop-media-stream! @mic-stream)
564
+ (reset! mic-stream nil)
565
+ (disconnect! @mic-source-node)
566
+ (disconnect! @mic-analyser)
567
+ (disconnect! @reference-source-node)
568
+ (disconnect! @reference-analyser)
569
+ (reset! mic-source-node nil)
570
+ (reset! mic-analyser nil)
571
+ (reset! mic-analyser-data nil)
572
+ (reset! reference-source-node nil)
573
+ (reset! reference-analyser nil)
574
+ (reset! reference-analyser-data nil)
575
+ (when-let [context @analysis-context]
576
+ (try (.close context) (catch :default _ nil)))
577
+ (reset! analysis-context nil))]
578
+ {:start
579
+ (fn [session-id config]
580
+ (start-provider! session-id config))
581
+
582
+ :stop
583
+ (fn []
584
+ (stop-provider! "stop"))
585
+
586
+ :abort
587
+ (fn []
588
+ (stop-provider! "abort"))
589
+
590
+ :retry
591
+ (fn [session-id delay-ms]
592
+ (retry-provider! session-id delay-ms))
593
+
594
+ :configure
595
+ (fn [config]
596
+ (apply-config! @recognition config)
597
+ (if (and @agent-speaking?
598
+ (:interruptDetectionEnabled config))
599
+ (start-interruption-monitoring!)
600
+ (stop-interruption-monitoring!))
601
+ nil)
602
+
603
+ :set-reference-track replace-reference-analyser!
604
+ :sync-agent-speaking sync-agent-speaking!
605
+
606
+ :dispose
607
+ (fn []
608
+ (when-not @disposed?
609
+ (reset! disposed? true)
610
+ (stop-provider! "abort")
611
+ (dispose-browser-resources!)))})))