mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-06-30 18:25:14 +08:00
feat: passing the inputs values using difyChatbotConfig
(#6376)
This commit is contained in:
parent
e493ce9981
commit
284ef52bba
@ -31,6 +31,7 @@ import type {
|
|||||||
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
||||||
import { useToastContext } from '@/app/components/base/toast'
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
import { changeLanguage } from '@/i18n/i18next-config'
|
import { changeLanguage } from '@/i18n/i18next-config'
|
||||||
|
import { getProcessedInputsFromUrlParams } from '@/app/components/base/chat/utils'
|
||||||
|
|
||||||
export const useEmbeddedChatbot = () => {
|
export const useEmbeddedChatbot = () => {
|
||||||
const isInstalledApp = false
|
const isInstalledApp = false
|
||||||
@ -109,6 +110,7 @@ export const useEmbeddedChatbot = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const newConversationInputsRef = useRef<Record<string, any>>({})
|
const newConversationInputsRef = useRef<Record<string, any>>({})
|
||||||
const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any>>({})
|
const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any>>({})
|
||||||
|
const [initInputs, setInitInputs] = useState<Record<string, any>>({})
|
||||||
const handleNewConversationInputsChange = useCallback((newInputs: Record<string, any>) => {
|
const handleNewConversationInputsChange = useCallback((newInputs: Record<string, any>) => {
|
||||||
newConversationInputsRef.current = newInputs
|
newConversationInputsRef.current = newInputs
|
||||||
setNewConversationInputs(newInputs)
|
setNewConversationInputs(newInputs)
|
||||||
@ -116,30 +118,49 @@ export const useEmbeddedChatbot = () => {
|
|||||||
const inputsForms = useMemo(() => {
|
const inputsForms = useMemo(() => {
|
||||||
return (appParams?.user_input_form || []).filter((item: any) => item.paragraph || item.select || item['text-input'] || item.number).map((item: any) => {
|
return (appParams?.user_input_form || []).filter((item: any) => item.paragraph || item.select || item['text-input'] || item.number).map((item: any) => {
|
||||||
if (item.paragraph) {
|
if (item.paragraph) {
|
||||||
|
let value = initInputs[item.paragraph.variable]
|
||||||
|
if (value && item.paragraph.max_length && value.length > item.paragraph.max_length)
|
||||||
|
value = value.slice(0, item.paragraph.max_length)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item.paragraph,
|
...item.paragraph,
|
||||||
|
default: value || item.default,
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.number) {
|
if (item.number) {
|
||||||
|
const convertedNumber = Number(initInputs[item.number.variable]) ?? undefined
|
||||||
return {
|
return {
|
||||||
...item.number,
|
...item.number,
|
||||||
|
default: convertedNumber || item.default,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.select) {
|
if (item.select) {
|
||||||
|
const isInputInOptions = item.select.options.includes(initInputs[item.select.variable])
|
||||||
return {
|
return {
|
||||||
...item.select,
|
...item.select,
|
||||||
|
default: (isInputInOptions ? initInputs[item.select.variable] : undefined) || item.default,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value = initInputs[item['text-input'].variable]
|
||||||
|
if (value && item['text-input'].max_length && value.length > item['text-input'].max_length)
|
||||||
|
value = value.slice(0, item['text-input'].max_length)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item['text-input'],
|
...item['text-input'],
|
||||||
|
default: value || item.default,
|
||||||
type: 'text-input',
|
type: 'text-input',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [appParams])
|
}, [appParams])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// init inputs from url params
|
||||||
|
setInitInputs(getProcessedInputsFromUrlParams())
|
||||||
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const conversationInputs: Record<string, any> = {}
|
const conversationInputs: Record<string, any> = {}
|
||||||
|
|
||||||
|
20
web/app/components/base/chat/utils.ts
Normal file
20
web/app/components/base/chat/utils.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
async function decodeBase64AndDecompress(base64String: string) {
|
||||||
|
const binaryString = atob(base64String)
|
||||||
|
const compressedUint8Array = Uint8Array.from(binaryString, char => char.charCodeAt(0))
|
||||||
|
const decompressedStream = new Response(compressedUint8Array).body.pipeThrough(new DecompressionStream('gzip'))
|
||||||
|
const decompressedArrayBuffer = await new Response(decompressedStream).arrayBuffer()
|
||||||
|
return new TextDecoder().decode(decompressedArrayBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProcessedInputsFromUrlParams(): Record<string, any> {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
|
const inputs: Record<string, any> = {}
|
||||||
|
urlParams.forEach(async (value, key) => {
|
||||||
|
inputs[key] = await decodeBase64AndDecompress(decodeURIComponent(value))
|
||||||
|
})
|
||||||
|
return inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getProcessedInputsFromUrlParams,
|
||||||
|
}
|
@ -24,27 +24,55 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Main function to embed the chatbot
|
// Main function to embed the chatbot
|
||||||
function embedChatbot() {
|
async function embedChatbot() {
|
||||||
if (!config || !config.token) {
|
if (!config || !config.token) {
|
||||||
console.error(`${configKey} is empty or token is not provided`);
|
console.error(`${configKey} is empty or token is not provided`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function compressAndEncodeBase64(input) {
|
||||||
|
const uint8Array = new TextEncoder().encode(input);
|
||||||
|
const compressedStream = new Response(
|
||||||
|
new Blob([uint8Array]).stream().pipeThrough(new CompressionStream('gzip'))
|
||||||
|
).arrayBuffer();
|
||||||
|
const compressedUint8Array = new Uint8Array(await compressedStream);
|
||||||
|
return btoa(String.fromCharCode(...compressedUint8Array));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCompressedInputsFromConfig() {
|
||||||
|
const inputs = config?.inputs || {};
|
||||||
|
const compressedInputs = {};
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(inputs).map(async ([key, value]) => {
|
||||||
|
compressedInputs[key] = await compressAndEncodeBase64(value);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return compressedInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(await getCompressedInputsFromConfig());
|
||||||
|
|
||||||
const baseUrl =
|
const baseUrl =
|
||||||
config.baseUrl || `https://${config.isDev ? "dev." : ""}udify.app`;
|
config.baseUrl || `https://${config.isDev ? "dev." : ""}udify.app`;
|
||||||
|
|
||||||
|
// pre-check the length of the URL
|
||||||
|
const iframeUrl = `${baseUrl}/chatbot/${config.token}?${params}`;
|
||||||
|
if(iframeUrl.length > 2048) {
|
||||||
|
console.error("The URL is too long, please reduce the number of inputs to prevent the bot from failing to load");
|
||||||
|
}
|
||||||
|
|
||||||
// Function to create the iframe for the chatbot
|
// Function to create the iframe for the chatbot
|
||||||
function createIframe() {
|
function createIframe() {
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.allow = "fullscreen;microphone";
|
iframe.allow = "fullscreen;microphone";
|
||||||
iframe.title = "dify chatbot bubble window";
|
iframe.title = "dify chatbot bubble window";
|
||||||
iframe.id = iframeId;
|
iframe.id = iframeId;
|
||||||
iframe.src = `${baseUrl}/chatbot/${config.token}`;
|
iframe.src = iframeUrl;
|
||||||
iframe.style.cssText = `
|
iframe.style.cssText = `
|
||||||
border: none; position: fixed; flex-direction: column; justify-content: space-between;
|
border: none; position: fixed; flex-direction: column; justify-content: space-between;
|
||||||
box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px;
|
box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px;
|
||||||
bottom: 5rem; right: 1rem; width: 24rem; max-width: calc(100vw - 2rem); height: 40rem;
|
bottom: 5rem; right: 1rem; width: 24rem; max-width: calc(100vw - 2rem); height: 40rem;
|
||||||
max-height: calc(100vh - 6rem); border-radius: 0.75rem; display: flex; z-index: 2147483647;
|
max-height: calc(100vh - 6rem); border-radius: 0.75rem; display: flex; z-index: 2147483647;
|
||||||
overflow: hidden; left: unset; background-color: #F3F4F6;
|
overflow: hidden; left: unset; background-color: #F3F4F6;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -106,19 +134,19 @@
|
|||||||
document.head.appendChild(styleSheet);
|
document.head.appendChild(styleSheet);
|
||||||
styleSheet.sheet.insertRule(`
|
styleSheet.sheet.insertRule(`
|
||||||
#${containerDiv.id} {
|
#${containerDiv.id} {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: var(--${containerDiv.id}-bottom, 1rem);
|
bottom: var(--${containerDiv.id}-bottom, 1rem);
|
||||||
right: var(--${containerDiv.id}-right, 1rem);
|
right: var(--${containerDiv.id}-right, 1rem);
|
||||||
left: var(--${containerDiv.id}-left, unset);
|
left: var(--${containerDiv.id}-left, unset);
|
||||||
top: var(--${containerDiv.id}-top, unset);
|
top: var(--${containerDiv.id}-top, unset);
|
||||||
width: var(--${containerDiv.id}-width, 50px);
|
width: var(--${containerDiv.id}-width, 50px);
|
||||||
height: var(--${containerDiv.id}-height, 50px);
|
height: var(--${containerDiv.id}-height, 50px);
|
||||||
border-radius: var(--${containerDiv.id}-border-radius, 25px);
|
border-radius: var(--${containerDiv.id}-border-radius, 25px);
|
||||||
background-color: var(--${containerDiv.id}-bg-color, #155EEF);
|
background-color: var(--${containerDiv.id}-bg-color, #155EEF);
|
||||||
box-shadow: var(--${containerDiv.id}-box-shadow, rgba(0, 0, 0, 0.2) 0px 4px 8px 0px);
|
box-shadow: var(--${containerDiv.id}-box-shadow, rgba(0, 0, 0, 0.2) 0px 4px 8px 0px);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 2147483647;
|
z-index: 2147483647;
|
||||||
transition: all 0.2s ease-in-out 0s;
|
transition: all 0.2s ease-in-out 0s;
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
styleSheet.sheet.insertRule(`
|
styleSheet.sheet.insertRule(`
|
||||||
@ -154,7 +182,8 @@
|
|||||||
} else {
|
} else {
|
||||||
document.addEventListener('keydown', handleEscKey);
|
document.addEventListener('keydown', handleEscKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resetIframePosition();
|
resetIframePosition();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
32
web/public/embed.min.js
vendored
32
web/public/embed.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user