d63074be71
- 所有自动化脚本、测试文件路径从旧工作区迁移到 /root/openclaw-workspace/projects/yu-zhi-ran/ - 保持项目独立于 OpenClaw 工作区管理 - 后端 run.sh 路径更新
139 lines
4.2 KiB
Python
139 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
将 Markdown 文章转换为 Word 文档,嵌入图片
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
from docx import Document
|
|
from docx.shared import Inches, Pt, RGBColor
|
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
|
|
|
# 路径配置
|
|
MARKDOWN_FILE = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/final-article.md"
|
|
IMAGES_DIR = "/root/openclaw-workspace/projects/yu-zhi-ran/content/publishing/images"
|
|
OUTPUT_DOCX = "/root/openclaw-workspace/projects/yu-zhi-ran/content/published/2026-04-14-上海阳台种菜一年/上海阳台种菜一年_最终版.docx"
|
|
|
|
# 读取 Markdown
|
|
with open(MARKDOWN_FILE, "r", encoding="utf-8") as f:
|
|
lines = f.readlines()
|
|
|
|
doc = Document()
|
|
doc.styles['Normal'].font.name = '微软雅黑'
|
|
doc.styles['Normal'].font.size = Pt(11)
|
|
|
|
# 样式函数
|
|
def add_heading(text, level=1):
|
|
heading = doc.add_heading(text, level=level)
|
|
heading.alignment = WD_ALIGN_PARAGRAPH.LEFT
|
|
return heading
|
|
|
|
def add_paragraph(text, bold=False, italic=False):
|
|
p = doc.add_paragraph()
|
|
run = p.add_run(text)
|
|
run.bold = bold
|
|
run.italic = italic
|
|
return p
|
|
|
|
# 解析 Markdown
|
|
in_code_block = False
|
|
in_table = False
|
|
table_data = []
|
|
|
|
for i, line in enumerate(lines):
|
|
line = line.rstrip('\n')
|
|
|
|
# 代码块跳过
|
|
if line.startswith('```'):
|
|
in_code_block = not in_code_block
|
|
continue
|
|
if in_code_block:
|
|
continue
|
|
|
|
# 标题
|
|
if line.startswith('# '):
|
|
add_heading(line[2:], level=1)
|
|
continue
|
|
if line.startswith('## '):
|
|
add_heading(line[3:], level=2)
|
|
continue
|
|
if line.startswith('### '):
|
|
add_heading(line[4:], level=3)
|
|
continue
|
|
|
|
# 表格处理(简化:将表格转为文本,图片位置用占位)
|
|
if line.startswith('|'):
|
|
in_table = True
|
|
table_data.append(line)
|
|
continue
|
|
if in_table and not line.startswith('|'):
|
|
in_table = False
|
|
# 可以在此转换表格,为简化直接跳过
|
|
continue
|
|
|
|
# 图片:
|
|
img_match = re.match(r'!\[(.*?)\]\((images/.*?)\)', line)
|
|
if img_match:
|
|
alt, path = img_match.groups()
|
|
img_full_path = os.path.join(os.path.dirname(MARKDOWN_FILE), path)
|
|
if os.path.exists(img_full_path):
|
|
try:
|
|
# 插入图片,宽度 6 英寸(约 15cm)
|
|
doc.add_picture(img_full_path, width=Inches(6))
|
|
# 居中
|
|
last_para = doc.paragraphs[-1]
|
|
last_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
# 添加图片说明(可选)
|
|
if alt:
|
|
cap = doc.add_paragraph(alt)
|
|
cap.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
cap.style = 'Caption'
|
|
except Exception as e:
|
|
doc.add_paragraph(f"[图片加载失败: {path}]")
|
|
else:
|
|
doc.add_paragraph(f"[图片缺失: {img_full_path}]")
|
|
continue
|
|
|
|
# 引用
|
|
if line.startswith('> '):
|
|
p = doc.add_paragraph(line[2:])
|
|
p.paragraph_format.left_indent = Inches(0.5)
|
|
p.italic = True
|
|
continue
|
|
|
|
# 列表
|
|
if re.match(r'^[-*] ', line):
|
|
p = doc.add_paragraph(line[2:], style='List Bullet')
|
|
continue
|
|
if re.match(r'^\d+\. ', line):
|
|
p = doc.add_paragraph(line[line.find('.')+2:], style='List Number')
|
|
continue
|
|
|
|
# 分隔线
|
|
if line.strip() == '---':
|
|
doc.add_paragraph('_' * 50)
|
|
continue
|
|
|
|
# 普通段落
|
|
if line.strip():
|
|
# 处理行内加粗、斜体
|
|
p = doc.add_paragraph()
|
|
parts = re.split(r'(\*\*[^*]+\*\*|\*[^*]+\*)', line)
|
|
for part in parts:
|
|
if part.startswith('**') and part.endswith('**'):
|
|
run = p.add_run(part[2:-2])
|
|
run.bold = True
|
|
elif part.startswith('*') and part.endswith('*'):
|
|
run = p.add_run(part[1:-1])
|
|
run.italic = True
|
|
else:
|
|
run = p.add_run(part)
|
|
else:
|
|
doc.add_paragraph() # 空行
|
|
|
|
# 保存文档
|
|
doc.save(OUTPUT_DOCX)
|
|
print(f"✅ Word 文档已生成: {OUTPUT_DOCX}")
|
|
print(f"📄 页数: {len(doc.paragraphs)} 段落")
|
|
print(f"🖼️ 图片路径: {IMAGES_DIR}")
|