@chat21/chat21-web-widget 5.1.30-rc1 → 5.1.32-rc1
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/CHANGELOG.md +44 -71
- package/angular.json +3 -1
- package/deploy_amazon_beta.sh +7 -17
- package/deploy_amazon_prod.sh +41 -0
- package/docs/changelog/this-branch.md +47 -0
- package/package.json +4 -1
- package/src/app/app.component.ts +1 -2
- package/src/app/app.module.ts +9 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.html +4 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +8 -0
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +2 -2
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +2 -0
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +42 -0
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +91 -0
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +101 -7
- package/src/app/component/message/audio/audio.component.ts +0 -5
- package/src/app/component/message/audio-sync/audio-sync.component.html +19 -0
- package/src/app/component/message/audio-sync/audio-sync.component.scss +65 -0
- package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +23 -0
- package/src/app/component/message/audio-sync/audio-sync.component.ts +197 -0
- package/src/app/component/message/bubble-message/bubble-message.component.html +6 -1
- package/src/app/component/message/bubble-message/bubble-message.component.ts +2 -1
- package/src/app/providers/global-settings.service.ts +10 -0
- package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +12 -0
- package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +171 -0
- package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +39 -0
- package/src/app/providers/voice/audio.types.ts +34 -0
- package/src/app/providers/voice/vad.service.spec.ts +28 -0
- package/src/app/providers/voice/vad.service.ts +70 -0
- package/src/app/providers/voice/voice.service.spec.ts +60 -0
- package/src/app/providers/voice/voice.service.ts +264 -0
- package/src/app/shims/onnxruntime-web-wasm.ts +4 -0
- package/src/app/utils/conversation-sender-classifier.ts +21 -0
- package/src/app/utils/globals.ts +3 -0
- package/src/assets/onnx/ort-wasm-simd-threaded.mjs +59 -0
- package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
- package/src/assets/vad/silero_vad_legacy.onnx +0 -0
- package/src/assets/vad/vad.worklet.bundle.min.js +1 -0
- package/src/chat21-core/models/message.ts +2 -1
- package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +3 -2
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +12 -0
- package/src/chat21-core/utils/utils-message.ts +7 -0
- package/tsconfig.json +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,9 +6,37 @@
|
|
|
6
6
|
### **Copyrigth**:
|
|
7
7
|
*Tiledesk SRL*
|
|
8
8
|
|
|
9
|
+
# 5.1.32-rc1
|
|
10
|
+
- **added**: Voice pipeline — VAD (`@ricky0123/vad-web`) with ONNX Runtime WASM served from `/assets/onnx` (`copy-onnx-wasm`), `VoiceService` with `audioSegment$` (WebM segments) and optional STT/TTS via unified OpenAI provider using `HttpClient`, transcript / error fields on segment payloads.
|
|
11
|
+
- **added**: Stream audio UI in conversation footer — toggle, real-time volume stream and animated waveform (`volume$`); mic session lifecycle wired to upload segments on speech end.
|
|
12
|
+
- **added**: `MessageModel.isJustRecived` — set when ingesting messages (MQTT/Firebase `addCommandMessage` for `command.type === "message"`, and default for non-command messages in `addedMessage` / `addedNew`) to distinguish “new in session” vs history.
|
|
13
|
+
- **added**: `chat-audio-sync` for TTS messages — karaoke-style word sync to audio, full `message` input, typography aligned with text bubbles; skips animation when `isJustRecived === false`; after playback ends sets `message.isJustRecived = false` so replays show full text without re-animating.
|
|
14
|
+
- **bug fixed**: `AnalyserNode.getByteFrequencyData` TypeScript error — `Uint8Array` created from an explicit `ArrayBuffer` for correct DOM typings.
|
|
15
|
+
- **bug fixed**: `isStreamAudioActive` no longer derived from per-frame mic level (`volume > 1`), which caused the stream button / active state to flash continuously while listening.
|
|
16
|
+
|
|
17
|
+
# 5.1.30
|
|
18
|
+
- **bug fixed**: startHidden is not working properly
|
|
19
|
+
|
|
20
|
+
# 5.1.30-rc3
|
|
21
|
+
- **bug fixed**: bug fix user-typing with human is not available
|
|
22
|
+
|
|
23
|
+
# 5.1.30-rc2
|
|
24
|
+
- **bug fixed**: bug fix disabled user-typing with human
|
|
25
|
+
|
|
9
26
|
# 5.1.30-rc1
|
|
10
27
|
- **bug fixed**: startHidden is not working properly
|
|
11
28
|
|
|
29
|
+
# 5.1.28
|
|
30
|
+
- **bug fixed**: fixed Bot/Human conversation detection by correctly classifying bot replies
|
|
31
|
+
|
|
32
|
+
# 5.1.27
|
|
33
|
+
- **bug fixed**: centralized fullscreen management on mobile and handled the case of the closed widget that remained fullscreen
|
|
34
|
+
- **changed**: start with authentication if hasCalloutInWidgetConfig is true
|
|
35
|
+
- **changed**: Force authentication if ageChangeVisibilityDesktop or PageChangeVisibilityMobile is OPEN
|
|
36
|
+
- **changed**: Set the default autoStart value to false
|
|
37
|
+
- **added**: Added the open widget loading spinner
|
|
38
|
+
- **changed**: Load the widget without authentication and display the speech bubble
|
|
39
|
+
|
|
12
40
|
# 5.1.27-rc3
|
|
13
41
|
- **bug fixed**: fixed Bot/Human conversation detection by correctly classifying bot replies
|
|
14
42
|
|
|
@@ -27,42 +55,29 @@
|
|
|
27
55
|
- **changed**: Hide the resize-widget button when on mobile
|
|
28
56
|
- **added**: added "I'm thinking" when the bot responds
|
|
29
57
|
|
|
30
|
-
# 5.1.26
|
|
31
|
-
- **
|
|
58
|
+
# 5.1.26
|
|
59
|
+
- **bug fixed**: attachment buttons text alignment
|
|
32
60
|
|
|
33
|
-
# 5.1.
|
|
34
|
-
- **changed**: start with authentication if a proactive message has been set, so if a rule has been set on at one chatbot in the project
|
|
35
|
-
|
|
36
|
-
# 5.1.26-rc2
|
|
37
|
-
- **changed**: start with authentication if hasCalloutInWidgetConfig is true
|
|
38
|
-
|
|
39
|
-
# 5.1.26-rc1
|
|
40
|
-
- **bug fixed**: improved audio recording/upload flow by ignoring empty recorder chunks, preserving the recorder MIME type when creating the audio blob/file, and uploading audio directly without Base64 conversion
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# 5.1.25-rc1
|
|
61
|
+
# 5.1.25
|
|
44
62
|
- **bug fixed**: attachment buttons in messages now respect the container max width and wrap/break long labels instead of being clipped
|
|
45
63
|
|
|
46
|
-
# 5.1.24
|
|
47
|
-
- **bug fixed**: minor fix in marked pipe to avoid rendering html tags
|
|
48
|
-
|
|
49
|
-
# 5.1.24-rc1
|
|
64
|
+
# 5.1.24
|
|
50
65
|
- **security**: hardened Markdown link rendering by blocking dangerous protocols (e.g. `javascript:`, `data:`, `vbscript:`) and preventing unsafe links from being rendered as anchors
|
|
51
66
|
- **changed**: refactored `MarkedPipe` to simplify Markdown parsing, improve link rendering via a custom `marked` renderer, and streamline newline handling (`\\n` → `\n`)
|
|
52
67
|
|
|
53
|
-
# 5.1.
|
|
68
|
+
# 5.1.23
|
|
69
|
+
- **changed**: API for upload a file/iamges
|
|
70
|
+
|
|
71
|
+
# 5.1.22
|
|
72
|
+
- **changed**: Updated Launch.js for Wix and Shopify by bypassing scrdoc
|
|
73
|
+
|
|
74
|
+
# 5.1.21
|
|
54
75
|
- **bug fixed**: saved the widget's size state to local storage (in HP conversations)
|
|
55
76
|
|
|
56
|
-
# 5.1.20
|
|
57
|
-
- **changed**: API for upload a file/iamges
|
|
77
|
+
# 5.1.20
|
|
58
78
|
- **changed**: marked pipe do not render /n
|
|
59
79
|
|
|
60
|
-
# 5.1.20-rc1
|
|
61
|
-
- **changed**: API for upload a file/iamges
|
|
62
|
-
|
|
63
80
|
# 5.1.19
|
|
64
|
-
|
|
65
|
-
# 5.1.19-rc1
|
|
66
81
|
- **bug fixed**: show bottom scroll button and unread message badge only when I'm not at the bottom of the page
|
|
67
82
|
- **changed**: allow HTML code to be inserted into messages, but do not parse the code. Ensure coexistence with Markdown.
|
|
68
83
|
- **bug fixed**: after sending a multi-line message, the text area remains open on multiple lines.
|
|
@@ -72,7 +87,6 @@
|
|
|
72
87
|
- **changed**: saved the widget's size state to local storage. The parameter flow is (default → storage → settings → URL)
|
|
73
88
|
|
|
74
89
|
# 5.1.18
|
|
75
|
-
# 5.1.15-rc3
|
|
76
90
|
- **added**: Implemented Shadow DOM in the text component to isolate HTML and Markdown rendering in a safe and protected context
|
|
77
91
|
- **changed**: Adapted text component styles to support Shadow DOM (removed ::ng-deep, added styles for common markdown elements)
|
|
78
92
|
- **security**: HTML/Markdown content is now rendered in an isolated Shadow DOM, improving security and preventing interference with the rest of the application
|
|
@@ -83,12 +97,6 @@
|
|
|
83
97
|
# 5.1.16
|
|
84
98
|
- **changed**: "close chat" header conversation menu button enabled in chatbot-panel.html
|
|
85
99
|
|
|
86
|
-
# 5.1.15-rc2
|
|
87
|
-
- **bug-fixed**: Bug fix for ifame message width
|
|
88
|
-
|
|
89
|
-
# 5.1.15-rc1
|
|
90
|
-
- **changed**: Load local translations before remote ones
|
|
91
|
-
|
|
92
100
|
# 5.1.15
|
|
93
101
|
- **changed**: Load local translations before remote ones
|
|
94
102
|
|
|
@@ -97,57 +105,22 @@
|
|
|
97
105
|
|
|
98
106
|
# 5.1.13
|
|
99
107
|
- **bug-fixed**: set default widget size
|
|
100
|
-
|
|
101
|
-
# 5.1.7-rc16
|
|
102
|
-
- **bug-fixed**: set default widget size
|
|
103
|
-
|
|
104
|
-
# 5.1.7-rc15
|
|
105
|
-
- **bug-fixed**: set the color of the buttons with visibility control to the font color
|
|
106
|
-
|
|
107
|
-
# 5.1.7-rc14
|
|
108
|
-
- **bug-fixed**: departmentId and departmentName is incorrect in attributes
|
|
109
|
-
|
|
110
|
-
# 5.1.7-rc13
|
|
111
|
-
- **changed**: Force authentication if ageChangeVisibilityDesktop or PageChangeVisibilityMobile is OPEN
|
|
112
|
-
|
|
113
|
-
# 5.1.7-rc12
|
|
114
|
-
- **changed**: Force authentication if ageChangeVisibilityDesktop or PageChangeVisibilityMobile is OPEN
|
|
115
|
-
- **changed**: Set the default autoStart value to false
|
|
116
|
-
- **added**: Added the open widget loading spinner
|
|
117
|
-
- **changed**: Load the widget without authentication and display the speech bubble
|
|
118
|
-
|
|
119
|
-
# 5.1.7-rc11
|
|
120
|
-
- **changed**: set default value autoStart false
|
|
121
|
-
- **added**:added loading spinner
|
|
122
|
-
|
|
123
|
-
# 5.1.7-rc10
|
|
124
|
-
- **changed**: load widget without authentication and display the balloon
|
|
125
|
-
|
|
126
|
-
# 5.1.7-rc9
|
|
127
|
-
- **removed**: 'DOMAIN_NOT_ALLOWED' in textarea footer component
|
|
128
|
-
|
|
129
|
-
# 5.1.7-rc8
|
|
130
|
-
# changes in the branch
|
|
131
|
-
- **changed**: Load local translations before remote ones
|
|
132
|
-
- **bug-fixed**: set default widget size
|
|
133
108
|
- **changed**: Updated the translations of the tooltips in the footer-component
|
|
134
109
|
- **changed**: Refactored the network-offline component and made it generic for displaying errors (now error-alert.component)
|
|
135
|
-
|
|
136
|
-
# 5.1.7-rc7
|
|
137
|
-
- **bug-fixed**: button new_conversation always appear. added subscription to conversationAdded
|
|
138
|
-
|
|
139
|
-
# 5.1.7-rc6
|
|
140
|
-
- **added**: Added MAX_ATTACHMENT_ERROR error message when uploading a file larger than 10 MB
|
|
110
|
+
- **bug-fixed**: set the color of the buttons with visibility control to the font color (setButtonColors function)
|
|
141
111
|
|
|
142
112
|
# 5.1.12
|
|
143
113
|
- **bug-fixed**: check showEmojiFooterButton to enable/disable emojii
|
|
144
114
|
- **bug-fixed**: markdown is fired as an emojii and blocked by isEmojii check fn
|
|
145
115
|
|
|
116
|
+
<<<<<<< HEAD
|
|
117
|
+
=======
|
|
146
118
|
# 5.1.7-rc7
|
|
147
119
|
- **bug-fixed**: button new_conversation always appear. added subscription to conversationAdded
|
|
148
120
|
|
|
149
121
|
# 5.1.7-rc6
|
|
150
122
|
- **added**: Added MAX_ATTACHMENT_ERROR error message when uploading a file larger than 10 MB
|
|
123
|
+
>>>>>>> master-pre
|
|
151
124
|
|
|
152
125
|
# 5.1.7-rc5
|
|
153
126
|
- **bug-fixed**: bug fixed BUTTON STYLES
|
package/angular.json
CHANGED
package/deploy_amazon_beta.sh
CHANGED
|
@@ -2,16 +2,8 @@
|
|
|
2
2
|
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
3
|
echo "version $version"
|
|
4
4
|
|
|
5
|
-
npm i
|
|
6
|
-
|
|
7
|
-
cp src/environments/real_data/environment.pre.ts src/environments/environment.pre.ts
|
|
8
|
-
|
|
9
5
|
ng build --configuration="pre" --aot=true --base-href
|
|
10
6
|
|
|
11
|
-
### SET HASHING : START ###
|
|
12
|
-
cp ./src/launch_template.js ./dist/browser/launch.js
|
|
13
|
-
node ./src/build_launch.js
|
|
14
|
-
### SET HASHING : END ###
|
|
15
7
|
|
|
16
8
|
# ########## --->>>> NATIVE-MQTT folder START <<<<<------ ########## #
|
|
17
9
|
|
|
@@ -31,17 +23,15 @@ node ./src/build_launch.js
|
|
|
31
23
|
|
|
32
24
|
|
|
33
25
|
# ########## --->>>> FIREBASE folder START <<<<<------ ########## #
|
|
34
|
-
cd dist
|
|
35
|
-
aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ --cache-control max-age=300
|
|
36
|
-
aws s3 sync . s3://tiledesk-widget-pre/v5
|
|
37
|
-
|
|
38
|
-
aws s3 sync . s3://tiledesk-widget-pre/v5/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
39
|
-
cd ../..
|
|
26
|
+
cd dist
|
|
27
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ --cache-control max-age=300
|
|
28
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/ --cache-control max-age=300
|
|
29
|
+
cd ..
|
|
40
30
|
|
|
41
|
-
aws cloudfront create-invalidation --distribution-id
|
|
42
|
-
|
|
43
|
-
git restore src/environments/environment.pre.ts
|
|
31
|
+
#aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*"
|
|
32
|
+
cd ..
|
|
44
33
|
|
|
34
|
+
aws cloudfront create-invalidation --distribution-id E2V5O0YPR61V8P --paths "/*"
|
|
45
35
|
# echo new version deployed $NEW_VER/$NEW_BUILD/ on s3://tiledesk-widget-pre/v2
|
|
46
36
|
echo new version deployed $version/ on s3://tiledesk-widget-pre/v5 and s3://tiledesk-widget-pre/v5/$version/
|
|
47
37
|
echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget-pre/v5/index.html
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# npm version patch
|
|
2
|
+
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
|
+
echo "version $version"
|
|
4
|
+
|
|
5
|
+
npm i
|
|
6
|
+
|
|
7
|
+
cp src/environments/real_data/environment.prod.ts src/environments/environment.prod.ts
|
|
8
|
+
|
|
9
|
+
# --build-optimizer=false if localstorage is disabled (webview) appears https://github.com/firebase/angularfire/issues/970
|
|
10
|
+
ng build --configuration="prod" --aot=true
|
|
11
|
+
##--base-href='./v5/' --output-hashing none
|
|
12
|
+
|
|
13
|
+
### SET HASHING : START ###
|
|
14
|
+
cp ./src/launch_template.js ./dist/browser/launch.js
|
|
15
|
+
node ./src/build_launch.js
|
|
16
|
+
### SET HASHING : END ###
|
|
17
|
+
|
|
18
|
+
#### FIREBASE #####
|
|
19
|
+
# cd dist
|
|
20
|
+
# # aws s3 sync . s3://tiledesk-widget/v5/latest/
|
|
21
|
+
# aws s3 sync . s3://tiledesk-widget/v5/$version/ --cache-control max-age=300
|
|
22
|
+
# aws s3 sync . s3://tiledesk-widget/v5/ --cache-control max-age=300
|
|
23
|
+
# cd ..
|
|
24
|
+
|
|
25
|
+
# #### MQTT #####
|
|
26
|
+
cd dist/browser
|
|
27
|
+
# aws s3 sync . s3://tiledesk-widget/v5/latest/
|
|
28
|
+
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
29
|
+
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
30
|
+
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
31
|
+
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
32
|
+
cd ../..
|
|
33
|
+
|
|
34
|
+
aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*"
|
|
35
|
+
|
|
36
|
+
git restore src/environments/environment.prod.ts
|
|
37
|
+
|
|
38
|
+
echo new version deployed $version on s3://tiledesk-widget/v6
|
|
39
|
+
echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget/v6/index.html
|
|
40
|
+
echo https://widget.tiledesk.com/v6/index.html
|
|
41
|
+
echo https://widget.tiledesk.com/v6/$version/index.html
|
|
@@ -1,3 +1,50 @@
|
|
|
1
|
+
# Questo branch: UX bot/umano + disaccoppiamento callout
|
|
2
|
+
|
|
3
|
+
## Contesto
|
|
4
|
+
|
|
5
|
+
Questo branch migliora il feedback in conversazione e rende il comportamento del callout indipendente dal sign-in del widget.
|
|
6
|
+
|
|
7
|
+
## Modifiche incluse
|
|
8
|
+
|
|
9
|
+
- Aggiunto un **badge Bot/Umano** nella vista conversazione.
|
|
10
|
+
- All'apertura della conversazione analizza **l'ultimo messaggio ricevuto dal server** (escludendo quelli inviati dal client).
|
|
11
|
+
- Classifica il mittente come `Bot` o `Umano`.
|
|
12
|
+
- Regola speciale: se l'ultimo evento di sistema rilevante e' `MEMBER_JOINED_GROUP` (handoff verso operatore), la conversazione viene classificata come **Umano**.
|
|
13
|
+
|
|
14
|
+
- Aggiunto il feedback temporaneo **"sto pensando..."** dopo l'invio del messaggio da parte del client.
|
|
15
|
+
- Mostrato solo quando la conversazione e' classificata come **Bot**.
|
|
16
|
+
- Nascosto alla prima risposta server, con durata minima visibile di 5 secondi.
|
|
17
|
+
|
|
18
|
+
- Rimossa l'implementazione temporanea del toast "ciao" nel footer e relativo wiring.
|
|
19
|
+
|
|
20
|
+
- Abilitato il percorso di avvio widget per i casi guidati da bot quando sono presenti `botsRules`.
|
|
21
|
+
|
|
22
|
+
## Disaccoppiamento callout (step completati)
|
|
23
|
+
|
|
24
|
+
- **Step 1**: rimossa la dipendenza da `g.senderId` nel rendering del componente callout in `app.component.html`.
|
|
25
|
+
- Prima: render solo con `g.senderId && !g.isOpenNewMessage`
|
|
26
|
+
- Dopo: render con `!g.isOpenNewMessage`
|
|
27
|
+
|
|
28
|
+
- **Step 2**: scheduling del callout al caricamento delle impostazioni widget in `AppComponent`.
|
|
29
|
+
- Aggiunto `scheduleCalloutFromSettings()` basato su `g.calloutTimer`.
|
|
30
|
+
- Invocato subito dopo la disponibilita' delle settings (non legato al login).
|
|
31
|
+
- Aggiunta la pulizia del timeout in `ngOnDestroy()`.
|
|
32
|
+
|
|
33
|
+
- **Step 3**: introdotte precedenze UI e rimossa la duplicazione dello scheduling callout.
|
|
34
|
+
- Aggiunta guardia `canShowCalloutNow()` in `AppComponent`:
|
|
35
|
+
- widget chiuso
|
|
36
|
+
- nessuna preview nuovo messaggio attiva
|
|
37
|
+
- stato callout abilitato
|
|
38
|
+
- callout presente nella configurazione widget
|
|
39
|
+
- Aggiornato `showCallout()` per aprire il callout solo quando le guardie passano e il componente esiste.
|
|
40
|
+
- Rimosso il timer interno (`openIfCallOutTimer`) da `EyeeyeCatcherCardComponent` per evitare doppi trigger.
|
|
41
|
+
|
|
42
|
+
## Comportamento atteso dopo questo branch
|
|
43
|
+
|
|
44
|
+
- Il callout puo' essere innescato da configurazione anche senza sign-in.
|
|
45
|
+
- Il callout non compare quando il widget e' aperto o quando la preview nuovo messaggio e' attiva.
|
|
46
|
+
- La UI della conversazione indica chiaramente se l'ultimo responder e' bot o umano.
|
|
47
|
+
- "Sto pensando..." compare solo nelle conversazioni bot e ha un comportamento prevedibile.
|
|
1
48
|
# This branch: identificazione bot o umano
|
|
2
49
|
|
|
3
50
|
## Obiettivo
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chat21/chat21-web-widget",
|
|
3
3
|
"author": "Tiledesk SRL",
|
|
4
|
-
"version": "5.1.
|
|
4
|
+
"version": "5.1.32-rc1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.tiledesk.com",
|
|
7
7
|
"repository": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"ng": "ng",
|
|
13
|
+
"copy-onnx-wasm": "mkdir -p src/assets/onnx && cp node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.wasm src/assets/onnx/",
|
|
13
14
|
"start": "ng serve",
|
|
14
15
|
"build": "ng build",
|
|
15
16
|
"test": "ng test",
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"@ctrl/ngx-emoji-mart": "^9.2.0",
|
|
33
34
|
"@ngx-translate/core": "^16.0.4",
|
|
34
35
|
"@ngx-translate/http-loader": "^16.0.1",
|
|
36
|
+
"@ricky0123/vad-web": "^0.0.30",
|
|
35
37
|
"accept-language-parser": "^1.5.0",
|
|
36
38
|
"bootstrap": "^5.1.3",
|
|
37
39
|
"dayjs": "^1.11.7",
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
"humanize-duration-ts": "^2.1.1",
|
|
41
43
|
"marked": "^16.3.0",
|
|
42
44
|
"ngx-logger": "^5.0.11",
|
|
45
|
+
"onnxruntime-web": "^1.24.3",
|
|
43
46
|
"replace": "^1.2.2",
|
|
44
47
|
"rxjs": "^7.8.2",
|
|
45
48
|
"source-map-explorer": "^2.5.3",
|
package/src/app/app.component.ts
CHANGED
|
@@ -116,7 +116,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
116
116
|
errorMessage: string = '';
|
|
117
117
|
errorKeyMessage: string = null;
|
|
118
118
|
errorParams: Record<string, any> = {};
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
private logger: LoggerService = LoggerInstance.getInstance();
|
|
121
121
|
constructor(
|
|
122
122
|
private el: ElementRef,
|
|
@@ -526,7 +526,6 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
526
526
|
this.g.onPageChangeVisibilityMobile === 'open' ||
|
|
527
527
|
(Array.isArray(this.g.botsRules) && this.g.botsRules.length > 0)
|
|
528
528
|
// || this.g.hasCalloutInWidgetConfig;
|
|
529
|
-
console.log('[APP-COMP] shouldAutoAuthenticate', shouldAutoAuthenticate, startHidden)
|
|
530
529
|
if (shouldAutoAuthenticate) {
|
|
531
530
|
that.authenticate();
|
|
532
531
|
if(startHidden){ that.hideWidget(); }
|
package/src/app/app.module.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { InfoMessageComponent } from './component/message/info-message/info-mess
|
|
|
25
25
|
import { HtmlComponent } from './component/message/html/html.component';
|
|
26
26
|
import { FrameComponent } from './component/message/frame/frame.component';
|
|
27
27
|
import { AudioComponent } from './component/message/audio/audio.component';
|
|
28
|
+
import { AudioSyncComponent } from './component/message/audio-sync/audio-sync.component';
|
|
28
29
|
import { UserTypingComponent } from './../chat21-core/utils/user-typing/user-typing.component';
|
|
29
30
|
/** MESSAGE ATTACHMENTS COMPONENTS */
|
|
30
31
|
import { MessageAttachmentComponent } from './component/message-attachment/message-attachment.component';
|
|
@@ -136,6 +137,11 @@ import { Rules } from './utils/rules';
|
|
|
136
137
|
import { ScriptService } from 'src/chat21-core/providers/scripts/script.service';
|
|
137
138
|
import { CarouselComponent } from './component/message/carousel/carousel.component';
|
|
138
139
|
import { BrandService } from './providers/brand.service';
|
|
140
|
+
import { OpenAiVoiceProviderService } from './providers/voice/STT&TTS/openai-voice.provider';
|
|
141
|
+
import {
|
|
142
|
+
SpeechToTextProvider,
|
|
143
|
+
TextToSpeechProvider,
|
|
144
|
+
} from './providers/voice/STT&TTS/speech-provider.abstract';
|
|
139
145
|
import { ErrorAlertComponent } from './component/error-alert/error-alert.component';
|
|
140
146
|
import { ConfirmCloseComponent } from './modals/confirm-close/confirm-close.component';
|
|
141
147
|
|
|
@@ -300,6 +306,7 @@ export function uploadFactory(http: HttpClient, appConfig: AppConfigService, app
|
|
|
300
306
|
LinkButtonComponent,
|
|
301
307
|
TextButtonComponent,
|
|
302
308
|
AudioComponent,
|
|
309
|
+
AudioSyncComponent,
|
|
303
310
|
UserTypingComponent,
|
|
304
311
|
/**DIRECTIVES */
|
|
305
312
|
HtmlEntitiesEncodePipe,
|
|
@@ -405,6 +412,8 @@ export function uploadFactory(http: HttpClient, appConfig: AppConfigService, app
|
|
|
405
412
|
WaitingService,
|
|
406
413
|
ScriptService,
|
|
407
414
|
BrandService,
|
|
415
|
+
{ provide: SpeechToTextProvider, useExisting: OpenAiVoiceProviderService },
|
|
416
|
+
{ provide: TextToSpeechProvider, useExisting: OpenAiVoiceProviderService },
|
|
408
417
|
provideHttpClient(withInterceptorsFromDi())
|
|
409
418
|
],
|
|
410
419
|
bootstrap: [AppComponent]
|
|
@@ -64,7 +64,9 @@
|
|
|
64
64
|
[nameUserTypingNow]="nameUserTypingNow"
|
|
65
65
|
[typingLocation]="g?.typingLocation"
|
|
66
66
|
[showThinkingMessage]="showThinkingMessage"
|
|
67
|
+
[lastServerSenderKind]="lastServerSenderKind"
|
|
67
68
|
[fullscreenMode]="g?.fullscreenMode"
|
|
69
|
+
[isStreamAudioActive]="isStreamAudioActive"
|
|
68
70
|
[translationMap]="translationMapContent"
|
|
69
71
|
[stylesMap]="stylesMap"
|
|
70
72
|
(onBeforeMessageRender)="onBeforeMessageRenderFN($event)"
|
|
@@ -131,6 +133,7 @@
|
|
|
131
133
|
[showAttachmentFooterButton]="g?.showAttachmentFooterButton"
|
|
132
134
|
[showEmojiFooterButton]="g?.showEmojiFooterButton"
|
|
133
135
|
[showAudioRecorderFooterButton]="g?.showAudioRecorderFooterButton"
|
|
136
|
+
[showAudioStreamFooterButton]="g?.showAudioStreamFooterButton"
|
|
134
137
|
[hideTextAreaContent]="(g?.singleConversation && hideTextAreaContent) || (isConversationArchived && !g?.allowReopen)"
|
|
135
138
|
[isConversationArchived]="isConversationArchived"
|
|
136
139
|
[hideTextReply]="hideFooterTextReply"
|
|
@@ -149,6 +152,7 @@
|
|
|
149
152
|
(onChangeTextArea)="onChangeTextArea($event)"
|
|
150
153
|
(onAttachmentFileButtonClicked)="onAttachmentFileButtonClicked($event)"
|
|
151
154
|
(onNewConversationButtonClicked)="onNewConversationButtonClickedFN($event)"
|
|
155
|
+
(onStreamAudioActiveChange)="onStreamAudioActiveChange($event)"
|
|
152
156
|
(onCloseChatButtonClicked)="onCloseChatButtonClickedFN($event)">
|
|
153
157
|
</chat-conversation-footer>
|
|
154
158
|
|
|
@@ -161,6 +161,10 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
161
161
|
membersConversation = ['SYSTEM'];
|
|
162
162
|
// ========== end:: typying =======
|
|
163
163
|
|
|
164
|
+
// ========== begin:: stream audio ======= //
|
|
165
|
+
public isStreamAudioActive = false;
|
|
166
|
+
// ========== end:: stream audio ======= //
|
|
167
|
+
|
|
164
168
|
@ViewChild(ConversationFooterComponent) conversationFooter: ConversationFooterComponent
|
|
165
169
|
@ViewChild(ConversationContentComponent) conversationContent: ConversationContentComponent
|
|
166
170
|
conversationHandlerService: ConversationHandlerService
|
|
@@ -1399,6 +1403,10 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
1399
1403
|
this.onNewConversationButtonClicked.emit()
|
|
1400
1404
|
}
|
|
1401
1405
|
|
|
1406
|
+
/** CALLED BY: conv-footer streaming audio button */
|
|
1407
|
+
onStreamAudioActiveChange(event: boolean){
|
|
1408
|
+
this.isStreamAudioActive = event
|
|
1409
|
+
}
|
|
1402
1410
|
/** CALLED BY: conv-footer component */
|
|
1403
1411
|
onCloseChatButtonClickedFN(event){
|
|
1404
1412
|
this.logger.debug('[CONV-COMP] onCloseChatButtonClicked::::', event)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<div *ngFor="let message of messages; let first = first; let last = last; let i = index" tabindex="1521" class="rowMsg">
|
|
23
23
|
|
|
24
24
|
<!-- message SENDER:: -->
|
|
25
|
-
<div role="messaggio" *ngIf="messageType(MESSAGE_TYPE_MINE, message)" class="msg_container base_sent">
|
|
25
|
+
<div role="messaggio" *ngIf="messageType(MESSAGE_TYPE_MINE, message) && (!isStreamAudioActive && !message.isJustRecived)" class="msg_container base_sent">
|
|
26
26
|
|
|
27
27
|
<!--backgroundColor non viene ancora usato -->
|
|
28
28
|
<!-- class="messages msg_sent slide-in-right" -->
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
</user-typing>
|
|
144
144
|
</div>
|
|
145
145
|
|
|
146
|
-
<div *ngIf="showThinkingMessage" class="msg_container base_receive thinking_receive">
|
|
146
|
+
<div *ngIf="showThinkingMessage && lastServerSenderKind === 'bot'" class="msg_container base_receive thinking_receive">
|
|
147
147
|
<user-typing class="loading thinking-dots"
|
|
148
148
|
[color]="stylesMap?.get('iconColor')"
|
|
149
149
|
[translationMap]="translationMap"
|
package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts
CHANGED
|
@@ -24,7 +24,9 @@ export class ConversationContentComponent implements OnInit {
|
|
|
24
24
|
@Input() nameUserTypingNow: string;
|
|
25
25
|
@Input() typingLocation: string;
|
|
26
26
|
@Input() showThinkingMessage: boolean;
|
|
27
|
+
@Input() lastServerSenderKind: 'bot' | 'human' | null;
|
|
27
28
|
@Input() fullscreenMode: boolean;
|
|
29
|
+
@Input() isStreamAudioActive: boolean;
|
|
28
30
|
@Input() translationMap: Map< string, string>;
|
|
29
31
|
@Input() stylesMap: Map<string, string>;
|
|
30
32
|
@Output() onBeforeMessageRender = new EventEmitter();
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html
CHANGED
|
@@ -12,6 +12,28 @@
|
|
|
12
12
|
<div tabindex="-1" class="alertText">{{translationMap.get('EMOJI_NOT_ELLOWED')}}</div>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
+
<!-- STREAM AUDIO: cerchio con onde animate -->
|
|
16
|
+
<div id="streamAudioAlert" *ngIf="!hideTextAreaContent && isStreamAudioActive" class="fade-in-bottom stream-audio-alert" [class.hideTextReply]="hideTextReply" role="status" [attr.aria-label]="translationMap?.get('STREAM_AUDIO_LISTENING') || 'Stream audio attivo'">
|
|
17
|
+
<div class="stream-audio-alert__orb" [ngStyle]="{ color: stylesMap?.get('themeColor') }">
|
|
18
|
+
<svg class="stream-audio-alert__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
19
|
+
<circle cx="50" cy="50" r="46" fill="currentColor" opacity="0.14"/>
|
|
20
|
+
<g class="stream-audio-alert__waves" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
|
|
21
|
+
<g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--1">
|
|
22
|
+
<path [attr.d]="wavePath1"></path>
|
|
23
|
+
</g>
|
|
24
|
+
|
|
25
|
+
<g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--2">
|
|
26
|
+
<path [attr.d]="wavePath2"></path>
|
|
27
|
+
</g>
|
|
28
|
+
|
|
29
|
+
<g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--3">
|
|
30
|
+
<path [attr.d]="wavePath3"></path>
|
|
31
|
+
</g>
|
|
32
|
+
</g>
|
|
33
|
+
</svg>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
15
37
|
</div>
|
|
16
38
|
|
|
17
39
|
<div class="textarea-container-wrapper" *ngIf="!hideTextAreaContent && !hideTextReply">
|
|
@@ -126,6 +148,26 @@
|
|
|
126
148
|
<div class="clear"></div>
|
|
127
149
|
</button>
|
|
128
150
|
</div>
|
|
151
|
+
|
|
152
|
+
<!-- ICON STREAM / CHIUDI STREAM (cerchio, icone bianche su iconColor) -->
|
|
153
|
+
<div *ngIf="showAudioStreamFooterButton" tabindex="-1" id="chat21-button-stream"
|
|
154
|
+
class="chat21-textarea-button chat21-stream-button" [class.active]="isStreamAudioActive || (!textInputTextArea && !hideTextReply)"
|
|
155
|
+
(click)="onStreamPressed($event)" [attr.aria-label]="isStreamAudioActive ? (translationMap?.get('CLOSE') || 'Chiudi stream') : (translationMap?.get('STREAM_AUDIO') || 'Stream audio')"
|
|
156
|
+
[ngStyle]="{ 'background-color': stylesMap?.get('iconColor') || stylesMap?.get('themeColor') }">
|
|
157
|
+
<span class="v-align-center chat21-stream-button__icon" *ngIf="!isStreamAudioActive">
|
|
158
|
+
<svg role="img" xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 30 30" fill="#ffffff" aria-hidden="true" preserveAspectRatio="xMidYMid meet">
|
|
159
|
+
<path class="s0" d="m5.21 7.41c-1.21 0-2.21 0.99-2.21 2.21v8.14c0 1.21 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-8.14c0-1.21-0.99-2.21-2.21-2.21z"/>
|
|
160
|
+
<path class="s0" d="m11.64 3.01c-1.22 0-2.21 0.99-2.21 2.2v16.94c0 1.21 0.99 2.2 2.21 2.2 1.22 0 2.21-0.98 2.21-2.2v-16.94c0-1.21-0.99-2.21-2.21-2.21z"/>
|
|
161
|
+
<path class="s0" d="m15.86 9.25v8.88c0 1.21 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-8.88c0-1.22-0.99-2.21-2.21-2.21-1.22 0-2.21 0.99-2.21 2.21z"/>
|
|
162
|
+
<path class="s0" d="m24.5 8.97c-1.22 0-2.21 0.99-2.21 2.21v5.02c0 1.22 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-5.02c0-1.21-0.99-2.21-2.21-2.21z"/>
|
|
163
|
+
</svg>
|
|
164
|
+
</span>
|
|
165
|
+
<span class="v-align-center chat21-stream-button__icon" *ngIf="isStreamAudioActive">
|
|
166
|
+
<svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ffffff" aria-hidden="true">
|
|
167
|
+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
|
|
168
|
+
</svg>
|
|
169
|
+
</span>
|
|
170
|
+
</div>
|
|
129
171
|
</div>
|
|
130
172
|
|
|
131
173
|
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss
CHANGED
|
@@ -84,6 +84,30 @@
|
|
|
84
84
|
border-radius: 50%;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/** Stream audio: cerchio pieno, glyph bianco su sfondo iconColor (stylesMap) */
|
|
88
|
+
.chat21-stream-button.chat21-textarea-button {
|
|
89
|
+
width: 36px;
|
|
90
|
+
height: 36px;
|
|
91
|
+
min-width: 36px;
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
box-sizing: border-box;
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
color: #ffffff;
|
|
96
|
+
|
|
97
|
+
.chat21-stream-button__icon svg {
|
|
98
|
+
width: 20px;
|
|
99
|
+
height: 20px;
|
|
100
|
+
path {
|
|
101
|
+
fill: #ffffff;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&.chat21-textarea-button span svg:hover {
|
|
106
|
+
background: rgba(255, 255, 255, 0.2) !important;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
87
111
|
textarea,
|
|
88
112
|
textarea:visited,
|
|
89
113
|
textarea:focus,
|
|
@@ -366,6 +390,73 @@ textarea:active{
|
|
|
366
390
|
}
|
|
367
391
|
}
|
|
368
392
|
|
|
393
|
+
#streamAudioAlert {
|
|
394
|
+
bottom: 100%;
|
|
395
|
+
width: 100%;
|
|
396
|
+
min-height: 96px;
|
|
397
|
+
display: flex;
|
|
398
|
+
align-items: center;
|
|
399
|
+
justify-content: center;
|
|
400
|
+
background-color: var(--content-background-color);
|
|
401
|
+
position: absolute;
|
|
402
|
+
padding: 10px 0;
|
|
403
|
+
|
|
404
|
+
&.hideTextReply {
|
|
405
|
+
position: unset;
|
|
406
|
+
min-height: auto;
|
|
407
|
+
padding: 16px 0;
|
|
408
|
+
box-shadow: none;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.stream-audio-alert__orb {
|
|
413
|
+
display: flex;
|
|
414
|
+
align-items: center;
|
|
415
|
+
justify-content: center;
|
|
416
|
+
width: 88px;
|
|
417
|
+
height: 88px;
|
|
418
|
+
border-radius: 50%;
|
|
419
|
+
border: 2px solid currentColor;
|
|
420
|
+
background: var(--content-background-color);
|
|
421
|
+
box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.04);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.stream-audio-alert__svg {
|
|
425
|
+
width: 72px;
|
|
426
|
+
height: 72px;
|
|
427
|
+
display: block;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.stream-audio-alert__wave-layer {
|
|
431
|
+
transform-origin: 50px 50px;
|
|
432
|
+
transform-box: fill-box;
|
|
433
|
+
animation: stream-wave-float 1.35s ease-in-out infinite;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.stream-audio-alert__wave-layer--1 {
|
|
437
|
+
animation-delay: 0s;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.stream-audio-alert__wave-layer--2 {
|
|
441
|
+
animation-delay: 0.18s;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.stream-audio-alert__wave-layer--3 {
|
|
445
|
+
animation-delay: 0.36s;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
@keyframes stream-wave-float {
|
|
449
|
+
0%,
|
|
450
|
+
100% {
|
|
451
|
+
transform: translateY(0);
|
|
452
|
+
opacity: 0.85;
|
|
453
|
+
}
|
|
454
|
+
50% {
|
|
455
|
+
transform: translateY(-6px);
|
|
456
|
+
opacity: 1;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
369
460
|
#textAlert{
|
|
370
461
|
bottom: 100%;
|
|
371
462
|
width: 100%;
|