Преглед изворни кода

update: 实现对embedding model & store 动态配置

tycoding пре 9 месеци
родитељ
комит
1126bde43f

+ 24 - 0
langchat-app/src/main/java/cn/tycoding/langchat/app/controller/AigcAppController.java

@@ -23,7 +23,10 @@ import cn.tycoding.langchat.app.entity.AigcAppApi;
 import cn.tycoding.langchat.app.service.AigcAppApiService;
 import cn.tycoding.langchat.app.service.AigcAppService;
 import cn.tycoding.langchat.app.store.AppStore;
+import cn.tycoding.langchat.biz.entity.AigcKnowledge;
+import cn.tycoding.langchat.biz.service.AigcKnowledgeService;
 import cn.tycoding.langchat.common.annotation.ApiLog;
+import cn.tycoding.langchat.common.exception.ServiceException;
 import cn.tycoding.langchat.common.utils.MybatisUtil;
 import cn.tycoding.langchat.common.utils.QueryPage;
 import cn.tycoding.langchat.common.utils.R;
@@ -33,7 +36,9 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 @RestController
 @RequiredArgsConstructor
@@ -43,6 +48,7 @@ public class AigcAppController {
     private final AigcAppService aigcAppService;
     private final AigcAppApiService aigcAppApiService;
     private final AppStore appStore;
+    private final AigcKnowledgeService knowledgeService;
 
     @GetMapping("/channel/api/{appId}")
     public R<AigcAppApi> getApiChanel(@PathVariable String appId) {
@@ -84,6 +90,24 @@ public class AigcAppController {
     @ApiLog("修改应用")
     @SaCheckPermission("aigc:app:update")
     public R update(@RequestBody AigcApp data) {
+        // 校验知识库是否是同纬度
+        List<String> knowledgeIds = data.getKnowledgeIds();
+        if (knowledgeIds != null) {
+            List<AigcKnowledge> list = knowledgeService.list(Wrappers.<AigcKnowledge>lambdaQuery().in(AigcKnowledge::getId, knowledgeIds));
+            Set<String> modelIds = new HashSet<>();
+            Set<String> storeIds = new HashSet<>();
+            list.forEach(know -> {
+                modelIds.add(know.getEmbedModelId());
+                storeIds.add(know.getEmbedStoreId());
+            });
+            if (modelIds.size() > 1) {
+                throw new ServiceException("请选择相同向量库数据源配置的知识库");
+            }
+            if (storeIds.size() > 1) {
+                throw new ServiceException("请选择相同向量模型配置的知识库");
+            }
+        }
+
         data.setSaveTime(new Date());
         aigcAppService.updateById(data);
         appStore.init();

+ 14 - 24
langchat-server/src/main/java/cn/tycoding/langchat/server/controller/AigcKnowledgeController.java

@@ -38,7 +38,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -62,35 +61,15 @@ public class AigcKnowledgeController {
     @GetMapping("/list")
     public R<List<AigcKnowledge>> list(AigcKnowledge data) {
         List<AigcKnowledge> list = kbService.list(Wrappers.<AigcKnowledge>lambdaQuery().orderByDesc(AigcKnowledge::getCreateTime));
-        List<String> ids = list.stream().map(AigcKnowledge::getId).toList();
-        List<AigcDocs> docs = new ArrayList<>();
-        if (!ids.isEmpty()){
-            docs = docsMapper.selectList(Wrappers.<AigcDocs>lambdaQuery().in(AigcDocs::getKnowledgeId, ids));
-        }
-        Map<String, List<AigcDocs>> docsMap = docs.stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
-        list.forEach(i -> {
-            List<AigcDocs> val = docsMap.get(i.getId());
-            if (val != null) {
-                i.setDocs(val);
-                i.setDocsNum(val.size());
-            }
-
-        });
+        build(list);
         return R.ok(list);
     }
 
-    @GetMapping("/page")
-    public R list(AigcKnowledge data, QueryPage queryPage) {
-        Page<AigcKnowledge> page = new Page<>(queryPage.getPage(), queryPage.getLimit());
-        LambdaQueryWrapper<AigcKnowledge> queryWrapper = Wrappers.<AigcKnowledge>lambdaQuery()
-                .like(!StrUtil.isBlank(data.getName()), AigcKnowledge::getName, data.getName())
-                .orderByDesc(AigcKnowledge::getCreateTime);
-        Page<AigcKnowledge> iPage = kbService.page(page, queryWrapper);
-
+    private void build(List<AigcKnowledge> records) {
         Map<String, List<AigcEmbedStore>> embedStoreMap = embedStoreService.list().stream().collect(Collectors.groupingBy(AigcEmbedStore::getId));
         Map<String, List<AigcModel>> embedModelMap = modelService.list().stream().collect(Collectors.groupingBy(AigcModel::getId));
         Map<String, List<AigcDocs>> docsMap = docsMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
-        iPage.getRecords().forEach(item -> {
+        records.forEach(item -> {
             List<AigcDocs> docs = docsMap.get(item.getId());
             if (docs != null) {
                 item.setDocsNum(docs.size());
@@ -105,6 +84,17 @@ public class AigcKnowledgeController {
                 item.setEmbedStore(list == null ? null : list.get(0));
             }
         });
+    }
+
+    @GetMapping("/page")
+    public R list(AigcKnowledge data, QueryPage queryPage) {
+        Page<AigcKnowledge> page = new Page<>(queryPage.getPage(), queryPage.getLimit());
+        LambdaQueryWrapper<AigcKnowledge> queryWrapper = Wrappers.<AigcKnowledge>lambdaQuery()
+                .like(!StrUtil.isBlank(data.getName()), AigcKnowledge::getName, data.getName())
+                .orderByDesc(AigcKnowledge::getCreateTime);
+        Page<AigcKnowledge> iPage = kbService.page(page, queryWrapper);
+
+        build(iPage.getRecords());
 
         return R.ok(MybatisUtil.getData(iPage));
     }

+ 23 - 2
langchat-ui/src/views/app/base/settings/KnowledgeList.vue

@@ -54,14 +54,35 @@
 </script>
 
 <template>
-  <basicModal style="width: 35%" @register="modalRegister">
+  <basicModal style="width: 40%" @register="modalRegister">
+    <n-alert
+      class="w-full mb-2 mt-2 min-alert"
+      title="注意:只能选择相同纬度向量库配置(以及相同向量模型)的知识库"
+      type="info"
+    />
     <n-scrollbar>
       <n-list clickable hoverable>
-        <n-list-item v-for="item in knowledges" :key="item.id">
+        <n-list-item v-for="item in knowledges" :key="item.id" class="!px-1">
           <div class="flex items-center justify-between">
             <div class="flex gap-1 items-center">
               <SvgIcon class="text-3xl" icon="flat-color-icons:document" />
               <div>{{ item.name }}</div>
+
+              <n-divider v-if="item.embedModel != null" vertical />
+              <n-tag v-if="item.embedModel != null" round type="success" size="small">
+                <div class="!flex gap-1 px-1.5">
+                  <SvgIcon icon="octicon:ai-model-24" />
+                  <span>{{ item.embedModel.name }}</span>
+                </div>
+              </n-tag>
+
+              <n-divider v-if="item.embedStore != null" class="!mx-1" vertical />
+              <n-tag v-if="item.embedStore != null" round type="primary" size="small">
+                <div class="!flex gap-1 px-1.5">
+                  <SvgIcon icon="material-symbols:database-outline" />
+                  <span>{{ item.embedStore.name }}</span>
+                </div>
+              </n-tag>
             </div>
             <n-button
               v-if="!appStore.knowledgeIds.includes(item.id)"