作者 lixiang

模型参数修改

... ... @@ -312,7 +312,7 @@ public class PgVectorMapper {
// 自动生成嵌入向量的方法(需根据您的嵌入模型实现)
private float[] generateEmbedding(String text) {
// 改为生成 768 维向量
float[] embedding = new float[768]; // OpenAI 标准维度是 1536,这里改为 768
float[] embedding = new float[1024]; // OpenAI 标准维度是 1536,这里改为 768
// 实际项目中应调用嵌入模型 API
// 例如:return embeddingClient.generate(text, 768);
... ...
... ... @@ -17,6 +17,7 @@ import org.jeecg.modules.airag.app.entity.QuestionEmbedding;
import org.jeecg.modules.airag.app.utils.AiModelUtils;
import org.postgresql.util.PGobject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.sql.*;
... ... @@ -30,6 +31,8 @@ public class QuestionEmbeddingMapper {
@Autowired
private AiModelUtils aiModelUtils;
@Value("${jeecg.ai-chat.embedId}")
private String embedId;
// PostgreSQL连接参数(应与项目配置一致)
private static final String URL = "jdbc:postgresql://192.168.100.104:5432/postgres";
private static final String USER = "postgres";
... ... @@ -185,7 +188,7 @@ public class QuestionEmbeddingMapper {
jsonObject.setType("json");
jsonObject.setValue(record.getMetadata());
stmt.setObject(5, jsonObject);
Response<Embedding> embedding = aiModelUtils.getEmbedding("1925730210204721154", record.getQuestion());
Response<Embedding> embedding = aiModelUtils.getEmbedding(embedId, record.getQuestion());
stmt.setObject(6, embedding.content().vector());
return stmt.executeUpdate();
} catch (SQLException e) {
... ... @@ -214,7 +217,7 @@ public class QuestionEmbeddingMapper {
jsonObject.setValue(mataData.toJSONString());*/
stmt.setObject(4, record.getMetadata());
Response<Embedding> embedding = aiModelUtils.getEmbedding("1925730210204721154", record.getQuestion());
Response<Embedding> embedding = aiModelUtils.getEmbedding(embedId, record.getQuestion());
stmt.setObject(5, embedding.content().vector());
stmt.setString(6, record.getId());
... ... @@ -274,7 +277,7 @@ public class QuestionEmbeddingMapper {
}
// 2. 获取问题的嵌入向量
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding("1925730210204721154", question);
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding(embedId, question);
float[] queryVector = embeddingResponse.content().vector();
// 3. 计算最大允许距离(1 - 相似度阈值)
... ...
... ... @@ -13,10 +13,7 @@ import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.output.Response;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.*;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.airag.app.entity.QuestionEmbedding;
import org.jeecg.modules.airag.app.mapper.QuestionEmbeddingMapper;
... ... @@ -67,12 +64,14 @@ public class QuestionEmbeddingServiceImpl implements IQuestionEmbeddingService {
@Value("${jeecg.upload.path}")
private String uploadPath;
@Value("${jeecg.ai-chat.embedId}")
private String embedId;
private static final Set<String> ALLOWED_EXTENSIONS = Set.of("txt", "doc", "docx");
private static final Pattern SPECIAL_CHARS_PATTERN = Pattern.compile("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s]");
private static final Pattern UUID_PATTERN = Pattern.compile("_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
// 新增:数据库连接配置
// 数据库连接配置
private static final String DB_URL = "jdbc:postgresql://192.168.100.104:5432/postgres";
private static final String DB_USER = "postgres";
private static final String DB_PASSWORD = "postgres";
... ... @@ -188,42 +187,43 @@ public class QuestionEmbeddingServiceImpl implements IQuestionEmbeddingService {
saveSegmentsToDatabase(segments, originalFileName, storedFileName, knowledgeId);
// 新增逻辑:同时保存到embeddings表
saveToEmbeddingsTable(segments, originalFileName, knowledgeId);
}
saveToEmbeddingsTable(segments, originalFileName, storedFileName, knowledgeId);
// 新增方法:将内容保存到embeddings表
private void saveToEmbeddingsTable(List<String> segments, String originalFileName, String knowledgeId) {
if (segments.isEmpty()) {
return;
}
private void saveToEmbeddingsTable(List<String> segments, String originalFileName, String storedFileName, String knowledgeId) {
if (segments.isEmpty()) return;
// 获取无UUID和扩展名的文件名用于显示
String displayFileName = removeUuidSuffix(originalFileName);
displayFileName = FilenameUtils.removeExtension(displayFileName);
// 为整个文档生成一个唯一的docId
String docId = UUID.randomUUID().toString();
try (Connection conn = getConnection()) {
for (String segment : segments) {
if (segment.trim().isEmpty()) continue;
// 合并所有段落作为完整内容
String fullContent = String.join("\n\n", segments);
// 回答内容是整个段落
String[] parts = segment.split("\\r?\\n", 2);
if (parts.length < 2) continue;
try (Connection conn = getConnection()) {
// 准备元数据
String titlePath = parts[0].trim();
String answer = segment.trim(); // 整个回答段(含标题 + 内容)
// 获取 embedding
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding(embedId, answer);
float[] embeddingVector = embeddingResponse.content().vector();
// 准备 metadata
Map<String, Object> metadata = new HashMap<>();
metadata.put("docId", docId);
metadata.put("docName", originalFileName);
metadata.put("storedFileName", storedFileName);
metadata.put("knowledgeId", knowledgeId);
metadata.put("title", displayFileName + ": " + titlePath);
// 获取文本的向量表示
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding("1925730210204721154", displayFileName + ": " + fullContent);
float[] embeddingVector = embeddingResponse.content().vector();
// 插入到embeddings表
// 插入
String sql = "INSERT INTO embeddings (embedding_id, embedding, text, metadata) VALUES (?, ?, ?, ?::jsonb)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, UUID.randomUUID().toString());
stmt.setObject(2, new PGvector(embeddingVector));
stmt.setString(3, fullContent);
stmt.setString(3, answer);
PGobject jsonObject = new PGobject();
jsonObject.setType("json");
... ... @@ -232,12 +232,14 @@ public class QuestionEmbeddingServiceImpl implements IQuestionEmbeddingService {
stmt.executeUpdate();
}
}
} catch (Exception e) {
log.error("保存到embeddings表失败", e);
log.error("保存分段到embeddings表失败", e);
}
}
// 新增方法:获取数据库连接
// 获取数据库连接
private Connection getConnection() throws SQLException {
return DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
}
... ... @@ -253,8 +255,8 @@ public class QuestionEmbeddingServiceImpl implements IQuestionEmbeddingService {
}
private String cleanText(String text) {
// 保留基本的标点符号,包括 . : - 等
Pattern preservedCharsPattern = Pattern.compile("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s.,:、,:;。;-]");
// 保留基本的标点符号
Pattern preservedCharsPattern = Pattern.compile("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s.,:、,:;。;#;-]");
text = preservedCharsPattern.matcher(text).replaceAll("");
// 将多个换行符缩减为一个换行符
... ... @@ -299,182 +301,183 @@ public class QuestionEmbeddingServiceImpl implements IQuestionEmbeddingService {
.collect(Collectors.toList());
}
public List<String> splitWordDocument(String filePath) throws Exception {
List<String> result = new ArrayList<>();
String ext = FilenameUtils.getExtension(filePath).toLowerCase();
StringBuilder fullContent = new StringBuilder();
// 获取无UUID的文件名用于显示
String displayFileName = removeUuidSuffix(new File(filePath).getName());
displayFileName = FilenameUtils.removeExtension(displayFileName);
if (ext.equals("docx")) {
try (XWPFDocument doc = new XWPFDocument(new FileInputStream(filePath))) {
StringBuilder currentSection = new StringBuilder();
boolean isTableSection = false;
// 后备分割方案:按段落结构分割
private List<String> splitByContentStructure(XWPFDocument doc) {
List<String> segments = new ArrayList<>();
StringBuilder currentSegment = new StringBuilder();
final int MAX_SEGMENT_LENGTH = 1000; // 最大分段长度
for (IBodyElement element : doc.getBodyElements()) {
String text = "";
if (element instanceof XWPFParagraph) {
XWPFParagraph para = (XWPFParagraph) element;
String text = cleanText(para.getText());
fullContent.append(text).append("\n");
text = ((XWPFParagraph) element).getText().trim();
} else if (element instanceof XWPFTable) {
text = extractTableContent((XWPFTable) element);
}
if (text.isEmpty()) continue;
if (isTableSection) {
result.add(currentSection.toString().trim());
currentSection = new StringBuilder();
isTableSection = false;
// 当遇到空行或达到最大长度时分段
if (currentSegment.length() + text.length() > MAX_SEGMENT_LENGTH
&& currentSegment.length() > 0) {
segments.add(currentSegment.toString().trim());
currentSegment = new StringBuilder();
}
String style = para.getStyle();
if (style != null && style.matches("Heading\\d")) {
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
currentSegment.append(text).append("\n\n");
}
currentSection = new StringBuilder(text).append("\n");
} else {
currentSection.append(text).append("\n");
if (currentSegment.length() > 0) {
segments.add(currentSegment.toString().trim());
}
return segments;
}
} else if (element instanceof XWPFTable) {
String tableContent = extractTableContent((XWPFTable) element);
fullContent.append(tableContent).append("\n");
if (!isTableSection) {
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
// 按标题分割文本
private List<String> splitByHeadings(String content) {
List<String> segments = new ArrayList<>();
StringBuilder currentSegment = new StringBuilder();
String[] lines = content.split("\\r?\\n");
for (String line : lines) {
// 检测标题行(以1-6个#开头,后面跟着空格)
if (line.trim().matches("^#{1,6}\\s+.*")) {
// 保存当前分段
if (!currentSegment.isEmpty()) {
segments.add(currentSegment.toString().trim());
currentSegment = new StringBuilder();
}
currentSection = new StringBuilder();
isTableSection = true;
}
currentSection.append(tableContent).append("\n");
currentSegment.append(line).append("\n");
}
// 添加最后一个分段
if (!currentSegment.isEmpty()) {
segments.add(currentSegment.toString().trim());
}
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
return segments;
}
private String extractTableContent(XWPFTable table) {
StringBuilder tableContent = new StringBuilder();
table.getRows().forEach(row -> {
StringBuilder rowContent = new StringBuilder("| ");
row.getTableCells().forEach(cell -> {
String cellText = cell.getText().replaceAll("(\r?\n){2,}", " ");
rowContent.append(cellText).append(" | ");
});
tableContent.append(rowContent.toString().trim()).append("\n");
});
return tableContent.toString();
}
} else if (ext.equals("doc")) {
try (HWPFDocument doc = new HWPFDocument(new FileInputStream(filePath))) {
Range range = doc.getRange();
StringBuilder currentSection = new StringBuilder();
boolean isTableSection = false;
public List<String> splitWordDocument(String filePath) throws Exception {
List<String> result = new ArrayList<>();
String ext = FilenameUtils.getExtension(filePath).toLowerCase();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph para = range.getParagraph(i);
String text = cleanText(para.text());
fullContent.append(text).append("\n");
if (!ext.equals("docx")) return result;
if (para.isInTable()) {
if (!isTableSection) {
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
}
currentSection = new StringBuilder();
isTableSection = true;
}
currentSection.append(text).append("\n");
} else {
if (isTableSection) {
result.add(currentSection.toString().trim());
currentSection = new StringBuilder();
isTableSection = false;
try (XWPFDocument doc = new XWPFDocument(new FileInputStream(filePath))) {
StringBuilder currentContent = new StringBuilder();
List<String> titlePath = new ArrayList<>();
String lastOutput = null;
for (IBodyElement element : doc.getBodyElements()) {
if (element instanceof XWPFParagraph) {
XWPFParagraph para = (XWPFParagraph) element;
String text = para.getText().trim();
if (text.isEmpty()) continue;
int headingLevel = getHeadingLevel(para);
if (headingLevel > 0) {
// 存在之前内容,保存上一个段
if (currentContent.length() > 0 && !titlePath.isEmpty()) {
String fullBlock = String.join("", titlePath) + "\n" + currentContent.toString().trim();
result.add(fullBlock);
currentContent.setLength(0);
}
if (isHeading(para, range)) {
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
// 更新标题路径
while (titlePath.size() >= headingLevel) {
titlePath.remove(titlePath.size() - 1);
}
currentSection = new StringBuilder(text).append("\n");
titlePath.add(text);
} else {
currentSection.append(text).append("\n");
currentContent.append(text).append("\n");
}
} else if (element instanceof XWPFTable) {
String tableText = extractTableContent((XWPFTable) element);
currentContent.append(tableText).append("\n");
}
}
if (!currentSection.isEmpty()) {
result.add(currentSection.toString().trim());
}
// 最后一段
if (currentContent.length() > 0 && !titlePath.isEmpty()) {
String fullBlock = String.join("", titlePath) + "\n" + currentContent.toString().trim();
result.add(fullBlock);
}
}
if (fullContent.length() < 1000) {
return Collections.singletonList(displayFileName + "\n" + fullContent.toString().trim());
}
return result;
}
private String extractTableContent(XWPFTable table) {
StringBuilder tableContent = new StringBuilder("\n"); // 表格前加换行
table.getRows().forEach(row -> {
row.getTableCells().forEach(cell -> {
// 处理单元格内容中的多个换行
String cellText = cleanText(cell.getText()).replaceAll("(\r?\n){2,}", "\n");
tableContent.append("| ").append(cellText).append(" ");
});
tableContent.append("|\n");
});
return tableContent.toString();
// 获取标题等级
private int getHeadingLevel(XWPFParagraph para) {
String style = para.getStyle();
if (style != null && style.matches("Heading\\d|标题\\d|\\d")) {
return Integer.parseInt(style.replaceAll("[^\\d]", ""));
}
private void saveSegmentsToDatabase(List<String> segments, String originalFileName, String storedFileName, String knowledgeId) {
if (segments.isEmpty()) {
return;
if (para.getRuns().size() > 0) {
XWPFRun run = para.getRuns().get(0);
if (run.isBold() || (run.getFontSize() > 12 && run.getFontSize() != -1)) {
return 2; // 可能是二级标题
}
}
// 从存储文件名中提取UUID部分作为docId
String docId = storedFileName.substring(
storedFileName.lastIndexOf('_') + 1,
storedFileName.lastIndexOf('.')
);
return 0;
}
private void saveSegmentsToDatabase(List<String> segments, String originalFileName, String storedFileName, String knowledgeId) {
if (segments.isEmpty()) return;
// 获取无UUID和扩展名的文件名用于显示
String docId = storedFileName.substring(storedFileName.lastIndexOf('_') + 1, storedFileName.lastIndexOf('.'));
String displayFileName = removeUuidSuffix(originalFileName);
displayFileName = FilenameUtils.removeExtension(displayFileName);
// 判断是否是单一段落
boolean isSingleSegment = segments.size() == 1;
for (String segment : segments) {
if (segment.trim().isEmpty()) {
continue;
}
if (segment.trim().isEmpty()) continue;
QuestionEmbedding record = new QuestionEmbedding();
record.setId(UUID.randomUUID().toString());
String[] parts = segment.split("\\r?\\n", 2);
if (parts.length < 2) continue;
if (isSingleSegment) {
record.setQuestion(displayFileName);
record.setAnswer(segment.trim());
} else {
String firstLine = segment.lines().findFirst().orElse("");
record.setQuestion(displayFileName + ": " + cleanText(firstLine));
record.setAnswer(segment.trim());
}
String titleLine = parts[0].trim(); // 如 掌静脉设备: 产品特点
String content = parts[1].trim();
// 构造问题:文件名: 标题层级路径
String question = displayFileName + titleLine;
QuestionEmbedding record = new QuestionEmbedding();
record.setId(UUID.randomUUID().toString());
record.setQuestion(question);
record.setAnswer(titleLine + "\n" + content);
record.setText("");
// 构建metadata JSON对象
Map<String, String> metadata = new LinkedHashMap<>(); // 使用LinkedHashMap保持字段顺序
Map<String, String> metadata = new LinkedHashMap<>();
metadata.put("docId", docId);
metadata.put("docName", originalFileName); // 上传前的原始文件名
metadata.put("storedFileName", storedFileName); // 上传后的带UUID的文件名
metadata.put("docName", originalFileName);
metadata.put("storedFileName", storedFileName);
metadata.put("knowledgeId", knowledgeId);
// 使用ObjectMapper转换为JSON字符串
try {
record.setMetadata(new ObjectMapper().writeValueAsString(metadata));
} catch (JsonProcessingException e) {
log.error("生成metadata JSON失败", e);
// 使用默认值
record.setMetadata(String.format(
"{\"docId\":\"%s\",\"docName\":\"%s\",\"storedFileName\":\"%s\",\"knowledgeId\":\"%s\"}",
docId, originalFileName, storedFileName, knowledgeId
));
}
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding("1925730210204721154", record.getQuestion());
log.info("保存分段: title={}, content_length={}", question, segment.length());
Response<Embedding> embeddingResponse = aiModelUtils.getEmbedding(embedId, record.getQuestion());
record.setEmbedding(embeddingResponse.content().vector());
record.setKnowledgeId(knowledgeId);
questionEmbeddingMapper.insert(record);
... ...
... ... @@ -258,6 +258,7 @@ public class EmbeddingHandler implements IEmbeddingHandler {
Map<String, Object> metadataMap = new HashMap<>();
metadataMap.put("docId", metadata.getString("docId")); // 假设metadata中有docId字段
metadataMap.put("storedFileName", metadata.getString("storedFileName"));
metadataMap.put("docName", metadata.getString(EMBED_STORE_METADATA_DOCNAME));
metadataMap.put("index", metadata.getInteger("index"));
ObjectMapper objectMapper = new ObjectMapper();
... ...
... ... @@ -61,39 +61,39 @@ public class ZdyRagController {
HashMap<String, Object> resMap = new HashMap<>();
//根据问题相似度进行查询
List<QuestionEmbedding> questionEmbeddings = questionEmbeddingService.similaritySearchByQuestion(questionText, 1,0.8);
for (QuestionEmbedding questionEmbedding : questionEmbeddings) {
resMap.put("question", questionText);
resMap.put("answer", questionEmbedding.getAnswer());
resMap.put("similarity", questionEmbedding.getSimilarity());
ObjectMapper objectMapper = new ObjectMapper();
Map<String, String> metadata = objectMapper.readValue(questionEmbedding.getMetadata(), Map.class);
// 获取docName和docId
if (metadata != null) {
String docName = metadata.get("docName");
resMap.put("fileName", docName);
String fileName = generateFilePath(questionEmbedding.getMetadata());
if (StringUtils.isNotBlank(fileName)) {
resMap.put("fileBase64", FileToBase64Util.fileToBase64(uploadPath + fileName));
}
}
// 记录日志 - 从问题库匹配
logRecord.setAnswer(questionEmbedding.getAnswer());
logRecord.setAnswerType(1);
airagLogService.save(logRecord);
log.info("questionEmbedding.getMetadata() = " + questionEmbedding.getMetadata());
log.info("questionEmbedding.getQuestion() = " + questionEmbedding.getQuestion());
log.info("questionEmbedding.getAnswer() = " + questionEmbedding.getAnswer());
log.info("questionEmbedding.getSimilarity() = " + questionEmbedding.getSimilarity());
log.info("-------------------------------------------------------------");
}
//返回问题库命中的问题
if (!questionEmbeddings.isEmpty()) {
return Result.OK(resMap);
}
// List<QuestionEmbedding> questionEmbeddings = questionEmbeddingService.similaritySearchByQuestion(questionText, 1,0.8);
// for (QuestionEmbedding questionEmbedding : questionEmbeddings) {
// resMap.put("question", questionText);
// resMap.put("answer", questionEmbedding.getAnswer());
// resMap.put("similarity", questionEmbedding.getSimilarity());
//
// ObjectMapper objectMapper = new ObjectMapper();
// Map<String, String> metadata = objectMapper.readValue(questionEmbedding.getMetadata(), Map.class);
// // 获取docName和docId
// if (metadata != null) {
// String docName = metadata.get("docName");
// resMap.put("fileName", docName);
// String fileName = generateFilePath(questionEmbedding.getMetadata());
//
// if (StringUtils.isNotBlank(fileName)) {
// resMap.put("fileBase64", FileToBase64Util.fileToBase64(uploadPath + fileName));
// }
// }
// // 记录日志 - 从问题库匹配
// logRecord.setAnswer(questionEmbedding.getAnswer());
// logRecord.setAnswerType(1);
// airagLogService.save(logRecord);
//
// log.info("questionEmbedding.getMetadata() = " + questionEmbedding.getMetadata());
// log.info("questionEmbedding.getQuestion() = " + questionEmbedding.getQuestion());
// log.info("questionEmbedding.getAnswer() = " + questionEmbedding.getAnswer());
// log.info("questionEmbedding.getSimilarity() = " + questionEmbedding.getSimilarity());
// log.info("-------------------------------------------------------------");
// }
// //返回问题库命中的问题
// if (!questionEmbeddings.isEmpty()) {
// return Result.OK(resMap);
// }
List<Map<String, Object>> maps = embeddingHandler.searchEmbedding(knowId, questionText, topNumber, similarity);
if (CollectionUtil.isEmpty(maps)) {
... ... @@ -129,9 +129,10 @@ public class ZdyRagController {
resMap.put("question", questionText);
resMap.put("answer", chat);
resMap.put("similarity", maps.get(0).get("score").toString());
String fileName = generateFilePath(maps.get(0).get("metadata").toString());
String fileName = generateFileDocName(maps.get(0).get("metadata").toString());
String storedFileName = generateFilePath(maps.get(0).get("metadata").toString());
resMap.put("fileName", fileName);
resMap.put("fileBase64",FileToBase64Util.fileToBase64(uploadPath + fileName));
resMap.put("fileBase64",FileToBase64Util.fileToBase64(uploadPath + storedFileName));
// 记录日志 - 从知识库生成回答
... ... @@ -153,19 +154,19 @@ public class ZdyRagController {
Map<String, String> metadata = objectMapper.readValue(metadataJson, Map.class);
// 获取docName和docId
String docName = metadata.get("docName");
String docId = metadata.get("docId");
return metadata.get("storedFileName");
// 分离文件名和扩展名
if(StringUtils.isEmpty(docName)){
return null;
}
int dotIndex = docName.lastIndexOf('.');
String baseName = (dotIndex > 0) ? docName.substring(0, dotIndex) : docName;
String extension = (dotIndex > 0) ? docName.substring(dotIndex) : "";
private String generateFileDocName(String metadataJson) throws Exception {
if (StringUtils.isEmpty(metadataJson)) {
return "";
}
ObjectMapper objectMapper = new ObjectMapper();
// 解析JSON字符串
Map<String, String> metadata = objectMapper.readValue(metadataJson, Map.class);
return metadata.get("docName");
// 组合成新文件名
return baseName + "_" + docId + extension;
}
public static void main(String[] args) {
... ...
server:
port: 8080
undertow:
max-http-post-size: 100MB
max-headers: 20000
max-parameters: 20000
max-buffered-request-size: 1MB
# max-http-post-size: 10MB # 平替 tomcat server.tomcat.max-swallow-siz, undertow该值默认为-1
worker-threads: 16 # 4核CPU标准配置
buffers:
... ... @@ -33,6 +37,7 @@ spring:
multipart:
max-file-size: 10MB
max-request-size: 10MB
enabled: true
mail:
# 定时任务发送邮件
timeJobSend: false
... ... @@ -152,7 +157,7 @@ spring:
slow-sql-millis: 5000
datasource:
master:
url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
url: jdbc:mysql://localhost:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
... ... @@ -181,7 +186,7 @@ mybatis-plus:
table-underline: true
configuration:
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 返回类型为Map,显示null对应的字段
call-setters-on-nulls: true
#jeecg专用配置
... ... @@ -189,9 +194,10 @@ minidao:
base-package: org.jeecg.modules.jmreport.*,org.jeecg.modules.drag.*
jeecg:
upload:
path: D:\\upload\\
path: D:\upload\
# AI集成
ai-chat:
embedId: 1937039670944731137
enabled: true
model: deepseek-chat
apiKey: ??
... ... @@ -200,7 +206,7 @@ jeecg:
# AIRag向量库
ai-rag:
embed-store:
host: 192.168.100.103
host: 192.168.100.104
port: 5432
database: postgres
user: postgres
... ...