@clikvn/agent-widget-embedded 0.0.10-dev → 0.0.11-dev
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/dist/commons/constants/variables.d.ts +4 -0
- package/dist/commons/constants/variables.d.ts.map +1 -1
- package/dist/components/Chat/Icons.d.ts +19 -1
- package/dist/components/Chat/Icons.d.ts.map +1 -1
- package/dist/components/Chat/Message.d.ts.map +1 -1
- package/dist/components/Chat/MultimodalInput.d.ts +1 -1
- package/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
- package/dist/components/Chat/SuggestedActions.d.ts +12 -0
- package/dist/components/Chat/SuggestedActions.d.ts.map +1 -0
- package/dist/features/AgentWidget/index.d.ts +8 -2
- package/dist/features/AgentWidget/index.d.ts.map +1 -1
- package/dist/hooks/useConfiguration.d.ts +8 -1
- package/dist/hooks/useConfiguration.d.ts.map +1 -1
- package/dist/index.html +12 -51
- package/dist/types/common.type.d.ts +6 -0
- package/dist/types/common.type.d.ts.map +1 -1
- package/dist/web.js +1 -1
- package/package.json +2 -1
- package/src/commons/constants/variables.ts +5 -0
- package/src/components/Chat/Chat.tsx +1 -1
- package/src/components/Chat/Icons.tsx +867 -1
- package/src/components/Chat/Message.tsx +42 -16
- package/src/components/Chat/MultimodalInput.tsx +136 -110
- package/src/components/Chat/SuggestedActions.tsx +99 -0
- package/src/features/AgentWidget/index.tsx +8 -2
- package/src/hooks/useConfiguration.tsx +8 -1
- package/src/types/common.type.ts +7 -0
- package/dist/components/Chat/AudioRecording.d.ts +0 -9
- package/dist/components/Chat/AudioRecording.d.ts.map +0 -1
- package/dist/hooks/useConnection.d.ts +0 -15
- package/dist/hooks/useConnection.d.ts.map +0 -1
- package/dist/services/user.service.d.ts +0 -3
- package/dist/services/user.service.d.ts.map +0 -1
- package/dist/types/agentType.d.ts +0 -11
- package/dist/types/agentType.d.ts.map +0 -1
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '../../types/flowise.type';
|
|
12
12
|
import { cn } from '../../utils/commonUtils';
|
|
13
13
|
import AudioPlayer from './AudioPlayer';
|
|
14
|
+
import { useConfiguration } from 'hooks/useConfiguration';
|
|
14
15
|
|
|
15
16
|
type PropsType = {
|
|
16
17
|
chatId?: string;
|
|
@@ -35,6 +36,7 @@ export const PreviewMessage: FC<PropsType> = ({
|
|
|
35
36
|
bot,
|
|
36
37
|
enableTTS,
|
|
37
38
|
}) => {
|
|
39
|
+
const { theme } = useConfiguration();
|
|
38
40
|
const parseOutput = (outputData: any) => {
|
|
39
41
|
try {
|
|
40
42
|
return JSON.parse(outputData);
|
|
@@ -56,12 +58,21 @@ export const PreviewMessage: FC<PropsType> = ({
|
|
|
56
58
|
return { customToolResults, toolResults };
|
|
57
59
|
}, [message.usedTools]);
|
|
58
60
|
|
|
61
|
+
const role = useMemo(() => {
|
|
62
|
+
return getRole(message.role);
|
|
63
|
+
}, [message.role]);
|
|
64
|
+
|
|
65
|
+
const assistantAvatar =
|
|
66
|
+
role === 'user'
|
|
67
|
+
? theme?.userMessage?.avatarSrc
|
|
68
|
+
: theme?.botMessage?.avatarSrc || bot?.avatar;
|
|
69
|
+
|
|
59
70
|
return (
|
|
60
71
|
<motion.div
|
|
61
72
|
className="w-full mx-auto max-w-3xl px-4 group/message"
|
|
62
73
|
initial={{ y: 5, opacity: 0 }}
|
|
63
74
|
animate={{ y: 0, opacity: 1 }}
|
|
64
|
-
data-role={
|
|
75
|
+
data-role={role}
|
|
65
76
|
>
|
|
66
77
|
<div className="flex justify-end text-[14px]">
|
|
67
78
|
{message?.fileUploads && !!message.fileUploads.length && (
|
|
@@ -70,15 +81,21 @@ export const PreviewMessage: FC<PropsType> = ({
|
|
|
70
81
|
</div>
|
|
71
82
|
<div
|
|
72
83
|
className={cn(
|
|
73
|
-
|
|
84
|
+
`group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl py-2 rounded-xl `
|
|
74
85
|
)}
|
|
86
|
+
style={{
|
|
87
|
+
backgroundColor:
|
|
88
|
+
role === 'user'
|
|
89
|
+
? theme?.userMessage?.backgroundColor
|
|
90
|
+
: theme?.botMessage?.backgroundColor || undefined,
|
|
91
|
+
}}
|
|
75
92
|
>
|
|
76
|
-
{message.role === 'apiMessage' && (
|
|
93
|
+
{theme?.botMessage?.showAvatar && message.role === 'apiMessage' && (
|
|
77
94
|
<div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
|
|
78
|
-
{
|
|
95
|
+
{assistantAvatar ? (
|
|
79
96
|
<img
|
|
80
|
-
src={
|
|
81
|
-
alt={bot
|
|
97
|
+
src={assistantAvatar}
|
|
98
|
+
alt={bot?.name ?? 'User Avatar'}
|
|
82
99
|
width={24}
|
|
83
100
|
height={24}
|
|
84
101
|
className="rounded-full"
|
|
@@ -133,7 +150,15 @@ export const PreviewMessage: FC<PropsType> = ({
|
|
|
133
150
|
{/* </div>*/}
|
|
134
151
|
{/* )}*/}
|
|
135
152
|
{message.content && (
|
|
136
|
-
<div
|
|
153
|
+
<div
|
|
154
|
+
className="flex flex-col gap-4"
|
|
155
|
+
style={{
|
|
156
|
+
color:
|
|
157
|
+
getRole(message.role) === 'user'
|
|
158
|
+
? theme?.userMessage?.textColor
|
|
159
|
+
: theme?.botMessage?.textColor || undefined,
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
137
162
|
<Markdown usedTools={message?.usedTools}>
|
|
138
163
|
{message.content as string}
|
|
139
164
|
</Markdown>
|
|
@@ -151,6 +176,10 @@ export const PreviewMessage: FC<PropsType> = ({
|
|
|
151
176
|
export const ThinkingMessage = ({ bot }: { bot: BotType | null }) => {
|
|
152
177
|
const role = 'assistant';
|
|
153
178
|
|
|
179
|
+
const { theme } = useConfiguration();
|
|
180
|
+
|
|
181
|
+
const assistantAvatar = theme?.botMessage?.avatarSrc || bot?.avatar;
|
|
182
|
+
|
|
154
183
|
return (
|
|
155
184
|
<motion.div
|
|
156
185
|
className="w-full mx-auto max-w-3xl px-4 group/message "
|
|
@@ -166,20 +195,17 @@ export const ThinkingMessage = ({ bot }: { bot: BotType | null }) => {
|
|
|
166
195
|
}
|
|
167
196
|
)}
|
|
168
197
|
>
|
|
169
|
-
|
|
170
|
-
|
|
198
|
+
{theme?.botMessage?.showAvatar && (
|
|
199
|
+
<div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
|
|
171
200
|
<img
|
|
172
|
-
src={
|
|
173
|
-
alt={bot
|
|
201
|
+
src={assistantAvatar}
|
|
202
|
+
alt={bot?.name ?? 'User Avatar'}
|
|
174
203
|
width={24}
|
|
175
204
|
height={24}
|
|
176
205
|
className="rounded-full"
|
|
177
206
|
/>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
)}
|
|
181
|
-
</div>
|
|
182
|
-
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
183
209
|
<div className="flex flex-col gap-2 w-full">
|
|
184
210
|
<div className="flex flex-col gap-4 text-muted-foreground">
|
|
185
211
|
Thinking...
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { motion } from 'framer-motion';
|
|
1
2
|
import {
|
|
2
3
|
type ChangeEvent,
|
|
3
4
|
FC,
|
|
@@ -6,33 +7,38 @@ import {
|
|
|
6
7
|
useRef,
|
|
7
8
|
useState,
|
|
8
9
|
} from 'react';
|
|
9
|
-
import { motion } from 'framer-motion';
|
|
10
10
|
import { useLocalStorage, useWindowSize } from 'usehooks-ts';
|
|
11
|
+
import { BotType } from '../../types/bot.type';
|
|
12
|
+
import { ChatMessageType, IFileUpload } from '../../types/flowise.type';
|
|
11
13
|
import {
|
|
12
14
|
cn,
|
|
13
15
|
generateExtendedFileName,
|
|
14
16
|
generateUUID,
|
|
15
17
|
} from '../../utils/commonUtils';
|
|
16
|
-
import { PreviewAttachment } from './PreviewAttachment';
|
|
17
18
|
import {
|
|
18
19
|
ArrowUpIcon,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
CheckCirclFillIcon,
|
|
21
|
+
ClikCloseIcon,
|
|
22
|
+
ClikMessageIcon,
|
|
23
|
+
ClikMicrophoneIcon,
|
|
24
|
+
ClikPlusIcon,
|
|
25
|
+
ClikVolumeIcon,
|
|
26
|
+
ClikWaveIcon,
|
|
22
27
|
StopIcon,
|
|
23
|
-
TrashIcon,
|
|
24
|
-
VolumeIcon,
|
|
25
28
|
} from './Icons';
|
|
26
|
-
import {
|
|
27
|
-
import { BotType } from '../../types/bot.type';
|
|
29
|
+
import { PreviewAttachment } from './PreviewAttachment';
|
|
28
30
|
|
|
29
31
|
import { createAttachments } from '../../services/chat.service';
|
|
30
32
|
import { Button } from './ui/Button';
|
|
31
33
|
import { Textarea } from './ui/Textarea';
|
|
32
34
|
import { useAudioRecording } from '../../hooks/useAudioRecording';
|
|
33
|
-
import { useChatData } from '../../hooks/useChatData';
|
|
34
35
|
import { useConfiguration } from '../../hooks/useConfiguration';
|
|
35
36
|
import { SuggestionType } from 'types/common.type';
|
|
37
|
+
import SuggestedActions from './SuggestedActions';
|
|
38
|
+
import { LAYOUT_MODE } from 'commons/constants';
|
|
39
|
+
|
|
40
|
+
const DEFAULT_COLOR_ICON = '#595959';
|
|
41
|
+
const ACTIVE_COLOR_ICON = '#0A82F7';
|
|
36
42
|
|
|
37
43
|
type PropsType = {
|
|
38
44
|
input: string;
|
|
@@ -87,6 +93,15 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
87
93
|
} = useAudioRecording();
|
|
88
94
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
89
95
|
const { width } = useWindowSize();
|
|
96
|
+
|
|
97
|
+
const defaultRows = theme?.suggestion?.defaultRows || 1;
|
|
98
|
+
const expandedRows = theme?.suggestion?.expandedRows || 2;
|
|
99
|
+
const suggestedActionLayoutMode =
|
|
100
|
+
theme?.suggestion?.layoutMode || LAYOUT_MODE.SCROLL;
|
|
101
|
+
|
|
102
|
+
const [suggestedActionRows, setSuggestedActionRows] =
|
|
103
|
+
useState<number>(defaultRows); // only use for scroll mode SuggestedActions
|
|
104
|
+
|
|
90
105
|
useEffect(() => {
|
|
91
106
|
if (textareaRef.current) {
|
|
92
107
|
adjustHeight();
|
|
@@ -125,6 +140,8 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
125
140
|
const handleInput = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
|
126
141
|
setInput(event.target.value);
|
|
127
142
|
adjustHeight();
|
|
143
|
+
if (suggestedActionRows !== defaultRows)
|
|
144
|
+
setSuggestedActionRows(defaultRows);
|
|
128
145
|
};
|
|
129
146
|
|
|
130
147
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
|
@@ -241,6 +258,12 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
241
258
|
[setUploadQueue, uploadFile]
|
|
242
259
|
);
|
|
243
260
|
|
|
261
|
+
const handleLogicShowFAQ = () => {
|
|
262
|
+
setSuggestedActionRows(
|
|
263
|
+
suggestedActionRows === defaultRows ? expandedRows : defaultRows
|
|
264
|
+
);
|
|
265
|
+
};
|
|
266
|
+
|
|
244
267
|
const handleFileChange = useCallback(
|
|
245
268
|
async (event: ChangeEvent<HTMLInputElement>) => {
|
|
246
269
|
const files = Array.from(event.target.files || []);
|
|
@@ -289,41 +312,12 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
289
312
|
return (
|
|
290
313
|
<div className="relative w-full flex flex-col gap-4">
|
|
291
314
|
{!!suggestedActions?.length && (
|
|
292
|
-
<
|
|
293
|
-
{suggestedActions
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
transition={{ delay: 0.05 * index }}
|
|
299
|
-
key={`suggested-action-${suggestedAction.title}-${index}`}
|
|
300
|
-
className={index > 1 ? 'hidden sm:block' : 'block'}
|
|
301
|
-
>
|
|
302
|
-
<Button
|
|
303
|
-
variant="ghost"
|
|
304
|
-
onClick={(e) => {
|
|
305
|
-
e.preventDefault();
|
|
306
|
-
if (append) {
|
|
307
|
-
append({
|
|
308
|
-
role: 'apiMessage',
|
|
309
|
-
content: suggestedAction.action,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}}
|
|
313
|
-
className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start"
|
|
314
|
-
>
|
|
315
|
-
<span className="font-medium overflow-hidden whitespace-nowrap text-ellipsis w-full group-hover:overflow-visible group-hover:whitespace-normal">
|
|
316
|
-
{suggestedAction.title}
|
|
317
|
-
</span>
|
|
318
|
-
{!!suggestedAction.label && (
|
|
319
|
-
<span className="text-muted-foreground">
|
|
320
|
-
{suggestedAction.label}
|
|
321
|
-
</span>
|
|
322
|
-
)}
|
|
323
|
-
</Button>
|
|
324
|
-
</motion.div>
|
|
325
|
-
))}
|
|
326
|
-
</div>
|
|
315
|
+
<SuggestedActions
|
|
316
|
+
suggestedActions={suggestedActions}
|
|
317
|
+
append={append}
|
|
318
|
+
layoutMode={suggestedActionLayoutMode}
|
|
319
|
+
suggestedActionRows={suggestedActionRows}
|
|
320
|
+
/>
|
|
327
321
|
)}
|
|
328
322
|
|
|
329
323
|
<input
|
|
@@ -358,14 +352,13 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
358
352
|
))}
|
|
359
353
|
</div>
|
|
360
354
|
)}
|
|
361
|
-
|
|
362
355
|
<Textarea
|
|
363
356
|
ref={textareaRef}
|
|
364
357
|
placeholder={theme?.input?.placeholder || 'Send a message...'}
|
|
365
358
|
value={input}
|
|
366
359
|
onChange={handleInput}
|
|
367
360
|
className={cn(
|
|
368
|
-
'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted',
|
|
361
|
+
'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted bg-[#ffffff]',
|
|
369
362
|
className
|
|
370
363
|
)}
|
|
371
364
|
rows={3}
|
|
@@ -388,7 +381,7 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
388
381
|
|
|
389
382
|
{isLoading ? (
|
|
390
383
|
<Button
|
|
391
|
-
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
|
|
384
|
+
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600 bg-[#000000D9]"
|
|
392
385
|
onClick={(event) => {
|
|
393
386
|
event.preventDefault();
|
|
394
387
|
stop();
|
|
@@ -399,7 +392,7 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
399
392
|
</Button>
|
|
400
393
|
) : (
|
|
401
394
|
<Button
|
|
402
|
-
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
|
|
395
|
+
className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600 bg-[#000000D9]"
|
|
403
396
|
onClick={(event) => {
|
|
404
397
|
event.preventDefault();
|
|
405
398
|
handleSend();
|
|
@@ -411,69 +404,102 @@ export const MultimodalInput: FC<PropsType> = ({
|
|
|
411
404
|
<ArrowUpIcon size={14} />
|
|
412
405
|
</Button>
|
|
413
406
|
)}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
407
|
+
|
|
408
|
+
<div className="absolute left-2 right-2 bottom-2 flex items-center">
|
|
409
|
+
<Button
|
|
410
|
+
className="rounded-full p-1.5 h-fit m-0.5 dark:border-zinc-700"
|
|
411
|
+
onClick={(event) => {
|
|
412
|
+
event.preventDefault();
|
|
413
|
+
fileInputRef.current?.click();
|
|
414
|
+
}}
|
|
415
|
+
variant="outline"
|
|
416
|
+
disabled={isLoading || isRecording}
|
|
417
|
+
>
|
|
418
|
+
<ClikPlusIcon size={14} />
|
|
419
|
+
</Button>
|
|
420
|
+
|
|
421
|
+
<Button
|
|
422
|
+
className={`rounded-full py-1 px-2 h-fit m-0.5 dark:border-zinc-700 text-[#595959] ${suggestedActionRows === expandedRows && 'border border-[#B9C6D6] bg-[#CBE1F3] text-[#0A82F7]'} `}
|
|
423
|
+
onClick={(event) => {
|
|
424
|
+
event.preventDefault();
|
|
425
|
+
handleLogicShowFAQ();
|
|
426
|
+
}}
|
|
427
|
+
variant="outline"
|
|
428
|
+
disabled={isLoading || isRecording}
|
|
429
|
+
>
|
|
430
|
+
<ClikMessageIcon
|
|
431
|
+
color={
|
|
432
|
+
suggestedActionRows === expandedRows
|
|
433
|
+
? ACTIVE_COLOR_ICON
|
|
434
|
+
: DEFAULT_COLOR_ICON
|
|
435
|
+
}
|
|
436
|
+
/>
|
|
437
|
+
FAQ
|
|
438
|
+
</Button>
|
|
439
|
+
|
|
440
|
+
{isRecording ? (
|
|
441
|
+
<>
|
|
442
|
+
<div
|
|
443
|
+
className="rounded-[100px] flex items-center bg-[#F3F3F3] gap-2 p-2"
|
|
444
|
+
data-testid="input"
|
|
445
|
+
>
|
|
446
|
+
<Button
|
|
447
|
+
className="rounded-full dark:border-zinc-700 p-0 h-6"
|
|
448
|
+
variant="outline"
|
|
449
|
+
onClick={(event) => {
|
|
450
|
+
event.preventDefault();
|
|
451
|
+
onRecordingCancelled();
|
|
452
|
+
}}
|
|
453
|
+
>
|
|
454
|
+
<ClikCloseIcon className="!w-full !h-full" />
|
|
455
|
+
</Button>
|
|
456
|
+
<div className="flex items-center gap-2 ">
|
|
457
|
+
<span>
|
|
458
|
+
<ClikWaveIcon />
|
|
459
|
+
</span>
|
|
460
|
+
<span>{elapsedTime || '00:00'}</span>
|
|
461
|
+
{isLoadingRecording && (
|
|
462
|
+
<span className="ml-1.5">Sending...</span>
|
|
463
|
+
)}
|
|
464
|
+
</div>
|
|
465
|
+
<Button
|
|
466
|
+
className="rounded-full dark:border-zinc-700 p-0 h-6"
|
|
467
|
+
variant="outline"
|
|
468
|
+
onClick={(event) => {
|
|
469
|
+
event.preventDefault();
|
|
470
|
+
}}
|
|
471
|
+
>
|
|
472
|
+
<CheckCirclFillIcon className="!w-full !h-full" />
|
|
473
|
+
</Button>
|
|
426
474
|
</div>
|
|
475
|
+
</>
|
|
476
|
+
) : (
|
|
477
|
+
<div>
|
|
478
|
+
<Button
|
|
479
|
+
className={`rounded-full py-1 px-2 h-fit m-0.5 dark:border-zinc-700 text-[#595959] ${enableTTS ? 'text-white hover:bg-primary/90 bg-primary' : ''}`}
|
|
480
|
+
onClick={(event) => {
|
|
481
|
+
event.preventDefault();
|
|
482
|
+
setEnableTTS(!enableTTS);
|
|
483
|
+
}}
|
|
484
|
+
variant="outline"
|
|
485
|
+
disabled={isLoading}
|
|
486
|
+
>
|
|
487
|
+
<ClikVolumeIcon /> Speak
|
|
488
|
+
</Button>
|
|
489
|
+
<Button
|
|
490
|
+
className="rounded-full py-1 px-2 gap-[4px] h-fit m-0.5 dark:border-zinc-700 text-[#595959]"
|
|
491
|
+
onClick={(event) => {
|
|
492
|
+
event.preventDefault();
|
|
493
|
+
setIsRecording(true);
|
|
494
|
+
}}
|
|
495
|
+
variant="outline"
|
|
496
|
+
disabled={isLoading}
|
|
497
|
+
>
|
|
498
|
+
<ClikMicrophoneIcon size={14} /> Talk
|
|
499
|
+
</Button>
|
|
427
500
|
</div>
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
variant="outline"
|
|
431
|
-
onClick={(event) => {
|
|
432
|
-
event.preventDefault();
|
|
433
|
-
onRecordingCancelled();
|
|
434
|
-
}}
|
|
435
|
-
>
|
|
436
|
-
<TrashIcon size={14} color="red" />
|
|
437
|
-
</Button>
|
|
438
|
-
</>
|
|
439
|
-
) : (
|
|
440
|
-
<>
|
|
441
|
-
<Button
|
|
442
|
-
className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
|
|
443
|
-
onClick={(event) => {
|
|
444
|
-
event.preventDefault();
|
|
445
|
-
setIsRecording(true);
|
|
446
|
-
}}
|
|
447
|
-
variant="outline"
|
|
448
|
-
disabled={isLoading}
|
|
449
|
-
>
|
|
450
|
-
<MicrophoneIcon size={14} />
|
|
451
|
-
</Button>
|
|
452
|
-
<Button
|
|
453
|
-
className={`rounded-full p-1.5 h-fit absolute bottom-2 right-[80px] m-0.5 dark:border-zinc-700 ${enableTTS ? 'text-white hover:bg-primary/90 bg-primary' : ''}`}
|
|
454
|
-
onClick={(event) => {
|
|
455
|
-
event.preventDefault();
|
|
456
|
-
setEnableTTS(!enableTTS);
|
|
457
|
-
}}
|
|
458
|
-
variant="outline"
|
|
459
|
-
disabled={isLoading}
|
|
460
|
-
>
|
|
461
|
-
<VolumeIcon />
|
|
462
|
-
</Button>
|
|
463
|
-
</>
|
|
464
|
-
)}
|
|
465
|
-
|
|
466
|
-
<Button
|
|
467
|
-
className="rounded-full p-1.5 h-fit absolute bottom-2 left-2 m-0.5 dark:border-zinc-700"
|
|
468
|
-
onClick={(event) => {
|
|
469
|
-
event.preventDefault();
|
|
470
|
-
fileInputRef.current?.click();
|
|
471
|
-
}}
|
|
472
|
-
variant="outline"
|
|
473
|
-
disabled={isLoading || isRecording}
|
|
474
|
-
>
|
|
475
|
-
<PlusIcon size={14} />
|
|
476
|
-
</Button>
|
|
501
|
+
)}
|
|
502
|
+
</div>
|
|
477
503
|
</div>
|
|
478
504
|
);
|
|
479
505
|
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import { SuggestionType } from 'types/common.type';
|
|
4
|
+
import { ChatMessageType } from 'types/flowise.type';
|
|
5
|
+
import { LAYOUT_MODE } from 'commons/constants';
|
|
6
|
+
|
|
7
|
+
interface SuggestedActionsProps {
|
|
8
|
+
suggestedActions?: SuggestionType[];
|
|
9
|
+
append?: (message: ChatMessageType) => Promise<void>;
|
|
10
|
+
layoutMode?: string;
|
|
11
|
+
suggestedActionRows?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const SuggestedActions: React.FC<SuggestedActionsProps> = ({
|
|
15
|
+
suggestedActions,
|
|
16
|
+
append,
|
|
17
|
+
layoutMode = LAYOUT_MODE.SCROLL,
|
|
18
|
+
suggestedActionRows = 1,
|
|
19
|
+
}) => {
|
|
20
|
+
if (!suggestedActions?.length) return null;
|
|
21
|
+
|
|
22
|
+
const containerHeight = suggestedActionRows * 60;
|
|
23
|
+
|
|
24
|
+
const animation = {
|
|
25
|
+
initial: { opacity: 0, y: 20 },
|
|
26
|
+
animate: { opacity: 1, y: 0 },
|
|
27
|
+
exit: { opacity: 0, y: 20 },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return layoutMode === LAYOUT_MODE.GRID ? (
|
|
31
|
+
// UI Grid (2 columns)
|
|
32
|
+
<div className="grid sm:grid-cols-2 gap-2 w-full">
|
|
33
|
+
{suggestedActions.map((suggestedAction, index) => (
|
|
34
|
+
<motion.div
|
|
35
|
+
key={`suggested-action-${suggestedAction.title}-${index}`}
|
|
36
|
+
{...animation}
|
|
37
|
+
transition={{ delay: 0.05 * index }}
|
|
38
|
+
className={index > 1 ? 'hidden sm:block' : 'block'}
|
|
39
|
+
>
|
|
40
|
+
<ActionButton suggestedAction={suggestedAction} append={append} />
|
|
41
|
+
</motion.div>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
) : (
|
|
45
|
+
// UI Scroll
|
|
46
|
+
<div
|
|
47
|
+
className="w-full overflow-x-auto scrollbar-hide"
|
|
48
|
+
style={{ maxHeight: `${containerHeight}px` }}
|
|
49
|
+
>
|
|
50
|
+
<div
|
|
51
|
+
style={{
|
|
52
|
+
gap: '8px',
|
|
53
|
+
display: 'grid',
|
|
54
|
+
gridAutoFlow: 'column',
|
|
55
|
+
gridTemplateRows: `repeat(${suggestedActionRows}, minmax(0, 1fr))`,
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
{suggestedActions.map((suggestedAction, index) => (
|
|
59
|
+
<motion.div
|
|
60
|
+
key={`suggested-action-${suggestedAction.title}-${index}`}
|
|
61
|
+
{...animation}
|
|
62
|
+
transition={{ delay: 0.05 * index }}
|
|
63
|
+
>
|
|
64
|
+
<ActionButton suggestedAction={suggestedAction} append={append} />
|
|
65
|
+
</motion.div>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
interface ActionButtonProps {
|
|
73
|
+
suggestedAction: SuggestionType;
|
|
74
|
+
append?: (message: ChatMessageType) => Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const ActionButton: React.FC<ActionButtonProps> = ({
|
|
78
|
+
suggestedAction,
|
|
79
|
+
append,
|
|
80
|
+
}) => (
|
|
81
|
+
<button
|
|
82
|
+
onClick={(e) => {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
if (append) {
|
|
85
|
+
append({ role: 'apiMessage', content: suggestedAction.action });
|
|
86
|
+
}
|
|
87
|
+
}}
|
|
88
|
+
className="text-left border rounded-xl px-4 py-3.5 text-sm flex-1 gap-1 sm:flex-col w-full h-auto justify-start items-start"
|
|
89
|
+
>
|
|
90
|
+
<span className="font-medium overflow-hidden whitespace-nowrap text-ellipsis w-full group-hover:overflow-visible group-hover:whitespace-normal">
|
|
91
|
+
{suggestedAction.title}
|
|
92
|
+
</span>
|
|
93
|
+
{!!suggestedAction.label && (
|
|
94
|
+
<span className="text-muted-foreground">{suggestedAction.label}</span>
|
|
95
|
+
)}
|
|
96
|
+
</button>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export default SuggestedActions;
|
|
@@ -5,7 +5,7 @@ import Agent from '../../components/Agent';
|
|
|
5
5
|
import { ChatDataProvider } from '../../hooks/useChatData';
|
|
6
6
|
import styles from '../../assets/tailwindcss.css';
|
|
7
7
|
import commonStyles from '../../assets/common.css';
|
|
8
|
-
import { SuggestionType } from '../../types/common.type';
|
|
8
|
+
import { ConfigMessageType, SuggestionType } from '../../types/common.type';
|
|
9
9
|
|
|
10
10
|
export type AgentWidgetType = {
|
|
11
11
|
apiHost: string;
|
|
@@ -16,7 +16,13 @@ export type AgentWidgetType = {
|
|
|
16
16
|
suggestedActions?: SuggestionType[];
|
|
17
17
|
} & Record<string, unknown>;
|
|
18
18
|
theme?: {
|
|
19
|
-
|
|
19
|
+
botMessage?: ConfigMessageType;
|
|
20
|
+
userMessage?: ConfigMessageType;
|
|
21
|
+
suggestion?: {
|
|
22
|
+
defaultRows?: number; // only for scroll mode
|
|
23
|
+
expandedRows?: number; // only for scroll mode
|
|
24
|
+
layoutMode?: 'grid' | 'scroll';
|
|
25
|
+
};
|
|
20
26
|
input?: {
|
|
21
27
|
placeholder?: string;
|
|
22
28
|
};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import React, { createContext, useEffect, useState } from 'react';
|
|
2
|
+
import { ConfigMessageType } from 'types/common.type';
|
|
2
3
|
|
|
3
4
|
type ConfigurationData = {
|
|
4
5
|
apiHost: string;
|
|
5
6
|
agentId: string;
|
|
6
7
|
overrideConfig?: Record<string, any>;
|
|
7
8
|
theme?: {
|
|
8
|
-
|
|
9
|
+
suggestion?: {
|
|
10
|
+
defaultRows?: number; // only for scroll mode
|
|
11
|
+
expandedRows?: number; // only for scroll mode
|
|
12
|
+
layoutMode?: 'grid' | 'scroll';
|
|
13
|
+
};
|
|
14
|
+
botMessage?: ConfigMessageType;
|
|
15
|
+
userMessage?: ConfigMessageType;
|
|
9
16
|
input?: {
|
|
10
17
|
placeholder?: string;
|
|
11
18
|
};
|
package/src/types/common.type.ts
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
type Props = {
|
|
3
|
-
addRecordingToPreviews: (blob: Blob) => void;
|
|
4
|
-
isRecording: boolean;
|
|
5
|
-
setIsRecording: (value: boolean) => void;
|
|
6
|
-
};
|
|
7
|
-
export declare const AudioRecording: FC<Props>;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=AudioRecording.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AudioRecording.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/AudioRecording.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAuB,MAAM,OAAO,CAAC;AAShD,KAAK,KAAK,GAAG;IACX,sBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C,CAAC;AACF,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,KAAK,CAiEpC,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
type TokenGeneratorData = {
|
|
3
|
-
shouldConnect: boolean;
|
|
4
|
-
wsUrl: string;
|
|
5
|
-
token: string;
|
|
6
|
-
disconnect: () => Promise<void>;
|
|
7
|
-
connect: () => Promise<void>;
|
|
8
|
-
};
|
|
9
|
-
export declare const ConnectionProvider: ({ children, livekitURL, }: {
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
livekitURL: string;
|
|
12
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export declare const useConnection: () => TokenGeneratorData;
|
|
14
|
-
export {};
|
|
15
|
-
//# sourceMappingURL=useConnection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useConnection.d.ts","sourceRoot":"","sources":["../../src/hooks/useConnection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAIvD,KAAK,kBAAkB,GAAG;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAMF,eAAO,MAAM,kBAAkB,8BAG5B;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,4CA6CA,CAAC;AAEF,eAAO,MAAM,aAAa,0BAMzB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../src/services/user.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C,eAAO,MAAM,WAAW,gBAAuB,MAAM,KAAG,OAAO,CAAC,QAAQ,CAUvE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agentType.d.ts","sourceRoot":"","sources":["../../src/types/agentType.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,GAAG,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB"}
|