由于此项目有嵌入dify部分功能的需求,针对dify源码做了部分调整。可以使用iframe的方式嵌入dify,并支持对其样式与脚本的调整。
<template>
<iframe :src="defaultUrl" id="dify"></iframe>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const defaultUrl = ref('http://192.168.20.119:28003');
onMounted(()=>{
const ele = document.getElementById('dify');
ele.onload = function(){
if(ele && ele.contentwindow){
const msg1 = {
type:'insertStyle',
value:`body{background-color:red;font-size:58px;}`
};
ele.contentWindow.postMessage(JSON.stringify(msg1), defaultUrl.value);
const msg2 = {
type: 'insertScript',
value: `console.log('hello world');`
}
ele.contentWindow.postMessage(JSON.stringify(msg2), defaultUrl.value);
}
}
})
</script>
<style scoped lang="css"></style>
为了解决无界微前端跨域的问题,修改了dify的配置文件。
nginx配置文件目录: /data/disk2/llm_platform/dify/docker/nginx/conf.d
nginx配置文件
修改:default.conf.template文件,添加如下内容:
添加内容如下:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' '*';
最终结果如下:
# Please do not directly edit this file. Instead, modify the .env variables related to NGINX configuration.
server {
listen ${NGINX_PORT};
server_name ${NGINX_SERVER_NAME};
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' '*';
location /console/api {
proxy_pass http://api:5001;
include proxy.conf;
}
location /api {
proxy_pass http://api:5001;
include proxy.conf;
}
location /v1 {
proxy_pass http://api:5001;
include proxy.conf;
}
location /files {
proxy_pass http://api:5001;
include proxy.conf;
}
location / {
proxy_pass http://web:3000;
include proxy.conf;
}
# placeholder for acme challenge location
${ACME_CHALLENGE_LOCATION}
# placeholder for https config defined in https.conf.template
${HTTPS_CONFIG}
}
然后执行:docker restart docker-nginx-1重启容器即可。
在大模型2.0中嵌入dify项目时,初始使用微前端方式,但是使用微前端时,发现dify的前端使用的是服务器端渲染框架nextjs,在加载dify项目时,会有报错,经过查询资料得知,无界当前不支持服务器端渲染(SSR),无界嵌入next.js或者nuxt.js都没有好的解决方案。
为了解决此问题,考虑了两个方案:
iframe进行嵌入,通过postMessage进行通信,调整样式和脚本。此方案需要调整dify的源码,与初衷有些许背离。无界的源码,调整起来比较困难。由于修改无界的源码,需要的时间较多,暂时使用iframe方式嵌入。此方案需要调整dify的源码。下方记录对dify的修改。
文件1
文件远程地址:http://192.168.20.116/_next/static/chunks/app/layout-4c8b096bae21994c.js
文件服务器路径:/data/disk2/llm_platform/dify/docker/web/.next/static/chunks/app/layout-4c8b096bae21994c.js
文件2
文件远程地址:http://192.168.20.116/_next/static/chunks/app/(commonLayout)/layout-f8be35226350c774.js
文件服务器路径:/data/disk2/llm_platform/dify/docker/web/.next/static/chunks/app/(commonLayout)/layout-f8be35226350c774.js
文件3
文件远程地址:http://192.168.20.116/_next/static/chunks/app/signin/layout-a9277f33772c3201.js
文件服务器目录位置:/data/disk2/llm_platform/dify/docker/web/.next/static/chunks/app/signin
在上述列出的js文件末尾添加下方脚本:
此处的修改接收
message,并进行相应的css和js的操作。
function handleMessage(event) {
const data = event.data;
try{
const dataInfo = JSON.parse(event.data);
const type = dataInfo.type;
const value = dataInfo.value;
if(type === 'insertStyle'){
// 插入样式表
const ele = document.createElement('style');
ele.innerHTML = value;
document.head.appendChild(ele);
}else if(type === 'insertScript'){
// 插入脚本
const ele = document.createElement('script');
ele.innerHTML = value;
document.head.appendChild(ele);
}else{
// 其他
}
}catch(err){
console.log('自定义事件出错');
}
}
window.addEventListener("message", handleMessage, false);
token参数处理为了解决嵌入登录问题,修改部分代码。
需求描述:大模型2.0使用iframe嵌入dify,需要进行登录,此时在嵌入时,将token放入url后面,dify中需要处理此参数,将token通过localstorage进行保存,从而实现登录操作。
http://192.168.20.116/explore/apps?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiODA1NGU5ZmMtNzViYS00N2FlLWFlMmItNTEwOWZlMDFkYjA0IiwiZXhwIjoxNzM0MDgzODg4LCJpc3MiOiJTRUxGX0hPU1RFRCIsInN1YiI6IkNvbnNvbGUgQVBJIFBhc3Nwb3J0In0.urrZl876HSqbgbmbvklvTvcvkTb05N21UKUSVfnlHsM
http://192.168.20.116/_next/static/chunks/app/(commonLayout)/layout-f8be35226350c774.js/data/disk2/llm_platform/dify/docker/web/.next/static/chunks/app/(commonLayout)/layout-f8be35226350c774.jsfunction getSearchParams(href){
const url = new URL(href);
const searchParams = new URLSearchParams(url.search);
// 将键值对列表转换为一个对象
const res = Object.fromEntries(searchParams.entries());
return res;
}
function setUrlToken(){
// 获取URL值
const href = location.href;
const params = getSearchParams(href);
if(params.token){
localStorage.setItem('console_token', params.token);
localStorage.setItem('refresh_token', '10846d07c926fe8db065246eea370067cfce547066865e6068792e78ebee3c41e841b0c0c41d0c59d3e149dbdfc746f6ea8638f4b99735fbe97b70d2aa0d78bb');
}else{
// 找不到token,提示错误
}
}
setUrlToken();
dify身份凭据是console_token,但是在dify代码中,会判断refresh_token是否存在,如果不存在,则会跳回登录页面。
此部分代码手动创建一个refresh_token,再配合参数中的token,从而实现登录流程正常。