办学质量监测教学评价系统
ageerle
2025-03-07 ea09421b0e42e0f4aaefa307055afc4fb48d7522
.editorconfig
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/org/ruoyi/controller/KnowledgeController.java
@@ -81,7 +81,7 @@
        List<Message> messages = chatRequest.getMessages();
        String content = messages.get(messages.size() - 1).getContent().toString();
        List<String> nearestList;
        List<Double> queryVector = embeddingService.getQueryVector(content);
        List<Double> queryVector = embeddingService.getQueryVector(content, chatRequest.getKid());
        nearestList = vectorStore.nearest(queryVector,chatRequest.getKid());
        for (String prompt : nearestList) {
            Message sysMessage = Message.builder().content(prompt).role(Message.Role.USER).build();
ruoyi-admin/src/main/resources/application-dev.yml
@@ -27,7 +27,7 @@
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
          username: ruoyi-ai
          password: ruoyi-ai
          password: eCaZ278N62k6fhYj
      hikari:
        # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
ruoyi-admin/src/main/resources/application.yml
@@ -310,11 +310,6 @@
  #  ä¼ä¸šå¾®ä¿¡åº”用
wechat:
  #  æ˜¯å¦ä½¿ç”¨å¾®ä¿¡ true/false
  enable: true
  #  ç”Ÿæˆçš„登录二维码路径 é»˜è®¤ä¸Žé¡¹ç›®åŒçº§
  qrPath: "./"
  #  ä¼ä¸šå¾®ä¿¡åº”用
  cp:
    corpId:
    appConfigs:
@@ -323,28 +318,5 @@
        token:   ''
        aesKey: ''
# çŸ¥è¯†åº“配置
chain:
  split:
    chunk:
      endspliter: "<STOP>"
      # åˆ†å—文本大小
      size: 200
      overlay: 30
      qaspliter: "###"
  # çŸ¥è¯†åº“中检索的条数
  limits: 5
  vector:
    model: 'text-embedding-3-small'
    store:
      type: weaviate
      weaviate:
        protocol: http
        host: 127.0.0.1:6038
        classname: LocalKnowledge
      milvus:
        host: 127.0.0.1
        port: 19530
        dimension: 1536
        collection: LocalKnowledge
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CodeFileLoader.java
@@ -31,7 +31,7 @@
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CsvFileLoader.java
@@ -10,7 +10,7 @@
    }
    @Override
    public List<String> getChunkList(String content) {
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/FolderLoader.java
@@ -10,7 +10,7 @@
    }
    @Override
    public List<String> getChunkList(String content) {
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/GithubLoader.java
@@ -10,7 +10,7 @@
    }
    @Override
    public List<String> getChunkList(String content) {
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/JsonFileLoader.java
@@ -10,7 +10,7 @@
    }
    @Override
    public List<String> getChunkList(String content) {
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/MarkDownFileLoader.java
@@ -31,7 +31,7 @@
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/PdfFileLoader.java
@@ -28,7 +28,7 @@
    }
    @Override
    public List<String> getChunkList(String content) {
        return characterTextSplitter.split(content);
    public List<String> getChunkList(String content, String kid) {
        return characterTextSplitter.split(content, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/ResourceLoader.java
@@ -7,6 +7,8 @@
 * èµ„源载入
 */
public interface ResourceLoader {
    String getContent(InputStream inputStream);
    List<String> getChunkList(String content);
    List<String> getChunkList(String content, String kid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/TextFileLoader.java
@@ -31,7 +31,7 @@
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/WordLoader.java
@@ -30,8 +30,8 @@
    }
    @Override
    public List<String> getChunkList(String content) {
        return textSplitter.split(content);
    public List<String> getChunkList(String content, String kid) {
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/retrieve/PromptRetrieverProperties.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CharacterTextSplitter.java
@@ -1,7 +1,10 @@
package org.ruoyi.knowledge.chain.split;
import lombok.AllArgsConstructor;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@@ -10,38 +13,46 @@
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
@Primary
public class CharacterTextSplitter implements TextSplitter{
    private final SplitterProperties splitterProperties;
public class CharacterTextSplitter implements TextSplitter {
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Override
    public List<String> split(String content) {
    public List<String> split(String content, String kid) {
        // ä»ŽçŸ¥è¯†åº“表中获取配置
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        String knowledgeSeparator = knowledgeInfoVo.getKnowledgeSeparator();
        int textBlockSize = knowledgeInfoVo.getTextBlockSize();
        int overlapChar = knowledgeInfoVo.getOverlapChar();
        List<String> chunkList = new ArrayList<>();
        if (content.contains(splitterProperties.getEndspliter())){
        if (content.contains(knowledgeSeparator)) {
            // æŒ‰è‡ªå®šä¹‰åˆ†éš”符切分
            String[] chunks = content.split(splitterProperties.getEndspliter());
            String[] chunks = content.split(knowledgeSeparator);
            chunkList.addAll(Arrays.asList(chunks));
        }else {
        } else {
            int indexMin = 0;
            int len = content.length();
            int i = 0;
            int right = 0;
            while (true) {
                if (len > right ){
                    int begin = i*splitterProperties.getSize() - splitterProperties.getOverlay();
                    if (begin < indexMin){
                if (len > right) {
                    int begin = i * textBlockSize - overlapChar;
                    if (begin < indexMin) {
                        begin = indexMin;
                    }
                    int end = splitterProperties.getSize()*(i+1) + splitterProperties.getOverlay();
                    if (end > len){
                    int end = textBlockSize * (i + 1) + overlapChar;
                    if (end > len) {
                        end = len;
                    }
                    String chunk = content.substring(begin,end);
                    String chunk = content.substring(begin, end);
                    chunkList.add(chunk);
                    i++;
                    right = right + splitterProperties.getSize();
                }else {
                    right = right + textBlockSize;
                } else {
                    break;
                }
            }
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CodeTextSplitter.java
@@ -11,7 +11,7 @@
@Slf4j
public class CodeTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/MarkdownTextSplitter.java
@@ -11,7 +11,7 @@
@Slf4j
public class MarkdownTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/SplitterProperties.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TextSplitter.java
@@ -7,5 +7,12 @@
 */
public interface TextSplitter {
    List<String> split(String content);
    /**
     * æ–‡æœ¬åˆ‡åˆ†
     *
     * @param content æ–‡æœ¬å†…容
     * @param kid     çŸ¥è¯†åº“id
     * @return åˆ‡åˆ†åŽçš„æ–‡æœ¬åˆ—表
     */
    List<String> split(String content, String kid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TokenTextSplitter.java
@@ -11,7 +11,7 @@
@Slf4j
public class TokenTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/OpenAiVectorization.java
@@ -1,5 +1,6 @@
package org.ruoyi.knowledge.chain.vectorizer;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -8,7 +9,10 @@
import org.ruoyi.common.chat.entity.embeddings.EmbeddingResponse;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@@ -20,8 +24,9 @@
@RequiredArgsConstructor
public class OpenAiVectorization implements Vectorization {
    @Value("${chain.vector.model}")
    private String embeddingModel;
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Getter
    private OpenAiStreamClient openAiStreamClient;
@@ -29,12 +34,12 @@
    private final ChatConfig chatConfig;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList) {
    public List<List<Double>> batchVectorization(List<String> chunkList, String kid) {
        openAiStreamClient = chatConfig.getOpenAiStreamClient();
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        Embedding embedding = Embedding.builder()
            .input(chunkList)
            .model(embeddingModel)
            .model(knowledgeInfoVo.getVectorModel())
            .build();
        EmbeddingResponse embeddings = openAiStreamClient.embeddings(embedding);
        List<List<Double>> vectorList = new ArrayList<>();
@@ -50,10 +55,10 @@
    }
    @Override
    public List<Double> singleVectorization(String chunk) {
    public List<Double> singleVectorization(String chunk, String kid) {
        List<String> chunkList = new ArrayList<>();
        chunkList.add(chunk);
        List<List<Double>> vectorList = batchVectorization(chunkList);
        List<List<Double>> vectorList = batchVectorization(chunkList, kid);
        return vectorList.get(0);
    }
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/Vectorization.java
@@ -6,6 +6,7 @@
 * å‘量化
 */
public interface Vectorization {
    List<List<Double>> batchVectorization(List<String> chunkList);
    List<Double> singleVectorization(String chunk);
    List<List<Double>> batchVectorization(List<String> chunkList, String kid);
    List<Double> singleVectorization(String chunk, String kid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationWrapper.java
@@ -15,14 +15,14 @@
    private final VectorizationFactory vectorizationFactory;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList) {
    public List<List<Double>> batchVectorization(List<String> chunkList, String kid) {
        Vectorization embedding = vectorizationFactory.getEmbedding();
        return embedding.batchVectorization(chunkList);
        return embedding.batchVectorization(chunkList, kid);
    }
    @Override
    public List<Double> singleVectorization(String chunk) {
    public List<Double> singleVectorization(String chunk, String kid) {
        Vectorization embedding = vectorizationFactory.getEmbedding();
        return embedding.singleVectorization(chunk);
        return embedding.singleVectorization(chunk, kid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/MilvusVectorStore.java
@@ -19,8 +19,10 @@
import io.milvus.response.QueryResultsWrapper;
import io.milvus.response.SearchResultsWrapper;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.core.service.ConfigService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -32,26 +34,27 @@
@Slf4j
public class MilvusVectorStore implements VectorStore{
    @Value("${chain.vector.store.milvus.host}")
    private String milvusHost;
    @Value("${chain.vector.store.milvus.port}")
    private Integer milvausPort;
    @Value("${chain.vector.store.milvus.dimension}")
    private Integer dimension;
    @Value("${chain.vector.store.milvus.collection}")
    private String collectionName;
    private volatile Integer dimension;
    private volatile String collectionName;
    private MilvusServiceClient milvusServiceClient;
    @Resource
    private ConfigService configService;
    @PostConstruct
    public void loadConfig() {
        this.dimension = Integer.parseInt(configService.getConfigValue("milvus", "dimension"));
        this.collectionName = configService.getConfigValue("milvus", "collection");
    }
    @PostConstruct
    public void init(){
        String milvusHost = configService.getConfigValue("milvus", "host");
        String milvausPort = configService.getConfigValue("milvus", "port");
        milvusServiceClient = new MilvusServiceClient(
                ConnectParam.newBuilder()
                        .withHost(milvusHost)
                        .withPort(milvausPort)
                        .withPort(Integer.parseInt(milvausPort))
                        .withDatabaseName("default")
                        .build()
        );
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreFactory.java
@@ -1,29 +1,37 @@
package org.ruoyi.knowledge.chain.vectorstore;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.mapper.KnowledgeInfoMapper;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
@RequiredArgsConstructor
public class VectorStoreFactory {
    @Value("${chain.vector.store.type}")
    private String type;
    private final WeaviateVectorStore weaviateVectorStore;
    private final MilvusVectorStore milvusVectorStore;
    public VectorStoreFactory(WeaviateVectorStore weaviateVectorStore, MilvusVectorStore milvusVectorStore) {
        this.weaviateVectorStore = weaviateVectorStore;
        this.milvusVectorStore = milvusVectorStore;
    }
    private final  KnowledgeInfoMapper knowledgeInfoMapper;
    public VectorStore getVectorStore(){
        if ("weaviate".equals(type)){
    public VectorStore getVectorStore(String kid){
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoMapper.selectVoOne(
                new LambdaQueryWrapper<KnowledgeInfo>().eq(KnowledgeInfo::getKid,kid)
        );
        String vectorModel = knowledgeInfoVo.getVector();
        if ("weaviate".equals(vectorModel)){
            return weaviateVectorStore;
        }else if ("milvus".equals(type)){
        }else if ("milvus".equals(vectorModel)){
            return milvusVectorStore;
        }
        return null;
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreWrapper.java
@@ -16,43 +16,43 @@
    private final VectorStoreFactory vectorStoreFactory;
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        vectorStore.storeEmbeddings(chunkList, vectorList,  kid,  docId, fidList);
    }
    @Override
    public void removeByDocId(String kid, String docId) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        vectorStore.removeByDocId(kid,docId);
    }
    @Override
    public void removeByKid(String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        vectorStore.removeByKid(kid);
    }
    @Override
    public List<String> nearest(List<Double> queryVector, String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        return vectorStore.nearest(queryVector,kid);
    }
    @Override
    public List<String> nearest(String query, String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        return vectorStore.nearest(query, kid);
    }
    @Override
    public void newSchema(String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        vectorStore.newSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        VectorStore vectorStore = vectorStoreFactory.getVectorStore(kid);
        vectorStore.removeByKidAndFid(kid, fid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/WeaviateVectorStore.java
@@ -22,10 +22,15 @@
import io.weaviate.client.v1.schema.model.Property;
import io.weaviate.client.v1.schema.model.Schema;
import io.weaviate.client.v1.schema.model.WeaviateClass;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.knowledge.chain.retrieve.PromptRetrieverProperties;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@@ -37,18 +42,23 @@
@Slf4j
public class WeaviateVectorStore implements VectorStore{
    @Value("${chain.vector.store.weaviate.protocol}")
    private String protocol;
    @Value("${chain.vector.store.weaviate.host}")
    private String host;
    private volatile String protocol;
    private volatile String host;
    private volatile String className;
    @Value("${chain.vector.store.weaviate.classname}")
    private String className;
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    private final PromptRetrieverProperties promptRetrieverProperties;
    @Lazy
    @Resource
    private ConfigService configService;
    public WeaviateVectorStore(PromptRetrieverProperties promptRetrieverProperties) {
        this.promptRetrieverProperties = promptRetrieverProperties;
    @PostConstruct
    public void loadConfig() {
        this.protocol =  configService.getConfigValue("weaviate", "protocol");
        this.host = configService.getConfigValue("weaviate", "host");
        this.className = configService.getConfigValue("weaviate", "classname");
    }
    public WeaviateClient getClient(){
@@ -309,11 +319,12 @@
                .vector(vf)
                .distance(1.6f) // certainty = 1f - distance /2f
                .build();
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(contentField,_additional)
                .withNearVector(nearVector)
                .withLimit(promptRetrieverProperties.getLimits())
                .withLimit(knowledgeInfoVo.getRetrieveLimit())
                .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
@@ -342,12 +353,12 @@
                .concepts(new String[]{ query })
                .distance(1.6f) // certainty = 1f - distance /2f
                .build();
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(contentField,_additional)
                .withNearText(nearText)
                .withLimit(promptRetrieverProperties.getLimits())
                .withLimit(knowledgeInfoVo.getRetrieveLimit())
                .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeInfo.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serial;
@@ -44,6 +45,11 @@
    private String kname;
    /**
     * çŸ¥è¯†åº“名称
     */
    private String share;
    /**
     * æè¿°
     */
    private String description;
@@ -59,5 +65,38 @@
     */
    private Date createTime;
    /**
     * çŸ¥è¯†åˆ†éš”符
     */
    private String knowledgeSeparator;
    /**
     * æé—®åˆ†éš”符
     */
    private String questionSeparator;
    /**
     * é‡å å­—符数
     */
    private Integer overlapChar;
    /**
     * çŸ¥è¯†åº“中检索的条数
     */
    private Integer retrieveLimit;
    /**
     * æ–‡æœ¬å—大小
     */
    private Integer textBlockSize;
    /**
     * å‘量库
     */
    private String vector;
    /**
     * å‘量模型
     */
    private String vectorModel;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeInfoBo.java
@@ -44,10 +44,56 @@
    private String kname;
    /**
     * çŸ¥è¯†åº“名称
     */
    @NotBlank(message = "是否公开知识库")
    private String share;
    /**
     * æè¿°
     */
    @NotBlank(message = "描述不能为空")
    private String description;
    /**
     * çŸ¥è¯†åˆ†éš”符
     */
    @NotBlank(message = "知识分隔符不能为空")
    private String knowledgeSeparator;
    /**
     * æé—®åˆ†éš”符
     */
    @NotBlank(message = "提问分隔符不能为空")
    private String questionSeparator;
    /**
     * é‡å å­—符数
     */
    @NotNull(message = "重叠字符数不能为空")
    private Integer overlapChar;
    /**
     * çŸ¥è¯†åº“中检索的条数
     */
    @NotNull(message = "知识库中检索的条数不能为空")
    private Integer retrieveLimit;
    /**
     * æ–‡æœ¬å—大小
     */
    @NotNull(message = "文本块大小不能为空")
    private Integer textBlockSize;
    /**
     * å‘量库
     */
    @NotBlank(message = "向量库不能为空")
    private String vector;
    /**
     * å‘量模型
     */
    @NotBlank(message = "向量模型不能为空")
    private String vectorModel;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeInfoVo.java
@@ -48,10 +48,55 @@
    private String kname;
    /**
     * çŸ¥è¯†åº“名称
     */
    private String share;
    /**
     * æè¿°
     */
    @ExcelProperty(value = "描述")
    private String description;
    /**
     * çŸ¥è¯†åˆ†éš”符
     */
    @ExcelProperty(value = "知识分隔符")
    private String knowledgeSeparator;
    /**
     * æé—®åˆ†éš”符
     */
    @ExcelProperty(value = "提问分隔符")
    private String questionSeparator;
    /**
     * é‡å å­—符数
     */
    @ExcelProperty(value = "重叠字符数")
    private Integer overlapChar;
    /**
     * çŸ¥è¯†åº“中检索的条数
     */
    @ExcelProperty(value = "知识库中检索的条数")
    private Integer retrieveLimit;
    /**
     * æ–‡æœ¬å—大小
     */
    @ExcelProperty(value = "文本块大小")
    private Integer textBlockSize;
    /**
     * å‘量库
     */
    @ExcelProperty(value = "向量库")
    private String vector;
    /**
     * å‘量模型
     */
    @ExcelProperty(value = "向量模型")
    private String vectorModel;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/EmbeddingService.java
@@ -10,7 +10,7 @@
    void removeByKid(String kid);
    List<Double> getQueryVector(String query);
    List<Double> getQueryVector(String query, String kid);
    void createSchema(String kid);
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeInfoService.java
@@ -55,4 +55,10 @@
     * åˆ é™¤çŸ¥è¯†åº“
     */
    void removeKnowledge(String id);
    /**
     * æ£€æŸ¥æ˜¯å¦æœ‰åˆ é™¤æƒé™
     * @param knowledgeInfoList çŸ¥è¯†åˆ—表
     */
    void check(List<KnowledgeInfoVo> knowledgeInfoList);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/EmbeddingServiceImpl.java
@@ -24,7 +24,7 @@
     */
    @Override
    public void storeEmbeddings(List<String> chunkList, String kid, String docId,List<String> fidList) {
        List<List<Double>> vectorList = vectorization.batchVectorization(chunkList);
        List<List<Double>> vectorList = vectorization.batchVectorization(chunkList, kid);
        vectorStore.storeEmbeddings(chunkList,vectorList,kid,docId,fidList);
    }
@@ -39,8 +39,8 @@
    }
    @Override
    public List<Double> getQueryVector(String query) {
        List<Double> queryVector = vectorization.singleVectorization(query);
    public List<Double> getQueryVector(String query, String kid) {
        List<Double> queryVector = vectorization.singleVectorization(query,kid);
        return queryVector;
    }
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeAttachServiceImpl.java
@@ -4,16 +4,21 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
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.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.mapper.KnowledgeAttachMapper;
import org.ruoyi.knowledge.mapper.KnowledgeFragmentMapper;
import org.ruoyi.knowledge.mapper.KnowledgeInfoMapper;
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.stereotype.Service;
import java.util.Collection;
@@ -34,6 +39,11 @@
    private final KnowledgeAttachMapper baseMapper;
    private final KnowledgeFragmentMapper fragmentMapper;
    private final KnowledgeInfoMapper knowledgeInfoMapper;
    private final IKnowledgeInfoService knowledgeInfoService;
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件
@@ -117,8 +127,12 @@
    @Override
    public void removeKnowledgeAttach(String kid) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("kid", kid);
        LoginUser loginUser = LoginHelper.getLoginUser();
        Map<String,Object> map = new HashMap<>();
        map.put("kid",kid);
        List<KnowledgeInfoVo> knowledgeInfoList = knowledgeInfoMapper.selectVoByMap(map);
        knowledgeInfoService.check(knowledgeInfoList);
        baseMapper.deleteByMap(map);
        fragmentMapper.deleteByMap(map);
    }
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeInfoServiceImpl.java
@@ -1,16 +1,16 @@
package org.ruoyi.knowledge.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.chat.OllamaChatResult;
import lombok.RequiredArgsConstructor;
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.mybatis.core.page.PageQuery;
@@ -21,8 +21,6 @@
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
@@ -30,14 +28,11 @@
import org.ruoyi.knowledge.mapper.KnowledgeFragmentMapper;
import org.ruoyi.knowledge.mapper.KnowledgeInfoMapper;
import org.ruoyi.knowledge.service.EmbeddingService;
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
/**
@@ -88,12 +83,13 @@
    }
    private LambdaQueryWrapper<KnowledgeInfo> buildQueryWrapper(KnowledgeInfoBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeInfo::getKid, bo.getKid());
        lqw.eq(bo.getUid() != null, KnowledgeInfo::getUid, bo.getUid());
        lqw.like(StringUtils.isNotBlank(bo.getKname()), KnowledgeInfo::getKname, bo.getKname());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription());
        // æŸ¥è¯¢å…¬å¼€çš„知识库
        lqw.or(wrapper -> wrapper.eq(KnowledgeInfo::getShare, "1"));
        return lqw;
    }
@@ -151,7 +147,7 @@
        List<String> fids = new ArrayList<>();
        try {
            content = resourceLoader.getContent(file.getInputStream());
            chunkList = resourceLoader.getChunkList(content);
            chunkList = resourceLoader.getChunkList(content, kid);
            for (int i = 0; i < chunkList.size(); i++) {
                String fid = RandomUtil.randomString(16);
                fids.add(fid);
@@ -179,6 +175,8 @@
        Map<String,Object> map = new HashMap<>();
        map.put("kid",id);
        List<KnowledgeInfoVo> knowledgeInfoList = baseMapper.selectVoByMap(map);
        check(knowledgeInfoList);
        // åˆ é™¤çŸ¥è¯†åº“
        baseMapper.deleteByMap(map);
        // åˆ é™¤é™„件和知识片段
@@ -188,31 +186,13 @@
        embeddingService.removeByKid(id);
    }
    /**
     * å°†æ–‡æœ¬å—转换为预训练数据
     * @param chunk è§£æžæ–‡æœ¬å—
     */
    public String convertTextBlockToPretrainData(String chunk){
            String host = "http://localhost:11434/";
            OllamaAPI ollama = new OllamaAPI(host);
            OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("qwen2.5:7b");
            // è®¾ç½®è¶…æ—¶æ—¶é—´
            ollama.setRequestTimeoutSeconds(100);
            // create first user question
            String json = "instruction:用户指令,根据语义提取一个关键词;input:用户输入,根据语义提取多个关键词;output:输出文本内容";
            OllamaChatRequestModel requestModel = builder.withMessage
                (OllamaChatMessageRole.USER, "文本:"+chunk+"理解文本内容,并且将文本内容转换为:"+json+",输出JSON格式,不要包含其他无关内容,内部使用无需脱敏")
            .build();
            // start conversation with model
            OllamaChatResult chatResult = null;
            try {
                chatResult = ollama.chat(requestModel);
            } catch (Exception e) {
                System.out.println("解析失败!");
    @Override
    public void check(List<KnowledgeInfoVo> knowledgeInfoList){
        LoginUser loginUser = LoginHelper.getLoginUser();
        for (KnowledgeInfoVo knowledgeInfoVo : knowledgeInfoList) {
            if(!knowledgeInfoVo.getUid().equals(loginUser.getUserId())){
                throw new SecurityException("权限不足");
            }
            return chatResult.getResponse();
        }
    }
}
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatConfigController.java
@@ -36,8 +36,8 @@
     */
    @GetMapping("/list")
    @SaCheckPermission("system:config:list")
    public List<ChatConfigVo> list(ChatConfigBo bo) {
        return chatConfigService.queryList(bo);
    public R<List<ChatConfigVo>> list(ChatConfigBo bo) {
        return R.ok(chatConfigService.queryList(bo));
    }
    /**
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/request/translation/TranslationRequest.java
@@ -22,13 +22,8 @@
    private String model;
    /**
     * æºè¯­è¨€
     */
    private String  sourceLanguage;
    /**
     * ç›®æ ‡è¯­è¨€
     */
    private String  targetLanguage;
    private String targetLanguage;
}
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java
@@ -553,7 +553,21 @@
        List<Message> messageList = new ArrayList<>();
        Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content("作为英汉翻译,您的任务是准确地在两种语言之间翻译文本。翻译时,请注意上下文,准确解释成语和谚语。如果连续收到多个英文单词,请默认将其翻译成中文句子。但如果前面有'phrase:’,则应翻译为短语;如果有'norma!:',则翻译为多个无关的单词。您的翻译应接近母语者的水平,并考虑用户要求的特定语言风格或语气。避免使用冒犯性词汇,必要时用x替换。提供翻译时,请用中文解释每句话的时态、从句、主语、谓语、宾语、特殊短语和谚语对于需要翻译的短语或单词,请提供来源(词典)。如果要求翻译多个短语,请用|符号分隔。请记住:您是英汉翻译,不是汉汉翻译或英英翻译。提交前请仔细检查和修订答案,回复控制在50字以内").build();
        Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content("你是一名翻译老师\n" +
            "\n" +
            "请将用户输入词语翻译成{" + translationRequest.getTargetLanguage() + "}\n" +
            "\n" +
            "让我们一步一步来思考\n" +
            "==示例输出==\n" +
            "**翻译** : <这里显示翻译成英语的结果>\n" +
            "\n" +
            "**造句** : What's the weather like today? Use the 'Weather Query' plugin to find out instantly! <造一个英语句子>\n" +
            "\n" +
            "**同义词** : Add-on、Extension、Module  <这里显示1-3个英文的同义词>\n" +
            "\n" +
            "==示例结束==\n" +
            "\n" +
            "注意:请严格按示例进行输出").build();
        messageList.add(sysMessage);
        Message message = Message.builder().role(Message.Role.USER).content(translationRequest.getPrompt()).build();
        messageList.add(message);
script/sql/update/update20250302.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
ALTER TABLE `knowledge_info` ADD COLUMN `share` tinyint(4) NULL DEFAULT NULL COMMENT '是否公开知识库(0 å¦ 1是)' AFTER `kname`;