markdown渲染服务的完成
This commit is contained in:
parent
590d0076bd
commit
36c070df1d
|
@ -19,12 +19,12 @@
|
|||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="briChat" options="-parameters" />
|
||||
<module name="briChat" options="-parameters -Xlint:unchecked" />
|
||||
<module name="common" options="-parameters" />
|
||||
<module name="eureka-server" options="-parameters" />
|
||||
<module name="eureka-server" options="-parameters -Xlint:unchecked" />
|
||||
<module name="face-proc" options="-parameters" />
|
||||
<module name="infrastructure" options="-parameters" />
|
||||
<module name="zuul-server" options="-parameters" />
|
||||
<module name="infrastructure" options="-parameters -Xlint:unchecked" />
|
||||
<module name="zuul-server" options="-parameters -Xlint:unchecked" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,34 @@
|
|||
package com.bjtds.brichat.controller;
|
||||
|
||||
import com.bjtds.brichat.service.MarkdownService;
|
||||
import com.bjtds.brichat.util.ResultUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Api(tags="Markdown标记")
|
||||
@RestController
|
||||
@Slf4j
|
||||
@CrossOrigin(value ="*",maxAge = 3600)
|
||||
@RequestMapping("/markdown")
|
||||
public class MarkdownController {
|
||||
@Autowired
|
||||
private MarkdownService markdownService;
|
||||
|
||||
@ApiOperation("Markdown标记")
|
||||
@PostMapping("/render")
|
||||
public ResultUtils replaceMarkdown(@RequestBody String content) throws IOException{
|
||||
markdownService.saveItem(content) ;
|
||||
markdownService.processMarkdownFiles(content);
|
||||
return ResultUtils.success("success");
|
||||
}
|
||||
@ApiOperation("获取文件名")
|
||||
@GetMapping("/getFileName")
|
||||
public ResultUtils getFileName(@RequestParam String FilePath){
|
||||
return ResultUtils.success(markdownService.getFileName(FilePath));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.bjtds.brichat.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public interface MarkdownService {
|
||||
void saveItem(String content) throws IOException;
|
||||
void processMarkdownFiles(String content) throws IOException;
|
||||
List<String> getFileName(String filePath);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.bjtds.brichat.service.impl;
|
||||
|
||||
import com.bjtds.brichat.service.MarkdownService;
|
||||
import com.bjtds.brichat.util.FuzzyMatcher;
|
||||
import com.itextpdf.text.pdf.parser.clipper.Path;
|
||||
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
|
||||
import java.io.File;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class MarkdownServiceImpl implements MarkdownService {
|
||||
|
||||
private static final String ITEM_FILE="F:\\project\\bjtdsweb\\ai-manus\\chat-server\\file\\item\\item.md";
|
||||
private static final String INPUT_DIR="F:\\project\\bjtdsweb\\ai-manus\\chat-server\\file\\input" ;
|
||||
private static final String OUTPUT_DIR="F:\\project\\bjtdsweb\\ai-manus\\chat-server\\file\\output" ;
|
||||
|
||||
@Override
|
||||
public void saveItem(String content) throws IOException {
|
||||
Files.write(Paths.get(ITEM_FILE),(content+"\n").getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE,StandardOpenOption.APPEND);
|
||||
}
|
||||
@Override
|
||||
public void processMarkdownFiles(String content) throws IOException {
|
||||
List<String> files = Files.list(Paths.get(INPUT_DIR))
|
||||
.filter(f->f.toString().endsWith(".md"))
|
||||
.map(Path->Path.toString())
|
||||
.collect(Collectors.toList());
|
||||
int count = 0;
|
||||
for (String file : files) {
|
||||
String result = FuzzyMatcher.fuzzyMarkdownProcess(file, ITEM_FILE);
|
||||
if (!"no".equals(result)) {
|
||||
Files.write(Paths.get(OUTPUT_DIR + "\\" + "change" + (count++) + ".md"), result.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFileName(String filePath) {
|
||||
List<String> fileNames = new ArrayList<>();
|
||||
File folder = new File(filePath);
|
||||
if (!folder.exists() || !folder.isDirectory()) {
|
||||
return fileNames;
|
||||
}
|
||||
File[] files = folder.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
fileNames.add(file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package com.bjtds.brichat.util;
|
||||
|
||||
import org.simmetrics.StringMetric;
|
||||
import org.simmetrics.metrics.StringMetrics;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FuzzyMatcher {
|
||||
|
||||
private static final StringMetric fuzzyMetric = StringMetrics.jaroWinkler();
|
||||
private static final int DEFAULT_THRESHOLD = 84;
|
||||
|
||||
public static String fuzzyMarkdownProcess(String sourcePath, String targetPath, int threshold) throws IOException {
|
||||
String source = String.join("\n", Files.readAllLines(Paths.get(sourcePath)));
|
||||
String target = String.join("\n", Files.readAllLines(Paths.get(targetPath)));
|
||||
|
||||
List<String> sourceBlocks = MarkdownUtils.splitMarkdownBlocks(source);
|
||||
List<String> targetBlocks = MarkdownUtils.splitMarkdownBlocks(target);
|
||||
|
||||
boolean hasReplacement = false; // ✅ 标记是否发生替换
|
||||
|
||||
for (int i = 0; i < targetBlocks.size(); i++) {
|
||||
ReplacementResult result = fuzzyReplaceWithProcessing(sourceBlocks, targetBlocks.get(i), threshold);
|
||||
if (result.replaced) {
|
||||
hasReplacement = true;
|
||||
sourceBlocks = result.updatedBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasReplacement) {
|
||||
return "no"; // ✅ 没有替换返回 no
|
||||
}
|
||||
|
||||
return String.join("\n\n", sourceBlocks);
|
||||
}
|
||||
|
||||
public static String fuzzyMarkdownProcess(String sourcePath, String targetPath) throws IOException {
|
||||
return fuzzyMarkdownProcess(sourcePath, targetPath, DEFAULT_THRESHOLD);
|
||||
}
|
||||
|
||||
// ✅ 用类封装返回值:包含更新后的块和是否替换的标记
|
||||
private static class ReplacementResult {
|
||||
List<String> updatedBlocks;
|
||||
boolean replaced;
|
||||
|
||||
ReplacementResult(List<String> updatedBlocks, boolean replaced) {
|
||||
this.updatedBlocks = updatedBlocks;
|
||||
this.replaced = replaced;
|
||||
}
|
||||
}
|
||||
|
||||
private static ReplacementResult fuzzyReplaceWithProcessing(List<String> sourceBlocks, String targetBlock, int threshold) {
|
||||
int bestIndex = -1;
|
||||
int bestScore = -1;
|
||||
|
||||
for (int i = 0; i < sourceBlocks.size(); i++) {
|
||||
String source = normalize(sourceBlocks.get(i));
|
||||
String target = normalize(targetBlock);
|
||||
|
||||
float score = fuzzyMetric.compare(source, target);
|
||||
int percentScore = Math.round(score * 100);
|
||||
|
||||
if (percentScore > bestScore) {
|
||||
bestScore = percentScore;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestScore < threshold || bestIndex == -1) {
|
||||
return new ReplacementResult(sourceBlocks, false);
|
||||
}
|
||||
|
||||
String replacement;
|
||||
if (MarkdownUtils.isMarkdownTable(targetBlock)) {
|
||||
replacement = MarkdownUtils.markdownTableToHtml(targetBlock);
|
||||
} else if (MarkdownUtils.isMarkdownHeading(targetBlock)) {
|
||||
replacement = MarkdownUtils.addEqualsToHeading(targetBlock);
|
||||
} else {
|
||||
replacement = "==" + targetBlock.trim() + "==";
|
||||
}
|
||||
|
||||
List<String> updated = new ArrayList<>(sourceBlocks);
|
||||
updated.set(bestIndex, replacement);
|
||||
|
||||
return new ReplacementResult(updated, true);
|
||||
}
|
||||
|
||||
private static String normalize(String text) {
|
||||
return text
|
||||
.replaceAll("\\|\\s*-+\\s*\\|", "")
|
||||
.replaceAll("[\\r\\n]+", " ")
|
||||
.replaceAll("\\s+", " ")
|
||||
.replaceAll("[`*_#>\\[\\]<>]", "")
|
||||
.replaceAll("<[^>]+>", "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package com.bjtds.brichat.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MarkdownUtils {
|
||||
|
||||
/**
|
||||
* 将 Markdown 文本按段落块分割(连续空行视为分隔)
|
||||
*/
|
||||
public static List<String> splitMarkdownBlocks(String markdown) {
|
||||
return Arrays.stream(markdown.split("\\n{2,}"))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格判断逻辑:只要一行中包含“|”,就视为表格块
|
||||
*/
|
||||
public static boolean isMarkdownTable(String block) {
|
||||
return Arrays.stream(block.split("\n")).anyMatch(line -> line.contains("|"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 Markdown 标题(以 '#' 开头)
|
||||
*/
|
||||
public static boolean isMarkdownHeading(String block) {
|
||||
return block.trim().startsWith("#");
|
||||
}
|
||||
|
||||
/**
|
||||
* 把 Markdown 标题转换为等号形式
|
||||
* 示例: "# 标题" -> "标题\n====="
|
||||
*/
|
||||
public static String addEqualsToHeading(String block) {
|
||||
String line = block.trim().replaceAll("^#+", "").trim();
|
||||
return line + "\n" + new String(new char[line.length()]).replace('\0', '=');
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Markdown 表格转换为 HTML 表格(简单处理)
|
||||
*/
|
||||
public static String markdownTableToHtml(String block) {
|
||||
List<String> lines = Arrays.stream(block.split("\n"))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String[]> rows = new ArrayList<>();
|
||||
for (String line : lines) {
|
||||
String[] cells = Arrays.stream(line.split("\\|"))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.toArray(String[]::new);
|
||||
if (cells.length > 0) {
|
||||
rows.add(cells);
|
||||
}
|
||||
}
|
||||
|
||||
if (rows.isEmpty()) return "<table></table>";
|
||||
|
||||
StringBuilder html = new StringBuilder();
|
||||
|
||||
// 加入前置分割线
|
||||
|
||||
// 设置表格背景色为淡黄色
|
||||
html.append("<table class=\"custom - table\"style=\"background-color:#ffffcc; border-collapse: collapse; width: 100%;\">\n");
|
||||
|
||||
// 表头
|
||||
html.append(" <thead><tr>");
|
||||
for (String header : rows.get(0)) {
|
||||
html.append("<th style=\"border:1px solid #999;padding:4px;\">")
|
||||
.append(header).append("</th>");
|
||||
}
|
||||
html.append("</tr></thead>\n");
|
||||
|
||||
// 表体
|
||||
html.append(" <tbody>\n");
|
||||
for (int i = 1; i < rows.size(); i++) {
|
||||
html.append(" <tr>");
|
||||
for (String cell : rows.get(i)) {
|
||||
html.append("<td style=\"border:1px solid #999;padding:4px;\">")
|
||||
.append(cell).append("</td>");
|
||||
}
|
||||
html.append("</tr>\n");
|
||||
}
|
||||
html.append(" </tbody>\n</table>");
|
||||
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue