@memori.ai/memori-react 8.8.2 → 8.8.4
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 +24 -0
- package/dist/components/Header/Header.d.ts +3 -0
- package/dist/components/Header/Header.js +31 -17
- package/dist/components/Header/Header.js.map +1 -1
- package/dist/components/MediaWidget/MediaItemWidget.css +216 -39
- package/dist/components/MediaWidget/MediaItemWidget.js +10 -0
- package/dist/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +28 -45
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/Snippet/Snippet.css +89 -13
- package/dist/components/Snippet/Snippet.js +46 -27
- package/dist/components/Snippet/Snippet.js.map +1 -1
- package/dist/helpers/tts/useTTS.js +15 -5
- package/dist/helpers/tts/useTTS.js.map +1 -1
- package/esm/components/Header/Header.d.ts +3 -0
- package/esm/components/Header/Header.js +32 -18
- package/esm/components/Header/Header.js.map +1 -1
- package/esm/components/MediaWidget/MediaItemWidget.css +216 -39
- package/esm/components/MediaWidget/MediaItemWidget.js +10 -0
- package/esm/components/MediaWidget/MediaItemWidget.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +28 -45
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/Snippet/Snippet.css +89 -13
- package/esm/components/Snippet/Snippet.js +46 -27
- package/esm/components/Snippet/Snippet.js.map +1 -1
- package/esm/helpers/tts/useTTS.js +15 -5
- package/esm/helpers/tts/useTTS.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Header/Header.tsx +58 -30
- package/src/components/Header/__snapshots__/Header.test.tsx.snap +0 -20
- package/src/components/MediaWidget/MediaItemWidget.css +216 -39
- package/src/components/MediaWidget/MediaItemWidget.stories.tsx +145 -58
- package/src/components/MediaWidget/MediaItemWidget.tsx +24 -1
- package/src/components/MediaWidget/__snapshots__/MediaItemWidget.test.tsx.snap +76 -12
- package/src/components/MemoriWidget/MemoriWidget.tsx +52 -78
- package/src/components/Snippet/Snippet.css +89 -13
- package/src/components/Snippet/Snippet.tsx +60 -28
- package/src/components/Snippet/__snapshots__/Snippet.test.tsx.snap +9 -0
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +0 -20
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +0 -40
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +0 -20
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +0 -20
- package/src/helpers/tts/useTTS.ts +23 -8
|
@@ -113,73 +113,160 @@ JavaScript.args = {
|
|
|
113
113
|
mediumID: '65ca4a6d-f20b-402e-9d79-5e470f247928',
|
|
114
114
|
mimeType: 'text/javascript',
|
|
115
115
|
title: 'JavaScript',
|
|
116
|
-
content: `
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
116
|
+
content: `{
|
|
117
|
+
"name": "John Doe",
|
|
118
|
+
"age": 43,
|
|
119
|
+
"city": "New York",
|
|
120
|
+
"items": [
|
|
121
|
+
{
|
|
122
|
+
"name": "Item 1",
|
|
123
|
+
"price": 10
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "Item 2",
|
|
127
|
+
"price": 20
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
`,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const ShortCodeSnippets = Template.bind({});
|
|
137
|
+
ShortCodeSnippets.args = {
|
|
138
|
+
items: [
|
|
139
|
+
{
|
|
140
|
+
mediumID: 'short-js-1',
|
|
141
|
+
mimeType: 'text/javascript',
|
|
142
|
+
title: 'Short JS Function',
|
|
143
|
+
content: 'function greet() {\n return "Hello World!";\n}',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
mediumID: 'short-python-1',
|
|
147
|
+
mimeType: 'text/python',
|
|
148
|
+
title: 'Python Print',
|
|
149
|
+
content: 'print("Hello, World!")',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
mediumID: 'short-css-1',
|
|
153
|
+
mimeType: 'text/css',
|
|
154
|
+
title: 'CSS Rule',
|
|
155
|
+
content: 'body {\n background: #f0f0f0;\n color: #333;\n}',
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const LongCodeSnippets = Template.bind({});
|
|
161
|
+
LongCodeSnippets.args = {
|
|
162
|
+
items: [
|
|
163
|
+
{
|
|
164
|
+
mediumID: 'long-js-1',
|
|
165
|
+
mimeType: 'text/javascript',
|
|
166
|
+
title: 'Long JavaScript Function',
|
|
167
|
+
content: `function processData(data) {
|
|
168
|
+
// Validate input
|
|
169
|
+
if (!data || typeof data !== 'object') {
|
|
170
|
+
throw new Error('Invalid data provided');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Process each item
|
|
174
|
+
return data.map(item => {
|
|
175
|
+
const processed = {
|
|
176
|
+
id: item.id,
|
|
177
|
+
name: item.name.toUpperCase(),
|
|
178
|
+
value: item.value * 2,
|
|
179
|
+
timestamp: new Date().toISOString()
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return processed;
|
|
183
|
+
});
|
|
184
|
+
}`,
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
mediumID: 'long-python-1',
|
|
188
|
+
mimeType: 'text/python',
|
|
189
|
+
title: 'Python Class',
|
|
190
|
+
content: `class DataProcessor:
|
|
191
|
+
def __init__(self, config):
|
|
192
|
+
self.config = config
|
|
193
|
+
self.cache = {}
|
|
194
|
+
|
|
195
|
+
def process(self, data):
|
|
196
|
+
if data in self.cache:
|
|
197
|
+
return self.cache[data]
|
|
198
|
+
|
|
199
|
+
result = self._transform(data)
|
|
200
|
+
self.cache[data] = result
|
|
201
|
+
return result
|
|
202
|
+
|
|
203
|
+
def _transform(self, data):
|
|
204
|
+
# Complex transformation logic
|
|
205
|
+
return data.upper()`,
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const MixedSnippets = Template.bind({});
|
|
211
|
+
MixedSnippets.args = {
|
|
212
|
+
items: [
|
|
213
|
+
{
|
|
214
|
+
mediumID: 'short-1',
|
|
215
|
+
mimeType: 'text/javascript',
|
|
216
|
+
title: 'Quick Function',
|
|
217
|
+
content: 'const add = (a, b) => a + b;',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
mediumID: 'long-1',
|
|
221
|
+
mimeType: 'text/javascript',
|
|
222
|
+
title: 'Complex Component',
|
|
223
|
+
content: `import React, { useState, useEffect } from 'react';
|
|
224
|
+
|
|
225
|
+
const MyComponent = ({ data, onUpdate }) => {
|
|
226
|
+
const [loading, setLoading] = useState(false);
|
|
227
|
+
const [error, setError] = useState(null);
|
|
228
|
+
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
if (data) {
|
|
231
|
+
setLoading(true);
|
|
232
|
+
processData(data)
|
|
233
|
+
.then(result => {
|
|
234
|
+
onUpdate(result);
|
|
235
|
+
setLoading(false);
|
|
236
|
+
})
|
|
237
|
+
.catch(err => {
|
|
238
|
+
setError(err.message);
|
|
239
|
+
setLoading(false);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}, [data, onUpdate]);
|
|
243
|
+
|
|
244
|
+
if (loading) return <div>Loading...</div>;
|
|
245
|
+
if (error) return <div>Error: {error}</div>;
|
|
246
|
+
|
|
247
|
+
return <div>Data processed successfully</div>;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export default MyComponent;`,
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
mediumID: 'short-2',
|
|
254
|
+
mimeType: 'text/css',
|
|
255
|
+
title: 'Simple Style',
|
|
256
|
+
content: '.button {\n padding: 10px;\n background: blue;\n}',
|
|
171
257
|
},
|
|
172
258
|
],
|
|
173
259
|
};
|
|
174
260
|
|
|
175
|
-
export const
|
|
176
|
-
|
|
261
|
+
export const LongTXT = Template.bind({});
|
|
262
|
+
LongTXT.args = {
|
|
177
263
|
items: [
|
|
178
264
|
{
|
|
179
265
|
mediumID: '65ca4a6d-f20b-402e-9d79-5e470f247928',
|
|
180
266
|
mimeType: 'text/plain',
|
|
181
267
|
title: 'Long Text',
|
|
182
|
-
content:
|
|
268
|
+
content:
|
|
269
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.',
|
|
183
270
|
},
|
|
184
271
|
],
|
|
185
272
|
};
|
|
@@ -187,7 +187,7 @@ export const RenderMediaItem = ({
|
|
|
187
187
|
widthMd="90%"
|
|
188
188
|
>
|
|
189
189
|
<div className="memori-media-item-preview--content">
|
|
190
|
-
<Snippet
|
|
190
|
+
<Snippet medium={item} showCopyButton={true} />
|
|
191
191
|
</div>
|
|
192
192
|
</Modal>
|
|
193
193
|
</>
|
|
@@ -368,6 +368,12 @@ export const RenderMediaItem = ({
|
|
|
368
368
|
}
|
|
369
369
|
};
|
|
370
370
|
|
|
371
|
+
// Helper function to count lines in content
|
|
372
|
+
const countLines = (content: string | undefined): number => {
|
|
373
|
+
if (!content) return 0;
|
|
374
|
+
return content.split('\n').length;
|
|
375
|
+
};
|
|
376
|
+
|
|
371
377
|
export const RenderSnippetItem = ({
|
|
372
378
|
item,
|
|
373
379
|
sessionID: _sessionID,
|
|
@@ -383,6 +389,23 @@ export const RenderSnippetItem = ({
|
|
|
383
389
|
apiURL?: string;
|
|
384
390
|
onClick?: (mediumID: string) => void;
|
|
385
391
|
}) => {
|
|
392
|
+
const lineCount = countLines(item.content);
|
|
393
|
+
const isShortSnippet = lineCount <= 5;
|
|
394
|
+
|
|
395
|
+
// For short snippets, show them directly without the clickable link
|
|
396
|
+
if (isShortSnippet) {
|
|
397
|
+
return (
|
|
398
|
+
<div className="memori-media-item--snippet-direct">
|
|
399
|
+
<Card className="memori-media-item--card memori-media-item--snippet">
|
|
400
|
+
<div className="memori-media-item--snippet-preview">
|
|
401
|
+
<Snippet showCopyButton={true} preview={false} medium={item} />
|
|
402
|
+
</div>
|
|
403
|
+
</Card>
|
|
404
|
+
</div>
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// For longer snippets, show preview with click to open modal
|
|
386
409
|
return (
|
|
387
410
|
<>
|
|
388
411
|
<a
|
|
@@ -25,13 +25,11 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
|
|
|
25
25
|
<div
|
|
26
26
|
class="memori-media-item ease-out duration-500 delay-0 opacity-0 scale-95"
|
|
27
27
|
>
|
|
28
|
-
<
|
|
29
|
-
class="memori-media-item--
|
|
30
|
-
href="#"
|
|
31
|
-
title="Snippet"
|
|
28
|
+
<div
|
|
29
|
+
class="memori-media-item--snippet-direct"
|
|
32
30
|
>
|
|
33
31
|
<div
|
|
34
|
-
class="memori-card memori-media-item--card memori-media-item--snippet
|
|
32
|
+
class="memori-card memori-media-item--card memori-media-item--snippet"
|
|
35
33
|
>
|
|
36
34
|
<div
|
|
37
35
|
class="memori-spin"
|
|
@@ -57,12 +55,46 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
|
|
|
57
55
|
>
|
|
58
56
|
<code
|
|
59
57
|
class="language-scss"
|
|
58
|
+
data-language="scss"
|
|
60
59
|
>
|
|
61
60
|
body{
|
|
62
61
|
background-color: #f00;
|
|
63
62
|
}
|
|
64
63
|
</code>
|
|
65
64
|
</pre>
|
|
65
|
+
<button
|
|
66
|
+
class="memori-button memori-button--ghost memori-button--rounded memori-button--icon-only memori-snippet--copy-button"
|
|
67
|
+
title="copy"
|
|
68
|
+
>
|
|
69
|
+
<span
|
|
70
|
+
class="memori-button--icon"
|
|
71
|
+
>
|
|
72
|
+
<svg
|
|
73
|
+
aria-hidden="true"
|
|
74
|
+
fill="none"
|
|
75
|
+
focusable="false"
|
|
76
|
+
role="img"
|
|
77
|
+
stroke="currentColor"
|
|
78
|
+
stroke-linecap="round"
|
|
79
|
+
stroke-linejoin="round"
|
|
80
|
+
stroke-width="1.5"
|
|
81
|
+
viewBox="0 0 24 24"
|
|
82
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
83
|
+
>
|
|
84
|
+
<rect
|
|
85
|
+
height="14"
|
|
86
|
+
rx="2"
|
|
87
|
+
ry="2"
|
|
88
|
+
width="14"
|
|
89
|
+
x="8"
|
|
90
|
+
y="8"
|
|
91
|
+
/>
|
|
92
|
+
<path
|
|
93
|
+
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
|
|
94
|
+
/>
|
|
95
|
+
</svg>
|
|
96
|
+
</span>
|
|
97
|
+
</button>
|
|
66
98
|
</div>
|
|
67
99
|
<p
|
|
68
100
|
class="memori-snippet--caption"
|
|
@@ -92,7 +124,7 @@ exports[`renders MediaItemWidget unchanged with css snippet to show 1`] = `
|
|
|
92
124
|
</div>
|
|
93
125
|
</div>
|
|
94
126
|
</div>
|
|
95
|
-
</
|
|
127
|
+
</div>
|
|
96
128
|
</div>
|
|
97
129
|
</div>
|
|
98
130
|
</div>
|
|
@@ -280,13 +312,11 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
|
|
|
280
312
|
<div
|
|
281
313
|
class="memori-media-item ease-out duration-500 delay-0 opacity-0 scale-95"
|
|
282
314
|
>
|
|
283
|
-
<
|
|
284
|
-
class="memori-media-item--
|
|
285
|
-
href="#"
|
|
286
|
-
title="Snippet"
|
|
315
|
+
<div
|
|
316
|
+
class="memori-media-item--snippet-direct"
|
|
287
317
|
>
|
|
288
318
|
<div
|
|
289
|
-
class="memori-card memori-media-item--card memori-media-item--snippet
|
|
319
|
+
class="memori-card memori-media-item--card memori-media-item--snippet"
|
|
290
320
|
>
|
|
291
321
|
<div
|
|
292
322
|
class="memori-spin"
|
|
@@ -312,10 +342,44 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
|
|
|
312
342
|
>
|
|
313
343
|
<code
|
|
314
344
|
class="language-jsx"
|
|
345
|
+
data-language="jsx"
|
|
315
346
|
>
|
|
316
347
|
console.log("Hello World!");
|
|
317
348
|
</code>
|
|
318
349
|
</pre>
|
|
350
|
+
<button
|
|
351
|
+
class="memori-button memori-button--ghost memori-button--rounded memori-button--icon-only memori-snippet--copy-button"
|
|
352
|
+
title="copy"
|
|
353
|
+
>
|
|
354
|
+
<span
|
|
355
|
+
class="memori-button--icon"
|
|
356
|
+
>
|
|
357
|
+
<svg
|
|
358
|
+
aria-hidden="true"
|
|
359
|
+
fill="none"
|
|
360
|
+
focusable="false"
|
|
361
|
+
role="img"
|
|
362
|
+
stroke="currentColor"
|
|
363
|
+
stroke-linecap="round"
|
|
364
|
+
stroke-linejoin="round"
|
|
365
|
+
stroke-width="1.5"
|
|
366
|
+
viewBox="0 0 24 24"
|
|
367
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
368
|
+
>
|
|
369
|
+
<rect
|
|
370
|
+
height="14"
|
|
371
|
+
rx="2"
|
|
372
|
+
ry="2"
|
|
373
|
+
width="14"
|
|
374
|
+
x="8"
|
|
375
|
+
y="8"
|
|
376
|
+
/>
|
|
377
|
+
<path
|
|
378
|
+
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
|
|
379
|
+
/>
|
|
380
|
+
</svg>
|
|
381
|
+
</span>
|
|
382
|
+
</button>
|
|
319
383
|
</div>
|
|
320
384
|
<p
|
|
321
385
|
class="memori-snippet--caption"
|
|
@@ -345,7 +409,7 @@ exports[`renders MediaItemWidget unchanged with js snippet to show 1`] = `
|
|
|
345
409
|
</div>
|
|
346
410
|
</div>
|
|
347
411
|
</div>
|
|
348
|
-
</
|
|
412
|
+
</div>
|
|
349
413
|
</div>
|
|
350
414
|
</div>
|
|
351
415
|
</div>
|
|
@@ -330,7 +330,6 @@ window.typeBatchMessages = typeBatchMessages;
|
|
|
330
330
|
let audioContext: IAudioContext;
|
|
331
331
|
|
|
332
332
|
let memoriPassword: string | undefined;
|
|
333
|
-
let speakerMuted: boolean = false;
|
|
334
333
|
let userToken: string | undefined;
|
|
335
334
|
|
|
336
335
|
export interface LayoutProps {
|
|
@@ -510,19 +509,21 @@ const MemoriWidget = ({
|
|
|
510
509
|
!user?.userID &&
|
|
511
510
|
(showLogin || memori.requireLoginToken)
|
|
512
511
|
) {
|
|
513
|
-
client.backend
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
512
|
+
client.backend
|
|
513
|
+
.pwlGetCurrentUser(loginToken)
|
|
514
|
+
.then(({ user, resultCode }) => {
|
|
515
|
+
if (user && resultCode === 0) {
|
|
516
|
+
setUser(user);
|
|
517
|
+
setLocalConfig('loginToken', loginToken);
|
|
518
|
+
|
|
519
|
+
if (!birthDate && user.birthDate) {
|
|
520
|
+
setBirthDate(user.birthDate);
|
|
521
|
+
setLocalConfig('birthDate', user.birthDate);
|
|
522
|
+
}
|
|
523
|
+
} else {
|
|
524
|
+
removeLocalConfig('loginToken');
|
|
521
525
|
}
|
|
522
|
-
}
|
|
523
|
-
removeLocalConfig('loginToken');
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
+
});
|
|
526
527
|
}
|
|
527
528
|
}, [loginToken, user?.userID]);
|
|
528
529
|
const [showLoginDrawer, setShowLoginDrawer] = useState(false);
|
|
@@ -870,7 +871,7 @@ const MemoriWidget = ({
|
|
|
870
871
|
|
|
871
872
|
translateDialogState(currentState, userLang, msg).then(ts => {
|
|
872
873
|
let text = ts.translatedEmission || ts.emission;
|
|
873
|
-
if (text && text
|
|
874
|
+
if (text && shouldPlayAudio(text)) {
|
|
874
875
|
handleSpeak(text);
|
|
875
876
|
}
|
|
876
877
|
});
|
|
@@ -897,7 +898,7 @@ const MemoriWidget = ({
|
|
|
897
898
|
tag: currentState.currentTag,
|
|
898
899
|
memoryTags: currentState.memoryTags,
|
|
899
900
|
});
|
|
900
|
-
if (emission && emission
|
|
901
|
+
if (emission && shouldPlayAudio(emission)) {
|
|
901
902
|
handleSpeak(emission);
|
|
902
903
|
}
|
|
903
904
|
}
|
|
@@ -1721,18 +1722,21 @@ const MemoriWidget = ({
|
|
|
1721
1722
|
|
|
1722
1723
|
const handleVisibilityChange = () => {
|
|
1723
1724
|
const isVisible = !document.hidden;
|
|
1724
|
-
|
|
1725
|
+
|
|
1725
1726
|
if (isVisible && !isTabVisible) {
|
|
1726
1727
|
// Tab became visible - start polling and send immediate date event
|
|
1727
1728
|
console.log('Tab is now active/visible - starting date polling');
|
|
1728
|
-
sendDateChangedEvent({
|
|
1729
|
+
sendDateChangedEvent({
|
|
1730
|
+
sessionID: sessionId,
|
|
1731
|
+
state: currentDialogState,
|
|
1732
|
+
});
|
|
1729
1733
|
startDatePolling();
|
|
1730
1734
|
} else if (!isVisible && isTabVisible) {
|
|
1731
1735
|
// Tab became hidden - stop polling
|
|
1732
1736
|
console.log('Tab is now hidden - stopping date polling');
|
|
1733
1737
|
stopDatePolling();
|
|
1734
1738
|
}
|
|
1735
|
-
|
|
1739
|
+
|
|
1736
1740
|
isTabVisible = isVisible;
|
|
1737
1741
|
};
|
|
1738
1742
|
|
|
@@ -1746,7 +1750,10 @@ const MemoriWidget = ({
|
|
|
1746
1750
|
|
|
1747
1751
|
return () => {
|
|
1748
1752
|
stopDatePolling();
|
|
1749
|
-
document.removeEventListener(
|
|
1753
|
+
document.removeEventListener(
|
|
1754
|
+
'visibilitychange',
|
|
1755
|
+
handleVisibilityChange
|
|
1756
|
+
);
|
|
1750
1757
|
};
|
|
1751
1758
|
}
|
|
1752
1759
|
}, [memori.needsDateTime, sessionId]);
|
|
@@ -1832,6 +1839,19 @@ const MemoriWidget = ({
|
|
|
1832
1839
|
defaultSpeakerActive
|
|
1833
1840
|
);
|
|
1834
1841
|
|
|
1842
|
+
// Helper function to check if audio should be played
|
|
1843
|
+
const shouldPlayAudio = (text?: string) => {
|
|
1844
|
+
const currentSpeakerMuted = getLocalConfig('muteSpeaker', false);
|
|
1845
|
+
console.log('[MemoriWidget] shouldPlayAudio', currentSpeakerMuted);
|
|
1846
|
+
return (
|
|
1847
|
+
text &&
|
|
1848
|
+
text.trim() &&
|
|
1849
|
+
!preview &&
|
|
1850
|
+
!currentSpeakerMuted &&
|
|
1851
|
+
defaultEnableAudio
|
|
1852
|
+
);
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1835
1855
|
// Create a single, centralized function to process and send messages
|
|
1836
1856
|
const processSpeechAndSendMessage = (text: string) => {
|
|
1837
1857
|
// console.log('processSpeechAndSendMessage', text);
|
|
@@ -1880,16 +1900,9 @@ const MemoriWidget = ({
|
|
|
1880
1900
|
* Uses promise-based approach for better reliability
|
|
1881
1901
|
*/
|
|
1882
1902
|
const handleSpeak = async (text: string) => {
|
|
1883
|
-
if (
|
|
1884
|
-
!text ||
|
|
1885
|
-
!text.trim() ||
|
|
1886
|
-
preview ||
|
|
1887
|
-
speakerMuted ||
|
|
1888
|
-
!defaultEnableAudio
|
|
1889
|
-
) {
|
|
1903
|
+
if (!shouldPlayAudio(text)) {
|
|
1890
1904
|
const e = new CustomEvent('MemoriEndSpeak');
|
|
1891
1905
|
document.dispatchEvent(e);
|
|
1892
|
-
|
|
1893
1906
|
return Promise.resolve();
|
|
1894
1907
|
}
|
|
1895
1908
|
|
|
@@ -1901,7 +1914,6 @@ const MemoriWidget = ({
|
|
|
1901
1914
|
setHasUserTypedMessage(false);
|
|
1902
1915
|
|
|
1903
1916
|
const processedText = sanitizeText(text);
|
|
1904
|
-
|
|
1905
1917
|
return ttsSpeak(processedText);
|
|
1906
1918
|
};
|
|
1907
1919
|
/**
|
|
@@ -1918,7 +1930,6 @@ const MemoriWidget = ({
|
|
|
1918
1930
|
try {
|
|
1919
1931
|
// First ensure we have a valid dialog state
|
|
1920
1932
|
if (!dialogState) {
|
|
1921
|
-
console.warn('translateAndSpeak called with empty dialog state');
|
|
1922
1933
|
return null;
|
|
1923
1934
|
}
|
|
1924
1935
|
|
|
@@ -1934,20 +1945,13 @@ const MemoriWidget = ({
|
|
|
1934
1945
|
const textToSpeak =
|
|
1935
1946
|
translatedState.translatedEmission || translatedState.emission;
|
|
1936
1947
|
|
|
1937
|
-
// Always set
|
|
1938
|
-
// to true when we have a valid dialog state,
|
|
1948
|
+
// Always set hasUserActivatedSpeak to true when we have a valid dialog state,
|
|
1939
1949
|
// regardless of audio settings, so the chat can start properly
|
|
1940
1950
|
if (!hasUserActivatedSpeak) {
|
|
1941
1951
|
setHasUserActivatedSpeak(true);
|
|
1942
1952
|
}
|
|
1943
1953
|
|
|
1944
|
-
if (
|
|
1945
|
-
textToSpeak &&
|
|
1946
|
-
textToSpeak.trim() &&
|
|
1947
|
-
!skipEmission &&
|
|
1948
|
-
!speakerMuted
|
|
1949
|
-
) {
|
|
1950
|
-
// Note: now using the Promise-based speak function to ensure proper sequencing
|
|
1954
|
+
if (textToSpeak && !skipEmission && shouldPlayAudio(textToSpeak)) {
|
|
1951
1955
|
await handleSpeak(textToSpeak);
|
|
1952
1956
|
}
|
|
1953
1957
|
|
|
@@ -1966,9 +1970,11 @@ const MemoriWidget = ({
|
|
|
1966
1970
|
handleSpeak,
|
|
1967
1971
|
hasUserActivatedSpeak,
|
|
1968
1972
|
setHasUserActivatedSpeak,
|
|
1973
|
+
speakerMuted,
|
|
1969
1974
|
]
|
|
1970
1975
|
);
|
|
1971
1976
|
|
|
1977
|
+
|
|
1972
1978
|
const focusChatInput = () => {
|
|
1973
1979
|
let textarea = document.querySelector(
|
|
1974
1980
|
'#chat-fieldset textarea'
|
|
@@ -2179,7 +2185,9 @@ const MemoriWidget = ({
|
|
|
2179
2185
|
// to use in integrations or snippets
|
|
2180
2186
|
const memoriTextEnteredHandler = useCallback(
|
|
2181
2187
|
(e: MemoriTextEnteredEvent) => {
|
|
2182
|
-
if (disableTextEnteredEvents)
|
|
2188
|
+
if (disableTextEnteredEvents) {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2183
2191
|
|
|
2184
2192
|
const {
|
|
2185
2193
|
text,
|
|
@@ -2222,6 +2230,7 @@ const MemoriWidget = ({
|
|
|
2222
2230
|
memoriTyping,
|
|
2223
2231
|
userLang,
|
|
2224
2232
|
disableTextEnteredEvents,
|
|
2233
|
+
speakerMuted,
|
|
2225
2234
|
]
|
|
2226
2235
|
);
|
|
2227
2236
|
useEffect(() => {
|
|
@@ -2776,8 +2785,7 @@ const MemoriWidget = ({
|
|
|
2776
2785
|
|
|
2777
2786
|
const showFullHistory =
|
|
2778
2787
|
showOnlyLastMessages === undefined
|
|
2779
|
-
? selectedLayout !== 'TOTEM' &&
|
|
2780
|
-
selectedLayout !== 'WEBSITE_ASSISTANT'
|
|
2788
|
+
? selectedLayout !== 'TOTEM' && selectedLayout !== 'WEBSITE_ASSISTANT'
|
|
2781
2789
|
: !showOnlyLastMessages;
|
|
2782
2790
|
|
|
2783
2791
|
const headerProps: HeaderProps = {
|
|
@@ -2790,49 +2798,16 @@ const MemoriWidget = ({
|
|
|
2790
2798
|
history,
|
|
2791
2799
|
showShare: showShare ?? integrationConfig?.showShare ?? true,
|
|
2792
2800
|
position,
|
|
2801
|
+
layout: selectedLayout,
|
|
2802
|
+
additionalSettings,
|
|
2793
2803
|
setShowPositionDrawer,
|
|
2794
2804
|
setShowSettingsDrawer,
|
|
2795
2805
|
setShowKnownFactsDrawer,
|
|
2796
2806
|
setShowExpertsDrawer,
|
|
2797
2807
|
enableAudio: defaultEnableAudio,
|
|
2798
2808
|
speakerMuted: speakerMuted ?? false,
|
|
2799
|
-
setSpeakerMuted: mute => {
|
|
2800
|
-
// If audio is disabled, force mute and don't allow unmuting
|
|
2801
|
-
if (!(enableAudio ?? integrationConfig?.enableAudio ?? true)) {
|
|
2802
|
-
mute = true;
|
|
2803
|
-
}
|
|
2804
|
-
|
|
2805
|
-
// Use the toggleMute function from useTTS hook which properly manages state
|
|
2809
|
+
setSpeakerMuted: (mute: boolean) => {
|
|
2806
2810
|
toggleMute(mute);
|
|
2807
|
-
|
|
2808
|
-
// Update local config for persistence
|
|
2809
|
-
setLocalConfig('muteSpeaker', !!mute);
|
|
2810
|
-
|
|
2811
|
-
// Handle microphone mode changes
|
|
2812
|
-
let microphoneMode = getLocalConfig<string>(
|
|
2813
|
-
'microphoneMode',
|
|
2814
|
-
'HOLD_TO_TALK'
|
|
2815
|
-
);
|
|
2816
|
-
if (microphoneMode === 'CONTINUOUS' && mute) {
|
|
2817
|
-
setContinuousSpeech(false);
|
|
2818
|
-
setLocalConfig('microphoneMode', 'HOLD_TO_TALK');
|
|
2819
|
-
}
|
|
2820
|
-
|
|
2821
|
-
// Stop audio if muting
|
|
2822
|
-
if (mute) {
|
|
2823
|
-
ttsStop();
|
|
2824
|
-
} else {
|
|
2825
|
-
// Initialize audio context when unmuting
|
|
2826
|
-
try {
|
|
2827
|
-
audioContext = new AudioContext();
|
|
2828
|
-
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
2829
|
-
let source = audioContext.createBufferSource();
|
|
2830
|
-
source.buffer = buffer;
|
|
2831
|
-
source.connect(audioContext.destination);
|
|
2832
|
-
} catch (error) {
|
|
2833
|
-
console.warn('Failed to initialize audio context:', error);
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
2811
|
},
|
|
2837
2812
|
setShowChatHistoryDrawer,
|
|
2838
2813
|
showSettings: showSettings ?? integrationConfig?.showSettings ?? true,
|
|
@@ -3280,7 +3255,6 @@ const MemoriWidget = ({
|
|
|
3280
3255
|
}}
|
|
3281
3256
|
/>
|
|
3282
3257
|
)}
|
|
3283
|
-
|
|
3284
3258
|
</div>
|
|
3285
3259
|
);
|
|
3286
3260
|
};
|