#!/usr/bin/env python3
"""律师业务操作指引 - Markdown转PDF"""
import os
import re
import subprocess
from pathlib import Path
BASE_DIR = Path("/root/.openclaw/workspace/知识库/律师业务操作指引")
PDF_DIR = BASE_DIR
def run_cmd(c):
result = subprocess.run(c, shell=True, capture_output=True, text=True)
return result.stdout, result.stderr
def md_to_pdf(input_md, output_pdf, title=""):
"""将markdown文件转换为PDF,使用weasyprint"""
# 先转成HTML
html_file = input_md.with_suffix('.html')
# 读取markdown
with open(input_md, 'r', encoding='utf-8') as f:
content = f.read()
# 提取标题(如果没有传入)
if not title:
match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
if match:
title = match.group(1)
# 简单的markdown解析器
def parse_md(md):
lines = md.split('\n')
result = []
in_ul = False
in_ol = False
in_table = False
table_lines = []
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
# 跳过front matter
if stripped == '---':
i += 1
continue
# 标题
if stripped.startswith('# '):
if in_ul:
result.append('')
in_ul = False
if in_ol:
result.append('')
in_ol = False
if in_table:
result.append('')
in_table = False
level = len(stripped) - len(stripped.lstrip('#'))
tag = f'h{level}'
text = stripped[level+1:]
result.append(f'<{tag}>{text}{tag}>')
# h2-h6
elif stripped.startswith('## '):
if in_ul: result.append(''); in_ul = False
if in_ol: result.append(''); in_ol = False
if in_table: result.append(''); in_table = False
result.append(f'
{stripped[3:]}
')
elif stripped.startswith('### '):
if in_ul: result.append(''); in_ul = False
if in_ol: result.append(''); in_ol = False
if in_table: result.append(''); in_table = False
result.append(f'{stripped[4:]}
')
elif stripped.startswith('#### '):
if in_ul: result.append(''); in_ul = False
if in_ol: result.append(''); in_ol = False
if in_table: result.append(''); in_table = False
result.append(f'{stripped[5:]}
')
# 分隔线
elif stripped in ('---', '***', '___'):
if in_ul: result.append(''); in_ul = False
if in_ol: result.append(''); in_ol = False
if in_table: result.append(''); in_table = False
result.append('
')
# 表格
elif '|' in stripped:
if not in_table:
in_table = True
table_lines = []
if not re.match(r'^[\|\-\s:]+$', stripped):
cells = [c.strip() for c in stripped.split('|')[1:-1]]
table_lines.append(cells)
i += 1
continue
else:
if in_table:
in_table = False
result.append('')
for j, row in enumerate(table_lines):
tag = 'th' if j == 0 else 'td'
cells_html = ''.join(f'<{tag}>{c}{tag}>' for c in row)
result.append(f'{cells_html}
')
result.append('
')
table_lines = []
# 无序列表
if stripped.startswith('- ') or stripped.startswith('* '):
if not in_ul:
result.append('')
in_ul = True
result.append(f'- {stripped[2:]}
')
# 有序列表
elif re.match(r'^\d+\.\s+', stripped):
if not in_ol:
result.append('')
in_ol = True
num_match = re.match(r'^(\d+)\.\s+(.*)', stripped)
result.append(f'- {num_match.group(2)}
')
# 空行
elif stripped == '':
if in_ul:
result.append('
')
in_ul = False
if in_ol:
result.append('')
in_ol = False
result.append('
')
# 段落
else:
if in_ul:
result.append('')
in_ul = False
if in_ol:
result.append('')
in_ol = False
# 处理行内样式
text = stripped
# 粗体 **text**
text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
# 链接 [text](url) -> text
text = re.sub(r'\[(.+?)\]\(.+?\)', r'\1', text)
# 行内代码 `code`
text = re.sub(r'`(.+?)`', r'\1', text)
result.append(f'{text}
')
i += 1
# 关闭打开的标签
if in_ul: result.append('')
if in_ol: result.append('')
if in_table:
result.append('')
for j, row in enumerate(table_lines):
tag = 'th' if j == 0 else 'td'
cells_html = ''.join(f'<{tag}>{c}{tag}>' for c in row)
result.append(f'{cells_html}
')
result.append('
')
return '\n'.join(result)
body_html = parse_md(content)
html = f'''
{title}
{body_html}
'''
with open(html_file, 'w', encoding='utf-8') as f:
f.write(html)
# 转换PDF
cmd_str = f"weasyprint {html_file} {output_pdf} 2>&1"
stdout, stderr = run_cmd(cmd_str)
# 清理临时HTML
try:
html_file.unlink()
except:
pass
if os.path.exists(output_pdf):
size = os.path.getsize(output_pdf)
return True, f"成功 ({size/1024:.1f}KB)"
else:
return False, f"失败: {stderr[:300]}"
# 已收集的指引列表
guides = [
("上海律协_律师从事关税法律业务操作指引_2025", "关税"),
("上海律协_律师代理医疗科技成果转化业务操作指引_2024", "医药健康"),
("上海律协_律师办理公司对外担保业务操作指引_2024", "公司与商事"),
("上海律协_律师签发律师函业务操作指引_2021", "民事"),
]
print("="*60)
print("律师业务操作指引 PDF 生成工具")
print("="*60)
print(f"注意: 需要先有markdown文件才能生成PDF")
print(f"Markdown目录: {BASE_DIR}")
print()
print("当前收集的指引:")
for name, cat in guides:
md_file = BASE_DIR / f"{name}.md"
pdf_file = PDF_DIR / f"{name}.pdf"
exists = "✓" if md_file.exists() else "✗"
print(f" [{exists}] {cat}: {name}")