3 Revīzijas 94e049c880 ... 9e8795a9dc

Autors SHA1 Ziņojums Datums
  183207892172 9e8795a9dc Merge branch 'master' of https://gogs.storlead.com/storlead/storlead-sasa-platform 5 stundas atpakaļ
  183207892172 996c53a922 新增新建训练,查看训练 5 stundas atpakaļ
  183207892172 20c5a30425 新增新建训练,查看训练 5 stundas atpakaļ
16 mainītis faili ar 736 papildinājumiem un 1 dzēšanām
  1. 19 0
      java/storlead-knowledge/sql/ai_datasets_file.sql
  2. 19 0
      java/storlead-knowledge/sql/ai_training.sql
  3. 1 1
      java/storlead-knowledge/storlead-knowledge-api/src/main/java/com/storlead/knowledge/api/DocumentController.java
  4. 197 0
      java/storlead-knowledge/storlead-knowledge-api/src/main/java/com/storlead/knowledge/api/KnowledgeController.java
  5. 16 0
      java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/mapper/AiDatasetsFileMapper.java
  6. 16 0
      java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/mapper/AiTrainingMapper.java
  7. 56 0
      java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/service/impl/AiDatasetsFileServiceImpl.java
  8. 58 0
      java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/service/impl/AiTrainingServiceImpl.java
  9. 21 0
      java/storlead-knowledge/storlead-knowledge-biz/src/main/resources/mapper/AiDatasetsFileMapper.xml
  10. 56 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/entity/AiDatasetsFileEntity.java
  11. 50 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/entity/AiTrainingEntity.java
  12. 41 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/dto/AiDatasetsFileDTO.java
  13. 40 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/dto/AiTrainingDTO.java
  14. 56 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/vo/AiDatasetsFileVO.java
  15. 59 0
      java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/vo/AiTrainingVO.java
  16. 31 0
      java/storlead-knowledge/storlead-knowledge-spi/src/main/java/com/storlead/knowledge/service/AiDatasetsFileService.java

+ 19 - 0
java/storlead-knowledge/sql/ai_datasets_file.sql

