Kaynağa Gözat

feat:智能体替换列表接口,新增根据应用,标签搜索

hanyang 1 yıl önce
ebeveyn
işleme
6cc5eb6921

+ 3 - 1
public/i18n/lang-en.json

@@ -68,7 +68,9 @@
     "useBtn": "Use",
     "addLabelBtn": "Add Label",
     "loadingDataTip": "Loading data, please wait...",
-    "noMoreData": "No more data available"
+    "noMoreData": "No more data available",
+    "searchAppTip": "All Application Types",
+    "searchLabelTip": "All Labels"
   },
   "permission": {
     "query": "Query",

+ 3 - 1
public/i18n/lang-zh.json

@@ -69,7 +69,9 @@
     "useBtn": "使用",
     "addLabelBtn": "添加标签",
     "loadingDataTip": "正在加载数据,请稍后……",
-    "noMoreData": "没有更多数据了"
+    "noMoreData": "没有更多数据了",
+    "searchAppTip": "全部应用类型",
+    "searchLabelTip": "全部标签"
   },
   "permission": {
     "query": "查询",

+ 15 - 0
src/apis/intelligent.js

@@ -12,6 +12,21 @@ export function getDialogList(current, pageSize, keyword) {
     method: 'get'
   });
 }
+/**
+ * 获取智能体列表(智能体页面专用)
+ * @param {number} current 当前页数
+ * @param {number} pageSize 每页条数
+ * @param {string} keyword 搜索
+ * @param { array } label: 标签列表
+ * @param { string } mode: 智能体类型
+ * */
+export function getDialogListForFilter(data) {
+  return request({
+    url: `/api/dialog/dialog_list`,
+    method: 'post',
+    data
+  });
+}
 /**
  * 新增智能体
  * @param {Object} data 智能体数据

+ 2 - 0
src/base/event-bus.js

@@ -19,3 +19,5 @@ export const bus_intelligentSearch = new EventBus('intelligent_search');
 export const bus_intelligentEdit = new EventBus('intelligent_edit');
 // 智能体图标编辑
 export const bus_intelligentIconEdit = new EventBus('intelligent_icon_edit');
+// 智能体标签数据同步
+export const bus_intelligentLabelSync = new EventBus('intelligent_label_sync');

+ 1 - 1
src/modules/Model/ModelList.vue

@@ -96,7 +96,7 @@ const showMoreModel = (item) => {
   cursor: pointer;
 }
 .list-collapse {
-  padding: 20px;
+  padding: 20px 20px 0 20px;
   max-height: 0;
 }
 </style>

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

@@ -15,36 +15,33 @@ const props = defineProps({
   }
 });
 const loading = ref(true);
-const DIFY_TOKEN = ref('');
 const BASE_URL = window.DIFY_BASE_URL;
 const token = kuky_Authorization.get();
 const defaultURL = ref('');
 
 //workflow  应用
-//configuration agent
 onMounted(async () => {
   defaultURL.value = BASE_URL + '/app/' + props.id + `/workflow?token=${token}`;
   // console.log('defaultURL', BASE_URL + '/app/' + props.id + `/workflow`);
   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: `
             .sticky{display:none;}
+            .style_app___hJq8 > div:first-of-type > div:first-of-type{display:none;}
+            .style_app___hJq8 > div:first-of-type > nav> a:nth-child(2){display:none;}
+            .style_app___hJq8 > div:first-of-type > nav> a:nth-child(3){display:none;}
             `
         }),
-
         defaultURL.value
       );
     }
     loading.value = false;
   };
 });
-// .style_app___hJq8 > div:first-of-type{display:none;}
-// .style_app___hJq8 .shrink-0{display:none;}
 </script>
 <style scoped lang="css">
 .body-container {

+ 2 - 1
src/modules/intelligent/CardDefault.vue

@@ -55,6 +55,7 @@ const props = defineProps({
 }
 .section {
   margin: 20px 0;
-  color: var(--color-neutral-6);
+  height: 66px;
+  color: var(--color-neutral-8);
 }
 </style>

+ 1 - 0
src/modules/intelligent/LabelSelected.vue

@@ -8,6 +8,7 @@
     <a-checkbox-group v-model="checkedList" direction="vertical" @change="handleToAdd">
       <a-checkbox v-for="item in label_list" :key="item.labelId" :value="item.labelId">{{ item.labelName }}</a-checkbox>
     </a-checkbox-group>
+    <a-empty v-if="!label_list.length"></a-empty>
     <div class="footer">
       <div class="label-manage" @click="toManageTags"><icon-tags /> 管理标签</div>
     </div>

+ 42 - 7
src/modules/intelligent/MessageBody.vue

@@ -41,6 +41,24 @@
             </div>
           </template>
         </a-dropdown>
+        <!-- <a-select :default-value="'Beijing'" placeholder="Please select ..." multiple>
+          <a-option>Beijing</a-option>
+          <a-option>Shanghai</a-option>
+          <a-option>Guangzhou</a-option>
+          <a-option disabled>Disabled</a-option>
+          <a-option>Shenzhen</a-option>
+          <a-option>Wuhan</a-option>
+          <template #header>
+            <div style="padding: 6px 12px">
+              <a-checkbox value="1">全选</a-checkbox>
+            </div>
+          </template>
+          <template #footer>
+            <div style="padding: 6px 0; text-align: center">
+              <a-button>Click Me</a-button>
+            </div>
+          </template>
+        </a-select> -->
       </template>
       <template #bottom>
         <div class="bottom">
@@ -72,8 +90,13 @@ import CardItem from '../../views/manage/CardItem.vue';
 import ManageTags from './ManageTags.vue';
 import { getIconIntelligent, getImageIntelligent } from '../common/icon-map.js';
 import LabelSelected from './LabelSelected.vue';
-import { getDialogList } from '../../apis/intelligent';
-import { bus_intelligentSearch, bus_intelligentEdit, bus_intelligentIconEdit } from '../../base/event-bus';
+import { getDialogListForFilter } from '../../apis/intelligent';
+import {
+  bus_intelligentSearch,
+  bus_intelligentEdit,
+  bus_intelligentIconEdit,
+  bus_intelligentLabelSync
+} from '../../base/event-bus';
 import { dialogType } from '../../views/manage/common';
 import { funcThrottle } from '../../utils/utils';
 import { getLabelList, addLabelToDialog, changeDialogStatus, deleteDialog } from '../../apis/intelligent';
@@ -98,7 +121,9 @@ const total_pages = ref(5);
 const body_container = ref(null);
 const scroll_bottom = ref(false);
 const search_text = ref('');
-const search_label = ref('');
+const search_label = ref(''); //单个card的搜索标签
+const search_labelId_list = ref([]); //头部的搜索标签
+const search_mode = ref(''); //要过滤的应用类型
 const label_list = ref([]);
 const dropdown = ref(null);
 const visible = ref(false);
@@ -109,7 +134,14 @@ const getDialog = async () => {
     loading_data.value = true;
   }
   try {
-    const res = await getDialogList(pages.current, pages.pageSize, search_text.value);
+    const filter_data = {
+      current: pages.current,
+      pageSize: pages.pageSize,
+      keyword: search_text.value,
+      label: search_labelId_list.value,
+      mode: search_mode.value
+    };
+    const res = await getDialogListForFilter(filter_data);
     const data = res.data.rows.map((item) => {
       return {
         ...item,
@@ -188,6 +220,8 @@ const getLabels = async () => {
     const res = await getLabelList(search_label.value, 1);
     if (res.code == 200) {
       label_list.value = [...res.data.rows];
+      // 将label_list数据给到top中
+      bus_intelligentLabelSync.emit(label_list.value);
     }
   } catch (err) {
     console.log(err);
@@ -224,7 +258,6 @@ const changeDropdownVisible = async (visible, id) => {
 };
 
 const changeStatus = async (item) => {
-  console.log(item);
   try {
     const res = await changeDialogStatus(item.id, item.status == '1' ? '0' : '1');
     if (res.code != 200) {
@@ -247,8 +280,10 @@ const editIconHandle = (item) => {
   bus_intelligentIconEdit.emit(item);
 };
 
-bus_intelligentSearch.on((text) => {
-  search_text.value = text;
+bus_intelligentSearch.on((search_data) => {
+  search_text.value = search_data.searchText;
+  search_labelId_list.value = search_data.target_label_list;
+  search_mode.value = search_data.target_app;
   moke_data.value = [];
   pages.current = 1;
   getDialog();

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

@@ -17,7 +17,7 @@
           :class="{ 'icon-border-active': icon.id === target_icon_id }"
           @click="changeItem(icon.id)"
         >
-          <img class="icon" :src="getIconIntelligent(icon.name)" alt="" />
+          <img class="icon" :src="getIconIntelligent(icon.name)" />
         </div>
       </div>
     </div>
@@ -107,15 +107,18 @@ watch(
   gap: 10px;
   margin-top: 10px;
 }
-.icons .icon-border {
-  /* width: 50px;
-  height: 50px; */
-  padding: 5px 10px;
+.icon-border {
+  border: 1px solid var(--color-neutral-2);
+
+  border-radius: 5px;
+  padding: 5px 8px 0px 8px;
   cursor: pointer;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
 }
 .icon-border:hover {
   border: 1px solid var(--color-neutral-4);
   border-radius: 5px;
+  transform: scale(1.05);
 }
 .icon-border .icon {
   width: 44px;
@@ -123,7 +126,7 @@ watch(
 }
 .icon-border-active {
   border: 1px solid var(--color-neutral-4);
-  border-radius: 5px;
+  transform: scale(1.1);
 }
 .arco-input-wrapper {
   height: 32px;

+ 53 - 5
src/modules/intelligent/TopSetting.vue

@@ -1,5 +1,30 @@
 <template>
   <a-space size="large">
+    <a-select
+      v-model="target_app"
+      :placeholder="$t('management.searchAppTip')"
+      allow-clear
+      :style="{
+        width: '200px',
+        'background-color': 'var(--color-bg-5)'
+      }"
+      @change="handleSearch"
+    >
+      <a-option v-for="item in search_app_list" :key="item.name" :value="item.type">{{ item.name }}</a-option>
+    </a-select>
+    <a-select
+      v-model="target_label_list"
+      :style="{ width: '200px', 'background-color': 'var(--color-bg-5)' }"
+      :placeholder="$t('management.searchLabelTip')"
+      multiple
+      :max-tag-count="1"
+      allow-clear
+      allow-search
+      :scrollbar="scrollbar"
+      @change="handleSearch"
+    >
+      <a-option v-for="item in label_list" :key="item.labelId" :value="item.labelId">{{ item.labelName }}</a-option>
+    </a-select>
     <a-input
       v-model="searchText"
       :placeholder="$t('management.search')"
@@ -36,9 +61,8 @@
     v-model:show_select_icon="show_select_icon"
     :target_icon="target_icon"
     @sendIcon="sendIcon"
-    @clearTargetIcon="clearTargetIcon"
-  ></ModelSelectIcon
-  >>
+    @clearTargetIcon="clearSelectIcon"
+  ></ModelSelectIcon>
   <AgentConfig
     v-model:show_rg_config="show_rg_config"
     ref="editAgentKuai"
@@ -62,11 +86,20 @@ import AgentConfig from './rgflow/agentConfig.vue';
 import { funcDebounce } from '../../utils/utils';
 import { getRagFlowData } from '../../apis/rgflow-dify';
 import { updateOwnIntelligentIcon } from '../../apis/intelligent';
-import { bus_intelligentSearch, bus_intelligentEdit, bus_intelligentIconEdit } from '../../base/event-bus';
+import { getDefaultIntelligent } from '../../views/manage/common';
+import {
+  bus_intelligentSearch,
+  bus_intelligentEdit,
+  bus_intelligentIconEdit,
+  bus_intelligentLabelSync
+} from '../../base/event-bus';
 
 const router = useRouter();
 
 const searchText = ref('');
+const target_app = ref(''); // 当前选择的应用
+const target_label_list = ref([]);
+const label_list = ref([]);
 const visible = ref(false);
 const show_model_item = ref(false);
 const show_select_icon = ref(false);
@@ -80,10 +113,18 @@ let add_type = ref('add');
 let itemObj = reactive({});
 const edit_icon_data = ref(null);
 
+const search_app_list = getDefaultIntelligent();
+search_app_list.push({ name: 'basic', type: 'agent-basic' });
+
 // 搜索
 const handleSearch = funcDebounce(
   () => {
-    bus_intelligentSearch.emit(searchText.value);
+    const search_data = {
+      searchText: searchText.value,
+      target_app: target_app.value,
+      target_label_list: target_label_list.value
+    };
+    bus_intelligentSearch.emit(search_data);
   },
   300,
   false
@@ -184,13 +225,20 @@ bus_intelligentIconEdit.on((item) => {
   edit_icon_data.value = item;
   target_icon.value = item.icon;
 });
+bus_intelligentLabelSync.on((item) => {
+  label_list.value = item;
+});
 onUnmounted(() => {
   bus_intelligentEdit.off();
   bus_intelligentIconEdit.off();
+  bus_intelligentLabelSync.off();
 });
 </script>
 <style scoped lang="css">
 .arco-input-wrapper {
   background-color: var(--color-bg-5);
 }
+/* :deep(.arco-select-view-single) {
+  background-color: var(--color-bg-5);
+} */
 </style>

+ 0 - 1
src/modules/intelligent/rgflow/AgentConfig.vue

@@ -281,7 +281,6 @@ const emit = defineEmits([
   'show_select_icon',
   'clearSelectIcon'
 ]);
-console.log(props, 'props');
 
 const { loading, setLoading } = useLoading(true);
 const visible = computed(() => props.show_rg_config);

+ 8 - 5
src/modules/knowledge/ModalSelectIcon.vue

@@ -98,15 +98,18 @@ watch(
   gap: 10px;
   margin-top: 10px;
 }
-.icons .icon-border {
-  /* width: 50px;
-  height: 50px; */
-  padding: 5px 10px;
+.icon-border {
+  border: 1px solid var(--color-neutral-2);
+
+  border-radius: 5px;
+  padding: 5px 8px 0px 8px;
   cursor: pointer;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
 }
 .icon-border:hover {
   border: 1px solid var(--color-neutral-4);
   border-radius: 5px;
+  transform: scale(1.05);
 }
 .icon-border .icon {
   width: 44px;
@@ -114,7 +117,7 @@ watch(
 }
 .icon-border-active {
   border: 1px solid var(--color-neutral-4);
-  border-radius: 5px;
+  transform: scale(1.1);
 }
 .arco-input-wrapper {
   height: 32px;

+ 7 - 2
src/modules/knowledge/TopSetting.vue

@@ -1,7 +1,12 @@
 <template>
   <a-space size="large">
-    <a-input v-model="searchText" :placeholder="$t('management.search')" style="width: 300px" allow-clear
-      @input="handleSearch">
+    <a-input
+      v-model="searchText"
+      :placeholder="$t('management.search')"
+      style="width: 300px"
+      allow-clear
+      @input="handleSearch"
+    >
       <template #prefix>
         <icon-search />
       </template>

+ 22 - 12
src/modules/login/FormItem.vue

@@ -2,8 +2,14 @@
   <div class="form-title">
     {{ form_type ? $t('login.registerModel') : $t('login.loginModel') }}
   </div>
-  <a-form ref="ref_form" :model="form" :rules="rules" :style="{ width: 'calc(100% - 40px)' }" layout="validate"
-    @submit-success="handleSubmit">
+  <a-form
+    ref="ref_form"
+    :model="form"
+    :rules="rules"
+    :style="{ width: 'calc(100% - 40px)' }"
+    layout="validate"
+    @submit-success="handleSubmit"
+  >
     <a-form-item field="username">
       <a-input v-model="form.username" :placeholder="$t('login.usernameTips')">
         <template #prefix> <icon-user /> </template>
@@ -15,19 +21,23 @@
       </a-input>
     </a-form-item>
     <a-form-item field="password">
-      <a-input-password v-model="form.password" :placeholder="$t('login.passwordTips')" :defaultVisibility="true"
-        allow-clear>
+      <a-input-password
+        v-model="form.password"
+        :placeholder="$t('login.passwordTips')"
+        :defaultVisibility="true"
+        allow-clear
+      >
         <template #prefix>
           <icon-user />
         </template>
       </a-input-password>
     </a-form-item>
     <a-form-item>
-      <a-button v-if="!form_type" class="submit-btn" type="primary" html-type="submit" :loading="loading">{{
-        $t('login.loginBtn') }}
+      <a-button v-if="!form_type" class="submit-btn" type="primary" html-type="submit" :loading="loading"
+        >{{ $t('login.loginBtn') }}
       </a-button>
-      <a-button v-if="form_type" class="submit-btn" type="primary" html-type="submit" :loading="loading">{{
-        $t('login.registerBtn') }}
+      <a-button v-if="form_type" class="submit-btn" type="primary" html-type="submit" :loading="loading"
+        >{{ $t('login.registerBtn') }}
       </a-button>
     </a-form-item>
   </a-form>
@@ -81,10 +91,9 @@ const handleSubmit = (data) => {
 
         // 登录成功后,获取路由列表
         // 阻塞路由的获取,等待用户信息获取成功
-        await userStore.getRoutesList()
+        await userStore.getRoutesList();
         // 登录成功后,获取用户权限
-        await userStore.getUserInfo()
-
+        await userStore.getUserInfo();
         router.push({ path: '/knowledge' });
       })
       .catch((err) => {
@@ -126,6 +135,7 @@ const changeFormType = (e) => {
   line-height: 42px;
   font-size: 30px;
   font-weight: 500;
+  color: var(--color-neutral-10);
 }
 
 .submit-btn {
@@ -164,7 +174,7 @@ const changeFormType = (e) => {
   border-color: var(--color-neutral-3);
 }
 
-:deep .arco-form-item-label-col>.arco-form-item-label {
+:deep .arco-form-item-label-col > .arco-form-item-label {
   display: none;
 }
 </style>

+ 2 - 1
src/views/manage/HeadManage.vue

@@ -37,9 +37,10 @@ const props = defineProps({
   font-family: 'pingfang sc';
   font-size: 18px;
   font-weight: 600;
+  color: var(--color-neutral-10);
 }
 .tips {
   font-size: 12px;
-  color: var(color-text-3);
+  color: var(--color-neutral-8);
 }
 </style>

+ 11 - 11
src/views/manage/common.js

@@ -14,27 +14,27 @@ export const dialogType = {
 export const getDefaultIntelligent = () => {
   return [
     {
-      name: '问答助理',
-      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
-      labels: 'LLM,TEXT',
-      type: 'ragflow'
+      name: '知识问答助理',
+      description: '基于专属知识库构建的智能问答助手,高效检索并解答特定领域问题,适用于文档问答、客户支持等场景',
+      labels: '',
+      type: 'agent-dialog'
     },
     {
-      name: '工作流助手',
-      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
-      labels: 'LLM,TEXT',
+      name: '聊天助理',
+      description: '基于大型语言模型构建的对话式交互助手,适用于多轮对话场景',
+      labels: '',
       type: 'advanced-chat'
     },
     {
       name: '智能Agent',
-      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
-      labels: 'LLM,TEXT',
+      description: '能够分解任务、进行推理思考并调用工具的对话式智能助手,适合处理复杂任务',
+      labels: '',
       type: 'agent-chat'
     },
     {
       name: '工作流应用',
-      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
-      labels: 'LLM,TEXT',
+      description: '通过流程编排的方式定义更灵活的 LLM 工作流,实现更稳定可控的输出',
+      labels: '',
       type: 'workflow'
     }
   ];