129 lines
4.3 KiB
Python
129 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
融资计划书PPT生成工具
|
|
Convert Markdown financing plan to a PowerPoint presentation
|
|
"""
|
|
|
|
import re
|
|
from pptx import Presentation
|
|
from pptx.util import Inches, Pt
|
|
from pptx.enum.text import PP_ALIGN
|
|
from pptx.dml.color import RGBColor
|
|
import os
|
|
|
|
class PptGenerator:
|
|
"""从Markdown生成PPT"""
|
|
|
|
def __init__(self, md_file, output_file='融资计划书.pptx'):
|
|
self.md_file = md_file
|
|
self.output_file = output_file
|
|
self.prs = Presentation()
|
|
self._set_slide_dimensions()
|
|
self.content = self._read_md_file()
|
|
|
|
def _set_slide_dimensions(self):
|
|
"""设置幻灯片尺寸为16:9"""
|
|
self.prs.slide_width = Inches(16)
|
|
self.prs.slide_height = Inches(9)
|
|
|
|
def _read_md_file(self):
|
|
"""读取并解析Markdown文件"""
|
|
with open(self.md_file, 'r', encoding='utf-8') as f:
|
|
return f.read()
|
|
|
|
def _add_title_slide(self, title, subtitle):
|
|
"""添加标题页"""
|
|
slide_layout = self.prs.slide_layouts[0]
|
|
slide = self.prs.slides.add_slide(slide_layout)
|
|
title_shape = slide.shapes.title
|
|
subtitle_shape = slide.placeholders[1]
|
|
title_shape.text = title
|
|
subtitle_shape.text = subtitle
|
|
|
|
# 格式化
|
|
title_shape.text_frame.paragraphs[0].font.bold = True
|
|
title_shape.text_frame.paragraphs[0].font.size = Pt(44)
|
|
subtitle_shape.text_frame.paragraphs[0].font.size = Pt(28)
|
|
|
|
def _add_content_slide(self, title, content_list, chart_path=None):
|
|
"""添加内容页"""
|
|
slide_layout = self.prs.slide_layouts[5] # Title Only
|
|
slide = self.prs.slides.add_slide(slide_layout)
|
|
|
|
# 标题
|
|
title_shape = slide.shapes.title
|
|
title_shape.text = title
|
|
title_shape.text_frame.paragraphs[0].font.size = Pt(36)
|
|
title_shape.text_frame.paragraphs[0].font.bold = True
|
|
|
|
if chart_path and os.path.exists(chart_path):
|
|
# 图文混合布局
|
|
left = Inches(0.5)
|
|
top = Inches(1.5)
|
|
width = Inches(7)
|
|
height = Inches(7)
|
|
txBox = slide.shapes.add_textbox(left, top, width, height)
|
|
tf = txBox.text_frame
|
|
tf.word_wrap = True
|
|
|
|
img_left = Inches(8)
|
|
img_top = Inches(1.75)
|
|
img_width = Inches(7.5)
|
|
slide.shapes.add_picture(chart_path, img_left, img_top, width=img_width)
|
|
else:
|
|
# 纯文本布局
|
|
left = Inches(1)
|
|
top = Inches(1.5)
|
|
width = Inches(14)
|
|
height = Inches(7)
|
|
txBox = slide.shapes.add_textbox(left, top, width, height)
|
|
tf = txBox.text_frame
|
|
tf.word_wrap = True
|
|
|
|
# 添加内容
|
|
for item in content_list:
|
|
p = tf.add_paragraph()
|
|
p.text = item.lstrip('-•* ').strip()
|
|
p.level = 1 if item.strip().startswith(('•', '- ')) else 0
|
|
p.font.size = Pt(20)
|
|
p.alignment = PP_ALIGN.LEFT
|
|
|
|
def generate(self):
|
|
"""生成PPT"""
|
|
print(f"正在生成PPT: {self.output_file}")
|
|
|
|
# 提取主标题和副标题
|
|
main_title = re.search(r'^#\s(.+)', self.content, re.MULTILINE).group(1)
|
|
sub_title = re.search(r'^##\s(.+)', self.content, re.MULTILINE).group(1)
|
|
self._add_title_slide(main_title, sub_title)
|
|
|
|
# 按章节分割
|
|
sections = re.split(r'\n---\n', self.content)
|
|
for section in sections:
|
|
title_match = re.search(r'^##\s(.+)', section, re.MULTILINE)
|
|
if not title_match:
|
|
continue
|
|
|
|
title = title_match.group(1)
|
|
|
|
# 提取内容和图表
|
|
content_list = re.findall(r'^\s*[-•*]\s(.+)', section, re.MULTILINE)
|
|
chart_match = re.search(r'!\[.+?\]\((.+?)\)', section)
|
|
chart_path = chart_match.group(1) if chart_match else None
|
|
|
|
if not content_list and not chart_path:
|
|
continue
|
|
|
|
self._add_content_slide(title, content_list, chart_path)
|
|
|
|
self.prs.save(self.output_file)
|
|
print(f"✅ PPT生成成功: {self.output_file}")
|
|
|
|
def main():
|
|
generator = PptGenerator('rongzi_deepseek.md')
|
|
generator.generate()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|