@chat21/chat21-web-widget 5.1.32-rc2 → 5.1.32-rc4
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 +10 -0
- package/nginx.conf +22 -2
- package/package.json +1 -1
- package/src/app/component/conversation-detail/conversation/conversation.component.html +2 -1
- package/src/app/component/conversation-detail/conversation/conversation.component.scss +10 -0
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +11 -0
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +9 -0
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +12 -3
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +18 -2
- package/src/app/providers/voice/voice.service.ts +34 -4
- package/src/app/sass/_variables.scss +2 -0
- package/deploy_amazon_prod.sh +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
### **Copyrigth**:
|
|
7
7
|
*Tiledesk SRL*
|
|
8
8
|
|
|
9
|
+
# 5.1.32-rc4
|
|
10
|
+
- **added**: Pulsante “chiudi stream” (`.close-stream-button`) — offset del contenuto e del foglio in fullscreen usando `--chat-footer-stream-button-height` solo mentre lo stream è in ascolto (`isStreamAudioActive`); variabili in `_variables.scss`.
|
|
11
|
+
- **added**: `VoiceService.discardCurrentRecordingSegment()` — in arrivo un messaggio da altro mittente durante lo stream, si scarta il segmento WebM corrente (nessun upload) senza chiudere mic/VAD; `interruptStreamDueToPeerMessage()` nel footer non spegne più `isStreamAudioActive`.
|
|
12
|
+
- **changed**: `#streamAudioAlert` — fascia superiore al footer con effetto vetro satinato (`backdrop-filter`, `color-mix` semi-trasparente).
|
|
13
|
+
|
|
14
|
+
# 5.1.32-rc3
|
|
15
|
+
- **changed**: `nginx.conf` (immagine Docker) — tipi MIME espliciti per `.mjs`, `.wasm`, `.onnx` e `default_type` a livello `http` (evita `text/plain` su moduli ONNX/VAD dietro deploy containerizzato).
|
|
16
|
+
- **chore**: rimossi script di deploy Amazon beta/prod deprecati dal repository.
|
|
17
|
+
|
|
9
18
|
# 5.1.32-rc2
|
|
10
19
|
- **bug fixed**: minor streaming icon UI fixed
|
|
20
|
+
- **changed**: Refactor UI pulsante stream audio nel conversation footer (layout / classi).
|
|
11
21
|
|
|
12
22
|
# 5.1.32-rc1
|
|
13
23
|
- **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.
|
package/nginx.conf
CHANGED
|
@@ -5,18 +5,38 @@ events {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
http {
|
|
8
|
+
include /etc/nginx/mime.types;
|
|
9
|
+
default_type application/octet-stream;
|
|
10
|
+
|
|
8
11
|
server {
|
|
9
12
|
listen 80;
|
|
10
13
|
server_name localhost;
|
|
11
14
|
|
|
12
15
|
root /usr/share/nginx/html;
|
|
13
16
|
index index.html index.htm;
|
|
14
|
-
include /etc/nginx/mime.types;
|
|
15
17
|
|
|
16
18
|
gzip on;
|
|
17
19
|
gzip_min_length 1000;
|
|
18
20
|
gzip_proxied expired no-cache no-store private auth;
|
|
19
|
-
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
|
21
|
+
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/wasm;
|
|
22
|
+
|
|
23
|
+
# ONNX Runtime (.mjs), WASM e modelli VAD: il browser rifiuta moduli ES con Content-Type: text/plain
|
|
24
|
+
location ~* \.mjs$ {
|
|
25
|
+
root /usr/share/nginx/html;
|
|
26
|
+
default_type application/javascript;
|
|
27
|
+
charset utf-8;
|
|
28
|
+
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
29
|
+
}
|
|
30
|
+
location ~* \.wasm$ {
|
|
31
|
+
root /usr/share/nginx/html;
|
|
32
|
+
default_type application/wasm;
|
|
33
|
+
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
34
|
+
}
|
|
35
|
+
location ~* \.onnx$ {
|
|
36
|
+
root /usr/share/nginx/html;
|
|
37
|
+
default_type application/octet-stream;
|
|
38
|
+
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
39
|
+
}
|
|
20
40
|
|
|
21
41
|
location / {
|
|
22
42
|
try_files $uri $uri/ /index.html;
|
package/package.json
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
<div id="chat21-conversation-component"
|
|
5
5
|
#afConversationComponent
|
|
6
6
|
tabindex="1500"
|
|
7
|
-
aria-modal="true"
|
|
7
|
+
aria-modal="true"
|
|
8
|
+
[class.chat21-conversation--close-stream-active]="closeStreamButtonActiveForSheetBottom()">
|
|
8
9
|
|
|
9
10
|
<!-- HEADER -->
|
|
10
11
|
<chat-conversation-header
|
|
@@ -242,6 +242,16 @@ dialog:-internal-dialog-in-top-layer{
|
|
|
242
242
|
::ng-deep .chat21-sheet-content{
|
|
243
243
|
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + var(--chat-footer-close-button-height) + 34px)!important;
|
|
244
244
|
}
|
|
245
|
+
|
|
246
|
+
/* Con `.close-stream-button` (stream in ascolto): spazio per alert stream sopra il footer */
|
|
247
|
+
#chat21-conversation-component.chat21-conversation--close-stream-active ::ng-deep .chat21-sheet-content {
|
|
248
|
+
bottom: calc(
|
|
249
|
+
var(--chat-footer-logo-height) +
|
|
250
|
+
var(--chat-footer-height) +
|
|
251
|
+
var(--chat-footer-stream-button-height) +
|
|
252
|
+
34px
|
|
253
|
+
) !important;
|
|
254
|
+
}
|
|
245
255
|
|
|
246
256
|
}
|
|
247
257
|
|
|
@@ -827,6 +827,10 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
827
827
|
this.showThinkingMessage = false;
|
|
828
828
|
}
|
|
829
829
|
|
|
830
|
+
if (this.isStreamAudioActive && msg.sender !== this.senderId) {
|
|
831
|
+
this.conversationFooter?.interruptStreamDueToPeerMessage();
|
|
832
|
+
}
|
|
833
|
+
|
|
830
834
|
that.newMessageAdded(msg);
|
|
831
835
|
// Update badge based on the latest message received from the server.
|
|
832
836
|
// We rely on `messages` being kept in-sync by the conversation handler.
|
|
@@ -1414,6 +1418,13 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
1414
1418
|
}
|
|
1415
1419
|
// =========== END: event emitter function ====== //
|
|
1416
1420
|
|
|
1421
|
+
/**
|
|
1422
|
+
* True quando è visibile il pulsante chiudi stream (`.close-stream-button`, `isStreamAudioActive`).
|
|
1423
|
+
* Solo in quel caso il bottom del foglio include `--chat-footer-stream-button-height`.
|
|
1424
|
+
*/
|
|
1425
|
+
closeStreamButtonActiveForSheetBottom(): boolean {
|
|
1426
|
+
return !!(this.g?.showAudioStreamFooterButton && this.isStreamAudioActive);
|
|
1427
|
+
}
|
|
1417
1428
|
|
|
1418
1429
|
openInputFiles() {
|
|
1419
1430
|
alert('ok');
|
|
@@ -270,6 +270,15 @@
|
|
|
270
270
|
}// end c21-body-container
|
|
271
271
|
}// end c21-body
|
|
272
272
|
|
|
273
|
+
/* Solo con pulsante chiudi stream (stream in ascolto): altezza extra come #streamAudioAlert */
|
|
274
|
+
:host-context(#chat21-conversation-component.chat21-conversation--close-stream-active) .c21-body .c21-body-container .c21-body-content .chat21-sheet-content {
|
|
275
|
+
bottom: calc(
|
|
276
|
+
var(--chat-footer-logo-height) +
|
|
277
|
+
var(--chat-footer-height) +
|
|
278
|
+
var(--chat-footer-stream-button-height)
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
273
282
|
@keyframes thinking-dot {
|
|
274
283
|
0%, 80%, 100% {
|
|
275
284
|
opacity: 0.2;
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss
CHANGED
|
@@ -393,19 +393,28 @@ textarea:active{
|
|
|
393
393
|
#streamAudioAlert {
|
|
394
394
|
bottom: 100%;
|
|
395
395
|
width: 100%;
|
|
396
|
-
min-height:
|
|
396
|
+
min-height: var(--chat-footer-stream-button-height);
|
|
397
397
|
display: flex;
|
|
398
398
|
align-items: center;
|
|
399
399
|
justify-content: center;
|
|
400
|
-
background-color: var(--content-background-color);
|
|
401
400
|
position: absolute;
|
|
402
|
-
padding:
|
|
401
|
+
padding: var(--chat-footer-stream-button-padding);
|
|
402
|
+
/* Satinato / vetro: più trasparenza, blur più marcato */
|
|
403
|
+
background-color: color-mix(in srgb, var(--content-background-color) 34%, transparent);
|
|
404
|
+
backdrop-filter: blur(20px) saturate(1.2);
|
|
405
|
+
-webkit-backdrop-filter: blur(20px) saturate(1.2);
|
|
406
|
+
box-shadow:
|
|
407
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.28),
|
|
408
|
+
0 1px 0 rgba(0, 0, 0, 0.05);
|
|
403
409
|
|
|
404
410
|
&.hideTextReply {
|
|
405
411
|
position: unset;
|
|
406
412
|
min-height: auto;
|
|
407
413
|
padding: 16px 0;
|
|
408
414
|
box-shadow: none;
|
|
415
|
+
backdrop-filter: none;
|
|
416
|
+
-webkit-backdrop-filter: none;
|
|
417
|
+
background-color: var(--content-background-color);
|
|
409
418
|
}
|
|
410
419
|
}
|
|
411
420
|
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -181,14 +181,30 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
|
|
|
181
181
|
await this.voiceService.startSession();
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
async stopVoice() {
|
|
184
|
+
async stopVoice(options?: { discardInProgressSegment?: boolean }) {
|
|
185
185
|
this.voiceAudioSubscription?.unsubscribe();
|
|
186
186
|
this.voiceAudioSubscription = undefined;
|
|
187
187
|
|
|
188
188
|
this.voiceVolumeSubscription?.unsubscribe();
|
|
189
189
|
this.voiceVolumeSubscription = undefined;
|
|
190
190
|
|
|
191
|
-
await this.voiceService.stopSession();
|
|
191
|
+
await this.voiceService.stopSession(options);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Messaggio in arrivo da un altro mittente mentre lo stream è attivo: scarta solo il segmento
|
|
196
|
+
* registrato in quel momento (nessun upload); mic + VAD restano attivi, `isStreamAudioActive` true.
|
|
197
|
+
*/
|
|
198
|
+
interruptStreamDueToPeerMessage(): void {
|
|
199
|
+
if (!this.isStreamAudioActive) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this.logger.log('[CONV-FOOTER] discard recording segment: incoming message from peer (stream stays on)');
|
|
203
|
+
try {
|
|
204
|
+
this.voiceService.discardCurrentRecordingSegment();
|
|
205
|
+
} catch (e) {
|
|
206
|
+
this.logger.error('[CONV-FOOTER] interruptStreamDueToPeerMessage', e);
|
|
207
|
+
}
|
|
192
208
|
}
|
|
193
209
|
|
|
194
210
|
updateWave(volume: number) {
|
|
@@ -100,9 +100,20 @@ export class VoiceService {
|
|
|
100
100
|
this.startVolumeLoop();
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
/**
|
|
104
|
+
* @param options.discardInProgressSegment — non inviare STT/upload per il segmento WebM corrente (es. interruzione da messaggio in arrivo).
|
|
105
|
+
*/
|
|
106
|
+
async stopSession(options?: { discardInProgressSegment?: boolean }): Promise<void> {
|
|
107
|
+
const discard = options?.discardInProgressSegment === true;
|
|
108
|
+
|
|
109
|
+
if (this.mediaRecorder) {
|
|
110
|
+
if (discard) {
|
|
111
|
+
this.mediaRecorder.onstop = null;
|
|
112
|
+
this.mediaRecorder.ondataavailable = null;
|
|
113
|
+
}
|
|
114
|
+
if (this.mediaRecorder.state === 'recording') {
|
|
115
|
+
this.mediaRecorder.stop();
|
|
116
|
+
}
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
this.mediaRecorder = undefined;
|
|
@@ -134,6 +145,23 @@ export class VoiceService {
|
|
|
134
145
|
this.onRecordingComplete = undefined;
|
|
135
146
|
}
|
|
136
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Scarta il segmento WebM in corso (nessun upload/STT) senza chiudere VAD, mic o sessione.
|
|
150
|
+
* Lo stream resta in ascolto per il prossimo `onSpeechStart`.
|
|
151
|
+
*/
|
|
152
|
+
discardCurrentRecordingSegment(): void {
|
|
153
|
+
if (this.mediaRecorder) {
|
|
154
|
+
this.mediaRecorder.onstop = null;
|
|
155
|
+
this.mediaRecorder.ondataavailable = null;
|
|
156
|
+
if (this.mediaRecorder.state === 'recording') {
|
|
157
|
+
this.mediaRecorder.stop();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
this.mediaRecorder = undefined;
|
|
161
|
+
this.audioChunks = [];
|
|
162
|
+
this.logger.log('[VoiceService] discarded in-progress segment; VAD session unchanged');
|
|
163
|
+
}
|
|
164
|
+
|
|
137
165
|
/**
|
|
138
166
|
* 🎧 AUDIO ANALYSER INIT
|
|
139
167
|
*/
|
|
@@ -161,7 +189,9 @@ export class VoiceService {
|
|
|
161
189
|
return;
|
|
162
190
|
}
|
|
163
191
|
|
|
164
|
-
this.analyser.getByteFrequencyData(
|
|
192
|
+
this.analyser.getByteFrequencyData(
|
|
193
|
+
this.dataArray as Parameters<AnalyserNode['getByteFrequencyData']>[0],
|
|
194
|
+
);
|
|
165
195
|
|
|
166
196
|
let sum = 0;
|
|
167
197
|
for (let i = 0; i < this.dataArray.length; i++) {
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
--chat-footer-logo-height: 30px;
|
|
39
39
|
--chat-footer-close-button-height: 30px;
|
|
40
40
|
--chat-footer-border-radius: 16px;
|
|
41
|
+
--chat-footer-stream-button-height: 96px;
|
|
42
|
+
--chat-footer-stream-button-padding: 10px 0;
|
|
41
43
|
--chat-footer-background-color: #f6f7fb;
|
|
42
44
|
--chat-footer-color: #1a1a1a;
|
|
43
45
|
--chat-footer-border-color-error: #aa0404;
|
package/deploy_amazon_prod.sh
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
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
|