办学质量监测教学评价系统
ageerle
2025-04-09 3be9005f95ebc14639a7e281703dfa9d9b4a7afc
pom.xml
@@ -244,18 +244,6 @@
                <version>${tencent.sms.version}</version>
            </dependency>
            <!--            <dependency>-->
            <!--                <groupId>de.codecentric</groupId>-->
            <!--                <artifactId>spring-boot-admin-starter-server</artifactId>-->
            <!--                <version>${spring-boot-admin.version}</version>-->
            <!--            </dependency>-->
            <!--            <dependency>-->
            <!--                <groupId>de.codecentric</groupId>-->
            <!--                <artifactId>spring-boot-admin-starter-client</artifactId>-->
            <!--                <version>${spring-boot-admin.version}</version>-->
            <!--            </dependency>-->
            <!--redisson-->
            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson-spring-boot-starter</artifactId>
@@ -321,10 +309,15 @@
                <version>${revision}</version>
            </dependency>
            <dependency>
                <groupId>org.ruoyi</groupId>
                <artifactId>ruoyi-knowledge-api</artifactId>
                <version>${revision}</version>
            </dependency>
            <dependency>
                <groupId>org.ruoyi</groupId>
                <artifactId>ruoyi-knowledge</artifactId>
                <artifactId>ruoyi-system-api</artifactId>
                <version>${revision}</version>
            </dependency>
@@ -347,11 +340,6 @@
        <module>ruoyi-common</module>
        <module>ruoyi-modules</module>
        <module>ruoyi-modules-api</module>
        <module>ruoyi-modules-api</module>
        <module>ruoyi-modules-api/ruoyi-device-api</module>
        <module>ruoyi-modules-api/ruoyi-weixin-api</module>
        <module>ruoyi-modules/ruoyi-weixin</module>
        <module>ruoyi-modules/ruoyi-device</module>
    </modules>
    <packaging>pom</packaging>
ruoyi-common/ruoyi-common-bom/pom.xml
@@ -166,14 +166,11 @@
                <version>${revision}</version>
            </dependency>
            <!-- AI绘画 -->
            <dependency>
                <groupId>org.ruoyi</groupId>
                <artifactId>ruoyi-chat</artifactId>
                <version>${revision}</version>
            </dependency>
            <!-- æ”¯ä»˜æ¨¡å— -->
            <dependency>
@@ -182,6 +179,7 @@
                <version>${revision}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
ruoyi-common/ruoyi-common-chat/pom.xml
@@ -98,10 +98,6 @@
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.bigmodel.openapi</groupId>
ruoyi-common/ruoyi-common-core/pom.xml
@@ -47,25 +47,11 @@
            <artifactId>jakarta.servlet-api</artifactId>
        </dependency>
        <!-- hutool工具模块 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-http</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-extra</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-json</artifactId>
            <scope>provided</scope>
            <artifactId>hutool-all</artifactId>
            <version>5.8.24</version>
        </dependency>
        <dependency>
ruoyi-modules-api/pom.xml
@@ -12,9 +12,11 @@
    <artifactId>ruoyi-modules-api</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>ruoyi-system-api</module>
        <module>ruoyi-chat-api</module>
        <module>ruoyi-device-api</module>
        <module>ruoyi-knowledge-api</module>
        <module>ruoyi-system-api</module>
        <module>ruoyi-weixin-api</module>
    </modules>
    <properties>
@@ -24,13 +26,11 @@
    </properties>
    <dependencies>
        <!-- ç³»ç»Ÿæ ¸å¿ƒæ¨¡å— -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-core</artifactId>
        </dependency>
        <!-- mybaits基础模块 -->
        <dependency>
@@ -38,13 +38,11 @@
            <artifactId>ruoyi-common-mybatis</artifactId>
        </dependency>
        <!-- è„±æ•æ¨¡å— -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-sensitive</artifactId>
        </dependency>
        <!-- excel模块-->
        <dependency>
@@ -52,10 +50,31 @@
            <artifactId>ruoyi-common-excel</artifactId>
        </dependency>
        <!-- ç§Ÿæˆ·åŸºç¡€æ¨¡å— -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-tenant</artifactId>
        </dependency>
        <!-- å­—段翻译基础模块 -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-translation</artifactId>
        </dependency>
        <!-- ç³»ç»Ÿæ—¥å¿—模块 -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-log</artifactId>
        </dependency>
        <!-- å¯¹è±¡å­˜å‚¨æ¨¡å— -->
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-oss</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules-api/ruoyi-chat-api/pom.xml
@@ -17,6 +17,13 @@
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!-- èŠå¤©åŸºç¡€æ¨¡å— -->
    <dependencies>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-chat</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatMessage.java
