CzRger 1 månad sedan
förälder
incheckning
acbd75c7e8

+ 6 - 0
src/api/modules/app/make.ts

@@ -10,3 +10,9 @@ export const promptTemplatesSave = (params) =>
 // 提示词模板-详情
 export const promptTemplatesDetail = (id) =>
   get(`/prompt-templates/${id}`, {}, {}, proxy)
+// 编排信息-详情
+export const appModelConfigDetail = (id) =>
+  get(`/app/model-config/${id}`, {}, {}, proxy)
+// 编排信息-保存
+export const appModelConfigSave = (params) =>
+  post(`/app/model-config`, params, {}, proxy)

+ 1 - 0
src/router/index.ts

@@ -42,6 +42,7 @@ const router = createRouter({
   routes,
 })
 router.beforeEach((to, from, next) => {
+  document.title = to.meta?.title || (import.meta as any).env.VITE_TITLE
   const isLogin = to.name === 'login'
   const inviteQuery = to.name === 'invite' ? to.query : {}
   const AppStore = useAppStore()

+ 35 - 2
src/stores/modules/dictionary.ts

@@ -2,7 +2,11 @@ import { defineStore } from 'pinia'
 import { tagsTenant } from '@/api/modules/knowledge/tags'
 import { ElMessage } from 'element-plus'
 import { datasetGroupsGetAllByTenantId } from '@/api/modules/knowledge/group'
-import { pluginConfigs, pluginGetModelTypeList } from '@/api/modules/model'
+import {
+  pluginConfigs,
+  pluginGetInstanceList,
+  pluginGetModelTypeList,
+} from '@/api/modules/model'
 import { dictionary, dictionaryDefine } from './dictionary-define'
 import { sysDictFindByDictType } from '@/api/modules/global/dictionary'
 // @ts-ignore
@@ -54,6 +58,12 @@ export const useDictionaryStore = defineStore('dictionary', {
       map: new Map(),
       objMap: new Map(),
     },
+    models: {
+      waiting: false,
+      list: [],
+      map: new Map(),
+      objMap: new Map(),
+    },
     tenants: {
       waiting: false,
       list: [],
@@ -213,7 +223,7 @@ export const useDictionaryStore = defineStore('dictionary', {
         this.tenants.waiting = true
         tenantsPage({
           page: 1,
-          size: 9999,
+          size: 100000,
           enabled: true,
         })
           .then(({ data }: any) => {
@@ -232,6 +242,29 @@ export const useDictionaryStore = defineStore('dictionary', {
           })
       }
     },
+    initModels() {
+      if (!this.models.waiting) {
+        this.models.waiting = true
+        pluginGetInstanceList({
+          page: 1,
+          size: 100000,
+        })
+          .then(({ data }: any) => {
+            const arr: any = data.records.map((v) => {
+              v.label = v.name
+              v.value = v.id
+              return v
+            })
+            this.models.list = arr
+            this.models.map = listToMap({ list: arr })
+            this.models.objMap = listToMap({ list: arr, isObj: true })
+          })
+          .catch(() => {})
+          .finally(() => {
+            this.models.waiting = false
+          })
+      }
+    },
     getFileIcon(name) {
       if (name.toLowerCase().includes('.txt')) {
         return FileTxt

+ 198 - 136
src/views/manage/app/make/index.vue

@@ -21,7 +21,10 @@
             <div class="mx-auto" />
             <div
               class="flex items-center text-[var(--czr-error-color)]"
-              v-if="state.autoSaveTimestamp"
+              v-if="
+                !state.config.publishTime ||
+                state.config.publishTime !== state.autoSaveTimestamp
+              "
             >
               <SvgIcon
                 name="czr_tip"
@@ -125,20 +128,25 @@
               <div
                 class="col-span-1 overflow-y-auto rounded-lg bg-[#ffffff] p-4"
               >
-                <div class="__czr-title_2">模型选择</div>
-                <div class="mt-4">
-                  <CzrFormColumn
-                    class="__czr-table-form-column"
-                    required
-                    label="模型选择"
-                    :span="24"
-                    v-model:param="state.form.model.name"
-                    placeholder="点击选择模型"
-                    readonly
-                    @click="onModel"
-                    default-error-msg="请选择模型"
-                  />
-                </div>
+                <template v-if="state.detail.type === 0">
+                  <div class="__czr-title_2">模型选择</div>
+                  <div class="mt-4">
+                    <CzrFormColumn
+                      class="__czr-table-form-column"
+                      required
+                      label="模型选择"
+                      :span="24"
+                      v-model:param="state.form.modelId"
+                      link="select"
+                      :options="DictionaryStore.models.list"
+                      placeholder="点击选择模型"
+                      @click.capture.stop="onModel"
+                      default-error-msg="请选择模型"
+                      :clearable="false"
+                    />
+                  </div>
+                </template>
+
                 <div class="__czr-title_2 mt-4">
                   组件
                   <template v-if="state.form.components.length > 0">
@@ -154,113 +162,117 @@
                     暂未添加组件
                   </div>
                 </template>
-                <div class="__czr-title_2 mt-4">
-                  知识库
+                <template v-if="state.detail.type === 0">
+                  <div class="__czr-title_2 mt-4">
+                    知识库
+                    <template v-if="state.form.knowledges.length > 0">
+                      ({{ state.form.knowledges.length }})
+                    </template>
+                    <CzrButton
+                      type="normal"
+                      title="新增"
+                      class="ml-auto"
+                      @click="onAddKnowledge"
+                    />
+                  </div>
                   <template v-if="state.form.knowledges.length > 0">
-                    ({{ state.form.knowledges.length }})
-                  </template>
-                  <CzrButton
-                    type="normal"
-                    title="新增"
-                    class="ml-auto"
-                    @click="onAddKnowledge"
-                  />
-                </div>
-                <template v-if="state.form.knowledges.length > 0">
-                  <div
-                    class="mt-2 flex max-h-42 flex-col gap-2 overflow-y-auto pr-2"
-                  >
-                    <template v-for="(item, index) in state.form.knowledges">
-                      <div class="flex items-center gap-1.5">
-                        <div
-                          class="flex flex-1 items-center overflow-hidden rounded-sm bg-[#F6F8FC] p-2.5"
-                        >
-                          <img
-                            src="@/assets/images/knowledge/knowledge-item-icon.png"
-                            class="mr-4 size-6"
-                          />
+                    <div
+                      class="mt-2 flex max-h-42 flex-col gap-2 overflow-y-auto pr-2"
+                    >
+                      <template v-for="(item, index) in state.form.knowledges">
+                        <div class="flex items-center gap-1.5">
                           <div
-                            class="flex-1 text-sm font-bold text-[#2E3238]"
-                            v-title
+                            class="flex flex-1 items-center overflow-hidden rounded-sm bg-[#F6F8FC] p-2.5"
                           >
-                            {{ item.name }}
+                            <img
+                              src="@/assets/images/knowledge/knowledge-item-icon.png"
+                              class="mr-4 size-6"
+                            />
+                            <div
+                              class="flex-1 text-sm font-bold text-[#2E3238]"
+                              v-title
+                            >
+                              {{ item.name }}
+                            </div>
                           </div>
+                          <SvgIcon
+                            class="__hover"
+                            name="czr_del"
+                            color="var(--czr-error-color)"
+                            @click="state.form.knowledges.splice(index, 1)"
+                          />
                         </div>
-                        <SvgIcon
-                          class="__hover"
-                          name="czr_del"
-                          color="var(--czr-error-color)"
-                          @click="state.form.knowledges.splice(index, 1)"
-                        />
-                      </div>
-                    </template>
-                  </div>
+                      </template>
+                    </div>
+                  </template>
+                  <template v-else>
+                    <div
+                      class="mt-2 flex h-8 items-center justify-center rounded-sm bg-[#F6F8FC] text-xs text-[#A7ADB9]"
+                    >
+                      暂未添加知识库
+                    </div>
+                  </template>
                 </template>
-                <template v-else>
-                  <div
-                    class="mt-2 flex h-8 items-center justify-center rounded-sm bg-[#F6F8FC] text-xs text-[#A7ADB9]"
-                  >
-                    暂未添加知识库
+                <template v-if="state.detail.type === 1">
+                  <div class="__czr-title_2 mt-4">
+                    工作流
+                    <template v-if="state.form.workflows.length > 0">
+                      ({{ state.form.workflows.length }})
+                    </template>
+                    <CzrButton
+                      type="normal"
+                      title="新增"
+                      class="ml-auto"
+                      @click="onAddWorkflow"
+                    />
                   </div>
-                </template>
-                <div class="__czr-title_2 mt-4">
-                  工作流
                   <template v-if="state.form.workflows.length > 0">
-                    ({{ state.form.workflows.length }})
-                  </template>
-                  <CzrButton
-                    type="normal"
-                    title="新增"
-                    class="ml-auto"
-                    @click="onAddWorkflow"
-                  />
-                </div>
-                <template v-if="state.form.workflows.length > 0">
-                  <div
-                    class="mt-2 flex max-h-42 flex-col gap-2 overflow-y-auto pr-2"
-                  >
-                    <template v-for="(item, index) in state.form.workflows">
-                      <div class="flex items-center gap-1.5">
-                        <div
-                          class="flex flex-1 items-center overflow-hidden rounded-sm bg-[#F6F8FC] p-2.5"
-                        >
-                          <img
-                            src="@/assets/images/workflow/workflow-default-icon.png"
-                            class="mr-4 size-15"
-                          />
+                    <div
+                      class="mt-2 flex max-h-42 flex-col gap-2 overflow-y-auto pr-2"
+                    >
+                      <template v-for="(item, index) in state.form.workflows">
+                        <div class="flex items-center gap-1.5">
                           <div
-                            class="flex flex-1 flex-col gap-2 overflow-hidden"
+                            class="flex flex-1 items-center overflow-hidden rounded-sm bg-[#F6F8FC] p-2.5"
                           >
+                            <img
+                              src="@/assets/images/workflow/workflow-default-icon.png"
+                              class="mr-4 size-15"
+                            />
                             <div
-                              class="text-sm font-bold text-[#2E3238]"
-                              v-title
-                            >
-                              {{ item.name }}
-                            </div>
-                            <div
-                              class="text-sm text-[#6F7889]"
-                              v-title="{ lines: 2 }"
+                              class="flex flex-1 flex-col gap-2 overflow-hidden"
                             >
-                              {{ item.description }}
+                              <div
+                                class="text-sm font-bold text-[#2E3238]"
+                                v-title
+                              >
+                                {{ item.name }}
+                              </div>
+                              <div
+                                class="text-sm text-[#6F7889]"
+                                v-title="{ lines: 2 }"
+                              >
+                                {{ item.description }}
+                              </div>
                             </div>
                           </div>
+                          <SvgIcon
+                            class="__hover"
+                            name="czr_del"
+                            color="var(--czr-error-color)"
+                            @click="state.form.workflows.splice(index, 1)"
+                          />
                         </div>
-                        <SvgIcon
-                          class="__hover"
-                          name="czr_del"
-                          color="var(--czr-error-color)"
-                          @click="state.form.workflows.splice(index, 1)"
-                        />
-                      </div>
-                    </template>
-                  </div>
-                </template>
-                <template v-else>
-                  <div
-                    class="mt-2 flex h-8 items-center justify-center rounded-sm bg-[#F6F8FC] text-xs text-[#A7ADB9]"
-                  >
-                    暂未添加工作流
-                  </div>
+                      </template>
+                    </div>
+                  </template>
+                  <template v-else>
+                    <div
+                      class="mt-2 flex h-8 items-center justify-center rounded-sm bg-[#F6F8FC] text-xs text-[#A7ADB9]"
+                    >
+                      暂未添加工作流
+                    </div>
+                  </template>
                 </template>
                 <div class="__czr-title_2 mt-4">开场白</div>
                 <div class="mt-4">
@@ -443,11 +455,13 @@
                       required
                       label="模型选择"
                       :span="24"
-                      v-model:param="state.form.advise.model.name"
+                      v-model:param="state.form.advise.modelId"
+                      link="select"
+                      :options="DictionaryStore.models.list"
                       placeholder="点击选择模型"
-                      readonly
                       @click="onAdviseModel"
                       default-error-msg="请选择问题建议模型"
+                      :clearable="false"
                     />
                     <div
                       class="mt-2 flex h-10 items-center gap-1 rounded-sm bg-[#FFFAEA] px-3.5 text-sm text-[#6F7889]"
@@ -667,6 +681,11 @@ import workflowSelect from './workflow-select.vue'
 import CzrForm from '@/components/czr-ui/CzrForm.vue'
 import CzrDialog from '@/components/czr-ui/CzrDialog.vue'
 import toBackCom from '@/views/manage/components/to-back.vue'
+import {
+  appModelConfigDetail,
+  appModelConfigSave,
+} from '@/api/modules/app/make'
+import { appDetail } from '@/api/modules/app'
 
 const DictionaryStore = useDictionaryStore()
 const DialogStore = useDialogStore()
@@ -677,10 +696,11 @@ const props = defineProps({})
 const { proxy }: any = getCurrentInstance()
 const state: any = reactive({
   ID: route.params.id,
+  isInit: false,
   autoSaveTimestamp: '',
   form: {
     tips: '',
-    model: { name: '', id: '' },
+    modelId: '',
     components: [],
     knowledges: [
       {
@@ -709,12 +729,13 @@ const state: any = reactive({
     voicePackage: '',
     advise: {
       types: [],
-      model: { name: '' },
+      modelId: '',
       tips: '',
       knowledges: [],
     },
   },
   detail: {},
+  config: {},
   knowledgeSelect: {
     show: false,
     transfer: {},
@@ -764,9 +785,69 @@ const ref_prologueBody = ref()
 const modelApplyCpt = computed(() => {
   return true
 })
+watch(
+  () => state.form,
+  (n) => {
+    if (state.isInit) {
+      console.log('触发自动保存')
+      autoSave(n)
+    }
+  },
+  { deep: true },
+)
+const autoSave = debounce((v) => {
+  const loading = ElLoading.service({
+    text: '自动保存中……',
+    background: 'rgba(0, 0,0, 0.3)',
+  })
+  const params: any = {
+    appId: state.ID,
+    prePrompt: state.form.tips,
+  }
+  if (state.detail.type === 0) {
+    params.modelId = state.form.modelId
+  } else {
+  }
+  appModelConfigSave(params)
+    .then(({ data }: any) => {
+      state.autoSaveTimestamp = data.updateTime
+      state.isDebug = false
+      loading.close()
+    })
+    .catch(() => {})
+    .finally(() => {})
+}, 5000)
 const initDetail = () => {
+  state.isInit = false
   if (state.ID) {
-    state.detail = {}
+    appDetail(state.ID)
+      .then(({ data: appData }: any) => {
+        state.detail = appData
+        document.title = state.detail.name
+        appModelConfigDetail(state.ID)
+          .then(({ data: configData }: any) => {
+            state.autoSaveTimestamp = configData.updateTime
+            state.config = JSON.parse(JSON.stringify(configData))
+            state.form.tips = configData.prePrompt || ''
+            if (state.detail.type === 0) {
+              if (configData.modelId) {
+                state.form.modelId = configData.modelId
+              }
+            } else {
+            }
+            setTimeout(() => {
+              state.isInit = true
+            }, 100)
+          })
+          .catch(() => {})
+          .finally(() => {
+            state.loading = false
+          })
+      })
+      .catch(() => {})
+      .finally(() => {
+        state.loading = false
+      })
     // pluginDetail(state.ID)
     //   .then(({ data }: any) => {
     //     state.detail = data
@@ -861,12 +942,12 @@ const getModel = (val) => {
   switch (state.modelSelect.transfer.type) {
     case 'model':
       {
-        state.form.model = val
+        state.form.modelId = val.value
       }
       break
     case 'advise':
       {
-        state.form.advise.model = val
+        state.form.advise.modelId = val
       }
       break
   }
@@ -874,14 +955,14 @@ const getModel = (val) => {
 const onModel = () => {
   state.modelSelect.transfer = {
     type: 'model',
-    id: state.form.model.id,
+    id: state.form.modelId,
   }
   state.modelSelect.show = true
 }
 const onAdviseModel = () => {
   state.modelSelect.transfer = {
     type: 'advise',
-    id: state.form.advise.model.id,
+    id: state.form.advise.modelId,
   }
   state.modelSelect.show = true
 }
@@ -953,24 +1034,6 @@ const onPublishSubmit = () => {
       })
     })
 }
-watch(
-  () => state.form,
-  (n) => {
-    autoSave(n)
-  },
-  { deep: true },
-)
-const autoSave = debounce((v) => {
-  const loading = ElLoading.service({
-    text: '自动保存中……',
-    background: 'rgba(0, 0,0, 0.3)',
-  })
-  setTimeout(() => {
-    loading.close()
-    state.autoSaveTimestamp = YMDHms(new Date())
-    state.isDebug = false
-  }, 1000)
-}, 3000)
 const onAddTipsTemplate = () => {
   state.templateDetail.transfer = {
     mode: 'add',
@@ -995,8 +1058,7 @@ onMounted(() => {
   initDetail()
 })
 const initDictionary = () => {
-  // DictionaryStore.initModelProvides()
-  // DictionaryStore.initModelTypes()
+  DictionaryStore.initModels()
 }
 </script>
 

+ 1 - 1
src/views/manage/app/make/template-select.vue

@@ -145,7 +145,7 @@ watch(
 const initData = () => {
   const params = {
     page: 1,
-    size: 9999,
+    size: 100000,
   }
   const arrSystem: any = []
   const arrUser: any = []

+ 9 - 9
src/views/manage/knowledge/documents/qa/index.vue

@@ -70,9 +70,9 @@
       :transfer="state.rename.transfer"
       @refresh="onSearch"
     />
-    <KnowledgeCard
-      v-model:show="state.knowledge.show"
-      :transfer="state.knowledge.transfer"
+    <moveSelectCom
+      v-model:show="state.moveSelect.show"
+      :transfer="state.moveSelect.transfer"
       @refresh="onSearch"
     />
   </div>
@@ -93,7 +93,7 @@ import { useDialogStore, useDictionaryStore } from '@/stores'
 import { ElMessage } from 'element-plus'
 import detailCom from './detail.vue'
 import renameCom from './rename.vue'
-import knowledgeCard from '@/views/manage/knowledge/knowledge-card.vue'
+import moveSelectCom from '../document/move-select.vue'
 import { qaGetQaPage, qaQaDocsDelete } from '@/api/modules/knowledge/qa'
 
 const DialogStore = useDialogStore()
@@ -154,7 +154,7 @@ const state: any = reactive({
     show: false,
     transfer: {},
   },
-  knowledge: {
+  moveSelect: {
     show: false,
     transfer: {},
   },
@@ -280,21 +280,21 @@ const onRename = (row) => {
 }
 const onKnowledge = (row: any = null) => {
   if (row) {
-    state.knowledge.transfer = {
+    state.moveSelect.transfer = {
       row: JSON.parse(JSON.stringify(row)),
       type: 'qa',
     }
-    state.knowledge.show = true
+    state.moveSelect.show = true
   } else {
     if (state.query.selected.length === 0) {
       ElMessage.warning('请至少选择一条记录!')
       return
     }
-    state.knowledge.transfer = {
+    state.moveSelect.transfer = {
       list: [...state.query.selected],
       type: 'qa',
     }
-    state.knowledge.show = true
+    state.moveSelect.show = true
   }
 }
 onMounted(() => {