tycoding пре 1 година
родитељ
комит
e0c842d0ec
36 измењених фајлова са 267 додато и 239 уклоњено
  1. 1 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcDocsController.java
  2. 3 4
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcDocsSliceController.java
  3. 18 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcKnowledgeController.java
  4. 6 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/endpoint/EmbeddingEndpoint.java
  5. 4 4
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcConversation.java
  6. 4 4
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcDocs.java
  7. 4 4
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcDocsSlice.java
  8. 6 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcKnowledge.java
  9. 5 5
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcMessage.java
  10. 3 3
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcOss.java
  11. 2 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcPrompt.java
  12. 2 2
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcUser.java
  13. 13 45
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/listener/StructExcelListener.java
  14. 3 3
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/service/impl/AigcMessageServiceImpl.java
  15. 1 1
      langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/utils/AigcAuthUtil.java
  16. 6 6
      langchat-common/src/main/java/cn/tycoding/langchat/common/dto/ChatReq.java
  17. 4 4
      langchat-core/src/main/java/cn/tycoding/langchat/core/entity/AigcStructCol.java
  18. 4 9
      langchat-core/src/main/java/cn/tycoding/langchat/core/entity/AigcStructRow.java
  19. 6 5
      langchat-core/src/main/java/cn/tycoding/langchat/core/tools/StructTools.java
  20. 3 4
      langchat-server/src/main/java/cn/tycoding/langchat/aigc/endpoint/KnowledgeChatEndpoint.java
  21. 6 4
      langchat-server/src/main/java/cn/tycoding/langchat/aigc/service/impl/ChatServiceImpl.java
  22. 1 1
      langchat-ui/src/components/CheckCard/CheckCard.vue
  23. 3 3
      langchat-ui/src/views/aigc/chat/components/Chat.vue
  24. 28 0
      langchat-ui/src/views/aigc/chat/components/DataTable.vue
  25. 4 6
      langchat-ui/src/views/aigc/chat/components/store/useChatStore.ts
  26. 76 70
      langchat-ui/src/views/aigc/chat/index.vue
  27. 12 4
      langchat-ui/src/views/aigc/knowledge/components/ImportFile/components/ExcelImport.vue
  28. 19 20
      langchat-ui/src/views/aigc/knowledge/components/ImportFile/index.vue
  29. 13 11
      langchat-ui/src/views/aigc/knowledge/components/index.vue
  30. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysClient.java
  31. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysDept.java
  32. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysLog.java
  33. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysMenu.java
  34. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysRole.java
  35. 1 1
      langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysUser.java
  36. 1 1
      pom.xml

+ 1 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcDocsController.java

@@ -1,6 +1,5 @@
 package cn.tycoding.langchat.aigc.controller;
 
-import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.aigc.entity.AigcDocs;
 import cn.tycoding.langchat.aigc.mapper.AigcDocsMapper;
 import cn.tycoding.langchat.common.utils.MybatisUtil;
@@ -33,7 +32,7 @@ public class AigcDocsController {
     public R list(AigcDocs data, QueryPage queryPage) {
         Page<AigcDocs> page = new Page<>(queryPage.getPage(), queryPage.getLimit());
         return R.ok(MybatisUtil.getData(docsMapper.selectPage(page, Wrappers.<AigcDocs>lambdaQuery()
-                .eq(!StrUtil.isBlank(data.getKnowledgeId()), AigcDocs::getKnowledgeId, data.getKnowledgeId())
+                .eq(data.getKnowledgeId() != null, AigcDocs::getKnowledgeId, data.getKnowledgeId())
                 .eq(data.getSliceStatus() != null, AigcDocs::getSliceStatus, data.getSliceStatus())
                 .orderByDesc(AigcDocs::getCreateTime)
         )));

+ 3 - 4
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcDocsSliceController.java

@@ -1,6 +1,5 @@
 package cn.tycoding.langchat.aigc.controller;
 
-import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.aigc.entity.AigcDocsSlice;
 import cn.tycoding.langchat.aigc.mapper.AigcDocsSliceMapper;
 import cn.tycoding.langchat.common.utils.MybatisUtil;
@@ -8,10 +7,10 @@ import cn.tycoding.langchat.common.utils.QueryPage;
 import cn.tycoding.langchat.common.utils.R;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import java.util.Date;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -34,8 +33,8 @@ public class AigcDocsSliceController {
     public R list(AigcDocsSlice data, QueryPage queryPage) {
         Page<AigcDocsSlice> page = new Page<>(queryPage.getPage(), queryPage.getLimit());
         return R.ok(MybatisUtil.getData(docsSliceMapper.selectPage(page, Wrappers.<AigcDocsSlice>lambdaQuery()
-                .eq(!StrUtil.isBlank(data.getKnowledgeId()), AigcDocsSlice::getKnowledgeId, data.getKnowledgeId())
-                .eq(!StrUtil.isBlank(data.getDocsId()), AigcDocsSlice::getDocsId, data.getDocsId())
+                .eq(data.getKnowledgeId() != null, AigcDocsSlice::getKnowledgeId, data.getKnowledgeId())
+                .eq(data.getDocsId() != null, AigcDocsSlice::getDocsId, data.getDocsId())
                 .orderByDesc(AigcDocsSlice::getCreateTime)
         )));
     }

+ 18 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/controller/AigcKnowledgeController.java

@@ -14,6 +14,7 @@ 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;
@@ -32,7 +33,22 @@ public class AigcKnowledgeController {
 
     @GetMapping("/list")
     public R<List<AigcKnowledge>> list(AigcKnowledge data) {
-        return R.ok(kbService.list(Wrappers.<AigcKnowledge>lambdaQuery().orderByDesc(AigcKnowledge::getCreateTime)));
+        List<AigcKnowledge> list = kbService.list(Wrappers.<AigcKnowledge>lambdaQuery().orderByDesc(AigcKnowledge::getCreateTime));
+        List<Long> 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<Long, 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());
+            }
+
+        });
+        return R.ok(list);
     }
 
     @GetMapping("/page")
