java使用poi操作world生成饼图,柱状图,折线图,组合图:二
*/
private String sheetName;
/**
- 图表
*/
private XWPFChart xwpfChart;
/**
- 具体图
*/
private List xmlObjectList = new ArrayList<>();
/**
- 绘制区域图
*/
private CTChart ctChart;
/**
- 标题
*/
private List titleList;
/**
- 数据源对应的key
*/
private List numberList;
/**
- 填充的数据源
*/
private List<Map<String, String>> sourceModelList;
/**
- 目标数据
*/
private List chartsEnumList;
/**
-
赋值 替换目标
-
@param numberList
*/
public void setNumberList(List numberList){
this.numberList = numberList;
}
/**
-
赋值 数据源
-
@param sourceModelList
*/
public void setSourceModelList(List<Map<String, String>> sourceModelList){
this.sourceModelList = sourceModelList;
}
/**
-
赋值 标题
-
@param titleList
*/
public void setTitleList(List titleList){
this.titleList = titleList;
}
/**
-
单个赋值 图表
-
@param charts 所有可绘制区域
-
@param chartSeat 要操作的图表中可绘制区域位置
-
@param xmlObjSeat 图表在可绘制区域中的位置
-
@param chartsEnum 目标的表格类型
*/
public void setSingleChart(List charts,int chartSeat,int xmlObjSeat,ChartsEnum chartsEnum){
List chartsEnumList = Arrays.asList(chartsEnum);
/**
- 封装基础数据
*/
this.packageBasic(charts, chartSeat,chartsEnumList);
/**
- 获得目标图表
*/
XmlObject targetChart = chartsEnum.getTargetChart(chartSeat, this.ctChart, xmlObjSeat);
this.xmlObjectList = Arrays.asList(targetChart);
//当前是单元素
this.isSingle = true;
}
/**
-
组合赋值 图表
-
@param charts 所有可绘制区域
-
@param chartSeat 要操作的图表中可绘制区域位置
-
@param xmlObjSeat 图表在可绘制区域中的位置
-
@param chartsEnumList 目标的表格类型
*/
public void setComBiChart(List charts,int chartSeat,int xmlObjSeat,List chartsEnumList){
/**
- 封装基础数据
*/
this.packageBasic(charts, chartSeat,chartsEnumList);
/**
- 获得目标图表
*/
this.xmlObjectList.clear();
chartsEnumList.stream().forEach(x->{
XmlObject targetChart = x.getTargetChart(chartSeat,this.ctChart, xmlObjSeat);
this.xmlObjectList.add(targetChart);
});
//当前不是单元素
this.isSingle = false;
}
/**
-
封装部分基础数据
-
@param charts
-
@param chartSeat
-
@param chartsEnumList
*/
private void packageBasic(List charts, int chartSeat,List chartsEnumList) {
if(CollectionUtils.isEmpty(charts)){
throw new RuntimeException(“模板中图表元素为null; !!!ctChart:null”);
}
if(CollectionUtils.isEmpty(chartsEnumList)){
throw new RuntimeException(“图表目标为null;!!!chartsEnum:null”);
}
/**
- 目标
*/
this.chartsEnumList = chartsEnumList;
/**
- 第N个位置图表
*/
this.xwpfChart = charts.get(chartSeat);
/**
- 第N个位置可绘制区域的图表
*/
this.ctChart = this.xwpfChart.getCTChart();
}
/**
-
执行模板数据源填充
-
@param sheetName 展示数据excel页名字
*/
public void executeFillModel(String sheetName) throws IOException, InvalidFormatException {
this.sheetName = sheetName;
//异常校验
String s = this.isSingle ? this.abnormalCheckSingle() : this.abnormalCheckComBi();
//执行填充数据
ChartsEnum.refreshExcel(this);
for (int i = 0; i < chartsEnumList.size(); i++) {
ChartsEnum chartsEnum = chartsEnumList.get(i);
chartsEnum.fillModel(this,this.getXmlObjectList().get(i),i);
}
}
/**
- 异常校验
*/
private String abnormalCheckSingle() {
if(CollectionUtils.isEmpty(this.numberList)){
throw new RuntimeException(“数据源比对为null; !!!numberList:null”);
}
if(CollectionUtils.isEmpty(this.titleList)){
throw new RuntimeException(“标题为null; !!!titleList:null”);
}
if(CollectionUtils.isEmpty(this.sourceModelList)){
throw new RuntimeException(“数据源为null; !!!sourceModelList:null”);
}
if(Objects.isNull(this.xwpfChart)){
throw new RuntimeException(“模板中图表元素为null; !!!xwpfChart:null”);
}
if(CollectionUtils.isEmpty(this.xmlObjectList)){
throw new RuntimeException(“模板中具体图表为null;!!!xmlObjectList:null”);
}
if(CollectionUtils.isEmpty(this.chartsEnumList)){
throw new RuntimeException(“图表目标为null;!!!chartsEnum:null”);
}
if(Objects.isNull(this.ctChart)){
throw new RuntimeException(“图表绘制区域为null;!!!chartsEnum:null”);
}
if(StringUtils.isEmpty(this.sheetName)){
throw new RuntimeException(“内置excel页名为null;!!!sheetName:null”);
}
return null;
}
/**
- 异常校验
*/
private String abnormalCheckComBi() {
this.abnormalCheckSingle();
if (this.xmlObjectList.size() < 2) {
throw new RuntimeException(“组合图中【图表】元素不足两个; !!!xmlObjectList.size !> 2”);
}
if (this.sourceModelList.stream().filter(x->{return x.keySet().size() >= 3;}).collect(Collectors.toList()).size() < 0) {
throw new RuntimeException(“组合图中【数据源】元素不足两个; !!!sourceModelList.map.keySet.size !>= 3”);
}
if (this.numberList.size() < 3) {
throw new RuntimeException(“组合图中【数据源对应的key】元素不足两个; !!!numberList.size !>= 3”);
}
return null;
}
}
package com.wyz.world.utils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.values.XmlComplexContentImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTBarChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTLineChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTPieChartImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.impl.CTScatterChartImpl;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
-
@author BM_hyjw
-
解析world 中图表
*/
@Slf4j
@Getter
public enum ChartsEnum {
/**
- 饼图
*/
PIE(CTPieChart.class, CTPieChartImpl.class){
/**
-
填充模板数据
-
@param chartModel 图表和数据源
-
@param xmlObject 当前元素
-
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTPieChart pieChart = (CTPieChart)xmlObject;
List serList = pieChart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTPieSer ser = pieChart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
-
得到目标位置的图表
-
@param ctChart 可绘制区域图表
-
@param xmlObjSeat 目标图标位置位置
-
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTPieChart pieChart = ctChart.getPlotArea().getPieChartArray(xmlObjSeat);
return pieChart;
}catch (Exception e){
throw new RuntimeException(“当前位置【” + chartSeat + “】不存在【饼图】!!!”);
}
}
},
/**
- 柱图
*/
COLUMN(CTBarChart.class, CTBarChartImpl.class) {
/**
-
填充模板数据
-
@param chartModel 图表和数据源
-
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTBarChart chart = (CTBarChart)xmlObject;
List serList = chart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTBarSer ser = chart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
-
得到目标位置的图表
-
@param ctChart 可绘制区域图表
-
@param xmlObjSeat 目标图标位置位置
-
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTBarChart barChart = ctChart.getPlotArea().getBarChartArray(xmlObjSeat);
return barChart;
}catch (Exception e){
throw new RuntimeException(“当前位置【” + chartSeat + “】不存在【柱状图】!!!”);
}
}
},
/**
- 折线图
*/
LINE_CHART(CTLineChart.class, CTLineChartImpl.class){
/**
-
填充模板数据
-
@param chartModel 图表和数据源
-
@param xmlObject 当前元素
-
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTLineChart chart = (CTLineChart)xmlObject;
List serList = chart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTLineSer ser = chart.getSerArray(i);
CTAxDataSource cat = ser.getCat();
CTNumDataSource val = ser.getVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
-
得到目标位置的图表
-
@param ctChart 可绘制区域图表
-
@param xmlObjSeat 目标图标位置位置
-
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTLineChart lineChart = ctChart.getPlotArea().getLineChartArray(xmlObjSeat);
return lineChart;
}catch (Exception e){
throw new RuntimeException(“当前位置【” + chartSeat + “】不存在【折线图】!!!”);
}
}
},
/**
- 散点图
*/
SCATTER(CTScatterChart.class, CTScatterChartImpl.class){
/**
-
填充模板数据
-
@param chartModel 图表和数据源
-
@param xmlObject 当前元素
-
@param bias 偏向值
*/
@Override
public void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias) {
if (!this.chartImplClazz.getName().equals(xmlObject.getClass().getName())) {
//当前循环中图表操作不属于当前枚举
ChartsEnum.getEnumByChartImplClazz(((XmlComplexContentImpl)xmlObject).getClass())
.fillModel(chartModel, xmlObject, bias);
return;
}
CTScatterChart chart = (CTScatterChart)xmlObject;
List serList = chart.getSerList();
//更新数据区域
for (int i = 0; i < serList.size(); i++) {
//数据填充
//
CTScatterSer ser = chart.getSerArray(i);
CTAxDataSource cat = ser.getXVal();
CTNumDataSource val = ser.getYVal();
this.dataAnalysisFill(chartModel,i,bias,cat,val);
}
}
/**
-
得到目标位置的图表
-
@param ctChart 可绘制区域图表
-
@param xmlObjSeat 目标图标位置位置
-
@return
*/
@Override
public XmlObject getTargetChart(int chartSeat, CTChart ctChart, int xmlObjSeat) {
try {
CTScatterChart scatterChart = ctChart.getPlotArea().getScatterChartArray(xmlObjSeat);
return scatterChart;
}catch (Exception e){
throw new RuntimeException(“当前位置【” + chartSeat + “】不存在【散点图】!!!”);
}
}
},
;
/**
- 图表对象
*/
public Class<? extends XmlObject> chartClazz;
/**
- 图表实现对象
*/
public Class<? extends XmlComplexContentImpl> chartImplClazz;
ChartsEnum(Class<? extends XmlObject> chartClazz,
Class<? extends XmlComplexContentImpl> chartImplClazz){
this.chartClazz = chartClazz;
this.chartImplClazz = chartImplClazz;
}
/**
-
填充模板数据
-
@param chartModel 图表和数据源
-
@param xmlObject 当前元素
-
@param bias 偏向值
*/
public abstract void fillModel(ChartModel chartModel,XmlObject xmlObject,int bias);
/**
-
得到目标位置的图表
-
@param chartSeat 位置
-
@param ctChart 可绘制区域图表
-
@param xmlObjSeat 目标图标位置位置
*/
public abstract XmlObject getTargetChart(int chartSeat,CTChart ctChart,int xmlObjSeat);
/**
-
根据值来源得到对应的 图表实现对象
-
@param chartImplClazz 图表实现对象
-
@return
*/
public static ChartsEnum getEnumByChartImplClazz(Class<? extends XmlComplexContentImpl> chartImplClazz){
for (ChartsEnum value : ChartsEnum.values()) {
if (value.getChartImplClazz().equals(chartImplClazz)){
return value;
}
}
return null;
}
/**
-
根据值来源得到对应的 图表对象
-
@param chartClazz 图表对象
-
@return
*/
public static ChartsEnum getEnumByChartClazz(Class<? extends XmlObject> chartClazz){
for (ChartsEnum value : ChartsEnum.values()) {
if (value.getChartClazz().equals(chartClazz)){
return value;
}
}
return null;
}
/**
-
刷新内置excel数据
-
@return
*/
public static boolean refreshExcel(ChartModel chartModel) throws IOException, InvalidFormatException {
List titleList = chartModel.getTitleList();
List numberList = chartModel.getNumberList();
List<Map<String, String>> sourceModelList = chartModel.getSourceModelList();
XWPFChart xwpfChart = chartModel.getXwpfChart();
boolean result = true;
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet(chartModel.getSheetName());
//根据数据创建excel第一行标题行
for (int i = 0; i < titleList.size(); i++) {
if (sheet.getRow(0) == null) {
sheet.createRow(0).createCell(i).setCellValue(titleList.get(i) == null ? “” : titleList.get(i));
} else {
sheet.getRow(0).createCell(i).setCellValue(titleList.get(i) == null ? “” : titleList.get(i));
}
}
//遍历数据行
for (int i = 0; i < sourceModelList.size(); i++) {
Map<String, String> baseFormMap = sourceModelList.get(i);//数据行
//fldNameArr字段属性
for (int j = 0; j < numberList.size(); j++) {
if (sheet.getRow(i + 1) == null) {
if (j == 0) {
try {
sheet.createRow(i + 1)
.createCell(j)
.setCellValue(baseFormMap.get(numberList.get(j)) == null ?
“” : baseFormMap.get(numberList.get(j)));
} catch (Exception e) {
if (baseFormMap.get(numberList.get(j)) == null) {
sheet.createRow(i + 1).createCell(j).setCellValue(“”);
} else {
sheet.createRow(i + 1)
.createCell(j)
.setCellValue(baseFormMap.get(numberList.get(j)));
}
}
}
} else {
BigDecimal b = new BigDecimal(baseFormMap.get(numberList.get(j)));
double value = 0D;
if (b != null) {
value = b.doubleValue();
}
if (value == 0D) {
sheet.getRow(i + 1).createCell(j);
} else {
sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue());
}
}
}
}
// 更新嵌入的workbook
List pxdList = xwpfChart.getRelations();
if(pxdList!=null&&pxdList.size()>0) {
for (int i = 0; i < pxdList.size(); i++) {
if (pxdList.get(i).toString().contains(“sheet”)) {
POIXMLDocumentPart xlsPart = xwpfChart.getRelations().get(0);
OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
try {
wb.write(xlsOut);
xlsOut.close();
} catch (IOException e) {
e.printStackTrace();
result = false;
} finally {
if (wb != null) {
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
result = false;
}
}
}
}
}
}
return result;
}
/**
-
数据分析
-
@param chartModel
-
@param i
-
@param bias
-
@param cat
-
@param val
*/
public void dataAnalysisFill (ChartModel chartModel,
int i,
int bias,
CTAxDataSource cat,
CTNumDataSource val) {
//数据源
List<Map<String, String>> sourceModelList = chartModel.getSourceModelList();
//数据源key
List numberList = chartModel.getNumberList();
//
CTStrData strData = cat.getStrRef().getStrCache();
CTNumData numData = val.getNumRef().getNumCache();
long idx = 0;
for (int j = 0; j < sourceModelList.size(); j++) {
//判断获取的值是否为空
String value = “0”;
if (new BigDecimal(sourceModelList.get(j).get(numberList.get(i + 1))) != null) {
value = new BigDecimal(sourceModelList.get(j).get(numberList.get(i + 1))).toString();
}
if (!“0”.equals(value)) {
CTNumVal numVal = numData.addNewPt();//序列值
numVal.setIdx(idx);
numVal.setV(value);
}
CTStrVal sVal = strData.addNewPt();//序列名称
sVal.setIdx(idx);
sVal.setV(sourceModelList.get(j).get(numberList.get(0)));
idx++;
}
numData.getPtCount().setVal(idx);
strData.getPtCount().setVal(idx);
//赋值横坐标数据区域
String axisDataRange = new
CellRangeAddress(1, sourceModelList.size(), 0, 0)
.formatAsString(chartModel.getSheetName(), false);
cat.getStrRef().setF(axisDataRange);
//赋值纵坐标数据区域
String numDataRange = new
CellRangeAddress(1, sourceModelList.size(), i + 1 + bias, i + 1 + bias)
.formatAsString(chartModel.getSheetName(), false);
val.getNumRef().setF(numDataRange);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。


既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:

redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?

Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展

高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展

jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:
[外链图片转存中…(img-m7bKGDE5-1713289562659)]
redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?
[外链图片转存中…(img-MCE4qk2a-1713289562659)]
Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展
[外链图片转存中…(img-u2LGyEeM-1713289562660)]
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
[外链图片转存中…(img-mSsxBxKP-1713289562660)]
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
[外链图片转存中…(img-Mr2uZDPh-1713289562660)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)