@chat21/chat21-web-widget 5.1.30 → 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/.github/workflows/docker-community-push-latest.yml +23 -13
- package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
- package/CHANGELOG.md +38 -2
- package/Dockerfile +4 -5
- package/angular.json +5 -2
- package/docs/changelog/this-branch.md +36 -0
- package/package.json +4 -1
- package/src/app/app.component.ts +10 -9
- package/src/app/app.module.ts +9 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.html +7 -1
- package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -2
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +34 -5
- 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.scss +1 -1
- 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 +143 -78
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +131 -13
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +108 -7
- package/src/app/component/last-message/last-message.component.ts +4 -1
- 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 +21 -0
- package/src/app/providers/translator.service.ts +2 -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/sass/_variables.scss +1 -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 +7 -1
- package/src/assets/i18n/en.json +1 -0
- package/src/assets/i18n/es.json +1 -0
- package/src/assets/i18n/fr.json +1 -0
- package/src/assets/i18n/it.json +1 -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/providers/tiledesk/tiledesk-requests.service.ts +1 -1
- package/src/chat21-core/utils/utils-message.ts +7 -0
- package/src/chat21-core/utils/utils.ts +5 -2
- package/tsconfig.json +5 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
name: Docker Image Community latest CI
|
|
2
2
|
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
5
|
branches: [ master ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master ]
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
push_to_registry:
|
|
@@ -12,12 +12,22 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
|
|
14
14
|
steps:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
- name: Check out the repo
|
|
16
|
+
uses: actions/checkout@v2
|
|
17
|
+
|
|
18
|
+
- name: Set up Docker Buildx
|
|
19
|
+
uses: docker/setup-buildx-action@v2
|
|
20
|
+
|
|
21
|
+
- name: Log in to Docker Hub
|
|
22
|
+
uses: docker/login-action@v2
|
|
23
|
+
with:
|
|
24
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
25
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
26
|
+
|
|
27
|
+
- name: Build and push multiarch Docker image
|
|
28
|
+
uses: docker/build-push-action@v3
|
|
29
|
+
with:
|
|
30
|
+
context: .
|
|
31
|
+
push: true
|
|
32
|
+
platforms: linux/amd64,linux/arm64
|
|
33
|
+
tags: chat21/chat21-web-widget:latest
|
|
@@ -3,20 +3,30 @@ name: Publish Docker Community image tags
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
tags:
|
|
6
|
-
- '**'
|
|
7
|
-
jobs:
|
|
6
|
+
- '**' # Trigger su qualsiasi tag
|
|
8
7
|
|
|
8
|
+
jobs:
|
|
9
9
|
push_to_registry:
|
|
10
10
|
name: Push Docker image to Docker Hub
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
|
+
|
|
12
13
|
steps:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
- name: Check out the repo
|
|
15
|
+
uses: actions/checkout@v2
|
|
16
|
+
|
|
17
|
+
- name: Set up Docker Buildx
|
|
18
|
+
uses: docker/setup-buildx-action@v2
|
|
19
|
+
|
|
20
|
+
- name: Log in to Docker Hub
|
|
21
|
+
uses: docker/login-action@v2
|
|
22
|
+
with:
|
|
23
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
24
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
25
|
+
|
|
26
|
+
- name: Build and push multiarch Docker image
|
|
27
|
+
uses: docker/build-push-action@v3
|
|
28
|
+
with:
|
|
29
|
+
context: .
|
|
30
|
+
push: true
|
|
31
|
+
platforms: linux/amd64,linux/arm64
|
|
32
|
+
tags: chat21/chat21-web-widget:${{ github.ref_name }}
|
package/CHANGELOG.md
CHANGED
|
@@ -6,11 +6,25 @@
|
|
|
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
|
+
|
|
9
17
|
# 5.1.30
|
|
10
18
|
- **bug fixed**: startHidden is not working properly
|
|
11
19
|
|
|
12
|
-
# 5.1.
|
|
13
|
-
- **bug fixed**:
|
|
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
|
+
|
|
26
|
+
# 5.1.30-rc1
|
|
27
|
+
- **bug fixed**: startHidden is not working properly
|
|
14
28
|
|
|
15
29
|
# 5.1.28
|
|
16
30
|
- **bug fixed**: fixed Bot/Human conversation detection by correctly classifying bot replies
|
|
@@ -22,8 +36,22 @@
|
|
|
22
36
|
- **changed**: Set the default autoStart value to false
|
|
23
37
|
- **added**: Added the open widget loading spinner
|
|
24
38
|
- **changed**: Load the widget without authentication and display the speech bubble
|
|
39
|
+
|
|
40
|
+
# 5.1.27-rc3
|
|
41
|
+
- **bug fixed**: fixed Bot/Human conversation detection by correctly classifying bot replies
|
|
42
|
+
|
|
43
|
+
# 5.1.27-rc2
|
|
44
|
+
- **bug fixed**: centralized fullscreen management on mobile and handled the case of the closed widget that remained fullscreen
|
|
45
|
+
|
|
46
|
+
# 5.1.27-rc1
|
|
47
|
+
- **added**: closeChatInConversation parameters
|
|
48
|
+
- **added**: close chat button under textarea footer component
|
|
49
|
+
|
|
50
|
+
# 5.1.26-rc6
|
|
25
51
|
- **changed**: mobile always opens fullscreen and ignores legacy stored size”.
|
|
26
52
|
- **changed**: changed user-typing
|
|
53
|
+
|
|
54
|
+
# 5.1.26-rc5
|
|
27
55
|
- **changed**: Hide the resize-widget button when on mobile
|
|
28
56
|
- **added**: added "I'm thinking" when the bot responds
|
|
29
57
|
|
|
@@ -85,6 +113,14 @@
|
|
|
85
113
|
- **bug-fixed**: check showEmojiFooterButton to enable/disable emojii
|
|
86
114
|
- **bug-fixed**: markdown is fired as an emojii and blocked by isEmojii check fn
|
|
87
115
|
|
|
116
|
+
<<<<<<< HEAD
|
|
117
|
+
=======
|
|
118
|
+
# 5.1.7-rc7
|
|
119
|
+
- **bug-fixed**: button new_conversation always appear. added subscription to conversationAdded
|
|
120
|
+
|
|
121
|
+
# 5.1.7-rc6
|
|
122
|
+
- **added**: Added MAX_ATTACHMENT_ERROR error message when uploading a file larger than 10 MB
|
|
123
|
+
>>>>>>> master-pre
|
|
88
124
|
|
|
89
125
|
# 5.1.7-rc5
|
|
90
126
|
- **bug-fixed**: bug fixed BUTTON STYLES
|
package/Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
### STAGE 1: Build ###
|
|
2
2
|
|
|
3
3
|
# We label our stage as ‘builder’
|
|
4
|
-
FROM node:20.12.2-alpine3.19 as builder
|
|
4
|
+
FROM --platform=$BUILDPLATFORM node:20.12.2-alpine3.19 as builder
|
|
5
5
|
|
|
6
6
|
COPY package.json package-lock.json ./
|
|
7
7
|
|
|
@@ -15,12 +15,11 @@ COPY . .
|
|
|
15
15
|
|
|
16
16
|
## Build the angular app in production mode and store the artifacts in dist folder
|
|
17
17
|
|
|
18
|
-
RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
|
|
19
18
|
|
|
19
|
+
RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
|
|
20
20
|
|
|
21
21
|
### STAGE 2: Setup ###
|
|
22
|
-
|
|
23
|
-
FROM nginx:1.14.1-alpine
|
|
22
|
+
FROM --platform=$BUILDPLATFORM nginx:1.14.1-alpine
|
|
24
23
|
|
|
25
24
|
## Copy our default nginx config
|
|
26
25
|
COPY nginx.conf /etc/nginx/nginx.conf
|
|
@@ -33,4 +32,4 @@ COPY --from=builder /ng-app/dist/browser /usr/share/nginx/html
|
|
|
33
32
|
|
|
34
33
|
RUN echo "Chat21 Web Widget Started!!"
|
|
35
34
|
|
|
36
|
-
CMD ["/bin/sh",
|
|
35
|
+
CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/widget-config-template.json > /usr/share/nginx/html/widget-config.json && exec nginx -g 'daemon off;'"]
|
package/angular.json
CHANGED
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"src/environments/real_data/widget-config-docker.json",
|
|
45
45
|
"src/environments/real_data/widget-config-native-mqtt.json",
|
|
46
46
|
"src/environments/real_data/widget-config-native-prod.json",
|
|
47
|
-
"src/environments/real_data/widget-config-aws-stage.json"
|
|
47
|
+
"src/environments/real_data/widget-config-aws-stage.json",
|
|
48
|
+
"src/environments/real_data/widget-config-aws-aruba.json"
|
|
48
49
|
],
|
|
49
50
|
"styles": [
|
|
50
51
|
"src/app/sass/styles.scss"
|
|
@@ -59,7 +60,9 @@
|
|
|
59
60
|
"idb",
|
|
60
61
|
"accept-language-parser",
|
|
61
62
|
"file-saver",
|
|
62
|
-
"dayjs"
|
|
63
|
+
"dayjs",
|
|
64
|
+
"onnxruntime-web",
|
|
65
|
+
"@ricky0123/vad-web"
|
|
63
66
|
],
|
|
64
67
|
"sourceMap": true,
|
|
65
68
|
"optimization": false,
|
|
@@ -45,3 +45,39 @@ Questo branch migliora il feedback in conversazione e rende il comportamento del
|
|
|
45
45
|
- Il callout non compare quando il widget e' aperto o quando la preview nuovo messaggio e' attiva.
|
|
46
46
|
- La UI della conversazione indica chiaramente se l'ultimo responder e' bot o umano.
|
|
47
47
|
- "Sto pensando..." compare solo nelle conversazioni bot e ha un comportamento prevedibile.
|
|
48
|
+
# This branch: identificazione bot o umano
|
|
49
|
+
|
|
50
|
+
## Obiettivo
|
|
51
|
+
|
|
52
|
+
In questo branch e' stata introdotta una logica esplicita per capire, all'apertura della conversazione, se l'ultimo responder lato server e' un **bot** oppure un **umano**.
|
|
53
|
+
|
|
54
|
+
## Come viene fatta l'identificazione
|
|
55
|
+
|
|
56
|
+
- La valutazione parte dai messaggi gia' caricati in conversazione.
|
|
57
|
+
- Viene cercato l'**ultimo messaggio ricevuto dal server** (non inviato dal client corrente).
|
|
58
|
+
- Quel messaggio viene classificato con una funzione dedicata (`classifyMessageSenderKind`) che usa piu' segnali:
|
|
59
|
+
- `attributes.flowAttributes.chatbot_id` (quando presente indica bot)
|
|
60
|
+
- pattern del mittente (es. `senderId` con prefisso bot, quando applicabile)
|
|
61
|
+
- informazioni del mittente (`sender_fullname` e metadati associati)
|
|
62
|
+
|
|
63
|
+
## Regola speciale per messaggi di sistema
|
|
64
|
+
|
|
65
|
+
Se l'ultimo messaggio utile e' di tipo `system`, viene fatto un controllo aggiuntivo:
|
|
66
|
+
|
|
67
|
+
- se in `attributes` e' presente un evento con `messagelabel.key = MEMBER_JOINED_GROUP`
|
|
68
|
+
- e rappresenta il passaggio della conversazione a un operatore
|
|
69
|
+
|
|
70
|
+
allora la conversazione viene forzata a **Umano** anche se altri indizi potrebbero suggerire bot.
|
|
71
|
+
|
|
72
|
+
## Risultato in UI
|
|
73
|
+
|
|
74
|
+
- In apertura conversazione viene mostrato un badge con stato:
|
|
75
|
+
- `Bot`
|
|
76
|
+
- `Umano`
|
|
77
|
+
- Questo stato viene ricalcolato al variare dei messaggi ricevuti.
|
|
78
|
+
|
|
79
|
+
## Effetto sui feedback utente
|
|
80
|
+
|
|
81
|
+
- Il messaggio temporaneo `"sto pensando..."` viene mostrato solo quando la conversazione risulta di tipo **Bot**.
|
|
82
|
+
- Alla ricezione della prima risposta dal server, `"sto pensando..."` viene nascosto **immediatamente**.
|
|
83
|
+
- Non e' previsto alcun tempo minimo di visualizzazione del messaggio.
|
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
|
@@ -106,17 +106,16 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
106
106
|
|
|
107
107
|
forceDisconnect: boolean = false;
|
|
108
108
|
|
|
109
|
+
//network status
|
|
110
|
+
isOnline: boolean = true;
|
|
111
|
+
loading: boolean = false;
|
|
112
|
+
private calloutScheduleTimeout: any = null;
|
|
113
|
+
|
|
109
114
|
// alert error message
|
|
110
115
|
isShowErrorMessage: boolean = false;
|
|
111
116
|
errorMessage: string = '';
|
|
112
117
|
errorKeyMessage: string = null;
|
|
113
118
|
errorParams: Record<string, any> = {};
|
|
114
|
-
|
|
115
|
-
//network status
|
|
116
|
-
isOnline: boolean = true;
|
|
117
|
-
|
|
118
|
-
loading: boolean = false;
|
|
119
|
-
private calloutScheduleTimeout: any = null;
|
|
120
119
|
|
|
121
120
|
private logger: LoggerService = LoggerInstance.getInstance();
|
|
122
121
|
constructor(
|
|
@@ -170,13 +169,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
170
169
|
if (conversation.attributes && conversation.attributes['subtype'] === 'info') {
|
|
171
170
|
return;
|
|
172
171
|
}
|
|
173
|
-
if (conversation.is_new &&
|
|
172
|
+
if (conversation.is_new && that.isInitialized) {
|
|
174
173
|
that.manageTabNotification(false, 'conv-added')
|
|
175
174
|
// this.soundMessage();
|
|
176
175
|
}
|
|
177
|
-
if(this.g.isOpen === false){
|
|
178
|
-
that.lastConversation = conversation;
|
|
176
|
+
if(this.g.isOpen === false && conversation.sender !== this.g.senderId && !isInfo(conversation)){
|
|
179
177
|
that.g.isOpenNewMessage = true;
|
|
178
|
+
that.lastConversation = conversation;
|
|
180
179
|
}
|
|
181
180
|
} else {
|
|
182
181
|
//widget closed
|
|
@@ -224,6 +223,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
224
223
|
that.lastConversation = conversation;
|
|
225
224
|
that.g.isOpenNewMessage = true;
|
|
226
225
|
that.logger.debug('[APP-COMP] lastconversationnn', that.lastConversation)
|
|
226
|
+
that.logger.debug('[APP-COMP] lastconversationnn message' + JSON.stringify(that.lastConversation?.attributes?.commands))
|
|
227
227
|
}
|
|
228
228
|
let badgeNewConverstionNumber = that.conversationsHandlerService.countIsNew()
|
|
229
229
|
that.g.setParameter('conversationsBadge', badgeNewConverstionNumber);
|
|
@@ -2319,6 +2319,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
2319
2319
|
this.el.nativeElement.style.setProperty('--chat-header-height', this.g.hideHeaderConversation? '0px': null)
|
|
2320
2320
|
this.el.nativeElement.style.setProperty('--font-size-bubble-message', this.g.fontSize)
|
|
2321
2321
|
this.el.nativeElement.style.setProperty('--font-family-bubble-message', this.g.fontFamily)
|
|
2322
|
+
this.el.nativeElement.style.setProperty('--chat-footer-close-button-height', this.g.closeChatInConversation? '30px': '0px')
|
|
2322
2323
|
|
|
2323
2324
|
}
|
|
2324
2325
|
|
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,12 +133,14 @@
|
|
|
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"
|
|
137
140
|
[isMobile]="g?.isMobile"
|
|
138
141
|
[isEmojiiPickerShow]="isEmojiiPickerShow"
|
|
139
142
|
[footerMessagePlaceholder]="footerMessagePlaceholder"
|
|
143
|
+
[closeChatInConversation]="g?.closeChatInConversation"
|
|
140
144
|
[fileUploadAccept]="g?.fileUploadAccept"
|
|
141
145
|
[dropEvent]="dropEvent"
|
|
142
146
|
[poweredBy]="g?.poweredBy"
|
|
@@ -147,7 +151,9 @@
|
|
|
147
151
|
(onAfterSendMessage)="onAfterSendMessageFN($event)"
|
|
148
152
|
(onChangeTextArea)="onChangeTextArea($event)"
|
|
149
153
|
(onAttachmentFileButtonClicked)="onAttachmentFileButtonClicked($event)"
|
|
150
|
-
(onNewConversationButtonClicked)="onNewConversationButtonClickedFN($event)"
|
|
154
|
+
(onNewConversationButtonClicked)="onNewConversationButtonClickedFN($event)"
|
|
155
|
+
(onStreamAudioActiveChange)="onStreamAudioActiveChange($event)"
|
|
156
|
+
(onCloseChatButtonClicked)="onCloseChatButtonClickedFN($event)">
|
|
151
157
|
</chat-conversation-footer>
|
|
152
158
|
|
|
153
159
|
</div>
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
#dropZone_container{
|
|
138
138
|
position: absolute;
|
|
139
139
|
top: 52px;
|
|
140
|
-
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height));
|
|
140
|
+
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + var(--chat-footer-close-button-height));
|
|
141
141
|
left: 0;
|
|
142
142
|
right: 0;
|
|
143
143
|
background-color: rgba(240,248,255,0.6);
|
|
@@ -240,7 +240,7 @@ dialog:-internal-dialog-in-top-layer{
|
|
|
240
240
|
|
|
241
241
|
|
|
242
242
|
::ng-deep .chat21-sheet-content{
|
|
243
|
-
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + 34px)!important;
|
|
243
|
+
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + var(--chat-footer-close-button-height) + 34px)!important;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
}
|
|
@@ -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
|
|
@@ -246,7 +250,8 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
246
250
|
'CONTINUE',
|
|
247
251
|
'EMOJI_NOT_ELLOWED',
|
|
248
252
|
'ATTACHMENT',
|
|
249
|
-
'EMOJI'
|
|
253
|
+
'EMOJI',
|
|
254
|
+
'CLOSE_CHAT'
|
|
250
255
|
];
|
|
251
256
|
|
|
252
257
|
const keysContent = [
|
|
@@ -501,7 +506,7 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
501
506
|
return this.isConversationArchived;
|
|
502
507
|
}
|
|
503
508
|
|
|
504
|
-
//FALLBACK TO TILEDESK
|
|
509
|
+
// //FALLBACK TO TILEDESK
|
|
505
510
|
const requests_list = await this.tiledeskRequestService.getMyRequests().catch(err => {
|
|
506
511
|
this.logger.error('[CONV-COMP] getConversationDetail: error getting request from Tiledesk', err);
|
|
507
512
|
this.isConversationArchived=true
|
|
@@ -519,9 +524,9 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
519
524
|
return this.isConversationArchived
|
|
520
525
|
}
|
|
521
526
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
527
|
+
this.isConversationArchived = false;
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
525
530
|
|
|
526
531
|
/**
|
|
527
532
|
* this.g.recipientId:
|
|
@@ -877,6 +882,20 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
877
882
|
this.subscriptions.push(subscribe);
|
|
878
883
|
}
|
|
879
884
|
|
|
885
|
+
subscribtionKey = 'conversationsAdded';
|
|
886
|
+
subscribtion = this.subscriptions.find(item => item.key === subscribtionKey);
|
|
887
|
+
if(!subscribtion){
|
|
888
|
+
|
|
889
|
+
subscribtion = this.chatManager.conversationsHandlerService.conversationChanged.pipe(takeUntil(this.unsubscribe$)).subscribe((conversation) => {
|
|
890
|
+
this.logger.debug('[CONV-COMP] ***** DATAIL conversationsChanged *****', conversation, this.conversationWith, this.isConversationArchived);
|
|
891
|
+
if(conversation && conversation.recipient === this.conversationId){
|
|
892
|
+
this.isConversationArchived = false
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
const subscribe = {key: subscribtionKey, value: subscribtion };
|
|
896
|
+
this.subscriptions.push(subscribe);
|
|
897
|
+
}
|
|
898
|
+
|
|
880
899
|
subscribtionKey = 'messageWait';
|
|
881
900
|
subscribtion = this.subscriptions.find(item => item.key === subscribtionKey);
|
|
882
901
|
if (!subscribtion) {
|
|
@@ -1383,6 +1402,16 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
1383
1402
|
this.logger.debug('[CONV-COMP] floating onNewConversationButtonClicked')
|
|
1384
1403
|
this.onNewConversationButtonClicked.emit()
|
|
1385
1404
|
}
|
|
1405
|
+
|
|
1406
|
+
/** CALLED BY: conv-footer streaming audio button */
|
|
1407
|
+
onStreamAudioActiveChange(event: boolean){
|
|
1408
|
+
this.isStreamAudioActive = event
|
|
1409
|
+
}
|
|
1410
|
+
/** CALLED BY: conv-footer component */
|
|
1411
|
+
onCloseChatButtonClickedFN(event){
|
|
1412
|
+
this.logger.debug('[CONV-COMP] onCloseChatButtonClicked::::', event)
|
|
1413
|
+
this.onCloseChat()
|
|
1414
|
+
}
|
|
1386
1415
|
// =========== END: event emitter function ====== //
|
|
1387
1416
|
|
|
1388
1417
|
|
|
@@ -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"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
top: 0;
|
|
45
45
|
right: 0;
|
|
46
46
|
left: 0;
|
|
47
|
-
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height));
|
|
47
|
+
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + var(--chat-footer-close-button-height));
|
|
48
48
|
overflow: hidden;
|
|
49
49
|
.time{
|
|
50
50
|
margin-bottom: 20px;
|
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();
|