2. Java-MarkDown文件解析-工具类
2. Java-MarkDown文件解析-工具类
1. 思路
- 读取markdown文件的内容,根据markdown的语法进行各个类型语法的解析。
- 引入工具类 commonmark 和 commonmark-ext-gfm-tables进行markdown语法解析。
2. 工具类
pom.xml
<!-- commonmark 解析markdown -->
<dependency><groupId>org.commonmark</groupId><artifactId>commonmark</artifactId><version>0.21.0</version>
</dependency>
<!-- commonmark 解析markdown tables -->
<dependency><groupId>org.commonmark</groupId><artifactId>commonmark-ext-gfm-tables</artifactId><version>0.21.0</version>
</dependency>
MarkdownParseResult
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** Markdown解析结果* @Author: onecomer* @Date: 2021/1/26 16:00*/
@ApiModel(description = "Markdown解析结果")
@Data
public class MarkdownParseResult {@ApiModelProperty(value = "MarkdownHtml内容")private String htmlContent;@ApiModelProperty(value = "标题及内容集合",example = "{'标题1':'内容1','标题2':'内容2',...}")private JSONObject titles;@ApiModelProperty(value = "表格标题及内容集合",example = "{'表格标题':'{headers:['列1','列2'],rows:[{'值1','值2'},{'值1','值2'}]}",notes = "headers为表头,rows为行数据")private JSONObject tables;@ApiModelProperty(value = "无序列表集合",example = "{''无序列表标题:[{'无序列表内容1'},{'无序列表内容2'},...]}")private JSONObject unOrderedLists;@ApiModelProperty(value = "有序列表集合",example = "{''有序列表标题:[{'有序列表内容1'},{'有序列表内容2'},...]}")private JSONObject orderedLists;@ApiModelProperty(value = "代码块集合",example = "{'代码块标题1':{'codeBlockContent(固定值)':'代码块内容1','codeBlockType(固定值)':'代码块类型1'}}")private JSONObject codeBlocks;
}
MarkdownParserUtil
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.ext.gfm.tables.TableBody;
import org.commonmark.ext.gfm.tables.TableCell;
import org.commonmark.ext.gfm.tables.TableHead;
import org.commonmark.ext.gfm.tables.TableRow;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.node.AbstractVisitor;
import org.commonmark.node.BulletList;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.Heading;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.OrderedList;
import org.commonmark.node.Paragraph;
import org.commonmark.node.SoftLineBreak;
import org.commonmark.node.Text;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Markdown解析工具类* @Author: onecomer* @Date: 2021/1/26 16:00*/
public class MarkdownParserUtil {private static Parser parser;private static HtmlRenderer renderer;static {parser = Parser.builder().extensions(Arrays.asList(TablesExtension.create())).build();renderer = HtmlRenderer.builder().extensions(Arrays.asList(TablesExtension.create())).build();}/*** 读取并解析Markdown文件*/public static MarkdownParseResult parseMarkdownFile(String filePath) {String content = null;try {content = new String(Files.readAllBytes(Paths.get(filePath)));} catch (IOException e) {throw new RuntimeException(e);}MarkdownParseResult result = parseMarkdownFileContent(content);return result;}/*** 解析Markdown内容*/public static MarkdownParseResult parseMarkdownFileContent(String content) {Node document = parser.parse(content);MarkdownParseResult result = new MarkdownParseResult();
// result.setHtmlContent(renderer.render(document));JSONObject titles = new JSONObject(true);JSONObject tables = new JSONObject(true);JSONObject unOrderedLists = new JSONObject(true);JSONObject orderedLists = new JSONObject(true);JSONObject codeBlocks = new JSONObject(true);String currentHeading = "";StringBuilder paragraphContent = new StringBuilder();boolean isDelReapeatTilte = true;Node node = document.getFirstChild();while (node != null) {if (node instanceof Heading) {// 标题String text = getText(node);currentHeading = text;// 只有标题的直接添加if (!((node.getNext()) instanceof Paragraph)) {titles.put(currentHeading, currentHeading);}} else if (node instanceof Paragraph) {String text = getText(node);// 普通文本paragraphContent.append(text).append("\n");// 结束添加paragraphContentif (!((node.getNext()) instanceof Paragraph)) {titles.put(currentHeading, paragraphContent.toString().trim());paragraphContent = new StringBuilder();}} else if (node instanceof BulletList) {// 无序列表JSONArray items = new JSONArray();Node listItem = node.getFirstChild();while (listItem != null) {if (listItem instanceof ListItem) {String text = getText(listItem);items.add(text);}listItem = listItem.getNext();}unOrderedLists.put(currentHeading, items);if (isDelReapeatTilte) {titles.remove(currentHeading);}} else if (node instanceof OrderedList) {// 有序列表JSONArray items = new JSONArray();Node listItem = node.getFirstChild();while (listItem != null) {if (listItem instanceof ListItem) {String text = getText(listItem);items.add(text);}listItem = listItem.getNext();}orderedLists.put(currentHeading, items);if (isDelReapeatTilte) {titles.remove(currentHeading);}} else if (node instanceof FencedCodeBlock) {// 代码块FencedCodeBlock codeBlock = (FencedCodeBlock) node;JSONObject codeBlockInfo = new JSONObject(true);String codeBlockContent = codeBlock.getLiteral();String codeBlockType = codeBlock.getInfo();codeBlockInfo.put("codeBlockContent", codeBlockContent);codeBlockInfo.put("codeBlockType", codeBlockType);codeBlocks.put(currentHeading, codeBlockInfo);if (isDelReapeatTilte) {titles.remove(currentHeading);}} else if (node instanceof TableBlock) {// 表格JSONObject tableInfo = new JSONObject(true);JSONArray headers = new JSONArray();JSONArray rows = new JSONArray();// TableHeadNode row = node.getFirstChild();if (row instanceof TableHead) {Node headerRow = row.getFirstChild();if (headerRow instanceof TableRow) {Node cell = headerRow.getFirstChild();while (cell != null) {if (cell instanceof TableCell) {String text = getText(cell);headers.add(text);}cell = cell.getNext();}}}// TableBodyNode tableBody = row.getNext();while (tableBody != null) {if (tableBody instanceof TableBody) {// TableRowNode tableRow = tableBody.getFirstChild();while (tableRow != null) {if (tableRow instanceof TableRow) {JSONArray rowData = new JSONArray();Node tableCell = tableRow.getFirstChild();while (tableCell != null) {if (tableCell instanceof TableCell) {String text = getText(tableCell);rowData.add(text);}tableCell = tableCell.getNext();}rows.add(rowData);}tableRow = tableRow.getNext();}}tableBody = tableBody.getNext();}tableInfo.put("headers", headers);tableInfo.put("rows", rows);tables.put(currentHeading, tableInfo);if (isDelReapeatTilte) {titles.remove(currentHeading);}}// 处理下一个节点node = node.getNext();}result.setTitles(titles);result.setTables(tables);result.setUnOrderedLists(unOrderedLists);result.setOrderedLists(orderedLists);result.setCodeBlocks(codeBlocks);return result;}/*** 获取节点的文本内容(包含格式)*/private static String getText(Node node) {StringBuilder sb = new StringBuilder();node.accept(new AbstractVisitor() {@Overridepublic void visit(Text text) {sb.append(text.getLiteral());}// @Override
// public void visit(Emphasis emphasis) {
// sb.append("*").append(getText(emphasis)).append("*");
// }
//
// @Override
// public void visit(StrongEmphasis strongEmphasis) {
// sb.append("**").append(getText(strongEmphasis)).append("**");
// }
//
// @Override
// public void visit(Code code) {
// sb.append("`").append(code.getLiteral()).append("`");
// }});return sb.toString().trim();}/*** 判断是否为表格节点*/@Deprecatedprivate static boolean isTable(Node node) {
// String content = getTextContent(node);
// return content.contains("|") && content.contains("\n") && content.contains("---");Node firstChild = node.getFirstChild();Node secondChild = firstChild != null ? firstChild.getNext() : null;if (secondChild instanceof SoftLineBreak) {return true;}return false;}/*** 解析表格内容*/@Deprecatedprivate static JSONObject parseTable(Node tableNode) {String[] lines = getText(tableNode).split("\n");boolean isHeader = true;List<String> headers = new ArrayList<>();for (String line : lines) {line = line.trim();if (line.isEmpty() || line.startsWith("|---")) {isHeader = false;continue;}String[] cells = line.split("\\|");List<String> cleanCells = new ArrayList<>();for (String cell : cells) {String cleaned = cell.trim();if (!cleaned.isEmpty()) {cleanCells.add(cleaned);}}if (isHeader) {headers.addAll(cleanCells);
// tableInfo.setHeaders(headers);} else {Map<String, String> row = new HashMap<>();for (int i = 0; i < headers.size() && i < cleanCells.size(); i++) {row.put(headers.get(i), cleanCells.get(i));}
// tableInfo.getRows().add(row);}}return null;}public static void main(String[] args) {String filePath = "D:\\tab\\1_ideaIC-2022.2.win\\2_WS\\1_SAAS_hgit_2\\2_assembler_all\\3_biz-project\\api-manage\\markdown\\新增实体数据能力.md";
// filePath = "D:\\tab\\1_ideaIC-2022.2.win\\2_WS\\1_SAAS_hgit_2\\2_assembler_all\\3_biz-project\\api-manage\\markdown\\新增实体数据能力2.md";MarkdownParseResult result = parseMarkdownFile(filePath);// System.out.println("HTML内容:");
// System.out.println(result.getHtmlContent());System.out.println("\n标题及内容:");System.out.println(result.getTitles().toJSONString());System.out.println("\n表格内容:");System.out.println(result.getTables().toJSONString());System.out.println("\n无序列表:");System.out.println(result.getUnOrderedLists().toJSONString());System.out.println("\n有序列表:");System.out.println(result.getOrderedLists().toJSONString());System.out.println("\n代码块:");System.out.println(result.getCodeBlocks().toJSONString());}
}
3. 测试
测试结果




markdown文件
# 新增实体数据能力## 接口说明用来新增一条记录用来新增一条记录2用来新增一条记录3## 资产类型:API## 应用- 应用S码:Sxx## 标签- 新增实体数据能力
- xxx系统
- Sxx
- 新增记录 数据管理## 版本- v1.0.0## 接口地址```json
{"测试地址": "{baseUrl}/model/{dataSource}/{entityName}/add","生产地址": "{baseUrl}/model/{dataSource}/{entityName}/add"
}
```## 调用前提```json
需要先部署低代码引擎微服务,部署文档链接如下:
开发环境引擎部署:https://ihaier.feishu.cn/wiki/LyitwBYg4i8fRDkpPC0crxpMnlg
运行环境引擎部署:https://ihaier.feishu.cn/wiki/ZG16wdmOiib658k39X1cuzlKnSe
```## 请求方式POST## 请求头Header| 参数名 | 类型 | 是否必填 | 参数说明 |
| :----------- | :----- | :------- | :---------------------------- |
| Access-Token | String | 是 | 统一登录token,从账号中心获取 |
| Access-Token2 | String | 是 | 统一登录token,从账号中心获取 |## 请求参数类型@RequestBody## 请求参数| 参数名 | 是否必填 | 类型 | 描述 |
| :--------- | :------- | :----------- | :---------------------- |
| field1 | 否 | String | 字段1 |
| field2 | 否 | Integer | 字段2 |
| entityName | 否 | Object/Array | 关联实体(一对一/一对多) |### 请求参数示例```json
{"field1": "","field2": 19,"entityName": {"field1": "","field2": ""},"entityName": [{"field1": "","field2": ""}]
}
```## 返回参数类型@ResponseBody## 返回参数| 参数名 | 类型 | 说明 |
| :------ | :------ | :--------------------------- |
| code | Integer | 响应码,0表示成功,非0表示失败 |
| message | String | 提示消息 |
| data | Object | 返回数据 |
| data.id | String | 主键ID |### 返回参数示例#### 正确```json
{"code": 0,"message": "success", "data": {"id": "主键ID"}
}
```#### 错误```json
{"code": 400,"message": "请求参数错误"
}
```### 错误码| errorCode | errorMessage |
| :-------- | :----------- |
| 400 | 请求参数错误 |## 调用示例```json
// 请求示例
POST /model/myDataSource/User/add
{"name": "张三","age": 25,"department": {"id": "dept001","name": "技术部"}
}// 返回结果示例
{"code": 0,"message": "success","data": {"id": "user001"}
}
```## 实现逻辑### 时序图```mermaid
sequenceDiagramparticipant Clientparticipant APIparticipant Serviceparticipant DatabaseClient->>API: POST /model/{ds}/{entity}/addAPI->>Service: addEntity(data)Service->>Service: validateData(data)Service->>Database: insert(data)Database-->>Service: Return idService-->>API: Return resultAPI-->>Client: Return response
```### 业务逻辑1. 校验请求参数的合法性
2. 根据实体定义验证字段
3. 生成主键ID
4. 保存实体数据
5. 返回新增记录的ID### 三方服务无
相关文章:
2. Java-MarkDown文件解析-工具类
2. Java-MarkDown文件解析-工具类 1. 思路 读取markdown文件的内容,根据markdown的语法进行各个类型语法的解析。引入工具类 commonmark 和 commonmark-ext-gfm-tables进行markdown语法解析。 2. 工具类 pom.xml <!-- commonmark 解析markdown --> <d…...
动态规划DP 最长上升子序列模型 登山(题目分析+C++完整代码)
概览检索 动态规划DP 最长上升子序列模型 登山 原题链接 AcWing 1014. 登山 题目描述 五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个…...
css-设置元素的溢出行为为可见overflow: visible;
1.前言 overflow 属性用于设置当元素的内容溢出其框时如何处理。 2. overflow overflow 属性的一些常见值: 1 visible:默认值。内容不会被剪裁,会溢出元素的框。 2 hidden:内容会被剪裁,不会显示溢出的部分。 3 sc…...
家居EDI:Hom Furniture EDI需求分析
HOM Furniture 是一家成立于1977年的美国家具零售商,总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品,满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…...
1、开始简单使用rag
文章目录 前言数据存放申请api开始代码安装依赖从文件夹中读取文档文档切块将分割嵌入并存储在向量库中检索部分代码构造用户接口演示提示 整体代码 前言 本章只是简单使用rag的一个示例,为了引出以后的学习,将整个rag的流程串起来 数据存放 一个示例…...
Linux Samba 低版本漏洞(远程控制)复现与剖析
目录 前言 漏洞介绍 漏洞原理 产生条件 漏洞影响 防御措施 复现过程 结语 前言 在网络安全的复杂生态中,系统漏洞的探索与防范始终是保障数字世界安全稳定运行的关键所在。Linux Samba 作为一款在网络共享服务领域应用极为广泛的软件,其低版本中…...
安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】
一、实验目的(如果代码有错漏,可查看源码) 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…...
【 AI agents】letta:2024年代理堆栈演进(中英文翻译)
The AI agents stack AI 代理堆栈 November 14, 2024 11月 14, 2024原文: The AI agents stack官方教程教程学习笔记: 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理Understanding the AI agents landscape 了解 AI 代理环境 Although we see a …...
Java中 instanceof 的用法(详解)
目录 引言 基本语法 基本作用 1. 检查对象是否是指定类的实例 2. 检查对象是否是子类的实例 3. 检查对象是否实现某个接口 4.null 处理 错误分析: 5.综合对比示例 最后总结 注意事项 引言 instanceof 概念在多态中引出,因为在多态发生时&…...
联想拯救者R720笔记本外接显示屏方法,显示屏是2K屏27英寸
晚上23点10分前下单,第二天上午显示屏送到,检查外包装没拆封过。这个屏幕左下方有几个按键,按一按就开屏幕、按一按就关闭屏幕,按一按方便节省时间,也支持阅读等模式。 显示屏是 :AOC 27英寸 2K高清 100Hz…...
【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础
文章目录 1. 前言 本文章基于 RocketMQ 4.9.3 1. 前言 RocketMQ 存储部分系列文章: 【RocketMQ 存储】- RocketMQ存储类 MappedFile 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础...
S4 HANA明确税金本币和外币之间转换汇率确定(OBC8)
本文主要介绍在S4 HANA OP中明确明确税金本币和外币之间转换汇率确定(OBC8)相关设置。具体请参照如下内容: 明确税金本币和外币之间转换汇率确定(OBC8) 以上配置,我们可以根据不同公司代码所配置的使用不同的汇率来对税金外币和本币之间进行换算。来针对…...
Cocos Creator 3.8 2D 游戏开发知识点整理
目录 Cocos Creator 3.8 2D 游戏开发知识点整理 1. Cocos Creator 3.8 概述 2. 2D 游戏核心组件 (1) 节点(Node)与组件(Component) (2) 渲染组件 (3) UI 组件 3. 动画系统 (1) 传统帧动画 (2) 动画编辑器 (3) Spine 和 …...
梯度提升用于高效的分类与回归
使用 决策树(Decision Tree) 实现 梯度提升(Gradient Boosting) 主要是模拟 GBDT(Gradient Boosting Decision Trees) 的原理,即: 第一棵树拟合原始数据计算残差(负梯度…...
【单细胞第二节:单细胞示例数据分析-GSE218208】
GSE218208 1.创建Seurat对象 #untar(“GSE218208_RAW.tar”) rm(list ls()) a data.table::fread("GSM6736629_10x-PBMC-1_ds0.1974_CountMatrix.tsv.gz",data.table F) a[1:4,1:4] library(tidyverse) a$alias:gene str_split(a$alias:gene,":",si…...
设计模式 - 行为模式_Template Method Pattern模板方法模式在数据处理中的应用
文章目录 概述1. 核心思想2. 结构3. 示例代码4. 优点5. 缺点6. 适用场景7. 案例:模板方法模式在数据处理中的应用案例背景UML搭建抽象基类 - 数据处理的 “总指挥”子类定制 - 适配不同供应商供应商 A 的数据处理器供应商 B 的数据处理器 在业务代码中整合运用 8. 总…...
新春登蛇山:告别岁月,启航未来
大年初一,晨曦透过薄雾,温柔地洒在武汉的大街小巷。2025 年的蛇年春节,带着新春的喜气与希望悄然而至。我站在蛇山脚下,心中涌动着复杂的情感,因为今天,我不仅将与家人一起登山揽胜,更将在这一天…...
hive:基本数据类型,关于表和列语法
基本数据类型 Hive 的数据类型分为基本数据类型和复杂数据类型 加粗的是常用数据类型 BOOLEAN出现ture和false外的其他值会变成NULL值 没有number,decimal类似number 如果输入的数据不符合数据类型, 映射时会变成NULL, 但是数据本身并没有被修改 创建表 创建表的本质其实就是在…...
安装最小化的CentOS7后,执行yum命令报错Could not resolve host mirrorlist.centos.org; 未知的错误
文章目录 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知的错误"错误解决方案: 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知…...
图论——spfa判负环
负环 图 G G G中存在一个回路,该回路边权之和为负数,称之为负环。 spfa求负环 方法1:统计每个点入队次数, 如果某个点入队n次, 说明存在负环。 证明:一个点入队n次,即被更新了n次。一个点每次被更新时所对应最短路的边数一定是…...
TradingAgents-CN 多智能体金融分析系统:企业级容器化部署实战指南
TradingAgents-CN 多智能体金融分析系统:企业级容器化部署实战指南 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN TradingAgents-CN…...
告别混乱!用PyQt5模块化设计打造你的工业上位机(附完整源码与两种传值方式详解)
工业级PyQt5模块化开发实战:从架构设计到数据交互的完整指南 在工业自动化与测控领域,上位机软件往往需要集成数据采集、实时监控、设备控制等复杂功能。传统开发方式容易导致代码臃肿、维护困难——按钮事件与业务逻辑纠缠不清,数据流向如迷…...
仅限前500位开发者获取:20年MCP协议老兵手写《Python服务器模板源码认知地图》PDF+可执行调试镜像
第一章:MCP协议核心原理与Python服务器模板设计哲学MCP(Model Control Protocol)是一种轻量级、面向模型交互的双向通信协议,专为AI代理系统与外部工具服务之间的结构化指令交换而设计。其核心在于以JSON-RPC 2.0为传输语义基础&a…...
掌握罗技鼠标宏的5个技术维度:从原理到实战优化
掌握罗技鼠标宏的5个技术维度:从原理到实战优化 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 一、技术原理解析:机械补…...
Scarab:重构空洞骑士模组管理体验的技术实践
Scarab:重构空洞骑士模组管理体验的技术实践 【免费下载链接】Scarab An installer for Hollow Knight mods written in Avalonia. 项目地址: https://gitcode.com/gh_mirrors/sc/Scarab 问题溯源:模组管理的隐性成本与技术瓶颈 量化手动管理的效…...
CLIP-GmP-ViT-L-14工具实测:如何用图文匹配优化电商搜索与内容审核
CLIP-GmP-ViT-L-14工具实测:如何用图文匹配优化电商搜索与内容审核 1. 图文匹配技术的商业价值 在数字化商业环境中,图片和文字是两种最核心的内容载体。但长期以来,计算机系统很难真正理解两者之间的语义关联。CLIP-GmP-ViT-L-14模型的出现…...
WarcraftHelper:魔兽争霸III游戏性能优化与兼容性解决方案完整指南
WarcraftHelper:魔兽争霸III游戏性能优化与兼容性解决方案完整指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为经典游戏《魔兽争…...
Cohere Transcribe:20亿参数14语言开源语音识别模型发布
Cohere Transcribe:20亿参数14语言开源语音识别模型发布 【免费下载链接】cohere-transcribe-03-2026 项目地址: https://ai.gitcode.com/hf_mirrors/CohereLabs/cohere-transcribe-03-2026 导语:Cohere正式发布开源语音识别模型Cohere Transcri…...
Ku频段相控阵天线避坑指南:从G/T骤降到EIRP波动,这些实测数据你要知道
Ku频段相控阵天线性能衰减实测:60离轴角下的G/T与EIRP工程修正策略 相控阵天线在卫星通信领域正经历从实验室到工程应用的跨越式发展。当无人机以60离轴角追踪卫星时,实测数据显示天线增益可能骤降4.5dB——这个数字足以让精心计算的链路预算彻底失效。在…...
QWEN-AUDIO开箱即用指南:无需conda/pip,纯Docker镜像启动
QWEN-AUDIO开箱即用指南:无需conda/pip,纯Docker镜像启动 想体验一下“有温度”的AI语音合成吗?以前你可能需要折腾Python环境、安装各种依赖、处理版本冲突,光是配置环境就能劝退一大半人。今天,我要分享一个完全不同…...
