cmcts-c-agent-embedding 1.0.0-cagent
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/.env +2 -0
- package/.env.example +34 -0
- package/.eslintrc.cjs +14 -0
- package/.prettierignore +3 -0
- package/.prettierrc +8 -0
- package/README.md +349 -0
- package/base.json +21 -0
- package/dist/BubbleChat.d.ts +13 -0
- package/dist/BubbleChat.d.ts.map +1 -0
- package/dist/FullPageChat.d.ts +18 -0
- package/dist/FullPageChat.d.ts.map +1 -0
- package/dist/components/Badge.d.ts +10 -0
- package/dist/components/Badge.d.ts.map +1 -0
- package/dist/components/Bot.d.ts +127 -0
- package/dist/components/Bot.d.ts.map +1 -0
- package/dist/components/FeedbackContentDialog.d.ts +13 -0
- package/dist/components/FeedbackContentDialog.d.ts.map +1 -0
- package/dist/components/Toast.d.ts +10 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/TypingBubble.d.ts +2 -0
- package/dist/components/TypingBubble.d.ts.map +1 -0
- package/dist/components/avatars/Avatar.d.ts +4 -0
- package/dist/components/avatars/Avatar.d.ts.map +1 -0
- package/dist/components/avatars/DefaultAvatar.d.ts +2 -0
- package/dist/components/avatars/DefaultAvatar.d.ts.map +1 -0
- package/dist/components/bubbles/AgentReasoningBubble.d.ts +16 -0
- package/dist/components/bubbles/AgentReasoningBubble.d.ts.map +1 -0
- package/dist/components/bubbles/BotBubble.d.ts +35 -0
- package/dist/components/bubbles/BotBubble.d.ts.map +1 -0
- package/dist/components/bubbles/FollowUpPromptBubble.d.ts +8 -0
- package/dist/components/bubbles/FollowUpPromptBubble.d.ts.map +1 -0
- package/dist/components/bubbles/GuestBubble.d.ts +16 -0
- package/dist/components/bubbles/GuestBubble.d.ts.map +1 -0
- package/dist/components/bubbles/LeadCaptureBubble.d.ts +20 -0
- package/dist/components/bubbles/LeadCaptureBubble.d.ts.map +1 -0
- package/dist/components/bubbles/LoadingBubble.d.ts +8 -0
- package/dist/components/bubbles/LoadingBubble.d.ts.map +1 -0
- package/dist/components/bubbles/SourceBubble.d.ts +9 -0
- package/dist/components/bubbles/SourceBubble.d.ts.map +1 -0
- package/dist/components/bubbles/StarterPromptBubble.d.ts +8 -0
- package/dist/components/bubbles/StarterPromptBubble.d.ts.map +1 -0
- package/dist/components/buttons/AttachmentUploadButton.d.ts +11 -0
- package/dist/components/buttons/AttachmentUploadButton.d.ts.map +1 -0
- package/dist/components/buttons/CancelButton.d.ts +10 -0
- package/dist/components/buttons/CancelButton.d.ts.map +1 -0
- package/dist/components/buttons/FeedbackButtons.d.ts +14 -0
- package/dist/components/buttons/FeedbackButtons.d.ts.map +1 -0
- package/dist/components/buttons/ImageUploadButton.d.ts +11 -0
- package/dist/components/buttons/ImageUploadButton.d.ts.map +1 -0
- package/dist/components/buttons/LeadCaptureButtons.d.ts +11 -0
- package/dist/components/buttons/LeadCaptureButtons.d.ts.map +1 -0
- package/dist/components/buttons/RecordAudioButton.d.ts +11 -0
- package/dist/components/buttons/RecordAudioButton.d.ts.map +1 -0
- package/dist/components/buttons/SendButton.d.ts +13 -0
- package/dist/components/buttons/SendButton.d.ts.map +1 -0
- package/dist/components/icons/AddImageIcon.d.ts +3 -0
- package/dist/components/icons/AddImageIcon.d.ts.map +1 -0
- package/dist/components/icons/AttachmentIcon.d.ts +3 -0
- package/dist/components/icons/AttachmentIcon.d.ts.map +1 -0
- package/dist/components/icons/CircleDotIcon.d.ts +3 -0
- package/dist/components/icons/CircleDotIcon.d.ts.map +1 -0
- package/dist/components/icons/ClipboardIcon.d.ts +3 -0
- package/dist/components/icons/ClipboardIcon.d.ts.map +1 -0
- package/dist/components/icons/CmcIcon.d.ts +3 -0
- package/dist/components/icons/CmcIcon.d.ts.map +1 -0
- package/dist/components/icons/DeleteIcon.d.ts +3 -0
- package/dist/components/icons/DeleteIcon.d.ts.map +1 -0
- package/dist/components/icons/FullScreenIcon.d.ts +3 -0
- package/dist/components/icons/FullScreenIcon.d.ts.map +1 -0
- package/dist/components/icons/RecordIcon.d.ts +3 -0
- package/dist/components/icons/RecordIcon.d.ts.map +1 -0
- package/dist/components/icons/ResetBtn.d.ts +3 -0
- package/dist/components/icons/ResetBtn.d.ts.map +1 -0
- package/dist/components/icons/SendIcon.d.ts +3 -0
- package/dist/components/icons/SendIcon.d.ts.map +1 -0
- package/dist/components/icons/SendIconOff.d.ts +3 -0
- package/dist/components/icons/SendIconOff.d.ts.map +1 -0
- package/dist/components/icons/SendIconOn.d.ts +3 -0
- package/dist/components/icons/SendIconOn.d.ts.map +1 -0
- package/dist/components/icons/SparklesIcon.d.ts +3 -0
- package/dist/components/icons/SparklesIcon.d.ts.map +1 -0
- package/dist/components/icons/ThumbsDownIcon.d.ts +5 -0
- package/dist/components/icons/ThumbsDownIcon.d.ts.map +1 -0
- package/dist/components/icons/ThumbsUpIcon.d.ts +5 -0
- package/dist/components/icons/ThumbsUpIcon.d.ts.map +1 -0
- package/dist/components/icons/TickIcon.d.ts +2 -0
- package/dist/components/icons/TickIcon.d.ts.map +1 -0
- package/dist/components/icons/TrashIcon.d.ts +3 -0
- package/dist/components/icons/TrashIcon.d.ts.map +1 -0
- package/dist/components/icons/XIcon.d.ts +5 -0
- package/dist/components/icons/XIcon.d.ts.map +1 -0
- package/dist/components/icons/index.d.ts +15 -0
- package/dist/components/icons/index.d.ts.map +1 -0
- package/dist/components/image/PreviewImage.d.ts +5 -0
- package/dist/components/image/PreviewImage.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/inputs/textInput/components/FilePreview.d.ts +12 -0
- package/dist/components/inputs/textInput/components/FilePreview.d.ts.map +1 -0
- package/dist/components/inputs/textInput/components/ShortTextInput.d.ts +13 -0
- package/dist/components/inputs/textInput/components/ShortTextInput.d.ts.map +1 -0
- package/dist/components/inputs/textInput/components/TextInput.d.ts +44 -0
- package/dist/components/inputs/textInput/components/TextInput.d.ts.map +1 -0
- package/dist/components/inputs/textInput/index.d.ts +3 -0
- package/dist/components/inputs/textInput/index.d.ts.map +1 -0
- package/dist/components/mobile/MobileWelcomeScreen.d.ts +13 -0
- package/dist/components/mobile/MobileWelcomeScreen.d.ts.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/features/bubble/components/Bubble.d.ts +5 -0
- package/dist/features/bubble/components/Bubble.d.ts.map +1 -0
- package/dist/features/bubble/components/BubbleButton.d.ts +16 -0
- package/dist/features/bubble/components/BubbleButton.d.ts.map +1 -0
- package/dist/features/bubble/components/Tooltip.d.ts +15 -0
- package/dist/features/bubble/components/Tooltip.d.ts.map +1 -0
- package/dist/features/bubble/components/index.d.ts +2 -0
- package/dist/features/bubble/components/index.d.ts.map +1 -0
- package/dist/features/bubble/index.d.ts +2 -0
- package/dist/features/bubble/index.d.ts.map +1 -0
- package/dist/features/bubble/types.d.ts +108 -0
- package/dist/features/bubble/types.d.ts.map +1 -0
- package/dist/features/full/components/Full.d.ts +7 -0
- package/dist/features/full/components/Full.d.ts.map +1 -0
- package/dist/features/full/components/index.d.ts +2 -0
- package/dist/features/full/components/index.d.ts.map +1 -0
- package/dist/features/full/index.d.ts +2 -0
- package/dist/features/full/index.d.ts.map +1 -0
- package/dist/features/popup/components/DisclaimerPopup.d.ts +14 -0
- package/dist/features/popup/components/DisclaimerPopup.d.ts.map +1 -0
- package/dist/features/popup/components/Popup.d.ts +8 -0
- package/dist/features/popup/components/Popup.d.ts.map +1 -0
- package/dist/features/popup/components/index.d.ts +3 -0
- package/dist/features/popup/components/index.d.ts.map +1 -0
- package/dist/features/popup/index.d.ts +2 -0
- package/dist/features/popup/index.d.ts.map +1 -0
- package/dist/features/popup/types.d.ts +8 -0
- package/dist/features/popup/types.d.ts.map +1 -0
- package/dist/hooks/useMobileDetection.d.ts +52 -0
- package/dist/hooks/useMobileDetection.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/queries/sendMessageQuery.d.ts +125 -0
- package/dist/queries/sendMessageQuery.d.ts.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/test-markdown-component.d.ts +2 -0
- package/dist/test-markdown-component.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/audioRecording.d.ts +21 -0
- package/dist/utils/audioRecording.d.ts.map +1 -0
- package/dist/utils/chatInputHistory.d.ts +22 -0
- package/dist/utils/chatInputHistory.d.ts.map +1 -0
- package/dist/utils/index.d.ts +27 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/isMobileSignal.d.ts +2 -0
- package/dist/utils/isMobileSignal.d.ts.map +1 -0
- package/dist/utils/mobileUtils.d.ts +32 -0
- package/dist/utils/mobileUtils.d.ts.map +1 -0
- package/dist/utils/ultimateJsonParser.d.ts +2 -0
- package/dist/utils/ultimateJsonParser.d.ts.map +1 -0
- package/dist/web.d.ts +29 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +1 -0
- package/dist/window.d.ts +33 -0
- package/dist/window.d.ts.map +1 -0
- package/images/ChatEmbed.gif +0 -0
- package/images/proxyserver.png +0 -0
- package/package.json +81 -0
- package/public/index.html +153 -0
- package/server.js +401 -0
package/dist/window.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { observersConfigType } from './components/Bot';
|
|
2
|
+
import { BubbleTheme } from './features/bubble/types';
|
|
3
|
+
type BotProps = {
|
|
4
|
+
chatflowid: string;
|
|
5
|
+
apiHost?: string;
|
|
6
|
+
onRequest?: (request: RequestInit) => Promise<void>;
|
|
7
|
+
chatflowConfig?: Record<string, unknown>;
|
|
8
|
+
observersConfig?: observersConfigType;
|
|
9
|
+
theme?: BubbleTheme;
|
|
10
|
+
chatwootUrl?: string;
|
|
11
|
+
roomIds?: Record<string, string>;
|
|
12
|
+
isUseFAQ?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare const initFull: (props: BotProps & {
|
|
15
|
+
id?: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
export declare const init: (props: BotProps) => void;
|
|
18
|
+
export declare const destroy: () => void;
|
|
19
|
+
type Chatbot = {
|
|
20
|
+
initFull: typeof initFull;
|
|
21
|
+
init: typeof init;
|
|
22
|
+
destroy: typeof destroy;
|
|
23
|
+
};
|
|
24
|
+
export declare const parseChatbot: () => {
|
|
25
|
+
initFull: (props: BotProps & {
|
|
26
|
+
id?: string;
|
|
27
|
+
}) => void;
|
|
28
|
+
init: (props: BotProps) => void;
|
|
29
|
+
destroy: () => void;
|
|
30
|
+
};
|
|
31
|
+
export declare const injectChatbotInWindow: (bot: Chatbot) => void;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=window.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../src/window.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,QAAQ,UAAW,QAAQ,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,SAMzD,CAAC;AAEF,eAAO,MAAM,IAAI,UAAW,QAAQ,SAOnC,CAAC;AAEF,eAAO,MAAM,OAAO,YAEnB,CAAC;AAEF,KAAK,OAAO,GAAG;IACb,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB,CAAC;AAQF,eAAO,MAAM,YAAY;sBAjCO,QAAQ,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE;kBAQ9B,QAAQ;;CA6BlC,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAAS,OAAO,SAGjD,CAAC"}
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cmcts-c-agent-embedding",
|
|
3
|
+
"version": "1.0.0-cagent",
|
|
4
|
+
"description": "Javascript library to display flowise chatbot on your website",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "cross-env NODE_ENV=development rollup --watch --config rollup.config.js",
|
|
10
|
+
"build": "cross-env NODE_ENV=production rollup --config rollup.config.js",
|
|
11
|
+
"type-check": "tsc --noEmit",
|
|
12
|
+
"lint": "eslint \"src/**/*.ts*\"",
|
|
13
|
+
"lint-fix": "eslint --fix \"src/**/*.ts*\"",
|
|
14
|
+
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,md,mdx}\"",
|
|
15
|
+
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,md,mdx}\"",
|
|
16
|
+
"prepare": "husky install",
|
|
17
|
+
"start": "node server.js",
|
|
18
|
+
"build-and-publish": "yarn build && npm publish"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@babel/core": "^7.22.1",
|
|
23
|
+
"@microsoft/fetch-event-source": "^2.0.1",
|
|
24
|
+
"@ts-stack/markdown": "^1.4.0",
|
|
25
|
+
"@types/pdfjs-dist": "^2.10.378",
|
|
26
|
+
"axios": "^1.7.7",
|
|
27
|
+
"c-agent-embedding": "^1.0.4",
|
|
28
|
+
"c-agent-embedding-react": "^1.0.1",
|
|
29
|
+
"cors": "^2.8.5",
|
|
30
|
+
"cross-env": "^7.0.3",
|
|
31
|
+
"device-detector-js": "^3.0.3",
|
|
32
|
+
"dotenv": "^16.4.5",
|
|
33
|
+
"express": "^4.21.1",
|
|
34
|
+
"form-data": "^4.0.1",
|
|
35
|
+
"lodash": "^4.17.21",
|
|
36
|
+
"multer": "^1.4.5-lts.1",
|
|
37
|
+
"node-fetch": "^3.3.2",
|
|
38
|
+
"pdfjs-dist": "3.11.174",
|
|
39
|
+
"prettier": "^3.4.2",
|
|
40
|
+
"solid-element": "1.7.0",
|
|
41
|
+
"solid-js": "1.7.1",
|
|
42
|
+
"zod": "^3.22.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@babel/preset-typescript": "7.21.4",
|
|
46
|
+
"@rollup/plugin-babel": "6.0.3",
|
|
47
|
+
"@rollup/plugin-commonjs": "^25.0.0",
|
|
48
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
49
|
+
"@rollup/plugin-node-resolve": "15.0.1",
|
|
50
|
+
"@rollup/plugin-terser": "0.4.0",
|
|
51
|
+
"@rollup/plugin-typescript": "11.0.0",
|
|
52
|
+
"@tailwindcss/typography": "^0.5.10",
|
|
53
|
+
"@types/lodash": "^4.14.195",
|
|
54
|
+
"@types/node": "18.15.11",
|
|
55
|
+
"@types/uuid": "^8.3.4",
|
|
56
|
+
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
|
57
|
+
"@typescript-eslint/parser": "^5.57.0",
|
|
58
|
+
"autoprefixer": "10.4.14",
|
|
59
|
+
"babel-plugin-lodash": "^3.3.4",
|
|
60
|
+
"babel-preset-solid": "1.7.1",
|
|
61
|
+
"eslint": "^8.24.0",
|
|
62
|
+
"eslint-config-next": "13.2.4",
|
|
63
|
+
"eslint-config-prettier": "^9.0.0",
|
|
64
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
65
|
+
"eslint-plugin-react": "^7.26.1",
|
|
66
|
+
"eslint-plugin-solid": "0.12.0",
|
|
67
|
+
"husky": "^8.0.0",
|
|
68
|
+
"postcss": "8.4.21",
|
|
69
|
+
"react": "18.2.0",
|
|
70
|
+
"rollup": "3.23.0",
|
|
71
|
+
"rollup-plugin-livereload": "2.0.5",
|
|
72
|
+
"rollup-plugin-postcss": "4.0.2",
|
|
73
|
+
"rollup-plugin-serve": "2.0.2",
|
|
74
|
+
"rollup-plugin-typescript-paths": "1.4.0",
|
|
75
|
+
"rollup-plugin-uglify": "^6.0.4",
|
|
76
|
+
"tailwindcss": "3.3.1",
|
|
77
|
+
"typescript": "5.0.3",
|
|
78
|
+
"uuid": "^9.0.1"
|
|
79
|
+
},
|
|
80
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
81
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
NOTE: This .html file (and public folder) is optional and can be safely deleted.
|
|
3
|
+
It serves only as a demo/test page.
|
|
4
|
+
|
|
5
|
+
The chatbot can be embedded directly on any allowed domain using the embed script that
|
|
6
|
+
is generated when starting the server.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
<!doctype html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
15
|
+
<title>Flowise Chatbot Widget</title>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body>
|
|
19
|
+
<!-- <div id="root">
|
|
20
|
+
<flowise-fullchatbot></flowise-fullchatbot>
|
|
21
|
+
</div> -->
|
|
22
|
+
<script type="module">
|
|
23
|
+
import Chatbot from './web.js';
|
|
24
|
+
|
|
25
|
+
const customStringify = (obj) => {
|
|
26
|
+
let stringified = JSON.stringify(obj, null, 4)
|
|
27
|
+
.replace(/"([^"]+)":/g, '$1:')
|
|
28
|
+
.replace(/: "([^"]+)"/g, (match, value) => (value.includes('<') ? `: "${value}"` : `: '${value}'`))
|
|
29
|
+
.replace(/: "(true|false|\d+)"/g, ': $1')
|
|
30
|
+
.replace(/customCSS: ""/g, 'customCSS: ``');
|
|
31
|
+
return stringified
|
|
32
|
+
.split('\n')
|
|
33
|
+
.map((line, index) => {
|
|
34
|
+
if (index === 0) return line;
|
|
35
|
+
return ' '.repeat(8) + line;
|
|
36
|
+
})
|
|
37
|
+
.join('\n');
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Example initialization:
|
|
41
|
+
// If your .env contains:
|
|
42
|
+
// agent1=xyz789-uvw456,https://example.com
|
|
43
|
+
// support=abc123-def456,https://example.com
|
|
44
|
+
// salesbot=ghi123-jkl456,https://example.com
|
|
45
|
+
//
|
|
46
|
+
// Then use the environment variable name as chatflowid:
|
|
47
|
+
Chatbot.init({
|
|
48
|
+
// chatflowid: '6a63bb88-88f7-4c4d-805e-9c027c85707b', // or 'support', 'salesbot', etc.
|
|
49
|
+
// chatflowid: 'b573e66d-0e28-4798-8e4f-fbbaff8e236f', // or 'support', 'salesbot', etc.
|
|
50
|
+
// chatflowid: '7ee803b4-e3f8-4f33-bf85-ef9ab9d6f693', // or 'support', 'salesbot', etc.
|
|
51
|
+
chatflowid: '529479a0-d808-4b73-8d32-102ba4ac2216', // or 'support', 'salesbot', etc.
|
|
52
|
+
// apiHost: 'https://vib.cagent.cmcts.ai',
|
|
53
|
+
apiHost: 'https://stock.cmcts.ai/c-agent',
|
|
54
|
+
chatwootUrl: 'https://livechat.cagent.cmcts.ai',
|
|
55
|
+
roomIds: {
|
|
56
|
+
'0123456789': 'Xa6HmhfbU5K73ZhHnspzKhqs',
|
|
57
|
+
},
|
|
58
|
+
theme: customStringify({
|
|
59
|
+
button: {
|
|
60
|
+
backgroundColor: '#3B81F6',
|
|
61
|
+
right: 20,
|
|
62
|
+
bottom: 20,
|
|
63
|
+
size: 48,
|
|
64
|
+
dragAndDrop: true,
|
|
65
|
+
iconColor: 'white',
|
|
66
|
+
customIconSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg',
|
|
67
|
+
autoWindowOpen: {
|
|
68
|
+
autoOpen: true,
|
|
69
|
+
openDelay: 2,
|
|
70
|
+
autoOpenOnMobile: false,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
tooltip: {
|
|
74
|
+
showTooltip: true,
|
|
75
|
+
tooltipMessage: 'Hi There 👋!',
|
|
76
|
+
tooltipBackgroundColor: 'black',
|
|
77
|
+
tooltipTextColor: 'white',
|
|
78
|
+
tooltipFontSize: 16,
|
|
79
|
+
},
|
|
80
|
+
disclaimer: {
|
|
81
|
+
title: 'Disclaimer',
|
|
82
|
+
message: 'By using this chatbot, you agree to the <a target="_blank" href="https://flowiseai.com/terms">Terms & Condition</a>',
|
|
83
|
+
textColor: 'black',
|
|
84
|
+
buttonColor: '#3b82f6',
|
|
85
|
+
buttonText: 'Start Chatting',
|
|
86
|
+
buttonTextColor: 'white',
|
|
87
|
+
blurredBackgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
88
|
+
backgroundColor: 'white',
|
|
89
|
+
},
|
|
90
|
+
customCSS: ``,
|
|
91
|
+
chatWindow: {
|
|
92
|
+
showTitle: true,
|
|
93
|
+
showAgentMessages: true,
|
|
94
|
+
title: 'Agent Studio Bot',
|
|
95
|
+
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg',
|
|
96
|
+
welcomeMessage: 'Hello! This is custom welcome message',
|
|
97
|
+
errorMessage: 'This is a custom error message',
|
|
98
|
+
backgroundColor: '#ffffff',
|
|
99
|
+
backgroundImage: 'enter image path or link',
|
|
100
|
+
height: 700,
|
|
101
|
+
width: 400,
|
|
102
|
+
fontSize: 16,
|
|
103
|
+
starterPrompts: ['What is a bot?', 'Who are you?'],
|
|
104
|
+
starterPromptFontSize: 15,
|
|
105
|
+
clearChatOnReload: false,
|
|
106
|
+
sourceDocsTitle: 'Sources:',
|
|
107
|
+
renderHTML: true,
|
|
108
|
+
botMessage: {
|
|
109
|
+
backgroundColor: '#f7f8ff',
|
|
110
|
+
textColor: '#303235',
|
|
111
|
+
showAvatar: true,
|
|
112
|
+
avatarSrc: 'https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png',
|
|
113
|
+
},
|
|
114
|
+
userMessage: {
|
|
115
|
+
backgroundColor: '#3B81F6',
|
|
116
|
+
textColor: '#ffffff',
|
|
117
|
+
showAvatar: true,
|
|
118
|
+
avatarSrc: 'https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png',
|
|
119
|
+
},
|
|
120
|
+
textInput: {
|
|
121
|
+
placeholder: 'Type your question',
|
|
122
|
+
backgroundColor: '#ffffff',
|
|
123
|
+
textColor: '#303235',
|
|
124
|
+
sendButtonColor: '#3B81F6',
|
|
125
|
+
maxChars: 50,
|
|
126
|
+
maxCharsWarningMessage: 'You exceeded the characters limit. Please input less than 50 characters.',
|
|
127
|
+
autoFocus: true,
|
|
128
|
+
sendMessageSound: true,
|
|
129
|
+
sendSoundLocation: 'send_message.mp3',
|
|
130
|
+
receiveMessageSound: true,
|
|
131
|
+
receiveSoundLocation: 'receive_message.mp3',
|
|
132
|
+
},
|
|
133
|
+
feedback: {
|
|
134
|
+
color: '#303235',
|
|
135
|
+
},
|
|
136
|
+
dateTimeToggle: {
|
|
137
|
+
date: true,
|
|
138
|
+
time: true,
|
|
139
|
+
},
|
|
140
|
+
footer: {
|
|
141
|
+
textColor: '#303235',
|
|
142
|
+
text: 'Powered by',
|
|
143
|
+
company: 'Agent Studio',
|
|
144
|
+
// companyLink: 'https://flowiseai.com'
|
|
145
|
+
companyLink: '#',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
}),
|
|
149
|
+
});
|
|
150
|
+
</script>
|
|
151
|
+
</body>
|
|
152
|
+
|
|
153
|
+
</html>
|
package/server.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
Error.stackTraceLimit = 0;
|
|
2
|
+
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import cors from 'cors';
|
|
5
|
+
import fetch from 'node-fetch';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import dotenv from 'dotenv';
|
|
9
|
+
import axios from 'axios';
|
|
10
|
+
import multer from 'multer';
|
|
11
|
+
import FormData from 'form-data';
|
|
12
|
+
import { generateEmbedScript } from './src/utils/embedScript.js';
|
|
13
|
+
|
|
14
|
+
dotenv.config();
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
|
|
19
|
+
const API_HOST = process.env.API_HOST;
|
|
20
|
+
const FLOWISE_API_KEY = process.env.FLOWISE_API_KEY;
|
|
21
|
+
|
|
22
|
+
if (!API_HOST) {
|
|
23
|
+
console.error('API_HOST is not set in environment variables');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!FLOWISE_API_KEY) {
|
|
28
|
+
console.error('FLOWISE_API_KEY is not set in environment variables');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const parseChatflows = () => {
|
|
33
|
+
try {
|
|
34
|
+
const chatflows = new Map();
|
|
35
|
+
|
|
36
|
+
// Get all environment variables that don't start with special prefixes
|
|
37
|
+
const chatflowVars = Object.entries(process.env).filter(([key]) => {
|
|
38
|
+
return (
|
|
39
|
+
!key.startsWith('_') &&
|
|
40
|
+
!key.startsWith('npm_') &&
|
|
41
|
+
!key.startsWith('yarn_') &&
|
|
42
|
+
!key.startsWith('VSCODE_') &&
|
|
43
|
+
key !== 'API_HOST' &&
|
|
44
|
+
key !== 'FLOWISE_API_KEY' &&
|
|
45
|
+
key !== 'PORT' &&
|
|
46
|
+
key !== 'HOST' &&
|
|
47
|
+
key !== 'BASE_URL' &&
|
|
48
|
+
key !== 'NODE_ENV'
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (chatflowVars.length === 0) {
|
|
53
|
+
console.error('No chatflow configurations found in environment variables');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const defaultDomains = process.env.NODE_ENV === 'production' ? [] : ['http://localhost:5678'];
|
|
58
|
+
|
|
59
|
+
for (const [identifier, value] of chatflowVars) {
|
|
60
|
+
const parts = value.split(',').map((s) => s.trim());
|
|
61
|
+
const chatflowId = parts[0];
|
|
62
|
+
const configuredDomains = parts.length > 1 ? parts.slice(1) : [];
|
|
63
|
+
|
|
64
|
+
const domains = [...new Set([...defaultDomains, ...configuredDomains])];
|
|
65
|
+
|
|
66
|
+
if (!chatflowId) {
|
|
67
|
+
console.error(`Missing chatflow ID for ${identifier}`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (domains.includes('*')) {
|
|
72
|
+
console.error(`\x1b[31mError: Wildcard (*) domains are not allowed in ${identifier}. This flow will not be accessible.\x1b[0m`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
chatflows.set(identifier, { chatflowId, domains });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (chatflows.size === 0) {
|
|
80
|
+
console.error('No valid chatflow configurations found');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return chatflows;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Failed to parse chatflow configurations:', error);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const chatflows = parseChatflows();
|
|
92
|
+
|
|
93
|
+
const getChatflowDetails = (identifier) => {
|
|
94
|
+
let chatflow = chatflows.get(identifier);
|
|
95
|
+
|
|
96
|
+
if (!chatflow) {
|
|
97
|
+
const lowerIdentifier = identifier.toLowerCase();
|
|
98
|
+
for (const [key, value] of chatflows.entries()) {
|
|
99
|
+
if (key.toLowerCase() === lowerIdentifier) {
|
|
100
|
+
chatflow = value;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!chatflow) {
|
|
107
|
+
throw new Error(`Chatflow not found: ${identifier}`);
|
|
108
|
+
}
|
|
109
|
+
return chatflow;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const isValidUUID = (str) => {
|
|
113
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
114
|
+
return uuidPattern.test(str);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const isValidChatflowConfig = (value) => {
|
|
118
|
+
if (!value) return false;
|
|
119
|
+
const parts = value.split(',').map((s) => s.trim());
|
|
120
|
+
return isValidUUID(parts[0]);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
console.info('\x1b[36m%s\x1b[0m', 'Configured chatflows:');
|
|
124
|
+
chatflows.forEach((config, identifier) => {
|
|
125
|
+
if (isValidChatflowConfig(config.chatflowId)) {
|
|
126
|
+
console.info('\x1b[36m%s\x1b[0m', ` ${identifier}: ${config.chatflowId} (${config.domains.join(', ')})`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const isValidDomain = (origin, domains) => {
|
|
131
|
+
if (!origin) return true;
|
|
132
|
+
return domains.includes(origin);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const app = express();
|
|
136
|
+
app.use(express.json({ limit: '50mb' }));
|
|
137
|
+
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
|
138
|
+
|
|
139
|
+
app.use(
|
|
140
|
+
cors({
|
|
141
|
+
origin: true,
|
|
142
|
+
credentials: true,
|
|
143
|
+
methods: ['GET', 'POST', 'PUT', 'OPTIONS'],
|
|
144
|
+
allowedHeaders: ['*'],
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
app.get('/', (_, res) => {
|
|
149
|
+
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
app.get('/web.js', (req, res) => {
|
|
153
|
+
const origin = req.headers.origin;
|
|
154
|
+
|
|
155
|
+
const allAllowedDomains = Array.from(chatflows.values()).flatMap((config) => config.domains);
|
|
156
|
+
|
|
157
|
+
if (!isValidDomain(origin, allAllowedDomains)) {
|
|
158
|
+
return res.status(403).send('Access Denied');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
res.set({
|
|
162
|
+
'Content-Type': 'application/javascript',
|
|
163
|
+
'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
|
|
164
|
+
Pragma: 'no-cache',
|
|
165
|
+
Expires: '0',
|
|
166
|
+
});
|
|
167
|
+
res.sendFile(path.join(__dirname, 'dist', 'web.js'));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const validateApiKey = (req, res, next) => {
|
|
171
|
+
if (req.path === '/web.js' || req.path === '/' || req.method === 'OPTIONS') {
|
|
172
|
+
return next();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (req.path.includes('/get-upload-file')) {
|
|
176
|
+
return next();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let identifier;
|
|
180
|
+
const pathParts = req.path.split('/').filter(Boolean);
|
|
181
|
+
|
|
182
|
+
if (pathParts.length >= 3) {
|
|
183
|
+
identifier = pathParts[3];
|
|
184
|
+
} else {
|
|
185
|
+
identifier = req.query.chatflowId?.split('/')[0];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!identifier) {
|
|
189
|
+
return res.status(400).json({ error: 'Bad Request' });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let chatflow;
|
|
193
|
+
try {
|
|
194
|
+
chatflow = getChatflowDetails(identifier);
|
|
195
|
+
req.chatflow = chatflow;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
return res.status(404).json({ error: 'Not Found' });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const origin = req.headers.origin;
|
|
201
|
+
const userAgent = req.headers['user-agent'];
|
|
202
|
+
const acceptLanguage = req.headers['accept-language'];
|
|
203
|
+
const accept = req.headers['accept'];
|
|
204
|
+
const secChUa = req.headers['sec-ch-ua'];
|
|
205
|
+
const secChUaPlatform = req.headers['sec-ch-ua-platform'];
|
|
206
|
+
const secChUaMobile = req.headers['sec-ch-ua-mobile'];
|
|
207
|
+
const secFetchMode = req.headers['sec-fetch-mode'];
|
|
208
|
+
const secFetchSite = req.headers['sec-fetch-site'];
|
|
209
|
+
|
|
210
|
+
if (
|
|
211
|
+
userAgent &&
|
|
212
|
+
acceptLanguage &&
|
|
213
|
+
accept &&
|
|
214
|
+
secChUa &&
|
|
215
|
+
secChUaPlatform &&
|
|
216
|
+
secChUaMobile &&
|
|
217
|
+
['?0', '?1'].includes(secChUaMobile) &&
|
|
218
|
+
secFetchMode === 'cors' &&
|
|
219
|
+
secFetchSite &&
|
|
220
|
+
['same-origin', 'same-site', 'cross-site'].includes(secFetchSite)
|
|
221
|
+
) {
|
|
222
|
+
if (isValidDomain(origin, chatflow.domains)) {
|
|
223
|
+
return next();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const authHeader = req.headers.authorization;
|
|
228
|
+
if (authHeader && authHeader.startsWith('Bearer ') && authHeader.split(' ')[1] === FLOWISE_API_KEY) {
|
|
229
|
+
return next();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
app.use(validateApiKey);
|
|
236
|
+
|
|
237
|
+
const proxyEndpoints = {
|
|
238
|
+
prediction: {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
path: '/api/v1/prediction/:identifier',
|
|
241
|
+
target: '/api/v1/prediction',
|
|
242
|
+
},
|
|
243
|
+
config: {
|
|
244
|
+
method: 'GET',
|
|
245
|
+
path: '/api/v1/public-chatbotConfig/:identifier',
|
|
246
|
+
target: '/api/v1/public-chatbotConfig',
|
|
247
|
+
},
|
|
248
|
+
streaming: {
|
|
249
|
+
method: 'GET',
|
|
250
|
+
path: '/api/v1/chatflows-streaming/:identifier',
|
|
251
|
+
target: '/api/v1/chatflows-streaming',
|
|
252
|
+
},
|
|
253
|
+
files: {
|
|
254
|
+
method: 'GET',
|
|
255
|
+
path: '/api/v1/get-upload-file',
|
|
256
|
+
target: '/api/v1/get-upload-file',
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const handleProxy = async (req, res, targetPath) => {
|
|
261
|
+
try {
|
|
262
|
+
let identifier = req.query.chatflowId?.split('/')[0] || req.path.split('/').pop() || null;
|
|
263
|
+
|
|
264
|
+
if (!identifier) {
|
|
265
|
+
return res.status(400).json({ error: 'Bad Request' });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const chatflow = getChatflowDetails(identifier);
|
|
269
|
+
if (!chatflow) {
|
|
270
|
+
return res.status(404).json({ error: 'Not Found' });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (req.query.chatId && req.query.fileName) {
|
|
274
|
+
const url = `${API_HOST}${targetPath}?chatflowId=${chatflow.chatflowId}&chatId=${req.query.chatId}&fileName=${req.query.fileName}`;
|
|
275
|
+
|
|
276
|
+
const response = await fetch(url, {
|
|
277
|
+
method: req.method,
|
|
278
|
+
headers: {
|
|
279
|
+
Authorization: `Bearer ${FLOWISE_API_KEY}`,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
console.error(`File proxy error: ${response.status} ${response.statusText}`);
|
|
285
|
+
return res.status(response.status).json({ error: `File proxy error: ${response.statusText}` });
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const contentType = response.headers.get('content-type');
|
|
289
|
+
if (contentType) {
|
|
290
|
+
res.setHeader('Content-Type', contentType);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return response.body.pipe(res);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
let finalPath = `${targetPath}/${chatflow.chatflowId}`;
|
|
297
|
+
const url = `${API_HOST}${finalPath}`;
|
|
298
|
+
|
|
299
|
+
const response = await fetch(url, {
|
|
300
|
+
method: req.method,
|
|
301
|
+
headers: {
|
|
302
|
+
...(req.method !== 'GET' && { 'Content-Type': 'application/json' }),
|
|
303
|
+
Authorization: `Bearer ${FLOWISE_API_KEY}`,
|
|
304
|
+
},
|
|
305
|
+
body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
if (!response.ok) {
|
|
309
|
+
console.error(`Proxy error: ${response.status} ${response.statusText}`);
|
|
310
|
+
return res.status(response.status).json({ error: `Proxy error: ${response.statusText}` });
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const contentType = response.headers.get('content-type');
|
|
314
|
+
|
|
315
|
+
if (contentType?.includes('image/') || contentType?.includes('audio/') || contentType?.includes('application/octet-stream')) {
|
|
316
|
+
res.setHeader('Content-Type', contentType);
|
|
317
|
+
return response.body.pipe(res);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (contentType?.includes('text/event-stream')) {
|
|
321
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
322
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
323
|
+
res.setHeader('Connection', 'keep-alive');
|
|
324
|
+
return response.body.pipe(res);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (contentType?.includes('application/json')) {
|
|
328
|
+
const data = await response.json();
|
|
329
|
+
return res.json(data);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return response.body.pipe(res);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error('Proxy error:', error);
|
|
335
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
Object.values(proxyEndpoints).forEach(({ method, path, target }) => {
|
|
340
|
+
app[method.toLowerCase()](path, (req, res) => {
|
|
341
|
+
return handleProxy(req, res, target);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const storage = multer.memoryStorage();
|
|
346
|
+
const upload = multer({ storage: storage });
|
|
347
|
+
|
|
348
|
+
app.post('/api/v1/attachments/:identifier/:chatId', upload.array('files'), async (req, res) => {
|
|
349
|
+
try {
|
|
350
|
+
const chatId = req.params.chatId;
|
|
351
|
+
if (!chatId) {
|
|
352
|
+
return res.status(400).json({ error: 'Bad Request' });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!req.files || req.files.length === 0) {
|
|
356
|
+
return res.status(400).json({ error: 'Bad Request' });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const form = new FormData();
|
|
360
|
+
req.files.forEach((file) => {
|
|
361
|
+
form.append('files', file.buffer, {
|
|
362
|
+
filename: file.originalname,
|
|
363
|
+
contentType: file.mimetype,
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const chatflow = req.chatflow;
|
|
368
|
+
const targetUrl = `${API_HOST}/api/v1/attachments/${chatflow.chatflowId}/${chatId}`;
|
|
369
|
+
|
|
370
|
+
const response = await axios.post(targetUrl, form, {
|
|
371
|
+
headers: {
|
|
372
|
+
...form.getHeaders(),
|
|
373
|
+
Authorization: `Bearer ${FLOWISE_API_KEY}`,
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
res.json(response.data);
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.error('Attachment upload error:', error);
|
|
380
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
app.use((_req, res) => {
|
|
385
|
+
res.status(404).json({ error: 'Not Found' });
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const PORT = process.env.PORT || 3001;
|
|
389
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
390
|
+
|
|
391
|
+
const server = app.listen(PORT, HOST, () => {
|
|
392
|
+
const addr = server.address();
|
|
393
|
+
if (!addr || typeof addr === 'string') return;
|
|
394
|
+
|
|
395
|
+
const baseUrl =
|
|
396
|
+
process.env.BASE_URL || process.env.NODE_ENV === 'production'
|
|
397
|
+
? `https://${process.env.HOST || 'localhost'}`
|
|
398
|
+
: `http://${HOST === '0.0.0.0' ? 'localhost' : HOST}:${addr.port}`;
|
|
399
|
+
|
|
400
|
+
generateEmbedScript(baseUrl);
|
|
401
|
+
});
|