@@ -0,0 +1,19 @@
+-- AI训练文件表
+CREATE TABLE `ai_datasets_file` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `file_name` varchar(255) DEFAULT NULL COMMENT '文件名称',
+  `document_id` varchar(100) DEFAULT NULL COMMENT '文本id',
+  `ai_training_id` bigint(20) DEFAULT NULL COMMENT '训练表id',
+  `indexing_status` varchar(50) DEFAULT NULL COMMENT '索引状态',
+  `owner_by` bigint(20) DEFAULT NULL COMMENT '所有者',
+  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
+  `update_by` bigint(20) DEFAULT NULL COMMENT '更新人',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否删除:0-未删除,1-已删除',
+  `enabled` tinyint(1) DEFAULT '1' COMMENT '是否启用:0-禁用,1-启用',
+  `sort` int(11) DEFAULT '0' COMMENT '排序',
+  PRIMARY KEY (`id`),
+  KEY `idx_ai_training_id` (`ai_training_id`),
+  KEY `idx_indexing_status` (`indexing_status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI训练文件表';

+ 19 - 0
java/storlead-knowledge/sql/ai_training.sql

@@ -0,0 +1,19 @@
+-- AI训练记录表
+CREATE TABLE `ai_training` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `datasets_id` varchar(100) DEFAULT NULL COMMENT '知识库ID',
+  `title` varchar(200) DEFAULT NULL COMMENT '标题',
+  `description` text DEFAULT NULL COMMENT '描述',
+  `status` int(11) DEFAULT '0' COMMENT '状态:0-禁用,1-启用',
+  `owner_by` bigint(20) DEFAULT NULL COMMENT '所有者',
+  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
+  `update_by` bigint(20) DEFAULT NULL COMMENT '更新人',
+  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否删除:0-未删除,1-已删除',
+  `enabled` tinyint(1) DEFAULT '1' COMMENT '是否启用:0-禁用,1-启用',
+  `sort` int(11) DEFAULT '0' COMMENT '排序',
+  PRIMARY KEY (`id`),
+  KEY `idx_datasets_id` (`datasets_id`),
+  KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI训练记录表';

+ 1 - 1
java/storlead-knowledge/storlead-knowledge-api/src/main/java/com/storlead/knowledge/api/DocumentController.java

@@ -21,7 +21,7 @@ import java.util.Map;
 
 @RestController
 @RequestMapping("/knowledge/document/")
-@Api(tags = "知识库: 知识库管理")
+@Api(tags = "知识库: 知识库文件管理")
 public class DocumentController {
     @Resource
     private HttpService httpService;

+ 197 - 0
java/storlead-knowledge/storlead-knowledge-api/src/main/java/com/storlead/knowledge/api/KnowledgeController.java

@@ -1,19 +1,34 @@
 package com.storlead.knowledge.api;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonMappingException;
 import com.storlead.framework.common.result.Result;
 import com.storlead.knowledge.config.DifyProperties;
+import com.storlead.knowledge.entity.AiDatasetsFileEntity;
+import com.storlead.knowledge.entity.AiTrainingEntity;
 import com.storlead.knowledge.pojo.dto.KnowledgeDTO;
 import com.storlead.knowledge.utils.HttpService;
 import com.storlead.knowledge.utils.JacksonHolder;
 import com.storlead.knowledge.pojo.dto.QueryPageDTO;
+import com.storlead.knowledge.pojo.dto.AiTrainingDTO;
+import com.storlead.knowledge.pojo.dto.AiDatasetsFileDTO;
+import com.storlead.knowledge.pojo.vo.AiTrainingVO;
+import com.storlead.knowledge.pojo.vo.AiDatasetsFileVO;
+import com.storlead.knowledge.service.AiTrainingService;
+import com.storlead.knowledge.service.AiDatasetsFileService;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
 import java.util.Map;
 
 
@@ -25,6 +40,10 @@ public class KnowledgeController {
     private HttpService httpService;
     @Resource
     private DifyProperties difyProperties;
+    @Resource
+    private AiTrainingService aiTrainingService;
+    @Resource
+    private AiDatasetsFileService aiDatasetsFileService;
 
     @GetMapping("datasets")
     @ApiOperation("获取所有知识库数据集")
@@ -90,4 +109,182 @@ public class KnowledgeController {
         String url = difyProperties.getBaseUrl() + "workspaces/current/models/model-types/"+model_type;
         return httpService.get(url, null, "Bearer "+difyProperties.getDatasetApiKey(), new TypeReference<>() {});
     }
+
+    // ==================== AI训练记录管理 ====================
+
+    @GetMapping("training/page")
+    @ApiOperation("分页获取AI训练记录")
+    public Result<IPage<AiTrainingEntity>> pageTraining(@RequestParam(defaultValue = "1") Integer pageIndex,
+                                                     @RequestParam(defaultValue = "10") Integer pageSize,
+                                                     @RequestParam(required = false) String keyword,
+                                                     @RequestParam(required = false) String datasetsId) {
+        IPage<AiTrainingEntity> result = aiTrainingService.pageVO(pageIndex, pageSize, keyword, datasetsId);
+        //https://api.dify.ai/v1/datasets/{dataset_id}/documents/{batch}/indexing-status
+        String url = difyProperties.getBaseUrl() ;
+        for (AiTrainingEntity vo : result.getRecords()) {
+            if (vo.getStatus()==0){
+                List<AiDatasetsFileEntity> files = aiDatasetsFileService.pageVO(1, 1000, null, vo.getId()).getRecords();
+                Boolean flag = true;
+                for (AiDatasetsFileEntity file : files) {
+                    String url2 = difyProperties.getBaseUrl() + "datasets/"+vo.getDatasetsId()+"/documents/"+file.getBatch()+"/indexing-status";
+                    Result<Object> result1 =  httpService.get(url2, null, "Bearer "+difyProperties.getDatasetApiKey(), new TypeReference<>() {});
+                    if (result1.isSuccess()) {
+                        // 从Dify返回结果中提取document_id
+                        Object responseData = result1.getResult();
+
+                        JSONObject root = new JSONObject((Map<String, Object>) responseData);
+                        JSONArray data = root.getJSONArray("data");
+                        String indexing_status = data.getJSONObject(0).getString("indexing_status");
+
+//                        String indexing_status = null;
+//                        if (responseData instanceof Map) {
+//                            Object data = ((Map<?, ?>) responseData).get("data");
+//                            if (data instanceof Map) {
+//                                Object status = ((Map<?, ?>) data).get("indexing_status");
+//                                if (status != null) {
+//                                    indexing_status = status.toString();
+//                                }
+//                            }
+//                        }
+                        file.setIndexingStatus(indexing_status);
+                        aiDatasetsFileService.updateById(file);
+                        if (!"completed".equals(indexing_status)) {
+                            flag = false;
+                        }
+                    }
+                }
+                if (flag) {
+                    vo.setStatus(1);
+                    aiTrainingService.updateById(vo);
+                }
+            }
+        }
+        return Result.ok(result);
+    }
+
+    @GetMapping("training/{id}")
+    @ApiOperation("根据ID获取AI训练记录")
+    public Result<AiTrainingEntity> getTrainingById(@PathVariable Long id) {
+        AiTrainingEntity vo = aiTrainingService.getById(id);
+        return Result.ok(vo);
+    }
+
+    @PostMapping("training")
+    @ApiOperation("创建AI训练记录(上传文件并导入知识库)")
+    /***
+     * {"datasetsId":"xxx", "name":"训练标题", "description":"描述"}
+     */
+    public Result<Object> createTraining(
+            @RequestParam("file") MultipartFile[] files,
+            @RequestParam("data") String data
+    ) throws JsonProcessingException {
+
+            // 1. 解析DTO
+            AiTrainingEntity entity = JacksonHolder.OBJECT_MAPPER.readValue(data, AiTrainingEntity.class);
+
+            // 2. 保存训练记录到数据库
+            boolean saved = aiTrainingService.save(entity);
+            if (!saved) {
+                return Result.error("保存训练记录失败");
+            }
+
+            // 3. 逐个上传文件到知识库
+            String url = difyProperties.getBaseUrl() + "datasets/" + entity.getDatasetsId() + "/document/create-by-file";
+            for (MultipartFile file : files) {
+                if (file.isEmpty()) {
+                    continue;
+                }
+                Result<Object> uploadResult = httpService.uploadWithJson(
+                        url,
+                        file,
+                        data,
+                        "Bearer " + difyProperties.getDatasetApiKey(),
+                        new TypeReference<>() {
+                        }
+                );
+
+                // 4. 如果上传成功,保存文件记录到数据库
+                if (uploadResult.isSuccess()) {
+                    // 从Dify返回结果中提取document_id
+                    Object responseData = uploadResult.getResult();
+                    String documentId = null;
+                    String batch = null;
+                    String indexing_status = null;
+                    if (responseData instanceof Map) {
+                        Object document = ((Map<?, ?>) responseData).get("document");
+                        if (document instanceof Map) {
+                            Object id = ((Map<?, ?>) document).get("id");
+                            if (id != null) {
+                                documentId = id.toString();
+                            }
+                            Object indexing_status_ob = ((Map<?, ?>) document).get("indexing_status");
+                            if (id != null) {
+                                indexing_status = indexing_status_ob.toString();
+                            }
+
+                        }
+                        batch = ((Map<?, ?>) responseData).get("batch").toString();
+                    }
+
+                    AiDatasetsFileEntity fileEntity = new AiDatasetsFileEntity();
+                    fileEntity.setFileName(file.getOriginalFilename());
+                    fileEntity.setDocumentId(documentId);
+                    fileEntity.setAiTrainingId(entity.getId());
+                    fileEntity.setIndexingStatus(indexing_status);
+                    fileEntity.setBatch(batch);
+                    aiDatasetsFileService.save(fileEntity);
+                }
+            }
+
+            return Result.ok("上传成功");
+
+    }
+
+
+    @DeleteMapping("training/{id}")
+    @ApiOperation("删除AI训练记录")
+    public Result<Boolean> deleteTraining(@PathVariable Long id) {
+        boolean result = aiTrainingService.removeById(id);
+        return Result.ok(result);
+    }
+
+    // ==================== AI训练文件管理 ====================
+
+    @GetMapping("training/file/page")
+    @ApiOperation("分页获取AI训练文件")
+    public Result<IPage<AiDatasetsFileEntity>> pageTrainingFile(@RequestParam(defaultValue = "1") Integer pageIndex,
+                                                            @RequestParam(defaultValue = "10") Integer pageSize,
+                                                            @RequestParam(required = false) String keyword,
+                                                            @RequestParam(required = false) Long aiTrainingId) {
+        IPage<AiDatasetsFileEntity> result = aiDatasetsFileService.pageVO(pageIndex, pageSize, keyword, aiTrainingId);
+        return Result.ok(result);
+    }
+
+//    @GetMapping("training/file/{id}")
+//    @ApiOperation("根据ID获取AI训练文件")
+//    public Result<AiDatasetsFileEntity> getTrainingFileById(@PathVariable Long id) {
+//        AiDatasetsFileEntity vo = aiDatasetsFileService.getById(id);
+//        return Result.ok(vo);
+//    }
+
+//    @PostMapping("training/file")
+//    @ApiOperation("创建AI训练文件")
+//    public Result<Boolean> createTrainingFile(@Valid @RequestBody AiDatasetsFileEntity dto) {
+//        boolean result = aiDatasetsFileService.save(dto);
+//        return Result.ok(result);
+//    }
+
+//    @PutMapping("training/file")
+//    @ApiOperation("更新AI训练文件")
+//    public Result<Boolean> updateTrainingFile(@Valid @RequestBody AiDatasetsFileEntity dto) {
+//        boolean result = aiDatasetsFileService.updateById(dto);
+//        return Result.ok(result);
+//    }
+
+//    @DeleteMapping("training/file/{id}")
+//    @ApiOperation("删除AI训练文件")
+//    public Result<Boolean> deleteTrainingFile(@PathVariable Long id) {
+//        boolean result = aiDatasetsFileService.removeById(id);
+//        return Result.ok(result);
+//    }
 }

+ 16 - 0
java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/mapper/AiDatasetsFileMapper.java

@@ -0,0 +1,16 @@
+package com.storlead.knowledge.mapper;
+
+import com.storlead.framework.mybatis.mapper.MyBaseMapper;
+import com.storlead.knowledge.entity.AiDatasetsFileEntity;
+
+/**
+ * <p>
+ * AI训练文件表 Mapper 接口
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+public interface AiDatasetsFileMapper extends MyBaseMapper<AiDatasetsFileEntity> {
+
+}

+ 16 - 0
java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/mapper/AiTrainingMapper.java

@@ -0,0 +1,16 @@
+package com.storlead.knowledge.mapper;
+
+import com.storlead.framework.mybatis.mapper.MyBaseMapper;
+import com.storlead.knowledge.entity.AiTrainingEntity;
+
+/**
+ * <p>
+ * AI训练记录表 Mapper 接口
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+public interface AiTrainingMapper extends MyBaseMapper<AiTrainingEntity> {
+
+}

+ 56 - 0
java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/service/impl/AiDatasetsFileServiceImpl.java

@@ -0,0 +1,56 @@
+package com.storlead.knowledge.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.knowledge.entity.AiDatasetsFileEntity;
+import com.storlead.knowledge.mapper.AiDatasetsFileMapper;
+import com.storlead.knowledge.pojo.dto.AiDatasetsFileDTO;
+import com.storlead.knowledge.pojo.vo.AiDatasetsFileVO;
+import com.storlead.knowledge.service.AiDatasetsFileService;
+import ma.glasnost.orika.impl.DefaultMapperFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * <p>
+ * AI训练文件表 服务实现类
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Service
+public class AiDatasetsFileServiceImpl extends MyBaseServiceImpl<AiDatasetsFileMapper, AiDatasetsFileEntity> implements AiDatasetsFileService {
+
+    @Override
+    public IPage<AiDatasetsFileEntity> pageVO(Integer pageIndex, Integer pageSize, String keyword, Long aiTrainingId) {
+        Page<AiDatasetsFileEntity> page = new Page<>(pageIndex, pageSize);
+        LambdaQueryWrapper<AiDatasetsFileEntity> wrapper = new LambdaQueryWrapper<>();
+
+        // 添加查询条件
+        wrapper.eq(AiDatasetsFileEntity::getIsDelete, 0);
+        if (aiTrainingId != null) {
+            wrapper.eq(AiDatasetsFileEntity::getAiTrainingId, aiTrainingId);
+        }
+        if (StringUtils.hasText(keyword)) {
+            wrapper.like(AiDatasetsFileEntity::getFileName, keyword);
+        }
+        wrapper.orderByDesc(AiDatasetsFileEntity::getCreateTime);
+
+        IPage<AiDatasetsFileEntity> entityPage = this.page(page, wrapper);
+
+        // 转换为VO
+        DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
+        IPage<AiDatasetsFileEntity> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize());
+        voPage.setTotal(entityPage.getTotal());
+        voPage.setRecords(entityPage.getRecords());
+//        voPage.setRecords(mapperFactory.getMapperFacade().mapAsList(entityPage.getRecords(), AiDatasetsFileVO.class));
+
+        return voPage;
+    }
+
+}

+ 58 - 0
java/storlead-knowledge/storlead-knowledge-biz/src/main/java/com/storlead/knowledge/service/impl/AiTrainingServiceImpl.java

@@ -0,0 +1,58 @@
+package com.storlead.knowledge.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.knowledge.entity.AiTrainingEntity;
+import com.storlead.knowledge.mapper.AiTrainingMapper;
+import com.storlead.knowledge.pojo.dto.AiTrainingDTO;
+import com.storlead.knowledge.pojo.vo.AiTrainingVO;
+import com.storlead.knowledge.service.AiTrainingService;
+import ma.glasnost.orika.impl.DefaultMapperFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+/**
+ * <p>
+ * AI训练记录表 服务实现类
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Service
+public class AiTrainingServiceImpl extends MyBaseServiceImpl<AiTrainingMapper, AiTrainingEntity> implements AiTrainingService {
+
+    @Override
+    public IPage<AiTrainingEntity> pageVO(Integer pageIndex, Integer pageSize, String keyword, String datasetsId) {
+        Page<AiTrainingEntity> page = new Page<>(pageIndex, pageSize);
+        LambdaQueryWrapper<AiTrainingEntity> wrapper = new LambdaQueryWrapper<>();
+
+        // 添加查询条件
+        wrapper.eq(AiTrainingEntity::getIsDelete, 0);
+        if (StringUtils.hasText(datasetsId)) {
+            wrapper.eq(AiTrainingEntity::getDatasetsId, datasetsId);
+        }
+        if (StringUtils.hasText(keyword)) {
+            wrapper.and(w -> w
+                    .like(AiTrainingEntity::getName, keyword)
+                    .or()
+                    .like(AiTrainingEntity::getDescription, keyword)
+            );
+        }
+        wrapper.orderByDesc(AiTrainingEntity::getCreateTime);
+
+        IPage<AiTrainingEntity> entityPage = this.page(page, wrapper);
+
+        // 转换为VO
+//        DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
+//        IPage<AiTrainingVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize());
+//        voPage.setTotal(entityPage.getTotal());
+//        voPage.setRecords(mapperFactory.getMapperFacade().mapAsList(entityPage.getRecords(), AiTrainingVO.class));
+
+        return entityPage;
+    }
+
+
+}

+ 21 - 0
java/storlead-knowledge/storlead-knowledge-biz/src/main/resources/mapper/AiDatasetsFileMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.storlead.knowledge.mapper.AiDatasetsFileMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.storlead.knowledge.entity.AiDatasetsFileEntity"
+               extends="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.BaseResultMap">
+        <id column="id" property="id"/>
+        <result column="file_name" property="fileName"/>
+        <result column="document_id" property="documentId"/>
+        <result column="ai_training_id" property="aiTrainingId"/>
+        <result column="indexing_status" property="indexingStatus"/>
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, file_name, document_id, ai_training_id, indexing_status,
+        owner_by, create_by, update_by, create_time, update_time, is_delete, enabled, sort
+    </sql>
+
+</mapper>

+ 56 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/entity/AiDatasetsFileEntity.java

@@ -0,0 +1,56 @@
+package com.storlead.knowledge.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.storlead.framework.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * AI训练文件表
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "AiDatasetsFileEntity对象", description = "AI训练文件")
+@TableName("ai_datasets_file")
+public class AiDatasetsFileEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "文件名称")
+    @TableField("file_name")
+    private String fileName;
+
+    @ApiModelProperty(value = "文本id")
+    @TableField("document_id")
+    private String documentId;
+
+    @ApiModelProperty(value = "训练表id")
+    @TableField("ai_training_id")
+    private Long aiTrainingId;
+
+    @ApiModelProperty(value = "索引状态")
+    @TableField("indexing_status")
+    private String indexingStatus;
+
+
+    @ApiModelProperty(value = "批次")
+    @TableField("batch")
+    private String batch;
+
+}

+ 50 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/entity/AiTrainingEntity.java

@@ -0,0 +1,50 @@
+package com.storlead.knowledge.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.storlead.framework.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * AI训练记录表
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "AiTrainingEntity对象", description = "AI训练记录")
+@TableName("ai_training")
+public class AiTrainingEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "知识库ID")
+    @TableField("datasets_id")
+    private String datasetsId;
+
+    @ApiModelProperty(value = "标题")
+    @TableField("name")
+    private String name;
+
+    @ApiModelProperty(value = "描述")
+    @TableField("description")
+    private String description;
+
+    @ApiModelProperty(value = "状态:0-运行中,1-完成")
+    @TableField("status")
+    private Integer status;
+}

+ 41 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/dto/AiDatasetsFileDTO.java

@@ -0,0 +1,41 @@
+package com.storlead.knowledge.pojo.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * AI训练文件数据传输对象
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@ApiModel(value = "AiDatasetsFileDTO", description = "AI训练文件数据传输对象")
+public class AiDatasetsFileDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+
+    @ApiModelProperty(value = "文件名称")
+    @NotBlank(message = "文件名称不能为空")
+    private String fileName;
+
+    @ApiModelProperty(value = "文本id")
+    private String documentId;
+
+    @ApiModelProperty(value = "训练表id")
+    @NotNull(message = "训练表id不能为空")
+    private Long aiTrainingId;
+
+    @ApiModelProperty(value = "索引状态")
+    private String indexingStatus;
+}

+ 40 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/dto/AiTrainingDTO.java

@@ -0,0 +1,40 @@
+package com.storlead.knowledge.pojo.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * AI训练记录数据传输对象
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@ApiModel(value = "AiTrainingDTO", description = "AI训练记录数据传输对象")
+public class AiTrainingDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+
+    @ApiModelProperty(value = "知识库ID")
+    @NotBlank(message = "知识库ID不能为空")
+    private String datasetsId;
+
+    @ApiModelProperty(value = "标题")
+    @NotBlank(message = "标题不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "描述")
+    private String description;
+
+    @ApiModelProperty(value = "状态:0-运行中,1-完成")
+    private Integer status;
+}

+ 56 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/vo/AiDatasetsFileVO.java

@@ -0,0 +1,56 @@
+package com.storlead.knowledge.pojo.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * AI训练文件视图对象
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@ApiModel(value = "AiDatasetsFileVO", description = "AI训练文件视图对象")
+public class AiDatasetsFileVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+
+    @ApiModelProperty(value = "文件名称")
+    private String fileName;
+
+    @ApiModelProperty(value = "文本id")
+    private String documentId;
+
+    @ApiModelProperty(value = "训练表id")
+    private Long aiTrainingId;
+
+    @ApiModelProperty(value = "索引状态")
+    private String indexingStatus;
+
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+}

+ 59 - 0
java/storlead-knowledge/storlead-knowledge-core/src/main/java/com/storlead/knowledge/pojo/vo/AiTrainingVO.java

@@ -0,0 +1,59 @@
+package com.storlead.knowledge.pojo.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * AI训练记录视图对象
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+@Data
+@ApiModel(value = "AiTrainingVO", description = "AI训练记录视图对象")
+public class AiTrainingVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    private Long id;
+
+    @ApiModelProperty(value = "知识库ID")
+    private String datasetsId;
+
+    @ApiModelProperty(value = "标题")
+    private String name;
+
+    @ApiModelProperty(value = "描述")
+    private String description;
+
+    @ApiModelProperty(value = "状态:0-禁用,1-启用")
+    private Integer status;
+
+    @ApiModelProperty(value = "状态描述")
+    private String statusDesc;
+
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "更新人")
+    private String updateBy;
+}

+ 31 - 0
java/storlead-knowledge/storlead-knowledge-spi/src/main/java/com/storlead/knowledge/service/AiDatasetsFileService.java

@@ -0,0 +1,31 @@
+package com.storlead.knowledge.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.storlead.framework.mybatis.service.MyBaseService;
+import com.storlead.knowledge.entity.AiDatasetsFileEntity;
+import com.storlead.knowledge.pojo.dto.AiDatasetsFileDTO;
+import com.storlead.knowledge.pojo.vo.AiDatasetsFileVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * AI训练文件表 服务类
+ * </p>
+ *
+ * @author storlead
+ * @since 2026-06-09
+ */
+public interface AiDatasetsFileService extends MyBaseService<AiDatasetsFileEntity> {
+
+    /**
+     * 分页查询AI训练文件
+     *
+     * @param pageIndex    页码
+     * @param pageSize     每页大小
+     * @param keyword      关键词(可选,搜索文件名称)
+     * @param aiTrainingId 训练表id(可选)
+     * @return 分页结果
+     */
+    IPage<AiDatasetsFileEntity> pageVO(Integer pageIndex, Integer pageSize, String keyword, Long aiTrainingId);
+}