@clikvn/agent-widget-embedded 0.0.11-dev → 0.0.12-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/components/Chat/MultimodalInput.d.ts.map +1 -1
- package/dist/index.html +52 -12
- package/dist/web.js +1 -1
- package/package.json +3 -3
- package/.eslintrc +0 -34
- package/.prettierrc +0 -8
- package/src/assets/common.css +0 -148
- package/src/assets/tailwindcss.css +0 -3
- package/src/commons/constants/index.ts +0 -1
- package/src/commons/constants/variables.ts +0 -25
- package/src/components/Agent/index.tsx +0 -14
- package/src/components/Chat/AudioPlayer.tsx +0 -44
- package/src/components/Chat/Chat.tsx +0 -91
- package/src/components/Chat/Icons.tsx +0 -1796
- package/src/components/Chat/Markdown.tsx +0 -335
- package/src/components/Chat/Message.tsx +0 -217
- package/src/components/Chat/MultimodalInput.tsx +0 -505
- package/src/components/Chat/Overview.tsx +0 -46
- package/src/components/Chat/PreviewAttachment.tsx +0 -46
- package/src/components/Chat/SuggestedActions.tsx +0 -99
- package/src/components/Chat/ui/Button.tsx +0 -55
- package/src/components/Chat/ui/Textarea.tsx +0 -23
- package/src/constants.ts +0 -1
- package/src/env.d.ts +0 -10
- package/src/features/AgentWidget/index.tsx +0 -63
- package/src/global.d.ts +0 -1
- package/src/hooks/useAudioRecording.ts +0 -50
- package/src/hooks/useChat.ts +0 -262
- package/src/hooks/useChatData.tsx +0 -68
- package/src/hooks/useConfiguration.tsx +0 -63
- package/src/hooks/useScrollToBottom.ts +0 -31
- package/src/index.ts +0 -1
- package/src/models/FlowiseClient.ts +0 -103
- package/src/models.ts +0 -1
- package/src/register.tsx +0 -85
- package/src/services/apis.ts +0 -12
- package/src/services/bot.service.ts +0 -15
- package/src/services/chat.service.ts +0 -199
- package/src/types/bot.type.ts +0 -10
- package/src/types/chat.type.ts +0 -11
- package/src/types/common.type.ts +0 -24
- package/src/types/flowise.type.ts +0 -108
- package/src/types/user.type.ts +0 -15
- package/src/types.ts +0 -0
- package/src/utils/audioRecording.ts +0 -371
- package/src/utils/commonUtils.ts +0 -47
- package/src/utils/functionUtils.ts +0 -17
- package/src/utils/requestUtils.ts +0 -113
- package/src/utils/streamUtils.ts +0 -18
- package/src/web.ts +0 -6
- package/src/window.ts +0 -43
- package/tsconfig.json +0 -24
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
2
|
-
import { cn } from '../../../utils/commonUtils';
|
|
3
|
-
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
-
import { ButtonHTMLAttributes, forwardRef } from 'react';
|
|
5
|
-
|
|
6
|
-
const buttonVariants = cva(
|
|
7
|
-
'inline-flex items-center gap-2 justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
|
8
|
-
{
|
|
9
|
-
variants: {
|
|
10
|
-
variant: {
|
|
11
|
-
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
12
|
-
destructive:
|
|
13
|
-
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
14
|
-
outline:
|
|
15
|
-
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
16
|
-
secondary:
|
|
17
|
-
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
18
|
-
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
19
|
-
link: 'text-primary underline-offset-4 hover:underline',
|
|
20
|
-
},
|
|
21
|
-
size: {
|
|
22
|
-
default: 'h-10 px-4 py-2',
|
|
23
|
-
sm: 'h-9 rounded-md px-3',
|
|
24
|
-
lg: 'h-11 rounded-md px-8',
|
|
25
|
-
icon: 'h-10 w-10',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
defaultVariants: {
|
|
29
|
-
variant: 'default',
|
|
30
|
-
size: 'default',
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
export interface ButtonProps
|
|
36
|
-
extends ButtonHTMLAttributes<HTMLButtonElement>,
|
|
37
|
-
VariantProps<typeof buttonVariants> {
|
|
38
|
-
asChild?: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
42
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
43
|
-
const Comp = asChild ? Slot : 'button';
|
|
44
|
-
return (
|
|
45
|
-
<Comp
|
|
46
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
47
|
-
ref={ref}
|
|
48
|
-
{...props}
|
|
49
|
-
/>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
Button.displayName = 'Button';
|
|
54
|
-
|
|
55
|
-
export { Button, buttonVariants };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { cn } from '../../../utils/commonUtils';
|
|
2
|
-
import { forwardRef, TextareaHTMLAttributes } from 'react';
|
|
3
|
-
|
|
4
|
-
export interface TextareaProps
|
|
5
|
-
extends TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
6
|
-
|
|
7
|
-
const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
8
|
-
({ className, ...props }, ref) => {
|
|
9
|
-
return (
|
|
10
|
-
<textarea
|
|
11
|
-
className={cn(
|
|
12
|
-
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
13
|
-
className
|
|
14
|
-
)}
|
|
15
|
-
ref={ref}
|
|
16
|
-
{...props}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
);
|
|
21
|
-
Textarea.displayName = 'Textarea';
|
|
22
|
-
|
|
23
|
-
export { Textarea };
|
package/src/constants.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const agentWidgetElementName = 'clik-agent-widget';
|
package/src/env.d.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
import { ConfigurationProvider } from '../../hooks/useConfiguration';
|
|
3
|
-
import { EVENT_TYPE } from '../../models';
|
|
4
|
-
import Agent from '../../components/Agent';
|
|
5
|
-
import { ChatDataProvider } from '../../hooks/useChatData';
|
|
6
|
-
import styles from '../../assets/tailwindcss.css';
|
|
7
|
-
import commonStyles from '../../assets/common.css';
|
|
8
|
-
import { ConfigMessageType, SuggestionType } from '../../types/common.type';
|
|
9
|
-
|
|
10
|
-
export type AgentWidgetType = {
|
|
11
|
-
apiHost: string;
|
|
12
|
-
agentId: string;
|
|
13
|
-
overrideConfig?: {
|
|
14
|
-
chatId?: string | undefined;
|
|
15
|
-
overrideConfig?: Record<string, unknown>;
|
|
16
|
-
suggestedActions?: SuggestionType[];
|
|
17
|
-
} & Record<string, unknown>;
|
|
18
|
-
theme?: {
|
|
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
|
-
};
|
|
26
|
-
input?: {
|
|
27
|
-
placeholder?: string;
|
|
28
|
-
};
|
|
29
|
-
overview?: {
|
|
30
|
-
title: string;
|
|
31
|
-
description?: string;
|
|
32
|
-
};
|
|
33
|
-
} & Record<string, unknown>;
|
|
34
|
-
listeners?: Record<EVENT_TYPE, (props: any) => void>;
|
|
35
|
-
};
|
|
36
|
-
const AgentWidget: FC<AgentWidgetType> = (props: AgentWidgetType) => {
|
|
37
|
-
return (
|
|
38
|
-
<div className="w-full h-full">
|
|
39
|
-
<style>{styles}</style>
|
|
40
|
-
<style>{commonStyles}</style>
|
|
41
|
-
<ConfigurationProvider
|
|
42
|
-
config={{
|
|
43
|
-
apiHost: props.apiHost,
|
|
44
|
-
agentId: props.agentId,
|
|
45
|
-
overrideConfig: props.overrideConfig?.overrideConfig,
|
|
46
|
-
theme: props.theme,
|
|
47
|
-
}}
|
|
48
|
-
>
|
|
49
|
-
<ChatDataProvider
|
|
50
|
-
data={{
|
|
51
|
-
chatId: props.overrideConfig?.chatId,
|
|
52
|
-
suggestedActions: props.overrideConfig?.suggestedActions,
|
|
53
|
-
listeners: props.listeners,
|
|
54
|
-
}}
|
|
55
|
-
>
|
|
56
|
-
<Agent />
|
|
57
|
-
</ChatDataProvider>
|
|
58
|
-
</ConfigurationProvider>
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export default AgentWidget;
|
package/src/global.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module '*.css';
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
cancelAudioRecording,
|
|
4
|
-
startAudioRecording,
|
|
5
|
-
stopAudioRecording,
|
|
6
|
-
} from '../utils/audioRecording';
|
|
7
|
-
|
|
8
|
-
export const useAudioRecording = () => {
|
|
9
|
-
const [elapsedTime, setElapsedTime] = useState('00:00');
|
|
10
|
-
const [recordingNotSupported, setRecordingNotSupported] = useState(false);
|
|
11
|
-
const [isLoadingRecording, setIsLoadingRecording] = useState(false);
|
|
12
|
-
const [isRecording, setIsRecording] = useState(false);
|
|
13
|
-
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
if (isRecording) {
|
|
16
|
-
onRecordingStarted();
|
|
17
|
-
}
|
|
18
|
-
}, [isRecording]);
|
|
19
|
-
const onRecordingStarted = () => {
|
|
20
|
-
setIsRecording(true);
|
|
21
|
-
setIsLoadingRecording(false);
|
|
22
|
-
startAudioRecording(
|
|
23
|
-
setIsRecording,
|
|
24
|
-
setRecordingNotSupported,
|
|
25
|
-
setElapsedTime
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const onRecordingCancelled = () => {
|
|
30
|
-
if (!recordingNotSupported) cancelAudioRecording();
|
|
31
|
-
setIsRecording(false);
|
|
32
|
-
setRecordingNotSupported(false);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const onRecordingStopped = (onStop: null | ((blob: Blob) => void)) => {
|
|
36
|
-
setIsLoadingRecording(true);
|
|
37
|
-
stopAudioRecording(onStop);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
elapsedTime,
|
|
42
|
-
recordingNotSupported,
|
|
43
|
-
isLoadingRecording,
|
|
44
|
-
isRecording,
|
|
45
|
-
setIsRecording,
|
|
46
|
-
onRecordingCancelled,
|
|
47
|
-
onRecordingStopped,
|
|
48
|
-
onRecordingStarted,
|
|
49
|
-
};
|
|
50
|
-
};
|
package/src/hooks/useChat.ts
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import useSWR from 'swr';
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
-
import { StreamResponse } from '../models/FlowiseClient';
|
|
4
|
-
import { getSuggestions, predict } from '../services/chat.service';
|
|
5
|
-
import {
|
|
6
|
-
ChatMessageMetadataType,
|
|
7
|
-
ChatMessageType,
|
|
8
|
-
IFileUpload,
|
|
9
|
-
PredictionData,
|
|
10
|
-
SourceDocument,
|
|
11
|
-
ToolUsage,
|
|
12
|
-
} from '../types/flowise.type';
|
|
13
|
-
import { generateUUID } from '../utils/commonUtils';
|
|
14
|
-
import { getBot } from '../services/bot.service';
|
|
15
|
-
import { BotType } from '../types/bot.type';
|
|
16
|
-
import { useConfiguration } from './useConfiguration';
|
|
17
|
-
import { SuggestionType } from 'types/common.type';
|
|
18
|
-
|
|
19
|
-
type PropsType = {
|
|
20
|
-
id?: string;
|
|
21
|
-
agentId?: string;
|
|
22
|
-
initialMessages: ChatMessageType[];
|
|
23
|
-
initialInput?: string;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
type ReturnType = {
|
|
27
|
-
messages?: ChatMessageType[];
|
|
28
|
-
setMessages: (messages: ChatMessageType[]) => void;
|
|
29
|
-
handleSubmit: (event?: { preventDefault?: () => void }) => void;
|
|
30
|
-
input?: string;
|
|
31
|
-
setInput: (input: string) => void;
|
|
32
|
-
isLoading: boolean;
|
|
33
|
-
stop: () => void;
|
|
34
|
-
chatId: string;
|
|
35
|
-
append: (message: ChatMessageType) => Promise<void>;
|
|
36
|
-
bot: BotType | null;
|
|
37
|
-
enableTTS: boolean;
|
|
38
|
-
setEnableTTS: (value: boolean) => void;
|
|
39
|
-
suggestions: SuggestionType[]
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const useChat = (props: PropsType): ReturnType => {
|
|
43
|
-
const { id, initialMessages, initialInput, agentId } = props;
|
|
44
|
-
const { apiHost, overrideConfig, theme } = useConfiguration();
|
|
45
|
-
|
|
46
|
-
const idKey = id ?? generateUUID();
|
|
47
|
-
const chatIdRef = useRef<string>(idKey);
|
|
48
|
-
const [chatId, setChatId] = useState(idKey);
|
|
49
|
-
const [bot, setBot] = useState<BotType | null>(null);
|
|
50
|
-
const [enableTTS, setEnableTTS] = useState(false);
|
|
51
|
-
const [suggestions, setSuggestions] = useState<SuggestionType[]>([]);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const updateChatId = (uuid: string) => {
|
|
55
|
-
chatIdRef.current = uuid;
|
|
56
|
-
setChatId(uuid);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (id) {
|
|
61
|
-
updateChatId(id);
|
|
62
|
-
}
|
|
63
|
-
}, [id]);
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
getBot(agentId || 'default', apiHost).then((res) => setBot(res));
|
|
67
|
-
}, [agentId, apiHost]);
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
if (bot?.id && chatId) {
|
|
71
|
-
updateSuggestions(`Agent name: ${bot.name}, Title: ${theme?.overview?.title}`)
|
|
72
|
-
}
|
|
73
|
-
}, [bot?.id, chatId])
|
|
74
|
-
|
|
75
|
-
const updateSuggestions = useCallback(async (question?: string) => {
|
|
76
|
-
const resSuggestions = await getSuggestions({ id: chatId, question, apiHost });
|
|
77
|
-
setSuggestions(resSuggestions);
|
|
78
|
-
}, [setSuggestions, chatId]);
|
|
79
|
-
|
|
80
|
-
const processResponseStream = async (
|
|
81
|
-
msgs: ChatMessageType[],
|
|
82
|
-
req: PredictionData
|
|
83
|
-
) => {
|
|
84
|
-
// Do an optimistic update to the chat state to show the updated messages immediately:
|
|
85
|
-
mutateMessages(msgs, false);
|
|
86
|
-
|
|
87
|
-
const newMessage: ChatMessageType = {
|
|
88
|
-
id: generateUUID(),
|
|
89
|
-
chatId: chatIdRef.current,
|
|
90
|
-
role: 'apiMessage',
|
|
91
|
-
content: '',
|
|
92
|
-
createdDate: new Date().toISOString(),
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const onUpdate = (chunk: StreamResponse) => {
|
|
96
|
-
if (chunk?.event === 'token') {
|
|
97
|
-
newMessage.content = newMessage.content + (chunk.data as string);
|
|
98
|
-
mutateMessages([...msgs, { ...newMessage }]);
|
|
99
|
-
} else if (chunk.event == 'usedTools') {
|
|
100
|
-
newMessage.usedTools = chunk.data as ToolUsage[];
|
|
101
|
-
mutateMessages([...msgs, { ...newMessage }]);
|
|
102
|
-
} else if (chunk.event == 'sourceDocuments') {
|
|
103
|
-
newMessage.sourceDocuments = chunk.data as SourceDocument[];
|
|
104
|
-
mutateMessages([...msgs, { ...newMessage }]);
|
|
105
|
-
} else if (chunk.event == 'metadata') {
|
|
106
|
-
newMessage.metaData = chunk.data as ChatMessageMetadataType;
|
|
107
|
-
const lastMsg = msgs[msgs.length - 1];
|
|
108
|
-
if (lastMsg) {
|
|
109
|
-
lastMsg.content = newMessage.metaData.question;
|
|
110
|
-
}
|
|
111
|
-
mutateMessages([...msgs, { ...newMessage }]);
|
|
112
|
-
updateSuggestions(`Agent name: ${bot?.name}, Title: ${theme?.overview?.title}`);
|
|
113
|
-
} else if (chunk.event == 'audio') {
|
|
114
|
-
newMessage.ttsUrl = chunk.data as string;
|
|
115
|
-
mutateMessages([...msgs, { ...newMessage }]);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
return await predict({
|
|
120
|
-
req,
|
|
121
|
-
apiHost,
|
|
122
|
-
onUpdate,
|
|
123
|
-
});
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Store a empty array as the initial messages
|
|
127
|
-
// (instead of using a default parameter value that gets re-created each time)
|
|
128
|
-
// to avoid re-renders:
|
|
129
|
-
const [initialMessagesFallback] = useState([]);
|
|
130
|
-
|
|
131
|
-
// Store the chat state in SWR, using the chatId as the key to share states.
|
|
132
|
-
const { data: messages, mutate: mutateMessages } = useSWR<ChatMessageType[]>(
|
|
133
|
-
[chatId, 'messages'],
|
|
134
|
-
null,
|
|
135
|
-
{ fallbackData: initialMessages ?? initialMessagesFallback }
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
// Keep the latest messages in a ref.
|
|
139
|
-
const messagesRef = useRef<ChatMessageType[]>(messages || []);
|
|
140
|
-
useEffect(() => {
|
|
141
|
-
messagesRef.current = messages || [];
|
|
142
|
-
}, [messages]);
|
|
143
|
-
|
|
144
|
-
// We store loading state in another hook to sync loading states across hook invocations
|
|
145
|
-
const { data: isLoading = false, mutate: mutateLoading } = useSWR<boolean>(
|
|
146
|
-
[chatId, 'loading'],
|
|
147
|
-
null
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
// Abort controller to cancel the current API call.
|
|
151
|
-
const abortControllerRef = useRef<AbortController | null>(null);
|
|
152
|
-
|
|
153
|
-
const triggerRequest = useCallback(
|
|
154
|
-
async (msgs: ChatMessageType[], req: PredictionData) => {
|
|
155
|
-
try {
|
|
156
|
-
mutateLoading(true);
|
|
157
|
-
|
|
158
|
-
const abortController = new AbortController();
|
|
159
|
-
abortControllerRef.current = abortController;
|
|
160
|
-
|
|
161
|
-
await processResponseStream(msgs, req);
|
|
162
|
-
|
|
163
|
-
abortControllerRef.current = null;
|
|
164
|
-
} catch (err) {
|
|
165
|
-
// Ignore abort errors as they are expected.
|
|
166
|
-
if ((err as any).name === 'AbortError') {
|
|
167
|
-
abortControllerRef.current = null;
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
console.error(err);
|
|
172
|
-
} finally {
|
|
173
|
-
mutateLoading(false);
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
[mutateMessages, mutateLoading]
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
const append = async (message: ChatMessageType) => {
|
|
180
|
-
if (!message.content) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const msgs = messagesRef.current.concat({
|
|
184
|
-
id: generateUUID(),
|
|
185
|
-
chatId: chatIdRef.current,
|
|
186
|
-
role: 'userMessage',
|
|
187
|
-
content: message.content,
|
|
188
|
-
createdDate: new Date().toISOString(),
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
triggerRequest(msgs, {
|
|
192
|
-
chatId: chatIdRef.current,
|
|
193
|
-
question: message.content,
|
|
194
|
-
chatflowId: bot?.id,
|
|
195
|
-
overrideConfig: overrideConfig,
|
|
196
|
-
tts: enableTTS,
|
|
197
|
-
});
|
|
198
|
-
setInput('');
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const stop = useCallback(() => {
|
|
202
|
-
if (abortControllerRef.current) {
|
|
203
|
-
abortControllerRef.current?.abort();
|
|
204
|
-
abortControllerRef.current = null;
|
|
205
|
-
}
|
|
206
|
-
}, []);
|
|
207
|
-
|
|
208
|
-
const setMessages = useCallback(
|
|
209
|
-
(msgs: ChatMessageType[]) => {
|
|
210
|
-
mutateMessages(msgs, false);
|
|
211
|
-
messagesRef.current = msgs;
|
|
212
|
-
},
|
|
213
|
-
[mutateMessages]
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
// Input state and handlers.
|
|
217
|
-
const [input, setInput] = useState(initialInput);
|
|
218
|
-
|
|
219
|
-
const handleSubmit = useCallback(
|
|
220
|
-
async (event?: { preventDefault?: () => void }, files?: IFileUpload[]) => {
|
|
221
|
-
event?.preventDefault?.();
|
|
222
|
-
|
|
223
|
-
if (!input && !files) return;
|
|
224
|
-
|
|
225
|
-
const msgs = messagesRef.current.concat({
|
|
226
|
-
id: generateUUID(),
|
|
227
|
-
chatId: chatIdRef.current,
|
|
228
|
-
role: 'userMessage',
|
|
229
|
-
content: input || '',
|
|
230
|
-
createdDate: new Date().toISOString(),
|
|
231
|
-
fileUploads: files || [],
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
triggerRequest(msgs, {
|
|
235
|
-
chatId: chatIdRef.current,
|
|
236
|
-
question: input || '',
|
|
237
|
-
uploads: files || [],
|
|
238
|
-
chatflowId: bot?.id,
|
|
239
|
-
overrideConfig: overrideConfig,
|
|
240
|
-
tts: enableTTS,
|
|
241
|
-
});
|
|
242
|
-
setInput('');
|
|
243
|
-
},
|
|
244
|
-
[input, triggerRequest, bot]
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
messages,
|
|
249
|
-
setMessages,
|
|
250
|
-
input,
|
|
251
|
-
setInput,
|
|
252
|
-
isLoading,
|
|
253
|
-
handleSubmit,
|
|
254
|
-
stop,
|
|
255
|
-
chatId,
|
|
256
|
-
append,
|
|
257
|
-
bot,
|
|
258
|
-
enableTTS,
|
|
259
|
-
setEnableTTS,
|
|
260
|
-
suggestions
|
|
261
|
-
};
|
|
262
|
-
};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useEffect, useState } from 'react';
|
|
2
|
-
import { EVENT_TYPE } from '../models';
|
|
3
|
-
import { getChatMessage } from '../services/chat.service';
|
|
4
|
-
import { ChatMessageType } from '../types/flowise.type';
|
|
5
|
-
import { generateUUID } from '../utils/commonUtils';
|
|
6
|
-
import { useConfiguration } from './useConfiguration';
|
|
7
|
-
import { SuggestionType } from '../types/common.type';
|
|
8
|
-
|
|
9
|
-
type ChatData = {
|
|
10
|
-
chatId?: string | undefined;
|
|
11
|
-
listeners?: Record<EVENT_TYPE, (props: any) => void>;
|
|
12
|
-
initialMessages?: ChatMessageType[];
|
|
13
|
-
suggestedActions?: SuggestionType[];
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const ChatDataContext = createContext<ChatData | undefined>(undefined);
|
|
17
|
-
|
|
18
|
-
export const ChatDataProvider = ({
|
|
19
|
-
children,
|
|
20
|
-
data,
|
|
21
|
-
}: {
|
|
22
|
-
children: React.ReactNode;
|
|
23
|
-
data: ChatData;
|
|
24
|
-
}) => {
|
|
25
|
-
const [chatData, setChatData] = useState<ChatData>({
|
|
26
|
-
...data,
|
|
27
|
-
chatId: data.chatId || generateUUID(),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const { apiHost } = useConfiguration();
|
|
31
|
-
|
|
32
|
-
const fetchHistory = async () => {
|
|
33
|
-
if (!chatData?.chatId) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const initialMessages = await getChatMessage({
|
|
38
|
-
chatId: chatData.chatId!,
|
|
39
|
-
apiHost,
|
|
40
|
-
});
|
|
41
|
-
setChatData({
|
|
42
|
-
...chatData,
|
|
43
|
-
initialMessages,
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
setChatData({ ...data, chatId: chatData.chatId });
|
|
49
|
-
}, [data]);
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
fetchHistory();
|
|
53
|
-
}, [chatData?.chatId]);
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<ChatDataContext.Provider value={chatData}>
|
|
57
|
-
{children}
|
|
58
|
-
</ChatDataContext.Provider>
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const useChatData = () => {
|
|
63
|
-
const context = React.useContext(ChatDataContext);
|
|
64
|
-
if (context === undefined) {
|
|
65
|
-
throw new Error('useChatData must be used within a ChatDataContext');
|
|
66
|
-
}
|
|
67
|
-
return context;
|
|
68
|
-
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useEffect, useState } from 'react';
|
|
2
|
-
import { ConfigMessageType } from 'types/common.type';
|
|
3
|
-
|
|
4
|
-
type ConfigurationData = {
|
|
5
|
-
apiHost: string;
|
|
6
|
-
agentId: string;
|
|
7
|
-
overrideConfig?: Record<string, any>;
|
|
8
|
-
theme?: {
|
|
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;
|
|
16
|
-
input?: {
|
|
17
|
-
placeholder?: string;
|
|
18
|
-
};
|
|
19
|
-
overview?: {
|
|
20
|
-
title: string;
|
|
21
|
-
description?: string;
|
|
22
|
-
};
|
|
23
|
-
} & Record<string, unknown>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const ConfigurationContext = createContext<ConfigurationData | undefined>(
|
|
27
|
-
undefined
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
export const ConfigurationProvider = ({
|
|
31
|
-
children,
|
|
32
|
-
config,
|
|
33
|
-
}: {
|
|
34
|
-
children: React.ReactNode;
|
|
35
|
-
config: ConfigurationData;
|
|
36
|
-
}) => {
|
|
37
|
-
const [configuration, setConfiguration] = useState<ConfigurationData>({
|
|
38
|
-
...config,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!config.apiHost) {
|
|
43
|
-
throw new Error('apiHost is required');
|
|
44
|
-
}
|
|
45
|
-
setConfiguration(config);
|
|
46
|
-
}, [config]);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<ConfigurationContext.Provider value={configuration}>
|
|
50
|
-
{children}
|
|
51
|
-
</ConfigurationContext.Provider>
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const useConfiguration = () => {
|
|
56
|
-
const context = React.useContext(ConfigurationContext);
|
|
57
|
-
if (context === undefined) {
|
|
58
|
-
throw new Error(
|
|
59
|
-
'useConfiguration must be used within a ConfigurationProvider'
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
return context;
|
|
63
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type RefObject, useEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
export function useScrollToBottom<T extends HTMLElement>(): [
|
|
4
|
-
RefObject<T>,
|
|
5
|
-
RefObject<T>,
|
|
6
|
-
] {
|
|
7
|
-
const containerRef = useRef<T>(null);
|
|
8
|
-
const endRef = useRef<T>(null);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
const container = containerRef.current;
|
|
12
|
-
const end = endRef.current;
|
|
13
|
-
|
|
14
|
-
if (container && end) {
|
|
15
|
-
const observer = new MutationObserver(() => {
|
|
16
|
-
end.scrollIntoView({ behavior: 'instant', block: 'end' });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
observer.observe(container, {
|
|
20
|
-
childList: true,
|
|
21
|
-
subtree: true,
|
|
22
|
-
attributes: true,
|
|
23
|
-
characterData: true,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return () => observer.disconnect();
|
|
27
|
-
}
|
|
28
|
-
}, []);
|
|
29
|
-
|
|
30
|
-
return [containerRef, endRef];
|
|
31
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { AgentWidgetType } from './features/AgentWidget';
|