@clikvn/agent-widget-embedded 0.0.1-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/.eslintrc +34 -0
- package/.prettierrc +8 -0
- package/README.md +20 -0
- package/base.json +21 -0
- package/dist/commons/constants/index.d.ts +2 -0
- package/dist/commons/constants/index.d.ts.map +1 -0
- package/dist/commons/constants/variables.d.ts +5 -0
- package/dist/commons/constants/variables.d.ts.map +1 -0
- package/dist/components/Agent/index.d.ts +3 -0
- package/dist/components/Agent/index.d.ts.map +1 -0
- package/dist/components/Chat/Chat.d.ts +10 -0
- package/dist/components/Chat/Chat.d.ts.map +1 -0
- package/dist/components/Chat/Icons.d.ts +120 -0
- package/dist/components/Chat/Icons.d.ts.map +1 -0
- package/dist/components/Chat/Markdown.d.ts +7 -0
- package/dist/components/Chat/Markdown.d.ts.map +1 -0
- package/dist/components/Chat/Message.d.ts +15 -0
- package/dist/components/Chat/Message.d.ts.map +1 -0
- package/dist/components/Chat/MultimodalInput.d.ts +24 -0
- package/dist/components/Chat/MultimodalInput.d.ts.map +1 -0
- package/dist/components/Chat/Overview.d.ts +8 -0
- package/dist/components/Chat/Overview.d.ts.map +1 -0
- package/dist/components/Chat/PreviewAttachment.d.ts +6 -0
- package/dist/components/Chat/PreviewAttachment.d.ts.map +1 -0
- package/dist/components/Chat/ui/Button.d.ts +12 -0
- package/dist/components/Chat/ui/Button.d.ts.map +1 -0
- package/dist/components/Chat/ui/Textarea.d.ts +6 -0
- package/dist/components/Chat/ui/Textarea.d.ts.map +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/features/AgentWidget/index.d.ts +16 -0
- package/dist/features/AgentWidget/index.d.ts.map +1 -0
- package/dist/hooks/useChat.d.ts +25 -0
- package/dist/hooks/useChat.d.ts.map +1 -0
- package/dist/hooks/useChatData.d.ts +18 -0
- package/dist/hooks/useChatData.d.ts.map +1 -0
- package/dist/hooks/useConfiguration.d.ts +20 -0
- package/dist/hooks/useConfiguration.d.ts.map +1 -0
- package/dist/hooks/useConnection.d.ts +15 -0
- package/dist/hooks/useConnection.d.ts.map +1 -0
- package/dist/hooks/useScrollToBottom.d.ts +6 -0
- package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/models/FlowiseClient.d.ts +20 -0
- package/dist/models/FlowiseClient.d.ts.map +1 -0
- package/dist/models.d.ts +2 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/register.d.ts +30 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/services/apis.d.ts +7 -0
- package/dist/services/apis.d.ts.map +1 -0
- package/dist/services/bot.service.d.ts +3 -0
- package/dist/services/bot.service.d.ts.map +1 -0
- package/dist/services/chat.service.d.ts +32 -0
- package/dist/services/chat.service.d.ts.map +1 -0
- package/dist/services/user.service.d.ts +3 -0
- package/dist/services/user.service.d.ts.map +1 -0
- package/dist/types/agentType.d.ts +11 -0
- package/dist/types/agentType.d.ts.map +1 -0
- package/dist/types/bot.type.d.ts +11 -0
- package/dist/types/bot.type.d.ts.map +1 -0
- package/dist/types/chat.type.d.ts +10 -0
- package/dist/types/chat.type.d.ts.map +1 -0
- package/dist/types/common.type.d.ts +11 -0
- package/dist/types/common.type.d.ts.map +1 -0
- package/dist/types/flowise.type.d.ts +90 -0
- package/dist/types/flowise.type.d.ts.map +1 -0
- package/dist/types/user.type.d.ts +14 -0
- package/dist/types/user.type.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/commonUtils.d.ts +7 -0
- package/dist/utils/commonUtils.d.ts.map +1 -0
- package/dist/utils/functionUtils.d.ts +3 -0
- package/dist/utils/functionUtils.d.ts.map +1 -0
- package/dist/utils/requestUtils.d.ts +16 -0
- package/dist/utils/requestUtils.d.ts.map +1 -0
- package/dist/utils/streamUtils.d.ts +5 -0
- package/dist/utils/streamUtils.d.ts.map +1 -0
- package/dist/web.d.ts +18 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +1 -0
- package/dist/window.d.ts +29 -0
- package/dist/window.d.ts.map +1 -0
- package/package.json +91 -0
- package/rollup.config.js +56 -0
- package/src/assets/common.css +148 -0
- package/src/assets/tailwindcss.css +3 -0
- package/src/commons/constants/index.ts +1 -0
- package/src/commons/constants/variables.ts +20 -0
- package/src/components/Agent/index.tsx +14 -0
- package/src/components/Chat/Chat.tsx +84 -0
- package/src/components/Chat/Icons.tsx +883 -0
- package/src/components/Chat/Markdown.tsx +324 -0
- package/src/components/Chat/Message.tsx +185 -0
- package/src/components/Chat/MultimodalInput.tsx +371 -0
- package/src/components/Chat/Overview.tsx +47 -0
- package/src/components/Chat/PreviewAttachment.tsx +41 -0
- package/src/components/Chat/ui/Button.tsx +55 -0
- package/src/components/Chat/ui/Textarea.tsx +23 -0
- package/src/constants.ts +1 -0
- package/src/env.d.ts +10 -0
- package/src/features/AgentWidget/index.tsx +47 -0
- package/src/global.d.ts +1 -0
- package/src/hooks/useChat.ts +225 -0
- package/src/hooks/useChatData.tsx +68 -0
- package/src/hooks/useConfiguration.tsx +54 -0
- package/src/hooks/useScrollToBottom.ts +31 -0
- package/src/index.ts +1 -0
- package/src/models/FlowiseClient.ts +103 -0
- package/src/models.ts +1 -0
- package/src/register.tsx +66 -0
- package/src/services/apis.ts +10 -0
- package/src/services/bot.service.ts +15 -0
- package/src/services/chat.service.ts +164 -0
- package/src/types/bot.type.ts +10 -0
- package/src/types/chat.type.ts +11 -0
- package/src/types/common.type.ts +11 -0
- package/src/types/flowise.type.ts +99 -0
- package/src/types/user.type.ts +15 -0
- package/src/types.ts +0 -0
- package/src/utils/commonUtils.ts +47 -0
- package/src/utils/functionUtils.ts +17 -0
- package/src/utils/requestUtils.ts +113 -0
- package/src/utils/streamUtils.ts +18 -0
- package/src/web.ts +6 -0
- package/src/window.ts +55 -0
- package/tailwind.config.cjs +122 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import FlowiseClient, { StreamResponse } from '../models/FlowiseClient';
|
|
2
|
+
import {
|
|
3
|
+
API_CHAT_MESSAGE,
|
|
4
|
+
API_CHATS,
|
|
5
|
+
API_CREATE_ATTACHMENTS,
|
|
6
|
+
API_PREDICTION,
|
|
7
|
+
API_VERSION,
|
|
8
|
+
} from './apis';
|
|
9
|
+
import { ChatRequestType, ChatType } from '../types/chat.type';
|
|
10
|
+
import { CommonChatType } from '../types/common.type';
|
|
11
|
+
import {
|
|
12
|
+
AttachmentUploadResult,
|
|
13
|
+
ChatMessageType,
|
|
14
|
+
PredictionData,
|
|
15
|
+
} from '../types/flowise.type';
|
|
16
|
+
import { request } from '../utils/requestUtils';
|
|
17
|
+
|
|
18
|
+
export const createChat = async ({
|
|
19
|
+
accessToken,
|
|
20
|
+
req,
|
|
21
|
+
apiHost,
|
|
22
|
+
}: {
|
|
23
|
+
accessToken?: string;
|
|
24
|
+
req: ChatRequestType;
|
|
25
|
+
apiHost: string;
|
|
26
|
+
}): Promise<ChatType> => {
|
|
27
|
+
const url = accessToken ? `${API_CHATS}` : `${API_VERSION}${API_CHATS}`;
|
|
28
|
+
let headers: any = {
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
};
|
|
31
|
+
if (accessToken) {
|
|
32
|
+
headers = {
|
|
33
|
+
...headers,
|
|
34
|
+
Authorization: `Bearer ${accessToken}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return request({
|
|
39
|
+
host: apiHost,
|
|
40
|
+
url,
|
|
41
|
+
headers,
|
|
42
|
+
method: 'POST',
|
|
43
|
+
body: JSON.stringify(req),
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const predict = async ({
|
|
48
|
+
accessToken,
|
|
49
|
+
req,
|
|
50
|
+
onUpdate,
|
|
51
|
+
apiHost,
|
|
52
|
+
}: {
|
|
53
|
+
accessToken?: string;
|
|
54
|
+
req: PredictionData;
|
|
55
|
+
apiHost: string;
|
|
56
|
+
onUpdate?: (chunk: StreamResponse) => void;
|
|
57
|
+
}): Promise<StreamResponse[]> => {
|
|
58
|
+
const url = accessToken
|
|
59
|
+
? `${API_PREDICTION}`
|
|
60
|
+
: `${API_VERSION}${API_PREDICTION}`;
|
|
61
|
+
const result: any[] = [];
|
|
62
|
+
const flowise = new FlowiseClient({
|
|
63
|
+
baseUrl: url,
|
|
64
|
+
accessToken: accessToken,
|
|
65
|
+
host: apiHost,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const completion: any = await flowise.createPrediction(req);
|
|
70
|
+
for await (const chunk of completion) {
|
|
71
|
+
result.push(chunk);
|
|
72
|
+
onUpdate?.(chunk);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Error:', error);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const getChatMessage = async ({
|
|
82
|
+
accessToken,
|
|
83
|
+
chatId,
|
|
84
|
+
apiHost,
|
|
85
|
+
}: {
|
|
86
|
+
accessToken?: string;
|
|
87
|
+
chatId: string;
|
|
88
|
+
apiHost: string;
|
|
89
|
+
}): Promise<ChatMessageType[]> => {
|
|
90
|
+
const headers = accessToken
|
|
91
|
+
? {
|
|
92
|
+
Authorization: `Bearer ${accessToken}`,
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
}
|
|
95
|
+
: {};
|
|
96
|
+
|
|
97
|
+
const url = accessToken
|
|
98
|
+
? `${API_CHAT_MESSAGE}/${chatId}`
|
|
99
|
+
: `${API_VERSION}${API_CHAT_MESSAGE}/${chatId}`;
|
|
100
|
+
|
|
101
|
+
return request({
|
|
102
|
+
host: apiHost,
|
|
103
|
+
url,
|
|
104
|
+
headers,
|
|
105
|
+
method: 'GET',
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const createAttachments = async ({
|
|
110
|
+
accessToken,
|
|
111
|
+
chatId,
|
|
112
|
+
body,
|
|
113
|
+
apiHost,
|
|
114
|
+
}: {
|
|
115
|
+
accessToken?: string;
|
|
116
|
+
chatId: string;
|
|
117
|
+
apiHost: string;
|
|
118
|
+
body: any;
|
|
119
|
+
}): Promise<AttachmentUploadResult[]> => {
|
|
120
|
+
const headers = accessToken
|
|
121
|
+
? {
|
|
122
|
+
Authorization: `Bearer ${accessToken}`,
|
|
123
|
+
// 'Content-Type': 'application/json',
|
|
124
|
+
}
|
|
125
|
+
: {};
|
|
126
|
+
const url = accessToken
|
|
127
|
+
? `${API_CREATE_ATTACHMENTS}/${chatId}`
|
|
128
|
+
: `${API_VERSION}${API_CREATE_ATTACHMENTS}/${chatId}`;
|
|
129
|
+
|
|
130
|
+
return request({
|
|
131
|
+
host: apiHost,
|
|
132
|
+
url,
|
|
133
|
+
headers,
|
|
134
|
+
method: 'POST',
|
|
135
|
+
body,
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const getById = async ({
|
|
140
|
+
accessToken,
|
|
141
|
+
id,
|
|
142
|
+
apiHost,
|
|
143
|
+
}: {
|
|
144
|
+
accessToken?: string;
|
|
145
|
+
id: string;
|
|
146
|
+
apiHost: string;
|
|
147
|
+
}): Promise<CommonChatType> => {
|
|
148
|
+
const headers = accessToken
|
|
149
|
+
? {
|
|
150
|
+
Authorization: `Bearer ${accessToken}`,
|
|
151
|
+
'Content-Type': 'application/json',
|
|
152
|
+
}
|
|
153
|
+
: {};
|
|
154
|
+
const url = accessToken
|
|
155
|
+
? `${API_CHATS}/${id}`
|
|
156
|
+
: `${API_VERSION}${API_CHATS}/${id}`;
|
|
157
|
+
|
|
158
|
+
return request({
|
|
159
|
+
host: apiHost,
|
|
160
|
+
url,
|
|
161
|
+
headers,
|
|
162
|
+
method: 'GET',
|
|
163
|
+
});
|
|
164
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type MessageRoleType = 'apiMessage' | 'userMessage';
|
|
2
|
+
|
|
3
|
+
export interface PredictionData {
|
|
4
|
+
chatflowId?: string;
|
|
5
|
+
question: string;
|
|
6
|
+
overrideConfig?: Record<string, any>;
|
|
7
|
+
chatId?: string;
|
|
8
|
+
streaming?: boolean;
|
|
9
|
+
history?: IMessage[];
|
|
10
|
+
uploads?: IFileUpload[];
|
|
11
|
+
leadEmail?: string;
|
|
12
|
+
action?: IAction;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ChatMessageType {
|
|
17
|
+
action?: IAction;
|
|
18
|
+
artifacts?: any;
|
|
19
|
+
chatId?: string;
|
|
20
|
+
chatType?: string;
|
|
21
|
+
chatflowid?: string;
|
|
22
|
+
content?: string;
|
|
23
|
+
createdDate?: string | Date;
|
|
24
|
+
followUpPrompts?: any;
|
|
25
|
+
id?: string;
|
|
26
|
+
leadEmail?: string;
|
|
27
|
+
role: MessageRoleType;
|
|
28
|
+
sessionId?: string;
|
|
29
|
+
usedTools?: ToolUsage[];
|
|
30
|
+
sourceDocuments?: SourceDocument[];
|
|
31
|
+
fileUploads?: IFileUpload[];
|
|
32
|
+
fileAnnotations?: FileAnnotation[];
|
|
33
|
+
agentReasoning?: AgentReasoning[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface IAction {
|
|
37
|
+
id?: string;
|
|
38
|
+
elements?: Array<{
|
|
39
|
+
type: string;
|
|
40
|
+
label: string;
|
|
41
|
+
}>;
|
|
42
|
+
mapping?: {
|
|
43
|
+
approve: string;
|
|
44
|
+
reject: string;
|
|
45
|
+
toolCalls: any[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface IFileUpload {
|
|
50
|
+
tempId?: string;
|
|
51
|
+
data?: string;
|
|
52
|
+
type: string;
|
|
53
|
+
name: string;
|
|
54
|
+
mime: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface IMessage {
|
|
58
|
+
message: string;
|
|
59
|
+
type: MessageRoleType;
|
|
60
|
+
role?: MessageRoleType;
|
|
61
|
+
content?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ToolUsage {
|
|
65
|
+
tool: string;
|
|
66
|
+
toolInput: {
|
|
67
|
+
input: string;
|
|
68
|
+
};
|
|
69
|
+
toolOutput: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface SourceDocument {
|
|
73
|
+
pageContent: string;
|
|
74
|
+
metadata: {
|
|
75
|
+
author: string;
|
|
76
|
+
date: string;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface AgentReasoning {
|
|
81
|
+
agentName: string;
|
|
82
|
+
messages: string[];
|
|
83
|
+
nodeName: string;
|
|
84
|
+
nodeId: string;
|
|
85
|
+
usedTools: ToolUsage[];
|
|
86
|
+
sourceDocuments: SourceDocument[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface FileAnnotation {
|
|
90
|
+
filePath: string;
|
|
91
|
+
fileName: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface AttachmentUploadResult {
|
|
95
|
+
name: string;
|
|
96
|
+
mimeType: string;
|
|
97
|
+
size: string;
|
|
98
|
+
content: string;
|
|
99
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CommonChatType } from './common.type';
|
|
2
|
+
|
|
3
|
+
export interface UserType {
|
|
4
|
+
id: string;
|
|
5
|
+
created?: Date;
|
|
6
|
+
lastModifiedDate?: Date;
|
|
7
|
+
phoneNumber?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
email: string;
|
|
10
|
+
userClik: number;
|
|
11
|
+
chats?: CommonChatType[];
|
|
12
|
+
|
|
13
|
+
user?: number;
|
|
14
|
+
authorities?: string[];
|
|
15
|
+
}
|
package/src/types.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ClassValue, clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export const cn = (...inputs: ClassValue[]) => {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function getLocalStorage(key: string) {
|
|
9
|
+
if (typeof window !== 'undefined') {
|
|
10
|
+
return JSON.parse(localStorage.getItem(key) || '[]');
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function generateUUID(): string {
|
|
16
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
17
|
+
const r = (Math.random() * 16) | 0;
|
|
18
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
19
|
+
return v.toString(16);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const generateExtendedFileName = (originalFileName: string) => {
|
|
24
|
+
// Extract the name and extension from the original file name
|
|
25
|
+
const dotIndex = originalFileName.lastIndexOf('.');
|
|
26
|
+
const baseName =
|
|
27
|
+
dotIndex === -1
|
|
28
|
+
? originalFileName
|
|
29
|
+
: originalFileName.substring(0, dotIndex);
|
|
30
|
+
const extension = dotIndex === -1 ? '' : originalFileName.substring(dotIndex);
|
|
31
|
+
|
|
32
|
+
// Get the current date and time
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const year = now.getFullYear();
|
|
35
|
+
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-11
|
|
36
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
37
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
38
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
39
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
40
|
+
|
|
41
|
+
// Create the new unique file name
|
|
42
|
+
return `${baseName}_${year}${month}${day}_${hours}${minutes}${seconds}${extension}`;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const sleep = async (duration: number): Promise<void> => {
|
|
46
|
+
return new Promise((resolve) => setTimeout(resolve, duration));
|
|
47
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const nonNull = (obj: any): boolean => {
|
|
2
|
+
return obj !== null && obj !== undefined;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const toQuery = (params: any, delimiter = '&') => {
|
|
6
|
+
const keys = Object.keys(params);
|
|
7
|
+
|
|
8
|
+
return keys.reduce((str, key, index) => {
|
|
9
|
+
let query = `${str}${key}=${params[key]}`;
|
|
10
|
+
|
|
11
|
+
if (index < keys.length - 1) {
|
|
12
|
+
query += delimiter;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return query;
|
|
16
|
+
}, '');
|
|
17
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { BE_API, LANGUAGE_HEADER } from '../commons/constants';
|
|
2
|
+
import { processTextStream } from './streamUtils';
|
|
3
|
+
|
|
4
|
+
type RequestPropsTypes = {
|
|
5
|
+
host?: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
8
|
+
streamProtocol?: 'data' | 'text';
|
|
9
|
+
onStreamUpdate?: (chunks: { content: string }[]) => void;
|
|
10
|
+
onStreamFinish?: (result: { content: string }) => void;
|
|
11
|
+
[x: string]: any;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const defaultHeaders = { 'Content-Type': 'application/json' };
|
|
15
|
+
|
|
16
|
+
export const request = async (props: RequestPropsTypes): Promise<any> => {
|
|
17
|
+
const {
|
|
18
|
+
host = BE_API,
|
|
19
|
+
url = '',
|
|
20
|
+
method = 'GET',
|
|
21
|
+
headers = { ...defaultHeaders, ...props.headers },
|
|
22
|
+
params,
|
|
23
|
+
streamProtocol,
|
|
24
|
+
onStreamUpdate,
|
|
25
|
+
onStreamFinish,
|
|
26
|
+
...options
|
|
27
|
+
} = props;
|
|
28
|
+
let apiLanguage: string = LANGUAGE_HEADER.en;
|
|
29
|
+
if (headers?.language) {
|
|
30
|
+
apiLanguage = LANGUAGE_HEADER[headers.language];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const customHeader = { ...headers, language: apiLanguage };
|
|
34
|
+
const requestInit = {
|
|
35
|
+
method,
|
|
36
|
+
headers: customHeader,
|
|
37
|
+
...options,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
let queryString = '';
|
|
41
|
+
let apiUrl = '';
|
|
42
|
+
|
|
43
|
+
// Generate query string if params exist
|
|
44
|
+
if (!!params && !!Object.keys(params).length) {
|
|
45
|
+
queryString = Object.keys(params)
|
|
46
|
+
.filter((key) => !!params[key])
|
|
47
|
+
.map((key) => {
|
|
48
|
+
const val: string[] | string = params[key];
|
|
49
|
+
if (Array.isArray(val)) {
|
|
50
|
+
return val
|
|
51
|
+
.map((v) => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`)
|
|
52
|
+
.join('&');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return `${encodeURIComponent(key)}=${encodeURIComponent(val)}`;
|
|
56
|
+
})
|
|
57
|
+
.join('&');
|
|
58
|
+
|
|
59
|
+
apiUrl = `${url}?${queryString}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const response = await fetch(`${host}${apiUrl || url}`, {
|
|
64
|
+
...requestInit,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
console.error(
|
|
69
|
+
new Error(`API request failed with status ${response.status}`)
|
|
70
|
+
);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!response.body) {
|
|
75
|
+
console.error(new Error('The response body is empty.'));
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!streamProtocol) {
|
|
80
|
+
return response.json();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
switch (streamProtocol) {
|
|
84
|
+
case 'text': {
|
|
85
|
+
const resultMessage = {
|
|
86
|
+
content: '',
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
await processTextStream({
|
|
90
|
+
stream: response.body as any,
|
|
91
|
+
onTextPart: (chunk) => {
|
|
92
|
+
resultMessage.content += chunk;
|
|
93
|
+
|
|
94
|
+
// note: creating a new message object is required for Solid.js streaming
|
|
95
|
+
onStreamUpdate?.([{ ...resultMessage }]);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// in text mode, we don't have usage information or finish reason:
|
|
100
|
+
onStreamFinish?.(resultMessage);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
default: {
|
|
105
|
+
console.error(new Error(`Unknown stream protocol: ${streamProtocol}`));
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(error);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const processTextStream = async ({
|
|
2
|
+
stream,
|
|
3
|
+
onTextPart,
|
|
4
|
+
}: {
|
|
5
|
+
stream: ReadableStream<Uint8Array>;
|
|
6
|
+
onTextPart: (chunk: string) => Promise<void> | void;
|
|
7
|
+
}): Promise<void> => {
|
|
8
|
+
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line no-constant-condition
|
|
11
|
+
while (true) {
|
|
12
|
+
const { done, value } = await reader.read();
|
|
13
|
+
if (done) {
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
await onTextPart(value);
|
|
17
|
+
}
|
|
18
|
+
};
|
package/src/web.ts
ADDED
package/src/window.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { agentWidgetElementName } from './constants';
|
|
2
|
+
import { registerWebComponents } from './register';
|
|
3
|
+
import { EVENT_TYPE } from './models';
|
|
4
|
+
|
|
5
|
+
let elementUsed: Element | undefined;
|
|
6
|
+
|
|
7
|
+
type VoiceAgentWidget = {
|
|
8
|
+
apiHost: string;
|
|
9
|
+
agentId: string;
|
|
10
|
+
overrideConfig?: {
|
|
11
|
+
chatId?: string | undefined;
|
|
12
|
+
} & Record<string, unknown>;
|
|
13
|
+
theme?: {
|
|
14
|
+
avatar?: string;
|
|
15
|
+
} & Record<string, unknown>;
|
|
16
|
+
listeners?: Record<EVENT_TYPE, (props: any) => void>;
|
|
17
|
+
};
|
|
18
|
+
export const initWidget = (props: VoiceAgentWidget & { id?: string }) => {
|
|
19
|
+
destroy();
|
|
20
|
+
const element: any = props.id
|
|
21
|
+
? document.getElementById(props.id)
|
|
22
|
+
: document.querySelector(agentWidgetElementName);
|
|
23
|
+
if (!element) throw new Error(`${agentWidgetElementName} element not found.`);
|
|
24
|
+
if (customElements.get(agentWidgetElementName)) {
|
|
25
|
+
element.updateAttributes(props);
|
|
26
|
+
} else {
|
|
27
|
+
Object.assign(element, props);
|
|
28
|
+
registerWebComponents();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const destroy = () => {
|
|
33
|
+
elementUsed?.remove();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type AgentWidget = {
|
|
37
|
+
initWidget: typeof initWidget;
|
|
38
|
+
destroy: typeof destroy;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
declare const window:
|
|
42
|
+
| {
|
|
43
|
+
AgentWidget: AgentWidget | undefined;
|
|
44
|
+
}
|
|
45
|
+
| undefined;
|
|
46
|
+
|
|
47
|
+
export const parseAgentVoice = () => ({
|
|
48
|
+
initWidget,
|
|
49
|
+
destroy,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const injectAgentVoiceInWindow = (agent: AgentWidget) => {
|
|
53
|
+
if (typeof window === 'undefined') return;
|
|
54
|
+
window.AgentWidget = { ...agent };
|
|
55
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2
|
+
const defaultTheme = require('tailwindcss/defaultTheme');
|
|
3
|
+
|
|
4
|
+
function rem2px(input, fontSize = 16) {
|
|
5
|
+
if (input == null) {
|
|
6
|
+
return input;
|
|
7
|
+
}
|
|
8
|
+
switch (typeof input) {
|
|
9
|
+
case 'object':
|
|
10
|
+
if (Array.isArray(input)) {
|
|
11
|
+
return input.map((val) => rem2px(val, fontSize));
|
|
12
|
+
}
|
|
13
|
+
// eslint-disable-next-line no-case-declarations
|
|
14
|
+
const ret = {};
|
|
15
|
+
for (const key in input) {
|
|
16
|
+
ret[key] = rem2px(input[key], fontSize);
|
|
17
|
+
}
|
|
18
|
+
return ret;
|
|
19
|
+
case 'string':
|
|
20
|
+
return input.replace(
|
|
21
|
+
/(\d*\.?\d+)rem$/,
|
|
22
|
+
(_, val) => `${parseFloat(val) * fontSize}px`
|
|
23
|
+
);
|
|
24
|
+
case 'function':
|
|
25
|
+
return eval(
|
|
26
|
+
input
|
|
27
|
+
.toString()
|
|
28
|
+
.replace(
|
|
29
|
+
/(\d*\.?\d+)rem/g,
|
|
30
|
+
(_, val) => `${parseFloat(val) * fontSize}px`
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
default:
|
|
34
|
+
return input;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @type {import('tailwindcss').Config} */
|
|
39
|
+
module.exports = {
|
|
40
|
+
darkMode: ['class'],
|
|
41
|
+
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
|
42
|
+
theme: {
|
|
43
|
+
...rem2px(defaultTheme),
|
|
44
|
+
fontFamily: {
|
|
45
|
+
sans: ['Be Vietnam Pro', 'sans-serif'],
|
|
46
|
+
mono: ['Be Vietnam Pro', 'sans-serif'],
|
|
47
|
+
},
|
|
48
|
+
extend: {
|
|
49
|
+
keyframes: {
|
|
50
|
+
'fade-in': {
|
|
51
|
+
'0%': {
|
|
52
|
+
opacity: '0',
|
|
53
|
+
},
|
|
54
|
+
'100%': {
|
|
55
|
+
opacity: '1',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
animation: {
|
|
60
|
+
'fade-in': 'fade-in 0.3s ease-out',
|
|
61
|
+
},
|
|
62
|
+
borderRadius: {
|
|
63
|
+
lg: 'var(--radius)',
|
|
64
|
+
md: 'calc(var(--radius) - 2px)',
|
|
65
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
66
|
+
},
|
|
67
|
+
colors: {
|
|
68
|
+
background: 'hsl(var(--background))',
|
|
69
|
+
foreground: 'hsl(var(--foreground))',
|
|
70
|
+
card: {
|
|
71
|
+
DEFAULT: 'hsl(var(--card))',
|
|
72
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
73
|
+
},
|
|
74
|
+
popover: {
|
|
75
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
76
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
77
|
+
},
|
|
78
|
+
primary: {
|
|
79
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
80
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
81
|
+
},
|
|
82
|
+
secondary: {
|
|
83
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
84
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
85
|
+
},
|
|
86
|
+
muted: {
|
|
87
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
88
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
89
|
+
},
|
|
90
|
+
accent: {
|
|
91
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
92
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
93
|
+
},
|
|
94
|
+
destructive: {
|
|
95
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
96
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
97
|
+
},
|
|
98
|
+
border: 'hsl(var(--border))',
|
|
99
|
+
input: 'hsl(var(--input))',
|
|
100
|
+
ring: 'hsl(var(--ring))',
|
|
101
|
+
chart: {
|
|
102
|
+
1: 'hsl(var(--chart-1))',
|
|
103
|
+
2: 'hsl(var(--chart-2))',
|
|
104
|
+
3: 'hsl(var(--chart-3))',
|
|
105
|
+
4: 'hsl(var(--chart-4))',
|
|
106
|
+
5: 'hsl(var(--chart-5))',
|
|
107
|
+
},
|
|
108
|
+
sidebar: {
|
|
109
|
+
DEFAULT: 'hsl(var(--sidebar-background))',
|
|
110
|
+
foreground: 'hsl(var(--sidebar-foreground))',
|
|
111
|
+
primary: 'hsl(var(--sidebar-primary))',
|
|
112
|
+
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
|
|
113
|
+
accent: 'hsl(var(--sidebar-accent))',
|
|
114
|
+
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
|
|
115
|
+
border: 'hsl(var(--sidebar-border))',
|
|
116
|
+
ring: 'hsl(var(--sidebar-ring))',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
|
|
122
|
+
};
|