README.md
@@ -34,6 +34,23 @@ <a href="https://github.com/ageerle/ruoyi-ai/issues">æåºæ°ç¹æ§</a> </p> ## å¿«éå¯å¨ 1. **å é项ç®** ```bash git clone https://github.com/alanpeng/ruoyi-ai-docker-deploy cd ruoyi-ai-docker-deploy ``` 2. **å¯å¨å ¨å¥åºç¨** ```bash docker-compose up -d ``` 3. **访é®åºç¨çé¢** - ç¨æ·çé¢ï¼`http://your-server-ip:8081` - 管çåçé¢ï¼`http://your-server-ip:8082` ## ç®å½ - [ç³»ç»ä½éª](#ç³»ç»ä½éª) ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java
@@ -1,5 +1,6 @@ package org.ruoyi.domain; import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import lombok.EqualsAndHashCode; @@ -78,14 +79,19 @@ private Long textBlockSize; /** * åéåº * åéåºæ¨¡ååç§° */ private String vector; private String vectorModelName; /** * å鿍¡å * åé忍¡ååç§° */ private String vectorModel; private String embeddingModelName; /** * ç³»ç»æç¤ºè¯ */ private String systemPrompt; /** * 夿³¨ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java
@@ -83,16 +83,22 @@ private Long textBlockSize; /** * åéåº * åéåºæ¨¡ååç§° */ @NotBlank(message = "åéåºä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private String vector; private String vectorModelName; /** * å鿍¡å * åé忍¡ååç§° */ @NotBlank(message = "å鿍¡åä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private String vectorModel; private String embeddingModelName; /** * ç³»ç»æç¤ºè¯ */ private String systemPrompt; /** * 夿³¨ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/QueryVectorBo.java
@@ -26,9 +26,14 @@ private Integer maxResults; /** * 模ååç§° * åéåºæ¨¡ååç§° */ private String modelName; private String vectorModelName; /** * åé忍¡ååç§° */ private String embeddingModelName; /** * 请æ±key ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/StoreEmbeddingBo.java
@@ -32,9 +32,14 @@ private List<String> fids; /** * 模ååç§° * åéåºæ¨¡ååç§° */ private String modelName; private String vectorModelName; /** * åé忍¡ååç§° */ private String embeddingModelName; /** * 请æ±key ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java
@@ -98,16 +98,20 @@ private Integer textBlockSize; /** * åéåº * åéåºæ¨¡ååç§° */ @ExcelProperty(value = "åéåº") private String vector; private String vectorModelName; /** * å鿍¡å * åé忍¡ååç§° */ @ExcelProperty(value = "å鿍¡å") private String vectorModel; private String embeddingModelName; /** * ç³»ç»æç¤ºè¯ */ private String systemPrompt; /** * 夿³¨ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/VectorStoreService.java
@@ -13,14 +13,14 @@ void storeEmbeddings(StoreEmbeddingBo storeEmbeddingBo); void removeByDocId(String kid,String docId); void removeByKid(String kid); List<String> getQueryVector(QueryVectorBo queryVectorBo); void createSchema(String kid,String modelName); void removeByKidAndFid(String kid, String fid); void removeByKid(String kid,String modelName); void removeByDocId(String kid,String docId,String modelName); void removeByKidAndFid(String kid, String fid,String modelName); } ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/VectorStoreServiceImpl.java
@@ -1,5 +1,7 @@ package org.ruoyi.service.impl; import cn.hutool.core.util.RandomUtil; import com.google.protobuf.ServiceException; import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; @@ -16,6 +18,7 @@ import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore; import dev.langchain4j.store.embedding.weaviate.WeaviateEmbeddingStore; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.ruoyi.common.core.service.ConfigService; import org.ruoyi.domain.bo.QueryVectorBo; @@ -40,11 +43,10 @@ private final ConfigService configService; Map<String,EmbeddingStore<TextSegment>> storeMap = new HashMap<>(); private EmbeddingStore<TextSegment> embeddingStore; @Override public void createSchema(String kid,String modelName) { EmbeddingStore<TextSegment> embeddingStore; switch (modelName) { case "weaviate" -> { String protocol = configService.getConfigValue("weaviate", "protocol"); @@ -84,88 +86,83 @@ embeddingStore = new InMemoryEmbeddingStore<>(); } } storeMap.put(kid,embeddingStore); } @Override public void storeEmbeddings(StoreEmbeddingBo storeEmbeddingBo) { EmbeddingStore<TextSegment> store = storeMap.get(storeEmbeddingBo.getKid()); EmbeddingModel embeddingModel = getEmbeddingModel(storeEmbeddingBo.getModelName(), createSchema(storeEmbeddingBo.getKid(),storeEmbeddingBo.getVectorModelName()); EmbeddingModel embeddingModel = getEmbeddingModel(storeEmbeddingBo.getEmbeddingModelName(), storeEmbeddingBo.getApiKey(), storeEmbeddingBo.getBaseUrl()); for (int i = 0; i < storeEmbeddingBo.getChunkList().size(); i++) { List<String> chunkList = storeEmbeddingBo.getChunkList(); for (int i = 0; i < chunkList.size(); i++) { Map<String, Object> dataSchema = new HashMap<>(); dataSchema.put("kid", storeEmbeddingBo.getKid()); dataSchema.put("docId", storeEmbeddingBo.getKid()); dataSchema.put("fid", storeEmbeddingBo.getFids().get(i)); Response<Embedding> response = embeddingModel.embed(storeEmbeddingBo.getChunkList().get(i)); Embedding embedding = response.content(); TextSegment segment = TextSegment.from(storeEmbeddingBo.getChunkList().get(i)); Embedding embedding = embeddingModel.embed(chunkList.get(i)).content(); TextSegment segment = TextSegment.from(chunkList.get(i)); segment.metadata().putAll(dataSchema); store.add(embedding,segment); embeddingStore.add(embedding,segment); } } @Override public List<String> getQueryVector(QueryVectorBo queryVectorBo) { EmbeddingStore<TextSegment> store = storeMap.get(queryVectorBo.getKid()); EmbeddingModel embeddingModel = getEmbeddingModel(queryVectorBo.getModelName(), createSchema(queryVectorBo.getKid(),queryVectorBo.getVectorModelName()); EmbeddingModel embeddingModel = getEmbeddingModel(queryVectorBo.getEmbeddingModelName(), queryVectorBo.getApiKey(), queryVectorBo.getBaseUrl()); Filter simpleFilter = new IsEqualTo("kid", queryVectorBo.getKid()); // Filter simpleFilter = new IsEqualTo("kid", queryVectorBo.getKid()); Embedding queryEmbedding = embeddingModel.embed(queryVectorBo.getQuery()).content(); EmbeddingSearchRequest embeddingSearchRequest = EmbeddingSearchRequest.builder() .queryEmbedding(queryEmbedding) .maxResults(queryVectorBo.getMaxResults()) // æ·»å è¿æ»¤æ¡ä»¶ .filter(simpleFilter) // .filter(simpleFilter) .build(); List<EmbeddingMatch<TextSegment>> matches = store.search(embeddingSearchRequest).matches(); List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(embeddingSearchRequest).matches(); List<String> results = new ArrayList<>(); matches.forEach(embeddingMatch -> results.add(embeddingMatch.embedded().text())); return results; } @Override public void removeByKid(String kid) { EmbeddingStore<TextSegment> store = storeMap.get(kid); public void removeByKid(String kid,String modelName) { createSchema(kid,modelName); // æ ¹æ®æ¡ä»¶å é¤åéæ°æ® Filter simpleFilter = new IsEqualTo("kid", kid); store.removeAll(simpleFilter); embeddingStore.removeAll(simpleFilter); } @Override public void removeByDocId(String kid, String docId) { EmbeddingStore<TextSegment> store = storeMap.get(kid); public void removeByDocId(String kid, String docId,String modelName) { createSchema(kid,modelName); // æ ¹æ®æ¡ä»¶å é¤åéæ°æ® Filter simpleFilterByDocId = new IsEqualTo("docId", docId); store.removeAll(simpleFilterByDocId); embeddingStore.removeAll(simpleFilterByDocId); } @Override public void removeByKidAndFid(String kid, String fid) { EmbeddingStore<TextSegment> store = storeMap.get(kid); public void removeByKidAndFid(String kid, String fid,String modelName) { createSchema(kid,modelName); // æ ¹æ®æ¡ä»¶å é¤åéæ°æ® Filter simpleFilterByKid = new IsEqualTo("kid", kid); Filter simpleFilterFid = new IsEqualTo("fid", fid); Filter simpleFilterByAnd = Filter.and(simpleFilterFid, simpleFilterByKid); store.removeAll(simpleFilterByAnd); embeddingStore.removeAll(simpleFilterByAnd); } /** * è·åå鿍¡å */ @SneakyThrows public EmbeddingModel getEmbeddingModel(String modelName,String apiKey,String baseUrl) { EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().build(); EmbeddingModel embeddingModel; if(TEXT_EMBEDDING_3_SMALL.toString().equals(modelName)) { embeddingModel = OpenAiEmbeddingModel.builder() .apiKey(apiKey) .baseUrl(baseUrl) .modelName(TEXT_EMBEDDING_3_SMALL) .modelName(modelName) .build(); // TODO æ·»å æä¸¾ }else if("quentinz/bge-large-zh-v1.5".equals(modelName)) { @@ -173,6 +170,14 @@ .baseUrl(baseUrl) .modelName(modelName) .build(); }else if("baai/bge-m3".equals(modelName)) { embeddingModel = OpenAiEmbeddingModel.builder() .apiKey(apiKey) .baseUrl(baseUrl) .modelName(modelName) .build(); }else { throw new ServiceException("æªæ¾å°å¯¹åºåé忍¡å!"); } return embeddingModel; } ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -2,6 +2,7 @@ import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.google.protobuf.ServiceException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; @@ -29,6 +30,8 @@ import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.bo.QueryVectorBo; import org.ruoyi.domain.vo.ChatModelVo; import org.ruoyi.domain.vo.KnowledgeInfoVo; import org.ruoyi.service.IKnowledgeInfoService; import org.ruoyi.service.VectorStoreService; import org.ruoyi.service.IChatModelService; import org.ruoyi.service.IChatSessionService; @@ -66,6 +69,8 @@ private final ChatServiceFactory chatServiceFactory; private final IChatSessionService chatSessionService; private final IKnowledgeInfoService knowledgeInfoService; private ChatModelVo chatModelVo; @@ -148,50 +153,61 @@ } } /** * æå»ºæ¶æ¯å表 */ private void buildChatMessageList(ChatRequest chatRequest){ String sysPrompt; chatModelVo = chatModelService.selectModelByName(chatRequest.getModel()); // è·åå¯¹è¯æ¶æ¯å表 List<Message> messages = chatRequest.getMessages(); String sysPrompt = chatModelVo.getSystemPrompt(); // æ¥è¯¢åéåºç¸å ³ä¿¡æ¯å å ¥å°ä¸ä¸æ if(StringUtils.isNotEmpty(chatRequest.getKid())){ List<Message> knMessages = new ArrayList<>(); String content = messages.get(messages.size() - 1).getContent().toString(); // éè¿kidæ¥è¯¢ç¥è¯åºä¿¡æ¯ KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid())); // æ¥è¯¢å鿍¡åé ç½®ä¿¡æ¯ ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName()); QueryVectorBo queryVectorBo = new QueryVectorBo(); queryVectorBo.setQuery(content); queryVectorBo.setKid(chatRequest.getKid()); queryVectorBo.setApiKey(chatModel.getApiKey()); queryVectorBo.setBaseUrl(chatModel.getApiHost()); queryVectorBo.setVectorModelName(knowledgeInfoVo.getVectorModelName()); queryVectorBo.setEmbeddingModelName(knowledgeInfoVo.getEmbeddingModelName()); queryVectorBo.setMaxResults(knowledgeInfoVo.getRetrieveLimit()); List<String> nearestList = vectorStoreService.getQueryVector(queryVectorBo); for (String prompt : nearestList) { Message userMessage = Message.builder().content(prompt).role(Message.Role.USER).build(); knMessages.add(userMessage); } messages.addAll(knMessages); // 设置ç¥è¯åºç³»ç»æç¤ºè¯ sysPrompt = knowledgeInfoVo.getSystemPrompt(); if(StringUtils.isEmpty(sysPrompt)){ // TODO ç³»ç»é»è®¤æç¤ºè¯,åç»ä¼å¢å æç¤ºè¯ç®¡ç sysPrompt ="###è§è²è®¾å®\n" + "ä½ æ¯ä¸ä¸ªæºè½ç¥è¯å©æï¼ä¸æ³¨äºå©ç¨ä¸ä¸æä¸çä¿¡æ¯æ¥æä¾åç¡®åç¸å ³çåçã\n" + "###æä»¤\n" + "å½ç¨æ·çé®é¢ä¸ä¸ä¸æç¥è¯å¹é æ¶ï¼å©ç¨ä¸ä¸æä¿¡æ¯è¿è¡åçã妿é®é¢ä¸ä¸ä¸æä¸å¹é ï¼è¿ç¨èªèº«çæ¨çè½åçæåéçåçã\n" + "###éå¶\n" + "ç¡®ä¿åçæ¸ æ°ç®æ´ï¼é¿å æä¾ä¸å¿ è¦çç»èãå§ç»ä¿æè¯æ°å好" + "å½åæ¶é´ï¼"+ DateUtils.getDate(); } }else { sysPrompt = chatModelVo.getSystemPrompt(); if(StringUtils.isEmpty(sysPrompt)){ sysPrompt ="ä½ æ¯ä¸ä¸ªç±RuoYI-AIå¼åç人工æºè½å©æï¼ååå«çç«å©æãä½ æ é¿ä¸è±æå¯¹è¯ï¼è½å¤ç解并å¤çåç§é®é¢ï¼æä¾å®å ¨ãæå¸®å©ãåç¡®çåçã" + "å½åæ¶é´ï¼"+ DateUtils.getDate()+ "#注æï¼åå¤ä¹å注æç»åä¸ä¸æåå·¥å ·è¿åå 容è¿è¡åå¤ã"; } } // 设置系ç»é»è®¤æç¤ºè¯ Message sysMessage = Message.builder().content(sysPrompt).role(Message.Role.SYSTEM).build(); messages.add(0,sysMessage); chatRequest.setSysPrompt(sysPrompt); // æ¥è¯¢åéåºç¸å ³ä¿¡æ¯å å ¥å°ä¸ä¸æ if(StringUtils.isNotEmpty(chatRequest.getKid())){ List<Message> knMessages = new ArrayList<>(); String content = messages.get(messages.size() - 1).getContent().toString(); QueryVectorBo queryVectorBo = new QueryVectorBo(); queryVectorBo.setQuery(content); queryVectorBo.setKid(chatRequest.getKid()); queryVectorBo.setApiKey(chatModelVo.getApiKey()); queryVectorBo.setBaseUrl(chatModelVo.getApiHost()); queryVectorBo.setModelName(chatModelVo.getModelName()); // TODO æ¥è¯¢åéè¿åæ¡æ°,è¿éåºè¯¥æ¥è¯¢ç¥è¯åºé ç½® queryVectorBo.setMaxResults(3); List<String> nearestList = vectorStoreService.getQueryVector(queryVectorBo); for (String prompt : nearestList) { Message userMessage = Message.builder().content(prompt).role(Message.Role.USER).build(); knMessages.add(userMessage); } // TODO æç¤ºè¯,è¿éåºè¯¥æ¥è¯¢ç¥è¯åºé ç½® Message userMessage = Message.builder().content(content + (!nearestList.isEmpty() ? "\n\n注æï¼åçé®é¢æ¶ï¼é¡»ä¸¥æ ¼æ ¹æ®æç»ä½ çç³»ç»ä¸ä¸æå 容åæè¿è¡åçï¼è¯·ä¸è¦èªå·±åæ¥,åçæ¶ä¿æåæ¥ææ¬çæ®µè½å±çº§" : "")).role(Message.Role.USER).build(); knMessages.add(userMessage); messages.addAll(knMessages); } // ç¨æ·å¯¹è¯å 容 String chatString = null; // è·åç¨æ·å¯¹è¯ä¿¡æ¯ ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java
@@ -1,14 +1,11 @@ package org.ruoyi.chat.service.knowledge; import cn.hutool.core.collection.CollUtil; 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 org.ruoyi.chain.loader.ResourceLoader; import org.ruoyi.chain.loader.ResourceLoaderFactory; @@ -16,8 +13,6 @@ 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; @@ -35,15 +30,11 @@ import org.ruoyi.service.IChatModelService; import org.ruoyi.service.VectorStoreService; import org.ruoyi.service.IKnowledgeInfoService; import org.ruoyi.system.domain.vo.SysOssVo; import org.ruoyi.system.service.ISysOssService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.springframework.scheduling.annotation.Async; import java.io.IOException; import java.util.*; @@ -70,8 +61,6 @@ private final KnowledgeAttachMapper attachMapper; private final IChatModelService chatModelService; private final ISysOssService ossService; /** * æ¥è¯¢ç¥è¯åº @@ -107,18 +96,12 @@ lqw.eq(bo.getUid() != null, KnowledgeInfo::getUid, bo.getUid()); lqw.like(StringUtils.isNotBlank(bo.getKname()), KnowledgeInfo::getKname, bo.getKname()); lqw.eq(bo.getShare() != null, KnowledgeInfo::getShare, bo.getShare()); lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription()); lqw.eq(StringUtils.isNotBlank(bo.getKnowledgeSeparator()), KnowledgeInfo::getKnowledgeSeparator, bo.getKnowledgeSeparator()); lqw.eq(StringUtils.isNotBlank(bo.getQuestionSeparator()), KnowledgeInfo::getQuestionSeparator, bo.getQuestionSeparator()); lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription()); lqw.eq(StringUtils.isNotBlank(bo.getKnowledgeSeparator()), KnowledgeInfo::getKnowledgeSeparator, bo.getKnowledgeSeparator()); lqw.eq(StringUtils.isNotBlank(bo.getQuestionSeparator()), KnowledgeInfo::getQuestionSeparator, bo.getQuestionSeparator()); lqw.eq(bo.getOverlapChar() != null, KnowledgeInfo::getOverlapChar, bo.getOverlapChar()); lqw.eq(bo.getRetrieveLimit() != null, KnowledgeInfo::getRetrieveLimit, bo.getRetrieveLimit()); lqw.eq(bo.getTextBlockSize() != null, KnowledgeInfo::getTextBlockSize, bo.getTextBlockSize()); lqw.eq(StringUtils.isNotBlank(bo.getVector()), KnowledgeInfo::getVector, bo.getVector()); lqw.eq(StringUtils.isNotBlank(bo.getVectorModel()), KnowledgeInfo::getVectorModel, bo.getVectorModel()); return lqw; } @@ -176,7 +159,7 @@ } baseMapper.insert(knowledgeInfo); if (knowledgeInfo != null) { vectorStoreService.createSchema(String.valueOf(knowledgeInfo.getId()), bo.getVector()); vectorStoreService.createSchema(String.valueOf(knowledgeInfo.getId()),bo.getVectorModelName()); } } else { baseMapper.updateById(knowledgeInfo); @@ -192,7 +175,7 @@ check(knowledgeInfoList); // å é¤åéåºä¿¡æ¯ knowledgeInfoList.forEach(knowledgeInfoVo -> { vectorStoreService.removeByKid(String.valueOf(knowledgeInfoVo.getId())); vectorStoreService.removeByKid(String.valueOf(knowledgeInfoVo.getId()),knowledgeInfoVo.getVectorModelName()); }); // å é¤éä»¶åç¥è¯ç段 fragmentMapper.deleteByMap(map); @@ -207,12 +190,6 @@ } 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(); @@ -222,17 +199,13 @@ knowledgeAttach.setDocName(fileName); 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); @@ -252,22 +225,25 @@ } 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); } @@ -282,96 +258,6 @@ if (!knowledgeInfoVo.getUid().equals(loginUser.getUserId())) { throw new SecurityException("æéä¸è¶³"); } } } /** * 宿¶ å¤ç éä»¶ä¸ä¼ åä¸ä¼ åéæ°æ®åºåPDFæä»¶å¾çæè§£ååæå 容 */ @Scheduled(fixedDelay = 3000) // æ¯3ç§æ§è¡ä¸æ¬¡ public void dealKnowledgeAttach() 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) ); if (ObjectUtil.isNotEmpty(knowledgeAttaches)) { for (KnowledgeAttach attachItem : knowledgeAttaches) { this.dealVectorStatus(attachItem); } } } @Async public void dealVectorStatus(KnowledgeAttach attachItem) throws Exception { try { //é宿°æ® æ´æ¹VectorStatus å°è¿è¡ä¸ if (attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() .set(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_20) .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getPicAnysStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_10) .eq(KnowledgeAttach::getId, attachItem.getId()) ) == 0) { return; } // éè¿kidæ¥è¯¢ç¥è¯åºä¿¡æ¯ KnowledgeInfoVo knowledgeInfoVo = baseMapper.selectVoOne(Wrappers.<KnowledgeInfo>lambdaQuery() .eq(KnowledgeInfo::getKid, attachItem.getKid())); // éè¿å鿍¡åæ¥è¯¢æ¨¡åä¿¡æ¯ ChatModelVo chatModelVo = chatModelService.selectModelByName( knowledgeInfoVo.getVectorModel()); List<KnowledgeFragment> knowledgeFragments = fragmentMapper.selectList( new LambdaQueryWrapper<KnowledgeFragment>() .eq(KnowledgeFragment::getKid, attachItem.getKid()) .eq(KnowledgeFragment::getDocId, attachItem.getDocId()) ); if (ObjectUtil.isEmpty(knowledgeFragments)) { throw new Exception("æä»¶æ®µè½ä¸ºç©º"); } List<String> fids = knowledgeFragments.stream() .map(KnowledgeFragment::getFid) .collect(Collectors.toList()); if (ObjectUtil.isEmpty(fids)) { throw new Exception("fids 为空"); } List<String> chunkList = knowledgeFragments.stream() .map(KnowledgeFragment::getContent) .collect(Collectors.toList()); if (ObjectUtil.isEmpty(chunkList)) { throw new Exception("chunkList 为空"); } StoreEmbeddingBo storeEmbeddingBo = new StoreEmbeddingBo(); storeEmbeddingBo.setKid(attachItem.getKid()); storeEmbeddingBo.setDocId(attachItem.getDocId()); storeEmbeddingBo.setFids(fids); storeEmbeddingBo.setChunkList(chunkList); storeEmbeddingBo.setModelName(knowledgeInfoVo.getVectorModel()); storeEmbeddingBo.setApiKey(chatModelVo.getApiKey()); storeEmbeddingBo.setBaseUrl(chatModelVo.getApiHost()); vectorStoreService.storeEmbeddings(storeEmbeddingBo); //设置å¤ç宿 attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() .set(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getPicAnysStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_20) .eq(KnowledgeAttach::getId, attachItem.getId())); } catch (Exception e) { //设置å¤ç失败 attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() .set(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_10) .eq(KnowledgeAttach::getPicStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getPicAnysStatus, DealStatus.STATUS_30) .eq(KnowledgeAttach::getVectorStatus, DealStatus.STATUS_20) .eq(KnowledgeAttach::getId, attachItem.getId())); throw new RuntimeException(e); } } script/sql/update/20250514.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,6 @@ LTER TABLE `knowledge_info` ADD COLUMN `system_prompt` varchar(255) NULL COMMENT 'ç³»ç»æç¤ºè¯' AFTER `vector_model`; ALTER TABLE `knowledge_info` CHANGE COLUMN `vector` `vector_model_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'åéåº' AFTER `text_block_size`, CHANGE COLUMN `vector_model` `embedding_model_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'å鿍¡å' AFTER `vector_model_name`;