Commit 2578ca731192a5df38b9e3dcef8f64324c8859be
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
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
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java
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
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 | ... | ... |