Commit 261011d1a8b8f80d0c45f99a0f34d2e725d85eca

Authored by 芋道源码
Committed by Gitee
2 parents 6cceab5b 96fb9537

!19 AI 知识库

Merge pull request !19 from 小新/master-jdk21-ai
Showing 39 changed files with 773 additions and 191 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiChatRoleEnum.java
1 package cn.iocoder.yudao.module.ai.enums; 1 package cn.iocoder.yudao.module.ai.enums;
2 2
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
5 import lombok.Getter; 4 import lombok.Getter;
6 5
7 -import java.util.Arrays;  
8 -  
9 /** 6 /**
10 * AI 内置聊天角色的枚举 7 * AI 内置聊天角色的枚举
11 * 8 *
@@ -13,16 +10,16 @@ import java.util.Arrays; @@ -13,16 +10,16 @@ import java.util.Arrays;
13 */ 10 */
14 @AllArgsConstructor 11 @AllArgsConstructor
15 @Getter 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 1. 撰写建议:根据用户提供的主题或问题,提供详细的写作建议、情节发展方向、角色设定以及背景描写,确保内容结构清晰、有逻辑。 17 1. 撰写建议:根据用户提供的主题或问题,提供详细的写作建议、情节发展方向、角色设定以及背景描写,确保内容结构清晰、有逻辑。
21 2. 回复生成:根据用户提供的场景和提示词,生成合适的对话或文字回复,确保语气和风格符合场景需求。 18 2. 回复生成:根据用户提供的场景和提示词,生成合适的对话或文字回复,确保语气和风格符合场景需求。
22 除此之外不需要除了正文内容外的其他回复,如标题、开头、任何解释性语句或道歉。 19 除此之外不需要除了正文内容外的其他回复,如标题、开头、任何解释性语句或道歉。
23 """), 20 """),
24 21
25 - AI_MIND_MAP_ROLE(2, "导图助手", """ 22 + AI_MIND_MAP_ROLE("导图助手", """
26 你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子: 23 你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:
27 # Geek-AI 助手 24 # Geek-AI 助手
28 ## 完整的开源系统 25 ## 完整的开源系统
@@ -39,11 +36,6 @@ public enum AiChatRoleEnum implements IntArrayValuable { @@ -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,11 +46,4 @@ public enum AiChatRoleEnum implements IntArrayValuable {
54 */ 46 */
55 private final String systemMessage; 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,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4
5 /** 5 /**
6 * AI 错误码枚举类 6 * AI 错误码枚举类
7 - * 7 + * <p>
8 * ai 系统,使用 1-040-000-000 段 8 * ai 系统,使用 1-040-000-000 段
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
@@ -55,5 +55,7 @@ public interface ErrorCodeConstants { @@ -55,5 +55,7 @@ public interface ErrorCodeConstants {
55 55
56 // ========== API 知识库 1-022-008-000 ========== 56 // ========== API 知识库 1-022-008-000 ==========
57 ErrorCode KNOWLEDGE_NOT_EXISTS = new ErrorCode(1_022_008_000, "知识库不存在!"); 57 ErrorCode KNOWLEDGE_NOT_EXISTS = new ErrorCode(1_022_008_000, "知识库不存在!");
  58 + ErrorCode KNOWLEDGE_DOCUMENT_NOT_EXISTS = new ErrorCode(1_022_008_001, "文档不存在!");
  59 + ErrorCode KNOWLEDGE_SEGMENT_NOT_EXISTS = new ErrorCode(1_022_008_002, "段落不存在!");
58 60
59 } 61 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeController.java
1 package cn.iocoder.yudao.module.ai.controller.admin.knowledge; 1 package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeCreateMyReqVO;  
5 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeUpdateMyReqVO;  
6 -import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeBaseService; 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;
7 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
8 import io.swagger.v3.oas.annotations.tags.Tag; 13 import io.swagger.v3.oas.annotations.tags.Tag;
9 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
10 import jakarta.validation.Valid; 15 import jakarta.validation.Valid;
  16 +import org.springframework.validation.annotation.Validated;
11 import org.springframework.web.bind.annotation.*; 17 import org.springframework.web.bind.annotation.*;
12 18
13 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -19,19 +25,27 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @@ -19,19 +25,27 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
19 public class AiKnowledgeController { 25 public class AiKnowledgeController {
20 26
21 @Resource 27 @Resource
22 - private AiKnowledgeBaseService knowledgeBaseService; 28 + private AiKnowledgeService knowledgeService;
  29 +
  30 + @GetMapping("/my-page")
  31 + @Operation(summary = "获取【我的】知识库分页")
  32 + public CommonResult<PageResult<AiKnowledgeRespVO>> getKnowledgePageMy(@Validated PageParam pageReqVO) {
  33 + PageResult<AiKnowledgeDO> pageResult = knowledgeService.getKnowledgePageMy(getLoginUserId(), pageReqVO);
  34 + return success(BeanUtils.toBean(pageResult, AiKnowledgeRespVO.class));
  35 + }
  36 +
23 37
24 @PostMapping("/create-my") 38 @PostMapping("/create-my")
25 @Operation(summary = "创建【我的】知识库") 39 @Operation(summary = "创建【我的】知识库")
26 public CommonResult<Long> createKnowledgeMy(@RequestBody @Valid AiKnowledgeCreateMyReqVO createReqVO) { 40 public CommonResult<Long> createKnowledgeMy(@RequestBody @Valid AiKnowledgeCreateMyReqVO createReqVO) {
27 - return success(knowledgeBaseService.createKnowledgeMy(createReqVO, getLoginUserId())); 41 + return success(knowledgeService.createKnowledgeMy(createReqVO, getLoginUserId()));
28 } 42 }
29 43
30 44
31 @PutMapping("/update-my") 45 @PutMapping("/update-my")
32 @Operation(summary = "更新【我的】知识库") 46 @Operation(summary = "更新【我的】知识库")
33 public CommonResult<Boolean> updateKnowledgeMy(@RequestBody @Valid AiKnowledgeUpdateMyReqVO updateReqVO) { 47 public CommonResult<Boolean> updateKnowledgeMy(@RequestBody @Valid AiKnowledgeUpdateMyReqVO updateReqVO) {
34 - knowledgeBaseService.updateKnowledgeMy(updateReqVO, getLoginUserId()); 48 + knowledgeService.updateKnowledgeMy(updateReqVO, getLoginUserId());
35 return success(true); 49 return success(true);
36 } 50 }
37 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 org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  19 +
  20 +
  21 +@Tag(name = "管理后台 - AI 知识库-文档")
  22 +@RestController
  23 +@RequestMapping("/ai/knowledge/document")
  24 +public class AiKnowledgeDocumentController {
  25 +
  26 + @Resource
  27 + private AiKnowledgeDocumentService documentService;
  28 +
  29 +
  30 + @PostMapping("/create")
  31 + @Operation(summary = "新建文档")
  32 + public CommonResult<Long> createKnowledgeDocument(@Validated AiKnowledgeDocumentCreateReqVO reqVO) {
  33 + Long knowledgeDocumentId = documentService.createKnowledgeDocument(reqVO);
  34 + return success(knowledgeDocumentId);
  35 + }
  36 +
  37 +
  38 + @GetMapping("/page")
  39 + @Operation(summary = "获取文档分页")
  40 + public CommonResult<PageResult<AiKnowledgeDocumentRespVO>> getKnowledgeDocumentPageMy(@Validated AiKnowledgeDocumentPageReqVO pageReqVO) {
  41 + PageResult<AiKnowledgeDocumentDO> pageResult = documentService.getKnowledgeDocumentPage(pageReqVO);
  42 + return success(BeanUtils.toBean(pageResult, AiKnowledgeDocumentRespVO.class));
  43 + }
  44 +
  45 +
  46 + @PutMapping("/update")
  47 + @Operation(summary = "更新文档")
  48 + public CommonResult<Boolean> updateKnowledgeDocument(@Validated @RequestBody AiKnowledgeDocumentUpdateReqVO reqVO) {
  49 + documentService.updateKnowledgeDocument(reqVO);
  50 + return success(true);
  51 + }
  52 +
  53 +
  54 +}
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 org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  19 +
  20 +
  21 +@Tag(name = "管理后台 - AI 知识库-段落")
  22 +@RestController
  23 +@RequestMapping("/ai/knowledge/segment")
  24 +public class AiKnowledgeSegmentController {
  25 +
  26 + @Resource
  27 + private AiKnowledgeSegmentService segmentService;
  28 +
  29 + @GetMapping("/page")
  30 + @Operation(summary = "获取段落分页")
  31 + public CommonResult<PageResult<AiKnowledgeSegmentRespVO>> getKnowledgeSegmentPageMy(@Validated AiKnowledgeSegmentPageReqVO pageReqVO) {
  32 + PageResult<AiKnowledgeSegmentDO> pageResult = segmentService.getKnowledgeSegmentPage(pageReqVO);
  33 + return success(BeanUtils.toBean(pageResult, AiKnowledgeSegmentRespVO.class));
  34 + }
  35 +
  36 +
  37 + @PutMapping("/update")
  38 + @Operation(summary = "更新段落内容")
  39 + public CommonResult<Boolean> updateKnowledgeSegment(@Validated @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(@Validated @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 +}
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 = "内容", 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 数量", example = "1024")
  27 + private Integer tokens;
  28 +
  29 + @Schema(description = "字符数", example = "1008")
  30 + private Integer wordCount;
  31 +
  32 + @Schema(description = "切片状态", example = "1")
  33 + private Integer sliceStatus;
  34 +
  35 + @Schema(description = "文档状态", example = "1")
  36 + private Integer status;
  37 +}
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 io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +
  8 +@Schema(description = "管理后台 - AI 更新 知识库-文档 Request VO")
  9 +@Data
  10 +public class AiKnowledgeDocumentUpdateReqVO {
  11 +
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
  14 + @NotNull(message = "编号不能为空")
  15 + private Long id;
  16 +
  17 + @Schema(description = "是否启用", example = "1")
  18 + private Integer status;
  19 +
  20 + @Schema(description = "名称", example = "Java 开发手册")
  21 + private String name;
  22 +
  23 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/AiKnowledgeCreateMyReqVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeCreateMyReqVO.java
1 -package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo; 1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotBlank; 4 import jakarta.validation.constraints.NotBlank;
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/AiKnowledgeDocumentCreateReqVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeDocumentCreateReqVO.java
1 -package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo; 1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotBlank; 4 import jakarta.validation.constraints.NotBlank;
@@ -6,10 +6,8 @@ import jakarta.validation.constraints.NotNull; @@ -6,10 +6,8 @@ import jakarta.validation.constraints.NotNull;
6 import lombok.Data; 6 import lombok.Data;
7 import org.hibernate.validator.constraints.URL; 7 import org.hibernate.validator.constraints.URL;
8 8
9 -/**  
10 - * @author xiaoxin  
11 - */  
12 -@Schema(description = "管理后台 - AI 知识库【创建文档】 Request VO") 9 +
  10 +@Schema(description = "管理后台 - AI 知识库创建【文档】 Request VO")
13 @Data 11 @Data
14 public class AiKnowledgeDocumentCreateReqVO { 12 public class AiKnowledgeDocumentCreateReqVO {
15 13
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 = "ruoyi-vue-pro 用户指南")
  18 + private String description;
  19 +
  20 + @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "14")
  21 + private Long modelId;
  22 +
  23 + @Schema(description = "模型标识", example = "qwen-72b-chat")
  24 + private String model;
  25 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/AiKnowledgeUpdateMyReqVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/knowledge/AiKnowledgeUpdateMyReqVO.java
1 -package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo; 1 +package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotBlank; 4 import jakarta.validation.constraints.NotBlank;
@@ -7,7 +7,7 @@ import lombok.Data; @@ -7,7 +7,7 @@ import lombok.Data;
7 7
8 import java.util.List; 8 import java.util.List;
9 9
10 -@Schema(description = "管理后台 - AI 知识库创建【我的】 Request VO") 10 +@Schema(description = "管理后台 - AI 知识库更新【我的】 Request VO")
11 @Data 11 @Data
12 public class AiKnowledgeUpdateMyReqVO { 12 public class AiKnowledgeUpdateMyReqVO {
13 13
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 +
  12 + @Schema(description = "分段状态", example = "1")
  13 + private Integer status;
  14 +
  15 + @Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer documentId;
  17 +
  18 + @Schema(description = "分段内容关键字", example = "Java 开发")
  19 + private String keyword;
  20 +
  21 +}
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 数量", example = "1024")
  26 + private Integer tokens;
  27 +
  28 + @Schema(description = "字符数", example = "1008")
  29 + private Integer wordCount;
  30 +
  31 + @Schema(description = "文档状态", example = "1")
  32 + private Integer status;
  33 +}
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 io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +
  7 +@Schema(description = "管理后台 - AI 更新 知识库-段落 request VO")
  8 +@Data
  9 +public class AiKnowledgeSegmentUpdateStatusReqVO {
  10 +
  11 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
  12 + private Long id;
  13 +
  14 + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  15 + private Integer status;
  16 +
  17 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeBaseDO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java
@@ -10,15 +10,14 @@ import lombok.Data; @@ -10,15 +10,14 @@ import lombok.Data;
10 10
11 import java.util.List; 11 import java.util.List;
12 12
13 -// TODO @xin:要不把 AiKnowledgeBaseDO 改成 AiKnowledgeDO。感觉 base 后缀,感觉有点奇怪(让人以为是基类)。然后,我们很多地方的外键编号,都是 knowledgeId  
14 /** 13 /**
15 * AI 知识库 DO 14 * AI 知识库 DO
16 * 15 *
17 * @author xiaoxin 16 * @author xiaoxin
18 */ 17 */
19 -@TableName(value = "ai_knowledge_base", autoResultMap = true) 18 +@TableName(value = "ai_knowledge", autoResultMap = true)
20 @Data 19 @Data
21 -public class AiKnowledgeBaseDO extends BaseDO { 20 +public class AiKnowledgeDO extends BaseDO {
22 21
23 /** 22 /**
24 * 编号 23 * 编号
@@ -46,7 +45,7 @@ public class AiKnowledgeBaseDO extends BaseDO { @@ -46,7 +45,7 @@ public class AiKnowledgeBaseDO extends BaseDO {
46 @TableField(typeHandler = JacksonTypeHandler.class) 45 @TableField(typeHandler = JacksonTypeHandler.class)
47 private List<Long> visibilityPermissions; 46 private List<Long> visibilityPermissions;
48 /** 47 /**
49 - * 嵌入模型编号,高质量模式时维护 48 + * 嵌入模型编号
50 */ 49 */
51 private Long modelId; 50 private Long modelId;
52 /** 51 /**
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java
@@ -24,7 +24,7 @@ public class AiKnowledgeDocumentDO extends BaseDO { @@ -24,7 +24,7 @@ public class AiKnowledgeDocumentDO extends BaseDO {
24 /** 24 /**
25 * 知识库编号 25 * 知识库编号
26 * 26 *
27 - * 关联 {@link AiKnowledgeBaseDO#getId()} 27 + * 关联 {@link AiKnowledgeDO#getId()}
28 */ 28 */
29 private Long knowledgeId; 29 private Long knowledgeId;
30 /** 30 /**
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java
@@ -15,6 +15,8 @@ import lombok.Data; @@ -15,6 +15,8 @@ import lombok.Data;
15 @Data 15 @Data
16 public class AiKnowledgeSegmentDO extends BaseDO { 16 public class AiKnowledgeSegmentDO extends BaseDO {
17 17
  18 + public static final String FIELD_KNOWLEDGE_ID = "knowledgeId";
  19 +
18 /** 20 /**
19 * 编号 21 * 编号
20 */ 22 */
@@ -24,10 +26,14 @@ public class AiKnowledgeSegmentDO extends BaseDO { @@ -24,10 +26,14 @@ public class AiKnowledgeSegmentDO extends BaseDO {
24 * 向量库的编号 26 * 向量库的编号
25 */ 27 */
26 private String vectorId; 28 private String vectorId;
27 - // TODO @新:knowledgeId 加个,会方便点 29 + /**
  30 + * 知识库编号
  31 + * 关联 {@link AiKnowledgeDO#getId()}
  32 + */
  33 + private Long knowledgeId;
28 /** 34 /**
29 * 文档编号 35 * 文档编号
30 - * 36 + * <p>
31 * 关联 {@link AiKnowledgeDocumentDO#getId()} 37 * 关联 {@link AiKnowledgeDocumentDO#getId()}
32 */ 38 */
33 private Long documentId; 39 private Long documentId;
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeDocumentMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge; 1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 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;
4 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 7 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
5 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
6 9
@@ -11,4 +14,11 @@ import org.apache.ibatis.annotations.Mapper; @@ -11,4 +14,11 @@ import org.apache.ibatis.annotations.Mapper;
11 */ 14 */
12 @Mapper 15 @Mapper
13 public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocumentDO> { 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 +
14 } 24 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeBaseMapper.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge; 1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
2 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;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 -import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeBaseDO; 7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
5 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
6 10
7 /** 11 /**
@@ -10,5 +14,12 @@ import org.apache.ibatis.annotations.Mapper; @@ -10,5 +14,12 @@ import org.apache.ibatis.annotations.Mapper;
10 * @author xiaoxin 14 * @author xiaoxin
11 */ 15 */
12 @Mapper 16 @Mapper
13 -public interface AiKnowledgeBaseMapper extends BaseMapperX<AiKnowledgeBaseDO> { 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 + }
14 } 25 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge; 1 package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 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;
4 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO; 7 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
5 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
6 9
@@ -11,4 +14,12 @@ import org.apache.ibatis.annotations.Mapper; @@ -11,4 +14,12 @@ import org.apache.ibatis.annotations.Mapper;
11 */ 14 */
12 @Mapper 15 @Mapper
13 public interface AiKnowledgeSegmentMapper extends BaseMapperX<AiKnowledgeSegmentDO> { 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 + }
14 } 25 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiEmbeddingService.java deleted
1 -package cn.iocoder.yudao.module.ai.service.knowledge;  
2 -  
3 -import org.springframework.ai.document.Document;  
4 -import org.springframework.ai.vectorstore.SearchRequest;  
5 -  
6 -import java.util.List;  
7 -  
8 -/**  
9 - * AI 嵌入 Service 接口  
10 - *  
11 - * @author xiaoxin  
12 - */  
13 -public interface AiEmbeddingService {  
14 -  
15 - /**  
16 - * 向量化文档并存储  
17 - */  
18 - void add(List<Document> documents);  
19 -  
20 - /**  
21 - * 相似查询  
22 - *  
23 - * @param request 查询实体  
24 - */  
25 - List<Document> similaritySearch(SearchRequest request);  
26 -  
27 -}  
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiEmbeddingServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.ai.service.knowledge;  
2 -  
3 -import jakarta.annotation.Resource;  
4 -import org.springframework.ai.document.Document;  
5 -import org.springframework.ai.vectorstore.RedisVectorStore;  
6 -import org.springframework.ai.vectorstore.SearchRequest;  
7 -import org.springframework.stereotype.Service;  
8 -  
9 -import java.util.List;  
10 -  
11 -// TODO @xin:是不是不用 AiEmbeddingServiceImpl,直接 vectorStore 注入到需要的地方就好啦。通过 KnowledgeDocumentService 返回就好。  
12 -/**  
13 - * AI 嵌入 Service 实现类  
14 - *  
15 - * @author xiaoxin  
16 - */  
17 -@Service  
18 -public class AiEmbeddingServiceImpl implements AiEmbeddingService {  
19 -  
20 - @Resource  
21 - private RedisVectorStore vectorStore;  
22 -  
23 - @Override  
24 -// @Async  
25 - // TODO xiaoxin 报错先注释  
26 - public void add(List<Document> documents) {  
27 - vectorStore.add(documents);  
28 - }  
29 -  
30 - @Override  
31 - public List<Document> similaritySearch(SearchRequest request) {  
32 - return vectorStore.similaritySearch(request);  
33 - }  
34 -  
35 -}  
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 2
3 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeDocumentCreateReqVO; 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;
4 8
5 /** 9 /**
6 * AI 知识库-文档 Service 接口 10 * AI 知识库-文档 Service 接口
@@ -17,4 +21,19 @@ public interface AiKnowledgeDocumentService { @@ -17,4 +21,19 @@ public interface AiKnowledgeDocumentService {
17 */ 21 */
18 Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO); 22 Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO);
19 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);
20 } 39 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.http.HttpUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeDocumentCreateReqVO; 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;
8 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 13 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
9 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO; 14 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
  15 +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
10 import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeDocumentMapper; 16 import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeDocumentMapper;
11 import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper; 17 import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper;
12 import cn.iocoder.yudao.module.ai.enums.knowledge.AiKnowledgeDocumentStatusEnum; 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;
13 import jakarta.annotation.Resource; 21 import jakarta.annotation.Resource;
14 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
15 import org.springframework.ai.document.Document; 23 import org.springframework.ai.document.Document;
16 import org.springframework.ai.reader.tika.TikaDocumentReader; 24 import org.springframework.ai.reader.tika.TikaDocumentReader;
17 -import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator; 25 +import org.springframework.ai.tokenizer.TokenCountEstimator;
18 import org.springframework.ai.transformer.splitter.TokenTextSplitter; 26 import org.springframework.ai.transformer.splitter.TokenTextSplitter;
19 -import org.springframework.beans.factory.annotation.Value; 27 +import org.springframework.ai.vectorstore.VectorStore;
  28 +import org.springframework.core.io.ByteArrayResource;
20 import org.springframework.stereotype.Service; 29 import org.springframework.stereotype.Service;
21 import org.springframework.transaction.annotation.Transactional; 30 import org.springframework.transaction.annotation.Transactional;
22 31
23 import java.util.List; 32 import java.util.List;
24 -import java.util.Objects; 33 +import java.util.Map;
  34 +
  35 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  36 +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_NOT_EXISTS;
25 37
26 /** 38 /**
27 * AI 知识库-文档 Service 实现类 39 * AI 知识库-文档 Service 实现类
@@ -39,53 +51,99 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic @@ -39,53 +51,99 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
39 51
40 @Resource 52 @Resource
41 private TokenTextSplitter tokenTextSplitter; 53 private TokenTextSplitter tokenTextSplitter;
42 -  
43 @Resource 54 @Resource
44 - private AiEmbeddingService embeddingService; 55 + private TokenCountEstimator tokenCountEstimator;
45 56
46 - // TODO @xin:@Resource 注入  
47 - private static final JTokkitTokenCountEstimator TOKEN_COUNT_ESTIMATOR = new JTokkitTokenCountEstimator(); 57 + @Resource
  58 + private AiApiKeyService apiKeyService;
  59 + @Resource
  60 + private AiKnowledgeService knowledgeService;
  61 + @Resource
  62 + private AiChatModelService chatModelService;
48 63
49 - // TODO xiaoxin 临时测试用,后续删  
50 - @Value("classpath:/webapp/test/Fel.pdf")  
51 - private org.springframework.core.io.Resource data;  
52 64
53 // TODO 芋艿:需要 review 下,代码格式; 65 // TODO 芋艿:需要 review 下,代码格式;
54 - // TODO @xin:最好有 1、/2、/3 这种,让代码更有层次感  
55 @Override 66 @Override
56 @Transactional(rollbackFor = Exception.class) 67 @Transactional(rollbackFor = Exception.class)
57 public Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO) { 68 public Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO) {
58 - // TODO xiaoxin 后续从 url 加载  
59 - TikaDocumentReader loader = new TikaDocumentReader(data);  
60 - // 加载文档 69 + // 1.1 下载文档
  70 + String url = createReqVO.getUrl();
  71 + // 1.2 加载文档
  72 + TikaDocumentReader loader = new TikaDocumentReader(downloadFile(url));
61 List<Document> documents = loader.get(); 73 List<Document> documents = loader.get();
62 Document document = CollUtil.getFirst(documents); 74 Document document = CollUtil.getFirst(documents);
63 - // TODO @xin:是不是不存在,就抛出异常呀;厚泽 return 呀;  
64 - // TODO 芋艿 文档层面有没有可能会比较大,这两个字段是否可以从分段表计算得出?回复:先直接算;  
65 - Integer tokens = Objects.nonNull(document) ? TOKEN_COUNT_ESTIMATOR.estimate(document.getContent()) : 0;  
66 - Integer wordCount = Objects.nonNull(document) ? document.getContent().length() : 0; 75 + String content = document.getContent();
  76 + Integer tokens = tokenCountEstimator.estimate(content);
  77 + Integer wordCount = content.length();
67 78
  79 + // 1.3 文档记录入库
68 AiKnowledgeDocumentDO documentDO = BeanUtils.toBean(createReqVO, AiKnowledgeDocumentDO.class) 80 AiKnowledgeDocumentDO documentDO = BeanUtils.toBean(createReqVO, AiKnowledgeDocumentDO.class)
69 .setTokens(tokens).setWordCount(wordCount) 81 .setTokens(tokens).setWordCount(wordCount)
70 .setStatus(CommonStatusEnum.ENABLE.getStatus()).setSliceStatus(AiKnowledgeDocumentStatusEnum.SUCCESS.getStatus()); 82 .setStatus(CommonStatusEnum.ENABLE.getStatus()).setSliceStatus(AiKnowledgeDocumentStatusEnum.SUCCESS.getStatus());
71 - // 文档记录入库  
72 documentMapper.insert(documentDO); 83 documentMapper.insert(documentDO);
73 Long documentId = documentDO.getId(); 84 Long documentId = documentDO.getId();
74 if (CollUtil.isEmpty(documents)) { 85 if (CollUtil.isEmpty(documents)) {
75 return documentId; 86 return documentId;
76 } 87 }
77 88
78 - // 文档分段 89 + // 2.1 文档分段
79 List<Document> segments = tokenTextSplitter.apply(documents); 90 List<Document> segments = tokenTextSplitter.apply(documents);
80 - // 分段内容入库 91 + // 2.2 分段内容入库
81 List<AiKnowledgeSegmentDO> segmentDOList = CollectionUtils.convertList(segments, 92 List<AiKnowledgeSegmentDO> segmentDOList = CollectionUtils.convertList(segments,
82 - segment -> new AiKnowledgeSegmentDO().setContent(segment.getContent()).setDocumentId(documentId)  
83 - .setTokens(TOKEN_COUNT_ESTIMATOR.estimate(segment.getContent())).setWordCount(segment.getContent().length()) 93 + segment -> new AiKnowledgeSegmentDO().setContent(segment.getContent()).setDocumentId(documentId).setKnowledgeId(createReqVO.getKnowledgeId()).setVectorId(segment.getId())
  94 + .setTokens(tokenCountEstimator.estimate(segment.getContent())).setWordCount(segment.getContent().length())
84 .setStatus(CommonStatusEnum.ENABLE.getStatus())); 95 .setStatus(CommonStatusEnum.ENABLE.getStatus()));
85 segmentMapper.insertBatch(segmentDOList); 96 segmentMapper.insertBatch(segmentDOList);
86 - // 向量化并存储  
87 - embeddingService.add(segments); 97 +
  98 + // 3.1 document 补充源数据
  99 + segments.forEach(segment -> {
  100 + Map<String, Object> metadata = segment.getMetadata();
  101 + metadata.put(AiKnowledgeSegmentDO.FIELD_KNOWLEDGE_ID, createReqVO.getKnowledgeId());
  102 + });
  103 +
  104 + AiKnowledgeDO knowledge = knowledgeService.validateKnowledgeExists(createReqVO.getKnowledgeId());
  105 + AiChatModelDO model = chatModelService.validateChatModel(knowledge.getModelId());
  106 + // 3.2 获取向量存储实例
  107 + VectorStore vectorStore = apiKeyService.getOrCreateVectorStore(model.getKeyId());
  108 + // 3.3 向量化并存储
  109 + vectorStore.add(segments);
88 return documentId; 110 return documentId;
89 } 111 }
90 112
  113 + @Override
  114 + public PageResult<AiKnowledgeDocumentDO> getKnowledgeDocumentPage(AiKnowledgeDocumentPageReqVO pageReqVO) {
  115 + return documentMapper.selectPage(pageReqVO);
  116 + }
  117 +
  118 + @Override
  119 + public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) {
  120 + validateKnowledgeDocumentExists(reqVO.getId());
  121 + AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class);
  122 + documentMapper.updateById(document);
  123 + }
  124 +
  125 + /**
  126 + * 校验文档是否存在
  127 + *
  128 + * @param id 文档编号
  129 + * @return 文档信息
  130 + */
  131 + private AiKnowledgeDocumentDO validateKnowledgeDocumentExists(Long id) {
  132 + AiKnowledgeDocumentDO knowledgeDocument = documentMapper.selectById(id);
  133 + if (knowledgeDocument == null) {
  134 + throw exception(KNOWLEDGE_DOCUMENT_NOT_EXISTS);
  135 + }
  136 + return knowledgeDocument;
  137 + }
  138 +
  139 + private org.springframework.core.io.Resource downloadFile(String url) {
  140 + try {
  141 + byte[] bytes = HttpUtil.downloadBytes(url);
  142 + return new ByteArrayResource(bytes);
  143 + } catch (Exception e) {
  144 + log.error("[downloadFile][url({}) 下载失败]", url, e);
  145 + throw new RuntimeException(e);
  146 + }
  147 + }
  148 +
91 } 149 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 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 +
3 /** 9 /**
4 * AI 知识库分片 Service 接口 10 * AI 知识库分片 Service 接口
5 * 11 *
@@ -7,4 +13,25 @@ package cn.iocoder.yudao.module.ai.service.knowledge; @@ -7,4 +13,25 @@ package cn.iocoder.yudao.module.ai.service.knowledge;
7 */ 13 */
8 public interface AiKnowledgeSegmentService { 14 public interface AiKnowledgeSegmentService {
9 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);
10 } 37 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 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;
3 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
4 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
5 13
@@ -12,4 +20,23 @@ import org.springframework.stereotype.Service; @@ -12,4 +20,23 @@ import org.springframework.stereotype.Service;
12 @Slf4j 20 @Slf4j
13 public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService { 21 public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService {
14 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 + }
15 } 42 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeBaseService.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeService.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeCreateMyReqVO;  
3 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeUpdateMyReqVO; 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;
4 8
5 /** 9 /**
6 * AI 知识库-基础信息 Service 接口 10 * AI 知识库-基础信息 Service 接口
7 * 11 *
8 * @author xiaoxin 12 * @author xiaoxin
9 */ 13 */
10 -public interface AiKnowledgeBaseService { 14 +public interface AiKnowledgeService {
11 15
12 /** 16 /**
13 * 创建【我的】知识库 17 * 创建【我的】知识库
14 * 18 *
15 * @param createReqVO 创建信息 19 * @param createReqVO 创建信息
16 - * @param userId 用户编号 20 + * @param userId 用户编号
17 * @return 编号 21 * @return 编号
18 */ 22 */
19 Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId); 23 Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId);
@@ -23,8 +27,24 @@ public interface AiKnowledgeBaseService { @@ -23,8 +27,24 @@ public interface AiKnowledgeBaseService {
23 * 创建【我的】知识库 27 * 创建【我的】知识库
24 * 28 *
25 * @param updateReqVO 更新信息 29 * @param updateReqVO 更新信息
26 - * @param userId 用户编号 30 + * @param userId 用户编号
27 */ 31 */
28 void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId); 32 void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId);
29 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);
30 } 50 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeBaseServiceImpl.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
2 2
3 -import cn.hutool.core.lang.Assert;  
4 import cn.hutool.core.util.ObjUtil; 3 import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeCreateMyReqVO;  
8 -import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.AiKnowledgeUpdateMyReqVO;  
9 -import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeBaseDO; 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;
10 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; 11 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
11 -import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeBaseMapper; 12 +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeMapper;
12 import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; 13 import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
13 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
14 import lombok.extern.slf4j.Slf4j; 15 import lombok.extern.slf4j.Slf4j;
@@ -24,56 +25,54 @@ import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_NOT_ @@ -24,56 +25,54 @@ import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_NOT_
24 */ 25 */
25 @Service 26 @Service
26 @Slf4j 27 @Slf4j
27 -public class AiKnowledgeBaseServiceImpl implements AiKnowledgeBaseService { 28 +public class AiKnowledgeServiceImpl implements AiKnowledgeService {
28 29
29 @Resource 30 @Resource
30 private AiChatModelService chatModalService; 31 private AiChatModelService chatModalService;
31 32
32 @Resource 33 @Resource
33 - private AiKnowledgeBaseMapper knowledgeBaseMapper; 34 + private AiKnowledgeMapper knowledgeMapper;
34 35
35 @Override 36 @Override
36 public Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId) { 37 public Long createKnowledgeMy(AiKnowledgeCreateMyReqVO createReqVO, Long userId) {
37 - // TODO @xin:貌似直接调用 chatModalService.validateChatModel(id) 完事,不用搞个方法  
38 // 1. 校验模型配置 38 // 1. 校验模型配置
39 - AiChatModelDO model = validateChatModel(createReqVO.getModelId()); 39 + AiChatModelDO model = chatModalService.validateChatModel(createReqVO.getModelId());
40 40
41 // 2. 插入知识库 41 // 2. 插入知识库
42 - // TODO @xin:不用 DO 结尾  
43 - AiKnowledgeBaseDO knowledgeBaseDO = BeanUtils.toBean(createReqVO, AiKnowledgeBaseDO.class) 42 + AiKnowledgeDO knowledgeBase = BeanUtils.toBean(createReqVO, AiKnowledgeDO.class)
44 .setModel(model.getModel()).setUserId(userId).setStatus(CommonStatusEnum.ENABLE.getStatus()); 43 .setModel(model.getModel()).setUserId(userId).setStatus(CommonStatusEnum.ENABLE.getStatus());
45 - knowledgeBaseMapper.insert(knowledgeBaseDO);  
46 - return knowledgeBaseDO.getId(); 44 + knowledgeMapper.insert(knowledgeBase);
  45 + return knowledgeBase.getId();
47 } 46 }
48 47
49 @Override 48 @Override
50 public void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId) { 49 public void updateKnowledgeMy(AiKnowledgeUpdateMyReqVO updateReqVO, Long userId) {
51 // 1.1 校验知识库存在 50 // 1.1 校验知识库存在
52 - AiKnowledgeBaseDO knowledgeBaseDO = validateKnowledgeExists(updateReqVO.getId()); 51 + AiKnowledgeDO knowledgeBaseDO = validateKnowledgeExists(updateReqVO.getId());
53 if (ObjUtil.notEqual(knowledgeBaseDO.getUserId(), userId)) { 52 if (ObjUtil.notEqual(knowledgeBaseDO.getUserId(), userId)) {
54 throw exception(KNOWLEDGE_NOT_EXISTS); 53 throw exception(KNOWLEDGE_NOT_EXISTS);
55 } 54 }
56 // 1.2 校验模型配置 55 // 1.2 校验模型配置
57 - AiChatModelDO model = validateChatModel(updateReqVO.getModelId()); 56 + AiChatModelDO model = chatModalService.validateChatModel(updateReqVO.getModelId());
58 57
59 // 2. 更新知识库 58 // 2. 更新知识库
60 - AiKnowledgeBaseDO updateDO = BeanUtils.toBean(updateReqVO, AiKnowledgeBaseDO.class); 59 + AiKnowledgeDO updateDO = BeanUtils.toBean(updateReqVO, AiKnowledgeDO.class);
61 updateDO.setModel(model.getModel()); 60 updateDO.setModel(model.getModel());
62 - knowledgeBaseMapper.updateById(updateDO); 61 + knowledgeMapper.updateById(updateDO);
63 } 62 }
64 63
65 - private AiChatModelDO validateChatModel(Long id) {  
66 - AiChatModelDO model = chatModalService.validateChatModel(id);  
67 - Assert.notNull(model, "未找到对应嵌入模型");  
68 - return model;  
69 - }  
70 -  
71 - public AiKnowledgeBaseDO validateKnowledgeExists(Long id) {  
72 - AiKnowledgeBaseDO knowledgeBase = knowledgeBaseMapper.selectById(id); 64 + @Override
  65 + public AiKnowledgeDO validateKnowledgeExists(Long id) {
  66 + AiKnowledgeDO knowledgeBase = knowledgeMapper.selectById(id);
73 if (knowledgeBase == null) { 67 if (knowledgeBase == null) {
74 throw exception(KNOWLEDGE_NOT_EXISTS); 68 throw exception(KNOWLEDGE_NOT_EXISTS);
75 } 69 }
76 return knowledgeBase; 70 return knowledgeBase;
77 } 71 }
78 72
  73 + @Override
  74 + public PageResult<AiKnowledgeDO> getKnowledgePageMy(Long userId, PageParam pageReqVO) {
  75 + return knowledgeMapper.selectPageByMy(userId, pageReqVO);
  76 + }
  77 +