@@ -46,8 +46,6 @@
    /**
     * æ‰£é™¤é‡‘额
     */
    private BigDecimal deductCost;
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatRobConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
 * èŠå¤©æœºå™¨äººé…ç½®å¯¹è±¡ chat_rob_config
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("chat_rob_config")
public class ChatRobConfig extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @TableId(value = "id")
    private Long id;
    /**
     * æ‰€å±žç”¨æˆ·
     */
    private Long userId;
    /**
     * æœºå™¨äººåç§°
     */
    private String botName;
    /**
     * æœºå™¨å”¯ä¸€ç 
     */
    private String uniqueKey;
    /**
     * é»˜è®¤å¥½å‹å›žå¤å¼€å…³
     */
    private String defaultFriend;
    /**
     * é»˜è®¤ç¾¤å›žå¤å¼€å…³
     */
    private String defaultGroup;
    /**
     * æœºå™¨äººçŠ¶æ€  0正常 1启用
     */
    private String enable;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatUsageToken.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
 * ç”¨æˆ·token使用详情对象 chat_usage_token
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("chat_usage_token")
public class ChatUsageToken extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @TableId(value = "id")
    private Long id;
    /**
     * ç”¨æˆ·
     */
    private Long userId;
    /**
     * å¾…结算token
     */
    private Integer token;
    /**
     * æ¨¡åž‹åç§°
     */
    private String modelName;
    /**
     * ç´¯è®¡ä½¿ç”¨token
     */
    private String totalToken;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatRobConfigBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.ChatRobConfig;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * èŠå¤©æœºå™¨äººé…ç½®ä¸šåŠ¡å¯¹è±¡ chat_rob_config
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ChatRobConfig.class, reverseConvertGenerate = false)
public class ChatRobConfigBo extends BaseEntity {
    /**
     * ä¸»é”®
     */
    @NotNull(message = "主键不能为空", groups = { EditGroup.class })
    private Long id;
    /**
     * æ‰€å±žç”¨æˆ·
     */
    @NotNull(message = "所属用户不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long userId;
    /**
     * æœºå™¨äººåç§°
     */
    @NotBlank(message = "机器人名称不能为空", groups = { AddGroup.class, EditGroup.class })
    private String botName;
    /**
     * æœºå™¨å”¯ä¸€ç 
     */
    @NotBlank(message = "机器唯一码不能为空", groups = { AddGroup.class, EditGroup.class })
    private String uniqueKey;
    /**
     * é»˜è®¤å¥½å‹å›žå¤å¼€å…³
     */
    @NotBlank(message = "默认好友回复开关不能为空", groups = { AddGroup.class, EditGroup.class })
    private String defaultFriend;
    /**
     * é»˜è®¤ç¾¤å›žå¤å¼€å…³
     */
    @NotBlank(message = "默认群回复开关不能为空", groups = { AddGroup.class, EditGroup.class })
    private String defaultGroup;
    /**
     * æœºå™¨äººçŠ¶æ€  0正常 1启用
     */
    @NotBlank(message = "机器人状态  0正常 1启用不能为空", groups = { AddGroup.class, EditGroup.class })
    private String enable;
    /**
     * å¤‡æ³¨
     */
    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
    private String remark;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatUsageTokenBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.ChatUsageToken;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * ç”¨æˆ·token使用详情业务对象 chat_usage_token
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ChatUsageToken.class, reverseConvertGenerate = false)
public class ChatUsageTokenBo extends BaseEntity {
    /**
     * ä¸»é”®
     */
    @NotNull(message = "主键不能为空", groups = { EditGroup.class })
    private Long id;
    /**
     * ç”¨æˆ·
     */
    @NotNull(message = "用户不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long userId;
    /**
     * å¾…结算token
     */
    @NotNull(message = "待结算token不能为空", groups = { AddGroup.class, EditGroup.class })
    private Integer token;
    /**
     * æ¨¡åž‹åç§°
     */
    @NotBlank(message = "模型名称不能为空", groups = { AddGroup.class, EditGroup.class })
    private String modelName;
    /**
     * ç´¯è®¡ä½¿ç”¨token
     */
    @NotBlank(message = "累计使用token不能为空", groups = { AddGroup.class, EditGroup.class })
    private String totalToken;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatVoucherBo.java
@@ -2,7 +2,7 @@
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.system.domain.ChatVoucher;
import org.ruoyi.domain.ChatVoucher;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/request/TranslationRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package org.ruoyi.domain.request;
import lombok.Data;
/**
 * æè¿°ï¼šç¿»è¯‘请求对象
 *
 * @author ageerle@163.com
 * date 2025/1/13
 */
@Data
public class TranslationRequest {
    /**
     * æç¤ºè¯
     */
    private String prompt;
    /**
     * æ¨¡åž‹åç§°
     */
    private String model;
    /**
     * ç›®æ ‡è¯­è¨€
     */
    private String targetLanguage;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatRobConfigVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package org.ruoyi.domain.vo;
import org.ruoyi.domain.ChatRobConfig;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * èŠå¤©æœºå™¨äººé…ç½®è§†å›¾å¯¹è±¡ chat_rob_config
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ChatRobConfig.class)
public class ChatRobConfigVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @ExcelProperty(value = "主键")
    private Long id;
    /**
     * æ‰€å±žç”¨æˆ·
     */
    @ExcelProperty(value = "所属用户")
    private Long userId;
    /**
     * æœºå™¨äººåç§°
     */
    @ExcelProperty(value = "机器人名称")
    private String botName;
    /**
     * æœºå™¨å”¯ä¸€ç 
     */
    @ExcelProperty(value = "机器唯一码")
    private String uniqueKey;
    /**
     * é»˜è®¤å¥½å‹å›žå¤å¼€å…³
     */
    @ExcelProperty(value = "默认好友回复开关")
    private String defaultFriend;
    /**
     * é»˜è®¤ç¾¤å›žå¤å¼€å…³
     */
    @ExcelProperty(value = "默认群回复开关")
    private String defaultGroup;
    /**
     * æœºå™¨äººçŠ¶æ€  0正常 1启用
     */
    @ExcelProperty(value = "机器人状态  0正常 1启用")
    private String enable;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String remark;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatUsageTokenVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package org.ruoyi.domain.vo;
import org.ruoyi.domain.ChatUsageToken;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * ç”¨æˆ·token使用详情视图对象 chat_usage_token
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ChatUsageToken.class)
public class ChatUsageTokenVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @ExcelProperty(value = "主键")
    private Long id;
    /**
     * ç”¨æˆ·
     */
    @ExcelProperty(value = "用户")
    private Long userId;
    /**
     * å¾…结算token
     */
    @ExcelProperty(value = "待结算token")
    private Integer token;
    /**
     * æ¨¡åž‹åç§°
     */
    @ExcelProperty(value = "模型名称")
    private String modelName;
    /**
     * ç´¯è®¡ä½¿ç”¨token
     */
    @ExcelProperty(value = "累计使用token")
    private String totalToken;
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatVoucherVo.java
@@ -1,12 +1,13 @@
package org.ruoyi.domain.vo;
import java.math.BigDecimal;
import org.ruoyi.system.domain.ChatVoucher;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.domain.ChatVoucher;
import java.io.Serial;
import java.io.Serializable;
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatRobConfigMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.domain.ChatRobConfig;
import org.ruoyi.domain.vo.ChatRobConfigVo;
/**
 * èŠå¤©æœºå™¨äººé…ç½®Mapper接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface ChatRobConfigMapper extends BaseMapperPlus<ChatRobConfig, ChatRobConfigVo> {
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatUsageTokenMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.domain.ChatUsageToken;
import org.ruoyi.domain.vo.ChatUsageTokenVo;
/**
 * ç”¨æˆ·token使用详情Mapper接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface ChatUsageTokenMapper extends BaseMapperPlus<ChatUsageToken, ChatUsageTokenVo> {
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatCostService.java
ÎļþÒÑɾ³ý
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java
@@ -46,4 +46,10 @@
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤èŠå¤©æ¨¡åž‹ä¿¡æ¯
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
    /**
     * é€šè¿‡æ¨¡åž‹åç§°èŽ·å–æ¨¡åž‹ä¿¡æ¯
     */
    ChatModelVo selectModelByName(String modelName);
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatTokenService.java
@@ -5,8 +5,8 @@
/**
 * èŠå¤©æ¶ˆæ¯Service接口
 *
 * @author Lion Li
 * @date 2023-11-26
 * @author ageerle
 * @date 2025-04-08
 */
public interface IChatTokenService {
@@ -20,6 +20,9 @@
     */
    void resetToken(Long userId,String modelName);
    /**
     * ä¿®æ”¹ç”¨æˆ·token
     */
    void editToken(ChatToken chatToken);
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatUsageTokenService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.service;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.domain.bo.ChatUsageTokenBo;
import org.ruoyi.domain.vo.ChatUsageTokenVo;
import java.util.Collection;
import java.util.List;
/**
 * ç”¨æˆ·token使用详情Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IChatUsageTokenService {
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情
     */
    ChatUsageTokenVo queryById(Long id);
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情列表
     */
    TableDataInfo<ChatUsageTokenVo> queryPageList(ChatUsageTokenBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情列表
     */
    List<ChatUsageTokenVo> queryList(ChatUsageTokenBo bo);
    /**
     * æ–°å¢žç”¨æˆ·token使用详情
     */
    Boolean insertByBo(ChatUsageTokenBo bo);
    /**
     * ä¿®æ”¹ç”¨æˆ·token使用详情
     */
    Boolean updateByBo(ChatUsageTokenBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤ç”¨æˆ·token使用详情信息
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatVisitorUsageService.java
@@ -11,8 +11,8 @@
/**
 * è®¿å®¢ç®¡ç†Service接口
 *
 * @author Lion Li
 * @date 2024-07-14
 * @author ageerle
 * @date 2025-04-08
 */
public interface IChatVisitorUsageService {
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java
@@ -115,4 +115,12 @@
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
    /**
     * é€šè¿‡æ¨¡åž‹åç§°èŽ·å–æ¨¡åž‹ä¿¡æ¯
     */
    @Override
    public ChatModelVo selectModelByName(String modelName) {
       return baseMapper.selectVoOne(Wrappers.<ChatModel>lambdaQuery().eq(ChatModel::getModelName, modelName));
    }
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatUsageTokenServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,112 @@
package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.ChatUsageToken;
import org.ruoyi.domain.bo.ChatUsageTokenBo;
import org.ruoyi.domain.vo.ChatUsageTokenVo;
import org.ruoyi.mapper.ChatUsageTokenMapper;
import org.ruoyi.service.IChatUsageTokenService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * ç”¨æˆ·token使用详情Service业务层处理
 *
 * @author ageerle
 * @date 2025-04-08
 */
@RequiredArgsConstructor
@Service
public class ChatUsageTokenServiceImpl implements IChatUsageTokenService {
    private final ChatUsageTokenMapper baseMapper;
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情
     */
    @Override
    public ChatUsageTokenVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情列表
     */
    @Override
    public TableDataInfo<ChatUsageTokenVo> queryPageList(ChatUsageTokenBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ChatUsageToken> lqw = buildQueryWrapper(bo);
        Page<ChatUsageTokenVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ç”¨æˆ·token使用详情列表
     */
    @Override
    public List<ChatUsageTokenVo> queryList(ChatUsageTokenBo bo) {
        LambdaQueryWrapper<ChatUsageToken> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<ChatUsageToken> buildQueryWrapper(ChatUsageTokenBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ChatUsageToken> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, ChatUsageToken::getUserId, bo.getUserId());
        lqw.eq(bo.getToken() != null, ChatUsageToken::getToken, bo.getToken());
        lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatUsageToken::getModelName, bo.getModelName());
        lqw.eq(StringUtils.isNotBlank(bo.getTotalToken()), ChatUsageToken::getTotalToken, bo.getTotalToken());
        return lqw;
    }
    /**
     * æ–°å¢žç”¨æˆ·token使用详情
     */
    @Override
    public Boolean insertByBo(ChatUsageTokenBo bo) {
        ChatUsageToken add = MapstructUtils.convert(bo, ChatUsageToken.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·token使用详情
     */
    @Override
    public Boolean updateByBo(ChatUsageTokenBo bo) {
        ChatUsageToken update = MapstructUtils.convert(bo, ChatUsageToken.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(ChatUsageToken entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤ç”¨æˆ·token使用详情
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/pom.xml
@@ -17,4 +17,35 @@
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- pdf解析器 -->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.27</version>
        </dependency>
        <!-- ollama java sdk -->
        <dependency>
            <groupId>io.github.ollama4j</groupId>
            <artifactId>ollama4j</artifactId>
            <version>1.0.79</version>
        </dependency>
        <!-- milvus java sdk -->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>io.weaviate</groupId>
            <artifactId>client</artifactId>
            <version>4.0.0</version>
        </dependency>
    </dependencies>
</project>
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/CodeFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class CodeFileLoader implements ResourceLoader {
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/CsvFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.loader;
import org.ruoyi.chain.loader.ResourceLoader;
import java.io.InputStream;
import java.util.List;
public class CsvFileLoader implements ResourceLoader {
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/FolderLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.chain.loader;
import java.io.InputStream;
import java.util.List;
public class FolderLoader implements ResourceLoader{
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/GithubLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.loader;
import org.ruoyi.chain.loader.ResourceLoader;
import java.io.InputStream;
import java.util.List;
public class GithubLoader implements ResourceLoader {
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/JsonFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.loader;
import org.ruoyi.chain.loader.ResourceLoader;
import java.io.InputStream;
import java.util.List;
public class JsonFileLoader implements ResourceLoader {
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/MarkDownFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.loader.ResourceLoader;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class MarkDownFileLoader implements ResourceLoader {
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/PdfFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.ruoyi.chain.loader.ResourceLoader;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Component
@AllArgsConstructor
public class PdfFileLoader implements ResourceLoader {
    private final TextSplitter characterTextSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        PDDocument document = null;
        try {
            document = PDDocument.load(inputStream);
            PDFTextStripper textStripper = new PDFTextStripper();
            String content = textStripper.getText(document);
            return content;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return characterTextSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package org.ruoyi.chain.loader;
import java.io.InputStream;
import java.util.List;
/**
 * èµ„源载入
 */
public interface ResourceLoader {
    String getContent(InputStream inputStream);
    List<String> getChunkList(String content, String kid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import org.ruoyi.chain.loader.ResourceLoader;
import org.ruoyi.chain.loader.TextFileLoader;
import org.ruoyi.chain.split.CharacterTextSplitter;
import org.ruoyi.chain.split.CodeTextSplitter;
import org.ruoyi.chain.split.MarkdownTextSplitter;
import org.ruoyi.chain.split.TokenTextSplitter;
import org.ruoyi.knowledge.constant.FileType;
import org.springframework.stereotype.Component;
@AllArgsConstructor
@Component
public class ResourceLoaderFactory {
    private final CharacterTextSplitter characterTextSplitter;
    private final CodeTextSplitter codeTextSplitter;
    private final MarkdownTextSplitter markdownTextSplitter;
    private final TokenTextSplitter tokenTextSplitter;
    public ResourceLoader getLoaderByFileType(String fileType){
        if (FileType.isTextFile(fileType)){
            return new TextFileLoader(characterTextSplitter);
        } else if (FileType.isWord(fileType)) {
            return new WordLoader(characterTextSplitter);
        } else if (FileType.isPdf(fileType)) {
            return new PdfFileLoader(characterTextSplitter);
        } else if (FileType.isMdFile(fileType)) {
            return new MarkDownFileLoader(markdownTextSplitter);
        }else if (FileType.isCodeFile(fileType)) {
            return new CodeFileLoader(codeTextSplitter);
        }else {
            return new TextFileLoader(characterTextSplitter);
        }
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/TextFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class TextFileLoader implements ResourceLoader{
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content, String kid){
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/WordLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
package org.ruoyi.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.ruoyi.chain.loader.ResourceLoader;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class WordLoader implements ResourceLoader {
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        XWPFDocument document = null;
        try {
            document = new XWPFDocument(inputStream);
            XWPFWordExtractor extractor = new XWPFWordExtractor(document);
            String content = extractor.getText();
            return content;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public List<String> getChunkList(String content, String kid) {
        return textSplitter.split(content, kid);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/CharacterTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package org.ruoyi.chain.split;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.chain.split.TextSplitter;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@Slf4j
@Primary
public class CharacterTextSplitter implements TextSplitter {
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Override
    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(knowledgeSeparator) && StringUtils.isNotBlank(knowledgeSeparator)) {
            // æŒ‰è‡ªå®šä¹‰åˆ†éš”符切分
            String[] chunks = content.split(knowledgeSeparator);
            chunkList.addAll(Arrays.asList(chunks));
        } else {
            int indexMin = 0;
            int len = content.length();
            int i = 0;
            int right = 0;
            while (true) {
                if (len > right) {
                    int begin = i * textBlockSize - overlapChar;
                    if (begin < indexMin) {
                        begin = indexMin;
                    }
                    int end = textBlockSize * (i + 1) + overlapChar;
                    if (end > len) {
                        end = len;
                    }
                    String chunk = content.substring(begin, end);
                    chunkList.add(chunk);
                    i++;
                    right = right + textBlockSize;
                } else {
                    break;
                }
            }
        }
        return chunkList;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/CodeTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class CodeTextSplitter implements TextSplitter {
    @Override
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/MarkdownTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class MarkdownTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/TextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.split;
import java.util.List;
/**
 * æ–‡æœ¬åˆ‡åˆ†
 */
public interface TextSplitter {
    /**
     * æ–‡æœ¬åˆ‡åˆ†
     *
     * @param content æ–‡æœ¬å†…容
     * @param kid     çŸ¥è¯†åº“id
     * @return åˆ‡åˆ†åŽçš„æ–‡æœ¬åˆ—表
     */
    List<String> split(String content, String kid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/split/TokenTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class TokenTextSplitter implements TextSplitter {
    @Override
    public List<String> split(String content, String kid) {
        return null;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/constant/FileType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,91 @@
package org.ruoyi.constant;
public class FileType {
    public static final String TXT = "txt";
    public static final String CSV = "csv";
    public static final String MD = "md";
    public static final String DOC = "doc";
    public static final String DOCX = "docx";
    public static final String PDF = "pdf";
    public static final String LOG = "log";
    public static final String XML = "xml";
    public static final String JAVA = "java";
    public static final String HTML = "html";
    public static final String HTM = "htm";
    public static final String CSS = "css";
    public static final String JS = "js";
    public static final String PY = "py";
    public static final String CPP = "cpp";
    public static final String SQL = "sql";
    public static final String PHP = "php";
    public static final String RUBY = "ruby";
    public static final String C = "c";
    public static final String H = "h";
    public static final String HPP = "hpp";
    public static final String SWIFT = "swift";
    public static final String TS = "ts";
    public static final String RUST = "rs";
    public static final String PERL = "perl";
    public static final String SHELL = "shell";
    public static final String BAT = "bat";
    public static final String CMD = "cmd";
    public static final String PROPERTIES = "properties";
    public static final String INI = "ini";
    public static final String YAML = "yaml";
    public static final String YML = "yml";
    public static boolean isTextFile(String type){
        if (type.equalsIgnoreCase(TXT) || type.equalsIgnoreCase(CSV) || type.equalsIgnoreCase(PROPERTIES)
                || type.equalsIgnoreCase(INI) || type.equalsIgnoreCase(YAML) || type.equalsIgnoreCase(YML)
                || type.equalsIgnoreCase(LOG) || type.equalsIgnoreCase(XML)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isCodeFile(String type){
        if (type.equalsIgnoreCase(JAVA) || type.equalsIgnoreCase(HTML) || type.equalsIgnoreCase(HTM) || type.equalsIgnoreCase(JS) || type.equalsIgnoreCase(PY)
                || type.equalsIgnoreCase(CPP) || type.equalsIgnoreCase(SQL) || type.equalsIgnoreCase(PHP) || type.equalsIgnoreCase(RUBY)
                || type.equalsIgnoreCase(C) || type.equalsIgnoreCase(H) || type.equalsIgnoreCase(HPP) || type.equalsIgnoreCase(SWIFT)
                || type.equalsIgnoreCase(TS) || type.equalsIgnoreCase(RUST) || type.equalsIgnoreCase(PERL) || type.equalsIgnoreCase(SHELL)
                || type.equalsIgnoreCase(BAT) || type.equalsIgnoreCase(CMD) || type.equalsIgnoreCase(CSS)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isMdFile(String type){
        if (type.equalsIgnoreCase(MD)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isWord(String type){
        if (type.equalsIgnoreCase(DOC) || type.equalsIgnoreCase(DOCX)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isPdf(String type){
        if (type.equalsIgnoreCase(PDF)){
            return true;
        }
        else {
            return false;
        }
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeAttach.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
 * çŸ¥è¯†åº“附件对象 knowledge_attach
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_attach")
public class KnowledgeAttach extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    private String content;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
 * çŸ¥è¯†ç‰‡æ®µå¯¹è±¡ knowledge_fragment
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_fragment")
public class KnowledgeFragment extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    private Long idx;
    /**
     * æ–‡æ¡£å†…容
     */
    private String content;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
 * çŸ¥è¯†åº“对象 knowledge_info
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_info")
public class KnowledgeInfo extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    private String kname;
    /**
     * æ˜¯å¦å…¬å¼€çŸ¥è¯†åº“(0 å¦ 1是)
     */
    private Integer share;
    /**
     * æè¿°
     */
    private String description;
    /**
     * çŸ¥è¯†åˆ†éš”符
     */
    private String knowledgeSeparator;
    /**
     * æé—®åˆ†éš”符
     */
    private String questionSeparator;
    /**
     * é‡å å­—符数
     */
    private Long overlapChar;
    /**
     * çŸ¥è¯†åº“中检索的条数
     */
    private Long retrieveLimit;
    /**
     * æ–‡æœ¬å—大小
     */
    private Long textBlockSize;
    /**
     * å‘量库
     */
    private String vector;
    /**
     * å‘量模型
     */
    private String vectorModel;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeAttachBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.KnowledgeAttach;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * çŸ¥è¯†åº“附件业务对象 knowledge_attach
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeAttach.class, reverseConvertGenerate = false)
public class KnowledgeAttachBo extends BaseEntity {
    /**
     *
     */
    @NotNull(message = "不能为空", groups = { EditGroup.class })
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @NotBlank(message = "文档ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    @NotBlank(message = "文档名称不能为空", groups = { AddGroup.class, EditGroup.class })
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    @NotBlank(message = "文档类型不能为空", groups = { AddGroup.class, EditGroup.class })
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    @NotBlank(message = "文档内容不能为空", groups = { AddGroup.class, EditGroup.class })
    private String content;
    /**
     * å¤‡æ³¨
     */
    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeFragmentBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.KnowledgeFragment;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * çŸ¥è¯†ç‰‡æ®µä¸šåŠ¡å¯¹è±¡ knowledge_fragment
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeFragment.class, reverseConvertGenerate = false)
public class KnowledgeFragmentBo extends BaseEntity {
    /**
     *
     */
    @NotNull(message = "不能为空", groups = { EditGroup.class })
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @NotBlank(message = "文档ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    @NotBlank(message = "知识片段ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    @NotNull(message = "片段索引下标不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long idx;
    /**
     * æ–‡æ¡£å†…容
     */
    @NotBlank(message = "文档内容不能为空", groups = { AddGroup.class, EditGroup.class })
    private String content;
    /**
     * å¤‡æ³¨
     */
    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.domain.KnowledgeInfo;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * çŸ¥è¯†åº“业务对象 knowledge_info
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeInfo.class, reverseConvertGenerate = false)
public class KnowledgeInfoBo extends BaseEntity {
    /**
     *
     */
    @NotNull(message = "不能为空", groups = { EditGroup.class })
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    @NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    @NotBlank(message = "知识库名称不能为空", groups = { AddGroup.class, EditGroup.class })
    private String kname;
    /**
     * æ˜¯å¦å…¬å¼€çŸ¥è¯†åº“(0 å¦ 1是)
     */
    @NotNull(message = "是否公开知识库(0 å¦ 1是)不能为空", groups = { AddGroup.class, EditGroup.class })
    private Integer share;
    /**
     * æè¿°
     */
    @NotBlank(message = "描述不能为空", groups = { AddGroup.class, EditGroup.class })
    private String description;
    /**
     * çŸ¥è¯†åˆ†éš”符
     */
    @NotBlank(message = "知识分隔符不能为空", groups = { AddGroup.class, EditGroup.class })
    private String knowledgeSeparator;
    /**
     * æé—®åˆ†éš”符
     */
    @NotBlank(message = "提问分隔符不能为空", groups = { AddGroup.class, EditGroup.class })
    private String questionSeparator;
    /**
     * é‡å å­—符数
     */
    @NotNull(message = "重叠字符数不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long overlapChar;
    /**
     * çŸ¥è¯†åº“中检索的条数
     */
    @NotNull(message = "知识库中检索的条数不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long retrieveLimit;
    /**
     * æ–‡æœ¬å—大小
     */
    @NotNull(message = "文本块大小不能为空", groups = { AddGroup.class, EditGroup.class })
    private Long textBlockSize;
    /**
     * å‘量库
     */
    @NotBlank(message = "向量库不能为空", groups = { AddGroup.class, EditGroup.class })
    private String vector;
    /**
     * å‘量模型
     */
    @NotBlank(message = "向量模型不能为空", groups = { AddGroup.class, EditGroup.class })
    private String vectorModel;
    /**
     * å¤‡æ³¨
     */
    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeAttachVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package org.ruoyi.domain.vo;
import org.ruoyi.domain.KnowledgeAttach;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†åº“附件视图对象 knowledge_attach
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeAttach.class)
public class KnowledgeAttachVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @ExcelProperty(value = "文档ID")
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    @ExcelProperty(value = "文档名称")
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    @ExcelProperty(value = "文档类型")
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    @ExcelProperty(value = "文档内容")
    private String content;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeFragmentVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
package org.ruoyi.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.domain.KnowledgeFragment;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†ç‰‡æ®µè§†å›¾å¯¹è±¡ knowledge_fragment
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeFragment.class)
public class KnowledgeFragmentVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @ExcelProperty(value = "文档ID")
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    @ExcelProperty(value = "知识片段ID")
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    @ExcelProperty(value = "片段索引下标")
    private Long idx;
    /**
     * æ–‡æ¡£å†…容
     */
    @ExcelProperty(value = "文档内容")
    private String content;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/vo/KnowledgeInfoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,119 @@
package org.ruoyi.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.common.excel.annotation.ExcelDictFormat;
import org.ruoyi.common.excel.convert.ExcelDictConvert;
import org.ruoyi.domain.KnowledgeInfo;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†åº“视图对象 knowledge_info
 *
 * @author ageerle
 * @date 2025-04-08
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeInfo.class)
public class KnowledgeInfoVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    @ExcelProperty(value = "用户ID")
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    @ExcelProperty(value = "知识库名称")
    private String kname;
    /**
     * æ˜¯å¦å…¬å¼€çŸ¥è¯†åº“(0 å¦ 1是)
     */
    @ExcelProperty(value = "是否公开知识库", converter = ExcelDictConvert.class)
    @ExcelDictFormat(readConverterExp = "0=,否=,1=是")
    private Integer 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;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String remark;
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/mapper/KnowledgeAttachMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.mapper;
import org.ruoyi.domain.KnowledgeAttach;
import org.ruoyi.domain.vo.KnowledgeAttachVo;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * çŸ¥è¯†åº“附件Mapper接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface KnowledgeAttachMapper extends BaseMapperPlus<KnowledgeAttach, KnowledgeAttachVo> {
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/mapper/KnowledgeFragmentMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.mapper;
import org.ruoyi.domain.KnowledgeFragment;
import org.ruoyi.domain.vo.KnowledgeFragmentVo;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * çŸ¥è¯†ç‰‡æ®µMapper接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface KnowledgeFragmentMapper extends BaseMapperPlus<KnowledgeFragment, KnowledgeFragmentVo> {
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/mapper/KnowledgeInfoMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.mapper;
import org.ruoyi.domain.KnowledgeInfo;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * çŸ¥è¯†åº“Mapper接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface KnowledgeInfoMapper extends BaseMapperPlus<KnowledgeInfo, KnowledgeInfoVo> {
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/EmbeddingService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package org.ruoyi.service;
import java.util.List;
public interface EmbeddingService {
    void storeEmbeddings(List<String> chunkList, String kid, String docId,List<String> fidList);
    void removeByDocId(String kid,String docId);
    void removeByKid(String kid);
    List<Double> getQueryVector(String query, String kid);
    void createSchema(String kid);
    void removeByKidAndFid(String kid, String fid);
    void saveFragment(String kid, String docId, String fid, String content);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.service;
import org.ruoyi.domain.bo.KnowledgeAttachBo;
import org.ruoyi.domain.vo.KnowledgeAttachVo;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†åº“附件Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IKnowledgeAttachService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件
     */
    KnowledgeAttachVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†åº“附件
     */
    Boolean insertByBo(KnowledgeAttachBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“附件
     */
    Boolean updateByBo(KnowledgeAttachBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“附件信息
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeFragmentService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.service;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.domain.vo.KnowledgeFragmentVo;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†ç‰‡æ®µService接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IKnowledgeFragmentService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µ
     */
    KnowledgeFragmentVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    TableDataInfo<KnowledgeFragmentVo> queryPageList(KnowledgeFragmentBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    List<KnowledgeFragmentVo> queryList(KnowledgeFragmentBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†ç‰‡æ®µ
     */
    Boolean insertByBo(KnowledgeFragmentBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†ç‰‡æ®µ
     */
    Boolean updateByBo(KnowledgeFragmentBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤çŸ¥è¯†ç‰‡æ®µä¿¡æ¯
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.service;
import org.ruoyi.domain.bo.KnowledgeInfoBo;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†åº“Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IKnowledgeInfoService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“
     */
    KnowledgeInfoVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†åº“
     */
    Boolean insertByBo(KnowledgeInfoBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“
     */
    Boolean updateByBo(KnowledgeInfoBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“信息
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/VectorStoreService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package org.ruoyi.service;
import java.util.List;
/**
 * å‘量存储
 */
public interface VectorStoreService {
    void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList);
    void removeByDocId(String kid, String docId);
    void removeByKid(String kid);
    List<String> nearest(List<Double> queryVector, String kid);
    List<String> nearest(String query, String kid);
    void newSchema(String kid);
    void removeByKidAndFid(String kid, String fid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/VectorizationService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.service;
import java.util.List;
/**
 * æ–‡æœ¬å‘量化
 */
public interface VectorizationService {
    List<List<Double>> batchVectorization(List<String> chunkList, String kid);
    List<Double> singleVectorization(String chunk, String kid);
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/EmbeddingServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package org.ruoyi.service.impl;
import lombok.AllArgsConstructor;
import org.ruoyi.service.EmbeddingService;
import org.ruoyi.service.VectorStoreService;
import org.ruoyi.service.VectorizationService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
@AllArgsConstructor
public class EmbeddingServiceImpl implements EmbeddingService {
    private final VectorStoreService vectorStore;
    private final VectorizationService vectorization;
    /**
     * ä¿å­˜å‘量数据库
     * @param chunkList         æ–‡æ¡£æŒ‰è¡Œåˆ‡åˆ†çš„片段
     * @param kid               çŸ¥è¯†åº“ID
     * @param docId             æ–‡æ¡£ID
     */
    @Override
    public void storeEmbeddings(List<String> chunkList, String kid, String docId,List<String> fidList) {
        List<List<Double>> vectorList = vectorization.batchVectorization(chunkList, kid);
        vectorStore.storeEmbeddings(chunkList,vectorList,kid,docId,fidList);
    }
    @Override
    public void removeByDocId(String kid,String docId) {
        vectorStore.removeByDocId(kid,docId);
    }
    @Override
    public void removeByKid(String kid) {
        vectorStore.removeByKid(kid);
    }
    @Override
    public List<Double> getQueryVector(String query, String kid) {
        return vectorization.singleVectorization(query,kid);
    }
    @Override
    public void createSchema(String kid) {
        vectorStore.newSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        vectorStore.removeByKidAndFid(kid,fid);
    }
    @Override
    public void saveFragment(String kid, String docId, String fid, String content) {
        List<String> chunkList = new ArrayList<>();
        List<String> fidList = new ArrayList<>();
        chunkList.add(content);
        fidList.add(fid);
        storeEmbeddings(chunkList,kid,docId,fidList);
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.vo.KnowledgeAttachVo;
import org.springframework.stereotype.Service;
import org.ruoyi.domain.bo.KnowledgeAttachBo;
import org.ruoyi.domain.KnowledgeAttach;
import org.ruoyi.mapper.KnowledgeAttachMapper;
import org.ruoyi.service.IKnowledgeAttachService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * çŸ¥è¯†åº“附件Service业务层处理
 *
 * @author ageerle
 * @date 2025-04-08
 */
@RequiredArgsConstructor
@Service
public class KnowledgeAttachServiceImpl implements IKnowledgeAttachService {
    private final KnowledgeAttachMapper baseMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件
     */
    @Override
    public KnowledgeAttachVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    @Override
    public TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
        Page<KnowledgeAttachVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    @Override
    public List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo) {
        LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<KnowledgeAttach> buildQueryWrapper(KnowledgeAttachBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeAttach> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeAttach::getKid, bo.getKid());
        lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeAttach::getDocId, bo.getDocId());
        lqw.like(StringUtils.isNotBlank(bo.getDocName()), KnowledgeAttach::getDocName, bo.getDocName());
        lqw.eq(StringUtils.isNotBlank(bo.getDocType()), KnowledgeAttach::getDocType, bo.getDocType());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeAttach::getContent, bo.getContent());
        return lqw;
    }
    /**
     * æ–°å¢žçŸ¥è¯†åº“附件
     */
    @Override
    public Boolean insertByBo(KnowledgeAttachBo bo) {
        KnowledgeAttach add = MapstructUtils.convert(bo, KnowledgeAttach.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“附件
     */
    @Override
    public Boolean updateByBo(KnowledgeAttachBo bo) {
        KnowledgeAttach update = MapstructUtils.convert(bo, KnowledgeAttach.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeAttach entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“附件
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeFragmentServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.vo.KnowledgeFragmentVo;
import org.springframework.stereotype.Service;
import org.ruoyi.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.domain.KnowledgeFragment;
import org.ruoyi.mapper.KnowledgeFragmentMapper;
import org.ruoyi.service.IKnowledgeFragmentService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * çŸ¥è¯†ç‰‡æ®µService业务层处理
 *
 * @author ageerle
 * @date 2025-04-08
 */
@RequiredArgsConstructor
@Service
public class KnowledgeFragmentServiceImpl implements IKnowledgeFragmentService {
    private final KnowledgeFragmentMapper baseMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public KnowledgeFragmentVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    @Override
    public TableDataInfo<KnowledgeFragmentVo> queryPageList(KnowledgeFragmentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeFragment> lqw = buildQueryWrapper(bo);
        Page<KnowledgeFragmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    @Override
    public List<KnowledgeFragmentVo> queryList(KnowledgeFragmentBo bo) {
        LambdaQueryWrapper<KnowledgeFragment> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<KnowledgeFragment> buildQueryWrapper(KnowledgeFragmentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeFragment> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeFragment::getKid, bo.getKid());
        lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeFragment::getDocId, bo.getDocId());
        lqw.eq(StringUtils.isNotBlank(bo.getFid()), KnowledgeFragment::getFid, bo.getFid());
        lqw.eq(bo.getIdx() != null, KnowledgeFragment::getIdx, bo.getIdx());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeFragment::getContent, bo.getContent());
        return lqw;
    }
    /**
     * æ–°å¢žçŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean insertByBo(KnowledgeFragmentBo bo) {
        KnowledgeFragment add = MapstructUtils.convert(bo, KnowledgeFragment.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean updateByBo(KnowledgeFragmentBo bo) {
        KnowledgeFragment update = MapstructUtils.convert(bo, KnowledgeFragment.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeFragment entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.springframework.stereotype.Service;
import org.ruoyi.domain.bo.KnowledgeInfoBo;
import org.ruoyi.domain.KnowledgeInfo;
import org.ruoyi.mapper.KnowledgeInfoMapper;
import org.ruoyi.service.IKnowledgeInfoService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * çŸ¥è¯†åº“Service业务层处理
 *
 * @author ageerle
 * @date 2025-04-08
 */
@RequiredArgsConstructor
@Service
public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
    private final KnowledgeInfoMapper baseMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“
     */
    @Override
    public KnowledgeInfoVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    @Override
    public TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo);
        Page<KnowledgeInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    @Override
    public List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo) {
        LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    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(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(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;
    }
    /**
     * æ–°å¢žçŸ¥è¯†åº“
     */
    @Override
    public Boolean insertByBo(KnowledgeInfoBo bo) {
        KnowledgeInfo add = MapstructUtils.convert(bo, KnowledgeInfo.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“
     */
    @Override
    public Boolean updateByBo(KnowledgeInfoBo bo) {
        KnowledgeInfo update = MapstructUtils.convert(bo, KnowledgeInfo.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeInfo entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysCache.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysConfig.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysDept.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysDictData.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysDictType.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysLogininfor.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysMenu.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysNotice.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysNoticeState.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysOperLog.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysOss.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysOssConfig.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysPost.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysRole.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysRoleDept.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysRoleMenu.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysTenant.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysTenantPackage.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysUser.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,133 @@
package org.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.ruoyi.common.core.constant.UserConstants;
import org.ruoyi.common.tenant.core.TenantEntity;
import java.util.Date;
/**
 * ç”¨æˆ·å¯¹è±¡ sys_user
 *
 * @author Lion Li
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class SysUser extends TenantEntity {
    /**
     * ç”¨æˆ·ID
     */
    @TableId(value = "user_id")
    private Long userId;
    /**
     * éƒ¨é—¨ID
     */
    private Long deptId;
    /**
     * ç”¨æˆ·è´¦å·
     */
    private String userName;
    /**
     * ç”¨æˆ·å¥—餐
     */
    private String userPlan;
    /**
     * ç”¨æˆ·æ˜µç§°
     */
    private String nickName;
    /**
     * ç”¨æˆ·ç±»åž‹ï¼ˆsys_user系统用户)
     */
    private String userType;
    /**
     * ç”¨æˆ·é‚®ç®±
     */
    private String email;
    /**
     * æ‰‹æœºå·ç 
     */
    private String phonenumber;
    /**
     * ç”¨æˆ·æ€§åˆ«
     */
    private String sex;
    /**
     * ç”¨æˆ·å¤´åƒ
     */
    private String avatar;
    /**
     * å¯†ç 
     */
    @TableField(
        insertStrategy = FieldStrategy.NOT_EMPTY,
        updateStrategy = FieldStrategy.NOT_EMPTY,
        whereStrategy = FieldStrategy.NOT_EMPTY
    )
    private String password;
    /**
     * å¸å·çŠ¶æ€ï¼ˆ0正常 1停用)
     */
    private String status;
    /**
     * åˆ é™¤æ ‡å¿—(0代表存在 2代表删除)
     */
    @TableLogic
    private String delFlag;
    /**
     * æœ€åŽç™»å½•IP
     */
    private String loginIp;
    /**
     * æ³¨å†ŒåŸŸå
     */
    private String domainName;
    /**
     * æœ€åŽç™»å½•æ—¶é—´
     */
    private Date loginDate;
    /**
     * å¤‡æ³¨
     */
    private String remark;
    /** æ™®é€šç”¨æˆ·çš„æ ‡è¯†,对当前开发者帐号唯一。一个openid对应一个公众号或小程序 */
    private String openId;
    /** ç”¨æˆ·ä½™é¢ */
    private Double userBalance;
    /** ç”¨æˆ·ç­‰çº§ */
    private String userGrade;
    public SysUser(Long userId) {
        this.userId = userId;
    }
    public boolean isSuperAdmin() {
        return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysUserOnline.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysUserPost.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/SysUserRole.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysConfigBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysDeptBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysDictDataBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysDictTypeBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysLogininforBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysMenuBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysNoticeBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysNoticeStateBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysOperLogBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysOssBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysOssConfigBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysPostBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysRoleBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysTenantBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysTenantPackageBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysUserBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysUserPasswordBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/bo/SysUserProfileBo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/request/EmailRequest.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/request/OrderRequest.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/request/UserRequest.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/AvatarVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/CacheListInfoVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/CaptchaVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/DeptTreeSelectVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/LoginTenantVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/LoginVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MenuTreeSelectVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/MetaVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/ProfileVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/RouterVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysConfigVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysDeptVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysDictDataVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysDictTypeVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysLogininforVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysMenuVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysNoticeStateVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysNoticeVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
package org.ruoyi.system.domain.vo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.system.domain.SysNotice;
import java.io.Serial;
import java.io.Serializable;
/**
 * é€šçŸ¥å…¬å‘Šè§†å›¾å¯¹è±¡ sys_notice
 *
 * @author Michelle.Chung
 */
@Data
@AutoMapper(target = SysNotice.class)
public class SysNoticeVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * å…¬å‘ŠID
     */
    private Long noticeId;
    /**
     * å…¬å‘Šæ ‡é¢˜
     */
    private String noticeTitle;
    /**
     * å…¬å‘Šç±»åž‹ï¼ˆ1通知 2公告)
     */
    private String noticeType;
    /**
     * å…¬å‘Šå†…容
     */
    private String noticeContent;
    /**
     * å…¬å‘ŠçŠ¶æ€ï¼ˆ0正常 1关闭)
     */
    private String status;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysOperLogVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysOssConfigVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysOssUploadVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysOssVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysPostVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysRoleVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysTenantPackageVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysTenantVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserExportVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserImportVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserInfoVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserModelVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package org.ruoyi.system.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘è§†å›¾å¯¹è±¡ sys_user_model
 *
 * @author Lion Li
 * @date 2024-08-03
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SysUserModel.class)
public class SysUserModelVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * id
     */
    @ExcelProperty(value = "id")
    private Long id;
    /**
     * æ¨¡åž‹id
     */
    @ExcelProperty(value = "模型id")
    private Long mid;
    /**
     * ç”¨æˆ·ç»„id
     */
    @ExcelProperty(value = "用户组id")
    private Long gid;
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserOptionVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/SysUserVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/TenantListVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/domain/vo/UserInfoVo.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatAppStoreMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatConfigMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatGptsMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatMessageMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatPluginMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatTokenMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatVisitorUsageMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/ChatVoucherMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/CoverMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.system.domain.vo.cover.CoverVo;
/**
 * ç¿»å”±Mapper接口
 *
 * @author NSL
 * @since 2024-12-25
 */
public interface CoverMapper extends BaseMapperPlus<Cover, CoverVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/CoverPromptAudioMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.system.domain.vo.cover.CoverPromptAudioVo;
import java.util.List;
/**
 * ç¿»å”±ç”¨æˆ·å‚考音频Mapper接口
 *
 * @author NSL
 * @since 2024-12-25
 */
public interface CoverPromptAudioMapper extends BaseMapperPlus<CoverPromptAudio, CoverPromptAudioVo> {
    /**
     * èŽ·å–æœ€è¿‘ä¸€æ¬¡ç¿»å”±è®°å½•
     * @param userId ç”¨æˆ·id
     * @return ç¿»å”±è®°å½•
     */
    List<CoverPromptAudioVo> selectLatestVoByUserId(Long userId);
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/PaymentOrdersMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * æ”¯ä»˜è®¢å•Mapper接口
 *
 * @author Lion Li
 * @date 2024-04-16
 */
public interface PaymentOrdersMapper extends BaseMapperPlus<PaymentOrder, PaymentOrdersVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysConfigMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysDeptMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysDictDataMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysDictTypeMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysLogininforMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysMenuMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysModelMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * ç³»ç»Ÿæ¨¡åž‹Mapper接口
 *
 * @author Lion Li
 * @date 2024-04-04
 */
public interface SysModelMapper extends BaseMapperPlus<SysModel, SysModelVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysNoticeMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysNoticeStateMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysOperLogMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysOssConfigMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysOssMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysPackagePlanMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * å¥—餐管理Mapper接口
 *
 * @author Lion Li
 * @date 2024-05-05
 */
public interface SysPackagePlanMapper extends BaseMapperPlus<SysPackagePlan, SysPackagePlanVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysPostMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysRoleDeptMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysRoleMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysRoleMenuMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysTenantMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysTenantPackageMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysUserGroupMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Mapper接口
 *
 * @author Lion Li
 * @date 2024-08-03
 */
public interface SysUserGroupMapper extends BaseMapperPlus<SysUserGroup, SysUserGroupVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysUserMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysUserModelMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.system.domain.vo.SysUserModelVo;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Mapper接口
 *
 * @author Lion Li
 * @date 2024-08-03
 */
public interface SysUserModelMapper extends BaseMapperPlus<SysUserModel, SysUserModelVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysUserPostMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/SysUserRoleMapper.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/WxRobConfigMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Mapper接口
 *
 * @author Lion Li
 * @date 2024-05-01
 */
public interface WxRobConfigMapper extends BaseMapperPlus<WxRobConfig, WxRobConfigVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/WxRobKeywordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Mapper接口
 *
 * @author Lion Li
 * @date 2024-05-01
 */
public interface WxRobKeywordMapper extends BaseMapperPlus<WxRobKeyword, WxRobKeywordVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/mapper/WxRobRelationMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.system.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Mapper接口
 *
 * @author Lion Li
 * @date 2024-05-01
 */
public interface WxRobRelationMapper extends BaseMapperPlus<WxRobRelation, WxRobRelationVo> {
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/runner/SystemApplicationRunner.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package org.ruoyi.system.runner;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.system.service.ISysOssConfigService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
 * åˆå§‹åŒ– system æ¨¡å—对应业务数据
 *
 * @author Lion Li
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SystemApplicationRunner implements ApplicationRunner {
    private final ISysOssConfigService ossConfigService;
    @Override
    public void run(ApplicationArguments args) {
        ossConfigService.init();
        log.info("初始化OSS配置成功");
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysConfigService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDataScopeService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDeptService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictDataService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysDictTypeService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysLogininforService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysMenuService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysNoticeService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysNoticeStateService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysOperLogService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysOssConfigService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysOssService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysPermissionService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysPostService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysRoleService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysTenantPackageService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysTenantService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/ISysUserService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/SysLoginService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,433 @@
package org.ruoyi.system.service;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.math.NumberUtils;
import org.ruoyi.common.core.constant.Constants;
import org.ruoyi.common.core.constant.GlobalConstants;
import org.ruoyi.common.core.constant.TenantConstants;
import org.ruoyi.common.core.domain.dto.RoleDTO;
import org.ruoyi.common.core.domain.model.LoginUser;
import org.ruoyi.common.core.domain.model.VisitorLoginBody;
import org.ruoyi.common.core.domain.model.VisitorLoginUser;
import org.ruoyi.common.core.enums.*;
import org.ruoyi.common.core.exception.user.CaptchaException;
import org.ruoyi.common.core.exception.user.CaptchaExpireException;
import org.ruoyi.common.core.exception.user.UserException;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.utils.*;
import org.ruoyi.common.log.event.LogininforEvent;
import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.common.tenant.exception.TenantException;
import org.ruoyi.common.tenant.helper.TenantHelper;
import org.ruoyi.system.domain.SysUser;
import org.ruoyi.system.domain.bo.SysUserBo;
import org.ruoyi.system.domain.vo.LoginVo;
import org.ruoyi.system.domain.vo.SysTenantVo;
import org.ruoyi.system.domain.vo.SysUserVo;
import org.ruoyi.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
/**
 * ç™»å½•校验方法
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class SysLoginService {
    private final SysUserMapper userMapper;
    private final ISysPermissionService permissionService;
    private final ISysTenantService tenantService;
    private final WxMaService wxMaService;
    private final ISysUserService userService;
    private final ConfigService configService;
    @Value("${user.password.maxRetryCount}")
    private Integer maxRetryCount;
    @Value("${user.password.lockTime}")
    private Integer lockTime;
    /**
     * èŽ·å–å¾®ä¿¡
     * @param xcxCode èŽ·å–xcxCode
    */
    public String getOpenidFromCode(String xcxCode) {
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(xcxCode);
            return sessionInfo.getOpenid();
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * ç™»å½•验证
     *
     * @param username ç”¨æˆ·å
     * @param password å¯†ç 
     * @param code     éªŒè¯ç 
     * @param uuid     å”¯ä¸€æ ‡è¯†
     * @return ç»“æžœ
     */
    public String login(String tenantId, String username, String password, String code, String uuid) {
        SysUserVo user = loadUserByUsername(tenantId, username);
        checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
        // æ­¤å¤„可根据登录用户的数据不同 è‡ªè¡Œåˆ›å»º loginUser
        LoginUser loginUser = buildLoginUser(user);
        // ç”Ÿæˆtoken
        LoginHelper.loginByDevice(loginUser, DeviceType.PC);
        recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId());
        return StpUtil.getTokenValue();
    }
    public String smsLogin(String tenantId, String phonenumber, String smsCode) {
        // æ ¡éªŒç§Ÿæˆ·
        checkTenant(tenantId);
        // é€šè¿‡æ‰‹æœºå·æŸ¥æ‰¾ç”¨æˆ·
        SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber);
        checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
        // æ­¤å¤„可根据登录用户的数据不同 è‡ªè¡Œåˆ›å»º loginUser
        LoginUser loginUser = buildLoginUser(user);
        // ç”Ÿæˆtoken
        LoginHelper.loginByDevice(loginUser, DeviceType.APP);
        recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId());
        return StpUtil.getTokenValue();
    }
    public String emailLogin(String tenantId, String email, String emailCode) {
        // æ ¡éªŒç§Ÿæˆ·
        checkTenant(tenantId);
        // é€šè¿‡æ‰‹æœºå·æŸ¥æ‰¾ç”¨æˆ·
        SysUserVo user = loadUserByEmail(tenantId, email);
        checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
        // æ­¤å¤„可根据登录用户的数据不同 è‡ªè¡Œåˆ›å»º loginUser
        LoginUser loginUser = buildLoginUser(user);
        // ç”Ÿæˆtoken
        LoginHelper.loginByDevice(loginUser, DeviceType.APP);
        recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId());
        return StpUtil.getTokenValue();
    }
    /**
     * æ¸¸å®¢ç™»å½•
     *
     * @param loginBody
     * @return String
     * @Date 2023/5/18
     **/
    public void visitorLogin(VisitorLoginBody loginBody) {
        String openid = "";
        // PC端游客登录
        if (LoginUserType.PC.getCode().equals(loginBody.getType())) {
            openid = loginBody.getCode();
        } else {
            // å°ç¨‹åºåŒ¿åç™»å½•
            try {
                WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(loginBody.getCode());
                openid = session.getOpenid();
            } catch (WxErrorException e) {
                log.error(e.getMessage(), e);
            } finally {
                // æ¸…理ThreadLocal
                WxMaConfigHolder.remove();
            }
        }
    }
    public LoginVo mpLogin(String openid) {
        // ä½¿ç”¨ openid æŸ¥è¯¢ç»‘定用户 å¦‚未绑定用户 åˆ™æ ¹æ®ä¸šåŠ¡è‡ªè¡Œå¤„ç† ä¾‹å¦‚ åˆ›å»ºé»˜è®¤ç”¨æˆ·
        SysUserVo user = userService.selectUserByOpenId(openid);
        VisitorLoginUser loginUser = new VisitorLoginUser();
        if (ObjectUtil.isNull(user)) {
            SysUserBo sysUser = new SysUserBo();
            // æ”¹ä¸ºè‡ªå¢ž
            String name = "用户" + UUID.randomUUID().toString().replace("-", "");
            // è®¾ç½®é»˜è®¤ç”¨æˆ·å
            sysUser.setUserName(name);
            // è®¾ç½®é»˜è®¤æ˜µç§°
            sysUser.setNickName(name);
            // è®¾ç½®é»˜è®¤å¯†ç 
            sysUser.setPassword(BCrypt.hashpw("123456"));
            // è®¾ç½®å¾®ä¿¡openId
            sysUser.setOpenId(openid);
            String configValue = configService.getConfigValue("mail", "amount");
            // è®¾ç½®é»˜è®¤ä½™é¢
            sysUser.setUserBalance(NumberUtils.toDouble(configValue, 1));
            // æ³¨å†Œç”¨æˆ·,设置默认租户为0
            SysUser registerUser = userService.registerUser(sysUser, "0");
            // æž„建登录用户信息
            loginUser.setTenantId("0");
            loginUser.setUserId(registerUser.getUserId());
            loginUser.setUsername(registerUser.getUserName());
            loginUser.setUserType(UserType.APP_USER.getUserType());
            loginUser.setOpenid(openid);
            loginUser.setNickName(registerUser.getNickName());
        } else {
            // æ­¤å¤„可根据登录用户的数据不同 è‡ªè¡Œåˆ›å»º loginUser
            loginUser.setTenantId(user.getTenantId());
            loginUser.setUserId(user.getUserId());
            loginUser.setUsername(user.getUserName());
            loginUser.setUserType(user.getUserType());
            loginUser.setNickName(user.getNickName());
            loginUser.setAvatar(user.getWxAvatar());
            loginUser.setOpenid(openid);
        }
        // ç”Ÿæˆtoken
        LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
        recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        LoginVo loginVo = new LoginVo();
        // ç”Ÿæˆä»¤ç‰Œ
        loginVo.setToken(StpUtil.getTokenValue());
        loginVo.setUserInfo(loginUser);
        return loginVo;
    }
    /**
     * é€€å‡ºç™»å½•
     */
    public void logout() {
        try {
            LoginUser loginUser = LoginHelper.getLoginUser();
            if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
                // è¶…级管理员 ç™»å‡ºæ¸…除动态租户
                TenantHelper.clearDynamic();
            }
            StpUtil.logout();
            if (loginUser !=null) {
                recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
            }
        } catch (NotLoginException ignored) {
        }
    }
    /**
     * è®°å½•登录信息
     *
     * @param tenantId ç§Ÿæˆ·ID
     * @param username ç”¨æˆ·å
     * @param status   çŠ¶æ€
     * @param message  æ¶ˆæ¯å†…容
     */
    private void recordLogininfor(String tenantId, String username, String status, String message) {
        LogininforEvent logininforEvent = new LogininforEvent();
        logininforEvent.setTenantId(tenantId);
        logininforEvent.setUsername(username);
        logininforEvent.setStatus(status);
        logininforEvent.setMessage(message);
        logininforEvent.setRequest(ServletUtils.getRequest());
        SpringUtils.context().publishEvent(logininforEvent);
    }
    /**
     * æ ¡éªŒçŸ­ä¿¡éªŒè¯ç 
     */
    private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
        if (StringUtils.isBlank(code)) {
            recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        return code.equals(smsCode);
    }
    /**
     * æ ¡éªŒé‚®ç®±éªŒè¯ç 
     */
    private boolean validateEmailCode(String tenantId, String email, String emailCode) {
        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
        if (StringUtils.isBlank(code)) {
            recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        return code.equals(emailCode);
    }
    /**
     * æ ¡éªŒéªŒè¯ç 
     *
     * @param username ç”¨æˆ·å
     * @param code     éªŒè¯ç 
     * @param uuid     å”¯ä¸€æ ‡è¯†
     */
    public void validateCaptcha(String tenantId, String username, String code, String uuid) {
        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
        String captcha = RedisUtils.getCacheObject(verifyKey);
        RedisUtils.deleteObject(verifyKey);
        if (captcha == null) {
            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
            throw new CaptchaException();
        }
    }
    private SysUserVo loadUserByUsername(String tenantId, String username) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().select(SysUser::getUserName, SysUser::getStatus).eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId).eq(SysUser::getUserName, username));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户:{} ä¸å­˜åœ¨.", username);
            throw new UserException("user.not.exists", username);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户:{} å·²è¢«åœç”¨.", username);
            throw new UserException("user.blocked", username);
        }
        if (TenantHelper.isEnable()) {
            return userMapper.selectTenantUserByUserName(username, tenantId);
        }
        return userMapper.selectUserByUserName(username);
    }
    private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().select(SysUser::getPhonenumber, SysUser::getStatus).eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId).eq(SysUser::getPhonenumber, phonenumber));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户:{} ä¸å­˜åœ¨.", phonenumber);
            throw new UserException("user.not.exists", phonenumber);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户:{} å·²è¢«åœç”¨.", phonenumber);
            throw new UserException("user.blocked", phonenumber);
        }
        if (TenantHelper.isEnable()) {
            return userMapper.selectTenantUserByPhonenumber(phonenumber, tenantId);
        }
        return userMapper.selectUserByPhonenumber(phonenumber);
    }
    private SysUserVo loadUserByEmail(String tenantId, String email) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().select(SysUser::getPhonenumber, SysUser::getStatus).eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId).eq(SysUser::getEmail, email));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户:{} ä¸å­˜åœ¨.", email);
            throw new UserException("user.not.exists", email);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户:{} å·²è¢«åœç”¨.", email);
            throw new UserException("user.blocked", email);
        }
        if (TenantHelper.isEnable()) {
            return userMapper.selectTenantUserByEmail(email, tenantId);
        }
        return userMapper.selectUserByEmail(email);
    }
    /**
     * æž„建登录用户
     */
    private LoginUser buildLoginUser(SysUserVo user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setTenantId(user.getTenantId());
        loginUser.setUserId(user.getUserId());
        loginUser.setDeptId(user.getDeptId());
        loginUser.setUsername(user.getUserName());
        loginUser.setAvatar(user.getAvatar());
        loginUser.setUserType(user.getUserType());
        loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
        loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName());
        List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class);
        loginUser.setRoles(roles);
        return loginUser;
    }
    /**
     * è®°å½•登录信息
     *
     * @param userId ç”¨æˆ·ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ServletUtils.getClientIP());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(userId);
        userMapper.updateById(sysUser);
    }
    /**
     * ç™»å½•校验
     */
    private void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
        String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
        String loginFail = Constants.LOGIN_FAIL;
        // èŽ·å–ç”¨æˆ·ç™»å½•é”™è¯¯æ¬¡æ•°(可自定义限制策略 ä¾‹å¦‚: key + username + ip)
        Integer errorNumber = RedisUtils.getCacheObject(errorKey);
        // é”å®šæ—¶é—´å†…登录 åˆ™è¸¢å‡º
        if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) {
            recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
            throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
        }
        if (supplier.get()) {
            // æ˜¯å¦ç¬¬ä¸€æ¬¡
            errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
            // è¾¾åˆ°è§„定错误次数 åˆ™é”å®šç™»å½•
            if (errorNumber.equals(maxRetryCount)) {
                RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
                throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
            } else {
                // æœªè¾¾åˆ°è§„定错误次数 åˆ™é€’增
                RedisUtils.setCacheObject(errorKey, errorNumber);
                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
                throw new UserException(loginType.getRetryLimitCount(), errorNumber);
            }
        }
        // ç™»å½•成功 æ¸…空错误次数
        RedisUtils.deleteObject(errorKey);
    }
    private void checkTenant(String tenantId) {
        if (!TenantHelper.isEnable()) {
            return;
        }
        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
            return;
        }
        SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
        if (ObjectUtil.isNull(tenant)) {
            log.info("登录租户:{} ä¸å­˜åœ¨.", tenantId);
            throw new TenantException("tenant.not.exists");
        } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
            log.info("登录租户:{} å·²è¢«åœç”¨.", tenantId);
            throw new TenantException("tenant.blocked");
        } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) && new Date().after(tenant.getExpireTime())) {
            log.info("登录租户:{} å·²è¶…过有效期.", tenantId);
            throw new TenantException("tenant.expired");
        }
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/SysRegisterService.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysConfigServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDataScopeServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDeptServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictDataServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysLogininforServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysMenuServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysNoticeServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysNoticeStateServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysOperLogServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysOssConfigServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysOssServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysPermissionServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysPostServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysRoleServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysSensitiveServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysTenantPackageServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysTenantServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysUserGroupServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
package org.ruoyi.system.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.ruoyi.system.mapper.SysUserGroupMapper;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘Service业务层处理
 *
 * @author Lion Li
 * @date 2024-08-03
 */
@RequiredArgsConstructor
@Service
public class SysUserGroupServiceImpl implements ISysUserGroupService {
    private final SysUserGroupMapper baseMapper;
    /**
     * æŸ¥è¯¢ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘
     */
    @Override
    public SysUserGroupVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘åˆ—è¡¨
     */
    @Override
    public TableDataInfo<SysUserGroupVo> queryPageList(SysUserGroupBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysUserGroup> lqw = buildQueryWrapper(bo);
        Page<SysUserGroupVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘åˆ—è¡¨
     */
    @Override
    public List<SysUserGroupVo> queryList(SysUserGroupBo bo) {
        LambdaQueryWrapper<SysUserGroup> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<SysUserGroup> buildQueryWrapper(SysUserGroupBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysUserGroup> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getGroupName()), SysUserGroup::getGroupName, bo.getGroupName());
        lqw.eq(StringUtils.isNotBlank(bo.getUpdateIp()), SysUserGroup::getUpdateIp, bo.getUpdateIp());
        return lqw;
    }
    /**
     * æ–°å¢žã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘
     */
    @Override
    public Boolean insertByBo(SysUserGroupBo bo) {
        SysUserGroup add = MapstructUtils.convert(bo, SysUserGroup.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘
     */
    @Override
    public Boolean updateByBo(SysUserGroupBo bo) {
        SysUserGroup update = MapstructUtils.convert(bo, SysUserGroup.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(SysUserGroup entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤ã€è¯·å¡«å†™åŠŸèƒ½åç§°ã€‘
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/SysUserServiceImpl.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/AesUtils.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/AudioOkHttpUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/DesensitizationUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/HttpUtils.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/KeyUtils.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/OrderNumberGenerator.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/WddPptApi.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/WeChatScanHttpUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/WeixinApiUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
package org.ruoyi.system.util;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.system.domain.model.WeixinQrCode;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.time.LocalDateTime;
/**
 * @author https://www.wdbyte.com
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WeixinApiUtil {
    private final ConfigService configService;
    private static String QR_CODE_URL_PREFIX = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";
    private static String ACCESS_TOKEN = null;
    private static LocalDateTime ACCESS_TOKEN_EXPIRE_TIME = null;
    /**
     * äºŒç»´ç  Ticket è¿‡æœŸæ—¶é—´
     */
    private static int QR_CODE_TICKET_TIMEOUT = 10 * 60;
    /**
     * èŽ·å– access token
     *
     * @return
     */
    public synchronized String getAccessToken() {
        if (ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRE_TIME.isAfter(LocalDateTime.now())) {
            return ACCESS_TOKEN;
        }
        String api = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + getKey("appid") + "&secret="
            + getKey("secret");
        String result = HttpUtil.get(api);
        JSONObject jsonObject = JSON.parseObject(result);
        ACCESS_TOKEN = jsonObject.getString("access_token");
        ACCESS_TOKEN_EXPIRE_TIME = LocalDateTime.now().plusSeconds(jsonObject.getLong("expires_in") - 10);
        return ACCESS_TOKEN;
    }
    /**
     * èŽ·å–äºŒç»´ç  Ticket
     *
     * https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
     *
     * @return
     */
    public WeixinQrCode getQrCode() {
        String api = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + getAccessToken();
        String jsonBody = String.format("{\n"
            + "  \"expire_seconds\": %d,\n"
            + "  \"action_name\": \"QR_STR_SCENE\",\n"
            + "  \"action_info\": {\n"
            + "    \"scene\": {\n"
            + "      \"scene_str\": \"%s\"\n"
            + "    }\n"
            + "  }\n"
            + "}", QR_CODE_TICKET_TIMEOUT, KeyUtils.uuid32());
        String result = HttpUtil.post(api, jsonBody);
        log.info("get qr code params:{}", jsonBody);
        log.info("get qr code result:{}", result);
        WeixinQrCode weixinQrCode = JSON.parseObject(result, WeixinQrCode.class);
        weixinQrCode.setQrCodeUrl(QR_CODE_URL_PREFIX + URI.create(weixinQrCode.getTicket()).toASCIIString());
        return weixinQrCode;
    }
    public String getKey(String key) {
        return configService.getConfigValue("weixin", key);
    }
}
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/WeixinMsgUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/WeixinQrCodeCacheUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/util/XmlUtil.java
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/CoverMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/CoverPromptAudioMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/PaymentOrdersMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysConfigMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysDeptMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysDictDataMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysDictTypeMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysLogininforMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysMenuMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysModelMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysNoticeMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysNoticeStateMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysOperLogMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysOssConfigMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysOssMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysPackagePlanMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysPostMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysRoleDeptMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysRoleMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysRoleMenuMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysTenantMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysTenantPackageMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysUserMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysUserPostMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/SysUserRoleMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/WxRobConfigMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/WxRobKeywordMapper.xml
ruoyi-modules-api/ruoyi-system-api/src/main/resources/mapper/WxRobRelationMapper.xml
ruoyi-modules/pom.xml
@@ -20,7 +20,6 @@
        <module>ruoyi-demo</module>
        <module>ruoyi-chat</module>
        <module>ruoyi-system</module>
        <module>ruoyi-knowledge</module>
        <module>ruoyi-generator</module>
    </modules>
ruoyi-modules/ruoyi-chat/pom.xml
@@ -107,13 +107,27 @@
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-knowledge</artifactId>
            <artifactId>ruoyi-knowledge-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-chat-api</artifactId>
            <version>1.0.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.26</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/ChatController.java
@@ -5,11 +5,12 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.chat.ISseService;
import org.ruoyi.common.chat.domain.request.ChatRequest;
import org.ruoyi.common.chat.domain.request.Dall3Request;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
import org.ruoyi.common.chat.entity.files.UploadFileResponse;
import org.ruoyi.common.chat.entity.images.Item;
import org.ruoyi.common.chat.entity.whisper.WhisperResponse;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.domain.model.LoginUser;
@@ -17,8 +18,10 @@
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.system.domain.request.translation.TranslationRequest;
import org.ruoyi.system.service.ISseService;
import org.ruoyi.domain.bo.ChatMessageBo;
import org.ruoyi.domain.vo.ChatMessageVo;
import org.ruoyi.service.IChatMessageService;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@@ -26,7 +29,6 @@
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.List;
/**
 * æè¿°ï¼šèŠå¤©ç®¡ç†
@@ -55,7 +57,6 @@
        }
        return sseService.sseChat(chatRequest,request);
    }
    /**
     * ä¸Šä¼ æ–‡ä»¶
@@ -90,22 +91,6 @@
        return sseService.textToSpeed(textToSpeech);
    }
    /**
     * æ–‡æœ¬ç¿»è¯‘
     *
     * @param
     */
    @PostMapping("/translation")
    @ResponseBody
    public String translation(@RequestBody TranslationRequest translationRequest) {
        return sseService.translation(translationRequest);
    }
    @PostMapping("/dall3")
    @ResponseBody
    public R<List<Item>> dall3(@RequestBody @Valid Dall3Request request) {
        return R.ok(sseService.dall3(request));
    }
    /**
     * èŠå¤©è®°å½•
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/SubmitController.java
@@ -7,7 +7,7 @@
import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import org.apache.commons.lang3.math.NumberUtils;
import org.ruoyi.chat.dto.*;
import org.ruoyi.chat.domain.dto.*;
import org.ruoyi.chat.enums.ActionType;
import org.ruoyi.chat.util.MjOkHttpUtil;
import org.springframework.web.bind.annotation.PostMapping;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/TaskController.java
@@ -7,7 +7,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import org.ruoyi.chat.dto.TaskConditionDTO;
import org.ruoyi.chat.domain.dto.TaskConditionDTO;
import org.ruoyi.chat.util.MjOkHttpUtil;
import org.springframework.web.bind.annotation.*;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/BaseSubmitDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public abstract class BaseSubmitDTO {
   @ApiModelProperty("自定义参数")
   protected String state;
   @ApiModelProperty("回调地址, ä¸ºç©ºæ—¶ä½¿ç”¨å…¨å±€notifyHook")
   protected String notifyHook;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitActionDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel("变化任务提交参数")
public class SubmitActionDTO {
   private String customId;
   private String taskId;
    private String state;
    private String notifyHook;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitBlendDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.chat.enums.BlendDimensions;
import java.util.List;
@Data
@ApiModel("Blend提交参数")
@EqualsAndHashCode(callSuper = true)
public class SubmitBlendDTO extends BaseSubmitDTO {
   @ApiModelProperty(value = "图片base64数组", required = true, example = "[\"data:image/png;base64,xxx1\", \"data:image/png;base64,xxx2\"]")
   private List<String> base64Array;
   @ApiModelProperty(value = "比例: PORTRAIT(2:3); SQUARE(1:1); LANDSCAPE(3:2)", example = "SQUARE")
   private BlendDimensions dimensions = BlendDimensions.SQUARE;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitChangeDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.chat.enums.TaskAction;
@Data
@ApiModel("变化任务提交参数")
@EqualsAndHashCode(callSuper = true)
public class SubmitChangeDTO extends BaseSubmitDTO {
   @ApiModelProperty(value = "任务ID", required = true, example = "\"1320098173412546\"")
   private String taskId;
   @ApiModelProperty(value = "UPSCALE(放大); VARIATION(变换); REROLL(重新生成)", required = true,
         allowableValues = "UPSCALE, VARIATION, REROLL", example = "UPSCALE")
   private TaskAction action;
   @ApiModelProperty(value = "序号(1~4), action为UPSCALE,VARIATION时必传", allowableValues = "range[1, 4]", example = "1")
   private Integer index;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitDescribeDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@ApiModel("Describe提交参数")
@EqualsAndHashCode(callSuper = true)
public class SubmitDescribeDTO extends BaseSubmitDTO {
   @ApiModelProperty(value = "图片base64", required = true, example = "data:image/png;base64,xxx")
   private String base64;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitImagineDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@ApiModel("Imagine提交参数")
@EqualsAndHashCode(callSuper = true)
public class SubmitImagineDTO extends BaseSubmitDTO {
   @ApiModelProperty(value = "提示词", required = true, example = "Cat")
   private String prompt;
   @ApiModelProperty(value = "垫图base64数组")
   private List<String> base64Array;
   @ApiModelProperty(hidden = true)
   @Deprecated(since = "3.0", forRemoval = true)
   private String base64;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitModalDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("局部重绘提交参数")
public class SubmitModalDTO extends BaseSubmitDTO{
   private String maskBase64;
   private String taskId;
    private String prompt;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitShortenDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("prompt分析提交参数")
public class SubmitShortenDTO extends BaseSubmitDTO{
   private String botType;
    private String prompt;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/SubmitSimpleChangeDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@ApiModel("变化任务提交参数-simple")
@EqualsAndHashCode(callSuper = true)
public class SubmitSimpleChangeDTO extends BaseSubmitDTO {
   @ApiModelProperty(value = "变化描述: ID $action$index", required = true, example = "1320098173412546 U2")
   private String content;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/domain/dto/TaskConditionDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package org.ruoyi.chat.domain.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("任务查询参数")
public class TaskConditionDTO {
   private List<String> ids;
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/BaseSubmitDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitActionDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitBlendDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitChangeDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitDescribeDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitImagineDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitModalDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitShortenDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/SubmitSimpleChangeDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/dto/TaskConditionDTO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
package org.ruoyi.chat.listener;
import cn.hutool.core.collection.CollectionUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
import org.ruoyi.common.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import java.util.Objects;
/**
 * æè¿°ï¼šOpenAIEventSourceListener
 *
 * @author https:www.unfbx.com
 * @date 2023-02-22
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SSEEventSourceListener extends EventSourceListener {
    @Autowired(required = false)
    public SSEEventSourceListener(ResponseBodyEmitter emitter) {
        this.emitter = emitter;
    }
    private ResponseBodyEmitter emitter;
    private StringBuilder stringBuffer;
    private String modelName;
    /**
     * {@inheritDoc}
     */
    @Override
    public void onOpen(EventSource eventSource, Response response) {
        log.info("OpenAI建立sse连接...");
    }
    /**
     * {@inheritDoc}
     */
    @SneakyThrows
    @Override
    public void onEvent(@NotNull EventSource eventSource, String id, String type, String data) {
        try {
            if ("[DONE]".equals(data)) {
                //成功响应
                emitter.complete();
                // æ‰£é™¤è´¹ç”¨ (消耗字符 æ¨¡åž‹åç§°)
                return;
            }
            // è§£æžè¿”回内容
            ObjectMapper mapper = new ObjectMapper();
            ChatCompletionResponse completionResponse = mapper.readValue(data, ChatCompletionResponse.class);
            if(completionResponse == null || CollectionUtil.isEmpty(completionResponse.getChoices())){
                return;
            }
            Object content = completionResponse.getChoices().get(0).getDelta().getContent();
            if(content == null){
                content = completionResponse.getChoices().get(0).getDelta().getReasoningContent();
                if(content == null) return;
            }
            if(StringUtils.isEmpty(modelName)){
                modelName = completionResponse.getModel();
            }
            stringBuffer.append(content);
            emitter.send(data);
        } catch (Exception e) {
            log.error("sse信息推送失败{}内容:{}",e.getMessage(),data);
            eventSource.cancel();
        }
    }
    @Override
    public void onClosed(EventSource eventSource) {
        log.info("OpenAI关闭sse连接...");
    }
    @SneakyThrows
    @Override
    public void onFailure(EventSource eventSource, Throwable t, Response response) {
        if (Objects.isNull(response)) {
            return;
        }
        ResponseBody body = response.body();
        if (Objects.nonNull(body)) {
            log.error("OpenAI  sse连接异常data:{},异常:{}", body.string(), t);
        } else {
            log.error("OpenAI  sse连接异常data:{},异常:{}", response, t);
        }
        eventSource.cancel();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatCostService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package org.ruoyi.chat.service.chat;
import org.ruoyi.domain.bo.ChatMessageBo;
/**
 * è®¡è´¹ç®¡ç†Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IChatCostService {
    /**
     * æ ¹æ®æ¶ˆè€—çš„tokens扣除余额
     *
     * @param chatMessageBo
     * @return ç»“æžœ
     */
    void deductToken(ChatMessageBo chatMessageBo);
    /**
     * æ‰£é™¤ç”¨æˆ·çš„余额
     *
     */
    void deductUserBalance(Long userId, Double numberCost);
    /**
     * æ‰£é™¤ä»»åŠ¡è´¹ç”¨å¹¶ä¸”ä¿å­˜è®°å½•
     *
     * @param type ä»»åŠ¡ç±»åž‹
     * @param prompt ä»»åŠ¡æè¿°
     * @param cost æ‰£é™¤è´¹ç”¨
     */
    void taskDeduct(String type,String prompt, double cost);
    /**
     * åˆ¤æ–­ç”¨æˆ·æ˜¯å¦ä»˜è´¹
     */
    void checkUserGrade();
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/ISseService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package org.ruoyi.chat.service.chat;
import jakarta.servlet.http.HttpServletRequest;
import org.ruoyi.common.chat.domain.request.ChatRequest;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
import org.ruoyi.common.chat.entity.files.UploadFileResponse;
import org.ruoyi.common.chat.entity.whisper.WhisperResponse;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
 * ç”¨æˆ·èŠå¤©ç®¡ç†Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface ISseService {
    /**
     * å®¢æˆ·ç«¯å‘送消息到服务端
     * @param chatRequest è¯·æ±‚对象
     */
    SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request);
    /**
     * è¯­éŸ³è½¬æ–‡å­—
     * @param file è¯­éŸ³æ–‡ä»¶
     */
   WhisperResponse speechToTextTranscriptionsV2(MultipartFile file);
    /**
     * æ–‡å­—转语音
     *
     * @param textToSpeech æ–‡æœ¬ä¿¡æ¯
     * @return æµå¼è¯­éŸ³
     */
    ResponseEntity<Resource> textToSpeed(TextToSpeech textToSpeech);
    /**
     * ä¸Šä¼ æ–‡ä»¶åˆ°api服务器
     *
     * @param file æ–‡ä»¶ä¿¡æ¯
     * @return è¿”回文件信息
     */
    UploadFileResponse upload(MultipartFile file);
    /**
     * ä½¿ç”¨ollama调用本地模型
     * @param chatRequest å¯¹è¯ä¿¡æ¯
     * @return æµå¼è¾“出返回内容
     */
    SseEmitter ollamaChat(ChatRequest chatRequest);
    /**
     * ä¼ä¸šåº”用回复
     * @param prompt æç¤ºè¯
     * @return å›žå¤å†…容
     */
    String wxCpChat(String prompt);
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,292 @@
package org.ruoyi.chat.service.chat.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.google.protobuf.ServiceException;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.models.chat.OllamaChatMessage;
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.generate.OllamaStreamHandler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.ruoyi.chat.listener.SSEEventSourceListener;
import org.ruoyi.chat.service.chat.ISseService;
import org.ruoyi.common.chat.config.ChatConfig;
import org.ruoyi.common.chat.domain.request.ChatRequest;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.entity.files.UploadFileResponse;
import org.ruoyi.common.chat.entity.whisper.WhisperResponse;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.core.utils.file.FileUtils;
import org.ruoyi.common.core.utils.file.MimeTypeUtils;
import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
@RequiredArgsConstructor
public class SseServiceImpl implements ISseService {
    private OpenAiStreamClient openAiStreamClient;
    private final ChatConfig chatConfig;
    private final IChatModelService chatModelService;
    @Override
    public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter);
        // èŽ·å–å¯¹è¯æ¶ˆæ¯åˆ—è¡¨
        List<Message> messages = chatRequest.getMessages();
        try {
            if (StpUtil.isLogin()) {
                // é€šè¿‡æ¨¡åž‹åç§°æŸ¥è¯¢æ¨¡åž‹ä¿¡æ¯
                ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
                // æž„建api请求客户端
                openAiStreamClient = chatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
                // æ¨¡åž‹è®¾ç½®é»˜è®¤æç¤ºè¯
                // æ˜¯å¦å¼€å¯è”网查询
            }else {
                // æœªç™»å½•用户限制对话次数,默认5次
                String clientIp = ServletUtil.getClientIP((javax.servlet.http.HttpServletRequest) request,"X-Forwarded-For");
                int timeWindowInSeconds = 5;
                String redisKey = "visitor:" + clientIp;
                int count = 0;
                if (RedisUtils.getCacheObject(redisKey) == null) {
                    // å½“前访问次数
                    RedisUtils.setCacheObject(redisKey, count, Duration.ofSeconds(86400));
                }else {
                    count = RedisUtils.getCacheObject(redisKey);
                    if (count >= timeWindowInSeconds) {
                        throw new ServiceException("当日免费次数已用完");
                    }
                    count++;
                    RedisUtils.setCacheObject(redisKey, count);
                }
            }
            ChatCompletion completion = ChatCompletion
                    .builder()
                    .messages(messages)
                    .model(chatRequest.getModel())
                    .temperature(chatRequest.getTemperature())
                    .topP(chatRequest.getTop_p())
                    .stream(true)
                    .build();
            openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
            // ä¿å­˜æ¶ˆæ¯è®°å½• å¹¶æ‰£é™¤è´¹ç”¨
        } catch (Exception e) {
            String message = e.getMessage();
            sendErrorEvent(sseEmitter, message);
            return sseEmitter;
        }
        return sseEmitter;
    }
    /**
     * å‘送SSE错误事件的封装方法
     *
     * @param sseEmitter
     * @param errorMessage
     */
    private void sendErrorEvent(SseEmitter sseEmitter, String errorMessage) {
        SseEmitter.SseEventBuilder event = SseEmitter.event()
                .name("error")
                .data(errorMessage);
        try {
            sseEmitter.send(event);
        } catch (IOException e) {
            log.error("发送事件失败: {}", e.getMessage());
        }
        sseEmitter.complete();
    }
    /**
     * æ–‡å­—转语音
     */
    @Override
    public ResponseEntity<Resource> textToSpeed(TextToSpeech textToSpeech) {
        ResponseBody body = openAiStreamClient.textToSpeech(textToSpeech);
        if (body != null) {
            // å°†ResponseBody转换为InputStreamResource
            InputStreamResource resource = new InputStreamResource(body.byteStream());
            // åˆ›å»ºå¹¶è¿”回ResponseEntity
            return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType("audio/mpeg"))
                .body(resource);
        } else {
            // å¦‚æžœResponseBody为空,返回404状态码
            return ResponseEntity.notFound().build();
        }
    }
    /**
     * è¯­éŸ³è½¬æ–‡å­—
     */
    @Override
    public WhisperResponse speechToTextTranscriptionsV2(MultipartFile file) {
        // ç¡®ä¿æ–‡ä»¶ä¸ä¸ºç©º
        if (file.isEmpty()) {
            throw new IllegalStateException("Cannot convert an empty MultipartFile");
        }
        if (!FileUtils.isValidFileExtention(file, MimeTypeUtils.AUDIO__EXTENSION)) {
            throw new IllegalStateException("File Extention not supported");
        }
        // åˆ›å»ºä¸€ä¸ªæ–‡ä»¶å¯¹è±¡
        File fileA = new File(System.getProperty("java.io.tmpdir") + File.separator + file.getOriginalFilename());
        try {
            // å°† MultipartFile çš„内容写入文件
            file.transferTo(fileA);
        } catch (IOException e) {
            throw new RuntimeException("Failed to convert MultipartFile to File", e);
        }
        return openAiStreamClient.speechToTextTranscriptions(fileA);
    }
    @Override
    public UploadFileResponse upload(MultipartFile file) {
        if (file.isEmpty()) {
            throw new IllegalStateException("Cannot upload an empty MultipartFile");
        }
        if (!FileUtils.isValidFileExtention(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)) {
            throw new IllegalStateException("File Extention not supported");
        }
        openAiStreamClient = chatConfig.getOpenAiStreamClient();
        return openAiStreamClient.uploadFile("fine-tune", convertMultiPartToFile(file));
    }
    private File convertMultiPartToFile(MultipartFile multipartFile) {
        File file = null;
        try {
            // èŽ·å–åŽŸå§‹æ–‡ä»¶å
            String originalFileName = multipartFile.getOriginalFilename();
            // é»˜è®¤æ‰©å±•名
            String extension = ".tmp";
            // å°è¯•从原始文件名中获取扩展名
            if (originalFileName != null && originalFileName.contains(".")) {
                extension = originalFileName.substring(originalFileName.lastIndexOf("."));
            }
            // ä½¿ç”¨åŽŸå§‹æ–‡ä»¶çš„æ‰©å±•ååˆ›å»ºä¸´æ—¶æ–‡ä»¶
            Path tempFile = Files.createTempFile(null, extension);
            file = tempFile.toFile();
            // å°†MultipartFile的内容写入文件
            try (InputStream inputStream = multipartFile.getInputStream();
                 FileOutputStream outputStream = new FileOutputStream(file)) {
                int read;
                byte[] bytes = new byte[1024];
                while ((read = inputStream.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
            } catch (IOException e) {
                // å¤„理文件写入异常
                e.printStackTrace();
            }
        } catch (IOException e) {
            // å¤„理临时文件创建异常
            e.printStackTrace();
        }
        return file;
    }
    @Override
    public SseEmitter ollamaChat(ChatRequest chatRequest) {
        String[] parts = chatRequest.getModel().split("ollama-");
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        final SseEmitter emitter = new SseEmitter();
        String host = chatModelVo.getApiHost();
        List<Message> msgList = chatRequest.getMessages();
        List<OllamaChatMessage> messages = new ArrayList<>();
        for (Message message : msgList) {
            OllamaChatMessage ollamaChatMessage = new OllamaChatMessage();
            ollamaChatMessage.setRole(OllamaChatMessageRole.USER);
            ollamaChatMessage.setContent(message.getContent().toString());
            messages.add(ollamaChatMessage);
        }
        OllamaAPI api = new OllamaAPI(host);
        api.setRequestTimeoutSeconds(100);
        OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(parts[1]);
        OllamaChatRequestModel requestModel = builder
            .withMessages(messages)
            .build();
        // å¼‚步执行 OllAma API è°ƒç”¨
        CompletableFuture.runAsync(() -> {
            try {
                StringBuilder response = new StringBuilder();
                OllamaStreamHandler streamHandler = (s) -> {
                    String substr = s.substring(response.length());
                    response.append(substr);
                    System.out.println(substr);
                    try {
                        emitter.send(substr);
                    } catch (IOException e) {
                        sendErrorEvent(emitter, e.getMessage());
                    }
                };
                api.chat(requestModel, streamHandler);
                emitter.complete();
            } catch (Exception e) {
                sendErrorEvent(emitter, e.getMessage());
            }
        });
        return emitter;
    }
    @Override
    public String wxCpChat(String prompt) {
        List<Message> messageList = new ArrayList<>();
        Message message = Message.builder().role(Message.Role.USER).content(prompt).build();
        messageList.add(message);
        ChatCompletion chatCompletion = ChatCompletion
            .builder()
            .messages(messageList)
            .model("gpt-4o-mini")
            .stream(false)
            .build();
        ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion);
        return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorizer/BgeLargeVectorization.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package org.ruoyi.chat.service.knowledge.vectorizer;
import com.google.gson.Gson;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorizationService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class BgeLargeVectorization implements VectorizationService {
    String host = "http://localhost:11434/";
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList, String kid) {
        OllamaAPI ollamaAPI = new OllamaAPI(host);
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        List<Double> doubleVector;
        try {
            doubleVector = ollamaAPI.generateEmbeddings(new OllamaEmbeddingsRequestModel(knowledgeInfoVo.getVectorModel(), new Gson().toJson(chunkList)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        List<List<Double>> vectorList = new ArrayList<>();
        vectorList.add(doubleVector);
        return vectorList;
    }
    @Override
    public List<Double> singleVectorization(String chunk, String kid) {
        List<String> chunkList = new ArrayList<>();
        chunkList.add(chunk);
        List<List<Double>> vectorList = batchVectorization(chunkList, kid);
        return vectorList.get(0);
    }
    public static void main(String[] args) {
        OllamaAPI ollamaAPI = new OllamaAPI("http://localhost:11434/");
        List<String> chunkList = Arrays.asList("天很蓝", "海很深");
        List<Double> doubleVector;
        try {
            doubleVector = ollamaAPI.generateEmbeddings(new OllamaEmbeddingsRequestModel("quentinz/bge-large-zh-v1.5", new Gson().toJson(chunkList)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("=== " + doubleVector + " 1===");
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorizer/OpenAiVectorization.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,110 @@
package org.ruoyi.chat.service.knowledge.vectorizer;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.chat.config.ChatConfig;
import org.ruoyi.common.chat.entity.embeddings.Embedding;
import org.ruoyi.common.chat.entity.embeddings.EmbeddingResponse;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorizationService;
import org.ruoyi.system.domain.SysModel;
import org.ruoyi.system.service.ISysModelService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Component
@Slf4j
@RequiredArgsConstructor
public class OpenAiVectorization implements VectorizationService {
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Lazy
    @Resource
    private ISysModelService sysModelService;
    @Getter
    private OpenAiStreamClient openAiStreamClient;
    private final ChatConfig chatConfig;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList, String kid) {
        List<List<Double>> vectorList;
        // èŽ·å–çŸ¥è¯†åº“ä¿¡æ¯
        KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
        if(knowledgeInfoVo == null){
            log.warn("知识库不存在:请查检ID {}",kid);
            vectorList=new ArrayList<>();
            vectorList.add(new ArrayList<>());
            return vectorList;
        }
        SysModel sysModel = sysModelService.selectModelByName(knowledgeInfoVo.getVectorModel());
        String apiHost= sysModel.getApiHost();
        String apiKey= sysModel.getApiKey();
        openAiStreamClient = chatConfig.createOpenAiStreamClient(apiHost,apiKey);
        Embedding embedding = buildEmbedding(chunkList, knowledgeInfoVo);
        EmbeddingResponse embeddings = openAiStreamClient.embeddings(embedding);
        // å¤„理 OpenAI è¿”回的嵌入数据
        vectorList = processOpenAiEmbeddings(embeddings);
        return vectorList;
    }
    /**
     * æž„建 Embedding å¯¹è±¡
     */
    private Embedding buildEmbedding(List<String> chunkList, KnowledgeInfoVo knowledgeInfoVo) {
        return Embedding.builder()
                .input(chunkList)
                .model(knowledgeInfoVo.getVectorModel())
                .build();
    }
    /**
     * å¤„理 OpenAI è¿”回的嵌入数据
     */
    private List<List<Double>> processOpenAiEmbeddings(EmbeddingResponse embeddings) {
        List<List<Double>> vectorList = new ArrayList<>();
        embeddings.getData().forEach(data -> {
            List<BigDecimal> vector = data.getEmbedding();
            List<Double> doubleVector = convertToDoubleList(vector);
            vectorList.add(doubleVector);
        });
        return vectorList;
    }
    /**
     * å°† BigDecimal è½¬æ¢ä¸º Double åˆ—表
     */
    private List<Double> convertToDoubleList(List<BigDecimal> vector) {
        return vector.stream()
                .map(BigDecimal::doubleValue)
                .collect(Collectors.toList());
    }
    @Override
    public List<Double> singleVectorization(String chunk, String kid) {
        List<String> chunkList = new ArrayList<>();
        chunkList.add(chunk);
        List<List<Double>> vectorList = batchVectorization(chunkList, kid);
        return vectorList.get(0);
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorizer/VectorizationFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package org.ruoyi.chat.service.knowledge.vectorizer;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorizationService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
/**
 * æ–‡æœ¬å‘量化
 * @author huangkh
 */
@Component
@Slf4j
public class VectorizationFactory {
    private final OpenAiVectorization openAiVectorization;
    private final BgeLargeVectorization bgeLargeVectorization;
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    public VectorizationFactory(OpenAiVectorization openAiVectorization, BgeLargeVectorization bgeLargeVectorization) {
        this.openAiVectorization = openAiVectorization;
        this.bgeLargeVectorization = bgeLargeVectorization;
    }
    public VectorizationService getEmbedding(String kid){
        String vectorModel = "text-embedding-3-small";
        if (StrUtil.isNotEmpty(kid)) {
            KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(kid));
            if (knowledgeInfoVo != null && StrUtil.isNotEmpty(knowledgeInfoVo.getVectorModel())) {
                vectorModel = knowledgeInfoVo.getVectorModel();
            }
        }
        return switch (vectorModel) {
            case "quentinz/bge-large-zh-v1.5" -> bgeLargeVectorization;
            default -> openAiVectorization;
        };
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorstore/MilvusVectorStore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,397 @@
package org.ruoyi.chat.service.knowledge.vectorstore;
import io.milvus.client.MilvusServiceClient;
import io.milvus.grpc.DataType;
import io.milvus.grpc.DescribeIndexResponse;
import io.milvus.grpc.MutationResult;
import io.milvus.grpc.SearchResults;
import io.milvus.param.*;
import io.milvus.param.collection.*;
import io.milvus.param.dml.DeleteParam;
import io.milvus.param.dml.InsertParam;
import io.milvus.param.dml.SearchParam;
import io.milvus.param.index.CreateIndexParam;
import io.milvus.param.index.DescribeIndexParam;
import io.milvus.param.partition.CreatePartitionParam;
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.ruoyi.service.VectorStoreService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class MilvusVectorStore implements VectorStoreService {
    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(Integer.parseInt(milvausPort))
                        .withDatabaseName("default")
                        .build()
        );
    }
    private void createSchema(String kid) {
        FieldType primaryField = FieldType.newBuilder()
                .withName("row_id")
                .withDataType(DataType.Int64)
                .withPrimaryKey(true)
                .withAutoID(true)
                .build();
        FieldType contentField = FieldType.newBuilder()
                .withName("content")
                .withDataType(DataType.VarChar)
                .withMaxLength(1000)
                .build();
        FieldType kidField = FieldType.newBuilder()
                .withName("kid")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType docIdField = FieldType.newBuilder()
                .withName("docId")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType fidField = FieldType.newBuilder()
                .withName("fid")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType vectorField = FieldType.newBuilder()
                .withName("fv")
                .withDataType(DataType.FloatVector)
                .withDimension(dimension)
                .build();
        CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder()
                .withCollectionName(collectionName + kid)
                .withDescription("local knowledge")
                .addFieldType(primaryField)
                .addFieldType(contentField)
                .addFieldType(kidField)
                .addFieldType(docIdField)
                .addFieldType(fidField)
                .addFieldType(vectorField)
                .build();
        milvusServiceClient.createCollection(createCollectionReq);
        // åˆ›å»ºå‘量的索引
        IndexType INDEX_TYPE = IndexType.IVF_FLAT;
        String INDEX_PARAM = "{\"nlist\":1024}";
        milvusServiceClient.createIndex(
                CreateIndexParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withFieldName("fv")
                        .withIndexType(INDEX_TYPE)
                        .withMetricType(MetricType.IP)
                        .withExtraParam(INDEX_PARAM)
                        .withSyncMode(Boolean.FALSE)
                        .build()
        );
    }
    @Override
    public void newSchema(String kid) {
        createSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        milvusServiceClient.delete(
                DeleteParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withExpr("fid == " + fid)
                        .build()
        );
    }
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList) {
        String fullCollectionName = collectionName + kid;
        // æ£€æŸ¥é›†åˆæ˜¯å¦å­˜åœ¨
        HasCollectionParam hasCollectionParam = HasCollectionParam.newBuilder()
                .withCollectionName(fullCollectionName)
                .build();
        R<Boolean> booleanR = milvusServiceClient.hasCollection(hasCollectionParam);
        if (booleanR.getStatus() == R.Status.Success.getCode()) {
            boolean collectionExists = booleanR.getData().booleanValue();
            if (!collectionExists) {
                // é›†åˆä¸å­˜åœ¨ï¼Œåˆ›å»ºé›†åˆ
                List<FieldType> fieldTypes = new ArrayList<>();
                // å‡è®¾è¿™é‡Œå®šä¹‰ id å­—段,根据实际情况修改
                FieldType idField = FieldType.newBuilder()
                        .withName("id")
                        .withDataType(DataType.Int64)
                        .withPrimaryKey(true)
                        .withAutoID(true)
                        .build();
                fieldTypes.add(idField);
                // å®šä¹‰å‘量字段
                FieldType vectorField = FieldType.newBuilder()
                        .withName("fv")
                        .withDataType(DataType.FloatVector)
                        .withDimension(vectorList.get(0).size())
                        .build();
                fieldTypes.add(vectorField);
                // å®šä¹‰å…¶ä»–字段
                FieldType contentField = FieldType.newBuilder()
                        .withName("content")
                        .withDataType(DataType.VarChar)
                        .withMaxLength(chunkList.size() * 1024) // æ ¹æ®å®žé™…情况修改
                        .build();
                fieldTypes.add(contentField);
                FieldType kidField = FieldType.newBuilder()
                        .withName("kid")
                        .withDataType(DataType.VarChar)
                        .withMaxLength(256) // æ ¹æ®å®žé™…情况修改
                        .build();
                fieldTypes.add(kidField);
                FieldType docIdField = FieldType.newBuilder()
                        .withName("docId")
                        .withDataType(DataType.VarChar)
                        .withMaxLength(256) // æ ¹æ®å®žé™…情况修改
                        .build();
                fieldTypes.add(docIdField);
                FieldType fidField = FieldType.newBuilder()
                        .withName("fid")
                        .withDataType(DataType.VarChar)
                        .withMaxLength(256) // æ ¹æ®å®žé™…情况修改
                        .build();
                fieldTypes.add(fidField);
                CreateCollectionParam createCollectionParam = CreateCollectionParam.newBuilder()
                        .withCollectionName(fullCollectionName)
                        .withFieldTypes(fieldTypes)
                        .build();
                R<RpcStatus> collection = milvusServiceClient.createCollection(createCollectionParam);
                if (collection.getStatus() == R.Status.Success.getCode()) {
                    System.out.println("集合 " + fullCollectionName + " åˆ›å»ºæˆåŠŸ");
                    // åˆ›å»ºç´¢å¼•
                    CreateIndexParam createIndexParam = CreateIndexParam.newBuilder()
                            .withCollectionName(fullCollectionName)
                            .withFieldName("fv") // å‘量字段名
                            .withIndexType(IndexType.IVF_FLAT) // ç´¢å¼•类型
                            .withMetricType(MetricType.IP)
                            .withExtraParam("{\"nlist\":1024}") // ç´¢å¼•参数
                            .build();
                    R<RpcStatus> indexResponse = milvusServiceClient.createIndex(createIndexParam);
                    if (indexResponse.getStatus() == R.Status.Success.getCode()) {
                        System.out.println("索引创建成功");
                    } else {
                        System.err.println("索引创建失败: " + indexResponse.getMessage());
                        return;
                    }
                } else {
                    System.err.println("集合创建失败: " + collection.getMessage());
                    return;
                }
            }
        } else {
            System.err.println("检查集合是否存在时出错: " + booleanR.getMessage());
            return;
        }
        if (StringUtils.isNotBlank(docId)) {
            milvusServiceClient.createPartition(
                    CreatePartitionParam.newBuilder()
                            .withCollectionName(fullCollectionName)
                            .withPartitionName(docId)
                            .build()
            );
        }
        List<List<Float>> vectorFloatList = new ArrayList<>();
        List<String> kidList = new ArrayList<>();
        List<String> docIdList = new ArrayList<>();
        for (int i = 0; i < Math.min(chunkList.size(), vectorList.size()); i++) {
            List<Double> vector = vectorList.get(i);
            List<Float> vfList = new ArrayList<>();
            for (int j = 0; j < vector.size(); j++) {
                Double value = vector.get(j);
                vfList.add(value.floatValue());
            }
            vectorFloatList.add(vfList);
            kidList.add(kid);
            docIdList.add(docId);
        }
        List<InsertParam.Field> fields = new ArrayList<>();
        fields.add(new InsertParam.Field("content", chunkList));
        fields.add(new InsertParam.Field("kid", kidList));
        fields.add(new InsertParam.Field("docId", docIdList));
        fields.add(new InsertParam.Field("fid", fidList));
        fields.add(new InsertParam.Field("fv", vectorFloatList));
        InsertParam insertParam = InsertParam.newBuilder()
                .withCollectionName(fullCollectionName)
                .withPartitionName(docId)
                .withFields(fields)
                .build();
        System.out.println("=========================");
        R<MutationResult> insert = milvusServiceClient.insert(insertParam);
        if (insert.getStatus() == R.Status.Success.getCode()) {
            System.out.println("插入成功,插入的行数: " + insert.getData().getInsertCnt());
        } else {
            System.err.println("插入失败: " + insert.getMessage());
        }
        System.out.println("=========================");
        // milvus在将数据装载到内存后才能进行向量计算.
        LoadCollectionParam loadCollectionParam = LoadCollectionParam.newBuilder()
                .withCollectionName(fullCollectionName)
                .build();
        R<RpcStatus> loadResponse = milvusServiceClient.loadCollection(loadCollectionParam);
        if (loadResponse.getStatus() != R.Status.Success.getCode()) {
            System.err.println("加载集合 " + fullCollectionName + " åˆ°å†…存时出错:" + loadResponse.getMessage());
        }
//        milvusServiceClient.loadCollection(LoadCollectionParam.newBuilder().withCollectionName(fullCollectionName).build());
    }
    @Override
    public void removeByDocId(String kid, String docId) {
        milvusServiceClient.delete(
                DeleteParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withExpr("1 == 1")
                        .withPartitionName(docId)
                        .build()
        );
    }
    @Override
    public void removeByKid(String kid) {
        milvusServiceClient.dropCollection(
                DropCollectionParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .build()
        );
    }
    @Override
    public List<String> nearest(List<Double> queryVector, String kid) {
        String fullCollectionName = collectionName + kid;
        HasCollectionParam hasCollectionParam = HasCollectionParam.newBuilder()
                .withCollectionName(fullCollectionName)
                .build();
        R<Boolean> booleanR = milvusServiceClient.hasCollection(hasCollectionParam);
        if (booleanR.getStatus() != R.Status.Success.getCode() || !booleanR.getData().booleanValue()) {
            System.err.println("集合 " + fullCollectionName + " ä¸å­˜åœ¨æˆ–检查集合存在性时出错。");
            return new ArrayList<>();
        }
        DescribeIndexParam describeIndexParam = DescribeIndexParam.newBuilder().withCollectionName(fullCollectionName).build();
        R<DescribeIndexResponse> describeIndexResponseR = milvusServiceClient.describeIndex(describeIndexParam);
        if (describeIndexResponseR.getStatus() == R.Status.Success.getCode()) {
            System.out.println("索引信息: " + describeIndexResponseR.getData().getIndexDescriptionsCount());
        } else {
            System.err.println("获取索引失败: " + describeIndexResponseR.getMessage());
        }
//        // åŠ è½½é›†åˆåˆ°å†…å­˜
//        LoadCollectionParam loadCollectionParam = LoadCollectionParam.newBuilder()
//                .withCollectionName(fullCollectionName)
//                .build();
//        R<RpcStatus> loadResponse = milvusServiceClient.loadCollection(loadCollectionParam);
//        if (loadResponse.getStatus() != R.Status.Success.getCode()) {
//            System.err.println("加载集合 " + fullCollectionName + " åˆ°å†…存时出错:" + loadResponse.getMessage());
//            return new ArrayList<>();
//        }
        List<String> search_output_fields = Arrays.asList("content", "fv");
        List<Float> fv = new ArrayList<>();
        for (int i = 0; i < queryVector.size(); i++) {
            fv.add(queryVector.get(i).floatValue());
        }
        List<List<Float>> vectors = new ArrayList<>();
        vectors.add(fv);
        String search_param = "{\"nprobe\":10, \"offset\":0}";
        SearchParam searchParam = SearchParam.newBuilder()
                .withCollectionName(collectionName + kid)
                .withMetricType(MetricType.IP)
                .withOutFields(search_output_fields)
                .withTopK(10)
                .withVectors(vectors)
                .withVectorFieldName("fv")
                .withParams(search_param)
                .build();
        System.out.println("SearchParam: " + searchParam.toString());
        R<SearchResults> respSearch = milvusServiceClient.search(searchParam);
        if (respSearch.getStatus() == R.Status.Success.getCode()) {
            SearchResults searchResults = respSearch.getData();
            if (searchResults != null) {
                System.out.println(searchResults.getResults());
                SearchResultsWrapper wrapperSearch = new SearchResultsWrapper(searchResults.getResults());
                List<QueryResultsWrapper.RowRecord> rowRecords = wrapperSearch.getRowRecords();
                List<String> resultList = new ArrayList<>();
                if (rowRecords != null && !rowRecords.isEmpty()) {
                    for (QueryResultsWrapper.RowRecord rowRecord : rowRecords) {
                        String content = rowRecord.get("content").toString();
                        resultList.add(content);
                    }
                }
                return resultList;
            } else {
                System.err.println("搜索结果为空");
            }
        } else {
            System.err.println("搜索操作失败: " + respSearch.getMessage());
        }
        return new ArrayList<>();
    }
    /**
     * milvus ä¸æ”¯æŒé€šè¿‡æ–‡æœ¬æ£€ç´¢ç›¸ä¼¼æ€§
     *
     * @param query
     * @param kid
     * @return
     */
    @Override
    public List<String> nearest(String query, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorstore/VectorStoreFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package org.ruoyi.chat.service.knowledge.vectorstore;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.mapper.KnowledgeInfoMapper;
import org.ruoyi.service.VectorStoreService;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class VectorStoreFactory {
    private final WeaviateVectorStore weaviateVectorStore;
    private final MilvusVectorStore milvusVectorStore;
    @Resource
    private KnowledgeInfoMapper knowledgeInfoMapper;
    public VectorStoreFactory(WeaviateVectorStore weaviateVectorStore, MilvusVectorStore milvusVectorStore) {
        this.weaviateVectorStore = weaviateVectorStore;
        this.milvusVectorStore = milvusVectorStore;
    }
    public VectorStoreService getVectorStore(String kid){
        String vectorModel = "weaviate";
        if (StrUtil.isNotEmpty(kid)) {
            KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoMapper.selectVoById(Long.valueOf(kid));
            if (knowledgeInfoVo != null && StrUtil.isNotEmpty(knowledgeInfoVo.getVector())) {
                vectorModel = knowledgeInfoVo.getVector();
            }
        }
        if ("weaviate".equals(vectorModel)){
            return weaviateVectorStore;
        }else if ("milvus".equals(vectorModel)){
            return milvusVectorStore;
        }
        return null;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorstore/WeaviateVectorStore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,402 @@
package org.ruoyi.chat.service.knowledge.vectorstore;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONObject;
import com.google.gson.internal.LinkedTreeMap;
import io.weaviate.client.Config;
import io.weaviate.client.WeaviateClient;
import io.weaviate.client.base.Result;
import io.weaviate.client.v1.data.model.WeaviateObject;
import io.weaviate.client.v1.data.replication.model.ConsistencyLevel;
import io.weaviate.client.v1.filters.Operator;
import io.weaviate.client.v1.filters.WhereFilter;
import io.weaviate.client.v1.graphql.model.GraphQLResponse;
import io.weaviate.client.v1.graphql.query.argument.NearTextArgument;
import io.weaviate.client.v1.graphql.query.argument.NearVectorArgument;
import io.weaviate.client.v1.graphql.query.fields.Field;
import io.weaviate.client.v1.misc.model.Meta;
import io.weaviate.client.v1.misc.model.ReplicationConfig;
import io.weaviate.client.v1.misc.model.ShardingConfig;
import io.weaviate.client.v1.misc.model.VectorIndexConfig;
import io.weaviate.client.v1.schema.model.DataType;
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.common.core.service.ConfigService;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorStoreService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class WeaviateVectorStore implements VectorStoreService {
    private volatile String protocol;
    private volatile String host;
    private volatile String className;
    @Lazy
    @Resource
    private IKnowledgeInfoService knowledgeInfoService;
    @Lazy
    @Resource
    private ConfigService configService;
    @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() {
        Config config = new Config(protocol, host);
        WeaviateClient client = new WeaviateClient(config);
        return client;
    }
    public Result<Meta> getMeta() {
        WeaviateClient client = getClient();
        Result<Meta> meta = client.misc().metaGetter().run();
        if (meta.getError() == null) {
            System.out.printf("meta.hostname: %s\n", meta.getResult().getHostname());
            System.out.printf("meta.version: %s\n", meta.getResult().getVersion());
            System.out.printf("meta.modules: %s\n", meta.getResult().getModules());
        } else {
            System.out.printf("Error: %s\n", meta.getError().getMessages());
        }
        return meta;
    }
    public Result<Schema> getSchemas() {
        WeaviateClient client = getClient();
        Result<Schema> result = client.schema().getter().run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        } else {
            System.out.println(result.getResult());
        }
        return result;
    }
    public Result<Boolean> createSchema(String kid) {
        WeaviateClient client = getClient();
        VectorIndexConfig vectorIndexConfig = VectorIndexConfig.builder()
                .distance("cosine")
                .cleanupIntervalSeconds(300)
                .efConstruction(128)
                .maxConnections(64)
                .vectorCacheMaxObjects(500000L)
                .ef(-1)
                .skip(false)
                .dynamicEfFactor(8)
                .dynamicEfMax(500)
                .dynamicEfMin(100)
                .flatSearchCutoff(40000)
                .build();
        ShardingConfig shardingConfig = ShardingConfig.builder()
                .desiredCount(3)
                .desiredVirtualCount(128)
                .function("murmur3")
                .key("_id")
                .strategy("hash")
                .virtualPerPhysical(128)
                .build();
        ReplicationConfig replicationConfig = ReplicationConfig.builder()
                .factor(1)
                .build();
        JSONObject classModuleConfigValue = new JSONObject();
        classModuleConfigValue.put("vectorizeClassName", false);
        JSONObject classModuleConfig = new JSONObject();
        classModuleConfig.put("text2vec-transformers", classModuleConfigValue);
        JSONObject propertyModuleConfigValueSkipTrue = new JSONObject();
        propertyModuleConfigValueSkipTrue.put("vectorizePropertyName", false);
        propertyModuleConfigValueSkipTrue.put("skip", true);
        JSONObject propertyModuleConfigSkipTrue = new JSONObject();
        propertyModuleConfigSkipTrue.put("text2vec-transformers", propertyModuleConfigValueSkipTrue);
        JSONObject propertyModuleConfigValueSkipFalse = new JSONObject();
        propertyModuleConfigValueSkipFalse.put("vectorizePropertyName", false);
        propertyModuleConfigValueSkipFalse.put("skip", false);
        JSONObject propertyModuleConfigSkipFalse = new JSONObject();
        propertyModuleConfigSkipFalse.put("text2vec-transformers", propertyModuleConfigValueSkipFalse);
        WeaviateClass clazz = WeaviateClass.builder()
                .className(className + kid)
                .description("local knowledge")
                .vectorIndexType("hnsw")
                .vectorizer("text2vec-transformers")
                .shardingConfig(shardingConfig)
                .vectorIndexConfig(vectorIndexConfig)
                .replicationConfig(replicationConfig)
                .moduleConfig(classModuleConfig)
                .properties(new ArrayList() {
                    {
                        add(Property.builder()
                                .dataType(new ArrayList() {
                                    {
                                        add(DataType.TEXT);
                                    }
                                })
                                .name("content")
                                .description("The content of the local knowledge,for search")
                                .moduleConfig(propertyModuleConfigSkipFalse)
                                .build());
                        add(Property.builder()
                                .dataType(new ArrayList() {
                                    {
                                        add(DataType.TEXT);
                                    }
                                })
                                .name("kid")
                                .description("The knowledge id of the local knowledge,for search")
                                .moduleConfig(propertyModuleConfigSkipTrue)
                                .build());
                        add(Property.builder()
                                .dataType(new ArrayList() {
                                    {
                                        add(DataType.TEXT);
                                    }
                                })
                                .name("docId")
                                .description("The doc id of the local knowledge,for search")
                                .moduleConfig(propertyModuleConfigSkipTrue)
                                .build());
                        add(Property.builder()
                                .dataType(new ArrayList() {
                                    {
                                        add(DataType.TEXT);
                                    }
                                })
                                .name("fid")
                                .description("The fragment id of the local knowledge,for search")
                                .moduleConfig(propertyModuleConfigSkipTrue)
                                .build());
                        add(Property.builder()
                                .dataType(new ArrayList() {
                                    {
                                        add(DataType.TEXT);
                                    }
                                })
                                .name("uuid")
                                .description("The uuid id of the local knowledge fragment(same with id properties),for search")
                                .moduleConfig(propertyModuleConfigSkipTrue)
                                .build());
                    } })
                .build();
        Result<Boolean> result = client.schema().classCreator().withClass(clazz).run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        }
        System.out.println(result.getResult());
        return result;
    }
    @Override
    public void newSchema(String kid) {
        createSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field fieldId = Field.builder().name("uuid").build();
        WhereFilter where = WhereFilter.builder()
                .path(new String[]{"fid"})
                .operator(Operator.Equal)
                .valueString(fid)
                .build();
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(fieldId)
                .withWhere(where)
                .run();
        LinkedTreeMap<String, Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String, ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m) {
            String uuid = linkedTreeMap.get("uuid").toString();
            resultList.add(uuid);
        }
        for (String uuid : resultList) {
            Result<Boolean> deleteResult = client.data().deleter()
                    .withID(uuid)
                    .withClassName(className + kid)
                    .withConsistencyLevel(ConsistencyLevel.ALL)  // default QUORUM
                    .run();
        }
    }
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList) {
        WeaviateClient client = getClient();
        for (int i = 0; i < Math.min(chunkList.size(), vectorList.size()); i++) {
            List<Double> vector = vectorList.get(i);
            Float[] vf = vector.stream().map(Double::floatValue).toArray(Float[]::new);
            Map<String, Object> dataSchema = new HashMap<>();
            dataSchema.put("content", chunkList.get(i));
            dataSchema.put("kid", kid);
            dataSchema.put("docId", docId);
            dataSchema.put("fid", fidList.get(i));
            String uuid = UUID.randomUUID().toString();
            dataSchema.put("uuid", uuid);
            Result<WeaviateObject> result = client.data().creator()
                    .withClassName(className + kid)
                    .withID(uuid)
                    .withVector(vf)
                    .withProperties(dataSchema)
                    .run();
        }
    }
    @Override
    public void removeByDocId(String kid, String docId) {
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field fieldId = Field.builder().name("uuid").build();
        WhereFilter where = WhereFilter.builder()
                .path(new String[]{"docId"})
                .operator(Operator.Equal)
                .valueString(docId)
                .build();
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(fieldId)
                .withWhere(where)
                .run();
        LinkedTreeMap<String, Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String, ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m) {
            String uuid = linkedTreeMap.get("uuid").toString();
            resultList.add(uuid);
        }
        for (String uuid : resultList) {
            Result<Boolean> deleteResult = client.data().deleter()
                    .withID(uuid)
                    .withClassName(className + kid)
                    .withConsistencyLevel(ConsistencyLevel.ALL)  // default QUORUM
                    .run();
        }
    }
    @Override
    public void removeByKid(String kid) {
        WeaviateClient client = getClient();
        Result<Boolean> result = client.schema().classDeleter().withClassName(className + kid).run();
        if (result.hasErrors()) {
            System.out.println("删除schema失败" + result.getError());
        } else {
            System.out.println("删除schema成功" + result.getResult());
        }
        log.info("drop schema by kid, result = {}", result);
    }
    @Override
    public List<String> nearest(List<Double> queryVector, String kid) {
        if (StringUtils.isBlank(kid)) {
            return new ArrayList<String>();
        }
        List<String> resultList = new ArrayList<>();
        Float[] vf = new Float[queryVector.size()];
        for (int j = 0; j < queryVector.size(); j++) {
            Double value = queryVector.get(j);
            vf[j] = value.floatValue();
        }
        WeaviateClient client = getClient();
        Field contentField = Field.builder().name("content").build();
        Field _additional = Field.builder()
                .name("_additional")
                .fields(new Field[]{
                        Field.builder().name("distance").build()
                }).build();
        NearVectorArgument nearVector = NearVectorArgument.builder()
                .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(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");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m) {
            String content = linkedTreeMap.get("content").toString();
            resultList.add(content);
        }
        return resultList;
    }
    @Override
    public List<String> nearest(String query, String kid) {
        if (StringUtils.isBlank(kid)) {
            return new ArrayList<String>();
        }
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field contentField = Field.builder().name("content").build();
        Field _additional = Field.builder()
                .name("_additional")
                .fields(new Field[]{
                        Field.builder().name("distance").build()
                }).build();
        NearTextArgument nearText = client.graphQL().arguments().nearTextArgBuilder()
                .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(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");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m) {
            String content = linkedTreeMap.get("content").toString();
            resultList.add(content);
        }
        return resultList;
    }
    public Result<Boolean> deleteSchema(String kid) {
        WeaviateClient client = getClient();
        Result<Boolean> result = client.schema().classDeleter().withClassName(className + kid).run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        } else {
            System.out.println(result.getResult());
        }
        return result;
    }
}
ruoyi-modules/ruoyi-device/pom.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/pom.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CodeFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CsvFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/FolderLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/GithubLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/JsonFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/MarkDownFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/PdfFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/ResourceLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/ResourceLoaderFactory.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/TextFileLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/WordLoader.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CharacterTextSplitter.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CodeTextSplitter.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/MarkdownTextSplitter.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TextSplitter.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TokenTextSplitter.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/BgeLargeVectorization.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/LocalModelsVectorization.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/OpenAiVectorization.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/Vectorization.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationFactory.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationType.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationWrapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/MilvusVectorStore.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStore.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreFactory.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreWrapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/WeaviateVectorStore.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/constant/FileType.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeAttach.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeFragment.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeInfo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeAttachBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeFragmentBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeInfoBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/req/KnowledgeInfoUploadRequest.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/request.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeAttachVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeFragmentVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeInfoVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeAttachMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeFragmentMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeInfoMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/EmbeddingService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeAttachService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeFragmentService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeInfoService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/EmbeddingServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeAttachServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeFragmentServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeInfoServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/pom.xml
@@ -118,17 +118,19 @@
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-pay</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.ollama4j</groupId>
            <artifactId>ollama4j</artifactId>
            <version>1.0.79</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system-api</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/AbstractBuilder.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/ImageBuilder.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/TextBuilder.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/GptConfig.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/OkHttpConfig.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/QqConfig.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxCpConfiguration.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxCpProperties.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxMaConfiguration.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxMaProperties.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatConfigController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatGptsController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatMessageController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatPluginController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatStoreController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatVisitorUsageController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatVoucherController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/KnowledgeController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/PayController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/PaymentOrdersController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysModelController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysNoticeController.java
@@ -16,7 +16,7 @@
import org.springframework.web.bind.annotation.*;
/**
 * å…¬å‘Š ä¿¡æ¯æ“ä½œå¤„ç†
 * å…¬å‘Šä¿¡æ¯æ“ä½œå¤„理
 *
 * @author Lion Li
 */
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysPackagePlanController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserGroupController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserModelController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WeChatController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WeixinServerController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WeixinUserController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WxRobConfigController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WxRobKeywordController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/wxsingle/WxJsController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/wxsingle/WxPortalController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/Cover.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/CoverPromptAudio.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/GenerateLuma.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/GenerateLyric.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/GenerateSuno.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/PaymentOrder.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/SysModel.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/SysPackagePlan.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/SysUser.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/SysUserGroup.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/SysUserModel.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/WxRobConfig.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/WxRobKeyword.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/WxRobRelation.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/PaymentOrdersBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/SysModelBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/SysPackagePlanBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/SysUserGroupBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/SysUserModelBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/WxRobConfigBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/WxRobKeywordBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/WxRobRelationBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/model/ApiResult.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/model/ReceiveMessage.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/model/WeixinQrCode.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/request/translation/TranslationRequest.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/PaymentOrdersVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/SysModelVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/SysNoticeVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/SysPackagePlanVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/SysUserGroupVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/SysUserModelVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/WxRobConfigVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/WxRobKeywordVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/WxRobRelationVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverCallbackVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverParamVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverPromptAudioVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/MusicVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptAllQueryDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGenerateContentDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGenerateOutlineDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGeneratePptxDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptTemplateFilterDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptTemplateQueryDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/CustomerBigDecimalSerialize.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/MyMsgHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/AbstractHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/ContactChangeHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/EnterAgentHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/LocationHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/LogHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/MenuHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/MsgHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/NullHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/ScanHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/SubscribeHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/UnsubscribeHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/CustomerBigDecimalSerialize.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package org.ruoyi.system.listener;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Objects;
public class CustomerBigDecimalSerialize extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if(Objects.nonNull(value)) {
            //返回到前端的数据为数字类型,前端接收有可能丢失精度
            //gen.writeNumber(value.stripTrailingZeros());
            //返回到前端的数据为字符串类型
            gen.writeString(value.stripTrailingZeros().toPlainString());
            //去除0后缀,如果想统一进行保留精度,也可以采用类似处理
        }else {//如果为null的话,就写null
            gen.writeNull();
        }
    }
}
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/SSEEventSourceListener.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/CoverMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/CoverPromptAudioMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/PaymentOrdersMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/SysModelMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/SysPackagePlanMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/SysUserGroupMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/SysUserModelMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/WxRobConfigMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/WxRobKeywordMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/WxRobRelationMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/request/RoleListDto.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/request/RoleRequest.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/request/SimpleGenerateRequest.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/MetadataResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/PromptResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/RoleDataResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/RoleResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/SimpleGenerateDataResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/SimpleGenerateResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/rolelist/ChatAppStoreVO.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/rolelist/ContentResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/rolelist/RoleListResponse.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/runner/SystemApplicationRunner.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ICoverPromptAudioService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ICoverService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IPaymentOrdersService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IPptService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISseService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISysModelService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISysPackagePlanService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISysUserGroupService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISysUserModelService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IWxRobConfigService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IWxRobKeywordService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IWxRobRelationService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/SysLoginService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/WeixinUserService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/CoverPromptAudioServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/CoverServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/PaymentOrdersServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/PptServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SysModelServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SysPackagePlanServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SysUserGroupServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SysUserModelServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/WeixinUserServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/WxRobConfigServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/WxRobKeywordServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/WxRobRelationServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/util/WeixinApiUtil.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-weixin/pom.xml
ÎļþÒÑɾ³ý
script/docker/localModels/Dockerfile
ÎļþÒÑɾ³ý
script/docker/localModels/app.py
ÎļþÒÑɾ³ý
script/docker/localModels/remade.md
ÎļþÒÑɾ³ý
script/docker/localModels/requirements.txt
ÎļþÒÑɾ³ý