| | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import java.util.stream.Collectors; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.ruoyi.chain.loader.ResourceLoader; |
| | | import org.ruoyi.chain.loader.ResourceLoaderFactory; |
| | | import org.ruoyi.common.core.domain.model.LoginUser; |
| | | import org.ruoyi.common.core.utils.MapstructUtils; |
| | | import org.ruoyi.common.core.utils.StringUtils; |
| | | import org.ruoyi.common.satoken.utils.LoginHelper; |
| | | import org.ruoyi.constant.DealStatus; |
| | | import org.ruoyi.constant.FileType; |
| | | import org.ruoyi.core.page.PageQuery; |
| | | import org.ruoyi.core.page.TableDataInfo; |
| | | import org.ruoyi.domain.ChatModel; |
| | | import org.ruoyi.domain.KnowledgeAttach; |
| | | import org.ruoyi.domain.KnowledgeAttachPic; |
| | | import org.ruoyi.domain.KnowledgeFragment; |
| | | import org.ruoyi.domain.KnowledgeInfo; |
| | | import org.ruoyi.domain.PdfFileContentResult; |
| | | import org.ruoyi.domain.bo.KnowledgeInfoBo; |
| | | import org.ruoyi.domain.bo.KnowledgeInfoUploadBo; |
| | | import org.ruoyi.domain.bo.StoreEmbeddingBo; |
| | |
| | | import org.ruoyi.domain.vo.KnowledgeAttachVo; |
| | | import org.ruoyi.domain.vo.KnowledgeInfoVo; |
| | | import org.ruoyi.mapper.KnowledgeAttachMapper; |
| | | import org.ruoyi.mapper.KnowledgeAttachPicMapper; |
| | | import org.ruoyi.mapper.KnowledgeFragmentMapper; |
| | | import org.ruoyi.mapper.KnowledgeInfoMapper; |
| | | import org.ruoyi.service.IChatModelService; |
| | | import org.ruoyi.service.PdfImageExtractService; |
| | | import org.ruoyi.service.VectorStoreService; |
| | | import org.ruoyi.service.IKnowledgeInfoService; |
| | | import org.ruoyi.service.impl.PdfImageExtractServiceImpl; |
| | | import org.ruoyi.system.domain.vo.SysOssVo; |
| | | import org.ruoyi.utils.ZipUtils; |
| | | import org.ruoyi.service.VectorStoreService; |
| | | import org.ruoyi.system.service.ISysOssService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.scheduling.annotation.Async; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | import org.ruoyi.system.service.ISysOssService; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | |
| | | /** |
| | |
| | | public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(KnowledgeInfoServiceImpl.class); |
| | | |
| | | private final KnowledgeInfoMapper baseMapper; |
| | | |
| | | private final VectorStoreService vectorStoreService; |
| | |
| | | private final IChatModelService chatModelService; |
| | | |
| | | private final ISysOssService ossService; |
| | | |
| | | // private final PdfImageExtractService pdfImageExtractService; |
| | | |
| | | private final KnowledgeAttachPicMapper picMapper; |
| | | |
| | | private final DealFileService dealFileService; |
| | | |
| | | @Value("${pdf.extract.service.url}") |
| | | private String serviceUrl; |
| | | @Value("${pdf.extract.ai-api.url}") |
| | | private String aiApiUrl; |
| | | @Value("${pdf.extract.ai-api.key}") |
| | | private String aiApiKey; |
| | | |
| | | /** |
| | | * æ¥è¯¢ç¥è¯åº |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void removeKnowledge(String id) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("kid", id); |
| | | Map<String,Object> map = new HashMap<>(); |
| | | map.put("kid",id); |
| | | List<KnowledgeInfoVo> knowledgeInfoList = baseMapper.selectVoByMap(map); |
| | | check(knowledgeInfoList); |
| | | // å é¤åéåºä¿¡æ¯ |
| | | knowledgeInfoList.forEach(knowledgeInfoVo -> { |
| | | vectorStoreService.removeByKid(String.valueOf(knowledgeInfoVo.getId()), |
| | | knowledgeInfoVo.getVectorModelName()); |
| | | }); |
| | | // knowledgeInfoList.forEach(knowledgeInfoVo -> { |
| | | // vectorStoreService.removeByKid(String.valueOf(knowledgeInfoVo.getId()),knowledgeInfoVo.getVectorModelName()); |
| | | // }); |
| | | // å é¤éä»¶åç¥è¯ç段 |
| | | fragmentMapper.deleteByMap(map); |
| | | List<KnowledgeAttachVo> knowledgeAttachVos = attachMapper.selectVoByMap(map); |
| | | if (ObjectUtil.isNotEmpty(knowledgeAttachVos)) { |
| | | Collection<Long> ossIds = knowledgeAttachVos.stream() |
| | | .map(KnowledgeAttachVo::getOssId) |
| | | .collect(Collectors.toList()); |
| | | //å é¤oss |
| | | ossService.deleteWithValidByIds(ossIds, false); |
| | | |
| | | //å é¤å¾çoss |
| | | List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList( |
| | | new LambdaQueryWrapper<KnowledgeAttachPic>() |
| | | .in(KnowledgeAttachPic::getKid, |
| | | knowledgeAttachVos.stream().map(KnowledgeAttachVo::getKid) |
| | | .collect(Collectors.toList())) |
| | | .in(KnowledgeAttachPic::getAid, |
| | | knowledgeAttachVos.stream().map(KnowledgeAttachVo::getId) |
| | | .collect(Collectors.toList())) |
| | | ); |
| | | if (ObjectUtil.isNotEmpty(knowledgeAttachPics)) { |
| | | Collection<Long> tossIds = knowledgeAttachPics.stream() |
| | | .map(KnowledgeAttachPic::getOssId) |
| | | .collect(Collectors.toList()); |
| | | ossService.deleteWithValidByIds(tossIds, false); |
| | | List<Long> collect = knowledgeAttachPics.stream().map(KnowledgeAttachPic::getId) |
| | | .collect(Collectors.toList()); |
| | | picMapper.deleteByIds(collect); |
| | | } |
| | | } |
| | | attachMapper.deleteByMap(map); |
| | | // å é¤ç¥è¯åº |
| | | baseMapper.deleteByMap(map); |
| | |
| | | } |
| | | |
| | | public void storeContent(MultipartFile file, String kid) { |
| | | if (file == null || file.isEmpty()) { |
| | | throw new IllegalArgumentException("File cannot be null or empty"); |
| | | } |
| | | |
| | | SysOssVo uploadDto = null; |
| | | String fileName = file.getOriginalFilename(); |
| | | List<String> chunkList = new ArrayList<>(); |
| | | KnowledgeAttach knowledgeAttach = new KnowledgeAttach(); |
| | |
| | | String docId = RandomUtil.randomString(10); |
| | | knowledgeAttach.setDocId(docId); |
| | | knowledgeAttach.setDocName(fileName); |
| | | knowledgeAttach.setDocType(fileName.substring(fileName.lastIndexOf(".") + 1)); |
| | | knowledgeAttach.setDocType(fileName.substring(fileName.lastIndexOf(".")+1)); |
| | | String content = ""; |
| | | ResourceLoader resourceLoader = resourceLoaderFactory.getLoaderByFileType( |
| | | knowledgeAttach.getDocType()); |
| | | ResourceLoader resourceLoader = resourceLoaderFactory.getLoaderByFileType(knowledgeAttach.getDocType()); |
| | | List<String> fids = new ArrayList<>(); |
| | | try { |
| | | content = resourceLoader.getContent(file.getInputStream()); |
| | | chunkList = resourceLoader.getChunkList(content, kid); |
| | | List<KnowledgeFragment> knowledgeFragmentList = new ArrayList<>(); |
| | | if (CollUtil.isNotEmpty(chunkList)) { |
| | | // Upload file to OSS |
| | | uploadDto = ossService.upload(file); |
| | | for (int i = 0; i < chunkList.size(); i++) { |
| | | String fid = RandomUtil.randomString(10); |
| | | fids.add(fid); |
| | |
| | | } |
| | | knowledgeAttach.setContent(content); |
| | | knowledgeAttach.setCreateTime(new Date()); |
| | | if (ObjectUtil.isNotEmpty(uploadDto) && ObjectUtil.isNotEmpty(uploadDto.getOssId())) { |
| | | knowledgeAttach.setOssId(uploadDto.getOssId()); |
| | | //åªæpdfæä»¶ æéè¦æè§£å¾çååæå¾çå
容 |
| | | if (FileType.PDF.equals(knowledgeAttach.getDocType())) { |
| | | knowledgeAttach.setPicStatus(DealStatus.STATUS_10); |
| | | knowledgeAttach.setPicAnysStatus(DealStatus.STATUS_10); |
| | | } else { |
| | | knowledgeAttach.setPicStatus(DealStatus.STATUS_30); |
| | | knowledgeAttach.setPicAnysStatus(DealStatus.STATUS_30); |
| | | } |
| | | //æææä»¶ä¸ä¼ åï¼é½éè¦åæ¥å°åéæ°æ®åº |
| | | knowledgeAttach.setVectorStatus(DealStatus.STATUS_10); |
| | | } |
| | | attachMapper.insert(knowledgeAttach); |
| | | |
| | | // éè¿kidæ¥è¯¢ç¥è¯åºä¿¡æ¯ |
| | | KnowledgeInfoVo knowledgeInfoVo = baseMapper.selectVoOne(Wrappers.<KnowledgeInfo>lambdaQuery() |
| | | .eq(KnowledgeInfo::getId, kid)); |
| | | |
| | | // éè¿å鿍¡åæ¥è¯¢æ¨¡åä¿¡æ¯ |
| | | ChatModelVo chatModelVo = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName()); |
| | | |
| | | StoreEmbeddingBo storeEmbeddingBo = new StoreEmbeddingBo(); |
| | | storeEmbeddingBo.setKid(kid); |
| | | storeEmbeddingBo.setDocId(docId); |
| | | storeEmbeddingBo.setFids(fids); |
| | | storeEmbeddingBo.setChunkList(chunkList); |
| | | storeEmbeddingBo.setVectorModelName(knowledgeInfoVo.getVectorModelName()); |
| | | storeEmbeddingBo.setEmbeddingModelName(knowledgeInfoVo.getEmbeddingModelName()); |
| | | storeEmbeddingBo.setApiKey(chatModelVo.getApiKey()); |
| | | storeEmbeddingBo.setBaseUrl(chatModelVo.getApiHost()); |
| | | vectorStoreService.storeEmbeddings(storeEmbeddingBo); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¥ 宿¶ æè§£PDFæä»¶ä¸çå¾ç |
| | | */ |
| | | //@Scheduled(fixedDelay = 15000) // æ¯3ç§æ§è¡ä¸æ¬¡ |
| | | public void dealKnowledgeAttachPic() throws Exception { |
| | | //å¤ç æè§£PDFæä»¶ä¸çå¾ççè®°å½ |
| | | List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( |
| | | new LambdaQueryWrapper<KnowledgeAttach>() |
| | | .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_10) |
| | | .eq(KnowledgeAttach::getPicAnysStatus, DealStatus.STATUS_10) |
| | | .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_10) |
| | | ); |
| | | log.info("===============æè§£PDFæä»¶ä¸çå¾ç size = {}", knowledgeAttaches.size()); |
| | | if (ObjectUtil.isNotEmpty(knowledgeAttaches)) { |
| | | for (KnowledgeAttach attachItem : knowledgeAttaches) { |
| | | dealFileService.dealPicStatus(attachItem); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ç¬¬äºæ¥ 宿¶ è§£æå¾çå
容 |
| | | */ |
| | | //@Scheduled(fixedDelay = 15000) |
| | | public void dealKnowledgeAttachPicAnys() throws Exception { |
| | | //è·åæªå¤ççå¾çè®°å½ |
| | | List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList( |
| | | new LambdaQueryWrapper<KnowledgeAttachPic>() |
| | | .eq(KnowledgeAttachPic::getPicAnysStatus, DealStatus.STATUS_10) |
| | | .last("LIMIT 20") |
| | | ); |
| | | if (ObjectUtil.isNotEmpty(knowledgeAttachPics)) { |
| | | for (KnowledgeAttachPic picItem : knowledgeAttachPics) { |
| | | dealFileService.dealPicAnysStatus(picItem); |
| | | } |
| | | } |
| | | } |
| | | /** |
| | | * ç¬¬ä¸æ¥ 宿¶ å¤ç éä»¶ä¸ä¼ åä¸ä¼ åéæ°æ®åº |
| | | */ |
| | | //@Scheduled(fixedDelay = 30000) // æ¯3ç§æ§è¡ä¸æ¬¡ |
| | | public void dealKnowledgeAttachVector() throws Exception { |
| | | //å¤ç éè¦ä¸ä¼ åéæ°æ®åºçè®°å½ |
| | | List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( |
| | | new LambdaQueryWrapper<KnowledgeAttach>() |
| | | .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_30) |
| | | .eq(KnowledgeAttach::getPicAnysStatus, DealStatus.STATUS_30) |
| | | .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_10) |
| | | ); |
| | | log.info("===============ä¸ä¼ åéæ°æ®åº size = {}", knowledgeAttaches.size()); |
| | | if (ObjectUtil.isNotEmpty(knowledgeAttaches)) { |
| | | for (KnowledgeAttach attachItem : knowledgeAttaches) { |
| | | dealFileService.dealVectorStatus(attachItem); |
| | | } |
| | | } |
| | | } |
| | | /** |
| | | * ç¬¬åæ¥ 宿¶ å¤ç å¤±è´¥æ°æ® |
| | | */ |
| | | //@Scheduled(fixedDelay = 30 * 60 * 1000) |
| | | public void dealKnowledge40Status() throws Exception { |
| | | //æè§£PDF失败 éæ°è®¾ç½®ç¶æ |
| | | attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() |
| | | .set(KnowledgeAttach::getPicStatus, DealStatus.STATUS_10) |
| | | .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_40)); |
| | | //å°å¾çåæå¤±è´¥çæ°æ® éæ°è®¾ç½®ç¶æ |
| | | picMapper.update(new LambdaUpdateWrapper<KnowledgeAttachPic>() |
| | | .set(KnowledgeAttachPic::getPicAnysStatus, DealStatus.STATUS_10) |
| | | .eq(KnowledgeAttachPic::getPicAnysStatus, DealStatus.STATUS_40)); |
| | | //ä¸ä¼ åéåºå¤±è´¥ éæ°è®¾ç½®ç¶æ |
| | | attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() |
| | | .set(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_10) |
| | | .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_40)); |
| | | } |
| | | @Scheduled(fixedDelay = 180000) // 3åéæ§è¡ä¸æ¬¡ |
| | | } |