79 } 78 }
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,7 +9,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveR
9 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; 9 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
10 import jakarta.validation.Valid; 10 import jakarta.validation.Valid;
11 import org.springframework.ai.chat.model.ChatModel; 11 import org.springframework.ai.chat.model.ChatModel;
  12 +import org.springframework.ai.embedding.EmbeddingModel;
12 import org.springframework.ai.image.ImageModel; 13 import org.springframework.ai.image.ImageModel;
  14 +import org.springframework.ai.vectorstore.VectorStore;
13 15
14 import java.util.List; 16 import java.util.List;
15 17
@@ -84,6 +86,14 @@ public interface AiApiKeyService { @@ -84,6 +86,14 @@ public interface AiApiKeyService {
84 ChatModel getChatModel(Long id); 86 ChatModel getChatModel(Long id);
85 87
86 /** 88 /**
  89 + * 获得 EmbeddingModel 对象
  90 + *
  91 + * @param id 编号
  92 + * @return EmbeddingModel 对象
  93 + */
  94 + EmbeddingModel getEmbeddingModel(Long id);
  95 +
  96 + /**
87 * 获得 ImageModel 对象 97 * 获得 ImageModel 对象
88 * 98 *
89 * TODO 可优化点:目前默认获取 platform 对应的第一个开启的配置用于绘画;后续可以支持配置选择 99 * TODO 可优化点:目前默认获取 platform 对应的第一个开启的配置用于绘画;后续可以支持配置选择
@@ -111,4 +121,12 @@ public interface AiApiKeyService { @@ -111,4 +121,12 @@ public interface AiApiKeyService {
111 */ 121 */
112 SunoApi getSunoApi(); 122 SunoApi getSunoApi();
113 123
  124 + /**
  125 + * 获得 vector 对象
  126 + *
  127 + * @param id 编号
  128 + * @return VectorStore 对象
  129 + */
  130 + VectorStore getOrCreateVectorStore(Long id);
  131 +
114 } 132 }
115 \ No newline at end of file 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,6 +2,7 @@ package cn.iocoder.yudao.module.ai.service.model;
2 2
3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory; 4 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
  5 +import cn.iocoder.yudao.framework.ai.core.factory.AiVectorStoreFactory;
