| | |
| | | <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> |
| | |
| | | <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> |
| | | |
| | |
| | | <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> |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | <!-- AIç»ç» --> |
| | | <dependency> |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-chat</artifactId> |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | |
| | | |
| | | |
| | | <!-- æ¯ä»æ¨¡å --> |
| | | <dependency> |
| | |
| | | <version>${revision}</version> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </dependencyManagement> |
| | | |
| | | </project> |
| | |
| | | </exclusion> |
| | | </exclusions> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>junit</groupId> |
| | | <artifactId>junit</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>cn.bigmodel.openapi</groupId> |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | </properties> |
| | | |
| | | <dependencies> |
| | | |
| | | <!-- ç³»ç»æ ¸å¿æ¨¡å --> |
| | | <dependency> |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- mybaitsåºç¡æ¨¡å --> |
| | | <dependency> |
| | |
| | | <artifactId>ruoyi-common-mybatis</artifactId> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- è±ææ¨¡å --> |
| | | <dependency> |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-sensitive</artifactId> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- excel模å--> |
| | | <dependency> |
| | |
| | | <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> |
| | |
| | | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| | | </properties> |
| | | |
| | | <!-- è天åºç¡æ¨¡å --> |
| | | <dependencies> |
| | | <dependency> |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-chat</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | |
| | | </project> |
| | |
| | | |
| | | /** |
| | | * æ£é¤éé¢ |
| | | |
| | | |
| | | */ |
| | | private BigDecimal deductCost; |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | 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; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| | |
| | | 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; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
| | |
| | | * æ ¡éªå¹¶æ¹éå é¤è天模åä¿¡æ¯ |
| | | */ |
| | | Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
| | | |
| | | |
| | | /** |
| | | * éè¿æ¨¡ååç§°è·å模åä¿¡æ¯ |
| | | */ |
| | | ChatModelVo selectModelByName(String modelName); |
| | | } |
| | |
| | | /** |
| | | * èå¤©æ¶æ¯Serviceæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2023-11-26 |
| | | * @author ageerle |
| | | * @date 2025-04-08 |
| | | */ |
| | | public interface IChatTokenService { |
| | | |
| | |
| | | */ |
| | | void resetToken(Long userId,String modelName); |
| | | |
| | | /** |
| | | * ä¿®æ¹ç¨æ·token |
| | | */ |
| | | void editToken(ChatToken chatToken); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | |
| | | /** |
| | | * 访客管çServiceæ¥å£ |
| | | * |
| | | * @author Lion Li |
| | | * @date 2024-07-14 |
| | | * @author ageerle |
| | | * @date 2025-04-08 |
| | | */ |
| | | public interface IChatVisitorUsageService { |
| | | |
| | |
| | | } |
| | | return baseMapper.deleteBatchIds(ids) > 0; |
| | | } |
| | | |
| | | /** |
| | | * éè¿æ¨¡ååç§°è·å模åä¿¡æ¯ |
| | | */ |
| | | @Override |
| | | public ChatModelVo selectModelByName(String modelName) { |
| | | return baseMapper.selectVoOne(Wrappers.<ChatModel>lambdaQuery().eq(ChatModel::getModelName, modelName)); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | <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> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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> { |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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é
ç½®æå"); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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"); |
| | | } |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | <module>ruoyi-demo</module> |
| | | <module>ruoyi-chat</module> |
| | | <module>ruoyi-system</module> |
| | | <module>ruoyi-knowledge</module> |
| | | <module>ruoyi-generator</module> |
| | | </modules> |
| | | |
| | |
| | | <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> |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * æè¿°ï¼è天管ç |
| | |
| | | } |
| | | return sseService.sseChat(chatRequest,request); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * ä¸ä¼ æä»¶ |
| | |
| | | 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)); |
| | | } |
| | | |
| | | /** |
| | | * èå¤©è®°å½ |
| | |
| | | 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; |
| | |
| | | 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.*; |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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(); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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(); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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==="); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | }; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | <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> |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * å
¬å ä¿¡æ¯æä½å¤ç |
| | | * å
¬åä¿¡æ¯æä½å¤ç |
| | | * |
| | | * @author Lion Li |
| | | */ |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |
| | | |