feat: 知识库优化
This commit is contained in:
parent
be9aecc45f
commit
f4fa8d026f
|
@ -49,6 +49,7 @@ mybatis-plus:
|
||||||
mapper-locations: classpath*:/mapper/*.xml
|
mapper-locations: classpath*:/mapper/*.xml
|
||||||
configuration:
|
configuration:
|
||||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
|
map-underscore-to-camel-case: true
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
file: /data/logs
|
file: /data/logs
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
package com.moyz.adi.chat.controller;
|
package com.moyz.adi.chat.controller;
|
||||||
|
|
||||||
|
import com.moyz.adi.common.entity.AdiFile;
|
||||||
|
import com.moyz.adi.common.exception.BaseException;
|
||||||
import com.moyz.adi.common.service.FileService;
|
import com.moyz.adi.common.service.FileService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.http.*;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.moyz.adi.common.enums.ErrorEnum.A_FILE_NOT_EXIST;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@Validated
|
@Validated
|
||||||
|
@ -35,6 +42,25 @@ public class FileController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/file/{uuid}")
|
||||||
|
public ResponseEntity<org.springframework.core.io.Resource> file(@Length(min = 32, max = 32) @PathVariable String uuid) {
|
||||||
|
AdiFile adiFile = fileService.getByUuid(uuid);
|
||||||
|
if (null == adiFile) {
|
||||||
|
throw new BaseException(A_FILE_NOT_EXIST);
|
||||||
|
}
|
||||||
|
byte[] bytes = fileService.readBytes(adiFile);
|
||||||
|
InputStreamResource inputStreamResource = new InputStreamResource(new ByteArrayInputStream(bytes));
|
||||||
|
|
||||||
|
String fileName = adiFile.getName();
|
||||||
|
if (StringUtils.isBlank(fileName)) {
|
||||||
|
fileName = adiFile.getUuid() + "." + adiFile.getExt();
|
||||||
|
}
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentDisposition(ContentDisposition.attachment().filename(fileName).build());
|
||||||
|
return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(path = "/file/upload", headers = "content-type=multipart/form-data", produces = MediaType.APPLICATION_JSON_VALUE)
|
@PostMapping(path = "/file/upload", headers = "content-type=multipart/form-data", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public Map<String, String> upload(@RequestPart(value = "file") MultipartFile file) {
|
public Map<String, String> upload(@RequestPart(value = "file") MultipartFile file) {
|
||||||
Map<String, String> result = new HashMap<>();
|
Map<String, String> result = new HashMap<>();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.moyz.adi.chat.controller;
|
package com.moyz.adi.chat.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.moyz.adi.common.dto.KbItemDto;
|
||||||
import com.moyz.adi.common.dto.KbItemEditReq;
|
import com.moyz.adi.common.dto.KbItemEditReq;
|
||||||
import com.moyz.adi.common.dto.KbItemEmbeddingBatchReq;
|
import com.moyz.adi.common.dto.KbItemEmbeddingBatchReq;
|
||||||
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
||||||
|
@ -11,8 +12,6 @@ import jakarta.validation.constraints.NotNull;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/knowledge-base-item")
|
@RequestMapping("/knowledge-base-item")
|
||||||
@Validated
|
@Validated
|
||||||
|
@ -27,7 +26,7 @@ public class KnowledgeBaseItemController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/search")
|
@GetMapping("/search")
|
||||||
public Page<KnowledgeBaseItem> search(String kbUuid, String keyword, @NotNull @Min(1) Integer currentPage, @NotNull @Min(10) Integer pageSize) {
|
public Page<KbItemDto> search(String kbUuid, String keyword, @NotNull @Min(1) Integer currentPage, @NotNull @Min(10) Integer pageSize) {
|
||||||
return knowledgeBaseItemService.search(kbUuid, keyword, currentPage, pageSize);
|
return knowledgeBaseItemService.search(kbUuid, keyword, currentPage, pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ public class ResponseWrapper implements ResponseBodyAdvice<Object> {
|
||||||
return result;
|
return result;
|
||||||
} else if (result instanceof String) {
|
} else if (result instanceof String) {
|
||||||
return JsonUtil.toJson(new BaseResponse(true, result));
|
return JsonUtil.toJson(new BaseResponse(true, result));
|
||||||
|
} else if (result instanceof org.springframework.core.io.Resource) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
log.info("result:" + result);
|
log.info("result:" + result);
|
||||||
return new BaseResponse(true, result);
|
return new BaseResponse(true, result);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.moyz.adi.common.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class KbItemDto {
|
||||||
|
|
||||||
|
private Long kbId;
|
||||||
|
|
||||||
|
private String kbUuid;
|
||||||
|
|
||||||
|
private Long sourceFileId;
|
||||||
|
|
||||||
|
private String uuid;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String brief;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
private Boolean isEmbedded;
|
||||||
|
|
||||||
|
private String sourceFileName;
|
||||||
|
|
||||||
|
private String sourceFileUuid;
|
||||||
|
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
|
@ -1,9 +1,16 @@
|
||||||
package com.moyz.adi.common.mapper;
|
package com.moyz.adi.common.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.moyz.adi.common.dto.KbItemDto;
|
||||||
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface KnowledgeBaseItemMapper extends BaseMapper<KnowledgeBaseItem> {
|
public interface KnowledgeBaseItemMapper extends BaseMapper<KnowledgeBaseItem> {
|
||||||
|
|
||||||
|
@InterceptorIgnore(tenantLine = "true")
|
||||||
|
Page<KbItemDto> searchByKb(Page<KbItemDto> page, @Param("kbUuid") String kbUuid, @Param("keyword") String keyword);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
@ -49,9 +48,6 @@ public class AiImageService extends ServiceImpl<AiImageMapper, AiImage> {
|
||||||
@Resource
|
@Resource
|
||||||
private QuotaHelper quotaHelper;
|
private QuotaHelper quotaHelper;
|
||||||
|
|
||||||
@Value("${local.images}")
|
|
||||||
private String localImagesPath;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RateLimitHelper rateLimitHelper;
|
private RateLimitHelper rateLimitHelper;
|
||||||
|
|
||||||
|
@ -180,7 +176,7 @@ public class AiImageService extends ServiceImpl<AiImageMapper, AiImage> {
|
||||||
}
|
}
|
||||||
List<String> imageUuids = new ArrayList();
|
List<String> imageUuids = new ArrayList();
|
||||||
images.forEach(imageUrl -> {
|
images.forEach(imageUrl -> {
|
||||||
String imageUuid = fileService.saveToLocal(user, imageUrl);
|
String imageUuid = fileService.saveImageToLocal(user, imageUrl);
|
||||||
imageUuids.add(imageUuid);
|
imageUuids.add(imageUuid);
|
||||||
});
|
});
|
||||||
String imageUuidsJoin = imageUuids.stream().collect(Collectors.joining(","));
|
String imageUuidsJoin = imageUuids.stream().collect(Collectors.joining(","));
|
||||||
|
|
|
@ -50,6 +50,7 @@ public class FileService extends ServiceImpl<FileMapper, AdiFile> {
|
||||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||||
Pair<String, String> originalFile = FileUtil.saveToLocal(file, imagePath, uuid);
|
Pair<String, String> originalFile = FileUtil.saveToLocal(file, imagePath, uuid);
|
||||||
AdiFile adiFile = new AdiFile();
|
AdiFile adiFile = new AdiFile();
|
||||||
|
adiFile.setName(file.getOriginalFilename());
|
||||||
adiFile.setUuid(uuid);
|
adiFile.setUuid(uuid);
|
||||||
adiFile.setMd5(md5);
|
adiFile.setMd5(md5);
|
||||||
adiFile.setPath(originalFile.getLeft());
|
adiFile.setPath(originalFile.getLeft());
|
||||||
|
@ -59,7 +60,7 @@ public class FileService extends ServiceImpl<FileMapper, AdiFile> {
|
||||||
return adiFile;
|
return adiFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String saveToLocal(User user, String sourceImageUrl) {
|
public String saveImageToLocal(User user, String sourceImageUrl) {
|
||||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||||
String localPath = imagePath + uuid + ".png";
|
String localPath = imagePath + uuid + ".png";
|
||||||
File target = new File(localPath);
|
File target = new File(localPath);
|
||||||
|
@ -71,10 +72,12 @@ public class FileService extends ServiceImpl<FileMapper, AdiFile> {
|
||||||
throw new BaseException(B_SAVE_IMAGE_ERROR);
|
throw new BaseException(B_SAVE_IMAGE_ERROR);
|
||||||
}
|
}
|
||||||
AdiFile adiFile = new AdiFile();
|
AdiFile adiFile = new AdiFile();
|
||||||
|
adiFile.setName(target.getName());
|
||||||
adiFile.setUuid(uuid);
|
adiFile.setUuid(uuid);
|
||||||
adiFile.setMd5(MD5Utils.calculateMD5(localPath));
|
adiFile.setMd5(MD5Utils.calculateMD5(localPath));
|
||||||
adiFile.setPath(localPath);
|
adiFile.setPath(localPath);
|
||||||
adiFile.setUserId(user.getId());
|
adiFile.setUserId(user.getId());
|
||||||
|
adiFile.setExt("png");
|
||||||
this.getBaseMapper().insert(adiFile);
|
this.getBaseMapper().insert(adiFile);
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +106,20 @@ public class FileService extends ServiceImpl<FileMapper, AdiFile> {
|
||||||
return this.softDel(uuid);
|
return this.softDel(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AdiFile getByUuid(String uuid) {
|
||||||
|
return this.lambdaQuery()
|
||||||
|
.eq(AdiFile::getUuid, uuid)
|
||||||
|
.eq(AdiFile::getUserId, ThreadContext.getCurrentUserId())
|
||||||
|
.oneOpt().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] readBytes(AdiFile adiFile) {
|
||||||
|
if (null == adiFile) {
|
||||||
|
throw new BaseException(A_FILE_NOT_EXIST);
|
||||||
|
}
|
||||||
|
return FileUtil.readBytes(adiFile.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] readBytes(String uuid) {
|
public byte[] readBytes(String uuid) {
|
||||||
AdiFile adiFile = this.lambdaQuery()
|
AdiFile adiFile = this.lambdaQuery()
|
||||||
.eq(AdiFile::getUuid, uuid)
|
.eq(AdiFile::getUuid, uuid)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package com.moyz.adi.common.service;
|
package com.moyz.adi.common.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
|
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
|
||||||
import com.moyz.adi.common.base.ThreadContext;
|
import com.moyz.adi.common.base.ThreadContext;
|
||||||
import com.moyz.adi.common.cosntant.AdiConstant;
|
import com.moyz.adi.common.cosntant.AdiConstant;
|
||||||
|
import com.moyz.adi.common.dto.KbItemDto;
|
||||||
import com.moyz.adi.common.dto.KbItemEditReq;
|
import com.moyz.adi.common.dto.KbItemEditReq;
|
||||||
import com.moyz.adi.common.entity.KnowledgeBase;
|
import com.moyz.adi.common.entity.KnowledgeBase;
|
||||||
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
import com.moyz.adi.common.entity.KnowledgeBaseItem;
|
||||||
|
@ -25,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static com.moyz.adi.common.cosntant.AdiConstant.RAG_TYPE_KB;
|
|
||||||
import static com.moyz.adi.common.enums.ErrorEnum.*;
|
import static com.moyz.adi.common.enums.ErrorEnum.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -74,15 +73,8 @@ public class KnowledgeBaseItemService extends ServiceImpl<KnowledgeBaseItemMappe
|
||||||
.one();
|
.one();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page<KnowledgeBaseItem> search(String kbUuid, String keyword, Integer currentPage, Integer pageSize) {
|
public Page<KbItemDto> search(String kbUuid, String keyword, Integer currentPage, Integer pageSize) {
|
||||||
LambdaQueryChainWrapper<KnowledgeBaseItem> wrapper = ChainWrappers.lambdaQueryChain(baseMapper);
|
return baseMapper.searchByKb(new Page<>(currentPage, pageSize), kbUuid, keyword);
|
||||||
wrapper.select(KnowledgeBaseItem::getId, KnowledgeBaseItem::getUuid, KnowledgeBaseItem::getTitle, KnowledgeBaseItem::getBrief, KnowledgeBaseItem::getKbUuid, KnowledgeBaseItem::getIsEmbedded, KnowledgeBaseItem::getCreateTime, KnowledgeBaseItem::getUpdateTime);
|
|
||||||
wrapper.eq(KnowledgeBaseItem::getIsDeleted, false);
|
|
||||||
wrapper.eq(KnowledgeBaseItem::getKbUuid, kbUuid);
|
|
||||||
if (StringUtils.isNotBlank(keyword)) {
|
|
||||||
wrapper.eq(KnowledgeBaseItem::getTitle, keyword);
|
|
||||||
}
|
|
||||||
return wrapper.page(new Page<>(currentPage, pageSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkAndEmbedding(String[] uuids) {
|
public boolean checkAndEmbedding(String[] uuids) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
|
||||||
import static com.moyz.adi.common.enums.ErrorEnum.A_FILE_NOT_EXIST;
|
import static com.moyz.adi.common.enums.ErrorEnum.A_FILE_NOT_EXIST;
|
||||||
|
|
||||||
|
@ -37,6 +38,9 @@ public class FileUtil {
|
||||||
public static byte[] readBytes(String localPath) {
|
public static byte[] readBytes(String localPath) {
|
||||||
try {
|
try {
|
||||||
return FileUtils.readFileToByteArray(new File(localPath));
|
return FileUtils.readFileToByteArray(new File(localPath));
|
||||||
|
} catch (NoSuchFileException noSuchFileException) {
|
||||||
|
log.error("file not found", noSuchFileException);
|
||||||
|
throw new BaseException(A_FILE_NOT_EXIST);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.moyz.adi.common.mapper.KnowledgeBaseItemMapper">
|
||||||
|
|
||||||
|
<select id="searchByKb" parameterType="Map" resultType="com.moyz.adi.common.dto.KbItemDto">
|
||||||
|
select a.*, b.name source_file_name, b.uuid source_file_uuid
|
||||||
|
from adi_knowledge_base_item a
|
||||||
|
left join adi_file b on a.source_file_id = b.id
|
||||||
|
where a.is_deleted = false
|
||||||
|
and a.kb_uuid = #{kbUuid}
|
||||||
|
<if test="keyword!='' and keyword!=null">
|
||||||
|
and a.title like CONCAT('%', #{keyword}, '%')
|
||||||
|
</if>
|
||||||
|
order by create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
Loading…
Reference in New Issue