5 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; 6 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
6 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; 7 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -13,7 +14,9 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; @@ -13,7 +14,9 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
13 import cn.iocoder.yudao.module.ai.dal.mysql.model.AiApiKeyMapper; 14 import cn.iocoder.yudao.module.ai.dal.mysql.model.AiApiKeyMapper;
14 import jakarta.annotation.Resource; 15 import jakarta.annotation.Resource;
15 import org.springframework.ai.chat.model.ChatModel; 16 import org.springframework.ai.chat.model.ChatModel;
  17 +import org.springframework.ai.embedding.EmbeddingModel;
16 import org.springframework.ai.image.ImageModel; 18 import org.springframework.ai.image.ImageModel;
  19 +import org.springframework.ai.vectorstore.VectorStore;
17 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
18 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
19 22
@@ -36,6 +39,8 @@ public class AiApiKeyServiceImpl implements AiApiKeyService { @@ -36,6 +39,8 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
36 39
37 @Resource 40 @Resource
38 private AiModelFactory modelFactory; 41 private AiModelFactory modelFactory;
  42 + @Resource
  43 + private AiVectorStoreFactory vectorFactory;
39 44
40 @Override 45 @Override
41 public Long createApiKey(AiApiKeySaveReqVO createReqVO) { 46 public Long createApiKey(AiApiKeySaveReqVO createReqVO) {
@@ -105,6 +110,13 @@ public class AiApiKeyServiceImpl implements AiApiKeyService { @@ -105,6 +110,13 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
105 } 110 }
106 111
107 @Override 112 @Override
  113 + public EmbeddingModel getEmbeddingModel(Long id) {
  114 + AiApiKeyDO apiKey = validateApiKey(id);
  115 + AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
  116 + return modelFactory.getOrCreateEmbeddingModel(platform, apiKey.getApiKey(), apiKey.getUrl());
  117 + }
  118 +
  119 + @Override
108 public ImageModel getImageModel(AiPlatformEnum platform) { 120 public ImageModel getImageModel(AiPlatformEnum platform) {
109 AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus(platform.getPlatform(), CommonStatusEnum.ENABLE.getStatus()); 121 AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus(platform.getPlatform(), CommonStatusEnum.ENABLE.getStatus());
110 if (apiKey == null) { 122 if (apiKey == null) {
@@ -132,4 +144,11 @@ public class AiApiKeyServiceImpl implements AiApiKeyService { @@ -132,4 +144,11 @@ public class AiApiKeyServiceImpl implements AiApiKeyService {
132 } 144 }
133 return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl()); 145 return modelFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl());
134 } 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 + }
135 } 154 }
136 \ No newline at end of file 155 \ No newline at end of file
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,6 +2,8 @@ package cn.iocoder.yudao.framework.ai.config;
2 2
3 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory; 3 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
4 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl; 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 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel; 7 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
6 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions; 8 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatOptions;
7 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; 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,20 +12,15 @@ import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
10 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions; 12 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatOptions;
11 import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration; 13 import com.alibaba.cloud.ai.tongyi.TongYiAutoConfiguration;
12 import lombok.extern.slf4j.Slf4j; 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 import org.springframework.ai.transformer.splitter.TokenTextSplitter; 17 import org.springframework.ai.transformer.splitter.TokenTextSplitter;
17 -import org.springframework.ai.transformers.TransformersEmbeddingModel;  
18 -import org.springframework.ai.vectorstore.RedisVectorStore;  
19 import org.springframework.boot.autoconfigure.AutoConfiguration; 18 import org.springframework.boot.autoconfigure.AutoConfiguration;
20 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 19 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21 -import org.springframework.boot.autoconfigure.data.redis.RedisProperties;  
22 import org.springframework.boot.context.properties.EnableConfigurationProperties; 20 import org.springframework.boot.context.properties.EnableConfigurationProperties;
23 import org.springframework.context.annotation.Bean; 21 import org.springframework.context.annotation.Bean;
24 import org.springframework.context.annotation.Import; 22 import org.springframework.context.annotation.Import;
25 import org.springframework.context.annotation.Lazy; 23 import org.springframework.context.annotation.Lazy;
26 -import redis.clients.jedis.JedisPooled;  
27 24
28 /** 25 /**
29 * 芋道 AI 自动配置 26 * 芋道 AI 自动配置
@@ -41,6 +38,12 @@ public class YudaoAiAutoConfiguration { @@ -41,6 +38,12 @@ public class YudaoAiAutoConfiguration {
41 return new AiModelFactoryImpl(); 38 return new AiModelFactoryImpl();
42 } 39 }
43 40
  41 + @Bean
  42 + public AiVectorStoreFactory aiVectorFactory() {
  43 + return new AiVectorStoreFactoryImpl();
  44 + }
  45 +
  46 +
44 // ========== 各种 AI Client 创建 ========== 47 // ========== 各种 AI Client 创建 ==========
45 48
46 @Bean 49 @Bean
@@ -83,35 +86,42 @@ public class YudaoAiAutoConfiguration { @@ -83,35 +86,42 @@ public class YudaoAiAutoConfiguration {
83 } 86 }
84 87
85 // ========== rag 相关 ========== 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 @Bean 115 @Bean
96 @Lazy // TODO 芋艿:临时注释,避免无法启动 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 @Bean 121 @Bean
112 @Lazy // TODO 芋艿:临时注释,避免无法启动 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 \ No newline at end of file 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,6 +4,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; 4 import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
5 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; 5 import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi;
6 import org.springframework.ai.chat.model.ChatModel; 6 import org.springframework.ai.chat.model.ChatModel;
  7 +import org.springframework.ai.embedding.EmbeddingModel;
7 import org.springframework.ai.image.ImageModel; 8 import org.springframework.ai.image.ImageModel;
8 9
9 /** 10 /**
@@ -26,6 +27,18 @@ public interface AiModelFactory { @@ -26,6 +27,18 @@ public interface AiModelFactory {
26 ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url); 27 ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url);
27 28
28 /** 29 /**
  30 + * 基于指定配置,获得 EmbeddingModel 对象
  31 + * <p>
  32 + * 如果不存在,则进行创建
  33 + *
  34 + * @param platform 平台
  35 + * @param apiKey API KEY
  36 + * @param url API URL
  37 + * @return ChatModel 对象
  38 + */
  39 + EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url);
  40 +
  41 + /**
29 * 基于默认配置,获得 ChatModel 对象 42 * 基于默认配置,获得 ChatModel 对象
30 * 43 *
31 * 默认配置,指的是在 application.yaml 配置文件中的 spring.ai 相关的配置 44 * 默认配置,指的是在 application.yaml 配置文件中的 spring.ai 相关的配置
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,6 +21,7 @@ import com.alibaba.cloud.ai.tongyi.image.TongYiImagesModel;
21 import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties; 21 import com.alibaba.cloud.ai.tongyi.image.TongYiImagesProperties;
22 import com.alibaba.dashscope.aigc.generation.Generation; 22 import com.alibaba.dashscope.aigc.generation.Generation;
23 import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis; 23 import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
  24 +import com.alibaba.dashscope.embeddings.TextEmbedding;
24 import com.azure.ai.openai.OpenAIClient; 25 import com.azure.ai.openai.OpenAIClient;
25 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration; 26 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiAutoConfiguration;
26 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties; 27 import org.springframework.ai.autoconfigure.azure.openai.AzureOpenAiChatProperties;
@@ -37,6 +38,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties; @@ -37,6 +38,7 @@ import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties;
37 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties; 38 import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiImageProperties;
38 import org.springframework.ai.azure.openai.AzureOpenAiChatModel; 39 import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
39 import org.springframework.ai.chat.model.ChatModel; 40 import org.springframework.ai.chat.model.ChatModel;
  41 +import org.springframework.ai.embedding.EmbeddingModel;
40 import org.springframework.ai.image.ImageModel; 42 import org.springframework.ai.image.ImageModel;
41 import org.springframework.ai.model.function.FunctionCallbackContext; 43 import org.springframework.ai.model.function.FunctionCallbackContext;
42 import org.springframework.ai.ollama.OllamaChatModel; 44 import org.springframework.ai.ollama.OllamaChatModel;
@@ -98,6 +100,21 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -98,6 +100,21 @@ public class AiModelFactoryImpl implements AiModelFactory {
98 } 100 }
99 101
100 @Override 102 @Override
  103 + public EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url) {
  104 + String cacheKey = buildClientCacheKey(EmbeddingModel.class, platform, apiKey, url);
  105 + return Singleton.get(cacheKey, (Func0<EmbeddingModel>) () -> {
  106 + // TODO @xin 先测试一个
  107 + switch (platform) {
  108 + case TONG_YI:
  109 + return buildTongYiEmbeddingModel(apiKey);
  110 + default:
  111 + throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
  112 + }
  113 + });
  114 + }
  115 +
  116 +
  117 + @Override
101 public ChatModel getDefaultChatModel(AiPlatformEnum platform) { 118 public ChatModel getDefaultChatModel(AiPlatformEnum platform) {
102 //noinspection EnhancedSwitchMigration 119 //noinspection EnhancedSwitchMigration
103 switch (platform) { 120 switch (platform) {
@@ -239,7 +256,7 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -239,7 +256,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
239 256
240 /** 257 /**
241 * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiChatModel( 258 * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiChatModel(
242 - * ZhiPuAiConnectionProperties, ZhiPuAiChatProperties, RestClient.Builder, List, FunctionCallbackContext, RetryTemplate, ResponseErrorHandler)} 259 + *ZhiPuAiConnectionProperties, ZhiPuAiChatProperties, RestClient.Builder, List, FunctionCallbackContext, RetryTemplate, ResponseErrorHandler)}
243 */ 260 */
244 private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) { 261 private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
245 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL); 262 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
@@ -249,7 +266,7 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -249,7 +266,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
249 266
250 /** 267 /**
251 * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiImageModel( 268 * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiImageModel(
252 - * ZhiPuAiConnectionProperties, ZhiPuAiImageProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)} 269 + *ZhiPuAiConnectionProperties, ZhiPuAiImageProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
253 */ 270 */
254 private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) { 271 private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
255 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL); 272 url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
@@ -315,4 +332,15 @@ public class AiModelFactoryImpl implements AiModelFactory { @@ -315,4 +332,15 @@ public class AiModelFactoryImpl implements AiModelFactory {
315 return new StabilityAiImageModel(stabilityAiApi); 332 return new StabilityAiImageModel(stabilityAiApi);
316 } 333 }
317 334
  335 + // ========== 各种创建 EmbeddingModel 的方法 ==========
  336 +
  337 + /**
  338 + * 可参考 {@link TongYiAutoConfiguration#tongYiTextEmbeddingClient(TextEmbedding, TongYiConnectionProperties)}
  339 + */
  340 + private EmbeddingModel buildTongYiEmbeddingModel(String apiKey) {
  341 + TongYiConnectionProperties connectionProperties = new TongYiConnectionProperties();
  342 + connectionProperties.setApiKey(apiKey);
  343 + return new TongYiAutoConfiguration().tongYiTextEmbeddingClient(SpringUtil.getBean(TextEmbedding.class), connectionProperties);
  344 + }
  345 +
