@adminforth/agent 1.40.4 → 1.41.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.
- package/build.log +2 -2
- package/custom/composables/useAgentAudio.ts +1 -1
- package/custom/package.json +1 -0
- package/custom/pnpm-lock.yaml +131 -0
- package/custom/speech_recognition_frontend/MicrophoneButon.vue +4 -8
- package/custom/speech_recognition_frontend/voiceActivityDetection.ts +48 -137
- package/dist/custom/composables/useAgentAudio.ts +1 -1
- package/dist/custom/package.json +1 -0
- package/dist/custom/pnpm-lock.yaml +131 -0
- package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +4 -8
- package/dist/custom/speech_recognition_frontend/voiceActivityDetection.ts +48 -137
- package/dist/index.js +44 -14
- package/index.ts +46 -7
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -58,5 +58,5 @@ custom/speech_recognition_frontend/voiceActivityDetection.ts
|
|
|
58
58
|
custom/speech_recognition_frontend/types/
|
|
59
59
|
custom/speech_recognition_frontend/types/voice-activity-detection.d.ts
|
|
60
60
|
|
|
61
|
-
sent 1,
|
|
62
|
-
total size is 1,
|
|
61
|
+
sent 1,660,143 bytes received 856 bytes 3,321,998.00 bytes/sec
|
|
62
|
+
total size is 1,656,231 speedup is 1.00
|
|
@@ -67,7 +67,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
|
|
|
67
67
|
async function sendAudioToServerAndHandleResponse(blob: Blob) {
|
|
68
68
|
currentAbortController = new AbortController();
|
|
69
69
|
const formData = new FormData();
|
|
70
|
-
formData.append('file', blob, 'user_prompt.
|
|
70
|
+
formData.append('file', blob, 'user_prompt.wav');
|
|
71
71
|
formData.append('sessionId', agentStore.activeSessionId);
|
|
72
72
|
formData.append('mode', agentStore.activeModeName ?? '');
|
|
73
73
|
formData.append('timeZone', Intl.DateTimeFormat().resolvedOptions().timeZone);
|
package/custom/package.json
CHANGED
package/custom/pnpm-lock.yaml
CHANGED
|
@@ -17,6 +17,9 @@ importers:
|
|
|
17
17
|
'@incremark/vue':
|
|
18
18
|
specifier: ^1.0.2
|
|
19
19
|
version: 1.0.2(katex@0.16.45)(vue@3.5.32)
|
|
20
|
+
'@ricky0123/vad-web':
|
|
21
|
+
specifier: ^0.0.30
|
|
22
|
+
version: 0.0.30
|
|
20
23
|
'@shikijs/langs':
|
|
21
24
|
specifier: ^4.0.2
|
|
22
25
|
version: 4.0.2
|
|
@@ -139,6 +142,39 @@ packages:
|
|
|
139
142
|
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
|
140
143
|
engines: {node: '>=8.0.0'}
|
|
141
144
|
|
|
145
|
+
'@protobufjs/aspromise@1.1.2':
|
|
146
|
+
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
|
|
147
|
+
|
|
148
|
+
'@protobufjs/base64@1.1.2':
|
|
149
|
+
resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
|
|
150
|
+
|
|
151
|
+
'@protobufjs/codegen@2.0.5':
|
|
152
|
+
resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==}
|
|
153
|
+
|
|
154
|
+
'@protobufjs/eventemitter@1.1.0':
|
|
155
|
+
resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
|
|
156
|
+
|
|
157
|
+
'@protobufjs/fetch@1.1.0':
|
|
158
|
+
resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
|
|
159
|
+
|
|
160
|
+
'@protobufjs/float@1.0.2':
|
|
161
|
+
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
|
|
162
|
+
|
|
163
|
+
'@protobufjs/inquire@1.1.1':
|
|
164
|
+
resolution: {integrity: sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==}
|
|
165
|
+
|
|
166
|
+
'@protobufjs/path@1.1.2':
|
|
167
|
+
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
|
|
168
|
+
|
|
169
|
+
'@protobufjs/pool@1.1.0':
|
|
170
|
+
resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
|
|
171
|
+
|
|
172
|
+
'@protobufjs/utf8@1.1.1':
|
|
173
|
+
resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==}
|
|
174
|
+
|
|
175
|
+
'@ricky0123/vad-web@0.0.30':
|
|
176
|
+
resolution: {integrity: sha512-cJyYrh4YeeUBJcbR9Bic/bFDyB9qBkAepvpuWM3vLxnAi7bC3VHzf51UeNdT+OtY4D7MLAgV8iJMc4z41ZnaWg==}
|
|
177
|
+
|
|
142
178
|
'@shikijs/core@3.23.0':
|
|
143
179
|
resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==}
|
|
144
180
|
|
|
@@ -218,6 +254,9 @@ packages:
|
|
|
218
254
|
'@types/ms@2.1.0':
|
|
219
255
|
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
|
220
256
|
|
|
257
|
+
'@types/node@25.6.0':
|
|
258
|
+
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
|
259
|
+
|
|
221
260
|
'@types/trusted-types@2.0.7':
|
|
222
261
|
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
|
223
262
|
|
|
@@ -472,6 +511,9 @@ packages:
|
|
|
472
511
|
fast-json-patch@3.1.1:
|
|
473
512
|
resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
|
|
474
513
|
|
|
514
|
+
flatbuffers@25.9.23:
|
|
515
|
+
resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==}
|
|
516
|
+
|
|
475
517
|
get-caller-file@2.0.5:
|
|
476
518
|
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
|
477
519
|
engines: {node: 6.* || 8.* || >= 10.*}
|
|
@@ -480,6 +522,9 @@ packages:
|
|
|
480
522
|
resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
|
|
481
523
|
engines: {node: '>=18'}
|
|
482
524
|
|
|
525
|
+
guid-typescript@1.0.9:
|
|
526
|
+
resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==}
|
|
527
|
+
|
|
483
528
|
hast-util-to-html@9.0.5:
|
|
484
529
|
resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
|
|
485
530
|
|
|
@@ -525,6 +570,9 @@ packages:
|
|
|
525
570
|
lodash-es@4.18.1:
|
|
526
571
|
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
|
527
572
|
|
|
573
|
+
long@5.3.2:
|
|
574
|
+
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
|
|
575
|
+
|
|
528
576
|
longest-streak@3.1.0:
|
|
529
577
|
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
|
530
578
|
|
|
@@ -690,12 +738,21 @@ packages:
|
|
|
690
738
|
oniguruma-to-es@4.3.5:
|
|
691
739
|
resolution: {integrity: sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==}
|
|
692
740
|
|
|
741
|
+
onnxruntime-common@1.25.1:
|
|
742
|
+
resolution: {integrity: sha512-kKvYQFdos4LWJqhZ+nmKu3NT8NXzw8I5x9fNUKe1rNKcPfNKnYXUtW7JBpcKFsvLtrJashRgVYSbFap4cHxvNg==}
|
|
743
|
+
|
|
744
|
+
onnxruntime-web@1.25.1:
|
|
745
|
+
resolution: {integrity: sha512-mgs61sJ9m3hLa5jGRr9Pen3kkG00vlxmrcRL6FufYpSWBZKaklo0sotQCq2fLjgDVLnW57jrDcLqzYJNKeZskQ==}
|
|
746
|
+
|
|
693
747
|
parse-entities@4.0.2:
|
|
694
748
|
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
|
695
749
|
|
|
696
750
|
picocolors@1.1.1:
|
|
697
751
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
|
698
752
|
|
|
753
|
+
platform@1.3.6:
|
|
754
|
+
resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
|
|
755
|
+
|
|
699
756
|
postcss@8.5.10:
|
|
700
757
|
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
|
|
701
758
|
engines: {node: ^10 || ^12 || >=14}
|
|
@@ -703,6 +760,10 @@ packages:
|
|
|
703
760
|
property-information@7.1.0:
|
|
704
761
|
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
|
|
705
762
|
|
|
763
|
+
protobufjs@7.5.6:
|
|
764
|
+
resolution: {integrity: sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==}
|
|
765
|
+
engines: {node: '>=12.0.0'}
|
|
766
|
+
|
|
706
767
|
regex-recursion@6.0.2:
|
|
707
768
|
resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
|
|
708
769
|
|
|
@@ -775,6 +836,9 @@ packages:
|
|
|
775
836
|
tslib@2.8.1:
|
|
776
837
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
|
777
838
|
|
|
839
|
+
undici-types@7.19.2:
|
|
840
|
+
resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==}
|
|
841
|
+
|
|
778
842
|
unist-util-is@6.0.1:
|
|
779
843
|
resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
|
|
780
844
|
|
|
@@ -1063,6 +1127,33 @@ snapshots:
|
|
|
1063
1127
|
|
|
1064
1128
|
'@opentelemetry/api@1.9.0': {}
|
|
1065
1129
|
|
|
1130
|
+
'@protobufjs/aspromise@1.1.2': {}
|
|
1131
|
+
|
|
1132
|
+
'@protobufjs/base64@1.1.2': {}
|
|
1133
|
+
|
|
1134
|
+
'@protobufjs/codegen@2.0.5': {}
|
|
1135
|
+
|
|
1136
|
+
'@protobufjs/eventemitter@1.1.0': {}
|
|
1137
|
+
|
|
1138
|
+
'@protobufjs/fetch@1.1.0':
|
|
1139
|
+
dependencies:
|
|
1140
|
+
'@protobufjs/aspromise': 1.1.2
|
|
1141
|
+
'@protobufjs/inquire': 1.1.1
|
|
1142
|
+
|
|
1143
|
+
'@protobufjs/float@1.0.2': {}
|
|
1144
|
+
|
|
1145
|
+
'@protobufjs/inquire@1.1.1': {}
|
|
1146
|
+
|
|
1147
|
+
'@protobufjs/path@1.1.2': {}
|
|
1148
|
+
|
|
1149
|
+
'@protobufjs/pool@1.1.0': {}
|
|
1150
|
+
|
|
1151
|
+
'@protobufjs/utf8@1.1.1': {}
|
|
1152
|
+
|
|
1153
|
+
'@ricky0123/vad-web@0.0.30':
|
|
1154
|
+
dependencies:
|
|
1155
|
+
onnxruntime-web: 1.25.1
|
|
1156
|
+
|
|
1066
1157
|
'@shikijs/core@3.23.0':
|
|
1067
1158
|
dependencies:
|
|
1068
1159
|
'@shikijs/types': 3.23.0
|
|
@@ -1162,6 +1253,10 @@ snapshots:
|
|
|
1162
1253
|
|
|
1163
1254
|
'@types/ms@2.1.0': {}
|
|
1164
1255
|
|
|
1256
|
+
'@types/node@25.6.0':
|
|
1257
|
+
dependencies:
|
|
1258
|
+
undici-types: 7.19.2
|
|
1259
|
+
|
|
1165
1260
|
'@types/trusted-types@2.0.7':
|
|
1166
1261
|
optional: true
|
|
1167
1262
|
|
|
@@ -1404,10 +1499,14 @@ snapshots:
|
|
|
1404
1499
|
|
|
1405
1500
|
fast-json-patch@3.1.1: {}
|
|
1406
1501
|
|
|
1502
|
+
flatbuffers@25.9.23: {}
|
|
1503
|
+
|
|
1407
1504
|
get-caller-file@2.0.5: {}
|
|
1408
1505
|
|
|
1409
1506
|
get-east-asian-width@1.5.0: {}
|
|
1410
1507
|
|
|
1508
|
+
guid-typescript@1.0.9: {}
|
|
1509
|
+
|
|
1411
1510
|
hast-util-to-html@9.0.5:
|
|
1412
1511
|
dependencies:
|
|
1413
1512
|
'@types/hast': 3.0.4
|
|
@@ -1457,6 +1556,8 @@ snapshots:
|
|
|
1457
1556
|
|
|
1458
1557
|
lodash-es@4.18.1: {}
|
|
1459
1558
|
|
|
1559
|
+
long@5.3.2: {}
|
|
1560
|
+
|
|
1460
1561
|
longest-streak@3.1.0: {}
|
|
1461
1562
|
|
|
1462
1563
|
magic-string@0.30.21:
|
|
@@ -1832,6 +1933,17 @@ snapshots:
|
|
|
1832
1933
|
regex: 6.1.0
|
|
1833
1934
|
regex-recursion: 6.0.2
|
|
1834
1935
|
|
|
1936
|
+
onnxruntime-common@1.25.1: {}
|
|
1937
|
+
|
|
1938
|
+
onnxruntime-web@1.25.1:
|
|
1939
|
+
dependencies:
|
|
1940
|
+
flatbuffers: 25.9.23
|
|
1941
|
+
guid-typescript: 1.0.9
|
|
1942
|
+
long: 5.3.2
|
|
1943
|
+
onnxruntime-common: 1.25.1
|
|
1944
|
+
platform: 1.3.6
|
|
1945
|
+
protobufjs: 7.5.6
|
|
1946
|
+
|
|
1835
1947
|
parse-entities@4.0.2:
|
|
1836
1948
|
dependencies:
|
|
1837
1949
|
'@types/unist': 2.0.11
|
|
@@ -1844,6 +1956,8 @@ snapshots:
|
|
|
1844
1956
|
|
|
1845
1957
|
picocolors@1.1.1: {}
|
|
1846
1958
|
|
|
1959
|
+
platform@1.3.6: {}
|
|
1960
|
+
|
|
1847
1961
|
postcss@8.5.10:
|
|
1848
1962
|
dependencies:
|
|
1849
1963
|
nanoid: 3.3.11
|
|
@@ -1852,6 +1966,21 @@ snapshots:
|
|
|
1852
1966
|
|
|
1853
1967
|
property-information@7.1.0: {}
|
|
1854
1968
|
|
|
1969
|
+
protobufjs@7.5.6:
|
|
1970
|
+
dependencies:
|
|
1971
|
+
'@protobufjs/aspromise': 1.1.2
|
|
1972
|
+
'@protobufjs/base64': 1.1.2
|
|
1973
|
+
'@protobufjs/codegen': 2.0.5
|
|
1974
|
+
'@protobufjs/eventemitter': 1.1.0
|
|
1975
|
+
'@protobufjs/fetch': 1.1.0
|
|
1976
|
+
'@protobufjs/float': 1.0.2
|
|
1977
|
+
'@protobufjs/inquire': 1.1.1
|
|
1978
|
+
'@protobufjs/path': 1.1.2
|
|
1979
|
+
'@protobufjs/pool': 1.1.0
|
|
1980
|
+
'@protobufjs/utf8': 1.1.1
|
|
1981
|
+
'@types/node': 25.6.0
|
|
1982
|
+
long: 5.3.2
|
|
1983
|
+
|
|
1855
1984
|
regex-recursion@6.0.2:
|
|
1856
1985
|
dependencies:
|
|
1857
1986
|
regex-utilities: 2.3.0
|
|
@@ -1925,6 +2054,8 @@ snapshots:
|
|
|
1925
2054
|
|
|
1926
2055
|
tslib@2.8.1: {}
|
|
1927
2056
|
|
|
2057
|
+
undici-types@7.19.2: {}
|
|
2058
|
+
|
|
1928
2059
|
unist-util-is@6.0.1:
|
|
1929
2060
|
dependencies:
|
|
1930
2061
|
'@types/unist': 3.0.3
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<script setup lang="ts">
|
|
29
29
|
import { computed, onMounted, onBeforeUnmount, ref, watch } from 'vue';
|
|
30
30
|
import debounce from 'lodash.debounce';
|
|
31
|
-
import { requestMicAndStartVAD, stopUserMedia,
|
|
31
|
+
import { requestMicAndStartVAD, stopUserMedia, getRecord } from './voiceActivityDetection';
|
|
32
32
|
import { Spinner } from '@/afcl'
|
|
33
33
|
import { storeToRefs } from 'pinia';
|
|
34
34
|
import { useAgentStore } from '../composables/useAgentStore';
|
|
@@ -41,7 +41,7 @@ const { sendAudioToServerAndHandleResponse } = agentAudio;
|
|
|
41
41
|
const { stopGenerationAndAudio } = agentAudio;
|
|
42
42
|
const { stopCurrentAudioPlayback } = agentAudio;
|
|
43
43
|
const { agentAudioMode } = storeToRefs(agentAudio);
|
|
44
|
-
const microphoneButtonMode = ref<'off' | '
|
|
44
|
+
const microphoneButtonMode = ref<'off' | 'listen' | 'transcribing' | 'generating'>('off');
|
|
45
45
|
const showAudioWavesAnimation = ref(false);
|
|
46
46
|
const audioAmplitude = ref(0);
|
|
47
47
|
const hideAnimationDebounced = debounce(() => {
|
|
@@ -93,14 +93,9 @@ function toggleChatMode() {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
async function onStartRecording() {
|
|
96
|
-
microphoneButtonMode.value = 'calibrating';
|
|
97
96
|
await requestMicAndStartVAD(saidSomething, stopRecording, onAnySound);
|
|
98
|
-
setTimeout(() => {
|
|
99
|
-
if (isAudioChatMode.value) {
|
|
100
97
|
microphoneButtonMode.value = 'listen';
|
|
101
98
|
agentAudio.playBeep(1000);
|
|
102
|
-
}
|
|
103
|
-
}, CALIBRATION_DURATION);
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
function onStopRecording() {
|
|
@@ -145,8 +140,9 @@ function onAnySound(amplitude: number) {
|
|
|
145
140
|
|
|
146
141
|
async function sendRecordForTranscription() {
|
|
147
142
|
showAudioWavesAnimation.value = false;
|
|
148
|
-
const recordBlob = await
|
|
143
|
+
const recordBlob = await getRecord();
|
|
149
144
|
if (recordBlob) {
|
|
145
|
+
console.log('Audio recorded, sending to server for transcription. Audio Blob size:', recordBlob.size, recordBlob.type);
|
|
150
146
|
onStopRecording();
|
|
151
147
|
await sendAudioToServerAndHandleResponse(recordBlob);
|
|
152
148
|
if (agentStore.isAudioChatMode) {
|
|
@@ -1,151 +1,62 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
let
|
|
4
|
-
let
|
|
5
|
-
let
|
|
6
|
-
let
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { MicVAD, utils } from "@ricky0123/vad-web"
|
|
2
|
+
|
|
3
|
+
let VADInstance: MicVAD | null = null;
|
|
4
|
+
let recordedAudioChunks: Float32Array[] = [];
|
|
5
|
+
let onVoiceStopCallback: () => void = () => {};
|
|
6
|
+
let onVoiceStartCallback: () => void = () => {};
|
|
7
|
+
let onUpdateCallback: (amplitude: number) => void = () => {};
|
|
8
|
+
|
|
9
|
+
async function createVADInstance(){
|
|
10
|
+
VADInstance = await MicVAD.new({
|
|
11
|
+
onFrameProcessed: ({ isSpeech }) => {
|
|
12
|
+
onUpdateCallback(isSpeech);
|
|
13
|
+
},
|
|
14
|
+
onSpeechEnd: (audio) => {
|
|
15
|
+
recordedAudioChunks.push(audio);
|
|
16
|
+
onVoiceStopCallback();
|
|
17
|
+
},
|
|
18
|
+
onSpeechStart: () => {
|
|
19
|
+
onVoiceStartCallback();
|
|
20
|
+
},
|
|
21
|
+
onnxWASMBasePath: "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.22.0/dist/",
|
|
22
|
+
baseAssetPath: "https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.29/dist/",
|
|
23
|
+
})
|
|
24
|
+
}
|
|
11
25
|
|
|
12
26
|
export async function requestMicAndStartVAD(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
onVoiceStop: () => void,
|
|
28
|
+
onVoiceStart: () => void,
|
|
29
|
+
onUpdate: (amplitude: number) => void
|
|
16
30
|
) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
navigator.mediaDevices
|
|
22
|
-
.getUserMedia({ audio: true })
|
|
23
|
-
.then((stream) => {
|
|
24
|
-
currentStream = stream;
|
|
25
|
-
startRecording(stream);
|
|
26
|
-
resolve();
|
|
27
|
-
startUserMedia(audioContext as AudioContext, stream, onVoiceStartCallback, onVoiceStopCallback, onUpdateCallback);
|
|
28
|
-
})
|
|
29
|
-
.catch((error) => {
|
|
30
|
-
handleMicConnectError();
|
|
31
|
-
reject(error);
|
|
32
|
-
});
|
|
33
|
-
} catch (e) {
|
|
34
|
-
handleUserMediaError();
|
|
35
|
-
reject(e);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function handleUserMediaError() {
|
|
41
|
-
console.error('Mic input is not supported by the browser.');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function handleMicConnectError() {
|
|
45
|
-
console.error('Could not connect microphone. Possible rejected by the user or is blocked by the browser.');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function stopUserMedia() {
|
|
49
|
-
wasVoiceStarted = false;
|
|
50
|
-
if (vadInstance && vadInstance.destroy) {
|
|
51
|
-
vadInstance.destroy();
|
|
52
|
-
vadInstance = null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (currentStream) {
|
|
56
|
-
currentStream.getTracks().forEach(track => track.stop());
|
|
57
|
-
currentStream = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (audioContext) {
|
|
61
|
-
audioContext.close();
|
|
62
|
-
audioContext = null;
|
|
63
|
-
}
|
|
31
|
+
onVoiceStopCallback = onVoiceStop;
|
|
32
|
+
onVoiceStartCallback = onVoiceStart;
|
|
33
|
+
onUpdateCallback = onUpdate;
|
|
64
34
|
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
mediaRecorder = null;
|
|
35
|
+
if (!VADInstance) {
|
|
36
|
+
await createVADInstance();
|
|
68
37
|
}
|
|
69
|
-
|
|
38
|
+
VADInstance?.start();
|
|
70
39
|
}
|
|
71
40
|
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
mediaRecorder = new MediaRecorder(stream);
|
|
75
|
-
mediaRecorder.ondataavailable = (event: BlobEvent) => {
|
|
76
|
-
if (event.data.size > 0) {
|
|
77
|
-
recordedChunks.push(event.data);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
mediaRecorder.start();
|
|
41
|
+
export async function stopUserMedia() {
|
|
42
|
+
await VADInstance?.pause();
|
|
81
43
|
}
|
|
82
44
|
|
|
83
|
-
export async function
|
|
84
|
-
|
|
85
|
-
|
|
45
|
+
export async function getRecord() {
|
|
46
|
+
const totalSamples = recordedAudioChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
47
|
+
if (totalSamples === 0) {
|
|
48
|
+
return null;
|
|
86
49
|
}
|
|
87
50
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
recordedChunks = [];
|
|
94
|
-
return blob;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
if (recorder.state === 'inactive') {
|
|
98
|
-
return Promise.resolve(finalizeBlob());
|
|
51
|
+
const mergedAudio = new Float32Array(totalSamples);
|
|
52
|
+
let offset = 0;
|
|
53
|
+
for (const chunk of recordedAudioChunks) {
|
|
54
|
+
mergedAudio.set(chunk, offset);
|
|
55
|
+
offset += chunk.length;
|
|
99
56
|
}
|
|
100
57
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
recorder.onerror = () => {
|
|
106
|
-
recordedChunks = [];
|
|
107
|
-
reject(new Error('Failed to finalize audio recording.'));
|
|
108
|
-
};
|
|
109
|
-
recorder.stop();
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function startUserMedia(
|
|
114
|
-
audioContext: AudioContext,
|
|
115
|
-
stream: MediaStream,
|
|
116
|
-
onVoiceStartCallback: () => void,
|
|
117
|
-
onVoiceStopCallback: () => void,
|
|
118
|
-
onUpdateCallback: (amplitude: number) => void
|
|
119
|
-
) {
|
|
120
|
-
const options = {
|
|
121
|
-
fftSize: 1024,
|
|
122
|
-
bufferLen: 1024,
|
|
123
|
-
smoothingTimeConstant: 0.2,
|
|
124
|
-
minCaptureFreq: 85, // in Hz
|
|
125
|
-
maxCaptureFreq: 255, // in Hz
|
|
126
|
-
noiseCaptureDuration: CALIBRATION_DURATION, // in ms
|
|
127
|
-
minNoiseLevel: 0.5, // from 0 to 1
|
|
128
|
-
maxNoiseLevel: 0.7, // from 0 to 1
|
|
129
|
-
avgNoiseMultiplier: 1.2,
|
|
130
|
-
onVoiceStart() {
|
|
131
|
-
wasVoiceStarted = true;
|
|
132
|
-
if (!mediaRecorder || mediaRecorder.state === 'inactive') {
|
|
133
|
-
startRecording(currentStream as MediaStream);
|
|
134
|
-
}
|
|
135
|
-
console.log('👹👹👹voice start👹👹👹');
|
|
136
|
-
onVoiceStartCallback();
|
|
137
|
-
},
|
|
138
|
-
onVoiceStop() {
|
|
139
|
-
if (!wasVoiceStarted) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
console.log('👿👿👿voice stop👿👿👿');
|
|
143
|
-
onVoiceStopCallback();
|
|
144
|
-
}, //Doesn't work properly, so we will handle it with onUpdate callback
|
|
145
|
-
onUpdate(val: number) {
|
|
146
|
-
onUpdateCallback(val);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
vadInstance = vad(audioContext, stream, options);
|
|
58
|
+
const wavBuffer = utils.encodeWAV(mergedAudio, 1, 16000, 1, 16);
|
|
59
|
+
const recordToReturn = new Blob([wavBuffer], { type: 'audio/wav' });
|
|
60
|
+
recordedAudioChunks = [];
|
|
61
|
+
return recordToReturn;
|
|
151
62
|
}
|
|
@@ -67,7 +67,7 @@ export const useAgentAudio = defineStore('agentAudio', () => {
|
|
|
67
67
|
async function sendAudioToServerAndHandleResponse(blob: Blob) {
|
|
68
68
|
currentAbortController = new AbortController();
|
|
69
69
|
const formData = new FormData();
|
|
70
|
-
formData.append('file', blob, 'user_prompt.
|
|
70
|
+
formData.append('file', blob, 'user_prompt.wav');
|
|
71
71
|
formData.append('sessionId', agentStore.activeSessionId);
|
|
72
72
|
formData.append('mode', agentStore.activeModeName ?? '');
|
|
73
73
|
formData.append('timeZone', Intl.DateTimeFormat().resolvedOptions().timeZone);
|
package/dist/custom/package.json
CHANGED
|
@@ -17,6 +17,9 @@ importers:
|
|
|
17
17
|
'@incremark/vue':
|
|
18
18
|
specifier: ^1.0.2
|
|
19
19
|
version: 1.0.2(katex@0.16.45)(vue@3.5.32)
|
|
20
|
+
'@ricky0123/vad-web':
|
|
21
|
+
specifier: ^0.0.30
|
|
22
|
+
version: 0.0.30
|
|
20
23
|
'@shikijs/langs':
|
|
21
24
|
specifier: ^4.0.2
|
|
22
25
|
version: 4.0.2
|
|
@@ -139,6 +142,39 @@ packages:
|
|
|
139
142
|
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
|
140
143
|
engines: {node: '>=8.0.0'}
|
|
141
144
|
|
|
145
|
+
'@protobufjs/aspromise@1.1.2':
|
|
146
|
+
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
|
|
147
|
+
|
|
148
|
+
'@protobufjs/base64@1.1.2':
|
|
149
|
+
resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
|
|
150
|
+
|
|
151
|
+
'@protobufjs/codegen@2.0.5':
|
|
152
|
+
resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==}
|
|
153
|
+
|
|
154
|
+
'@protobufjs/eventemitter@1.1.0':
|
|
155
|
+
resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
|
|
156
|
+
|
|
157
|
+
'@protobufjs/fetch@1.1.0':
|
|
158
|
+
resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
|
|
159
|
+
|
|
160
|
+
'@protobufjs/float@1.0.2':
|
|
161
|
+
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
|
|
162
|
+
|
|
163
|
+
'@protobufjs/inquire@1.1.1':
|
|
164
|
+
resolution: {integrity: sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==}
|
|
165
|
+
|
|
166
|
+
'@protobufjs/path@1.1.2':
|
|
167
|
+
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
|
|
168
|
+
|
|
169
|
+
'@protobufjs/pool@1.1.0':
|
|
170
|
+
resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
|
|
171
|
+
|
|
172
|
+
'@protobufjs/utf8@1.1.1':
|
|
173
|
+
resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==}
|
|
174
|
+
|
|
175
|
+
'@ricky0123/vad-web@0.0.30':
|
|
176
|
+
resolution: {integrity: sha512-cJyYrh4YeeUBJcbR9Bic/bFDyB9qBkAepvpuWM3vLxnAi7bC3VHzf51UeNdT+OtY4D7MLAgV8iJMc4z41ZnaWg==}
|
|
177
|
+
|
|
142
178
|
'@shikijs/core@3.23.0':
|
|
143
179
|
resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==}
|
|
144
180
|
|
|
@@ -218,6 +254,9 @@ packages:
|
|
|
218
254
|
'@types/ms@2.1.0':
|
|
219
255
|
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
|
220
256
|
|
|
257
|
+
'@types/node@25.6.0':
|
|
258
|
+
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
|
259
|
+
|
|
221
260
|
'@types/trusted-types@2.0.7':
|
|
222
261
|
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
|
223
262
|
|
|
@@ -472,6 +511,9 @@ packages:
|
|
|
472
511
|
fast-json-patch@3.1.1:
|
|
473
512
|
resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
|
|
474
513
|
|
|
514
|
+
flatbuffers@25.9.23:
|
|
515
|
+
resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==}
|
|
516
|
+
|
|
475
517
|
get-caller-file@2.0.5:
|
|
476
518
|
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
|
477
519
|
engines: {node: 6.* || 8.* || >= 10.*}
|
|
@@ -480,6 +522,9 @@ packages:
|
|
|
480
522
|
resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
|
|
481
523
|
engines: {node: '>=18'}
|
|
482
524
|
|
|
525
|
+
guid-typescript@1.0.9:
|
|
526
|
+
resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==}
|
|
527
|
+
|
|
483
528
|
hast-util-to-html@9.0.5:
|
|
484
529
|
resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
|
|
485
530
|
|
|
@@ -525,6 +570,9 @@ packages:
|
|
|
525
570
|
lodash-es@4.18.1:
|
|
526
571
|
resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
|
|
527
572
|
|
|
573
|
+
long@5.3.2:
|
|
574
|
+
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
|
|
575
|
+
|
|
528
576
|
longest-streak@3.1.0:
|
|
529
577
|
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
|
530
578
|
|
|
@@ -690,12 +738,21 @@ packages:
|
|
|
690
738
|
oniguruma-to-es@4.3.5:
|
|
691
739
|
resolution: {integrity: sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==}
|
|
692
740
|
|
|
741
|
+
onnxruntime-common@1.25.1:
|
|
742
|
+
resolution: {integrity: sha512-kKvYQFdos4LWJqhZ+nmKu3NT8NXzw8I5x9fNUKe1rNKcPfNKnYXUtW7JBpcKFsvLtrJashRgVYSbFap4cHxvNg==}
|
|
743
|
+
|
|
744
|
+
onnxruntime-web@1.25.1:
|
|
745
|
+
resolution: {integrity: sha512-mgs61sJ9m3hLa5jGRr9Pen3kkG00vlxmrcRL6FufYpSWBZKaklo0sotQCq2fLjgDVLnW57jrDcLqzYJNKeZskQ==}
|
|
746
|
+
|
|
693
747
|
parse-entities@4.0.2:
|
|
694
748
|
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
|
695
749
|
|
|
696
750
|
picocolors@1.1.1:
|
|
697
751
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
|
698
752
|
|
|
753
|
+
platform@1.3.6:
|
|
754
|
+
resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
|
|
755
|
+
|
|
699
756
|
postcss@8.5.10:
|
|
700
757
|
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
|
|
701
758
|
engines: {node: ^10 || ^12 || >=14}
|
|
@@ -703,6 +760,10 @@ packages:
|
|
|
703
760
|
property-information@7.1.0:
|
|
704
761
|
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
|
|
705
762
|
|
|
763
|
+
protobufjs@7.5.6:
|
|
764
|
+
resolution: {integrity: sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==}
|
|
765
|
+
engines: {node: '>=12.0.0'}
|
|
766
|
+
|
|
706
767
|
regex-recursion@6.0.2:
|
|
707
768
|
resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
|
|
708
769
|
|
|
@@ -775,6 +836,9 @@ packages:
|
|
|
775
836
|
tslib@2.8.1:
|
|
776
837
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
|
777
838
|
|
|
839
|
+
undici-types@7.19.2:
|
|
840
|
+
resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==}
|
|
841
|
+
|
|
778
842
|
unist-util-is@6.0.1:
|
|
779
843
|
resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
|
|
780
844
|
|
|
@@ -1063,6 +1127,33 @@ snapshots:
|
|
|
1063
1127
|
|
|
1064
1128
|
'@opentelemetry/api@1.9.0': {}
|
|
1065
1129
|
|
|
1130
|
+
'@protobufjs/aspromise@1.1.2': {}
|
|
1131
|
+
|
|
1132
|
+
'@protobufjs/base64@1.1.2': {}
|
|
1133
|
+
|
|
1134
|
+
'@protobufjs/codegen@2.0.5': {}
|
|
1135
|
+
|
|
1136
|
+
'@protobufjs/eventemitter@1.1.0': {}
|
|
1137
|
+
|
|
1138
|
+
'@protobufjs/fetch@1.1.0':
|
|
1139
|
+
dependencies:
|
|
1140
|
+
'@protobufjs/aspromise': 1.1.2
|
|
1141
|
+
'@protobufjs/inquire': 1.1.1
|
|
1142
|
+
|
|
1143
|
+
'@protobufjs/float@1.0.2': {}
|
|
1144
|
+
|
|
1145
|
+
'@protobufjs/inquire@1.1.1': {}
|
|
1146
|
+
|
|
1147
|
+
'@protobufjs/path@1.1.2': {}
|
|
1148
|
+
|
|
1149
|
+
'@protobufjs/pool@1.1.0': {}
|
|
1150
|
+
|
|
1151
|
+
'@protobufjs/utf8@1.1.1': {}
|
|
1152
|
+
|
|
1153
|
+
'@ricky0123/vad-web@0.0.30':
|
|
1154
|
+
dependencies:
|
|
1155
|
+
onnxruntime-web: 1.25.1
|
|
1156
|
+
|
|
1066
1157
|
'@shikijs/core@3.23.0':
|
|
1067
1158
|
dependencies:
|
|
1068
1159
|
'@shikijs/types': 3.23.0
|
|
@@ -1162,6 +1253,10 @@ snapshots:
|
|
|
1162
1253
|
|
|
1163
1254
|
'@types/ms@2.1.0': {}
|
|
1164
1255
|
|
|
1256
|
+
'@types/node@25.6.0':
|
|
1257
|
+
dependencies:
|
|
1258
|
+
undici-types: 7.19.2
|
|
1259
|
+
|
|
1165
1260
|
'@types/trusted-types@2.0.7':
|
|
1166
1261
|
optional: true
|
|
1167
1262
|
|
|
@@ -1404,10 +1499,14 @@ snapshots:
|
|
|
1404
1499
|
|
|
1405
1500
|
fast-json-patch@3.1.1: {}
|
|
1406
1501
|
|
|
1502
|
+
flatbuffers@25.9.23: {}
|
|
1503
|
+
|
|
1407
1504
|
get-caller-file@2.0.5: {}
|
|
1408
1505
|
|
|
1409
1506
|
get-east-asian-width@1.5.0: {}
|
|
1410
1507
|
|
|
1508
|
+
guid-typescript@1.0.9: {}
|
|
1509
|
+
|
|
1411
1510
|
hast-util-to-html@9.0.5:
|
|
1412
1511
|
dependencies:
|
|
1413
1512
|
'@types/hast': 3.0.4
|
|
@@ -1457,6 +1556,8 @@ snapshots:
|
|
|
1457
1556
|
|
|
1458
1557
|
lodash-es@4.18.1: {}
|
|
1459
1558
|
|
|
1559
|
+
long@5.3.2: {}
|
|
1560
|
+
|
|
1460
1561
|
longest-streak@3.1.0: {}
|
|
1461
1562
|
|
|
1462
1563
|
magic-string@0.30.21:
|
|
@@ -1832,6 +1933,17 @@ snapshots:
|
|
|
1832
1933
|
regex: 6.1.0
|
|
1833
1934
|
regex-recursion: 6.0.2
|
|
1834
1935
|
|
|
1936
|
+
onnxruntime-common@1.25.1: {}
|
|
1937
|
+
|
|
1938
|
+
onnxruntime-web@1.25.1:
|
|
1939
|
+
dependencies:
|
|
1940
|
+
flatbuffers: 25.9.23
|
|
1941
|
+
guid-typescript: 1.0.9
|
|
1942
|
+
long: 5.3.2
|
|
1943
|
+
onnxruntime-common: 1.25.1
|
|
1944
|
+
platform: 1.3.6
|
|
1945
|
+
protobufjs: 7.5.6
|
|
1946
|
+
|
|
1835
1947
|
parse-entities@4.0.2:
|
|
1836
1948
|
dependencies:
|
|
1837
1949
|
'@types/unist': 2.0.11
|
|
@@ -1844,6 +1956,8 @@ snapshots:
|
|
|
1844
1956
|
|
|
1845
1957
|
picocolors@1.1.1: {}
|
|
1846
1958
|
|
|
1959
|
+
platform@1.3.6: {}
|
|
1960
|
+
|
|
1847
1961
|
postcss@8.5.10:
|
|
1848
1962
|
dependencies:
|
|
1849
1963
|
nanoid: 3.3.11
|
|
@@ -1852,6 +1966,21 @@ snapshots:
|
|
|
1852
1966
|
|
|
1853
1967
|
property-information@7.1.0: {}
|
|
1854
1968
|
|
|
1969
|
+
protobufjs@7.5.6:
|
|
1970
|
+
dependencies:
|
|
1971
|
+
'@protobufjs/aspromise': 1.1.2
|
|
1972
|
+
'@protobufjs/base64': 1.1.2
|
|
1973
|
+
'@protobufjs/codegen': 2.0.5
|
|
1974
|
+
'@protobufjs/eventemitter': 1.1.0
|
|
1975
|
+
'@protobufjs/fetch': 1.1.0
|
|
1976
|
+
'@protobufjs/float': 1.0.2
|
|
1977
|
+
'@protobufjs/inquire': 1.1.1
|
|
1978
|
+
'@protobufjs/path': 1.1.2
|
|
1979
|
+
'@protobufjs/pool': 1.1.0
|
|
1980
|
+
'@protobufjs/utf8': 1.1.1
|
|
1981
|
+
'@types/node': 25.6.0
|
|
1982
|
+
long: 5.3.2
|
|
1983
|
+
|
|
1855
1984
|
regex-recursion@6.0.2:
|
|
1856
1985
|
dependencies:
|
|
1857
1986
|
regex-utilities: 2.3.0
|
|
@@ -1925,6 +2054,8 @@ snapshots:
|
|
|
1925
2054
|
|
|
1926
2055
|
tslib@2.8.1: {}
|
|
1927
2056
|
|
|
2057
|
+
undici-types@7.19.2: {}
|
|
2058
|
+
|
|
1928
2059
|
unist-util-is@6.0.1:
|
|
1929
2060
|
dependencies:
|
|
1930
2061
|
'@types/unist': 3.0.3
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<script setup lang="ts">
|
|
29
29
|
import { computed, onMounted, onBeforeUnmount, ref, watch } from 'vue';
|
|
30
30
|
import debounce from 'lodash.debounce';
|
|
31
|
-
import { requestMicAndStartVAD, stopUserMedia,
|
|
31
|
+
import { requestMicAndStartVAD, stopUserMedia, getRecord } from './voiceActivityDetection';
|
|
32
32
|
import { Spinner } from '@/afcl'
|
|
33
33
|
import { storeToRefs } from 'pinia';
|
|
34
34
|
import { useAgentStore } from '../composables/useAgentStore';
|
|
@@ -41,7 +41,7 @@ const { sendAudioToServerAndHandleResponse } = agentAudio;
|
|
|
41
41
|
const { stopGenerationAndAudio } = agentAudio;
|
|
42
42
|
const { stopCurrentAudioPlayback } = agentAudio;
|
|
43
43
|
const { agentAudioMode } = storeToRefs(agentAudio);
|
|
44
|
-
const microphoneButtonMode = ref<'off' | '
|
|
44
|
+
const microphoneButtonMode = ref<'off' | 'listen' | 'transcribing' | 'generating'>('off');
|
|
45
45
|
const showAudioWavesAnimation = ref(false);
|
|
46
46
|
const audioAmplitude = ref(0);
|
|
47
47
|
const hideAnimationDebounced = debounce(() => {
|
|
@@ -93,14 +93,9 @@ function toggleChatMode() {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
async function onStartRecording() {
|
|
96
|
-
microphoneButtonMode.value = 'calibrating';
|
|
97
96
|
await requestMicAndStartVAD(saidSomething, stopRecording, onAnySound);
|
|
98
|
-
setTimeout(() => {
|
|
99
|
-
if (isAudioChatMode.value) {
|
|
100
97
|
microphoneButtonMode.value = 'listen';
|
|
101
98
|
agentAudio.playBeep(1000);
|
|
102
|
-
}
|
|
103
|
-
}, CALIBRATION_DURATION);
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
function onStopRecording() {
|
|
@@ -145,8 +140,9 @@ function onAnySound(amplitude: number) {
|
|
|
145
140
|
|
|
146
141
|
async function sendRecordForTranscription() {
|
|
147
142
|
showAudioWavesAnimation.value = false;
|
|
148
|
-
const recordBlob = await
|
|
143
|
+
const recordBlob = await getRecord();
|
|
149
144
|
if (recordBlob) {
|
|
145
|
+
console.log('Audio recorded, sending to server for transcription. Audio Blob size:', recordBlob.size, recordBlob.type);
|
|
150
146
|
onStopRecording();
|
|
151
147
|
await sendAudioToServerAndHandleResponse(recordBlob);
|
|
152
148
|
if (agentStore.isAudioChatMode) {
|
|
@@ -1,151 +1,62 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
let
|
|
4
|
-
let
|
|
5
|
-
let
|
|
6
|
-
let
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { MicVAD, utils } from "@ricky0123/vad-web"
|
|
2
|
+
|
|
3
|
+
let VADInstance: MicVAD | null = null;
|
|
4
|
+
let recordedAudioChunks: Float32Array[] = [];
|
|
5
|
+
let onVoiceStopCallback: () => void = () => {};
|
|
6
|
+
let onVoiceStartCallback: () => void = () => {};
|
|
7
|
+
let onUpdateCallback: (amplitude: number) => void = () => {};
|
|
8
|
+
|
|
9
|
+
async function createVADInstance(){
|
|
10
|
+
VADInstance = await MicVAD.new({
|
|
11
|
+
onFrameProcessed: ({ isSpeech }) => {
|
|
12
|
+
onUpdateCallback(isSpeech);
|
|
13
|
+
},
|
|
14
|
+
onSpeechEnd: (audio) => {
|
|
15
|
+
recordedAudioChunks.push(audio);
|
|
16
|
+
onVoiceStopCallback();
|
|
17
|
+
},
|
|
18
|
+
onSpeechStart: () => {
|
|
19
|
+
onVoiceStartCallback();
|
|
20
|
+
},
|
|
21
|
+
onnxWASMBasePath: "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.22.0/dist/",
|
|
22
|
+
baseAssetPath: "https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.29/dist/",
|
|
23
|
+
})
|
|
24
|
+
}
|
|
11
25
|
|
|
12
26
|
export async function requestMicAndStartVAD(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
onVoiceStop: () => void,
|
|
28
|
+
onVoiceStart: () => void,
|
|
29
|
+
onUpdate: (amplitude: number) => void
|
|
16
30
|
) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
navigator.mediaDevices
|
|
22
|
-
.getUserMedia({ audio: true })
|
|
23
|
-
.then((stream) => {
|
|
24
|
-
currentStream = stream;
|
|
25
|
-
startRecording(stream);
|
|
26
|
-
resolve();
|
|
27
|
-
startUserMedia(audioContext as AudioContext, stream, onVoiceStartCallback, onVoiceStopCallback, onUpdateCallback);
|
|
28
|
-
})
|
|
29
|
-
.catch((error) => {
|
|
30
|
-
handleMicConnectError();
|
|
31
|
-
reject(error);
|
|
32
|
-
});
|
|
33
|
-
} catch (e) {
|
|
34
|
-
handleUserMediaError();
|
|
35
|
-
reject(e);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function handleUserMediaError() {
|
|
41
|
-
console.error('Mic input is not supported by the browser.');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function handleMicConnectError() {
|
|
45
|
-
console.error('Could not connect microphone. Possible rejected by the user or is blocked by the browser.');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function stopUserMedia() {
|
|
49
|
-
wasVoiceStarted = false;
|
|
50
|
-
if (vadInstance && vadInstance.destroy) {
|
|
51
|
-
vadInstance.destroy();
|
|
52
|
-
vadInstance = null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (currentStream) {
|
|
56
|
-
currentStream.getTracks().forEach(track => track.stop());
|
|
57
|
-
currentStream = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (audioContext) {
|
|
61
|
-
audioContext.close();
|
|
62
|
-
audioContext = null;
|
|
63
|
-
}
|
|
31
|
+
onVoiceStopCallback = onVoiceStop;
|
|
32
|
+
onVoiceStartCallback = onVoiceStart;
|
|
33
|
+
onUpdateCallback = onUpdate;
|
|
64
34
|
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
mediaRecorder = null;
|
|
35
|
+
if (!VADInstance) {
|
|
36
|
+
await createVADInstance();
|
|
68
37
|
}
|
|
69
|
-
|
|
38
|
+
VADInstance?.start();
|
|
70
39
|
}
|
|
71
40
|
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
mediaRecorder = new MediaRecorder(stream);
|
|
75
|
-
mediaRecorder.ondataavailable = (event: BlobEvent) => {
|
|
76
|
-
if (event.data.size > 0) {
|
|
77
|
-
recordedChunks.push(event.data);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
mediaRecorder.start();
|
|
41
|
+
export async function stopUserMedia() {
|
|
42
|
+
await VADInstance?.pause();
|
|
81
43
|
}
|
|
82
44
|
|
|
83
|
-
export async function
|
|
84
|
-
|
|
85
|
-
|
|
45
|
+
export async function getRecord() {
|
|
46
|
+
const totalSamples = recordedAudioChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
47
|
+
if (totalSamples === 0) {
|
|
48
|
+
return null;
|
|
86
49
|
}
|
|
87
50
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
recordedChunks = [];
|
|
94
|
-
return blob;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
if (recorder.state === 'inactive') {
|
|
98
|
-
return Promise.resolve(finalizeBlob());
|
|
51
|
+
const mergedAudio = new Float32Array(totalSamples);
|
|
52
|
+
let offset = 0;
|
|
53
|
+
for (const chunk of recordedAudioChunks) {
|
|
54
|
+
mergedAudio.set(chunk, offset);
|
|
55
|
+
offset += chunk.length;
|
|
99
56
|
}
|
|
100
57
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
recorder.onerror = () => {
|
|
106
|
-
recordedChunks = [];
|
|
107
|
-
reject(new Error('Failed to finalize audio recording.'));
|
|
108
|
-
};
|
|
109
|
-
recorder.stop();
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function startUserMedia(
|
|
114
|
-
audioContext: AudioContext,
|
|
115
|
-
stream: MediaStream,
|
|
116
|
-
onVoiceStartCallback: () => void,
|
|
117
|
-
onVoiceStopCallback: () => void,
|
|
118
|
-
onUpdateCallback: (amplitude: number) => void
|
|
119
|
-
) {
|
|
120
|
-
const options = {
|
|
121
|
-
fftSize: 1024,
|
|
122
|
-
bufferLen: 1024,
|
|
123
|
-
smoothingTimeConstant: 0.2,
|
|
124
|
-
minCaptureFreq: 85, // in Hz
|
|
125
|
-
maxCaptureFreq: 255, // in Hz
|
|
126
|
-
noiseCaptureDuration: CALIBRATION_DURATION, // in ms
|
|
127
|
-
minNoiseLevel: 0.5, // from 0 to 1
|
|
128
|
-
maxNoiseLevel: 0.7, // from 0 to 1
|
|
129
|
-
avgNoiseMultiplier: 1.2,
|
|
130
|
-
onVoiceStart() {
|
|
131
|
-
wasVoiceStarted = true;
|
|
132
|
-
if (!mediaRecorder || mediaRecorder.state === 'inactive') {
|
|
133
|
-
startRecording(currentStream as MediaStream);
|
|
134
|
-
}
|
|
135
|
-
console.log('👹👹👹voice start👹👹👹');
|
|
136
|
-
onVoiceStartCallback();
|
|
137
|
-
},
|
|
138
|
-
onVoiceStop() {
|
|
139
|
-
if (!wasVoiceStarted) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
console.log('👿👿👿voice stop👿👿👿');
|
|
143
|
-
onVoiceStopCallback();
|
|
144
|
-
}, //Doesn't work properly, so we will handle it with onUpdate callback
|
|
145
|
-
onUpdate(val: number) {
|
|
146
|
-
onUpdateCallback(val);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
vadInstance = vad(audioContext, stream, options);
|
|
58
|
+
const wavBuffer = utils.encodeWAV(mergedAudio, 1, 16000, 1, 16);
|
|
59
|
+
const recordToReturn = new Blob([wavBuffer], { type: 'audio/wav' });
|
|
60
|
+
recordedAudioChunks = [];
|
|
61
|
+
return recordToReturn;
|
|
151
62
|
}
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,15 @@ const sessionIdBodySchema = z.object({
|
|
|
47
47
|
const createSessionBodySchema = z.object({
|
|
48
48
|
triggerMessage: z.string().optional(),
|
|
49
49
|
}).strict();
|
|
50
|
+
function isAbortError(error) {
|
|
51
|
+
return (error instanceof DOMException && error.name === "AbortError") || (typeof error === "object" &&
|
|
52
|
+
error !== null &&
|
|
53
|
+
"name" in error &&
|
|
54
|
+
(error.name === "AbortError" || error.name === "APIUserAbortError"));
|
|
55
|
+
}
|
|
56
|
+
function getErrorMessage(error) {
|
|
57
|
+
return error instanceof Error ? error.message : String(error);
|
|
58
|
+
}
|
|
50
59
|
export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
51
60
|
parseBody(schema, body, response) {
|
|
52
61
|
const parsed = schema.safeParse(body !== null && body !== void 0 ? body : {});
|
|
@@ -134,6 +143,20 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
134
143
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
135
144
|
}
|
|
136
145
|
});
|
|
146
|
+
if (!this.adminforth.config.customization.customHeadItems) {
|
|
147
|
+
this.adminforth.config.customization.customHeadItems = [];
|
|
148
|
+
}
|
|
149
|
+
this.adminforth.config.customization.customHeadItems.push({
|
|
150
|
+
tagName: 'script',
|
|
151
|
+
attributes: {
|
|
152
|
+
src: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.22.0/dist/ort.wasm.min.js'
|
|
153
|
+
}
|
|
154
|
+
}, {
|
|
155
|
+
tagName: 'script',
|
|
156
|
+
attributes: {
|
|
157
|
+
src: 'https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.29/dist/bundle.min.js'
|
|
158
|
+
},
|
|
159
|
+
});
|
|
137
160
|
if (!this.options.sessionResource) {
|
|
138
161
|
throw new Error("sessionResource is required for AdminForthAgentPlugin");
|
|
139
162
|
}
|
|
@@ -151,7 +174,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
151
174
|
runAgentTurn(input) {
|
|
152
175
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
176
|
var _a, e_1, _b, _c;
|
|
154
|
-
var _d, _e, _f, _g;
|
|
177
|
+
var _d, _e, _f, _g, _h;
|
|
155
178
|
let fullResponse = "";
|
|
156
179
|
const maxTokens = (_d = this.options.maxTokens) !== null && _d !== void 0 ? _d : 1000;
|
|
157
180
|
const selectedMode = (_e = this.options.modes.find((mode) => mode.name === input.modeName)) !== null && _e !== void 0 ? _e : this.options.modes[0];
|
|
@@ -172,7 +195,11 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
172
195
|
const modelMiddleware = primaryModelSpec.middleware;
|
|
173
196
|
const userLanguage = yield detectUserLanguage(selectedMode.completionAdapter, input.prompt, input.previousUserMessages)
|
|
174
197
|
.catch((error) => {
|
|
175
|
-
|
|
198
|
+
var _a;
|
|
199
|
+
if (((_a = input.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) || isAbortError(error)) {
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
|
|
176
203
|
return null;
|
|
177
204
|
});
|
|
178
205
|
const systemPrompt = buildAgentTurnSystemPrompt({
|
|
@@ -209,10 +236,13 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
209
236
|
sequenceDebugSink: input.sequenceDebugCollector,
|
|
210
237
|
});
|
|
211
238
|
try {
|
|
212
|
-
for (var
|
|
213
|
-
_c =
|
|
214
|
-
|
|
239
|
+
for (var _j = true, _k = __asyncValues(stream), _l; _l = yield _k.next(), _a = _l.done, !_a; _j = true) {
|
|
240
|
+
_c = _l.value;
|
|
241
|
+
_j = false;
|
|
215
242
|
const rawChunk = _c;
|
|
243
|
+
if ((_f = input.abortSignal) === null || _f === void 0 ? void 0 : _f.aborted) {
|
|
244
|
+
throw new DOMException("This operation was aborted", "AbortError");
|
|
245
|
+
}
|
|
216
246
|
const [token, metadata] = rawChunk;
|
|
217
247
|
const nodeName = typeof (metadata === null || metadata === void 0 ? void 0 : metadata.langgraph_node) === "string"
|
|
218
248
|
? metadata.langgraph_node
|
|
@@ -234,18 +264,18 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
234
264
|
.map((b) => { var _a; return String((_a = b.text) !== null && _a !== void 0 ? _a : ""); })
|
|
235
265
|
.join("");
|
|
236
266
|
if (reasoningDelta) {
|
|
237
|
-
(
|
|
267
|
+
(_g = input.emitReasoningDelta) === null || _g === void 0 ? void 0 : _g.call(input, reasoningDelta);
|
|
238
268
|
}
|
|
239
269
|
if (textDelta) {
|
|
240
270
|
fullResponse += textDelta;
|
|
241
|
-
(
|
|
271
|
+
(_h = input.emitTextDelta) === null || _h === void 0 ? void 0 : _h.call(input, textDelta);
|
|
242
272
|
}
|
|
243
273
|
}
|
|
244
274
|
}
|
|
245
275
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
246
276
|
finally {
|
|
247
277
|
try {
|
|
248
|
-
if (!
|
|
278
|
+
if (!_j && !_a && (_b = _k.return)) yield _b.call(_k);
|
|
249
279
|
}
|
|
250
280
|
finally { if (e_1) throw e_1.error; }
|
|
251
281
|
}
|
|
@@ -285,14 +315,14 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
285
315
|
fullResponse = agentResponse.text;
|
|
286
316
|
}
|
|
287
317
|
catch (error) {
|
|
288
|
-
if ((_a = input.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
318
|
+
if (((_a = input.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) || isAbortError(error)) {
|
|
289
319
|
aborted = true;
|
|
290
320
|
logger.info(input.abortLogMessage);
|
|
291
321
|
}
|
|
292
322
|
else {
|
|
293
323
|
failed = true;
|
|
294
|
-
|
|
295
|
-
|
|
324
|
+
fullResponse = getErrorMessage(error);
|
|
325
|
+
logger.error(`${input.failureLogMessage}:\n${fullResponse}`);
|
|
296
326
|
(_b = input.emitErrorResponse) === null || _b === void 0 ? void 0 : _b.call(input, fullResponse);
|
|
297
327
|
}
|
|
298
328
|
}
|
|
@@ -392,12 +422,12 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
392
422
|
});
|
|
393
423
|
}
|
|
394
424
|
catch (error) {
|
|
395
|
-
if (abortSignal.aborted) {
|
|
425
|
+
if (abortSignal.aborted || isAbortError(error)) {
|
|
396
426
|
logger.info("Agent speech transcription aborted by the client");
|
|
397
427
|
stream.end();
|
|
398
428
|
return null;
|
|
399
429
|
}
|
|
400
|
-
logger.error(`Agent speech transcription failed:\n${error
|
|
430
|
+
logger.error(`Agent speech transcription failed:\n${getErrorMessage(error)}`);
|
|
401
431
|
stream.error("Speech transcription failed. Check server logs for details.");
|
|
402
432
|
stream.end();
|
|
403
433
|
return null;
|
|
@@ -481,7 +511,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
481
511
|
return null;
|
|
482
512
|
}
|
|
483
513
|
catch (error) {
|
|
484
|
-
if (abortSignal.aborted) {
|
|
514
|
+
if (abortSignal.aborted || isAbortError(error)) {
|
|
485
515
|
logger.info("Agent speech audio streaming aborted by the client");
|
|
486
516
|
}
|
|
487
517
|
else {
|
package/index.ts
CHANGED
|
@@ -75,6 +75,20 @@ const createSessionBodySchema = z.object({
|
|
|
75
75
|
triggerMessage: z.string().optional(),
|
|
76
76
|
}).strict();
|
|
77
77
|
|
|
78
|
+
function isAbortError(error: unknown): boolean {
|
|
79
|
+
return (
|
|
80
|
+
error instanceof DOMException && error.name === "AbortError"
|
|
81
|
+
) || (
|
|
82
|
+
typeof error === "object" &&
|
|
83
|
+
error !== null &&
|
|
84
|
+
"name" in error &&
|
|
85
|
+
(error.name === "AbortError" || error.name === "APIUserAbortError")
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getErrorMessage(error: unknown): string {
|
|
90
|
+
return error instanceof Error ? error.message : String(error);
|
|
91
|
+
}
|
|
78
92
|
|
|
79
93
|
export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
80
94
|
options: PluginOptions;
|
|
@@ -176,6 +190,23 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
176
190
|
hasAudioAdapter: Boolean(this.options.audioAdapter),
|
|
177
191
|
}
|
|
178
192
|
});
|
|
193
|
+
if (!this.adminforth.config.customization.customHeadItems) {
|
|
194
|
+
this.adminforth.config.customization.customHeadItems = [];
|
|
195
|
+
}
|
|
196
|
+
this.adminforth.config.customization.customHeadItems.push(
|
|
197
|
+
{
|
|
198
|
+
tagName: 'script',
|
|
199
|
+
attributes: {
|
|
200
|
+
src: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.22.0/dist/ort.wasm.min.js'
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
tagName: 'script',
|
|
205
|
+
attributes: {
|
|
206
|
+
src: 'https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.29/dist/bundle.min.js'
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
);
|
|
179
210
|
if (!this.options.sessionResource) {
|
|
180
211
|
throw new Error("sessionResource is required for AdminForthAgentPlugin");
|
|
181
212
|
}
|
|
@@ -216,7 +247,11 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
216
247
|
|
|
217
248
|
const userLanguage = await detectUserLanguage(selectedMode.completionAdapter, input.prompt, input.previousUserMessages)
|
|
218
249
|
.catch((error) => {
|
|
219
|
-
|
|
250
|
+
if (input.abortSignal?.aborted || isAbortError(error)) {
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
logger.warn(`Failed to detect user language: ${getErrorMessage(error)}`);
|
|
220
255
|
return null;
|
|
221
256
|
});
|
|
222
257
|
const systemPrompt = buildAgentTurnSystemPrompt({
|
|
@@ -257,6 +292,10 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
257
292
|
});
|
|
258
293
|
|
|
259
294
|
for await (const rawChunk of stream as AsyncIterable<[any, any]>) {
|
|
295
|
+
if (input.abortSignal?.aborted) {
|
|
296
|
+
throw new DOMException("This operation was aborted", "AbortError");
|
|
297
|
+
}
|
|
298
|
+
|
|
260
299
|
const [token, metadata] = rawChunk;
|
|
261
300
|
|
|
262
301
|
const nodeName =
|
|
@@ -327,13 +366,13 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
327
366
|
});
|
|
328
367
|
fullResponse = agentResponse.text;
|
|
329
368
|
} catch (error) {
|
|
330
|
-
if (input.abortSignal?.aborted) {
|
|
369
|
+
if (input.abortSignal?.aborted || isAbortError(error)) {
|
|
331
370
|
aborted = true;
|
|
332
371
|
logger.info(input.abortLogMessage);
|
|
333
372
|
} else {
|
|
334
373
|
failed = true;
|
|
335
|
-
|
|
336
|
-
|
|
374
|
+
fullResponse = getErrorMessage(error);
|
|
375
|
+
logger.error(`${input.failureLogMessage}:\n${fullResponse}`);
|
|
337
376
|
input.emitErrorResponse?.(fullResponse);
|
|
338
377
|
}
|
|
339
378
|
}
|
|
@@ -437,13 +476,13 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
437
476
|
abortSignal,
|
|
438
477
|
});
|
|
439
478
|
} catch (error) {
|
|
440
|
-
if (abortSignal.aborted) {
|
|
479
|
+
if (abortSignal.aborted || isAbortError(error)) {
|
|
441
480
|
logger.info("Agent speech transcription aborted by the client");
|
|
442
481
|
stream.end();
|
|
443
482
|
return null;
|
|
444
483
|
}
|
|
445
484
|
|
|
446
|
-
logger.error(`Agent speech transcription failed:\n${error
|
|
485
|
+
logger.error(`Agent speech transcription failed:\n${getErrorMessage(error)}`);
|
|
447
486
|
stream.error("Speech transcription failed. Check server logs for details.");
|
|
448
487
|
stream.end();
|
|
449
488
|
return null;
|
|
@@ -545,7 +584,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
|
|
|
545
584
|
stream.end();
|
|
546
585
|
return null;
|
|
547
586
|
} catch (error) {
|
|
548
|
-
if (abortSignal.aborted) {
|
|
587
|
+
if (abortSignal.aborted || isAbortError(error)) {
|
|
549
588
|
logger.info("Agent speech audio streaming aborted by the client");
|
|
550
589
|
} else {
|
|
551
590
|
logger.error(`Agent speech audio streaming failed:\n${error}`);
|