@eeacms/volto-eea-chatbot 4.1.1 → 4.1.2
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 +12 -0
- package/locales/de/LC_MESSAGES/volto.po +12 -0
- package/locales/en/LC_MESSAGES/volto.po +12 -0
- package/locales/it/LC_MESSAGES/volto.po +12 -0
- package/locales/ro/LC_MESSAGES/volto.po +12 -0
- package/locales/volto.pot +13 -1
- package/package.json +1 -1
- package/src/ChatBlock/chat/AIMessage.tsx +41 -0
- package/src/ChatBlock/chat/ChatWindow.tsx +89 -0
- package/src/ChatBlock/components/AutoResizeTextarea.jsx +71 -18
- package/src/ChatBlock/schema.jsx +13 -0
- package/src/ChatBlock/style.less +130 -0
- package/src/ChatBlock/types/interfaces.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [4.1.2](https://github.com/eea/volto-eea-chatbot/compare/4.1.1...4.1.2) - 17 September 2026
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: make floating pill the default stop button mode [Tiberiu Ichim - [`c7ce2f0`](https://github.com/eea/volto-eea-chatbot/commit/c7ce2f0eb7e0e9fd843eceadf12f5555b807cc1a)]
|
|
12
|
+
- feat: support stop button modes (input, floating pill, message loader) with pulse animation [Tiberiu Ichim - [`fb29273`](https://github.com/eea/volto-eea-chatbot/commit/fb2927319872a1e39f1fdc0557f1b290d76c42dd)]
|
|
13
|
+
- feat: add stop generation button with block toggle option [Tiberiu Ichim - [`b964ae3`](https://github.com/eea/volto-eea-chatbot/commit/b964ae3dce9abb7f4dd8c4acf2c1374bd5004358)]
|
|
14
|
+
|
|
15
|
+
#### :bug: Bug Fixes
|
|
16
|
+
|
|
17
|
+
- fix: avoid duplicate stop buttons when using message_loader option [Tiberiu Ichim - [`4f0c854`](https://github.com/eea/volto-eea-chatbot/commit/4f0c854bef40172b754db0ca46405426f1a2fd60)]
|
|
18
|
+
|
|
7
19
|
### [4.1.1](https://github.com/eea/volto-eea-chatbot/compare/4.1.0...4.1.1) - 14 September 2026
|
|
8
20
|
|
|
9
21
|
### [4.1.0](https://github.com/eea/volto-eea-chatbot/compare/4.0.0...4.1.0) - 31 August 2026
|
|
@@ -46,6 +46,18 @@ msgstr ""
|
|
|
46
46
|
msgid "Invalid assistant page URL."
|
|
47
47
|
msgstr ""
|
|
48
48
|
|
|
49
|
+
#. Default: "Send"
|
|
50
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
51
|
+
msgid "Send"
|
|
52
|
+
msgstr ""
|
|
53
|
+
|
|
54
|
+
#. Default: "Stop generating"
|
|
55
|
+
#: ChatBlock/chat/AIMessage
|
|
56
|
+
#: ChatBlock/chat/ChatWindow
|
|
57
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
58
|
+
msgid "Stop generating"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
49
61
|
#. Default: "Submit question"
|
|
50
62
|
#: AISearchInput/components/SearchInput
|
|
51
63
|
#: AISearchInput/messages
|
|
@@ -46,6 +46,18 @@ msgstr ""
|
|
|
46
46
|
msgid "Invalid assistant page URL."
|
|
47
47
|
msgstr ""
|
|
48
48
|
|
|
49
|
+
#. Default: "Send"
|
|
50
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
51
|
+
msgid "Send"
|
|
52
|
+
msgstr ""
|
|
53
|
+
|
|
54
|
+
#. Default: "Stop generating"
|
|
55
|
+
#: ChatBlock/chat/AIMessage
|
|
56
|
+
#: ChatBlock/chat/ChatWindow
|
|
57
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
58
|
+
msgid "Stop generating"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
49
61
|
#. Default: "Submit question"
|
|
50
62
|
#: AISearchInput/components/SearchInput
|
|
51
63
|
#: AISearchInput/messages
|
|
@@ -46,6 +46,18 @@ msgstr ""
|
|
|
46
46
|
msgid "Invalid assistant page URL."
|
|
47
47
|
msgstr ""
|
|
48
48
|
|
|
49
|
+
#. Default: "Send"
|
|
50
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
51
|
+
msgid "Send"
|
|
52
|
+
msgstr ""
|
|
53
|
+
|
|
54
|
+
#. Default: "Stop generating"
|
|
55
|
+
#: ChatBlock/chat/AIMessage
|
|
56
|
+
#: ChatBlock/chat/ChatWindow
|
|
57
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
58
|
+
msgid "Stop generating"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
49
61
|
#. Default: "Submit question"
|
|
50
62
|
#: AISearchInput/components/SearchInput
|
|
51
63
|
#: AISearchInput/messages
|
|
@@ -46,6 +46,18 @@ msgstr ""
|
|
|
46
46
|
msgid "Invalid assistant page URL."
|
|
47
47
|
msgstr ""
|
|
48
48
|
|
|
49
|
+
#. Default: "Send"
|
|
50
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
51
|
+
msgid "Send"
|
|
52
|
+
msgstr ""
|
|
53
|
+
|
|
54
|
+
#. Default: "Stop generating"
|
|
55
|
+
#: ChatBlock/chat/AIMessage
|
|
56
|
+
#: ChatBlock/chat/ChatWindow
|
|
57
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
58
|
+
msgid "Stop generating"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
49
61
|
#. Default: "Submit question"
|
|
50
62
|
#: AISearchInput/components/SearchInput
|
|
51
63
|
#: AISearchInput/messages
|
package/locales/volto.pot
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
msgid ""
|
|
2
2
|
msgstr ""
|
|
3
3
|
"Project-Id-Version: Plone\n"
|
|
4
|
-
"POT-Creation-Date: 2026-
|
|
4
|
+
"POT-Creation-Date: 2026-09-17T10:07:41.673Z\n"
|
|
5
5
|
"Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
|
|
6
6
|
"Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
|
|
7
7
|
"Content-Type: text/plain; charset=utf-8\n"
|
|
@@ -48,6 +48,18 @@ msgstr ""
|
|
|
48
48
|
msgid "Invalid assistant page URL."
|
|
49
49
|
msgstr ""
|
|
50
50
|
|
|
51
|
+
#. Default: "Send"
|
|
52
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
53
|
+
msgid "Send"
|
|
54
|
+
msgstr ""
|
|
55
|
+
|
|
56
|
+
#. Default: "Stop generating"
|
|
57
|
+
#: ChatBlock/chat/AIMessage
|
|
58
|
+
#: ChatBlock/chat/ChatWindow
|
|
59
|
+
#: ChatBlock/components/AutoResizeTextarea
|
|
60
|
+
msgid "Stop generating"
|
|
61
|
+
msgstr ""
|
|
62
|
+
|
|
51
63
|
#. Default: "Submit question"
|
|
52
64
|
#: AISearchInput/components/SearchInput
|
|
53
65
|
#: AISearchInput/messages
|
package/package.json
CHANGED
|
@@ -23,6 +23,9 @@ import { addCitations } from '@eeacms/volto-eea-chatbot/ChatBlock/utils/citation
|
|
|
23
23
|
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
24
24
|
import BotIcon from '@eeacms/volto-eea-chatbot/icons/bot.svg';
|
|
25
25
|
import ClearIcon from '@eeacms/volto-eea-chatbot/icons/clear.svg';
|
|
26
|
+
import StopIcon from '@eeacms/volto-eea-chatbot/icons/stop.svg';
|
|
27
|
+
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
28
|
+
import { FormattedMessage } from 'react-intl';
|
|
26
29
|
|
|
27
30
|
// Lazy load heavy components
|
|
28
31
|
const SourceDetails: any = loadable(
|
|
@@ -214,6 +217,8 @@ export function AIMessage({
|
|
|
214
217
|
extraRemarkPlugins,
|
|
215
218
|
extraMarkdownComponents,
|
|
216
219
|
extraRehypePlugins,
|
|
220
|
+
stopButton,
|
|
221
|
+
onCancel,
|
|
217
222
|
}: ChatMessageProps) {
|
|
218
223
|
const [allToolsDisplayed, setAllToolsDisplayed] = useState(false);
|
|
219
224
|
const [messageDisplayed, setMessageDisplayed] = useState(false);
|
|
@@ -470,6 +475,42 @@ export function AIMessage({
|
|
|
470
475
|
</RendererComponent>
|
|
471
476
|
</div>
|
|
472
477
|
))}
|
|
478
|
+
|
|
479
|
+
{stopButton === 'message_loader' &&
|
|
480
|
+
Boolean(message.isFinalMessageComing) &&
|
|
481
|
+
isLoading &&
|
|
482
|
+
isLastMessage &&
|
|
483
|
+
onCancel && (
|
|
484
|
+
<div className="inline-message-stop">
|
|
485
|
+
<Button
|
|
486
|
+
className="inline-message-stop-btn"
|
|
487
|
+
type="button"
|
|
488
|
+
aria-label="Stop generating"
|
|
489
|
+
onClick={() => {
|
|
490
|
+
if (enableMatomoTracking) {
|
|
491
|
+
trackEvent({
|
|
492
|
+
category: persona ? `Chatbot - ${persona}` : 'Chatbot',
|
|
493
|
+
action: 'Chatbot: Stop generating',
|
|
494
|
+
name: 'Message generation stopped',
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
onCancel();
|
|
498
|
+
}}
|
|
499
|
+
>
|
|
500
|
+
<div className="stop-btn-inner">
|
|
501
|
+
<div className="stop-icon-circle">
|
|
502
|
+
<SVGIcon name={StopIcon} size={8} color="#fff" />
|
|
503
|
+
</div>
|
|
504
|
+
<span>
|
|
505
|
+
<FormattedMessage
|
|
506
|
+
id="Stop generating"
|
|
507
|
+
defaultMessage="Stop generating"
|
|
508
|
+
/>
|
|
509
|
+
</span>
|
|
510
|
+
</div>
|
|
511
|
+
</Button>
|
|
512
|
+
</div>
|
|
513
|
+
)}
|
|
473
514
|
</div>
|
|
474
515
|
|
|
475
516
|
{/* Total fail message */}
|
|
@@ -10,6 +10,7 @@ import type { Persona } from '@eeacms/volto-eea-chatbot/ChatBlock/types/interfac
|
|
|
10
10
|
import { Button, Form, Segment, Checkbox } from 'semantic-ui-react';
|
|
11
11
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
|
|
12
12
|
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
13
|
+
import { FormattedMessage } from 'react-intl';
|
|
13
14
|
|
|
14
15
|
import { ChatMessage } from '.';
|
|
15
16
|
import { PacketType } from '@eeacms/volto-eea-chatbot/ChatBlock/types/streamingModels';
|
|
@@ -19,6 +20,7 @@ import EmptyState from '@eeacms/volto-eea-chatbot/ChatBlock/components/EmptyStat
|
|
|
19
20
|
import { useChatController } from '@eeacms/volto-eea-chatbot/ChatBlock/hooks';
|
|
20
21
|
import SVGIcon from '@eeacms/volto-eea-chatbot/ChatBlock/components/Icon';
|
|
21
22
|
import PenIcon from '@eeacms/volto-eea-chatbot/icons/square-pen.svg';
|
|
23
|
+
import StopIcon from '@eeacms/volto-eea-chatbot/icons/stop.svg';
|
|
22
24
|
|
|
23
25
|
import '@eeacms/volto-eea-chatbot/ChatBlock/style.less';
|
|
24
26
|
|
|
@@ -33,6 +35,8 @@ interface ChatWindowProps {
|
|
|
33
35
|
qgenAsistantId?: number;
|
|
34
36
|
enableQgen?: boolean;
|
|
35
37
|
enableFeedback?: boolean;
|
|
38
|
+
stopButton?: 'disabled' | 'input' | 'floating' | 'message_loader';
|
|
39
|
+
enableStopButton?: boolean;
|
|
36
40
|
scrollToInput?: boolean;
|
|
37
41
|
feedbackReasons?: string[];
|
|
38
42
|
qualityCheck?: string;
|
|
@@ -74,6 +78,8 @@ function ChatWindow({
|
|
|
74
78
|
qgenAsistantId,
|
|
75
79
|
enableQgen,
|
|
76
80
|
enableFeedback = true,
|
|
81
|
+
stopButton,
|
|
82
|
+
enableStopButton = true,
|
|
77
83
|
scrollToInput,
|
|
78
84
|
feedbackReasons,
|
|
79
85
|
qualityCheck = 'disabled',
|
|
@@ -97,6 +103,14 @@ function ChatWindow({
|
|
|
97
103
|
extraMarkdownComponents,
|
|
98
104
|
extraRehypePlugins,
|
|
99
105
|
} = data;
|
|
106
|
+
|
|
107
|
+
const stopButtonSetting:
|
|
108
|
+
| 'disabled'
|
|
109
|
+
| 'input'
|
|
110
|
+
| 'floating'
|
|
111
|
+
| 'message_loader' =
|
|
112
|
+
stopButton || (enableStopButton === false ? 'disabled' : 'floating');
|
|
113
|
+
|
|
100
114
|
const [qualityCheckEnabled, setQualityCheckEnabled] = useState(
|
|
101
115
|
onDemandInputToggle ?? true,
|
|
102
116
|
);
|
|
@@ -123,6 +137,7 @@ function ChatWindow({
|
|
|
123
137
|
isStreaming,
|
|
124
138
|
isFetchingRelatedQuestions,
|
|
125
139
|
clearChat,
|
|
140
|
+
cancelStreaming,
|
|
126
141
|
setIsDeepResearchEnabled,
|
|
127
142
|
isDeepResearchEnabled,
|
|
128
143
|
} = useChatController({
|
|
@@ -249,6 +264,8 @@ function ChatWindow({
|
|
|
249
264
|
extraRemarkPlugins={extraRemarkPlugins}
|
|
250
265
|
extraMarkdownComponents={extraMarkdownComponents}
|
|
251
266
|
extraRehypePlugins={extraRehypePlugins}
|
|
267
|
+
stopButton={stopButtonSetting}
|
|
268
|
+
onCancel={cancelStreaming}
|
|
252
269
|
/>
|
|
253
270
|
</React.Fragment>
|
|
254
271
|
))}
|
|
@@ -261,6 +278,43 @@ function ChatWindow({
|
|
|
261
278
|
<div className="comment-content">
|
|
262
279
|
<div className="loader-container">
|
|
263
280
|
<div className="loader" />
|
|
281
|
+
{stopButtonSetting === 'message_loader' && (
|
|
282
|
+
<div className="message-loader-stop">
|
|
283
|
+
<Button
|
|
284
|
+
className="message-loader-stop-btn"
|
|
285
|
+
type="button"
|
|
286
|
+
aria-label="Stop generating"
|
|
287
|
+
onClick={() => {
|
|
288
|
+
if (enableMatomoTracking) {
|
|
289
|
+
trackEvent({
|
|
290
|
+
category: persona?.name
|
|
291
|
+
? `Chatbot - ${persona.name}`
|
|
292
|
+
: 'Chatbot',
|
|
293
|
+
action: 'Chatbot: Stop generating',
|
|
294
|
+
name: 'Message generation stopped',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
cancelStreaming();
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
<div className="stop-btn-inner">
|
|
301
|
+
<div className="stop-icon-circle">
|
|
302
|
+
<SVGIcon
|
|
303
|
+
name={StopIcon}
|
|
304
|
+
size={8}
|
|
305
|
+
color="#fff"
|
|
306
|
+
/>
|
|
307
|
+
</div>
|
|
308
|
+
<span>
|
|
309
|
+
<FormattedMessage
|
|
310
|
+
id="Stop generating"
|
|
311
|
+
defaultMessage="Stop generating"
|
|
312
|
+
/>
|
|
313
|
+
</span>
|
|
314
|
+
</div>
|
|
315
|
+
</Button>
|
|
316
|
+
</div>
|
|
317
|
+
)}
|
|
264
318
|
</div>
|
|
265
319
|
</div>
|
|
266
320
|
</div>
|
|
@@ -271,6 +325,39 @@ function ChatWindow({
|
|
|
271
325
|
</div>
|
|
272
326
|
|
|
273
327
|
<div className="chat-form">
|
|
328
|
+
{stopButtonSetting === 'floating' && isStreaming && (
|
|
329
|
+
<div className="chat-floating-stop">
|
|
330
|
+
<Button
|
|
331
|
+
className="floating-stop-btn"
|
|
332
|
+
type="button"
|
|
333
|
+
aria-label="Stop generating"
|
|
334
|
+
onClick={() => {
|
|
335
|
+
if (enableMatomoTracking) {
|
|
336
|
+
trackEvent({
|
|
337
|
+
category: persona?.name
|
|
338
|
+
? `Chatbot - ${persona.name}`
|
|
339
|
+
: 'Chatbot',
|
|
340
|
+
action: 'Chatbot: Stop generating',
|
|
341
|
+
name: 'Message generation stopped',
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
cancelStreaming();
|
|
345
|
+
}}
|
|
346
|
+
>
|
|
347
|
+
<div className="stop-btn-inner">
|
|
348
|
+
<div className="stop-icon-circle">
|
|
349
|
+
<SVGIcon name={StopIcon} size={8} color="#fff" />
|
|
350
|
+
</div>
|
|
351
|
+
<span>
|
|
352
|
+
<FormattedMessage
|
|
353
|
+
id="Stop generating"
|
|
354
|
+
defaultMessage="Stop generating"
|
|
355
|
+
/>
|
|
356
|
+
</span>
|
|
357
|
+
</div>
|
|
358
|
+
</Button>
|
|
359
|
+
</div>
|
|
360
|
+
)}
|
|
274
361
|
{/* @ts-ignore */}
|
|
275
362
|
<Form>
|
|
276
363
|
<div className="textarea-wrapper">
|
|
@@ -283,6 +370,8 @@ function ChatWindow({
|
|
|
283
370
|
messages.length > 0 ? 'Ask follow-up...' : placeholderPrompt
|
|
284
371
|
}
|
|
285
372
|
isStreaming={isStreaming}
|
|
373
|
+
stopButton={stopButtonSetting}
|
|
374
|
+
onCancel={cancelStreaming}
|
|
286
375
|
enableMatomoTracking={enableMatomoTracking}
|
|
287
376
|
persona={persona}
|
|
288
377
|
onSubmit={onSubmit}
|
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { useIntl, defineMessages } from 'react-intl';
|
|
2
3
|
import { Button } from 'semantic-ui-react';
|
|
3
4
|
import { trackEvent } from '@eeacms/volto-matomo/utils';
|
|
4
5
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
5
6
|
|
|
6
7
|
import SVGIcon from './Icon';
|
|
7
8
|
import SendIcon from '@eeacms/volto-eea-chatbot/icons/send.svg';
|
|
9
|
+
import StopIcon from '@eeacms/volto-eea-chatbot/icons/stop.svg';
|
|
10
|
+
|
|
11
|
+
const messages = defineMessages({
|
|
12
|
+
send: {
|
|
13
|
+
id: 'Send',
|
|
14
|
+
defaultMessage: 'Send',
|
|
15
|
+
},
|
|
16
|
+
stopGenerating: {
|
|
17
|
+
id: 'Stop generating',
|
|
18
|
+
defaultMessage: 'Stop generating',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
8
21
|
|
|
9
22
|
export default React.forwardRef(function AutoResizeTextarea(props, ref) {
|
|
10
|
-
const {
|
|
11
|
-
|
|
23
|
+
const {
|
|
24
|
+
onSubmit,
|
|
25
|
+
isStreaming,
|
|
26
|
+
stopButton,
|
|
27
|
+
enableStopButton = true,
|
|
28
|
+
onCancel,
|
|
29
|
+
enableMatomoTracking,
|
|
30
|
+
persona,
|
|
31
|
+
...rest
|
|
32
|
+
} = props;
|
|
33
|
+
const intl = useIntl();
|
|
12
34
|
const [input, setInput] = React.useState('');
|
|
13
35
|
|
|
14
36
|
const handleSubmit = (e) => {
|
|
@@ -27,6 +49,24 @@ export default React.forwardRef(function AutoResizeTextarea(props, ref) {
|
|
|
27
49
|
}
|
|
28
50
|
};
|
|
29
51
|
|
|
52
|
+
const handleCancel = (e) => {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
if (enableMatomoTracking) {
|
|
55
|
+
trackEvent({
|
|
56
|
+
category: persona?.name ? `Chatbot - ${persona.name}` : 'Chatbot',
|
|
57
|
+
action: 'Chatbot: Stop generating',
|
|
58
|
+
name: 'Message generation stopped',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (onCancel) {
|
|
62
|
+
onCancel();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const resolvedStopButton =
|
|
67
|
+
stopButton || (enableStopButton === false ? 'disabled' : 'floating');
|
|
68
|
+
const showStopButton = Boolean(resolvedStopButton === 'input' && isStreaming);
|
|
69
|
+
|
|
30
70
|
return (
|
|
31
71
|
<>
|
|
32
72
|
<TextareaAutosize
|
|
@@ -46,22 +86,35 @@ export default React.forwardRef(function AutoResizeTextarea(props, ref) {
|
|
|
46
86
|
/>
|
|
47
87
|
|
|
48
88
|
<div className="chat-right-actions">
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
89
|
+
{showStopButton ? (
|
|
90
|
+
<Button
|
|
91
|
+
className="stop-btn"
|
|
92
|
+
type="button"
|
|
93
|
+
aria-label={intl.formatMessage(messages.stopGenerating)}
|
|
94
|
+
onClick={handleCancel}
|
|
95
|
+
>
|
|
96
|
+
<div className="btn-icon">
|
|
97
|
+
<SVGIcon name={StopIcon} size={14} color="#fff" />
|
|
98
|
+
</div>
|
|
99
|
+
</Button>
|
|
100
|
+
) : (
|
|
101
|
+
<Button
|
|
102
|
+
className="submit-btn"
|
|
103
|
+
type="submit"
|
|
104
|
+
aria-label={intl.formatMessage(messages.send)}
|
|
105
|
+
onKeyDown={(e) => {
|
|
106
|
+
handleSubmit(e);
|
|
107
|
+
}}
|
|
108
|
+
disabled={isStreaming || input.trim() === ''}
|
|
109
|
+
onClick={(e) => {
|
|
110
|
+
handleSubmit(e);
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
<div className="btn-icon">
|
|
114
|
+
<SVGIcon name={SendIcon} size="28" />
|
|
115
|
+
</div>
|
|
116
|
+
</Button>
|
|
117
|
+
)}
|
|
65
118
|
</div>
|
|
66
119
|
</>
|
|
67
120
|
);
|
package/src/ChatBlock/schema.jsx
CHANGED
|
@@ -100,6 +100,7 @@ export function ChatBlockSchema({ assistants, data }) {
|
|
|
100
100
|
: []),
|
|
101
101
|
'enableFeedback',
|
|
102
102
|
...(data.enableFeedback ? ['feedbackReasons'] : []),
|
|
103
|
+
'stopButton',
|
|
103
104
|
'showTools',
|
|
104
105
|
'enableMatomoTracking',
|
|
105
106
|
'scrollToInput',
|
|
@@ -175,6 +176,18 @@ export function ChatBlockSchema({ assistants, data }) {
|
|
|
175
176
|
type: 'boolean',
|
|
176
177
|
default: true,
|
|
177
178
|
},
|
|
179
|
+
stopButton: {
|
|
180
|
+
title: 'Stop generation button',
|
|
181
|
+
choices: [
|
|
182
|
+
['disabled', 'Disabled'],
|
|
183
|
+
['input', 'Inline text input'],
|
|
184
|
+
['floating', 'Floating pill'],
|
|
185
|
+
['message_loader', 'Inline message loader'],
|
|
186
|
+
],
|
|
187
|
+
default: 'floating',
|
|
188
|
+
description:
|
|
189
|
+
'Choose where and how the stop generation button appears during response generation',
|
|
190
|
+
},
|
|
178
191
|
qualityCheck: {
|
|
179
192
|
title: 'Quality checks',
|
|
180
193
|
choices: [
|
package/src/ChatBlock/style.less
CHANGED
|
@@ -123,6 +123,20 @@
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
@keyframes stopButtonPulse {
|
|
127
|
+
0% {
|
|
128
|
+
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.45);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
70% {
|
|
132
|
+
box-shadow: 0 0 0 7px rgba(0, 0, 0, 0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
100% {
|
|
136
|
+
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
126
140
|
@keyframes popIn {
|
|
127
141
|
0% {
|
|
128
142
|
opacity: 0;
|
|
@@ -1353,6 +1367,122 @@ mark {
|
|
|
1353
1367
|
color: @grey;
|
|
1354
1368
|
}
|
|
1355
1369
|
}
|
|
1370
|
+
|
|
1371
|
+
.ui.button.stop-btn {
|
|
1372
|
+
display: flex;
|
|
1373
|
+
width: 28px;
|
|
1374
|
+
height: 28px;
|
|
1375
|
+
align-items: center;
|
|
1376
|
+
justify-content: center;
|
|
1377
|
+
padding: 0;
|
|
1378
|
+
border-radius: 50%;
|
|
1379
|
+
margin: 0 0.5em 0 0.8em;
|
|
1380
|
+
animation: stopButtonPulse 1.8s cubic-bezier(0.66, 0, 0, 1) infinite;
|
|
1381
|
+
background: #000;
|
|
1382
|
+
cursor: pointer;
|
|
1383
|
+
transition:
|
|
1384
|
+
background-color 0.2s ease,
|
|
1385
|
+
transform 0.15s ease;
|
|
1386
|
+
|
|
1387
|
+
&:hover {
|
|
1388
|
+
background: #333;
|
|
1389
|
+
transform: scale(1.1);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
&:focus {
|
|
1393
|
+
background: #000;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
.btn-icon {
|
|
1397
|
+
display: flex;
|
|
1398
|
+
width: 100%;
|
|
1399
|
+
height: 100%;
|
|
1400
|
+
align-items: center;
|
|
1401
|
+
justify-content: center;
|
|
1402
|
+
|
|
1403
|
+
svg {
|
|
1404
|
+
width: 12px;
|
|
1405
|
+
height: 12px;
|
|
1406
|
+
color: #fff;
|
|
1407
|
+
fill: #fff;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
.chat-floating-stop {
|
|
1414
|
+
display: flex;
|
|
1415
|
+
justify-content: center;
|
|
1416
|
+
margin-bottom: 0.75em;
|
|
1417
|
+
animation: fadeInScale 0.2s ease;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
.message-loader-stop {
|
|
1421
|
+
display: inline-flex;
|
|
1422
|
+
align-items: center;
|
|
1423
|
+
margin-left: 20px;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
.inline-message-stop {
|
|
1427
|
+
display: flex;
|
|
1428
|
+
margin-top: 12px;
|
|
1429
|
+
animation: fadeIn 0.2s ease;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
.ui.button.floating-stop-btn,
|
|
1433
|
+
.ui.button.inline-message-stop-btn,
|
|
1434
|
+
.ui.button.message-loader-stop-btn {
|
|
1435
|
+
display: inline-flex;
|
|
1436
|
+
align-items: center;
|
|
1437
|
+
justify-content: center;
|
|
1438
|
+
padding: 6px 14px;
|
|
1439
|
+
border: 1px solid #d0d5dd;
|
|
1440
|
+
border-radius: 20px;
|
|
1441
|
+
background: #fff;
|
|
1442
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
|
1443
|
+
color: #344054;
|
|
1444
|
+
cursor: pointer;
|
|
1445
|
+
font-size: 13px;
|
|
1446
|
+
font-weight: 500;
|
|
1447
|
+
line-height: 1;
|
|
1448
|
+
transition: all 0.2s ease;
|
|
1449
|
+
|
|
1450
|
+
&:hover {
|
|
1451
|
+
border-color: #98a2b3;
|
|
1452
|
+
background: #f9fafb;
|
|
1453
|
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
|
|
1454
|
+
color: #1d2939;
|
|
1455
|
+
transform: translateY(-1px);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
&:focus {
|
|
1459
|
+
background: #fff;
|
|
1460
|
+
color: #344054;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
.stop-btn-inner {
|
|
1464
|
+
display: inline-flex;
|
|
1465
|
+
align-items: center;
|
|
1466
|
+
gap: 8px;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
.stop-icon-circle {
|
|
1470
|
+
display: flex;
|
|
1471
|
+
width: 18px;
|
|
1472
|
+
height: 18px;
|
|
1473
|
+
align-items: center;
|
|
1474
|
+
justify-content: center;
|
|
1475
|
+
border-radius: 50%;
|
|
1476
|
+
animation: stopButtonPulse 1.8s cubic-bezier(0.66, 0, 0, 1) infinite;
|
|
1477
|
+
background: #000;
|
|
1478
|
+
|
|
1479
|
+
svg {
|
|
1480
|
+
width: 8px;
|
|
1481
|
+
height: 8px;
|
|
1482
|
+
color: #fff;
|
|
1483
|
+
fill: #fff;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1356
1486
|
}
|
|
1357
1487
|
|
|
1358
1488
|
#quality-check-toggle[disabled] ~ label {
|
|
@@ -171,6 +171,8 @@ export interface ChatMessageProps {
|
|
|
171
171
|
extraMarkdownComponents?: any;
|
|
172
172
|
/** Extra rehype plugins merged after the built-in ones. */
|
|
173
173
|
extraRehypePlugins?: any[];
|
|
174
|
+
stopButton?: 'disabled' | 'input' | 'floating' | 'message_loader';
|
|
175
|
+
onCancel?: () => void;
|
|
174
176
|
}
|
|
175
177
|
|
|
176
178
|
export interface Persona {
|