feat: dify1.11.1进行适配
@@ -3,10 +3,10 @@ FROM node:22-alpine3.21 AS base
|
||||
LABEL maintainer="takatost@gmail.com"
|
||||
|
||||
# if you located in China, you can use aliyun mirror to speed up
|
||||
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||
|
||||
# if you located in China, you can use taobao registry to speed up
|
||||
# RUN npm config set registry https://registry.npmmirror.com
|
||||
RUN npm config set registry https://registry.npmmirror.com
|
||||
|
||||
RUN apk add --no-cache tzdata
|
||||
RUN corepack enable
|
||||
|
||||
80
dify_1.11.1/web/app/components/base/iframe-postmessage.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
'use client'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
/**
|
||||
* IframePostMessage
|
||||
* 页面加载完成后向父页面发送一次消息,并每 5 秒发送一次。
|
||||
* 仅当当前窗口运行在 iframe 中时才发送。
|
||||
*/
|
||||
const IframePostMessage = () => {
|
||||
const initializedRef = useRef(false)
|
||||
|
||||
/**
|
||||
* sendMessage
|
||||
* 向父页面发送消息的函数:收集当前页面的 localStorage 全量键值并发送。
|
||||
* 如果不在 iframe 环境中则不发送。
|
||||
*/
|
||||
const sendMessage = () => {
|
||||
try {
|
||||
if (typeof window === 'undefined') return
|
||||
// 只在 iframe 环境下发送
|
||||
if (window.parent === window) return
|
||||
// 收集 localStorage 全量数据
|
||||
const localStorageData: Record<string, string | null> = {}
|
||||
try {
|
||||
const { localStorage } = window
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i)
|
||||
if (!key) continue
|
||||
localStorageData[key] = localStorage.getItem(key)
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// 可能因浏览器隐私设置导致不可访问 localStorage
|
||||
}
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: 'dify-localstorage',
|
||||
status: 1,
|
||||
message: '将智能体本地缓存发送给父页面!',
|
||||
data: localStorageData,
|
||||
},
|
||||
'*',
|
||||
)
|
||||
}
|
||||
catch {
|
||||
// 忽略跨域或其他运行时错误
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (initializedRef.current) return
|
||||
initializedRef.current = true
|
||||
|
||||
let timer: number | undefined
|
||||
|
||||
const init = () => {
|
||||
sendMessage()
|
||||
timer = window.setInterval(sendMessage, 5000)
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
const onReady = () => {
|
||||
init()
|
||||
document.removeEventListener('DOMContentLoaded', onReady)
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', onReady)
|
||||
}
|
||||
else {
|
||||
init()
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timer) window.clearInterval(timer)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default IframePostMessage
|
||||
@@ -4,6 +4,7 @@ import type { Viewport } from 'next'
|
||||
import I18nServer from './components/i18n-server'
|
||||
import BrowserInitializer from './components/browser-initializer'
|
||||
import SentryInitializer from './components/sentry-initializer'
|
||||
import IframePostMessage from './components/base/iframe-postmessage'
|
||||
import { getLocaleOnServer } from '@/i18n-config/server'
|
||||
import { TanstackQueryInitializer } from '@/context/query-client'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
@@ -109,6 +110,7 @@ const LocaleLayout = async ({
|
||||
</BrowserInitializer>
|
||||
</ThemeProvider>
|
||||
<RoutePrefixHandle />
|
||||
<IframePostMessage />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 173 KiB |
BIN
dify_1.11.1/web/public/logo/logo.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
@@ -128,7 +128,35 @@ export const createFirstDocument = ({ body }: { body: CreateDocumentReq }): Prom
|
||||
}
|
||||
|
||||
export const createDocument = ({ datasetId, body }: { datasetId: string; body: CreateDocumentReq }): Promise<createDocumentResponse> => {
|
||||
return post<createDocumentResponse>(`/datasets/${datasetId}/documents`, { body })
|
||||
const IsHsAiApp = localStorage.getItem('IsHsAiApp')
|
||||
if (IsHsAiApp == null) {
|
||||
// 当 IsHsAiApp 为 null 时,调用 post 方法并返回其结果
|
||||
return post<createDocumentResponse>(`/datasets/${datasetId}/documents`, { body })
|
||||
}
|
||||
else{
|
||||
// 当 IsHsAiApp 不为 null 时,调用 Electron 的 IPC 方法
|
||||
// 需要返回一个 Promise,以符合 Fetcher 的返回类型
|
||||
return new Promise<createDocumentResponse>((resolve, reject) => {
|
||||
if (typeof window !== 'undefined' && 'electron' in window) {
|
||||
// 安全地使用 window.electron
|
||||
// @ts-ignore
|
||||
window.electron.ipcRenderer
|
||||
.invoke('difyWebUploadFileToApi', datasetId, JSON.stringify(body))
|
||||
.then((response: any) => {
|
||||
console.log(response)
|
||||
// 假设 response 是符合 createDocumentResponse 类型的
|
||||
resolve(response as createDocumentResponse)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error(error)
|
||||
reject(error) // 捕获错误并拒绝 Promise
|
||||
})
|
||||
}
|
||||
else {
|
||||
console.warn('Electron API is not available in this environment.')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const fetchIndexingEstimate = ({ datasetId, documentId }: CommonDocReq): Promise<IndexingEstimateResponse> => {
|
||||
|
||||