318 } 346 }
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 +/**
  8 + * AI Vector 模型工厂的接口类
  9 + * @author xiaoxin
  10 + */
  11 +public interface AiVectorStoreFactory {
  12 +
  13 +
  14 + /**
  15 + * 基于指定配置,获得 VectorStore 对象
  16 + * <p>
  17 + * 如果不存在,则进行创建
  18 + *
  19 + * @param embeddingModel 嵌入模型
  20 + * @param platform 平台
  21 + * @param apiKey API KEY
  22 + * @param url API URL
  23 + * @return VectorStore 对象
  24 + */
  25 + VectorStore getOrCreateVectorStore(EmbeddingModel embeddingModel, AiPlatformEnum platform, String apiKey, String url);
  26 +
  27 +}
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 + String index = "default-index";
  30 + String prefix = "default:";
  31 + var config = RedisVectorStore.RedisVectorStoreConfig.builder()
  32 + .withIndexName(index)
  33 + .withPrefix(prefix)
  34 + .build();
  35 + RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
  36 + RedisVectorStore redisVectorStore = new RedisVectorStore(config, embeddingModel,
  37 + new JedisPooled(redisProperties.getHost(), redisProperties.getPort()),
  38 + true);
  39 + redisVectorStore.afterPropertiesSet();
  40 + return redisVectorStore;
  41 + });
  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 +}
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,6 +19,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
19 import org.springframework.ai.vectorstore.RedisVectorStore; 19 import org.springframework.ai.vectorstore.RedisVectorStore;
20 import org.springframework.ai.vectorstore.RedisVectorStore.RedisVectorStoreConfig; 20 import org.springframework.ai.vectorstore.RedisVectorStore.RedisVectorStoreConfig;
21 import org.springframework.boot.autoconfigure.AutoConfiguration; 21 import org.springframework.boot.autoconfigure.AutoConfiguration;
  22 +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 23 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; 25 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
@@ -38,7 +39,7 @@ import redis.clients.jedis.JedisPooled; @@ -38,7 +39,7 @@ import redis.clients.jedis.JedisPooled;
38 */ 39 */
39 @AutoConfiguration(after = RedisAutoConfiguration.class) 40 @AutoConfiguration(after = RedisAutoConfiguration.class)
40 @ConditionalOnClass({JedisPooled.class, JedisConnectionFactory.class, RedisVectorStore.class, EmbeddingModel.class}) 41 @ConditionalOnClass({JedisPooled.class, JedisConnectionFactory.class, RedisVectorStore.class, EmbeddingModel.class})
41 -//@ConditionalOnBean(JedisConnectionFactory.class) 42 +@ConditionalOnBean(JedisConnectionFactory.class)
42 @EnableConfigurationProperties(RedisVectorStoreProperties.class) 43 @EnableConfigurationProperties(RedisVectorStoreProperties.class)
43 public class RedisVectorStoreAutoConfiguration { 44 public class RedisVectorStoreAutoConfiguration {
44 45
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/resources/webapp/test/Fel.pdf deleted
No preview for this file type