@@ -43,7 +59,7 @@ public class AigcKnowledgeController {
                 .orderByDesc(AigcKnowledge::getCreateTime);
         Page<AigcKnowledge> iPage = kbService.page(page, queryWrapper);
 
-        Map<String, List<AigcDocs>> docsMap = docsMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
+        Map<Long, List<AigcDocs>> docsMap = docsMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcDocs::getKnowledgeId));
         iPage.getRecords().forEach(i -> {
             List<AigcDocs> docs = docsMap.get(i.getId());
             if (docs != null) {

+ 6 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/endpoint/EmbeddingEndpoint.java

@@ -18,6 +18,7 @@ import cn.tycoding.langchat.core.service.LangDocService;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.enums.CellExtraTypeEnum;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -30,6 +31,7 @@ import java.util.List;
  * @author tycoding
  * @since 2024/4/25
  */
+@Slf4j
 @RestController
 @AllArgsConstructor
 @RequestMapping("/aigc/embedding")
@@ -66,7 +68,7 @@ public class EmbeddingEndpoint {
     }
 
     @PostMapping("/docs/{knowledgeId}")
-    public R docs(MultipartFile file, @PathVariable String knowledgeId) {
+    public R docs(MultipartFile file, @PathVariable Long knowledgeId) {
         AigcOss oss = aigcOssService.upload(file);
         AigcDocs data = new AigcDocs()
                 .setName(oss.getFileName())
@@ -93,7 +95,7 @@ public class EmbeddingEndpoint {
     }
 
     @PostMapping("/struct/excel/{knowledgeId}")
-    public void structExcel(MultipartFile file, @PathVariable String knowledgeId) throws IOException {
+    public R structExcel(MultipartFile file, @PathVariable Long knowledgeId) throws IOException {
         byte[] bytes = file.getBytes();
         AigcOss oss = aigcOssService.upload(file);
         AigcDocs data = new AigcDocs()
@@ -104,8 +106,10 @@ public class EmbeddingEndpoint {
                 .setKnowledgeId(knowledgeId);
         aigcKnowledgeService.addDocs(data);
 
+        log.info("解析开始...");
         EasyExcel.read(new ByteArrayInputStream(bytes), new StructExcelListener(structColService, structRowService, knowledgeId, data.getId()))
                 .extraRead(CellExtraTypeEnum.MERGE)
                 .sheet().doRead();
+        return R.ok();
     }
 }

+ 4 - 4
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcConversation.java

@@ -22,18 +22,18 @@ public class AigcConversation implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 提示词ID
      */
-    private String promptId;
+    private Long promptId;
 
     /**
      * 用户ID
      */
-    private String userId;
+    private Long userId;
 
     /**
      * 会话标题

+ 4 - 4
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcDocs.java

@@ -3,10 +3,10 @@ package cn.tycoding.langchat.aigc.entity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import lombok.Data;
+import lombok.experimental.Accessors;
 
 import java.io.Serializable;
 import java.util.Date;
-import lombok.experimental.Accessors;
 
 /**
  * @author tycoding
@@ -20,13 +20,13 @@ public class AigcDocs implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 知识库ID
      */
-    private String knowledgeId;
+    private Long knowledgeId;
 
     /**
      * 名称

+ 4 - 4
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcDocsSlice.java

@@ -20,8 +20,8 @@ public class AigcDocsSlice implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 向量库的ID
@@ -31,12 +31,12 @@ public class AigcDocsSlice implements Serializable {
     /**
      * 文档ID
      */
-    private String docsId;
+    private Long docsId;
 
     /**
      * 知识库ID
      */
-    private String knowledgeId;
+    private Long knowledgeId;
 
     /**
      * 文档名称

+ 6 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcKnowledge.java

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * @author tycoding
@@ -20,8 +22,8 @@ public class AigcKnowledge implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 知识库名称
@@ -52,5 +54,7 @@ public class AigcKnowledge implements Serializable {
     private Integer docsNum = 0;
     @TableField(exist = false)
     private Long totalSize = 0L;
+    @TableField(exist = false)
+    private List<AigcDocs> docs = new ArrayList<>();
 }
 

+ 5 - 5
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcMessage.java

@@ -23,23 +23,23 @@ public class AigcMessage implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 消息ID
      */
-    private String chatId;
+    private Long chatId;
 
     /**
      * 会话ID
      */
-    private String conversationId;
+    private Long conversationId;
 
     /**
      * 用户ID
      */
-    private String userId;
+    private Long userId;
     /**
      * 用户名
      */

+ 3 - 3
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcOss.java

@@ -19,13 +19,13 @@ public class AigcOss extends OssR {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 用户ID
      */
-    private String userId;
+    private Long userId;
 
     /**
      * 文件描述

+ 2 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcPrompt.java

@@ -19,8 +19,8 @@ public class AigcPrompt implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 名称

+ 2 - 2
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/entity/AigcUser.java

@@ -19,8 +19,8 @@ public class AigcUser implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 用户名

+ 13 - 45
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/listener/StructExcelListener.java

@@ -1,5 +1,6 @@
 package cn.tycoding.langchat.aigc.listener;
 
+import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.core.entity.AigcStructCol;
 import cn.tycoding.langchat.core.entity.AigcStructRow;
 import cn.tycoding.langchat.core.service.AigcStructColService;
@@ -29,10 +30,10 @@ public class StructExcelListener extends AnalysisEventListener<Map<Integer, Stri
 
     private final AigcStructColService structColService;
     private final AigcStructRowService structRowService;
-    private final String knowledgeId;
-    private final String docsId;
+    private final Long knowledgeId;
+    private final Long docsId;
 
-    public StructExcelListener(AigcStructColService structColService, AigcStructRowService structRowService, String knowledgeId, String docsId) {
+    public StructExcelListener(AigcStructColService structColService, AigcStructRowService structRowService, Long knowledgeId, Long docsId) {
         this.structColService = structColService;
         this.structRowService = structRowService;
         this.knowledgeId = knowledgeId;
@@ -46,7 +47,6 @@ public class StructExcelListener extends AnalysisEventListener<Map<Integer, Stri
 
     @Override
     public void doAfterAllAnalysed(AnalysisContext context) {
-        //读取完成 填充合并过的单元格
         if (!cellExtraList.isEmpty()) {
             mergeExcelData(list, cellExtraList, HEAD_ROW_NUM);
         }
@@ -54,23 +54,22 @@ public class StructExcelListener extends AnalysisEventListener<Map<Integer, Stri
         structColService.saveBatch(cols);
         List<AigcStructRow> rows = new ArrayList<>();
         list.forEach(i -> {
-            i.forEach((k,v) -> {
-                rows.add(new AigcStructRow()
-                        .setValue(v)
-                        .setColIndex(k)
-                        .setColId(cols.get(k).getId())
-                        .setDocsId(docsId)
-                        .setKnowledgeId(knowledgeId));
+            i.forEach((k, v) -> {
+                if (StrUtil.isNotBlank(v)) {
+                    rows.add(new AigcStructRow()
+                            .setValue(v)
+                            .setColIndex(k)
+                            .setDocsId(docsId)
+                            .setKnowledgeId(knowledgeId));
+                }
             });
         });
         structRowService.saveBatch(rows);
-
-        log.info("----");
     }
 
     @Override
     public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
-        headMap.forEach((k,v) -> {
+        headMap.forEach((k, v) -> {
             cols.add(new AigcStructCol()
                     .setColIndex(v.getColumnIndex())
                     .setLabel(v.getStringValue())
@@ -110,42 +109,11 @@ public class StructExcelListener extends AnalysisEventListener<Map<Integer, Stri
     private void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<Map<Integer, String>> data) {
         Map<Integer, String> object = data.get(rowIndex);
         object.put(columnIndex, String.valueOf(filedValue));
-
-//        for (Field field : object.getClass().getDeclaredFields()) {
-//            field.setAccessible(true);
-//            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
-//            if (annotation != null) {
-//                if (annotation.index() == columnIndex) {
-//                    try {
-//                        field.set(object, filedValue);
-//                        break;
-//                    } catch (IllegalAccessException e) {
-//                        log.error("设置合并单元格的值异常:{}", e.getMessage());
-//                    }
-//                }
-//            }
-//        }
     }
 
     private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<Map<Integer, String>> data) {
         Map<Integer, String> object = data.get(firstRowIndex);
         return object.get(firstColumnIndex);
-//        Object filedValue = null;
-//        for (Field field : object.getClass().getDeclaredFields()) {
-//            field.setAccessible(true);
-//            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
-//            if (annotation != null) {
-//                if (annotation.index() == firstColumnIndex) {
-//                    try {
-//                        filedValue = field.get(object);
-//                        break;
-//                    } catch (IllegalAccessException e) {
-//                        log.error("设置合并单元格的初始值异常:{}", e.getMessage());
-//                    }
-//                }
-//            }
-//        }
-//        return filedValue;
     }
 
 }

+ 3 - 3
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/service/impl/AigcMessageServiceImpl.java

@@ -50,8 +50,8 @@ public class AigcMessageServiceImpl extends ServiceImpl<AigcMessageMapper, AigcM
                 .orderByDesc(AigcConversation::getCreateTime));
 
         if (!iPage.getRecords().isEmpty()) {
-            Map<String, List<AigcUser>> map = aigcUserMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcUser::getId));
-            Set<String> ids = iPage.getRecords().stream().map(AigcConversation::getId).collect(Collectors.toSet());
+            Map<Long, List<AigcUser>> map = aigcUserMapper.selectList(Wrappers.lambdaQuery()).stream().collect(Collectors.groupingBy(AigcUser::getId));
+            Set<Long> ids = iPage.getRecords().stream().map(AigcConversation::getId).collect(Collectors.toSet());
             List<AigcMessage> messages = baseMapper.selectList(Wrappers.<AigcMessage>lambdaQuery()
                     .in(AigcMessage::getConversationId, ids)
                     .orderByDesc(AigcMessage::getCreateTime));
@@ -102,7 +102,7 @@ public class AigcMessageServiceImpl extends ServiceImpl<AigcMessageMapper, AigcM
 
     @Override
     public AigcMessage addMessage(AigcMessage message) {
-        if (StrUtil.isBlank(message.getConversationId()) && RoleEnum.USER.getName()
+        if (message.getConversationId() != null && RoleEnum.USER.getName()
                 .equals(message.getRole())) {
             // create new conversation
             AigcConversation conversation = new AigcConversation();

+ 1 - 1
langchat-aigc/src/main/java/cn/tycoding/langchat/aigc/utils/AigcAuthUtil.java

@@ -67,7 +67,7 @@ public class AigcAuthUtil {
     /**
      * 获取登录用户ID
      */
-    public static String getUserId() {
+    public static Long getUserId() {
         AigcUserInfo userInfo = getUserInfo();
         if (userInfo == null) {
             return null;

+ 6 - 6
langchat-common/src/main/java/cn/tycoding/langchat/common/dto/ChatReq.java

@@ -17,21 +17,21 @@ public class ChatReq {
 
     private String message;
 
-    private String conversationId;
+    private Long conversationId;
 
-    private String userId;
+    private Long userId;
 
     private String username;
 
-    private String chatId;
+    private Long chatId;
 
-    private String promptId;
+    private Long promptId;
 
     private String promptText;
 
-    private String knowledgeId;
+    private Long knowledgeId;
 
-    private String docsId;
+    private Long docsId;
 
     private String path;
 

+ 4 - 4
langchat-core/src/main/java/cn/tycoding/langchat/core/entity/AigcStructCol.java

@@ -19,8 +19,8 @@ public class AigcStructCol implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 列索引
@@ -30,12 +30,12 @@ public class AigcStructCol implements Serializable {
     /**
      * 知识库ID
      */
-    private String knowledgeId;
+    private Long knowledgeId;
 
     /**
      * 文档ID
      */
-    private String docsId;
+    private Long docsId;
 
     /**
      * 列名称

+ 4 - 9
langchat-core/src/main/java/cn/tycoding/langchat/core/entity/AigcStructRow.java

@@ -19,23 +19,18 @@ public class AigcStructRow implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_UUID)
-    private String id;
+    @TableId(type = IdType.AUTO)
+    private Long id;
 
     /**
      * 知识库ID
      */
-    private String knowledgeId;
+    private Long knowledgeId;
 
     /**
      * 文档ID
      */
-    private String docsId;
-
-    /**
-     * 列ID
-     */
-    private String colId;
+    private Long docsId;
 
     /**
      * 列索引

+ 6 - 5
langchat-core/src/main/java/cn/tycoding/langchat/core/tools/StructTools.java

@@ -1,6 +1,5 @@
 package cn.tycoding.langchat.core.tools;
 
-import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.common.dto.ChatReq;
 import cn.tycoding.langchat.core.entity.AigcStructCol;
 import cn.tycoding.langchat.core.entity.AigcStructRow;
@@ -32,8 +31,9 @@ public class StructTools {
     @Tool("Gets column name data in Data")
     List<String> getCols() {
         List<AigcStructCol> list = structColService.list(Wrappers.<AigcStructCol>lambdaQuery()
-                .eq(StrUtil.isNotBlank(req.getKnowledgeId()), AigcStructCol::getKnowledgeId, req.getKnowledgeId())
-                .eq(StrUtil.isNotBlank(req.getDocsId()), AigcStructCol::getDocsId, req.getDocsId())
+                .eq(req.getKnowledgeId() != null, AigcStructCol::getKnowledgeId, req.getKnowledgeId())
+                .eq(req.getDocsId() != null, AigcStructCol::getDocsId, req.getDocsId())
+                .select(AigcStructCol::getLabel)
         );
         return list.stream().map(AigcStructCol::getLabel).toList();
     }
@@ -41,9 +41,10 @@ public class StructTools {
     @Tool("Gets all the data for a column")
     List<String> getColData(int col) {
         List<AigcStructRow> list = structRowService.list(Wrappers.<AigcStructRow>lambdaQuery()
-                .eq(StrUtil.isNotBlank(req.getKnowledgeId()), AigcStructRow::getKnowledgeId, req.getKnowledgeId())
-                .eq(StrUtil.isNotBlank(req.getDocsId()), AigcStructRow::getDocsId, req.getDocsId())
+                .eq(req.getKnowledgeId() != null, AigcStructRow::getKnowledgeId, req.getKnowledgeId())
+                .eq(req.getDocsId() != null, AigcStructRow::getDocsId, req.getDocsId())
                 .eq(AigcStructRow::getColIndex, col)
+                .select(AigcStructRow::getValue)
         );
         return list.stream().map(AigcStructRow::getValue).toList();
     }

+ 3 - 4
langchat-server/src/main/java/cn/tycoding/langchat/aigc/endpoint/KnowledgeChatEndpoint.java

@@ -1,6 +1,5 @@
 package cn.tycoding.langchat.aigc.endpoint;
 
-import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.aigc.entity.AigcMessage;
 import cn.tycoding.langchat.aigc.service.AigcMessageService;
 import cn.tycoding.langchat.aigc.service.ChatService;
@@ -30,14 +29,14 @@ public class KnowledgeChatEndpoint {
     public Object chat(@RequestBody ChatReq req) {
         StreamEmitter emitter = new StreamEmitter();
         req.setEmitter(emitter);
-        req.setUserId(String.valueOf(AuthUtil.getUserId()));
+        req.setUserId(AuthUtil.getUserId());
         req.setUsername(AuthUtil.getUsername());
 
-        if (StrUtil.isNotBlank(req.getKnowledgeId())) {
+        if (req.getKnowledgeId() != null) {
             req.setPrompt(PromptUtil.buildDocs(req.getMessage()));
             chatService.docsChat(req);
         }
-        if (StrUtil.isNotBlank(req.getPromptId())) {
+        if (req.getPromptId() != null) {
             req.setPrompt(PromptUtil.build(req.getMessage(), req.getPromptText()));
             chatService.chat(req);
         }

+ 6 - 4
langchat-server/src/main/java/cn/tycoding/langchat/aigc/service/impl/ChatServiceImpl.java

@@ -1,12 +1,14 @@
 package cn.tycoding.langchat.aigc.service.impl;
 
-import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.aigc.entity.AigcMessage;
 import cn.tycoding.langchat.aigc.entity.AigcOss;
 import cn.tycoding.langchat.aigc.service.AigcMessageService;
 import cn.tycoding.langchat.aigc.service.ChatService;
 import cn.tycoding.langchat.common.constant.RoleEnum;
-import cn.tycoding.langchat.common.dto.*;
+import cn.tycoding.langchat.common.dto.ChatReq;
+import cn.tycoding.langchat.common.dto.ChatRes;
+import cn.tycoding.langchat.common.dto.ImageR;
+import cn.tycoding.langchat.common.dto.TextR;
 import cn.tycoding.langchat.common.utils.ServletUtil;
 import cn.tycoding.langchat.common.utils.StreamEmitter;
 import cn.tycoding.langchat.core.enums.ModelConst;
@@ -56,7 +58,7 @@ public class ChatServiceImpl implements ChatService {
                         emitter.complete();
 
                         // save message
-                        if (StrUtil.isNotBlank(req.getConversationId())) {
+                        if (req.getConversationId() != null) {
                             req.setMessage(text.toString());
                             req.setRole(RoleEnum.ASSISTANT.getName());
                             saveMessage(req, tokenUsage.inputTokenCount(), tokenUsage.outputTokenCount());
@@ -155,7 +157,7 @@ public class ChatServiceImpl implements ChatService {
                         emitter.complete();
 
                         // save message
-                        if (StrUtil.isNotBlank(req.getConversationId())) {
+                        if (req.getConversationId() != null) {
                             req.setMessage(text.toString());
                             req.setRole(RoleEnum.ASSISTANT.getName());
                             saveMessage(req, tokenUsage.inputTokenCount(), tokenUsage.outputTokenCount());

+ 1 - 1
langchat-ui/src/components/CheckCard/CheckCard.vue

@@ -1,7 +1,7 @@
 <template>
   <n-space :justify="justify">
     <template v-for="item in dataSource" :key="item.key">
-      <div v-if="!item.isHidden" @click="handleChecked(item)" style="height: 96px">
+      <div @click="handleChecked(item)" style="height: 96px">
         <n-list
           :class="checked == item.key ? 'check-list-checked' : ''"
           class="check-list"

+ 3 - 3
langchat-ui/src/views/aigc/chat/components/Chat.vue

@@ -84,9 +84,9 @@
         {
           chatId: chatId.value,
           conversationId: chatStore.conversationId,
-          promptId: chatStore.promptId,
-          promptText: chatStore.promptText,
-          knowledgeId: chatStore.knowledgeId,
+          promptId: chatStore.prompt.id,
+          promptText: chatStore.prompt.prompt,
+          knowledgeId: chatStore.knowledge.id,
           message,
           role: 'user',
           model: chatStore.model,

+ 28 - 0
langchat-ui/src/views/aigc/chat/components/DataTable.vue

@@ -0,0 +1,28 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="w-full h-full overflow-y-auto">
+    <n-table size="small" :striped="true" class="w-full">
+      <thead>
+        <tr>
+          <th>Abandon</th>
+          <th>Abnormal</th>
+          <th>Abolish</th>
+          <th>...</th>
+          <th>万事开头难</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr v-for="i in 100">
+          <td>放弃</td>
+          <td>反常的</td>
+          <td>彻底废除</td>
+          <td>...</td>
+          <td>干!我刚才背的是啥</td>
+        </tr>
+      </tbody>
+    </n-table>
+  </div>
+</template>
+
+<style scoped lang="less"></style>

+ 4 - 6
langchat-ui/src/views/aigc/chat/components/store/useChatStore.ts

@@ -5,9 +5,8 @@ export interface ChatState {
   messages: any[];
   model: string;
   conversationId: string;
-  promptId: string | null;
-  promptText: string | null;
-  knowledgeId: string | null;
+  prompt: any;
+  knowledge: any;
 }
 
 export const useChatStore = defineStore('chat-store', {
@@ -16,9 +15,8 @@ export const useChatStore = defineStore('chat-store', {
       model: 'openai',
       conversationId: '',
       messages: [],
-      promptId: null,
-      promptText: null,
-      knowledgeId: null,
+      prompt: null,
+      knowledge: null,
     },
 
   getters: {},

+ 76 - 70
langchat-ui/src/views/aigc/chat/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-  import { onMounted, ref } from 'vue';
+  import { computed, onMounted, ref, toRaw } from 'vue';
   import SvgIcon from '@/components/SvgIcon/index.vue';
   import Chat from './components/Chat.vue';
   import { list as getKnowledgeList } from '@/api/aigc/knowledge';
@@ -8,6 +8,7 @@
   import { getMessages, clean } from '@/api/aigc/chat';
   import { useChatStore } from './components/store/useChatStore';
   import { useDialog, useMessage } from 'naive-ui';
+  import DataTable from './components/DataTable.vue';
 
   const dialog = useDialog();
   const ms = useMessage();
@@ -16,7 +17,7 @@
   const list = ref();
   const knowledgeList = ref();
   const promptList = ref();
-  const value = ref();
+  const value = ref('');
   const loading = ref(true);
   const chatLoading = ref(false);
   const model = ref('openai');
@@ -24,38 +25,36 @@
 
   onMounted(async () => {
     loading.value = true;
-    knowledgeList.value = await getKnowledgeList({});
+    const data = await getKnowledgeList({});
+    let arr: any[] = [];
+    data.forEach((item) => {
+      item.docs = item.docs.map((opt) => ({
+        label: opt.name,
+        value: opt.id,
+      }));
+      arr.push(item);
+    });
+    knowledgeList.value = arr;
+    console.log('xxx', knowledgeList.value);
     promptList.value = await getPromptList({});
     list.value = knowledgeList.value;
     loading.value = false;
   });
-  const options = [
-    {
-      label: 'Drive My Car',
-      value: 'Drive My Car',
-    },
-    {
-      label: 'Norwegian Wood',
-      value: 'Norwegian Wood',
-    },
-  ];
 
   async function onCheck(item: any) {
     checked.value = item;
     chatLoading.value = true;
     chatStore.messages = [];
     chatStore.conversationId = item.id;
-    chatStore.knowledgeId = null;
-    chatStore.promptId = null;
-    chatStore.promptText = null;
+    chatStore.knowledge = null;
+    chatStore.prompt = null;
     chatStore.messages = await getMessages(item.id);
 
     if (activeTab.value === 'knowledge') {
-      chatStore.knowledgeId = item.id;
+      chatStore.knowledge = item;
     }
     if (activeTab.value === 'prompt') {
-      chatStore.promptId = item.id;
-      chatStore.promptText = item.prompt;
+      chatStore.prompt = item;
     }
 
     chatLoading.value = false;
@@ -70,6 +69,10 @@
     }
   }
 
+  function onUpdateSelect(val, opt) {
+    console.log(val, opt);
+  }
+
   // 清除
   function handleClear() {
     if (loading.value || chatStore.conversationId == null) {
@@ -103,8 +106,9 @@
             <li v-for="(item, idx) in list" :key="idx" @click="onCheck(item)">
               <n-popselect
                 v-model:value="value"
-                :options="options"
+                :options="item.docs"
                 placement="right"
+                @update:value="onUpdateSelect"
                 :show="item.isStruct !== undefined && item.isStruct && item == checked"
               >
                 <label :for="item.name" class="block relative">
@@ -140,19 +144,6 @@
                       </p>
                     </div>
                   </div>
-                  <div
-                    class="absolute top-4 right-4 flex-none flex items-center justify-center w-4 h-4 rounded-full border peer-checked:bg-indigo-600 text-white peer-checked:text-white duration-200"
-                  >
-                    <svg class="w-2.5 h-2.5" viewBox="0 0 12 10">
-                      <polyline
-                        fill="none"
-                        stroke-width="2px"
-                        stroke="currentColor"
-                        stroke-dasharray="16px"
-                        points="1.5 6 4.5 9 10.5 1"
-                      />
-                    </svg>
-                  </div>
                 </label>
               </n-popselect>
             </li>
@@ -161,46 +152,61 @@
       </n-spin>
     </n-layout-sider>
 
-    <div class="flex justify-center items-center w-full mt-0">
-      <div class="p-8 pt-6 w-full h-full mb-2">
-        <div class="mb-2 flex flex-wrap justify-between items-center">
-          <div class="font-bold flex justify-center items-center flex-wrap gap-2">
-            <SvgIcon class="text-lg" icon="ion:sparkles-outline" />
-            <span>AI对话</span>
+    <div class="flex flex-col gap-1 items-center w-full mt-0">
+      <n-split direction="vertical" :default-size="0" :resize-trigger-size="0">
+        <template #1>
+          <div class="w-full p-2 mb-4 h-full">
+            <span
+              class="inline-flex items-center mb-2 gap-x-2 rounded-full bg-green-600/20 px-2.5 py-1 text-sm font-semibold leading-5 text-green-600"
+            >
+              <span class="inline-block h-1.5 w-1.5 rounded-full bg-green-600"></span>
+              Approved
+            </span>
+            <DataTable />
           </div>
-          <n-space align="center">
-            <n-select
-              size="small"
-              v-model:value="chatStore.model"
-              :options="modelList"
-              class="!w-[200px]"
-            />
+        </template>
+        <template #2>
+          <div class="p-8 pt-6 w-full h-full mb-2">
+            <div class="mb-2 flex flex-wrap justify-between items-center">
+              <div class="font-bold flex justify-center items-center flex-wrap gap-2">
+                <SvgIcon class="text-lg" icon="ion:sparkles-outline" />
+                <span>AI对话</span>
+              </div>
+              <n-space align="center">
+                <n-select
+                  size="small"
+                  v-model:value="chatStore.model"
+                  :options="modelList"
+                  class="!w-[200px]"
+                />
 
-            <n-button @click="handleClear" size="small" type="success" secondary>
-              <template #icon>
-                <SvgIcon class="text-[14px]" icon="fluent:delete-12-regular" />
-              </template>
-              清空聊天
-            </n-button>
-          </n-space>
-        </div>
-        <div class="w-full h-full rounded-md p-2 flex items-center justify-center">
-          <n-spin :show="chatLoading">
-            <Chat
-              :id="checked.id"
-              :model="model"
-              v-if="checked !== undefined && checked.id !== undefined"
-            />
-            <div v-else class="w-full h-full flex items-center justify-center">
-              <n-empty description="请先选中左侧的知识库或者提示词列表开始聊天!">
-                <template #extra>
-                  <n-button size="small" type="success"> 立即开始 </n-button>
-                </template>
-              </n-empty>
+                <n-button @click="handleClear" size="small" type="success" secondary>
+                  <template #icon>
+                    <SvgIcon class="text-[14px]" icon="fluent:delete-12-regular" />
+                  </template>
+                  清空聊天
+                </n-button>
+              </n-space>
             </div>
-          </n-spin>
-        </div>
-      </div>
+            <div class="w-full h-full rounded-md p-2 flex items-center justify-center">
+              <n-spin :show="chatLoading">
+                <Chat
+                  :id="checked.id"
+                  :model="model"
+                  v-if="checked !== undefined && checked.id !== undefined"
+                />
+                <div v-else class="w-full h-full flex items-center justify-center">
+                  <n-empty description="请先选中左侧的知识库或者提示词列表开始聊天!">
+                    <template #extra>
+                      <n-button size="small" type="success"> 立即开始 </n-button>
+                    </template>
+                  </n-empty>
+                </div>
+              </n-spin>
+            </div>
+          </div>
+        </template>
+      </n-split>
     </div>
   </n-layout>
 </template>

+ 12 - 4
langchat-ui/src/views/aigc/knowledge/components/ImportFile/components/ExcelImport.vue

@@ -8,9 +8,12 @@
   const router = useRouter();
   const message = useMessage();
   const fileList = ref<any[]>([]);
+  const loading = ref(false);
 
   const handleImport = ({ file, onFinish, onError, onProgress }: UploadCustomRequestOptions) => {
+    message.info('数据解析中...');
     const kbId = router.currentRoute.value.params.id;
+    loading.value = true;
     embeddingExcel(
       String(kbId),
       {
@@ -24,19 +27,24 @@
     )
       .then((res) => {
         fileList.value.push(res);
-        message.success('上传成功');
+        message.success('数据解析成功...');
         onFinish();
       })
       .catch((err) => {
-        message.error('上传失败');
+        console.error(err);
+        message.error('数据解析失败...');
         onError();
+      })
+      .finally(() => {
+        loading.value = false;
       });
   };
 </script>
 
 <template>
-  <div>
+  <n-spin :show="loading">
     <n-upload
+      :disabled="loading"
       :custom-request="handleImport"
       directory-dnd
       accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-exce"
@@ -53,7 +61,7 @@
         </n-p>
       </n-upload-dragger>
     </n-upload>
-  </div>
+  </n-spin>
 </template>
 
 <style scoped lang="less"></style>

+ 19 - 20
langchat-ui/src/views/aigc/knowledge/components/ImportFile/index.vue

@@ -31,13 +31,6 @@
       title: '导入文档',
       label: '支持导入word、txt、pdf、markdown等文本文件',
     },
-    {
-      key: 'excel-import',
-      icon: PodiumOutline,
-      title: 'Excel文件导入',
-      isHidden: !props.data.isStruct,
-      label: '处理excel结构化数据,支持对Excel行列数据读取',
-    },
     {
       key: 'url-import',
       icon: CloudDownloadOutline,
@@ -53,19 +46,25 @@
 </script>
 
 <template>
-  <div v-if="data">
-    <CheckCard
-      v-if="!data.isStruct"
-      :data-source="dataSource"
-      :default-checked="checked"
-      :justify="'start'"
-      @on-checked="handleCheck"
-    />
-    <n-card class="mt-3">
-      <DocInput v-if="checked == 'doc-input'" />
-      <URLImport v-if="checked == 'url-import'" />
-      <DocImport v-if="checked == 'doc-import'" />
-      <ExcelImport v-if="checked == 'excel-import'" />
+  <div v-if="data" class="flex flex-col gap-3">
+    <template v-if="!data.isStruct">
+      <CheckCard
+        :data-source="dataSource"
+        :default-checked="checked"
+        :justify="'start'"
+        @on-checked="handleCheck"
+      />
+    </template>
+
+    <n-card>
+      <template v-if="data.isStruct">
+        <ExcelImport />
+      </template>
+      <template v-else>
+        <DocInput v-if="checked == 'doc-input'" />
+        <URLImport v-if="checked == 'url-import'" />
+        <DocImport v-if="checked == 'doc-import'" />
+      </template>
     </n-card>
   </div>
 </template>

+ 13 - 11
langchat-ui/src/views/aigc/knowledge/components/index.vue

@@ -19,28 +19,30 @@
 
   const menu = ref();
   const menuOptions: MenuOption[] = [
-    {
-      label: '文档管理',
-      key: 'doc-list',
-      icon: renderIcon(DocumentTextOutline),
-    },
-    {
-      label: '切片管理',
-      key: 'slice-list',
-      icon: renderIcon(AlbumsOutline),
-    },
     {
       label: '数据导入',
       key: 'import-file',
       icon: renderIcon(CloudUploadOutline),
     },
+    {
+      label: '文档管理',
+      key: 'doc-list',
+      icon: renderIcon(DocumentTextOutline),
+    },
   ];
 
   const knowledge = ref<any>({});
   onMounted(async () => {
     const id = router.currentRoute.value.params.id;
     knowledge.value = await getById(String(id));
-    menu.value = 'doc-list';
+    menu.value = menuOptions[0].key;
+    if (knowledge.value.isStruct) {
+      menuOptions.push({
+        label: '切片管理',
+        key: 'slice-list',
+        icon: renderIcon(AlbumsOutline),
+      });
+    }
   });
 
   function handleSelect(key: string, item: MenuOption) {

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysClient.java

@@ -21,7 +21,7 @@ public class SysClient implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysDept.java

@@ -19,7 +19,7 @@ public class SysDept implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysLog.java

@@ -22,7 +22,7 @@ public class SysLog implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysMenu.java

@@ -19,7 +19,7 @@ public class SysMenu implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysRole.java

@@ -19,7 +19,7 @@ public class SysRole implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
langchat-upms/src/main/java/cn/tycoding/langchat/upms/entity/SysUser.java

@@ -22,7 +22,7 @@ public class SysUser implements Serializable {
     /**
      * 主键
      */
-    @TableId(type = IdType.ASSIGN_ID)
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /**

+ 1 - 1
pom.xml

@@ -26,7 +26,7 @@
         <mysql-connector.version>8.3.0</mysql-connector.version>
         <fastjson.version>2.0.47</fastjson.version>
         <snakeyaml.version>2.1</snakeyaml.version>
-        <langchain4j.version>0.30.0</langchain4j.version>
+        <langchain4j.version>0.31.0</langchain4j.version>
         <sa-token.version>1.37.0</sa-token.version>
     </properties>