Commit 2578ca731192a5df38b9e3dcef8f64324c8859be

Authored by YunaiV
2 parents 56ae4503 059f64ac

Merge branch 'master-jdk21-ai' of https://gitee.com/cherishsince/ruoyi-vue-pro into master-jdk17

Showing 46 changed files with 1355 additions and 128 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatRoleEnum.java
1 1 package cn.iocoder.yudao.module.ai.enums;
2 2  
3   -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4 3 import lombok.AllArgsConstructor;
5 4 import lombok.Getter;
6 5  
7   -import java.util.Arrays;
8   -
9 6 /**
10 7 * AI 内置聊天角色的枚举
11 8 *
... ... @@ -13,16 +10,16 @@ import java.util.Arrays;
13 10 */
14 11 @AllArgsConstructor
15 12 @Getter
16   -public enum AiChatRoleEnum implements IntArrayValuable {
  13 +public enum AiChatRoleEnum {
17 14  
18   - AI_WRITE_ROLE(1, "写作助手", """
  15 + AI_WRITE_ROLE("写作助手", """
19 16 你是一位出色的写作助手,能够帮助用户生成创意和灵感,并在用户提供场景和提示词时生成对应的回复。你的任务包括:
20 17 1. 撰写建议:根据用户提供的主题或问题,提供详细的写作建议、情节发展方向、角色设定以及背景描写,确保内容结构清晰、有逻辑。
21 18 2. 回复生成:根据用户提供的场景和提示词,生成合适的对话或文字回复,确保语气和风格符合场景需求。
22 19 除此之外不需要除了正文内容外的其他回复,如标题、开头、任何解释性语句或道歉。
23 20 """),
24 21  
25   - AI_MIND_MAP_ROLE(2, "导图助手", """
  22 + AI_MIND_MAP_ROLE("导图助手", """
26 23 你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:
27 24 # Geek-AI 助手
28 25 ## 完整的开源系统
... ... @@ -39,11 +36,6 @@ public enum AiChatRoleEnum implements IntArrayValuable {
39 36 除此之外不要任何解释性语句。
40 37 """);
41 38  
42   - // TODO @xin:这个 role 是不是删除掉好点哈。= = 目前主要是没做角色枚举。这里多了 role 反倒容易误解哈
43   - /**
44   - * 角色
45   - */
46   - private final Integer role;
47 39 /**
48 40 * 角色名
49 41 */
... ... @@ -54,11 +46,4 @@ public enum AiChatRoleEnum implements IntArrayValuable {
54 46 */
55 47 private final String systemMessage;
56 48  
57   - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiChatRoleEnum::getRole).toArray();
58   -
59   - @Override
60   - public int[] array() {
61   - return ARRAYS;
62   - }
63   -
64 49 }
... ...
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4  
5 5 /**
6 6 * AI 错误码枚举类
7   - *
  7 + * <p>
8 8 * ai 系统,使用 1-040-000-000 段
9 9 */
10 10 public interface ErrorCodeConstants {
... ... @@ -52,4 +52,9 @@ public interface ErrorCodeConstants {
52 52 // ========== API 思维导图 1-040-008-000 ==========
53 53 ErrorCode MIND_MAP_NOT_EXISTS = new ErrorCode(1_040_008_000, "思维导图不存在!");
54 54  
  55 + // ========== API 知识库 1-022-008-000 ==========
  56 + ErrorCode KNOWLEDGE_NOT_EXISTS = new ErrorCode(1_022_008_000, "知识库不存在!");
  57 + ErrorCode KNOWLEDGE_DOCUMENT_NOT_EXISTS = new ErrorCode(1_022_008_001, "文档不存在!");
  58 + ErrorCode KNOWLEDGE_SEGMENT_NOT_EXISTS = new ErrorCode(1_022_008_002, "段落不存在!");
  59 +
55 60 }
... ...
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/knowledge/AiKnowledgeDocumentStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.enums.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * AI 知识库-文档状态的枚举
  11 + *
  12 + * @author xiaoxin
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum AiKnowledgeDocumentStatusEnum implements IntArrayValuable {
  17 +
  18 + IN_PROGRESS(10, "索引中"),
  19 + SUCCESS(20, "可用"),
  20 + FAIL(30, "失败");
  21 +
  22 + /**
  23 + * 状态
  24 + */
  25 + private final Integer status;
  26 +
  27 + /**
  28 + * 状态名
  29 + */
  30 + private final String name;
  31 +
  32 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiKnowledgeDocumentStatusEnum::getStatus).toArray();
  33 +
  34 + @Override
  35 + public int[] array() {
  36 + return ARRAYS;
  37 + }
  38 +
  39 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeCreateMyReqVO;
  8 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeRespVO;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeUpdateMyReqVO;
  10 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
  11 +import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  21 +
  22 +@Tag(name = "管理后台 - AI 知识库")
  23 +@RestController
  24 +@RequestMapping("/ai/knowledge")
  25 +@Validated
  26 +public class AiKnowledgeController {
  27 +
  28 + @Resource
  29 + private AiKnowledgeService knowledgeService;
  30 +
  31 + @GetMapping("/my-page")
  32 + @Operation(summary = "获取【我的】知识库分页")
  33 + public CommonResult<PageResult<AiKnowledgeRespVO>> getKnowledgePageMy(@Validated PageParam pageReqVO) {
  34 + PageResult<AiKnowledgeDO> pageResult = knowledgeService.getKnowledgePageMy(getLoginUserId(), pageReqVO);
  35 + return success(BeanUtils.toBean(pageResult, AiKnowledgeRespVO.class));
  36 + }
  37 +
  38 + @PostMapping("/create-my")
  39 + @Operation(summary = "创建【我的】知识库")
  40 + public CommonResult<Long> createKnowledgeMy(@RequestBody @Valid AiKnowledgeCreateMyReqVO createReqVO) {
  41 + return success(knowledgeService.createKnowledgeMy(createReqVO, getLoginUserId()));
  42 + }
  43 +
  44 + @PutMapping("/update-my")
  45 + @Operation(summary = "更新【我的】知识库")
  46 + public CommonResult<Boolean> updateKnowledgeMy(@RequestBody @Valid AiKnowledgeUpdateMyReqVO updateReqVO) {
  47 + knowledgeService.updateKnowledgeMy(updateReqVO, getLoginUserId());
  48 + return success(true);
  49 + }
  50 +
  51 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
  7 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentRespVO;
  8 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
  10 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
  11 +import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +@Tag(name = "管理后台 - AI 知识库文档")
  22 +@RestController
  23 +@RequestMapping("/ai/knowledge/document")
  24 +@Validated
  25 +public class AiKnowledgeDocumentController {
  26 +
  27 + @Resource
  28 + private AiKnowledgeDocumentService documentService;
  29 +
  30 + @PostMapping("/create")
  31 + @Operation(summary = "新建文档")
  32 + public CommonResult<Long> createKnowledgeDocument(@Valid AiKnowledgeDocumentCreateReqVO reqVO) {
  33 + Long knowledgeDocumentId = documentService.createKnowledgeDocument(reqVO);
  34 + return success(knowledgeDocumentId);
  35 + }
  36 +
  37 + @GetMapping("/page")
  38 + @Operation(summary = "获取文档分页")
  39 + public CommonResult<PageResult<AiKnowledgeDocumentRespVO>> getKnowledgeDocumentPageMy(@Valid AiKnowledgeDocumentPageReqVO pageReqVO) {
  40 + PageResult<AiKnowledgeDocumentDO> pageResult = documentService.getKnowledgeDocumentPage(pageReqVO);
  41 + return success(BeanUtils.toBean(pageResult, AiKnowledgeDocumentRespVO.class));
  42 + }
  43 +
  44 + @PutMapping("/update")
  45 + @Operation(summary = "更新文档")
  46 + public CommonResult<Boolean> updateKnowledgeDocument(@Valid @RequestBody AiKnowledgeDocumentUpdateReqVO reqVO) {
  47 + documentService.updateKnowledgeDocument(reqVO);
  48 + return success(true);
  49 + }
  50 +
  51 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentPageReqVO;
  7 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentRespVO;
  8 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateReqVO;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateStatusReqVO;
  10 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  11 +import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeSegmentService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +@Tag(name = "管理后台 - AI 知识库段落")
  22 +@RestController
  23 +@RequestMapping("/ai/knowledge/segment")
  24 +@Validated
  25 +public class AiKnowledgeSegmentController {
  26 +
  27 + @Resource
  28 + private AiKnowledgeSegmentService segmentService;
  29 +
  30 + @GetMapping("/page")
  31 + @Operation(summary = "获取段落分页")
  32 + public CommonResult<PageResult<AiKnowledgeSegmentRespVO>> getKnowledgeSegmentPageMy(@Valid AiKnowledgeSegmentPageReqVO pageReqVO) {
  33 + PageResult<AiKnowledgeSegmentDO> pageResult = segmentService.getKnowledgeSegmentPage(pageReqVO);
  34 + return success(BeanUtils.toBean(pageResult, AiKnowledgeSegmentRespVO.class));
  35 + }
  36 +
  37 + @PutMapping("/update")
  38 + @Operation(summary = "更新段落内容")
  39 + public CommonResult<Boolean> updateKnowledgeSegment(@Valid @RequestBody AiKnowledgeSegmentUpdateReqVO reqVO) {
  40 + segmentService.updateKnowledgeSegment(reqVO);
  41 + return success(true);
  42 + }
  43 +
  44 + @PutMapping("/update-status")
  45 + @Operation(summary = "启禁用段落内容")
  46 + public CommonResult<Boolean> updateKnowledgeSegmentStatus(@Valid @RequestBody AiKnowledgeSegmentUpdateStatusReqVO reqVO) {
  47 + segmentService.updateKnowledgeSegmentStatus(reqVO);
  48 + return success(true);
  49 + }
  50 +
  51 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - AI 知识库文档的分页 Request VO")
  8 +@Data
  9 +public class AiKnowledgeDocumentPageReqVO extends PageParam {
  10 +
  11 + @Schema(description = "文档名称", example = "Java 开发手册")
  12 + private String name;
  13 +
  14 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - AI 知识库-文档 Response VO")
  8 +@Data
  9 +public class AiKnowledgeDocumentRespVO extends PageParam {
  10 +
  11 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  12 + private Long id;
  13 +
  14 + @Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  15 + private Long knowledgeId;
  16 +
  17 + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
  18 + private String name;
  19 +
  20 + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 是一门面向对象的语言.....")
  21 + private String content;
  22 +
  23 + @Schema(description = "文档 url", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://doc.iocoder.cn")
  24 + private String url;
  25 +
  26 + @Schema(description = "token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  27 + private Integer tokens;
  28 +
  29 + @Schema(description = "字符数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1008")
  30 + private Integer wordCount;
  31 +
  32 + @Schema(description = "切片状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + private Integer sliceStatus;
  34 +
  35 + @Schema(description = "文档状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  36 + private Integer status;
  37 +
  38 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
  9 +
  10 +@Schema(description = "管理后台 - AI 更新 知识库-文档 Request VO")
  11 +@Data
  12 +public class AiKnowledgeDocumentUpdateReqVO {
  13 +
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
  16 + @NotNull(message = "编号不能为空")
  17 + private Long id;
  18 +
  19 + @Schema(description = "是否启用", example = "1")
  20 + @InEnum(CommonStatusEnum.class)
  21 + private Integer status;
  22 +
  23 + @Schema(description = "名称", example = "Java 开发手册")
  24 + private String name;
  25 +
  26 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeCreateMyReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +import java.util.List;
  9 +
  10 +@Schema(description = "管理后台 - AI 知识库创建【我的】 Request VO")
  11 +@Data
  12 +public class AiKnowledgeCreateMyReqVO {
  13 +
  14 + @Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "ruoyi-vue-pro 用户指南")
  15 + @NotBlank(message = "知识库名称不能为空")
  16 + private String name;
  17 +
  18 + @Schema(description = "知识库描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "存储 ruoyi-vue-pro 操作文档")
  19 + private String description;
  20 +
  21 + @Schema(description = "可见权限,只能选择哪些人可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1]")
  22 + private List<Long> visibilityPermissions;
  23 +
  24 + @Schema(description = "嵌入模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + @NotNull(message = "嵌入模型不能为空")
  26 + private Long modelId;
  27 +
  28 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeDocumentCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +import org.hibernate.validator.constraints.URL;
  8 +
  9 +
  10 +@Schema(description = "管理后台 - AI 知识库文档的创建 Request VO")
  11 +@Data
  12 +public class AiKnowledgeDocumentCreateReqVO {
  13 +
  14 + @Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1204")
  15 + @NotNull(message = "知识库编号不能为空")
  16 + private Long knowledgeId;
  17 +
  18 + @Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "三方登陆")
  19 + @NotBlank(message = "文档名称不能为空")
  20 + private String name;
  21 +
  22 + @Schema(description = "文档 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://doc.iocoder.cn")
  23 + @URL(message = "文档 URL 格式不正确")
  24 + private String url;
  25 +
  26 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +
  7 +@Schema(description = "管理后台 - AI 知识库 Response VO")
  8 +@Data
  9 +public class AiKnowledgeRespVO {
  10 +
  11 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  12 + private Long id;
  13 +
  14 + @Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "ruoyi-vue-pro 用户指南")
  15 + private String name;
  16 +
  17 + @Schema(description = "知识库描述", example = "帮助你快速构建系统")
  18 + private String description;
  19 +
  20 + @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "14")
  21 + private Long modelId;
  22 +
  23 + @Schema(description = "模型标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "qwen-72b-chat")
  24 + private String model;
  25 +
  26 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeUpdateMyReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +import java.util.List;
  9 +
  10 +@Schema(description = "管理后台 - AI 知识库更新【我的】 Request VO")
  11 +@Data
  12 +public class AiKnowledgeUpdateMyReqVO {
  13 +
  14 + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1204")
  15 + @NotNull(message = "知识库编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
  19 + @NotBlank(message = "知识库名称不能为空")
  20 + private String name;
  21 +
  22 + @Schema(description = "知识库描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
  23 + private String description;
  24 +
  25 + @Schema(description = "可见权限,只能选择哪些人可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1]")
  26 + private List<Long> visibilityPermissions;
  27 +
  28 + @Schema(description = "嵌入模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  29 + @NotNull(message = "嵌入模型不能为空")
  30 + private Long modelId;
  31 +
  32 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - AI 知识库分段的分页 Request VO")
  8 +@Data
  9 +public class AiKnowledgeSegmentPageReqVO extends PageParam {
  10 +
  11 + @Schema(description = "分段状态", example = "1")
  12 + private Integer status;
  13 +
  14 + @Schema(description = "文档编号", example = "1")
  15 + private Integer documentId;
  16 +
  17 + @Schema(description = "分段内容关键字", example = "Java 开发")
  18 + private String keyword;
  19 +
  20 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - AI 知识库-文档 Response VO")
  7 +@Data
  8 +public class AiKnowledgeSegmentRespVO {
  9 +
  10 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  11 + private Long id;
  12 +
  13 + @Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  14 + private Long documentId;
  15 +
  16 + @Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  17 + private Long knowledgeId;
  18 +
  19 + @Schema(description = "向量库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1858496a-1dde-4edf-a43e-0aed08f37f8c")
  20 + private String vectorId;
  21 +
  22 + @Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
  23 + private String content;
  24 +
  25 + @Schema(description = "token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  26 + private Integer tokens;
  27 +
  28 + @Schema(description = "字符数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1008")
  29 + private Integer wordCount;
  30 +
  31 + @Schema(description = "文档状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  32 + private Integer status;
  33 +
  34 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +
  7 +@Schema(description = "管理后台 - AI 更新 知识库-段落 request VO")
  8 +@Data
  9 +public class AiKnowledgeSegmentUpdateReqVO {
  10 +
  11 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  12 + private Long id;
  13 +
  14 + @Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
  15 + private String content;
  16 +
  17 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentUpdateStatusReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
  9 +
  10 +@Schema(description = "管理后台 - AI 知识库段落的更新状态 Request VO")
  11 +@Data
  12 +public class AiKnowledgeSegmentUpdateStatusReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  15 + private Long id;
  16 +
  17 + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "是否启用不能为空")
  19 + @InEnum(CommonStatusEnum.class)
  20 + private Integer status;
  21 +
  22 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
... ... @@ -30,7 +30,7 @@ public class AiImageDO extends BaseDO {
30 30 /**
31 31 * 编号
32 32 */
33   - @TableId(type = IdType.AUTO)
  33 + @TableId
34 34 private Long id;
35 35  
36 36 /**
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.TableField;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  9 +import lombok.Data;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * AI 知识库 DO
  15 + *
  16 + * @author xiaoxin
  17 + */
  18 +@TableName(value = "ai_knowledge", autoResultMap = true)
  19 +@Data
  20 +public class AiKnowledgeDO extends BaseDO {
  21 +
  22 + /**
  23 + * 编号
  24 + */
  25 + @TableId
  26 + private Long id;
  27 + /**
  28 + * 用户编号
  29 + * <p>
  30 + * 关联 AdminUserDO 的 userId 字段
  31 + */
  32 + private Long userId;
  33 + /**
  34 + * 知识库名称
  35 + */
  36 + private String name;
  37 + /**
  38 + * 知识库描述
  39 + */
  40 + private String description;
  41 + // TODO @新:如果全部可见,需要怎么设置?
  42 + /**
  43 + * 可见权限,只能选择哪些人可见
  44 + */
  45 + @TableField(typeHandler = JacksonTypeHandler.class)
  46 + private List<Long> visibilityPermissions;
  47 + /**
  48 + * 嵌入模型编号
  49 + */
  50 + private Long modelId;
  51 + /**
  52 + * 模型标识
  53 + */
  54 + private String model;
  55 + /**
  56 + * 状态
  57 + * <p>
  58 + * 枚举 {@link CommonStatusEnum}
  59 + */
  60 + private Integer status;
  61 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.ai.enums.knowledge.AiKnowledgeDocumentStatusEnum;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import lombok.Data;
  9 +
  10 +/**
  11 + * AI 知识库-文档 DO
  12 + *
  13 + * @author xiaoxin
  14 + */
  15 +@TableName(value = "ai_knowledge_document")
  16 +@Data
  17 +public class AiKnowledgeDocumentDO extends BaseDO {
  18 +
  19 + /**
  20 + * 编号
  21 + */
  22 + @TableId
  23 + private Long id;
  24 + /**
  25 + * 知识库编号
  26 + *
  27 + * 关联 {@link AiKnowledgeDO#getId()}
  28 + */
  29 + private Long knowledgeId;
  30 + /**
  31 + * 文件名称
  32 + */
  33 + private String name;
  34 + /**
  35 + * 内容
  36 + */
  37 + private String content;
  38 + /**
  39 + * 文件 URL
  40 + */
  41 + private String url;
  42 + /**
  43 + * token 数量
  44 + */
  45 + private Integer tokens;
  46 + /**
  47 + * 字符数
  48 + */
  49 + private Integer wordCount;
  50 + /**
  51 + * 切片状态
  52 + * <p>
  53 + * 枚举 {@link AiKnowledgeDocumentStatusEnum}
  54 + */
  55 + private Integer sliceStatus;
  56 +
  57 + /**
  58 + * 状态
  59 + * <p>
  60 + * 枚举 {@link CommonStatusEnum}
  61 + */
  62 + private Integer status;
  63 +
  64 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.Data;
  8 +
  9 +/**
  10 + * AI 知识库-文档分段 DO
  11 + *
  12 + * @author xiaoxin
  13 + */
  14 +@TableName(value = "ai_knowledge_segment")
  15 +@Data
  16 +public class AiKnowledgeSegmentDO extends BaseDO {
  17 +
  18 + public static final String FIELD_KNOWLEDGE_ID = "knowledgeId";
  19 +
  20 + /**
  21 + * 编号
  22 + */
  23 + @TableId
  24 + private Long id;
  25 + /**
  26 + * 向量库的编号
  27 + */
  28 + private String vectorId;
  29 + /**
  30 + * 知识库编号
  31 + *
  32 + * 关联 {@link AiKnowledgeDO#getId()}
  33 + */
  34 + private Long knowledgeId;
  35 + /**
  36 + * 文档编号
  37 + *
  38 + * 关联 {@link AiKnowledgeDocumentDO#getId()}
  39 + */
  40 + private Long documentId;
  41 + /**
  42 + * 切片内容
  43 + */
  44 + private String content;
  45 + /**
  46 + * 字符数
  47 + */
  48 + private Integer wordCount;
  49 + /**
  50 + * token 数量
  51 + */
  52 + private Integer tokens;
  53 + /**
  54 + * 状态
  55 + *
  56 + * 枚举 {@link CommonStatusEnum}
  57 + */
  58 + private Integer status;
  59 +
  60 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java
... ... @@ -19,7 +19,7 @@ public class AiMindMapDO extends BaseDO {
19 19 /**
20 20 * 编号
21 21 */
22   - @TableId(type = IdType.AUTO)
  22 + @TableId
23 23 private Long id;
24 24  
25 25 /**
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
... ... @@ -25,7 +25,7 @@ public class AiMusicDO extends BaseDO {
25 25 /**
26 26 * 编号
27 27 */
28   - @TableId(type = IdType.AUTO)
  28 + @TableId
29 29 private Long id;
30 30  
31 31 /**
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java
... ... @@ -20,7 +20,7 @@ public class AiWriteDO extends BaseDO {
20 20 /**
21 21 * 编号
22 22 */
23   - @TableId(type = IdType.AUTO)
  23 + @TableId
24 24 private Long id;
25 25  
26 26 /**
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeDocumentMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
  7 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * AI 知识库-文档 Mapper
  12 + *
  13 + * @author xiaoxin
  14 + */
  15 +@Mapper
  16 +public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocumentDO> {
  17 +
  18 + default PageResult<AiKnowledgeDocumentDO> selectPage(AiKnowledgeDocumentPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<AiKnowledgeDocumentDO>()
  20 + .likeIfPresent(AiKnowledgeDocumentDO::getName, reqVO.getName())
  21 + .orderByDesc(AiKnowledgeDocumentDO::getId));
  22 + }
  23 +
  24 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +/**
  12 + * AI 知识库基础信息 Mapper
  13 + *
  14 + * @author xiaoxin
  15 + */
  16 +@Mapper
  17 +public interface AiKnowledgeMapper extends BaseMapperX<AiKnowledgeDO> {
  18 +
  19 + default PageResult<AiKnowledgeDO> selectPageByMy(Long userId, PageParam pageReqVO) {
  20 + return selectPage(pageReqVO, new LambdaQueryWrapperX<AiKnowledgeDO>()
  21 + .eq(AiKnowledgeDO::getUserId, userId)
  22 + .eq(AiKnowledgeDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
  23 + .orderByDesc(AiKnowledgeDO::getId));
  24 + }
  25 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentPageReqVO;
  7 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * AI 知识库-分片 Mapper
  12 + *
  13 + * @author xiaoxin
  14 + */
  15 +@Mapper
  16 +public interface AiKnowledgeSegmentMapper extends BaseMapperX<AiKnowledgeSegmentDO> {
  17 +
  18 + default PageResult<AiKnowledgeSegmentDO> selectPage(AiKnowledgeSegmentPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<AiKnowledgeSegmentDO>()
  20 + .eq(AiKnowledgeSegmentDO::getDocumentId, reqVO.getDocumentId())
  21 + .eqIfPresent(AiKnowledgeSegmentDO::getStatus, reqVO.getStatus())
  22 + .likeIfPresent(AiKnowledgeSegmentDO::getContent, reqVO.getKeyword())
  23 + .orderByDesc(AiKnowledgeSegmentDO::getId));
  24 + }
  25 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
  7 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
  8 +
  9 +/**
  10 + * AI 知识库-文档 Service 接口
  11 + *
  12 + * @author xiaoxin
  13 + */
  14 +public interface AiKnowledgeDocumentService {
  15 +
  16 + /**
  17 + * 创建文档
  18 + *
  19 + * @param createReqVO 文档创建 Request VO
  20 + * @return 文档编号
  21 + */
  22 + Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO);
  23 +
  24 +
  25 + /**
  26 + * 获取文档分页
  27 + *
  28 + * @param pageReqVO 分页参数
  29 + * @return 文档分页
  30 + */
  31 + PageResult<AiKnowledgeDocumentDO> getKnowledgeDocumentPage(AiKnowledgeDocumentPageReqVO pageReqVO);
  32 +
  33 + /**
  34 + * 更新文档
  35 + *
  36 + * @param reqVO 更新信息
  37 + */
  38 + void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO);
  39 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.http.HttpUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
  10 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO;
  11 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
  12 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
  13 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
  14 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  15 +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
  16 +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeDocumentMapper;
  17 +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper;
  18 +import cn.iocoder.yudao.module.ai.enums.knowledge.AiKnowledgeDocumentStatusEnum;
  19 +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
  20 +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
  21 +import jakarta.annotation.Resource;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.springframework.ai.document.Document;
  24 +import org.springframework.ai.reader.tika.TikaDocumentReader;
  25 +import org.springframework.ai.tokenizer.TokenCountEstimator;
  26 +import org.springframework.ai.transformer.splitter.TokenTextSplitter;
  27 +import org.springframework.ai.vectorstore.VectorStore;
  28 +import org.springframework.core.io.ByteArrayResource;
  29 +import org.springframework.stereotype.Service;
  30 +import org.springframework.transaction.annotation.Transactional;
  31 +
  32 +import java.util.List;
  33 +
  34 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  35 +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_NOT_EXISTS;
  36 +
  37 +/**
  38 + * AI 知识库文档 Service 实现类
  39 + *
  40 + * @author xiaoxin
  41 + */
  42 +@Service
  43 +@Slf4j
  44 +public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentService {
  45 +
  46 + @Resource
  47 + private AiKnowledgeDocumentMapper documentMapper;
  48 + @Resource
  49 + private AiKnowledgeSegmentMapper segmentMapper;
  50 +
  51 + @Resource
  52 + private TokenTextSplitter tokenTextSplitter;
  53 + @Resource
  54 + private TokenCountEstimator tokenCountEstimator;
  55 +
  56 + @Resource
  57 + private AiApiKeyService apiKeyService;
  58 + @Resource
  59 + private AiKnowledgeService knowledgeService;
  60 + @Resource
  61 + private AiChatModelService chatModelService;
  62 +
  63 + @Override
  64 + @Transactional(rollbackFor = Exception.class)
  65 + public Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO) {
  66 + // 0. 校验
  67 + AiKnowledgeDO knowledge = knowledgeService.validateKnowledgeExists(createReqVO.getKnowledgeId());
  68 + AiChatModelDO model = chatModelService.validateChatModel(knowledge.getModelId());
  69 +
  70 + // 1.1 下载文档
  71 + TikaDocumentReader loader = new TikaDocumentReader(downloadFile(createReqVO.getUrl()));
  72 + List<Document> documents = loader.get();
  73 + Document document = CollUtil.getFirst(documents);
  74 + // 1.2 文档记录入库
  75 + String content = document.getContent();
  76 + AiKnowledgeDocumentDO documentDO = BeanUtils.toBean(createReqVO, AiKnowledgeDocumentDO.class)
  77 + .setTokens(tokenCountEstimator.estimate(content)).setWordCount(content.length())
  78 + .setStatus(CommonStatusEnum.ENABLE.getStatus()).setSliceStatus(AiKnowledgeDocumentStatusEnum.SUCCESS.getStatus());
  79 + documentMapper.insert(documentDO);
  80 + Long documentId = documentDO.getId();
  81 + if (CollUtil.isEmpty(documents)) {
  82 + return documentId;
  83 + }
  84 +
  85 + // 2.1 文档分段
  86 + List<Document> segments = tokenTextSplitter.apply(documents);
  87 + // 2.2 分段内容入库
  88 + List<AiKnowledgeSegmentDO> segmentDOList = CollectionUtils.convertList(segments,
  89 + segment -> new AiKnowledgeSegmentDO().setContent(segment.getContent()).setDocumentId(documentId)
  90 + .setKnowledgeId(createReqVO.getKnowledgeId()).setVectorId(segment.getId())
  91 + .setTokens(tokenCountEstimator.estimate(segment.getContent())).setWordCount(segment.getContent().length())
  92 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  93 + segmentMapper.insertBatch(segmentDOList);
  94 +
  95 + // 3.1 获取向量存储实例
  96 + VectorStore vectorStore = apiKeyService.getOrCreateVectorStore(model.getKeyId());
  97 + // 3.2 向量化并存储
  98 + segments.forEach(segment -> segment.getMetadata().put(AiKnowledgeSegmentDO.FIELD_KNOWLEDGE_ID, createReqVO.getKnowledgeId()));
  99 + vectorStore.add(segments);
  100 + return documentId;
  101 + }
  102 +
  103 + @Override
  104 + public PageResult<AiKnowledgeDocumentDO> getKnowledgeDocumentPage(AiKnowledgeDocumentPageReqVO pageReqVO) {
  105 + return documentMapper.selectPage(pageReqVO);
  106 + }
  107 +
  108 + @Override
  109 + public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) {
  110 + // 1. 校验文档是否存在
  111 + validateKnowledgeDocumentExists(reqVO.getId());
  112 + // 2. 更新文档
  113 + AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class);
  114 + documentMapper.updateById(document);
  115 + }
  116 +
  117 + /**
  118 + * 校验文档是否存在
  119 + *
  120 + * @param id 文档编号
  121 + * @return 文档信息
  122 + */
  123 + private AiKnowledgeDocumentDO validateKnowledgeDocumentExists(Long id) {
  124 + AiKnowledgeDocumentDO knowledgeDocument = documentMapper.selectById(id);
  125 + if (knowledgeDocument == null) {
  126 + throw exception(KNOWLEDGE_DOCUMENT_NOT_EXISTS);
  127 + }
  128 + return knowledgeDocument;
  129 + }
  130 +
  131 + private org.springframework.core.io.Resource downloadFile(String url) {
  132 + try {
  133 + byte[] bytes = HttpUtil.downloadBytes(url);
  134 + return new ByteArrayResource(bytes);
  135 + } catch (Exception e) {
  136 + log.error("[downloadFile][url({}) 下载失败]", url, e);
  137 + throw new RuntimeException(e);
  138 + }
  139 + }
  140 +
  141 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentPageReqVO;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateReqVO;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateStatusReqVO;
  7 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  8 +
  9 +/**
  10 + * AI 知识库段落 Service 接口
  11 + *
  12 + * @author xiaoxin
  13 + */
  14 +public interface AiKnowledgeSegmentService {
  15 +
  16 + /**
  17 + * 获取段落分页
  18 + *
  19 + * @param pageReqVO 分页查询
  20 + * @return 文档分页
  21 + */
  22 + PageResult<AiKnowledgeSegmentDO> getKnowledgeSegmentPage(AiKnowledgeSegmentPageReqVO pageReqVO);
  23 +
  24 + /**
  25 + * 更新段落的内容
  26 + *
  27 + * @param reqVO 更新内容
  28 + */
  29 + void updateKnowledgeSegment(AiKnowledgeSegmentUpdateReqVO reqVO);
  30 +
  31 + /**
  32 + * 更新段落的状态
  33 + *
  34 + * @param reqVO 更新内容
  35 + */
  36 + void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO);
  37 +
  38 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentPageReqVO;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateReqVO;
  7 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.AiKnowledgeSegmentUpdateStatusReqVO;
  8 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  9 +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper;
  10 +import jakarta.annotation.Resource;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +import org.springframework.stereotype.Service;
  13 +
  14 +/**
  15 + * AI 知识库分片 Service 实现类
  16 + *
  17 + * @author xiaoxin
  18 + */
  19 +@Service
  20 +@Slf4j
  21 +public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService {
  22 +
  23 + @Resource
  24 + private AiKnowledgeSegmentMapper segmentMapper;
  25 +
  26 + @Override
  27 + public PageResult<AiKnowledgeSegmentDO> getKnowledgeSegmentPage(AiKnowledgeSegmentPageReqVO pageReqVO) {
  28 + return segmentMapper.selectPage(pageReqVO);
  29 + }
  30 +
  31 + @Override
  32 + public void updateKnowledgeSegment(AiKnowledgeSegmentUpdateReqVO reqVO) {
  33 + segmentMapper.updateById(BeanUtils.toBean(reqVO, AiKnowledgeSegmentDO.class));
  34 + // TODO @xin 重新向量化
  35 + }
  36 +
  37 + @Override
  38 + public void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO) {
  39 + segmentMapper.updateById(BeanUtils.toBean(reqVO, AiKnowledgeSegmentDO.class));
  40 + // TODO @xin 1.禁用删除向量 2.启用重新向量化
  41 + }
  42 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeCreateMyReqVO;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeUpdateMyReqVO;
  7 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
  8 +
  9 +/**
  10 + * AI 知识库-基础信息 Service 接口
  11 + *
  12 + * @author xiaoxin
  13 + */
  14 +public interface AiKnowledgeService {
  15 +
  16 + /**
  17 + * 创建【我的】知识库
  18 + *
  19 + * @param createReqVO 创建信息
  20 + * @param userId 用户编号
  21 + * @return 编号
  22 + */
  23 + Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId);
  24 +
  25 +
  26 + /**
  27 + * 创建【我的】知识库
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + * @param userId 用户编号
  31 + */
  32 + void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId);
  33 +
  34 +
  35 + /**
  36 + * 校验知识库是否存在
  37 + *
  38 + * @param id 记录编号
  39 + */
  40 + AiKnowledgeDO validateKnowledgeExists(Long id);
  41 +
  42 + /**
  43 + * 获得【我的】知识库分页
  44 + *
  45 + * @param userId 用户编号
  46 + * @param pageReqVO 分页查询
  47 + * @return 知识库分页
  48 + */
  49 + PageResult<AiKnowledgeDO> getKnowledgePageMy(Long userId, PageParam pageReqVO);
  50 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.knowledge;
  2 +
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeCreateMyReqVO;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeUpdateMyReqVO;
  10 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
  11 +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
  12 +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeMapper;
  13 +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
  14 +import jakarta.annotation.Resource;
  15 +import lombok.extern.slf4j.Slf4j;
  16 +import org.springframework.stereotype.Service;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_NOT_EXISTS;
  20 +
  21 +/**
  22 + * AI 知识库-基础信息 Service 实现类
  23 + *
  24 + * @author xiaoxin
  25 + */
  26 +@Service
  27 +@Slf4j
  28 +public class AiKnowledgeServiceImpl implements AiKnowledgeService {
  29 +
  30 + @Resource
  31 + private AiChatModelService chatModalService;
  32 +
  33 + @Resource
  34 + private AiKnowledgeMapper knowledgeMapper;
  35 +
  36 + @Override
  37 + public Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId) {
  38 + // 1. 校验模型配置
  39 + AiChatModelDO model = chatModalService.validateChatModel(createReqVO.getModelId());
  40 +
  41 + // 2. 插入知识库
  42 + AiKnowledgeDO knowledgeBase = BeanUtils.toBean(createReqVO, AiKnowledgeDO.class)
  43 + .setModel(model.getModel()).setUserId(userId).setStatus(CommonStatusEnum.ENABLE.getStatus());
  44 + knowledgeMapper.insert(knowledgeBase);
  45 + return knowledgeBase.getId();
  46 + }
  47 +
  48 + @Override
  49 + public void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId) {
  50 + // 1.1 校验知识库存在
  51 + AiKnowledgeDO knowledgeBaseDO = validateKnowledgeExists(updateReqVO.getId());
  52 + if (ObjUtil.notEqual(knowledgeBaseDO.getUserId(), userId)) {
  53 + throw exception(KNOWLEDGE_NOT_EXISTS);
  54 + }
  55 + // 1.2 校验模型配置
  56 + AiChatModelDO model = chatModalService.validateChatModel(updateReqVO.getModelId());
  57 +
  58 + // 2. 更新知识库
  59 + AiKnowledgeDO updateDO = BeanUtils.toBean(updateReqVO, AiKnowledgeDO.class);
  60 + updateDO.setModel(model.getModel());
  61 + knowledgeMapper.updateById(updateDO);
  62 + }
  63 +
  64 + @Override
  65 + public AiKnowledgeDO validateKnowledgeExists(Long id) {
  66 + AiKnowledgeDO knowledgeBase = knowledgeMapper.selectById(id);
  67 + if (knowledgeBase == null) {
  68 + throw exception(KNOWLEDGE_NOT_EXISTS);
  69 + }
  70 + return knowledgeBase;
  71 + }
  72 +
  73 + @Override
  74 + public PageResult<AiKnowledgeDO> getKnowledgePageMy(Long userId, PageParam pageReqVO) {
  75 + return knowledgeMapper.selectPageByMy(userId, pageReqVO);
  76 + }
  77 +
  78 +}
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/DocService.java deleted
1   -package cn.iocoder.yudao.module.ai.service.knowledge;
2   -
3   -/**
4   - * AI 知识库 Service 接口
5   - *
6   - * @author xiaoxin
7   - */
8   -public interface DocService {
9   -
10   - /**
11   - * 向量化文档
12   - */
13   - void embeddingDoc();
14   -
15   -}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/DocServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.ai.service.knowledge;
2   -
3   -import jakarta.annotation.Resource;
4   -import lombok.extern.slf4j.Slf4j;
5   -import org.springframework.ai.document.Document;
6   -import org.springframework.ai.reader.tika.TikaDocumentReader;
7   -import org.springframework.ai.transformer.splitter.TokenTextSplitter;
8   -import org.springframework.ai.vectorstore.RedisVectorStore;
9   -import org.springframework.beans.factory.annotation.Value;
10   -
11   -import java.util.List;
12   -
13   -/**
14   - * AI 知识库 Service 实现类
15   - *
16   - * @author xiaoxin
17   - */
18   -//@Service // TODO 芋艿:临时注释,避免无法启动
19   -@Slf4j
20   -public class DocServiceImpl implements DocService {
21   -
22   - @Resource
23   - private RedisVectorStore vectorStore;
24   - @Resource
25   - private TokenTextSplitter tokenTextSplitter;
26   -
27   - // TODO @xin 临时测试用,后续删
28   - @Value("classpath:/webapp/test/Fel.pdf")
29   - private org.springframework.core.io.Resource data;
30   -
31   - @Override
32   - public void embeddingDoc() {
33   - // 读取文件
34   - TikaDocumentReader loader = new TikaDocumentReader(data);
35   - List<Document> documents = loader.get();
36   - // 文档分段
37   - List<Document> segments = tokenTextSplitter.apply(documents);
38   - // 向量化并存储
39   - vectorStore.add(segments);
40   - }
41   -
42   -}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyService.java
... ... @@ -9,7 +9,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveR
9 9 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
10 10 import jakarta.validation.Valid;
11 11 import org.springframework.ai.chat.model.ChatModel;
  12 +import org.springframework.ai.embedding.EmbeddingModel;
12 13 import org.springframework.ai.image.ImageModel;
  14 +import org.springframework.ai.vectorstore.VectorStore;
13 15  
14 16 import java.util.List;
15 17  
... ... @@ -111,4 +113,20 @@ public interface AiApiKeyService {
111 113 */
112 114 SunoApi getSunoApi();
113 115  
  116 + /**
  117 + * 获得 EmbeddingModel 对象
  118 + *
  119 + * @param id 编号
  120 + * @return EmbeddingModel 对象
  121 + */
  122 + EmbeddingModel getEmbeddingModel(Long id);
  123 +
  124 + /**
  125 + * 获得 VectorStore 对象
  126 + *
  127 + * @param id 编号
  128 + * @return VectorStore 对象
  129 + */
  130 + VectorStore getOrCreateVectorStore(Long id);
  131 +
114 132 }
115 133 \ No newline at end of file
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.service.model;
2 2  
3 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
  5 +import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactory;
5 6 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
6 7 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
7 8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
... ... @@ -13,7 +14,9 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
13 14 import cn.iocoder.yudao.module.ai.dal.mysql.model.AiApiKeyMapper;
14 15 import jakarta.annotation.Resource;
15 16 import org.springframework.ai.chat.model.ChatModel;
  17 +import org.springframework.ai.embedding.EmbeddingModel;
16 18 import org.springframework.ai.image.ImageModel;
  19 +import org.springframework.ai.vectorstore.VectorStore;
17 20 import org.springframework.stereotype.Service;
18 21 import org.springframework.validation.annotation.Validated;
19 22  
... ... @@ -36,6 +39,8 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
36 39  
37 40 @Resource
38 41 private AiModelFactory modelFactory;
  42 + @Resource
  43 + private AiVectorStoreFactory vectorFactory;
39 44  
40 45 @Override
41 46 public Long createApiKey(AiApiKeySaveReqVO createReqVO) {
... ... @@ -132,4 +137,19 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
132 137 }
133 138 return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl());
134 139 }
  140 +
  141 + @Override
  142 + public EmbeddingModel getEmbeddingModel(Long id) {
  143 + AiApiKeyDO apiKey = validateApiKey(id);
  144 + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
  145 + return modelFactory.getOrCreateEmbeddingModel(platform, apiKey.getApiKey(), apiKey.getUrl());
  146 + }
  147 +
  148 + @Override
  149 + public VectorStore getOrCreateVectorStore(Long id) {
  150 + AiApiKeyDO apiKey = validateApiKey(id);
  151 + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
  152 + return vectorFactory.getOrCreateVectorStore(getEmbeddingModel(id), platform, apiKey.getApiKey(), apiKey.getUrl());
  153 + }
  154 +
135 155 }
136 156 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
... ... @@ -14,58 +14,57 @@
14 14 <name>${project.artifactId}</name>
15 15 <description>AI 大模型拓展,接入国内外大模型</description>
16 16 <properties>
17   - <spring-ai.version>1.0.0-M1</spring-ai.version>
  17 + <spring-ai.groupId>group.springframework.ai</spring-ai.groupId>
  18 + <spring-ai.version>1.1.0</spring-ai.version>
18 19 </properties>
19 20  
20 21 <dependencies>
21 22 <dependency>
22   - <groupId>org.springframework.ai</groupId>
  23 + <groupId>${spring-ai.groupId}</groupId>
23 24 <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
24 25 <version>${spring-ai.version}</version>
25 26 </dependency>
26 27 <dependency>
27   - <groupId>org.springframework.ai</groupId>
  28 + <groupId>${spring-ai.groupId}</groupId>
28 29 <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
29 30 <version>${spring-ai.version}</version>
30 31 </dependency>
31 32 <dependency>
32   - <groupId>org.springframework.ai</groupId>
  33 + <groupId>${spring-ai.groupId}</groupId>
33 34 <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
34 35 <version>${spring-ai.version}</version>
35 36 </dependency>
36 37 <dependency>
37   - <groupId>org.springframework.ai</groupId>
  38 + <groupId>${spring-ai.groupId}</groupId>
38 39 <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
39 40 <version>${spring-ai.version}</version>
40 41 </dependency>
41 42 <dependency>
42   - <groupId>org.springframework.ai</groupId>
  43 + <groupId>${spring-ai.groupId}</groupId>
43 44 <artifactId>spring-ai-stability-ai-spring-boot-starter</artifactId>
44 45 <version>${spring-ai.version}</version>
45 46 </dependency>
46 47  
47 48 <!-- 向量化,基于 Redis 存储,Tika 解析内容 -->
48 49 <dependency>
49   - <groupId>org.springframework.ai</groupId>
  50 + <groupId>${spring-ai.groupId}</groupId>
50 51 <artifactId>spring-ai-transformers-spring-boot-starter</artifactId>
51 52 <version>${spring-ai.version}</version>
52 53 </dependency>
53 54 <dependency>
54   - <groupId>org.springframework.ai</groupId>
  55 + <groupId>${spring-ai.groupId}</groupId>
55 56 <artifactId>spring-ai-tika-document-reader</artifactId>
56 57 <version>${spring-ai.version}</version>
57 58 </dependency>
58 59 <dependency>
59   - <groupId>org.springframework.ai</groupId>
  60 + <groupId>${spring-ai.groupId}</groupId>
60 61 <artifactId>spring-ai-redis-store</artifactId>
61 62 <version>${spring-ai.version}</version>
62 63 </dependency>
63 64  
64   - <!-- TODO @xin:引入我们项目的 starter -->
65 65 <dependency>
66   - <groupId>org.springframework.data</groupId>
67   - <artifactId>spring-data-redis</artifactId>
68   - <optional>true</optional>
  66 + <groupId>cn.iocoder.boot</groupId>
  67 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
69 68 </dependency>
70 69  
71 70 <dependency>
... ... @@ -73,11 +72,10 @@
73 72 <artifactId>yudao-common</artifactId>
74 73 </dependency>
75 74  
76   - <!-- TODO 芋艿:等 spring-ai 官方发布后,需要把 groupId 改下 -->
77 75 <dependency>
78   - <groupId>group.springframework.ai</groupId>
  76 + <groupId>${spring-ai.groupId}</groupId>
79 77 <artifactId>spring-ai-qianfan-spring-boot-starter</artifactId>
80   - <version>1.1.0</version>
  78 + <version>${spring-ai.version}</version>
81 79 </dependency>
82 80  
83 81 <!-- 阿里云 通义千问 -->
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
... ... @@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.ai.config;
2 2  
3 3 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
4 4 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
  5 +import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactory;
  6 +import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactoryImpl;
5 7 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
6 8 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions;
7 9 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
... ... @@ -10,20 +12,15 @@ import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
10 12 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions;
11 13 import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
12 14 import lombok.extern.slf4j.Slf4j;
13   -import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
14   -import org.springframework.ai.document.MetadataMode;
15   -import org.springframework.ai.embedding.EmbeddingModel;
  15 +import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
  16 +import org.springframework.ai.tokenizer.TokenCountEstimator;
16 17 import org.springframework.ai.transformer.splitter.TokenTextSplitter;
17   -import org.springframework.ai.transformers.TransformersEmbeddingModel;
18   -import org.springframework.ai.vectorstore.RedisVectorStore;
19 18 import org.springframework.boot.autoconfigure.AutoConfiguration;
20 19 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21   -import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
22 20 import org.springframework.boot.context.properties.EnableConfigurationProperties;
23 21 import org.springframework.context.annotation.Bean;
24 22 import org.springframework.context.annotation.Import;
25 23 import org.springframework.context.annotation.Lazy;
26   -import redis.clients.jedis.JedisPooled;
27 24  
28 25 /**
29 26 * 芋道 AI 自动配置
... ... @@ -41,6 +38,12 @@ public class YudaoAiAutoConfiguration {
41 38 return new AiModelFactoryImpl();
42 39 }
43 40  
  41 + @Bean
  42 + public AiVectorStoreFactory aiVectorFactory() {
  43 + return new AiVectorStoreFactoryImpl();
  44 + }
  45 +
  46 +
44 47 // ========== 各种 AI Client 创建 ==========
45 48  
46 49 @Bean
... ... @@ -83,35 +86,42 @@ public class YudaoAiAutoConfiguration {
83 86 }
84 87  
85 88 // ========== rag 相关 ==========
86   - @Bean
87   - @Lazy // TODO 芋艿:临时注释,避免无法启动
88   - public EmbeddingModel transformersEmbeddingClient() {
89   - return new TransformersEmbeddingModel(MetadataMode.EMBED);
90   - }
  89 + // TODO @xin 免费版本
  90 +// @Bean
  91 +// @Lazy // TODO 芋艿:临时注释,避免无法启动」
  92 +// public EmbeddingModel transformersEmbeddingClient() {
  93 +// return new TransformersEmbeddingModel(MetadataMode.EMBED);
  94 +// }
91 95  
92 96 /**
93   - * 我们启动有加载很多 Embedding 模型,不晓得取哪个好,先 new 个 TransformersEmbeddingModel 跑
  97 + * TODO @xin 默认版本先不弄,目前都先取对应的 EmbeddingModel
94 98 */
  99 +// @Bean
  100 +// @Lazy // TODO 芋艿:临时注释,避免无法启动
  101 +// public RedisVectorStore vectorStore(TongYiTextEmbeddingModel tongYiTextEmbeddingModel, RedisVectorStoreProperties properties,
  102 +// RedisProperties redisProperties) {
  103 +// var config = RedisVectorStore.RedisVectorStoreConfig.builder()
  104 +// .withIndexName(properties.getIndex())
  105 +// .withPrefix(properties.getPrefix())
  106 +// .build();
  107 +//
  108 +// RedisVectorStore redisVectorStore = new RedisVectorStore(config, tongYiTextEmbeddingModel,
  109 +// new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
  110 +// properties.isInitializeSchema());
  111 +// redisVectorStore.afterPropertiesSet();
  112 +// return redisVectorStore;
  113 +// }
  114 +
95 115 @Bean
96 116 @Lazy // TODO 芋艿:临时注释,避免无法启动
97   - public RedisVectorStore vectorStore(TransformersEmbeddingModel transformersEmbeddingModel, RedisVectorStoreProperties properties,
98   - RedisProperties redisProperties) {
99   - var config = RedisVectorStore.RedisVectorStoreConfig.builder()
100   - .withIndexName(properties.getIndex())
101   - .withPrefix(properties.getPrefix())
102   - .build();
103   -
104   - RedisVectorStore redisVectorStore = new RedisVectorStore(config, transformersEmbeddingModel,
105   - new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
106   - properties.isInitializeSchema());
107   - redisVectorStore.afterPropertiesSet();
108   - return redisVectorStore;
  117 + public TokenTextSplitter tokenTextSplitter() {
  118 + return new TokenTextSplitter(500, 100, 5, 10000, true);
109 119 }
110 120  
111 121 @Bean
112 122 @Lazy // TODO 芋艿:临时注释,避免无法启动
113   - public TokenTextSplitter tokenTextSplitter() {
114   - return new TokenTextSplitter(500, 100, 5, 10000, true);
  123 + public TokenCountEstimator tokenCountEstimator() {
  124 + return new JTokkitTokenCountEstimator();
115 125 }
116 126  
117 127 }
118 128 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactory.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
5 5 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
6 6 import org.springframework.ai.chat.model.ChatModel;
  7 +import org.springframework.ai.embedding.EmbeddingModel;
7 8 import org.springframework.ai.image.ImageModel;
8 9  
9 10 /**
... ... @@ -79,4 +80,16 @@ public interface AiModelFactory {
79 80 */
80 81 SunoApi getOrCreateSunoApi(String apiKey, String url);
81 82  
  83 + /**
  84 + * 基于指定配置,获得 EmbeddingModel 对象
  85 + *
  86 + * 如果不存在,则进行创建
  87 + *
  88 + * @param platform 平台
  89 + * @param apiKey API KEY
  90 + * @param url API URL
  91 + * @return ChatModel 对象
  92 + */
  93 + EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url);
  94 +
82 95 }
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
... ... @@ -21,6 +21,7 @@ import com.alibaba.cloud.ai.tongyi.image.TongYiImagesModel;
21 21 import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties;
22 22 import com.alibaba.dashscope.aigc.generation.Generation;
23 23 import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
  24 +import com.alibaba.dashscope.embeddings.TextEmbedding;
24 25 import com.azure.ai.openai.OpenAIClient;
25 26 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration;
26 27 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties;
... ... @@ -37,6 +38,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties;
37 38 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties;
38 39 import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
39 40 import org.springframework.ai.chat.model.ChatModel;
  41 +import org.springframework.ai.embedding.EmbeddingModel;
40 42 import org.springframework.ai.image.ImageModel;
41 43 import org.springframework.ai.model.function.FunctionCallbackContext;
42 44 import org.springframework.ai.ollama.OllamaChatModel;
... ... @@ -175,6 +177,20 @@ public class AiModelFactoryImpl implements AiModelFactory {
175 177 return Singleton.get(cacheKey, (Func0<SunoApi>) () -> new SunoApi(url));
176 178 }
177 179  
  180 + @Override
  181 + public EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url) {
  182 + String cacheKey = buildClientCacheKey(EmbeddingModel.class, platform, apiKey, url);
  183 + return Singleton.get(cacheKey, (Func0<EmbeddingModel>) () -> {
  184 + // TODO @xin 先测试一个
  185 + switch (platform) {
  186 + case TONG_YI:
  187 + return buildTongYiEmbeddingModel(apiKey);
  188 + default:
  189 + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
  190 + }
  191 + });
  192 + }
  193 +
178 194 private static String buildClientCacheKey(Class<?> clazz, Object... params) {
179 195 if (ArrayUtil.isEmpty(params)) {
180 196 return clazz.getName();
... ... @@ -238,8 +254,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
238 254 }
239 255  
240 256 /**
241   - * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiChatModel(
242   - * ZhiPuAiConnectionProperties, ZhiPuAiChatProperties, RestClient.Builder, List, FunctionCallbackContext, RetryTemplate, ResponseErrorHandler)}
  257 + * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiChatModel(ZhiPuAiConnectionProperties, ZhiPuAiChatProperties, RestClient.Builder, List, FunctionCallbackContext, RetryTemplate, ResponseErrorHandler)}
243 258 */
244 259 private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
245 260 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
... ... @@ -248,8 +263,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
248 263 }
249 264  
250 265 /**
251   - * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiImageModel(
252   - * ZhiPuAiConnectionProperties, ZhiPuAiImageProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
  266 + * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiImageModel(ZhiPuAiConnectionProperties, ZhiPuAiImageProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
253 267 */
254 268 private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
255 269 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
... ... @@ -315,4 +329,15 @@ public class AiModelFactoryImpl implements AiModelFactory {
315 329 return new StabilityAiImageModel(stabilityAiApi);
316 330 }
317 331  
  332 + // ========== 各种创建 EmbeddingModel 的方法 ==========
  333 +
  334 + /**
  335 + * 可参考 {@link TongYiAutoConfiguration#tongYiTextEmbeddingClient(TextEmbedding, TongYiConnectionProperties)}
  336 + */
  337 + private EmbeddingModel buildTongYiEmbeddingModel(String apiKey) {
  338 + TongYiConnectionProperties connectionProperties = new TongYiConnectionProperties();
  339 + connectionProperties.setApiKey(apiKey);
  340 + return new TongYiAutoConfiguration().tongYiTextEmbeddingClient(SpringUtil.getBean(TextEmbedding.class), connectionProperties);
  341 + }
  342 +
318 343 }
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactory.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.core.factory;
  2 +
  3 +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
  4 +import org.springframework.ai.embedding.EmbeddingModel;
  5 +import org.springframework.ai.vectorstore.VectorStore;
  6 +
  7 +// TODO @xin:也放到 AiModelFactory 里面好了,后续改成 AiFactory
  8 +/**
  9 + * AI Vector 模型工厂的接口类
  10 + *
  11 + * @author xiaoxin
  12 + */
  13 +public interface AiVectorStoreFactory {
  14 +
  15 + /**
  16 + * 基于指定配置,获得 VectorStore 对象
  17 + * <p>
  18 + * 如果不存在,则进行创建
  19 + *
  20 + * @param embeddingModel 嵌入模型
  21 + * @param platform 平台
  22 + * @param apiKey API KEY
  23 + * @param url API URL
  24 + * @return VectorStore 对象
  25 + */
  26 + VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url);
  27 +
  28 +}
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiVectorStoreFactoryImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.core.factory;
  2 +
  3 +import cn.hutool.core.lang.Singleton;
  4 +import cn.hutool.core.lang.func.Func0;
  5 +import cn.hutool.core.util.ArrayUtil;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
  8 +import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
  9 +import org.springframework.ai.embedding.EmbeddingModel;
  10 +import org.springframework.ai.vectorstore.RedisVectorStore;
  11 +import org.springframework.ai.vectorstore.VectorStore;
  12 +import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
  13 +import redis.clients.jedis.JedisPooled;
  14 +
  15 +/**
  16 + * AI Vector 模型工厂的实现类
  17 + * 使用 redisVectorStore 实现 VectorStore
  18 + *
  19 + * @author xiaoxin
  20 + */
  21 +public class AiVectorStoreFactoryImpl implements AiVectorStoreFactory {
  22 +
  23 + @Override
  24 + public VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url) {
  25 + String cacheKey = buildClientCacheKey(VectorStore.class, platform, apiKey, url);
  26 + return Singleton.get(cacheKey, (Func0<VectorStore>) () -> {
  27 + // TODO 芋艿 @xin 这两个配置取哪好呢
  28 + // TODO 不同模型的向量维度可能会不一样,目前看貌似是以 index 来做区分的,维度不一样存不到一个 index 上
  29 + // TODO 回复:好的哈
  30 + String index = "default-index";
  31 + String prefix = "default:";
  32 + var config = RedisVectorStore.RedisVectorStoreConfig.builder()
  33 + .withIndexName(index)
  34 + .withPrefix(prefix)
  35 + .build();
  36 + RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
  37 + RedisVectorStore redisVectorStore = new RedisVectorStore(config, embeddingModel,
  38 + new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
  39 + true);
  40 + redisVectorStore.afterPropertiesSet();
  41 + return redisVectorStore;
  42 + });
  43 + }
  44 +
  45 + private static String buildClientCacheKey(Class<?> clazz, Object... params) {
  46 + if (ArrayUtil.isEmpty(params)) {
  47 + return clazz.getName();
  48 + }
  49 + return StrUtil.format("{}#{}", clazz.getName(), ArrayUtil.join(params, "_"));
  50 + }
  51 +
  52 +}
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/org/springframework/ai/autoconfigure/vectorstore/redis/RedisVectorStoreAutoConfiguration.java
... ... @@ -19,6 +19,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
19 19 import org.springframework.ai.vectorstore.RedisVectorStore;
20 20 import org.springframework.ai.vectorstore.RedisVectorStore.RedisVectorStoreConfig;
21 21 import org.springframework.boot.autoconfigure.AutoConfiguration;
  22 +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24 25 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
... ... @@ -31,13 +32,14 @@ import redis.clients.jedis.JedisPooled;
31 32 * TODO @xin 先拿 spring-ai 最新代码覆盖,1.0.0-M1 跟 redis 自动配置会冲突
32 33 *
33 34 * TODO 这个官方,有说啥时候 fix 哇?
  35 + * TODO 看着是列在1.0.0-M2版本
34 36 *
35 37 * @author Christian Tzolov
36 38 * @author Eddú Meléndez
37 39 */
38 40 @AutoConfiguration(after = RedisAutoConfiguration.class)
39 41 @ConditionalOnClass({JedisPooled.class, JedisConnectionFactory.class, RedisVectorStore.class, EmbeddingModel.class})
40   -//@ConditionalOnBean(JedisConnectionFactory.class)
  42 +@ConditionalOnBean(JedisConnectionFactory.class)
41 43 @EnableConfigurationProperties(RedisVectorStoreProperties.class)
42 44 public class RedisVectorStoreAutoConfiguration {
43 45  
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/webapp/test/Fel.pdf deleted
No preview for this file type
yudao-server/src/main/resources/application.yaml
... ... @@ -151,6 +151,12 @@ spring:
151 151 redis:
152 152 index: default-index
153 153 prefix: "default:"
  154 + embedding:
  155 + transformer:
  156 + onnx:
  157 + model-uri: http://test.yudao.iocoder.cn/model.onnx
  158 + tokenizer:
  159 + uri: http://test.yudao.iocoder.cn/tokenizer.json
154 160 qianfan: # 文心一言
155 161 api-key: x0cuLZ7XsaTCU08vuJWO87Lg
156 162 secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
... ...