package com.kexue.skills.common.util; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import java.io.*; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import net.sf.sevenzipjbinding.*; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; /** * 技能包解析工具类 * 用于解析skill zip包并生成符合要求的yaml描述 */ public class SkillZipParser { /** * 提取压缩包中的skillMdText * @param filePath 压缩文件路径 * @param defaultSkillName 默认技能名称 * @return 包含skillMdText的Map * @throws IOException 解析过程中的IO异常 * @throws SevenZipException 解析RAR文件时的异常 */ public static Map extractSkillMdText(String filePath, String defaultSkillName) throws IOException, SevenZipException { // 检查文件扩展名 String fileExtension = ""; if (filePath.contains(".")) { int dotIndex = filePath.lastIndexOf("."); fileExtension = filePath.substring(dotIndex).toLowerCase(); } // 根据文件类型选择不同的解析方法 if (".rar".equals(fileExtension)) { return extractSkillInfoFromRar(filePath, defaultSkillName); } else { // 默认为zip文件 try (ZipFile zipFile = new ZipFile(filePath, StandardCharsets.UTF_8)) { return extractSkillInfo(zipFile, defaultSkillName); } } } /** * 生成技能包的yaml描述 * @param filePath 压缩文件路径 * @param author 作者 * @param skillName 技能名称 * @param skillDescription 技能描述 * @param skillTags 技能标签 * @return 生成的yaml描述 * @throws IOException 解析过程中的IO异常 * @throws SevenZipException 解析RAR文件时的异常 */ public static String generateYamlFromSkillInfo(String filePath, String author, String skillName, String skillDescription, List skillTags) throws IOException, SevenZipException { // 检查文件扩展名 String fileExtension = ""; if (filePath.contains(".")) { int dotIndex = filePath.lastIndexOf("."); fileExtension = filePath.substring(dotIndex).toLowerCase(); } // 根据文件类型选择不同的解析方法 Map skillStructure; if (".rar".equals(fileExtension)) { skillStructure = generateSkillStructureFromRar(filePath, skillName, skillDescription, skillTags, author); } else { // 默认为zip文件 try (ZipFile zipFile = new ZipFile(filePath, StandardCharsets.UTF_8)) { skillStructure = generateSkillStructure(zipFile, skillName, skillDescription, skillTags, author); } } // 生成yaml return generateYaml(skillStructure); } /** * 解析skill zip包并生成yaml描述 * @param zipFilePath zip文件路径 * @param author 作者 * @param defaultSkillName 默认技能名称 * @return 包含技能信息和yaml描述的Map * @throws IOException 解析过程中的IO异常 * @throws SevenZipException 解析RAR文件时的异常 */ public static Map parseSkillZip(String zipFilePath, String author, String defaultSkillName) throws IOException, SevenZipException { // 检查文件扩展名 String fileExtension = ""; if (zipFilePath.contains(".")) { int dotIndex = zipFilePath.lastIndexOf("."); fileExtension = zipFilePath.substring(dotIndex).toLowerCase(); } // 根据文件类型选择不同的解析方法 if (".rar".equals(fileExtension)) { return parseRarFile(zipFilePath, author, defaultSkillName); } else { // 默认为zip文件 try (ZipFile zipFile = new ZipFile(zipFilePath, StandardCharsets.UTF_8)) { // 从压缩文件中提取技能信息 Map skillInfo = extractSkillInfo(zipFile, defaultSkillName); String skillName = (String) skillInfo.get("name"); String skillDescription = (String) skillInfo.get("description"); List skillTags = (List) skillInfo.get("tags"); // 生成技能包结构 Map skillStructure = generateSkillStructure(zipFile, skillName, skillDescription, skillTags, author); // 生成yaml String yamlContent = generateYaml(skillStructure); // 构建返回结果 Map result = new LinkedHashMap<>(); result.put("name", skillName); result.put("description", skillDescription); result.put("tags", skillTags); result.put("yamlContent", yamlContent); // 包含md文件的完整内容 if (skillInfo.containsKey("skillMdText")) { result.put("skillMdText", skillInfo.get("skillMdText")); } return result; } } } /** * 解析rar文件 * @param rarFilePath rar文件路径 * @param author 作者 * @param defaultSkillName 默认技能名称 * @return 技能信息 * @throws IOException 解析过程中的IO异常 * @throws SevenZipException 解析RAR文件时的异常 */ private static Map parseRarFile(String rarFilePath, String author, String defaultSkillName) throws IOException, SevenZipException { // 从rar文件中提取技能信息 Map skillInfo = extractSkillInfoFromRar(rarFilePath, defaultSkillName); String skillName = (String) skillInfo.get("name"); String skillDescription = (String) skillInfo.get("description"); List skillTags = (List) skillInfo.get("tags"); // 生成技能包结构 Map skillStructure = generateSkillStructureFromRar(rarFilePath, skillName, skillDescription, skillTags, author); // 生成yaml String yamlContent = generateYaml(skillStructure); // 构建返回结果 Map result = new LinkedHashMap<>(); result.put("name", skillName); result.put("description", skillDescription); result.put("tags", skillTags); result.put("yamlContent", yamlContent); // 包含md文件的完整内容 if (skillInfo.containsKey("skillMdText")) { result.put("skillMdText", skillInfo.get("skillMdText")); } return result; } /** * 从rar文件中提取技能信息 * @param rarFilePath rar文件路径 * @param defaultSkillName 默认技能名称 * @return 技能信息 * @throws IOException 解析过程中的IO异常 * @throws Exception 解析过程中的异常 */ private static Map extractSkillInfoFromRar(String rarFilePath, String defaultSkillName) throws IOException, SevenZipException { Map skillInfo = new LinkedHashMap<>(); boolean foundMdFile = false; // 验证文件是否存在 File rarFile = new File(rarFilePath); if (!rarFile.exists()) { throw new FileNotFoundException("RAR file not found: " + rarFilePath); } if (!rarFile.canRead()) { throw new IOException("Cannot read RAR file: " + rarFilePath); } try (RandomAccessFile randomAccessFile = new RandomAccessFile(rarFile, "r"); IInArchive archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile))) { // 使用简单接口 ISimpleInArchive simpleInArchive = archive.getSimpleInterface(); // 遍历所有文件条目 for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) { // 检查是否是根目录下的md文件 String path = item.getPath(); if (!item.isFolder() && path.endsWith(".md") && !path.contains("/") && !path.contains("\\")) { // 读取文件内容 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); item.extractSlow(data -> { try { outputStream.write(data); } catch (IOException e) { throw new RuntimeException(e); } return data.length; }); String content = outputStream.toString(StandardCharsets.UTF_8); // 存储md文件的完整内容 skillInfo.put("skillMdText", content); // 解析md内容 parseSkillsMd(content, skillInfo); foundMdFile = true; break; // 找到一个md文件后就停止 } } } // 如果没有找到 md 文件,使用默认值 if (!foundMdFile) { skillInfo.put("name", defaultSkillName); skillInfo.put("description", "Skill uploaded via uploadSkillV2"); skillInfo.put("tags", Arrays.asList("10001", "10002")); } else { // 确保 tags 不为 null if (!skillInfo.containsKey("tags")) { skillInfo.put("tags", Arrays.asList("10001")); } } return skillInfo; } /** * 从压缩文件中提取技能信息 * @param zipFile zip文件对象 * @param defaultSkillName 默认技能名称 * @return 技能信息 * @throws IOException 解析过程中的IO异常 */ private static Map extractSkillInfo(ZipFile zipFile, String defaultSkillName) throws IOException { Map skillInfo = new LinkedHashMap<>(); boolean foundMdFile = false; // 尝试从zip根目录的md文件中提取信息 Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); // 检查是否是根目录下的md文件 if (!entry.isDirectory() && entry.getName().endsWith(".md") && !entry.getName().contains("/")) { try (InputStream inputStream = zipFile.getInputStream(entry); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { StringBuilder content = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } // 存储md文件的完整内容 skillInfo.put("skillMdText", content.toString()); // 解析md内容 parseSkillsMd(content.toString(), skillInfo); foundMdFile = true; break; // 找到一个md文件后就停止 } } } // 如果没有找到 md 文件,使用默认值 if (!foundMdFile) { skillInfo.put("name", defaultSkillName); skillInfo.put("description", "Skill uploaded "); skillInfo.put("tags", Arrays.asList("10001", "10002")); } else { // 确保 tags 不为 null if (!skillInfo.containsKey("tags")) { skillInfo.put("tags", Arrays.asList("10001")); } } return skillInfo; } /** * 解析skills.md文件内容 * @param content skills.md文件内容 * @param skillInfo 技能信息Map */ private static void parseSkillsMd(String content, Map skillInfo) { // 解析技能名称 Pattern namePattern = Pattern.compile("#\s+(.*)"); Matcher nameMatcher = namePattern.matcher(content); if (nameMatcher.find()) { skillInfo.put("name", nameMatcher.group(1).trim()); } // 解析技能描述 Pattern descPattern = Pattern.compile("##\s+Description\s+(.*?)(?=##|$)", Pattern.DOTALL); Matcher descMatcher = descPattern.matcher(content); if (descMatcher.find()) { String description = descMatcher.group(1).trim(); skillInfo.put("description", description); } // 解析技能标签 Pattern tagPattern = Pattern.compile("##\s+Tags\s+(.*?)(?=##|$)", Pattern.DOTALL); Matcher tagMatcher = tagPattern.matcher(content); if (tagMatcher.find()) { String tagsSection = tagMatcher.group(1); Pattern tagItemPattern = Pattern.compile("-\s+(.*)"); Matcher tagItemMatcher = tagItemPattern.matcher(tagsSection); List tags = new ArrayList<>(); while (tagItemMatcher.find()) { tags.add(tagItemMatcher.group(1).trim()); } if (!tags.isEmpty()) { skillInfo.put("tags", tags); } } } /** * 从rar文件生成技能包结构 * @param rarFilePath rar文件路径 * @param skillName 技能包名称 * @param skillDescription 技能包描述 * @param skillTags 技能包标签 * @param author 作者 * @return 技能包结构 * @throws IOException 解析过程中的IO异常 * @throws Exception 解析过程中的异常 */ private static Map generateSkillStructureFromRar(String rarFilePath, String skillName, String skillDescription, List skillTags, String author) throws IOException, SevenZipException { // 验证文件是否存在 File rarFile = new File(rarFilePath); if (!rarFile.exists()) { throw new FileNotFoundException("RAR file not found: " + rarFilePath); } if (!rarFile.canRead()) { throw new IOException("Cannot read RAR file: " + rarFilePath); } Map skillStructure = new LinkedHashMap<>(); // 核心概要 skillStructure.put("name", skillName); skillStructure.put("version", "1.0.0"); skillStructure.put("description", skillDescription); skillStructure.put("author", author); skillStructure.put("created", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); skillStructure.put("tags", skillTags); // 核心节点 structure Map structure = new LinkedHashMap<>(); structure.put("name", skillName); structure.put("type", "directory"); structure.put("path", "."); structure.put("format", "directory"); structure.put("description", skillDescription); // 构建目录树结构 List> children = new ArrayList<>(); Map> directoryMap = new HashMap<>(); // 一次性读取所有条目并处理 try (RandomAccessFile randomAccessFile = new RandomAccessFile(rarFile, "r"); IInArchive archive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile))) { // 使用简单接口 ISimpleInArchive simpleInArchive = archive.getSimpleInterface(); ISimpleInArchiveItem[] archiveItems = simpleInArchive.getArchiveItems(); // 首先处理所有目录 for (ISimpleInArchiveItem item : archiveItems) { if (item.isFolder()) { String path = item.getPath(); // 确保路径以/结尾,与 zip 处理一致 if (!path.endsWith("/")) { path = path + "/"; } String[] pathParts = path.split("/"); createDirectoryTree(children, directoryMap, pathParts, path); } } // 然后处理所有文件 for (ISimpleInArchiveItem item : archiveItems) { if (!item.isFolder()) { String path = item.getPath(); String[] pathParts = path.split("/"); String fileName = pathParts[pathParts.length - 1]; // 读取文件内容 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); item.extractSlow(data -> { try { outputStream.write(data); } catch (IOException e) { throw new RuntimeException(e); } return data.length; }); String fileContent = outputStream.toString(StandardCharsets.UTF_8); addFileToTreeFromRar(children, directoryMap, pathParts, fileName, fileContent, path); } } } // 确保包含skills.md文件 boolean hasSkillsMd = false; for (Map child : children) { if ("skills.md".equals(child.get("name")) && "file".equals(child.get("type"))) { hasSkillsMd = true; break; } } if (!hasSkillsMd) { Map skillsMdNode = createSkillsMdNode(skillName, skillDescription, skillTags); children.add(skillsMdNode); } // 确保包含scripts目录 boolean hasScriptsDir = false; for (Map child : children) { if ("scripts".equals(child.get("name")) && "directory".equals(child.get("type"))) { hasSkillsMd = true; break; } } if (!hasScriptsDir) { Map scriptsDirNode = createScriptsDirNode(); children.add(scriptsDirNode); } structure.put("children", children); skillStructure.put("structure", structure); return skillStructure; } /** * 将 rar 文件添加到目录树中 * @param children 子节点列表 * @param directoryMap 目录映射 * @param pathParts 路径部分 * @param item rar 文件项 * @param fileName 文件名 * @param fileContent 文件内容 * @param filePath 文件路径 * @throws IOException 读取文件内容时的 IO 异常 */ private static void addFileToTreeFromRar(List> children, Map> directoryMap, String[] pathParts, String fileName, String fileContent, String filePath) throws IOException { if (pathParts.length == 0) return; // 构建目录路径 StringBuilder directoryPath = new StringBuilder(); for (int i = 0; i < pathParts.length - 1; i++) { String part = pathParts[i]; if (!part.isEmpty()) { directoryPath.append(part).append("/"); } } // 找到文件所在的目录节点 List> targetChildren = children; if (directoryPath.length() > 0) { Map directoryNode = directoryMap.get(directoryPath.toString()); if (directoryNode != null) { targetChildren = (List>) directoryNode.get("children"); } } // 创建文件节点并添加到目标目录 Map fileNode = createFileNodeFromRar(fileName, fileContent, filePath); targetChildren.add(fileNode); } /** * 从文件信息创建文件节点 * @param fileName 文件名 * @param fileContent 文件内容 * @param filePath 文件路径 * @return 文件节点 * @throws IOException 读取文件内容时的 IO 异常 */ private static Map createFileNodeFromRar(String fileName, String fileContent, String filePath) throws IOException { Map fileNode = new LinkedHashMap<>(); fileNode.put("name", fileName); fileNode.put("type", "file"); fileNode.put("path", filePath); fileNode.put("format", getFileFormat(fileName)); fileNode.put("description", fileName + " file"); fileNode.put("content", fileContent); return fileNode; } /** * 生成技能包结构 * @param zipFile zip文件对象 * @param skillName 技能包名称 * @param skillDescription 技能包描述 * @param skillTags 技能包标签 * @param author 作者 * @return 技能包结构 * @throws IOException 解析过程中的IO异常 */ private static Map generateSkillStructure(ZipFile zipFile, String skillName, String skillDescription, List skillTags, String author) throws IOException { Map skillStructure = new LinkedHashMap<>(); // 核心概要 skillStructure.put("name", skillName); skillStructure.put("version", "1.0.0"); skillStructure.put("description", skillDescription); skillStructure.put("author", author); skillStructure.put("created", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); skillStructure.put("tags", skillTags); // 核心节点structure Map structure = new LinkedHashMap<>(); structure.put("name", skillName); structure.put("type", "directory"); structure.put("path", "."); structure.put("format", "directory"); structure.put("description", skillDescription); // 构建目录树结构 List> children = new ArrayList<>(); Map> directoryMap = new HashMap<>(); // 首先处理所有目录 Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (entry.isDirectory()) { String path = entry.getName(); String[] pathParts = path.split("/"); createDirectoryTree(children, directoryMap, pathParts, path); } } // 然后处理所有文件 entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (!entry.isDirectory()) { String path = entry.getName(); String[] pathParts = path.split("/"); addFileToTree(children, directoryMap, pathParts, entry, zipFile); } } // 确保包含skills.md文件 boolean hasSkillsMd = false; for (Map child : children) { if ("skills.md".equals(child.get("name")) && "file".equals(child.get("type"))) { hasSkillsMd = true; break; } } if (!hasSkillsMd) { Map skillsMdNode = createSkillsMdNode(skillName, skillDescription, skillTags); children.add(skillsMdNode); } // 确保包含scripts目录 boolean hasScriptsDir = false; for (Map child : children) { if ("scripts".equals(child.get("name")) && "directory".equals(child.get("type"))) { hasScriptsDir = true; break; } } if (!hasScriptsDir) { Map scriptsDirNode = createScriptsDirNode(); children.add(scriptsDirNode); } structure.put("children", children); skillStructure.put("structure", structure); return skillStructure; } /** * 创建目录树结构 * @param children 子节点列表 * @param directoryMap 目录映射 * @param pathParts 路径部分 * @param fullPath 完整路径 */ private static void createDirectoryTree(List> children, Map> directoryMap, String[] pathParts, String fullPath) { List> currentChildren = children; StringBuilder currentPath = new StringBuilder(); for (int i = 0; i < pathParts.length; i++) { String part = pathParts[i]; if (part.isEmpty()) continue; currentPath.append(part).append("/"); String pathKey = currentPath.toString(); // 检查当前目录是否已存在 Map directoryNode = directoryMap.get(pathKey); if (directoryNode == null) { // 创建新目录节点 directoryNode = new LinkedHashMap<>(); directoryNode.put("name", part); directoryNode.put("type", "directory"); directoryNode.put("path", pathKey); directoryNode.put("format", "directory"); directoryNode.put("description", part + " directory"); directoryNode.put("children", new ArrayList<>()); // 添加到当前子节点列表 currentChildren.add(directoryNode); directoryMap.put(pathKey, directoryNode); } // 进入下一级目录 currentChildren = (List>) directoryNode.get("children"); } } /** * 将文件添加到目录树中 * @param children 子节点列表 * @param directoryMap 目录映射 * @param pathParts 路径部分 * @param entry zip条目 * @param zipFile zip文件对象 * @throws IOException 读取文件内容时的IO异常 */ private static void addFileToTree(List> children, Map> directoryMap, String[] pathParts, ZipEntry entry, ZipFile zipFile) throws IOException { if (pathParts.length == 0) return; // 获取文件名 String fileName = pathParts[pathParts.length - 1]; // 构建目录路径 StringBuilder directoryPath = new StringBuilder(); for (int i = 0; i < pathParts.length - 1; i++) { String part = pathParts[i]; if (!part.isEmpty()) { directoryPath.append(part).append("/"); } } // 找到文件所在的目录节点 List> targetChildren = children; if (directoryPath.length() > 0) { Map directoryNode = directoryMap.get(directoryPath.toString()); if (directoryNode != null) { targetChildren = (List>) directoryNode.get("children"); } } // 创建文件节点并添加到目标目录 Map fileNode = createFileNode(entry, zipFile); targetChildren.add(fileNode); } /** * 创建目录节点 * @param entry zip条目 * @param zipFile zip文件对象 * @return 目录节点 */ private static Map createDirectoryNode(ZipEntry entry, ZipFile zipFile) { Map directoryNode = new LinkedHashMap<>(); String name = entry.getName().replaceAll("/$", ""); name = name.substring(name.lastIndexOf("/") + 1); directoryNode.put("name", name); directoryNode.put("type", "directory"); directoryNode.put("path", entry.getName()); directoryNode.put("format", "directory"); directoryNode.put("description", name + " directory"); directoryNode.put("children", new ArrayList<>()); return directoryNode; } /** * 创建文件节点 * @param entry zip条目 * @param zipFile zip文件对象 * @return 文件节点 * @throws IOException 读取文件内容时的IO异常 */ private static Map createFileNode(ZipEntry entry, ZipFile zipFile) throws IOException { Map fileNode = new LinkedHashMap<>(); String name = entry.getName().substring(entry.getName().lastIndexOf("/") + 1); fileNode.put("name", name); fileNode.put("type", "file"); fileNode.put("path", entry.getName()); fileNode.put("format", getFileFormat(name)); fileNode.put("description", name + " file"); // 读取文件内容 try (InputStream inputStream = zipFile.getInputStream(entry); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { StringBuilder content = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } fileNode.put("content", content.toString()); } return fileNode; } /** * 创建skills.md文件节点 * @param skillName 技能包名称 * @param skillDescription 技能包描述 * @param skillTags 技能包标签 * @return skills.md文件节点 */ private static Map createSkillsMdNode(String skillName, String skillDescription, List skillTags) { Map skillsMdNode = new LinkedHashMap<>(); skillsMdNode.put("name", "skills.md"); skillsMdNode.put("type", "file"); skillsMdNode.put("path", "skills.md"); skillsMdNode.put("format", "markdown"); skillsMdNode.put("description", "Skills metadata file"); // 生成skills.md内容 StringBuilder content = new StringBuilder(); content.append("# " + skillName).append("\n\n"); content.append("## Description").append("\n"); content.append(skillDescription).append("\n\n"); content.append("## Tags").append("\n"); if (skillTags != null && !skillTags.isEmpty()) { for (String tag : skillTags) { content.append("- " + tag).append("\n"); } } else { content.append("- general\n").append("- skill\n"); } content.append("\n"); content.append("## Usage").append("\n"); content.append("This skill provides functionality for " + skillName).append("\n"); skillsMdNode.put("content", content.toString()); return skillsMdNode; } /** * 创建scripts目录节点 * @return scripts目录节点 */ private static Map createScriptsDirNode() { Map scriptsDirNode = new LinkedHashMap<>(); scriptsDirNode.put("name", "scripts"); scriptsDirNode.put("type", "directory"); scriptsDirNode.put("path", "scripts/"); scriptsDirNode.put("format", "directory"); scriptsDirNode.put("description", "Scripts directory"); // 添加示例脚本 List> scriptChildren = new ArrayList<>(); // 示例Python脚本 Map pythonScriptNode = new LinkedHashMap<>(); pythonScriptNode.put("name", "example.py"); pythonScriptNode.put("type", "file"); pythonScriptNode.put("path", "scripts/example.py"); pythonScriptNode.put("format", "python"); pythonScriptNode.put("description", "Example Python script"); pythonScriptNode.put("content", "#!/usr/bin/env python3\n" + "\"\"\"\n" + "Example script for " + "skill" + "\n" + "\"\"\"\n\n" + "def main():\n" + " print('Hello from skill script!')\n\n" + "if __name__ == '__main__':\n" + " main()\n"); scriptChildren.add(pythonScriptNode); scriptsDirNode.put("children", scriptChildren); return scriptsDirNode; } /** * 获取文件格式 * @param fileName 文件名 * @return 文件格式 */ private static String getFileFormat(String fileName) { if (fileName.endsWith(".md")) { return "markdown"; } else if (fileName.endsWith(".py")) { return "python"; } else if (fileName.endsWith(".js")) { return "javascript"; } else if (fileName.endsWith(".json")) { return "json"; } else if (fileName.endsWith(".yaml") || fileName.endsWith(".yml")) { return "yaml"; } else if (fileName.endsWith(".txt")) { return "text"; } else if (fileName.endsWith(".sh")) { return "shell"; } else { return "other"; } } /** * 生成yaml * @param skillStructure 技能包结构 * @return 生成的yaml描述 */ private static String generateYaml(Map skillStructure) { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); options.setIndent(2); options.setPrettyFlow(true); Yaml yaml = new Yaml(options); return yaml.dump(skillStructure); } }