Просмотр исходного кода

feat(智能体管理):新增dify智能体

hanyang 1 год назад
Родитель
Сommit
f778da8715

+ 19 - 0
src/apis/intelligent.js

@@ -12,6 +12,25 @@ export function getDialogList(current, pageSize, keyword) {
     method: 'get'
   });
 }
+/**
+ * 新增智能体
+ * @param {Object} data 智能体数据
+ * @param {string} data.id 智能体id
+ * @param {string} data.name 智能体名称
+ * @param {string} data.description 智能体描述
+ * @param {string} data.dialogType 智能体类型 1:rgflow 2dify
+ * @param {string} data.icon 智能体图标
+ * @param {string} data.mode dify智能体类型
+ * */
+
+export function createDialog(data) {
+  return request({
+    url: `/api/dialog/create`,
+    method: 'post',
+    data
+  });
+}
+
 /**
  * 获取标签列表
  * @param {string} keyword 搜索关键字

+ 18 - 0
src/apis/rgflow-dify.js

@@ -0,0 +1,18 @@
+import request from '../base/ajax';
+
+/**
+ * 创建Dify智能体,
+ * @param {Object} data 包含创建Dify所需参数的对象
+ * @param {String} data.mode 模式,可选值:'advanced-chat'、'agent-chat'、'workflow'
+ * */
+export function createDify(data) {
+  const initData = { icon_type: 'emoji', icon: '🤖', icon_background: '#FFEAD5' };
+  initData.mode = data.mode;
+  initData.name = data.name;
+  initData.description = data.description;
+  return request({
+    url: `/dify/console/api/apps`,
+    method: 'post',
+    data: initData
+  });
+}

+ 38 - 3
src/modules/dify/MessageBody.vue

@@ -1,13 +1,48 @@
 <template>
   <div class="body-container">
-    <WujieVue width="100%" height="100%" name="sub-app" :url="defaultUrl" sync></WujieVue>
+    <!-- <WujieVue
+      width="100%"
+      height="100%"
+      name="sub-app"
+      :url="defaultUrl"
+      :sandbox="['allow-scripts', 'allow-same-origin', 'allow-forms', 'allow-popups']"
+      :debug="true"
+      :mode="'iframe'"
+      :onError="handleError"
+      :onBeforeLoad="beforeLoad"
+      :onAfterLoad="afterLoad"
+      sync
+    ></WujieVue> -->
+    <iframe id="dify" :src="defaultURL" width="100%" height="100%" frameborder="0"></iframe>
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
+import { ref, onMounted } from 'vue';
+const props = defineProps({
+  id: {
+    type: String,
+    required: true
+  }
+});
+const BASE_URL = 'http://192.168.20.119:28003/app';
+const defaultURL = ref(BASE_URL + '/' + props.id + '/workflow');
+console.log(defaultURL.value);
 
-const defaultUrl = ref('http://192.168.20.116');
+onMounted(() => {
+  const element = document.getElementById('dify');
+  element.onload = function () {
+    if (element && element.contentWindow) {
+      console.log('iframe loaded', element.contentWindow);
+      element.contentWindow.postMessage(
+        JSON.stringify({
+          type: 'insertStyle',
+          value: `body{background-color:red;font-size:50px;}`
+        })
+      );
+    }
+  };
+});
 </script>
 <style scoped lang="css">
 .body-container {

+ 4 - 5
src/modules/intelligent/MessageBody.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="body-container" ref="body_container">
     <CardItem v-for="item in moke_data" :key="item.id" :name="item.name" :img_src="item.img_src" :height="200">
-      <template #description> {{ item.desc }}> </template>
+      <template #description> {{ item.desc }} </template>
       <template #settings>
         <a-switch v-model="item.online">
           <template #checked> {{ $t('management.online') }} </template>
@@ -60,7 +60,7 @@
 import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
 import CardItem from '../../views/manage/CardItem.vue';
 import ManageTags from './ManageTags.vue';
-import { getImageIntelligent } from '../../views/manage/common';
+import { getIconIntelligent, getImageIntelligent } from '../../views/manage/common';
 import LabelSelected from './LabelSelected.vue';
 import { getDialogList } from '../../apis/intelligent';
 import { bus_intelligentSearch, bus_intelligentEdit } from '../../base/event-bus';
@@ -94,11 +94,12 @@ const getDialog = async () => {
   try {
     const res = await getDialogList(pages.current, pages.pageSize, search_text.value);
     const data = res.data.rows.map((item) => {
+      console.log(item.icon, getImageIntelligent(item.icon));
       return {
         ...item,
         time: new Date(item.update_time).toLocaleString('zh-CN'),
         desc: item.description,
-        img_src: getImageIntelligent(item.icon),
+        img_src: getImageIntelligent(item.icon) || getIconIntelligent(item.icon),
         user: item.user.userName || '-',
         online: item.status == 1
       };
@@ -135,7 +136,6 @@ const deleteIntelligent = () => {
 const getLabels = async () => {
   try {
     const res = await getLabelList(search_label.value, 1);
-    console.log(res);
     if (res.code == 200) {
       label_list.value = [...res.data.rows];
     }
@@ -153,7 +153,6 @@ const toSearchLabels = (text) => {
 };
 // 添加标签到智能体
 const addLabelToTarget = async (label_id_list, target_id) => {
-  console.log(label_id_list, target_id);
   try {
     await addLabelToDialog(label_id_list, target_id);
   } catch (err) {

+ 9 - 5
src/modules/intelligent/ModalAddIntel.vue

@@ -51,16 +51,20 @@ const handleCancel = () => {
 
 const addNewIntelligent = (item) => {
   // TODO: 根据item中的type区分新建智能体的类型
-  if (item.type === 'RAGFLOW') {
+  if (item.type === 'ragflow') {
     // TODO: 新建RAGFLOW智能体
     emit('update:visible', false);
     emit('createRAGFLOWIntelligent');
-  } else if (item.type === 'DIFY_1') {
-    // TODO: 新建ARGFLOW智能体
+    // } else if (item.type === 'advanced-chat') {
+    //   // TODO: 新建ARGFLOW智能体
+    //   emit('update:visible', false);
+    //   emit('add_intelligent', item);
+    // } else if (item.type === 'agent-chat') {
+    // } else if (item.type === 'workflow') {
+    // }
+  } else {
     emit('update:visible', false);
     emit('add_intelligent', item);
-  } else if (item.type === 'DIFY_2') {
-  } else if (item.type === 'DIFY_3') {
   }
 };
 </script>

+ 9 - 14
src/modules/intelligent/ModalSelectIcon.vue

@@ -17,7 +17,7 @@
           :class="{ 'icon-border-active': icon.id === target_icon }"
           @click="changeItem(icon.id)"
         >
-          <img class="icon" :src="icon.icon" alt="" />
+          <img class="icon" :src="getIconIntelligent(icon.name)" alt="" />
         </div>
       </div>
     </div>
@@ -26,12 +26,7 @@
 
 <script setup>
 import { ref, computed } from 'vue';
-import intellFrame1 from '../../assets/image/management/intellFrame1.png';
-import intellFrame2 from '../../assets/image/management/intellFrame2.png';
-import intellFrame3 from '../../assets/image/management/intellFrame3.png';
-import intellFrame4 from '../../assets/image/management/intellFrame4.png';
-import intellFrame5 from '../../assets/image/management/intellFrame5.png';
-import intellFrame6 from '../../assets/image/management/intellFrame6.png';
+import { getIconIntelligent } from '../../views/manage/common';
 
 const props = defineProps({
   show_select_icon: {
@@ -42,27 +37,27 @@ const props = defineProps({
 const icons = ref([
   {
     id: 1,
-    icon: intellFrame1
+    name: 'intellFrame1'
   },
   {
     id: 2,
-    icon: intellFrame2
+    name: 'intellFrame2'
   },
   {
     id: 3,
-    icon: intellFrame3
+    name: 'intellFrame3'
   },
   {
     id: 4,
-    icon: intellFrame4
+    name: 'intellFrame4'
   },
   {
     id: 5,
-    icon: intellFrame5
+    name: 'intellFrame5'
   },
   {
     id: 6,
-    icon: intellFrame6
+    name: 'intellFrame6'
   }
 ]);
 
@@ -75,7 +70,7 @@ const changeItem = (id) => {
   target_icon.value = id;
 };
 const handleBeforeOk = (done) => {
-  emit('sendIcon', icons.value.filter((icon) => icon.id === target_icon.value)[0].icon);
+  emit('sendIcon', icons.value.filter((icon) => icon.id === target_icon.value)[0].name);
   emit('update:show_select_icon', false);
   done();
 };

+ 57 - 22
src/modules/intelligent/ModelAddItem.vue

@@ -1,23 +1,17 @@
 <template>
-  <a-modal
-    v-model:visible="show_modal"
-    :align-center="false"
-    top="15vh"
-    @cancel="handleCancel"
-    @before-ok="handleBeforeOk"
-  >
+  <a-modal v-model:visible="show_modal" :align-center="false" top="15vh" @ok="handleOk" @cancel="handleCancel">
     <template #title> 新建 </template>
     <div class="section">
       <div class="form-item">
         <div class="label">图标&名称</div>
         <div class="value">
-          <img class="icon" :src="target_icon" alt="" @click="handleSelectIcon" />
-          <a-input v-model:value="form.name" placeholder="请输入名称" />
+          <img class="icon" :src="getIconIntelligent(props.target_icon)" alt="" @click="handleSelectIcon" />
+          <a-input v-model="form.name" placeholder="请输入名称" />
         </div>
       </div>
       <div class="form-item">
         <div class="label">描述</div>
-        <a-input v-model:value="form.description" placeholder="请输入名称" />
+        <a-input v-model="form.description" placeholder="请输入名称" />
       </div>
     </div>
   </a-modal>
@@ -25,33 +19,74 @@
 
 <script setup>
 import { ref, computed } from 'vue';
-
+import { createDify } from '../../apis/rgflow-dify';
+import { createDialog } from '../../apis/intelligent';
+import { getIconIntelligent, dialogType } from '../../views/manage/common';
 const props = defineProps({
   show_model_item: {
     type: Boolean,
     default: false
   },
+  target_intell_type: {
+    type: String,
+    default: 'advanced-chat'
+  },
   target_icon: {
     type: String,
-    default: '../../assets/image/management/intelligent-frame1.png'
+    default: 'intellFrame1'
   }
 });
-const form = ref({
+const formInit = {
   name: '',
   description: ''
-});
+};
+const form = ref(Object.assign({}, formInit));
 
-const emit = defineEmits(['update:show_model_item', 'select_icon']);
+const emit = defineEmits(['update:show_model_item', 'select_icon', 'updateIntelligentList']);
 
-const show_modal = computed(() => props.show_model_item);
-const handleBeforeOk = (done) => {
-  // TODO: 调新建接口
-  // TODO: 进入到对应的页面
-  
-  done();
+let show_modal = computed(() => props.show_model_item);
+
+const handleOk = () => {
+  if (form.value.name.trim().length) {
+    const data = {
+      name: form.value.name,
+      description: form.value.description,
+      mode: props.target_intell_type
+    };
+    createDify(data)
+      .then((res) => {
+        if (res.id && res.id.length) {
+          const dialogData = {
+            id: res.id,
+            name: form.value.name,
+            description: form.value.description,
+            icon: props.target_icon,
+            dialogType: dialogType.DIFY,
+            mode: props.target_intell_type
+          };
+          createOwnDialog(dialogData);
+        }
+      })
+      .catch((err) => {
+        console.log('新建失败', err);
+      })
+      .finally(() => {});
+  }
+};
+const createOwnDialog = async (data) => {
+  try {
+    const res = await createDialog(data);
+    if (res.code == 200) {
+      form.value = Object.assign({}, formInit);
+      emit('update:show_model_item', false);
+      emit('updateIntelligentList');
+    }
+  } catch (err) {
+    console.log('创建对话失败', err);
+  }
 };
 const handleCancel = () => {
-  form.value.name = '';
+  form.value = Object.assign({}, formInit);
   emit('update:show_model_item', false);
 };
 const handleSelectIcon = () => {

+ 20 - 23
src/modules/intelligent/TopSetting.vue

@@ -26,11 +26,13 @@
   <ModelAddItem
     v-model:show_model_item="show_model_item"
     :target_icon="target_icon"
+    :target_intell_type="target_intell_type"
     @select_icon="selectIcon"
+    @updateIntelligentList="updateIntelligentList"
   ></ModelAddItem>
   <ModelSelectIcon v-model:show_select_icon="show_select_icon" @sendIcon="sendIcon"></ModelSelectIcon>
   <AgentConfig
-    v-model:show_dify_config="show_dify_config"
+    v-model:show_rg_config="show_rg_config"
     ref="editAgentKuai"
     :typeAngint="add_type"
     :formData="itemObj"
@@ -40,6 +42,7 @@
 
 <script setup>
 import { ref, reactive } from 'vue';
+import { useRouter } from 'vue-router';
 import ModalAddIntel from './ModalAddIntel.vue';
 import ModelAddItem from './ModelAddItem.vue';
 import ModelSelectIcon from './ModalSelectIcon.vue';
@@ -47,15 +50,17 @@ import AgentConfig from './rgflow/agentConfig.vue';
 import { funcDebounce } from '../../utils/utils';
 import { bus_intelligentSearch, bus_intelligentEdit } from '../../base/event-bus';
 
+const router = useRouter();
+
 const searchText = ref('');
 const visible = ref(false);
 const show_model_item = ref(false);
 const show_select_icon = ref(false);
-const target_icon = ref('../../assets/image/management/intelligent-frame1.png');
+const target_icon = ref('');
 // 当前新建智能体类型
 const target_intell_type = ref('');
 // ragflow配置
-const show_dify_config = ref(false);
+const show_rg_config = ref(false);
 const editAgentKuai = ref(null);
 let add_type = ref('add');
 let itemObj = reactive({});
@@ -92,28 +97,15 @@ const handleCreate = () => {
 // 创建Dify智能体
 const createRAGFLOWIntelligent = () => {
   console.log('createRAGFLOWIntelligent');
-  show_dify_config.value = true;
+  show_rg_config.value = true;
 };
 const closeAgentConfig = () => {
-  show_dify_config.value = false;
+  show_rg_config.value = false;
 };
 const addIntelligent = (data) => {
   //根据智能体类型,打开不同的配置面板data.type
-  switch (data.type) {
-    case 'DIFY_1':
-      // TODO: 工作流助手
-      show_model_item.value = true;
-      target_intell_type.value = data.type;
-      break;
-    case 'DIFY_2':
-      // TODO: 智能Agent
-      break;
-    case 'DIFY_3':
-      // TODO: 工作流应用
-      break;
-    default:
-      console.log('暂不支持该智能体类型');
-  }
+  show_model_item.value = true;
+  target_intell_type.value = data.type;
 };
 const selectIcon = () => {
   show_select_icon.value = true;
@@ -122,6 +114,11 @@ const sendIcon = (icon) => {
   console.log('sendIcon', icon);
   target_icon.value = icon;
 };
+
+const updateIntelligentList = () => {
+  bus_intelligentSearch.emit('');
+  target_icon.value = '';
+};
 /**
  * 监听编辑智能体事件
  * @param {Object} item 编辑智能体对象
@@ -131,15 +128,15 @@ const sendIcon = (icon) => {
  * case 4: 编辑Dify智能体
  * */
 bus_intelligentEdit.on((item) => {
-  console.log('bus_intelligentEdit', item);
   switch (item.agentType) {
     case '1':
       // TODO: 编辑rgflow智能体
       // itemObj = item;
-      show_dify_config.value = true;
+      show_rg_config.value = true;
       break;
     case '4':
-      add_type.value = 'edit';
+      // TODO: 进入Dify智能体配置
+      router.push({ path: '/difydetail', query: { id: item.id } });
       console.log('item1', item);
       break;
     default:

+ 4 - 4
src/modules/intelligent/rgflow/AgentConfig.vue

@@ -270,11 +270,11 @@ import Upload from './Upload.vue';
 import { Message } from '@arco-design/web-vue';
 // import { dialogSet } from '@/api/Agent';
 
-const props = defineProps(['show_dify_config', 'typeAngint', 'formData']);
-const emit = defineEmits(['queryList', 'update:show_dify_config']);
+const props = defineProps(['show_rg_config', 'typeAngint', 'formData']);
+const emit = defineEmits(['queryList', 'update:show_rg_config']);
 
 const { loading, setLoading } = useLoading(true);
-const visible = computed(() => props.show_dify_config);
+const visible = computed(() => props.show_rg_config);
 const modelList = ref({});
 const rankModelList = ref({});
 let tabs = ref([]);
@@ -403,7 +403,7 @@ const handleCancel = () => {
   formRef1.value.resetFields();
   formRef2.value.resetFields();
   form.name = '';
-  emit('update:show_dify_config', false);
+  emit('update:show_rg_config', false);
   emit('queryList');
 };
 

+ 6 - 1
src/views/difyDetail.vue

@@ -2,14 +2,19 @@
   <LayoutExperience>
     <ContentContainer>
       <TopSetting></TopSetting>
-      <MessageBody></MessageBody>
+      <MessageBody :id="id"></MessageBody>
     </ContentContainer>
   </LayoutExperience>
 </template>
 
 <script setup>
+import { useRoute } from 'vue-router';
 import LayoutExperience from './layout/LayoutExperience.vue';
 import ContentContainer from './layout/ContentContainer.vue';
 import TopSetting from '../modules/dify/TopSetting.vue';
 import MessageBody from '../modules/dify/MessageBody.vue';
+
+const route = useRoute();
+
+const id = route.query.id;
 </script>

+ 32 - 5
src/views/manage/common.js

@@ -10,6 +10,12 @@ import intelligentFrame5 from '../../assets/image/management/intelligent-frame5.
 import intelligentFrame6 from '../../assets/image/management/intelligent-frame6.png';
 import intelligentFrame7 from '../../assets/image/management/intelligent-frame7.png';
 import intelligentFrame8 from '../../assets/image/management/intelligent-frame8.png';
+import intellFrame1 from '../../assets/image/management/intellFrame1.png';
+import intellFrame2 from '../../assets/image/management/intellFrame2.png';
+import intellFrame3 from '../../assets/image/management/intellFrame3.png';
+import intellFrame4 from '../../assets/image/management/intellFrame4.png';
+import intellFrame5 from '../../assets/image/management/intellFrame5.png';
+import intellFrame6 from '../../assets/image/management/intellFrame6.png';
 
 const image_knowLedge_map = {
   knowledgeFrame1: knowledgeFrame1,
@@ -27,6 +33,24 @@ const image_intelligent_map = {
   intelligentFrame7: intelligentFrame7,
   intelligentFrame8: intelligentFrame8
 };
+const icon_intelligent_map = {
+  intellFrame1: intellFrame1,
+  intellFrame2: intellFrame2,
+  intellFrame3: intellFrame3,
+  intellFrame4: intellFrame4,
+  intellFrame5: intellFrame5,
+  intellFrame6: intellFrame6
+};
+/**
+ * @description: 智能体类型
+ * */
+export const dialogType = {
+  RAGFLOW_TYPE: '1',
+  BS_TYPE: '2',
+  BASIC: '3',
+  DIFY: '4'
+};
+
 /**
  * @description: 图片映射表
  * avatar: 图片名称
@@ -36,7 +60,10 @@ export const getImageKnowLedge = (avatar) => {
   return image_knowLedge_map[avatar] || knowledgeFrame1;
 };
 export const getImageIntelligent = (avatar) => {
-  return image_intelligent_map[avatar] || intelligentFrame1;
+  return image_intelligent_map[avatar];
+};
+export const getIconIntelligent = (avatar) => {
+  return icon_intelligent_map[avatar] || intellFrame1;
 };
 
 /**
@@ -48,25 +75,25 @@ export const getDefaultIntelligent = () => {
       name: '问答助理',
       description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
       labels: 'LLM,TEXT',
-      type: 'RAGFLOW'
+      type: 'ragflow'
     },
     {
       name: '工作流助手',
       description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
       labels: 'LLM,TEXT',
-      type: 'DIFY_1'
+      type: 'advanced-chat'
     },
     {
       name: '智能Agent',
       description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
       labels: 'LLM,TEXT',
-      type: 'DIFY_2'
+      type: 'agent-chat'
     },
     {
       name: '工作流应用',
       description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
       labels: 'LLM,TEXT',
-      type: 'DIFY_3'
+      type: 'workflow'
     }
   ];
 };

+ 7 - 0
vite.config.mjs

@@ -27,6 +27,13 @@ export default defineConfig({
         secure: false,
         ws: true,
         rewrite: (path) => path.replace(/^\/proxy_url/, '')
+      },
+      '/dify': {
+        target: 'http://192.168.20.119:28003/',
+        changeOrigin: true,
+        secure: false,
+        ws: true,
+        rewrite: (path) => path.replace(/^\/dify/, '')
       }
     }
   },