585 lines
27 KiB
Python
585 lines
27 KiB
Python
from pptx import Presentation
|
||
from pptx.util import Inches, Pt, Cm
|
||
from pptx.dml.color import RGBColor
|
||
from pptx.enum.text import PP_ALIGN
|
||
from pptx.enum.text import MSO_ANCHOR # 导入正确的垂直对齐枚举
|
||
from pptx.enum.shapes import MSO_SHAPE
|
||
from pptx.chart.data import ChartData
|
||
from pptx.enum.chart import XL_CHART_TYPE,XL_LABEL_POSITION,XL_LEGEND_POSITION
|
||
from pptx.table import Table
|
||
|
||
|
||
from parse_html import parse_html_to_ppt
|
||
from init import gcfg
|
||
|
||
def apply_gradient_background(slide):
|
||
"""应用统一的渐变背景"""
|
||
background = slide.background
|
||
fill = background.fill
|
||
fill.gradient()
|
||
fill.gradient_stops[0].color.rgb = RGBColor(0, 32, 96) # 深蓝
|
||
fill.gradient_stops[1].color.rgb = RGBColor(0, 112, 192) # 蓝色
|
||
|
||
def create_content_slide(prs, title_text, subtitle_text=None, content_items=None):
|
||
"""创建带二级标题的内容页"""
|
||
slide_layout = prs.slide_layouts[6] # 空白布局
|
||
slide = prs.slides.add_slide(slide_layout)
|
||
apply_gradient_background(slide)
|
||
|
||
# 添加主标题
|
||
left = Cm(1.5)
|
||
top = Cm(1.5)
|
||
width = Cm(30)
|
||
height = Cm(2)
|
||
title_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = title_box.text_frame
|
||
tf.word_wrap = True
|
||
tf.clear()
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = title_text
|
||
p.font.size = Pt(36)
|
||
p.font.color.rgb = RGBColor(255, 255, 255)
|
||
p.font.bold = True
|
||
|
||
# 添加二级标题(如果有)
|
||
if subtitle_text:
|
||
left = Cm(1.5)
|
||
top = Cm(3)
|
||
width = Cm(30)
|
||
height = Cm(1.5)
|
||
subtitle_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = subtitle_box.text_frame
|
||
tf.word_wrap = True
|
||
tf.clear()
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = subtitle_text
|
||
p.font.size = Pt(24)
|
||
p.font.color.rgb = RGBColor(200, 230, 255) # 浅蓝色
|
||
p.font.italic = True
|
||
|
||
# 添加内容区域,多级列表
|
||
if content_items:
|
||
# 添加内容文字
|
||
left_text = Cm(2)
|
||
top_text = Cm(5.5 if subtitle_text else 4.5)
|
||
width_text = Cm(36)
|
||
height_text = Cm(8)
|
||
text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text)
|
||
tf = text_box.text_frame
|
||
|
||
# 启用自动换行
|
||
tf.word_wrap = True
|
||
tf.clear()
|
||
|
||
for item in content_items:
|
||
p = tf.add_paragraph()
|
||
p.text = item["text"]
|
||
|
||
p.font.size = Pt(item.get("size", 18))
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.space_after = Pt(item.get("space_after", 8))
|
||
p.level = item.get("level", 0)
|
||
if item.get("bold", False):
|
||
p.font.bold = True
|
||
if item.get("bullet", False):
|
||
p.text = "• " + p.text
|
||
|
||
return slide
|
||
|
||
def create_table_slide(prs, title_text, subtitle_text, headers, data,content):
|
||
"""创建带表格的数据页"""
|
||
slide = create_content_slide(prs, title_text, subtitle_text,content)
|
||
|
||
# 计算表格位置和大小
|
||
left = Cm(2)
|
||
top = Cm(8 if content else 7) #有内容则朝下一些
|
||
width = Cm(26.5)
|
||
|
||
height = Cm(12 if len(data) >10 else 8) #表格数据比较多
|
||
|
||
# 创建表格 (行数=数据行数+1,列数=标题数)
|
||
rows = len(data) + 1
|
||
cols = len(headers)
|
||
table = slide.shapes.add_table(rows, cols, left, top, width, height).table
|
||
|
||
# 设置表格样式
|
||
table.first_row = True # 强调第一行
|
||
table.horz_banding = True # 横向条纹
|
||
|
||
# 设置表头
|
||
for col_idx, header in enumerate(headers):
|
||
cell = table.cell(0, col_idx)
|
||
cell.text = header
|
||
cell.fill.solid()
|
||
cell.fill.fore_color.rgb = RGBColor(0, 64, 128) # 深蓝色表头
|
||
cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(255, 255, 255)
|
||
cell.text_frame.paragraphs[0].font.bold = True
|
||
cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
|
||
|
||
# 填充表格数据
|
||
for row_idx, row_data in enumerate(data, start=1):
|
||
for col_idx, cell_data in enumerate(row_data):
|
||
cell = table.cell(row_idx, col_idx)
|
||
cell.text = str(cell_data)
|
||
cell.fill.solid()
|
||
cell.fill.fore_color.rgb = RGBColor(255, 255, 255)
|
||
cell.fill.fore_color.alpha = 0.2 # 半透明白色
|
||
cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0) # 黑色文字
|
||
cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
|
||
|
||
# #边框线(赞不支持)
|
||
# for border_side in ["top", "bottom", "left", "right"]:
|
||
# border = getattr(cell, f"{border_side}_border")
|
||
# border.fill.background() # 清除任何填充色,确保只应用线条样式
|
||
# border.color.rgb = RGBColor(0, 64, 128)
|
||
# border.size = Cm(0.1)
|
||
|
||
# 设置表格边框
|
||
for cell in table.iter_cells():
|
||
cell.margin_left = Cm(0.1)
|
||
cell.margin_right = Cm(0.1)
|
||
cell.margin_top = Cm(0.05)
|
||
cell.margin_bottom = Cm(0.05)
|
||
cell.vertical_anchor = MSO_ANCHOR.MIDDLE
|
||
|
||
return slide
|
||
|
||
|
||
def create_chart_slide(prs, title_text, subtitle_text, chart_type, data):
|
||
"""创建图表的数据页"""
|
||
slide = create_content_slide(prs, title_text, subtitle_text)
|
||
|
||
#半透明白色背景
|
||
left_content = Cm(2)
|
||
top_content = Cm(7 if subtitle_text else 6) # 根据是否有二级标题调整位置
|
||
width_content = Cm(28.5)
|
||
height_content = Cm(15 if len(data) >10 else 12 )
|
||
content_box = slide.shapes.add_shape(
|
||
MSO_SHAPE.RECTANGLE, left_content, top_content, width_content, height_content
|
||
)
|
||
content_box.fill.solid()
|
||
content_box.fill.fore_color.rgb = RGBColor(255, 255, 255)
|
||
content_box.fill.fore_color.alpha = 0.2 # 20%透明度
|
||
content_box.line.color.rgb = RGBColor(200, 230, 255)
|
||
|
||
# 和前端颜色一致
|
||
colors = [
|
||
"#FF6384", # 对应 rgba(255,99,132,1)
|
||
"#36A2EB", # 对应 rgba(54, 162, 235, 1)
|
||
"#FFCE56", # 对应 rgba(255, 206, 86, 1)
|
||
"#4BC0C0", # 对应 rgba(75, 192, 192, 1)
|
||
"#9966FF", # 对应 rgba(153, 102, 255, 1)
|
||
"#FF9F40", # 对应 rgba(255, 159, 64, 1)
|
||
"#FF6347", # 新增:对应 rgba(255, 99, 71, 1),番茄红
|
||
"#90EE90", # 新增:对应 rgba(144, 238, 144, 1),淡绿
|
||
"#ADD8E6", # 新增:对应 rgba(173, 216, 230, 1),浅天蓝
|
||
"#FFC0CB" # 新增:对应 rgba(255, 192, 203, 1),浅粉
|
||
]
|
||
|
||
# 添加图表数据
|
||
if data:
|
||
chart_data = ChartData()
|
||
|
||
chart_data.categories = data["categories"]
|
||
del data["categories"]
|
||
for lable, series in data.items():
|
||
chart_data.add_series(lable, series)
|
||
|
||
# 添加图表
|
||
left_chart = Cm(3)
|
||
top_chart = Cm(8)
|
||
width_chart = Cm(25)
|
||
height_chart = Cm(12 if len(data) >10 else 10 )
|
||
|
||
if chart_type=="[chart][bar]":
|
||
xl_chart_type=XL_CHART_TYPE.COLUMN_CLUSTERED
|
||
elif chart_type=="[chart][line]":
|
||
xl_chart_type=XL_CHART_TYPE.LINE
|
||
elif chart_type=="[chart][bar_line]":
|
||
xl_chart_type=XL_CHART_TYPE.BAR_CLUSTERED
|
||
elif chart_type=="[chart][area]":
|
||
xl_chart_type=XL_CHART_TYPE.AREA
|
||
else:
|
||
xl_chart_type=XL_CHART_TYPE.BAR_STACKED
|
||
|
||
chart = slide.shapes.add_chart(
|
||
xl_chart_type,left_chart, top_chart, width_chart, height_chart, chart_data
|
||
)
|
||
|
||
# 设置数据标签
|
||
plot = chart.chart.plots[0]
|
||
plot.has_data_labels = True
|
||
data_labels = plot.data_labels
|
||
data_labels.show_value = True # 显示数值
|
||
data_labels.position = XL_LABEL_POSITION.OUTSIDE_END # 标签位置
|
||
# 设置数据标签的字体大小
|
||
data_labels.font.size = Pt(6) # 假设你想要设置字体大小为12磅
|
||
|
||
# 设置图例
|
||
chart.chart.has_legend = True # 确保图例可见
|
||
chart.chart.legend.position = XL_LEGEND_POSITION.BOTTOM # 设置图例位置为底部
|
||
chart.chart.legend.include_in_layout = False # 不让图例覆盖图表
|
||
|
||
# 设置图表颜色
|
||
if len(chart.chart.series) ==1: #只有一个series
|
||
for idx, point in enumerate(chart.chart.series[0].points):
|
||
if idx < len(colors): # 确保颜色数量足够
|
||
fill = point.format.fill
|
||
fill.solid()
|
||
fill.fore_color.alpha = 0.2 # 20%透明度
|
||
fill.fore_color.rgb = RGBColor.from_string(colors[idx][1:])
|
||
else:
|
||
#设置图表颜色 - 为每个系列分配一种颜色
|
||
for idx, serie in enumerate(chart.chart.series):
|
||
if idx < len(colors): # 确保颜色数量足够
|
||
fill = serie.format.fill
|
||
fill.solid()
|
||
fill.fore_color.rgb = RGBColor.from_string(colors[idx][1:]) # 移除前缀'#'
|
||
|
||
# # 设置图表颜色以匹配主题
|
||
# chart.chart.plots[0].series[0].format.fill.solid()
|
||
# chart.chart.plots[0].series[0].format.fill.fore_color.rgb = RGBColor(100, 180, 255)
|
||
# chart.chart.plots[0].series[1].format.fill.solid()
|
||
# chart.chart.plots[0].series[1].format.fill.fore_color.rgb = RGBColor(200, 230, 255)
|
||
|
||
return slide
|
||
|
||
|
||
|
||
|
||
def create_image_layout_slide(prs, title_text, subtitle_text, images,content_items=None):
|
||
"""创建图片布局页面"""
|
||
slide = create_content_slide(prs, title_text, subtitle_text)
|
||
|
||
# 清除默认内容区域
|
||
for shape in slide.shapes:
|
||
if shape.shape_type == MSO_SHAPE.ROUNDED_RECTANGLE:
|
||
sp = shape._element
|
||
sp.getparent().remove(sp)
|
||
|
||
# 根据图片数量决定布局
|
||
if len(images) == 1:
|
||
# 单张大图布局
|
||
left = Cm(3)
|
||
top = Cm(5 if subtitle_text else 4)+Cm(0.5)
|
||
width = Cm(26)
|
||
height = Cm(15)
|
||
pic = slide.shapes.add_picture(images[0]["path"], left, top, width, height)
|
||
|
||
# 添加图片说明
|
||
if "caption" in images[0]:
|
||
left_cap = Cm(3)
|
||
top_cap = Cm(19 if subtitle_text else 20)
|
||
width_cap = Cm(25)
|
||
height_cap = Cm(1)
|
||
cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap)
|
||
tf = cap.text_frame
|
||
p = tf.add_paragraph()
|
||
if images[0]["caption"]:
|
||
p.text = images[0]["caption"]
|
||
else:
|
||
p.text = "主图"
|
||
p.font.size = Pt(14)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
|
||
# 在图片的右侧添加内容区域,可以多级列表
|
||
if content_items:
|
||
# 添加内容文字
|
||
left_text = Cm(30)
|
||
top_text = Cm(5.5 if subtitle_text else 4.5)
|
||
width_text = Cm(5)
|
||
height_text = Cm(18)
|
||
text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text)
|
||
tf = text_box.text_frame
|
||
|
||
# 启用自动换行
|
||
tf.word_wrap = True
|
||
tf.clear()
|
||
|
||
for item in content_items:
|
||
p = tf.add_paragraph()
|
||
p.text = item["text"]
|
||
p.font.size = Pt(item.get("size", 18))
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.space_after = Pt(item.get("space_after", 8))
|
||
p.level = item.get("level", 0)
|
||
if item.get("bold", False):
|
||
p.font.bold = True
|
||
if item.get("bullet", False):
|
||
p.text = "• " + p.text
|
||
|
||
elif len(images) == 2:
|
||
# 两张图片并排布局,大小一致
|
||
# 第一张图片
|
||
left1 = Cm(2)
|
||
top1 = Cm(5 if subtitle_text else 4)+Cm(0.5)
|
||
width1 = Cm(13)
|
||
height1 = Cm(15)
|
||
pic1 = slide.shapes.add_picture(images[0]["path"], left1, top1, width1, height1)
|
||
|
||
# 第二张图片
|
||
left2 = Cm(16)
|
||
top2 = Cm(5 if subtitle_text else 4)+Cm(0.5)
|
||
width2 = Cm(13)
|
||
height2 = Cm(15)
|
||
pic2 = slide.shapes.add_picture(images[1]["path"], left2, top2, width2, height2)
|
||
|
||
# 添加图片说明
|
||
for i, img in enumerate(images):
|
||
if "caption" in img:
|
||
left_cap = Cm(2 if i == 0 else 19)
|
||
top_cap = Cm(17 if subtitle_text else 16)
|
||
width_cap = Cm(13)
|
||
height_cap = Cm(1)
|
||
cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap)
|
||
tf = cap.text_frame
|
||
p = tf.add_paragraph()
|
||
if img["caption"]:
|
||
p.text = img["caption"]
|
||
else:
|
||
p.text = f"图片{i+1}"
|
||
p.font.size = Pt(12)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
|
||
# 在图片的右侧添加内容区域,可以多级列表
|
||
if content_items:
|
||
# 添加内容文字
|
||
left_text = Cm(30)
|
||
top_text = Cm(5.5 if subtitle_text else 4.5)
|
||
width_text = Cm(5)
|
||
height_text = Cm(18)
|
||
text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text)
|
||
tf = text_box.text_frame
|
||
|
||
# 启用自动换行
|
||
tf.word_wrap = True
|
||
tf.clear()
|
||
|
||
for item in content_items:
|
||
p = tf.add_paragraph()
|
||
p.text = item["text"]
|
||
p.font.size = Pt(item.get("size", 18))
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.space_after = Pt(item.get("space_after", 8))
|
||
p.level = item.get("level", 0)
|
||
if item.get("bold", False):
|
||
p.font.bold = True
|
||
if item.get("bullet", False):
|
||
p.text = "• " + p.text
|
||
|
||
|
||
elif len(images) >= 3:
|
||
# 三张以上图片网格布局
|
||
|
||
|
||
# 第一行,三张
|
||
if len(images)==3:
|
||
img_size = Cm(12)
|
||
else:
|
||
img_size = Cm(8)
|
||
gap = Cm(1)
|
||
for i in range(min(3, len(images))):
|
||
left = Cm(3) + (img_size + gap) * i
|
||
top = Cm(5 if subtitle_text else 4)+Cm(0.5)
|
||
pic = slide.shapes.add_picture(images[i]["path"], left, top, img_size, img_size)
|
||
|
||
if "caption" in images[i]:
|
||
left_cap = left
|
||
top_cap = top + img_size + Cm(0.5)
|
||
width_cap = img_size
|
||
height_cap = Cm(1)
|
||
cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap)
|
||
tf = cap.text_frame
|
||
p = tf.add_paragraph()
|
||
if images[i]["caption"]:
|
||
p.text = images[i]["caption"]
|
||
else:
|
||
p.text = f"图片{i+1}"
|
||
p.font.size = Pt(10)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
|
||
# 第二行(如果有4张以上图片)
|
||
img_size = Cm(4)
|
||
gap = Cm(1)
|
||
for i in range(3, len(images)):
|
||
left = Cm(3) + (img_size + gap) * (i - 3)
|
||
top = Cm(16 if subtitle_text else 15)
|
||
pic = slide.shapes.add_picture(images[i]["path"], left, top, img_size, img_size)
|
||
|
||
if "caption" in images[i] and images[i]["caption"]:
|
||
left_cap = left
|
||
top_cap = top + img_size + Cm(0.5)
|
||
width_cap = img_size
|
||
height_cap = Cm(1)
|
||
cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap)
|
||
tf = cap.text_frame
|
||
p = tf.add_paragraph()
|
||
p.text = images[i]["caption"]
|
||
p.font.size = Pt(10)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
|
||
return slide
|
||
|
||
# ===== 封面幻灯片 =====
|
||
def create_main_slide(prs, title_text, subject_text,content=None):
|
||
# ===== 封面幻灯片 =====
|
||
slide_layout = prs.slide_layouts[6] # 空白布局
|
||
slide = prs.slides.add_slide(slide_layout)
|
||
apply_gradient_background(slide)
|
||
|
||
#添加宽屏主题
|
||
left = Cm(2)
|
||
top = Cm(8)
|
||
width = Cm(36)
|
||
height = Cm(6)
|
||
subtitle_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = subtitle_box.text_frame
|
||
tf.word_wrap = True
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = title_text
|
||
p.font.size = Pt(66)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.LEFT
|
||
|
||
# 添加副标题
|
||
if subject_text:
|
||
left = Cm(1.5)
|
||
top = Cm(1.5)
|
||
width = Cm(36)
|
||
height = Cm(4)
|
||
title_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = title_box.text_frame
|
||
tf.word_wrap = True
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = subject_text
|
||
p.font.size = Pt(36)
|
||
p.font.color.rgb = RGBColor(255, 255, 255)
|
||
p.font.bold = True
|
||
p.alignment = PP_ALIGN.LEFT
|
||
|
||
# 添加其它标题
|
||
if content:
|
||
i=0
|
||
for line in content:
|
||
left = Cm(12)
|
||
top = Cm(12+i)
|
||
width = Cm(16)
|
||
height = Cm(2)
|
||
subtitle_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = subtitle_box.text_frame
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = line["text"]
|
||
p.font.size = Pt(28)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
i+=3
|
||
#end
|
||
|
||
# ===== 结束幻灯片 =====
|
||
def create_end_slide(prs,title,subtitle):
|
||
slide = create_content_slide(
|
||
prs,
|
||
title,
|
||
subtitle
|
||
)
|
||
|
||
img_width = Cm(8)
|
||
img_height = Cm(4)
|
||
print(prs.slide_width,prs.slide_width/Cm(1),prs.slide_width/Cm(1)/2-3)
|
||
left = Cm(prs.slide_width/Cm(1)/2-3) #屏幕中央
|
||
top = Cm(8)
|
||
#添加logo
|
||
if gcfg["fs"]["logo"]!="":
|
||
pic = slide.shapes.add_picture(f'{gcfg["fs"]["path"]}/img/{gcfg["fs"]["logo"]}', left, top, img_width, img_height)
|
||
else:
|
||
pic = slide.shapes.add_picture(f'ui/images/logo2.jpg', left, top, img_width, img_height)
|
||
|
||
# 在内容区域添加slogan和网址
|
||
left = Cm(12)
|
||
top = Cm(12)
|
||
width = Cm(16)
|
||
height = Cm(3)
|
||
contact_box = slide.shapes.add_textbox(left, top, width, height)
|
||
tf = contact_box.text_frame
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = gcfg["fs"]["slogan"]
|
||
p.font.size = Pt(28)
|
||
p.font.color.rgb = RGBColor(255, 255, 255)
|
||
p.font.bold = True
|
||
p.alignment = PP_ALIGN.CENTER
|
||
p.space_after = Pt(16)
|
||
|
||
p = tf.add_paragraph()
|
||
p.text = gcfg["fs"]["url"]
|
||
p.font.size = Pt(18)
|
||
p.font.color.rgb = RGBColor(200, 230, 255)
|
||
p.alignment = PP_ALIGN.CENTER
|
||
p.space_before = Pt(10)
|
||
|
||
|
||
#入口函数,根据html创建ppt
|
||
def create_unified_ppt(html,output_filename):
|
||
# 创建一个16:9宽屏演示文稿对象
|
||
prs = Presentation()
|
||
#prs.slide_width = Inches(13.333) # 16:9的宽度
|
||
#prs.slide_height = Inches(7.5) # 16:9的高度
|
||
|
||
prs.slide_width = Inches(16) # 16:9的宽度
|
||
prs.slide_height = Inches(9) # 16:9的高度
|
||
|
||
ppt = parse_html_to_ppt(html)
|
||
|
||
for slide in ppt:
|
||
if slide["type"]=="main":
|
||
create_main_slide(prs,slide["title"],slide["subtitle"],slide["content"])
|
||
elif slide["type"]=="text":
|
||
create_content_slide(
|
||
prs,slide["title"],slide["subtitle"],slide["content"]
|
||
)
|
||
elif slide["type"]=="image":
|
||
create_image_layout_slide(
|
||
prs,slide["title"],slide["subtitle"],slide["images"],slide["content"]
|
||
)
|
||
elif slide["type"]=="chart":
|
||
create_chart_slide(
|
||
prs,slide["title"],slide["subtitle"],slide["chart_type"],slide["data"]
|
||
)
|
||
elif slide["type"]=="table":
|
||
create_table_slide(
|
||
prs,slide["title"],slide["subtitle"],slide["header"],slide["data"],slide["content"]
|
||
)
|
||
else:
|
||
pass
|
||
|
||
create_end_slide(prs,"感谢聆听","欢迎指正")
|
||
# 保存演示文稿
|
||
prs.save(output_filename)
|
||
|
||
if __name__ == "__main__":
|
||
html_string ="""
|
||
<h1>K3GPT数据分析智能体</h1>
|
||
<h3>三国工资表.xls</h3>
|
||
<h2>问题</h2><h3>按如下分析三国详情:1不同集团的人数,2不同集团不同级别的人数,3不同集团的平均服务年龄,4不同集团工种帝王人数</h3>
|
||
<h2>数据分析</h2><h3>集团分布</h3><p>[chart][bar]</p><pre><code >{\"categories\":[\"魏\",\"吴\",\"无\",\"蜀\"],\"count\":[3,3,3,2]}</code></pre>
|
||
<h3>集团->职级的分布</h3><p>[chart][bar]</p><pre><code >{\"L4\":[10,9,7,1],\"L3\":[8,0,4,1],\"L5\":[6,9,6,3],\"L6\":[4,5,3,2],\"L7\":[3,4,3,2],\"L8\":[2,2,2,0],\"L9\":[1,1,1,0],\"L2\":[0,0,1,0],\"categories\":[\"吴\",\"魏\",\"蜀\",\"无\"]}</code></pre>
|
||
<h3>不同集团对应的司龄(年)的常见六指标分析</h3><p>[chart][bar]</p><pre><code >{\"categories\":[\"蜀\",\"魏\",\"无\",\"吴\"],\"总和\":[397,586,179,560],\"平均值\":[14.703703703703704,19.533333333333335,19.88888888888889,16.470588235294116],\"中位数\":[12,19,20,15],\"最小值\":[5,10,8,5],\"最大值\":[40,35,30,40],\"个数\":[27,30,9,34]}</code></pre>
|
||
<h3>表格1</h3><table style=\"width: auto;\"><tbody><tr><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">序号</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">姓名</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">集团</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工种</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">职级</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工资(万)</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">司龄(年)</th></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">1</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹操</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">30</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">2</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘备</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">3</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙权</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">53</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙策</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">54</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙坚</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">55</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘禅</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">56</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹丕</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">57</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹叡</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">97</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁绍</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">20</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">98</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁术</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">100</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘表</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">4.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr></tbody></table>
|
||
<h2>小结</h2><p>根据分析结果,三国工资表的详细情况如下:</p><ol><li>集团人数分布 吴国:34人 魏国:30人 蜀国:27人 无集团:9人</li><li>集团-职级人数分布 吴国主要职级为L4(10人)、L3(8人)、L5(6人) 魏国最高职级达L9(1人),L5(9人)占比较大 蜀国职级分布较均衡,L4(7人)、L5(6人)为主</li><li>平均服务年龄 魏国平均19.53年(最高) 吴国16.47年 蜀国14.70年(最低) 无集团19.89年(可能包含临时人员)</li><li>帝王工种分布 吴国、魏国、无集团各有3名帝王,蜀国2名 帝王多集中在高级职级(L6-L9)</li></ol><p><strong>分析点评</strong>: </p><ul><li>魏国和无集团的平均服务年龄显著高于其他集团,可能与人员稳定性或招聘策略有关。 </li><li>帝王工种在吴、魏、无集团分布较均,但蜀国仅2人,可能需关注其人才结构。 </li><li>职级分布显示魏国存在较高职级人员,而蜀国职级整体偏低,可能反映组织架构差异。</li></ul>",
|
||
|
||
"""
|
||
|
||
|
||
# 使用前请替换示例图片路径为实际图片路径
|
||
create_unified_ppt(html_string,"test.pptx")
|
||
print("带生成完成!")
|