Commit 3344c79c authored by 林洋洋's avatar 林洋洋

切片相关代码提交

parent 67d9f272
......@@ -24,7 +24,7 @@ public class DocumentSegmentResult {
/**
* 文件名
*/
@Schema(description = "文件")
@Schema(description = "文件路径")
private String filePath;
/**
......@@ -39,6 +39,12 @@ public class DocumentSegmentResult {
@Schema(description = "总分段数")
private Integer totalSegments;
/**
* 总分段数
*/
@Schema(description = "文件大小")
private Long fileSize;
/**
* 文档分段详情
......@@ -68,7 +74,7 @@ public class DocumentSegmentResult {
/**
* 分段token数(预估)
*/
@Schema(description = "分段token数(预估)")
private Integer tokenCount;
@Schema(description = "标题")
private String title;
}
}
\ No newline at end of file
......@@ -83,6 +83,11 @@ public class KnowledgeDocument extends BaseEntity {
@Schema(description = "总token数量")
private Integer tokenCount;
/**
* 分段数量
*/
@Schema(description = "启用状态 0停用 1启用")
private Integer isEnabled;
/**
* 删除标记,0未删除,1已删除
*/
......
//package com.ask.config;
//
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.scheduling.annotation.EnableAsync;
//import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
//
//import java.util.concurrent.Executor;
//import java.util.concurrent.ThreadPoolExecutor;
//
///**
// * 异步配置类
// *
// * @author ai
// * @date 2024/12/19
// */
//@Slf4j
//@Configuration
//@EnableAsync
//public class AsyncConfig {
//
// /**
// * 向量化任务执行器
// */
// @Bean("vectorizeExecutor")
// public Executor vectorizeExecutor() {
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// executor.setCorePoolSize(2);
// executor.setMaxPoolSize(5);
// executor.setQueueCapacity(100);
// executor.setKeepAliveSeconds(60);
// executor.setThreadNamePrefix("vectorize-");
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// executor.setWaitForTasksToCompleteOnShutdown(true);
// executor.setAwaitTerminationSeconds(60);
// executor.initialize();
//
// log.info("向量化任务执行器初始化完成");
// return executor;
// }
//}
\ No newline at end of file
//package com.ask.config;
//
//import com.pig4cloud.pig.ask.api.entity.GenDatasourceConf;
//import com.pig4cloud.pig.ask.service.GenDatasourceConfService;
//import org.jasypt.encryption.StringEncryptor;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.CommandLineRunner;
//import org.springframework.stereotype.Component;
//
//import java.util.List;
//
//@Component
//public class InitDataBase implements CommandLineRunner {
//
// @Autowired
// private GenDatasourceConfService genDatasourceConfService;
// @Autowired
// private StringEncryptor stringEncryptor;
//
// @Override
// public void run(String... args) throws Exception {
// List<GenDatasourceConf> genDatasourceConfList = genDatasourceConfService.list();
// genDatasourceConfList.forEach(conf->{
// conf.setPassword(stringEncryptor.decrypt(conf.getPassword()));
// genDatasourceConfService.addDynamicDataSource(conf);
// });
// }
//}
package com.ask.controller;
import com.ask.api.entity.AskVectorStore;
import com.ask.common.core.R;
import com.ask.service.AskVectorStoreService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 向量存储管理
*
* @author ai
* @date 2024/12/20
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/vector/store")
@Tag(description = "askVectorStore", name = "向量存储管理")
public class AskVectorStoreController {
private final AskVectorStoreService askVectorStoreService;
private final ObjectMapper objectMapper;
/**
* 分页查询向量存储
*
* @param page 分页对象
* @param documentId 文档ID(非必填)
* @param content 内容关键词(非必填,模糊搜索)
* @return 分页数据
*/
@Operation(summary = "分页查询向量存储", description = "分页查询向量存储数据(不包含向量字段)")
@GetMapping("/page")
public R<IPage<AskVectorStore>> getPage(Page page,
@Parameter(description = "文档ID") @RequestParam Long documentId,
@Parameter(description = "内容关键词") @RequestParam(required = false) String content,
@Parameter(description = "标题关键词") @RequestParam(required = false) String title
) {
LambdaQueryWrapper<AskVectorStore> wrapper = Wrappers.lambdaQuery(AskVectorStore.class)
.like(org.apache.commons.lang3.StringUtils.isNoneBlank(content), AskVectorStore::getContent, content.trim())
.like(org.apache.commons.lang3.StringUtils.isNoneBlank(title), AskVectorStore::getContent, title.trim())
.eq(AskVectorStore::getDocumentId, documentId)
.orderByDesc(AskVectorStore::getId);
IPage<AskVectorStore> result = askVectorStoreService.page(page, wrapper);
return R.ok(result);
}
/**
* 通过ID查询向量存储
*
* @param id ID
* @return 向量存储数据
*/
@Operation(summary = "通过ID查询", description = "通过ID查询向量存储数据(不包含向量字段)")
@GetMapping("/{id}")
public R<AskVectorStore> getById(@PathVariable("id") String id) {
if (!StringUtils.hasText(id)) {
return R.failed("ID不能为空");
}
return R.ok(askVectorStoreService.getById(id));
}
/**
* 修改切片启用状态
*
* @param segmentId 切片ID
* @param isEnabled 启用状态(1:启用,0:禁用)
* @return 修改结果
*/
@Operation(summary = "修改切片启用状态", description = "修改指定切片的启用状态")
@PutMapping("/segment/status/{segmentId}")
public R<Boolean> updateSegmentStatus(@Parameter(description = "切片ID") @PathVariable String segmentId,
@Parameter(description = "启用状态(1:启用,0:禁用)") @RequestParam Integer isEnabled) {
return R.ok(askVectorStoreService.update(Wrappers.<AskVectorStore>lambdaUpdate().eq(AskVectorStore::getId, segmentId)
.set(AskVectorStore::getIsEnabled, isEnabled)));
}
/**
* 修改向量存储
*
* @param askVectorStore 向量存储数据
* @return 操作结果
*/
@Operation(summary = "修改向量存储", description = "修改向量存储数据")
@PutMapping
public R<Boolean> updateById(@Valid @RequestBody AskVectorStore askVectorStore) {
if (!StringUtils.hasText(askVectorStore.getId())) {
return R.failed("ID不能为空");
}
boolean result = askVectorStoreService.updateById(askVectorStore);
return R.ok(result, result ? "修改成功" : "修改失败");
}
/**
* 批量删除向量存储
*
* @param ids ID列表
* @return 操作结果
*/
@Operation(summary = "批量删除", description = "批量删除向量存储数据")
@DeleteMapping("/batch")
public R<Boolean> removeBatchByIds(@RequestBody List<String> ids) {
if (ids == null || ids.isEmpty()) {
return R.failed("ID列表不能为空");
}
try {
boolean result = askVectorStoreService.removeByIds(ids);
return R.ok(result, result ? "批量删除成功" : "批量删除失败");
} catch (Exception e) {
log.error("批量删除向量存储失败,IDs: {}, 错误: {}", ids, e.getMessage(), e);
return R.failed("批量删除失败:" + e.getMessage());
}
}
}
......@@ -5,10 +5,12 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.ask.api.dto.DocumentSegmentRequest;
import com.ask.api.dto.DocumentSegmentResult;
import com.ask.api.entity.AskVectorStore;
import com.ask.api.entity.KnowledgeDocument;
import com.ask.api.entity.SysFile;
import com.ask.common.core.FileTemplate;
import com.ask.common.core.R;
import com.ask.service.AskVectorStoreService;
import com.ask.service.KnowledgeDocumentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
......@@ -22,6 +24,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
......@@ -46,9 +49,12 @@ public class KnowledgeDocumentController {
private final KnowledgeDocumentService knowledgeDocumentService;
private final FileTemplate fileTemplate;
private final AskVectorStoreService askVectorStoreService;
/**
* 分页查询
*
* @param page 分页对象
* @param knowledgeBaseId 知识库ID(必填)
* @param name 文档名称(非必填,模糊搜索)
......@@ -58,7 +64,7 @@ public class KnowledgeDocumentController {
@GetMapping("/page")
public R<IPage<KnowledgeDocument>> getPage(Page page,
@Parameter(description = "知识库id") @RequestParam Long knowledgeBaseId,
@Parameter(description = "知识库名称") @RequestParam(required = false) String name) {
@Parameter(description = "文档名称") @RequestParam(required = false) String name) {
LambdaQueryWrapper<KnowledgeDocument> wrapper = Wrappers.lambdaQuery();
// 知识库ID必填条件
......@@ -74,19 +80,20 @@ public class KnowledgeDocumentController {
return R.ok(knowledgeDocumentService.page(page, wrapper));
}
/**
* 通过id查询知识库文档
* @param id id
* @return R
*/
@Operation(summary = "通过id查询", description = "通过id查询")
@GetMapping("/{id}")
public R<KnowledgeDocument> getById(@PathVariable("id") Long id) {
return R.ok(knowledgeDocumentService.getById(id));
}
// /**
// * 通过id查询知识库文档
// * @param id id
// * @return R
// */
// @Operation(summary = "通过id查询", description = "通过id查询")
// @GetMapping("/{id}")
// public R<KnowledgeDocument> getById(@PathVariable("id") Long id) {
// return R.ok(knowledgeDocumentService.getById(id));
// }
/**
* 新增知识库文档
*
* @param knowledgeBaseId 知识库ID
* @param segmentResults 文档分段结果列表
* @return R
......@@ -114,30 +121,38 @@ public class KnowledgeDocumentController {
}
}
/**
* 修改知识库文档
* @param knowledgeDocument 知识库文档
* @return R
*/
@Operation(summary = "修改知识库文档", description = "修改知识库文档")
@PutMapping
public R<Boolean> updateById(@RequestBody KnowledgeDocument knowledgeDocument) {
return R.ok(knowledgeDocumentService.updateById(knowledgeDocument));
}
// /**
// * 修改知识库文档
// * @param knowledgeDocument 知识库文档
// * @return R
// */
// @Operation(summary = "修改知识库文档", description = "修改知识库文档")
// @PutMapping
// public R<Boolean> updateById(@RequestBody KnowledgeDocument knowledgeDocument) {
// return R.ok(knowledgeDocumentService.updateById(knowledgeDocument));
// }
/**
* 通过id删除知识库文档
* @param id id
*
* @param ids
* @return R
*/
@Operation(summary = "通过id删除知识库文档", description = "通过id删除知识库文档")
@DeleteMapping("/{id}")
public R<Boolean> removeById(@PathVariable Long id) {
return R.ok(knowledgeDocumentService.removeById(id));
@Operation(summary = "批量知识库文档", description = "通过id删除知识库文档")
@DeleteMapping("/batch")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> removeById(@RequestBody List<Long> ids) {
ids.forEach(id -> {
knowledgeDocumentService.removeById(id);
askVectorStoreService.remove(Wrappers.lambdaQuery(AskVectorStore.class).eq(AskVectorStore::getDocumentId, id));
});
return R.ok(true);
}
/**
* 文档分段处理
*
* @param request 请求体
* @return 文档分段结果列表
*/
......@@ -156,6 +171,7 @@ public class KnowledgeDocumentController {
/**
* 检查文件类型是否支持
*
* @param fileName 文件名
* @return 是否支持
*/
......@@ -176,6 +192,38 @@ public class KnowledgeDocumentController {
extension.endsWith(".odt");
}
/**
* 修改文档启用状态
*
* @param documentId 文档ID
* @param isEnabled 启用状态(1:启用,0:禁用)
* @return 修改结果
*/
@Operation(summary = "修改文档启用状态", description = "修改指定文档的启用状态")
@PutMapping("/status/{documentId}")
public R<Boolean> updateDocumentStatus(@Parameter(description = "文档ID") @PathVariable Long documentId,
@Parameter(description = "启用状态(1:启用,0:禁用)") @RequestParam Integer isEnabled) {
// 参数校验
if (documentId == null || documentId <= 0) {
return R.failed("文档ID不能为空且必须大于0");
}
if (isEnabled == null || (isEnabled != 0 && isEnabled != 1)) {
return R.failed("启用状态参数无效,只能为0(禁用)或1(启用)");
}
try {
boolean result = knowledgeDocumentService.updateDocumentStatus(documentId, isEnabled);
if (result) {
return R.ok(true, "文档状态修改成功");
} else {
return R.failed("文档状态修改失败,请检查文档是否存在");
}
} catch (Exception e) {
log.error("修改文档状态异常,文档ID: {}, 状态: {}, 错误: {}", documentId, isEnabled, e.getMessage(), e);
return R.failed("修改文档状态失败:" + e.getMessage());
}
}
}
\ No newline at end of file
///*
// * Copyright (c) 2018-2025, lengleng All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions are met:
// *
// * Redistributions of source code must retain the above copyright notice,
// * this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// * notice, this list of conditions and the following disclaimer in the
// * documentation and/or other materials provided with the distribution.
// * Neither the name of the pig4cloud.com developer nor the names of its
// * contributors may be used to endorse or promote products derived from
// * this software without specific prior written permission.
// * Author: lengleng (wangiegie@gmail.com)
// */
//package com.ask.service;
//
//import com.ask.api.entity.GenDatasourceConf;
//import com.baomidou.mybatisplus.extension.service.IService;
//
//
//
///**
// * 数据源配置服务接口 提供数据源的增删改查及校验等功能
// *
// * @author lengleng
// * @date 2025/05/31
// */
//public interface GenDatasourceConfService extends IService<GenDatasourceConf> {
//
// /**
// * 保存数据源并加密
// * @param genDatasourceConf 数据源配置信息
// * @return 保存是否成功
// */
// Boolean saveDsByEnc(GenDatasourceConf genDatasourceConf);
//
// /**
// * 更新数据源
// * @param genDatasourceConf 数据源配置信息
// * @return 更新是否成功
// */
// Boolean updateDsByEnc(GenDatasourceConf genDatasourceConf);
//
// /**
// * 添加动态数据源
// * @param datasourceConf 数据源配置信息
// */
// void addDynamicDataSource(GenDatasourceConf datasourceConf);
//
// /**
// * 校验数据源配置是否有效
// * @param datasourceConf 数据源配置信息
// * @return true表示有效,false表示无效
// */
// Boolean checkDataSource(GenDatasourceConf datasourceConf);
//
// /**
// * 通过数据源ID删除数据源
// * @param dsIds 数据源ID数组
// * @return 删除是否成功
// */
// Boolean removeByDsId(Long[] dsIds);
//
//}
///*
// * Copyright (c) 2018-2025, lengleng All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions are met:
// *
// * Redistributions of source code must retain the above copyright notice,
// * this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// * notice, this list of conditions and the following disclaimer in the
// * documentation and/or other materials provided with the distribution.
// * Neither the name of the pig4cloud.com developer nor the names of its
// * contributors may be used to endorse or promote products derived from
// * this software without specific prior written permission.
// * Author: lengleng (wangiegie@gmail.com)
// */
//
//package com.ask.service;
//
//import com.ask.api.dto.TableDto;
//import com.ask.api.dto.TableParam;
//import com.ask.api.entity.GenTable;
//import com.baomidou.mybatisplus.core.metadata.IPage;
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.baomidou.mybatisplus.extension.service.IService;
//
//import java.util.List;
//
///**
// * 代码生成表服务接口
// *
// * @author lengleng
// * @date 2025/05/31
// */
//public interface GenTableService extends IService<GenTable> {
//
// /**
// * 查询对应数据源的表
// * @param page 分页信息
// * @param table 查询条件
// * @return 表
// */
// IPage<TableDto> queryTablePage(Page<TableDto> page, TableParam table);
//
//
// /**
// * 查询表ddl 语句
// * @param dsName 数据源名称
// * @param tableName 表名称
// * @return ddl 语句
// * @throws Exception
// */
// String queryTableDdl(String dsName, String tableName) throws Exception;
//
// /**
// * 查询数据源里面的全部表
// * @param dsName 数据源名称
// * @return table
// */
// List<String> queryTableList(String dsName);
//
// /**
// * 查询表的全部字段
// * @param dsName 数据源
// * @param tableName 表名称
// * @return column
// */
// List<String> queryTableColumn(String dsName, String tableName);
//
//}
......@@ -30,4 +30,13 @@ public interface KnowledgeDocumentService extends IService<KnowledgeDocument> {
*/
boolean saveSegmentResults(Long knowledgeBaseId, List<DocumentSegmentResult> segmentResults);
/**
* 修改文档启用状态
* @param documentId 文档ID
* @param isEnabled 启用状态(1:启用,0:禁用)
* @return 修改结果
*/
boolean updateDocumentStatus(Long documentId, Integer isEnabled);
}
\ No newline at end of file
///*
// * Copyright (c) 2018-2025, lengleng All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions are met:
// *
// * Redistributions of source code must retain the above copyright notice,
// * this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// * notice, this list of conditions and the following disclaimer in the
// * documentation and/or other materials provided with the distribution.
// * Neither the name of the pig4cloud.com developer nor the names of its
// * contributors may be used to endorse or promote products derived from
// * this software without specific prior written permission.
// * Author: lengleng (wangiegie@gmail.com)
// */
//package com.ask.service.impl;
//
//import com.ask.api.entity.GenDatasourceConf;
//import com.ask.mapper.GenDatasourceConfMapper;
//import com.ask.service.GenDatasourceConfService;
//import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
//import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
//import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//
//import javax.sql.DataSource;
//import java.sql.Connection;
//import java.sql.DriverManager;
//import java.sql.SQLException;
//
///**
// * 数据源配置服务实现类
// *
// * <p>
// * 提供数据源的增删改查及校验功能,支持数据源密码加密存储
// * </p>
// *
// * @author lengleng
// * @date 2025/05/31
// */
//@Slf4j
//@Service
//@RequiredArgsConstructor
//public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfMapper, GenDatasourceConf>
// implements GenDatasourceConfService {
//
// private final StringEncryptor stringEncryptor;
//
// private final DataSourceCreator hikariDataSourceCreator;
//
//
// /**
// * 保存数据源配置并进行加密处理
// * @param conf 数据源配置信息
// * @return 保存成功返回true,失败返回false
// */
// @Override
// public Boolean saveDsByEnc(GenDatasourceConf conf) {
// // 校验配置合法性
// if (!checkDataSource(conf)) {
// return Boolean.FALSE;
// }
//
// // 添加动态数据源
// addDynamicDataSource(conf);
//
// // 更新数据库配置
// conf.setPassword(stringEncryptor.encrypt(conf.getPassword()));
// this.baseMapper.insert(conf);
// return Boolean.TRUE;
// }
//
// /**
// * 更新加密数据源
// * @param conf 数据源配置信息
// * @return 更新成功返回true,失败返回false
// */
// @Override
// public Boolean updateDsByEnc(GenDatasourceConf conf) {
// if (!checkDataSource(conf)) {
// return Boolean.FALSE;
// }
// // 先移除
// DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
// dynamicRoutingDataSource.removeDataSource(baseMapper.selectById(conf.getId()).getName());
//
// // 再添加
// addDynamicDataSource(conf);
//
// // 更新数据库配置
// if (StrUtil.isNotBlank(conf.getPassword())) {
// conf.setPassword(stringEncryptor.encrypt(conf.getPassword()));
// }
// this.baseMapper.updateById(conf);
// return Boolean.TRUE;
// }
//
// /**
// * 通过数据源ID删除数据源
// * @param dsIds 数据源ID数组
// * @return 删除是否成功
// */
// @Override
// public Boolean removeByDsId(Long[] dsIds) {
// DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
// this.baseMapper.selectByIds(CollUtil.toList(dsIds))
// .forEach(ds -> dynamicRoutingDataSource.removeDataSource(ds.getName()));
// this.baseMapper.deleteByIds(CollUtil.toList(dsIds));
// return Boolean.TRUE;
// }
//
// /**
// * 添加动态数据源
// * @param conf 数据源配置信息
// */
// @Override
// public void addDynamicDataSource(GenDatasourceConf conf) {
// DataSourceProperty dataSourceProperty = new DataSourceProperty();
// dataSourceProperty.setPoolName(conf.getName());
// dataSourceProperty.setUrl(conf.getUrl());
// dataSourceProperty.setUsername(conf.getUsername());
// dataSourceProperty.setPassword(conf.getPassword());
// DataSource dataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);
//
// DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
// dynamicRoutingDataSource.addDataSource(dataSourceProperty.getPoolName(), dataSource);
// }
//
// /**
// * 校验数据源配置是否有效
// * @param conf 数据源配置信息
// * @return 数据源配置是否有效,true表示有效
// * @throws RuntimeException 数据库连接失败时抛出异常
// */
// @Override
// public Boolean checkDataSource(GenDatasourceConf conf) {
// String url;
// // JDBC 配置形式
// if (DsConfTypeEnum.JDBC.getType().equals(conf.getConfType())) {
// url = conf.getUrl();
// }
// else if (DsJdbcUrlEnum.MSSQL.getDbName().equals(conf.getDsType())) {
// // 主机形式 sql server 特殊处理
// DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(conf.getDsType());
// url = String.format(urlEnum.getUrl(), conf.getHost(), conf.getPort(), conf.getDsName());
// }
// else {
// DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(conf.getDsType());
// url = String.format(urlEnum.getUrl(), conf.getHost(), conf.getPort(), conf.getDsName());
// }
//
// conf.setUrl(url);
//
// try (Connection connection = DriverManager.getConnection(url, conf.getUsername(), conf.getPassword())) {
// }
// catch (SQLException e) {
// log.error("数据源配置 {} , 获取链接失败", conf.getName(), e);
// throw new RuntimeException("数据库配置错误,链接失败");
// }
// return Boolean.TRUE;
// }
//
//}
///*
// * Copyright (c) 2018-2025, lengleng All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions are met:
// *
// * Redistributions of source code must retain the above copyright notice,
// * this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// * notice, this list of conditions and the following disclaimer in the
// * documentation and/or other materials provided with the distribution.
// * Neither the name of the pig4cloud.com developer nor the names of its
// * contributors may be used to endorse or promote products derived from
// * this software without specific prior written permission.
// * Author: lengleng (wangiegie@gmail.com)
// */
//package com.ask.service.impl;
//
//import cn.hutool.core.util.EnumUtil;
//import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
//import com.baomidou.mybatisplus.core.metadata.IPage;
//import com.baomidou.mybatisplus.core.toolkit.StringUtils;
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.pig4cloud.pig.ask.api.dto.TableDto;
//import com.pig4cloud.pig.ask.api.dto.TableParam;
//import com.pig4cloud.pig.ask.api.entity.GenTable;
//import com.pig4cloud.pig.ask.api.entity.GenTableColumnEntity;
//import com.pig4cloud.pig.ask.api.enums.AutoFillEnum;
//import com.pig4cloud.pig.ask.api.enums.BoolFillEnum;
//import com.pig4cloud.pig.ask.api.enums.CommonColumnFiledEnum;
//import com.pig4cloud.pig.ask.mapper.GenTableMapper;
//import com.pig4cloud.pig.ask.service.GenTableService;
//import com.pig4cloud.pig.ask.utils.DataSourceQueryUtils;
//import com.pig4cloud.pig.common.datasource.enums.DsJdbcUrlEnum;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.anyline.metadata.Column;
//import org.anyline.metadata.Table;
//import org.anyline.proxy.CacheProxy;
//import org.anyline.proxy.ServiceProxy;
//import org.jetbrains.annotations.NotNull;
//import org.springframework.stereotype.Service;
//
//import java.util.*;
//
///**
// * 代码生成表服务实现类
// *
// * @author lengleng
// * @date 2025/05/31
// */
//@Slf4j
//@Service
//@RequiredArgsConstructor
//public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> implements GenTableService {
// private final DataSourceQueryUtils dataSourceQueryUtils;
//
// /**
// * 查询表ddl 语句
// *
// * @param dsName 数据源名称
// * @param tableName 表名称
// * @return ddl 语句
// * @throws Exception
// */
// @Override
// public String queryTableDdl(String dsName, String tableName) throws Exception {
// // 手动切换数据源
// DynamicDataSourceContextHolder.push(dsName);
// Table table = ServiceProxy.metadata().table(tableName); // 获取表结构
// table.execute(false);// 不执行SQL
// ServiceProxy.ddl().create(table);
// return table.getDdl();// 返回创建表的DDL
// }
//
// /**
// * 查询表的全部字段
// *
// * @param dsName 数据源
// * @param tableName 表名称
// * @return column
// */
// @Override
// public List<String> queryTableColumn(String dsName, String tableName) {
// // 手动切换数据源
// DynamicDataSourceContextHolder.push(dsName);
// CacheProxy.clear();
// return ServiceProxy.metadata().columns(tableName).values().stream().map(Column::getName).toList();
// }
//
// /**
// * 查询对应数据源的表
// *
// * @param page 分页信息
// * @param table 查询条件
// * @return 表
// */
// @Override
// public IPage<TableDto> queryTablePage(Page<TableDto> page, TableParam table) {
// String sql = null;
// Map<String, Object> params = new HashMap<>();
// if (DsJdbcUrlEnum.MYSQL.getDbName().equals(table.getDbType())) {
// sql = "SELECT table_name,table_comment,create_time FROM information_schema.tables WHERE table_schema = (SELECT database()) AND table_type = 'BASE TABLE' ORDER BY table_name;";
// params.put("table_name", table.getTableName());
//
// } else if (DsJdbcUrlEnum.PG.getDbName().equals(table.getDbType())) {
// sql = """
// SELECT
// t.table_name,
// obj_description((t.table_schema || '.' || t.table_name)::regclass, 'pg_class') as table_comment
// FROM
// information_schema.tables t
// WHERE
// t.table_schema = current_schema()
// AND t.table_type = 'BASE TABLE'
// AND (:tableName IS NULL OR t.table_name ILIKE :tableName)
// ORDER BY
// t.table_name
// """;
// params.put("tableName",
// StrUtil.isBlank(table.getTableName()) ? null : "%" + table.getTableName() + "%");
// }
// if (StringUtils.isBlank(sql)) {
// return new Page<>(page.getCurrent(), page.getSize());
// }
//
// return dataSourceQueryUtils.executePageQuery(page,table.getDsName(),sql,TableDto.class);
// }
//
//
// /**
// * 查询数据源里面的全部表
// *
// * @param dsName 数据源名称
// * @return table
// */
// @Override
// public List<String> queryTableList(String dsName) {
// // 手动切换数据源
// DynamicDataSourceContextHolder.push(dsName);
// CacheProxy.clear();
// return ServiceProxy.metadata().tables().values().stream().map(Table::getName).toList();
// }
//
//
// /**
// * 获取表字段信息
// *
// * @param dsName 数据源信息
// * @param tableName 表名称
// * @param tableMetadata 表的元数据
// * @return list
// */
// private static @NotNull List<GenTableColumnEntity> getGenTableColumnEntities(String dsName, String tableName,
// Table tableMetadata) {
// List<GenTableColumnEntity> tableFieldList = new ArrayList<>();
// LinkedHashMap<String, Column> columns = tableMetadata.getColumns();
// columns.forEach((columnName, column) -> {
// GenTableColumnEntity genTableColumnEntity = new GenTableColumnEntity();
// genTableColumnEntity.setTableName(tableName);
// genTableColumnEntity.setDsName(dsName);
// genTableColumnEntity.setFieldName(column.getName());
// genTableColumnEntity.setFieldComment(column.getComment());
// genTableColumnEntity.setFieldType(column.getTypeName());
// genTableColumnEntity.setPrimaryPk(
// column.isPrimaryKey() == 1 ? BoolFillEnum.TRUE.getValue() : BoolFillEnum.FALSE.getValue());
// genTableColumnEntity.setAutoFill(AutoFillEnum.DEFAULT.name());
// genTableColumnEntity.setFormItem(BoolFillEnum.TRUE.getValue());
// genTableColumnEntity.setGridItem(BoolFillEnum.TRUE.getValue());
//
// // 审计字段处理
// if (EnumUtil.contains(CommonColumnFiledEnum.class, column.getName())) {
// CommonColumnFiledEnum commonColumnFiledEnum = CommonColumnFiledEnum.valueOf(column.getName());
// genTableColumnEntity.setFormItem(commonColumnFiledEnum.getFormItem());
// genTableColumnEntity.setGridItem(commonColumnFiledEnum.getGridItem());
// genTableColumnEntity.setAutoFill(commonColumnFiledEnum.getAutoFill());
// genTableColumnEntity.setSort(commonColumnFiledEnum.getSort());
// }
// tableFieldList.add(genTableColumnEntity);
// });
// return tableFieldList;
// }
//
//}
......@@ -2,33 +2,31 @@ package com.ask.service.impl;
import com.ask.api.dto.DocumentSegmentRequest;
import com.ask.api.dto.DocumentSegmentResult;
import com.ask.api.entity.AskVectorStore;
import com.ask.api.entity.KnowledgeDocument;
import com.ask.api.entity.SysFile;
import com.ask.mapper.KnowledgeDocumentMapper;
import com.ask.service.AskVectorStoreService;
import com.ask.service.KnowledgeDocumentService;
import com.ask.service.SysFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.ParagraphPdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.LocalDateTime;
import java.util.*;
/**
* 知识库文档服务实现类
......@@ -42,9 +40,9 @@ import java.util.Map;
public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentMapper, KnowledgeDocument> implements KnowledgeDocumentService {
private final SysFileService sysFileService;
private final VectorStore vectorStore;
private final AskVectorStoreService askVectorStoreService;
private final ObjectMapper objectMapper;
/**
* 从PDF文档中读取带目录结构的文档分段
*
......@@ -145,7 +143,7 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
}
/**
* 按段落切片 - 每个段落一个Document
* 按段落切片 - 每个段落一个Document,超长段落进行token二次分片
*/
private List<Document> sliceByParagraph(InputStreamResource resource) {
// 先读取整个文档
......@@ -153,34 +151,179 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
PdfDocumentReaderConfig.builder()
.withPageTopMargin(0)
.withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
.withNumberOfTopTextLinesToDelete(0)
.withNumberOfTopTextLinesToDelete(1) // 去除页眉
.withNumberOfBottomTextLinesToDelete(1) // 去除页脚
.build())
.withPagesPerDocument(0)
.build());
List<Document> pageDocuments = pdfReader.read();
// List<Document> paragraphDocuments = new ArrayList<>();
//
// int paragraphIndex = 1;
// for (Document pageDoc : pageDocuments) {
// String content = pageDoc.getText();
// if (StringUtils.hasText(content)) {
// // 按段落分割(双换行符)
// String[] paragraphs = content.split("\\n\\s*\\n");
List<Document> paragraphDocuments = new ArrayList<>();
for (Document pageDoc : pageDocuments) {
String content = pageDoc.getText();
if (StringUtils.hasText(content)) {
// 整理和清理文本内容
String cleanedContent = cleanAndFormatText(content);
List<Document> subDocuments = splitLongParagraph(cleanedContent, pageDoc.getMetadata().get("title"), pageDoc.getMetadata().get("page_number"));
paragraphDocuments.addAll(subDocuments);
}
}
return paragraphDocuments;
}
/**
* 清理和格式化文本内容 - Spring AI文档内容整理的核心方法
*
* @param rawText 原始文本内容
* @return 清理后的文本内容
*/
private String cleanAndFormatText(String rawText) {
if (!StringUtils.hasText(rawText)) {
return "";
}
String cleanedText = rawText;
// 1. 去除PDF提取时常见的问题字符
cleanedText = cleanedText.replaceAll("[\u0000-\u001F\u007F]", ""); // 控制字符
cleanedText = cleanedText.replaceAll("[\uFEFF\uFFFE\uFFFF]", ""); // BOM和特殊字符
// 2. 规范化空白字符
cleanedText = cleanedText.replaceAll("[ \t]+", " "); // 多个空格/制表符合并为单个空格
cleanedText = cleanedText.replaceAll("(?m)^[ \t]+", ""); // 去除行首空白
cleanedText = cleanedText.replaceAll("(?m)[ \t]+$", ""); // 去除行尾空白
// // 3. 规范化换行符
// cleanedText = cleanedText.replaceAll("\r\n", "\n"); // Windows换行符统一
// cleanedText = cleanedText.replaceAll("\r", "\n"); // Mac换行符统一
// cleanedText = cleanedText.replaceAll("\n{3,}", "\n\n"); // 多个换行符最多保留两个
// 4. 清理常见的PDF提取问题
cleanedText = cleanedText.replaceAll("(?m)^[-=_]{3,}$", ""); // 去除分隔线
cleanedText = cleanedText.replaceAll("(?m)^[\\s\\*\\-]{0,3}第?\\s*\\d+\\s*[页頁].*$", ""); // 去除页码行
cleanedText = cleanedText.replaceAll("(?m)^\\s*\\d+\\s*$", ""); // 去除单独的数字行(可能是页码)
// // 5. 修复常见的字符编码问题
// cleanedText = cleanedText.replace("Â", ""); // 常见的UTF-8编码问题
// cleanedText = cleanedText.replace("’", "'"); // 单引号
// cleanedText = cleanedText.replace("“", "\""); // 左双引号
// cleanedText = cleanedText.replace("â€", "\""); // 右双引号
// 6. 处理中文标点符号
cleanedText = cleanedText.replace("(", "(");
cleanedText = cleanedText.replace(")", ")");
cleanedText = cleanedText.replace(",", ",");
cleanedText = cleanedText.replace("。", ".");
cleanedText = cleanedText.replace(":", ":");
cleanedText = cleanedText.replace(";", ";");
cleanedText = cleanedText.replace("?", "?");
cleanedText = cleanedText.replace("!", "!");
// // 7. 最终清理
// cleanedText = cleanedText.replaceAll("\n{3,}", "\n\n"); // 再次清理多余换行
cleanedText = cleanedText.trim(); // 去除首尾空白
//
// for (String paragraph : paragraphs) {
// if (StringUtils.hasText(paragraph.trim())) {
// Document paragraphDoc = new Document(paragraph.trim());
// paragraphDoc.getMetadata().put("paragraph_index", paragraphIndex++);
// paragraphDoc.getMetadata().put("slice_type", "paragraph");
// paragraphDoc.getMetadata().put("source_page", pageDoc.getMetadata().get("page_number"));
// paragraphDocuments.add(paragraphDoc);
// }
// }
// }
// // 8. 记录清理效果
// if (log.isDebugEnabled()) {
// int originalLength = rawText.length();
// int cleanedLength = cleanedText.length();
// log.debug("文本清理完成: 原长度={}, 清理后长度={}, 压缩率={:.2f}%",
// originalLength, cleanedLength,
// (1.0 - (double) cleanedLength / originalLength) * 100);
// }
return pageDocuments;
return cleanedText;
}
/**
* 智能段落分割 - 根据文档类型和内容特征进行分割
*
* @param text 清理后的文本内容
* @return 段落数组
*/
private String[] splitIntoParagraphs(String text) {
if (!StringUtils.hasText(text)) {
return new String[0];
}
// 首先尝试按双换行符分割
String[] paragraphs = text.split("\n\\s*\n");
// 如果分割结果太少,尝试其他分割策略
if (paragraphs.length < 3) {
// 策略2: 按句号+换行符分割
paragraphs = text.split("\\.[\\s]*\n");
}
// 过滤掉太短的段落(可能是噪音)
List<String> validParagraphs = new ArrayList<>();
for (String paragraph : paragraphs) {
String trimmed = paragraph.trim();
if (trimmed.length() >= 20) { // 至少20个字符
validParagraphs.add(trimmed);
} else if (trimmed.length() >= 5 && containsImportantContent(trimmed)) {
// 短段落但包含重要内容(如标题、编号等)
validParagraphs.add(trimmed);
}
}
return validParagraphs.toArray(new String[0]);
}
/**
* 判断短文本是否包含重要内容
*/
private boolean containsImportantContent(String text) {
// 包含数字编号
if (text.matches("^\\d+[.\u3001\\))].*")) return true;
// 包含中文编号
if (text.matches("^[一二三四五六七八九十][.\u3001].*")) return true;
// 包含章节标题关键词
if (text.matches(".*[章节条款项第].*")) return true;
// 包含重要标点
if (text.contains(":") || text.contains(":") || text.contains("、")) return true;
return false;
}
/**
* 分割超长段落 - 对超过1024 token的段落进行token-based二次分片
*
* @param longParagraph 超长段落内容
* @param sourcePage 来源页码
* @return 分割后的Document列表
*/
private List<Document> splitLongParagraph(String longParagraph, Object title, Object sourcePage) {
// 使用TokenTextSplitter进行token-based分割
TokenTextSplitter textSplitter = new TokenTextSplitter(
4096, // 分片大小
50, // 最小分片字符数
50, // 设置最小需要嵌入的长度
1000, // 最大片段大小
true // 保持分隔符
);
if (Objects.nonNull(title)) {
longParagraph = longParagraph.replace(String.valueOf(title), "");
}
Document longDoc = new Document(longParagraph);
List<Document> subDocuments = textSplitter.apply(List.of(longDoc));
// 为每个子片段设置元数据
List<Document> result = new ArrayList<>();
for (int i = 0; i < subDocuments.size(); i++) {
Document subDoc = subDocuments.get(i);
subDoc.getMetadata().put("size", Objects.requireNonNull(subDoc.getText()).length());
subDoc.getMetadata().put("title", title);
result.add(subDoc);
}
log.info("超长段落分片完成,原段落token数: {}, 分片数: {}",
estimateTokenCount(longParagraph), subDocuments.size());
return result;
}
/**
......@@ -192,7 +335,8 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
PdfDocumentReaderConfig.builder()
.withPageTopMargin(0)
.withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
.withNumberOfTopTextLinesToDelete(0)
.withNumberOfTopTextLinesToDelete(1) // 去除页眉
.withNumberOfBottomTextLinesToDelete(1) // 去除页脚
.build())
.build());
......@@ -249,7 +393,7 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
List<Document> segments = slicePdfDocument(
sysFileService.getFileStream(file.getBucketName(), file.getFileName()),
SliceStrategy.PARAGRAPH, // 可以改为 PARAGRAPH 或 CUSTOM
500 // 仅在CUSTOM策略时生效
1024 // 仅在CUSTOM策略时生效
);
if (segments.isEmpty()) {
log.warn("文档解析失败或内容为空: {}", file.getOriginal());
......@@ -260,6 +404,7 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
result.setFileName(file.getOriginal());
result.setFilePath(file.getUrl());
result.setTotalSegments(segments.size());
result.setFileSize(file.getFileSize());
List<DocumentSegmentResult.DocumentSegment> segmentList = new ArrayList<>();
for (int i = 0; i < segments.size(); i++) {
......@@ -267,9 +412,9 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
DocumentSegmentResult.DocumentSegment segmentDto = new DocumentSegmentResult.DocumentSegment();
segmentDto.setIndex(i + 1);
segmentDto.setContent(segment.getText());
segmentDto.setCharCount(segment.getText().length());
segmentDto.setCharCount((Integer) segment.getMetadata().get("size"));
// 简单估算token数(大约1个中文字符=1.5token,英文单词=1token)
segmentDto.setTokenCount(estimateTokenCount(segment.getText()));
segmentDto.setTitle(segment.getMetadata().get("title").toString());
segmentList.add(segmentDto);
}
result.setSegments(segmentList);
......@@ -294,25 +439,34 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
document.setKnowledgeBaseId(knowledgeBaseId);
document.setName(result.getFileName());
document.setFileName(result.getFileName());
document.setStatus(0); // 默认待处理状态
document.setStatus(0); // 设置为待处理状态
document.setSegmentCount(result.getTotalSegments());
document.setTokenCount(result.getSegments().stream()
.mapToInt(DocumentSegmentResult.DocumentSegment::getTokenCount)
.sum());
document.setFilePath(result.getFilePath());
document.setIsEnabled(1);
document.setFileType("pdf");
document.setFileSize(result.getFileSize());
this.save(document);
List<Document> list = new ArrayList<>();
List<AskVectorStore> askVectorStores = new ArrayList<>();
result.getSegments().forEach(vo -> {
Map<String, Object> map = new HashMap<>();
map.put("documentId", document.getId());
map.put("knowledgeBaseId", knowledgeBaseId);
map.put("fileName", document.getFileName());
map.put("filePath", document.getFilePath());
list.add(new Document(vo.getContent(), map));
AskVectorStore askVectorStore = new AskVectorStore();
// 构建metadata
Map<String, Object> metadata = new HashMap<>();
metadata.put("knowledgeBaseId", document.getKnowledgeBaseId());
metadata.put("documentId", document.getId());
metadata.put("fileName", document.getFileName());
metadata.put("filePath", document.getFilePath());
metadata.put("vectorized", 0);
metadata.put("isEnabled", 1); //启用
metadata.put("createTime", LocalDateTime.now().toString());
askVectorStore.setContent(vo.getContent());
try {
askVectorStore.setMetadata(objectMapper.writeValueAsString(metadata));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
vectorStore.add(list);
document.setStatus(2);
this.updateById(document);
askVectorStoreService.saveBatch(askVectorStores);
}
return true;
}
......@@ -346,4 +500,50 @@ public class KnowledgeDocumentServiceImpl extends ServiceImpl<KnowledgeDocumentM
return Math.round(chineseCharCount * 1.5f + englishWordCount);
}
@Transactional
@Override
public boolean updateDocumentStatus(Long documentId, Integer isEnabled) {
// 参数验证
if (documentId == null) {
log.error("文档ID不能为空");
return false;
}
if (isEnabled == null || (isEnabled != 0 && isEnabled != 1)) {
log.error("启用状态参数无效,只能为0(禁用)或1(启用),当前值: {}", isEnabled);
return false;
}
try {
// 检查文档是否存在
KnowledgeDocument document = this.getById(documentId);
if (document == null) {
log.error("文档不存在,文档ID: {}", documentId);
return false;
}
// 更新文档状态
KnowledgeDocument updateDocument = new KnowledgeDocument();
updateDocument.setId(documentId);
updateDocument.setIsEnabled(isEnabled);
boolean result = this.updateById(updateDocument);
if (result) {
log.info("文档状态修改成功,文档ID: {}, 文档名称: {}, 状态: {}",
documentId, document.getName(), isEnabled == 1 ? "启用" : "禁用");
} else {
log.error("文档状态修改失败,文档ID: {}", documentId);
}
return result;
} catch (Exception e) {
log.error("修改文档状态异常,文档ID: {}, 错误信息: {}", documentId, e.getMessage(), e);
return false;
}
}
}
\ No newline at end of file
......@@ -2,12 +2,14 @@ package com.ask;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 启动类
*
* @author YangKai
*/
@EnableAsync
@SpringBootApplication
public class AskDataAiApplication {
......
......@@ -39,10 +39,10 @@ spring:
options:
model: qwen-plus
embedding:
base-url: http://localhost:11434/api/embeddings
base-url: https://dashscope.aliyuncs.com/compatible-mode
api-key: sk-ae96ff281ff644c992843c64a711a950
options:
model: nomic-embed-text:latest
model: text-embedding-v4
mybatis-plus:
mapper-locations: classpath*:/mapper/*Mapper.xml # mapper文件位置
......@@ -110,4 +110,4 @@ logging:
file:
local:
enable: true
base-path: D:/app/upFiles
\ No newline at end of file
base-path: /app/upFiles
\ No newline at end of file
......@@ -39,10 +39,10 @@ spring:
options:
model: qwen-plus
embedding:
base-url: http://localhost:11434/api/embeddings
base-url: https://dashscope.aliyuncs.com/compatible-mode
api-key: sk-ae96ff281ff644c992843c64a711a950
options:
model: nomic-embed-text:latest
model: text-embedding-v4
mybatis-plus:
mapper-locations: classpath*:/mapper/*Mapper.xml # mapper文件位置
......@@ -110,4 +110,4 @@ logging:
file:
local:
enable: true
base-path: D:/app/upFiles
\ No newline at end of file
base-path: /app/upFiles
\ No newline at end of file
......@@ -31,6 +31,9 @@ public class R<T> implements Serializable {
public static <T> R<T> ok(T data) {
return new R<>(0, "success", data);
}
public static <T> R<T> ok(T data,String msg) {
return new R<>(0, msg, data);
}
public static <T> R<T> failed(String msg) {
return new R<>(1, msg, null);
......
......@@ -28,11 +28,13 @@ public class MybatisMetaObjectHandler implements MetaObjectHandler {
this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
// 设置更新人(新增时也设置更新人)
this.strictInsertFill(metaObject, "updateBy", () -> "admin", String.class);
this.strictInsertFill(metaObject, "del_flag", () -> "0", String.class);
}
@Override
public void updateFill(MetaObject metaObject) {
log.debug("自动填充更新字段");
// 设置更新时间
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment