AI排版+配图一键搞定:自建微信公众号自动化发布工具

项目背景

写公众号文章,最耗时的不是写内容,而是排版。

调整字体大小、配色、间距、配图位置、引用样式……一篇2000字的文章,排版至少花30分钟。

如果用AI生成内容呢?内容快了,排版照样折磨人。

这个项目就是解决这件事:输入Markdown,自动输出排版精美的HTML,附带AI生成的配图,一键复制到公众号后台。

技术选型

  • Python 3.11+:核心语言
  • mistune 2.x:Markdown转HTML
  • OpenAI API(或兼容接口):生成文章配图
  • Pillow:图片合成与文字叠加
  • requests:API调用
  • Jinja2:HTML模板渲染

全部开源库,零依赖成本。

实现步骤

第一步:安装依赖

pip install mistune jinja2 pillow openai requests

第二步:定义排版模板

创建 template.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
  body {
    font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue",
                 "PingFang SC", "Microsoft YaHei", sans-serif;
    max-width: 677px;
    margin: 0 auto;
    padding: 20px;
    color: #333;
    line-height: 1.8;
    font-size: 15px;
  }
  h1 {
    font-size: 22px;
    color: #1a1a1a;
    border-left: 4px solid #07c160;
    padding-left: 12px;
    margin: 30px 0 15px;
  }
  h2 {
    font-size: 18px;
    color: #333;
    background: #f7f7f7;
    padding: 8px 12px;
    border-radius: 4px;
    margin: 25px 0 12px;
  }
  h3 {
    font-size: 16px;
    color: #555;
    margin: 20px 0 10px;
  }
  p { margin: 12px 0; }
  strong { color: #07c160; }
  blockquote {
    border-left: 3px solid #07c160;
    background: #f9f9f9;
    padding: 10px 15px;
    margin: 15px 0;
    color: #666;
    font-style: italic;
  }
  code {
    background: #f0f0f0;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 13px;
    color: #e83e8c;
  }
  pre {
    background: #282c34;
    color: #abb2bf;
    padding: 15px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 13px;
    line-height: 1.6;
  }
  pre code {
    background: none;
    color: inherit;
    padding: 0;
  }
  ul, ol { padding-left: 20px; }
  li { margin: 6px 0; }
  img {
    max-width: 100%;
    border-radius: 8px;
    margin: 15px 0;
  }
  .tag {
    display: inline-block;
    background: #e8f5e9;
    color: #07c160;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: 12px;
    margin-right: 6px;
  }
  hr {
    border: none;
    height: 1px;
    background: linear-gradient(90deg, #07c160, transparent);
    margin: 25px 0;
  }
</style>
</head>
<body>
{{ content }}
<hr>
<p style="font-size:12px;color:#999;">
  原文链接:{{ url }} | 生成于 {{ time }}
</p>
</body>
</html>

第三步:写核心转换脚本

创建 wechat_formatter.py

#!/usr/bin/env python3
"""
微信公众号文章自动排版工具
输入 Markdown → 输出排版好的 HTML
"""
import mistune
import json
import sys
from pathlib import Path
from datetime import datetime

from PIL import Image, ImageDraw, ImageFont
import requests


def markdown_to_html(markdown_text: str) -> str:
    """Markdown 转 HTML,带自定义渲染器"""
    renderer = mistune.HTMLRenderer(escape=False)
    parser = mistune.create_inline_renderer(renderer)
    block_parser = mistune.create_block_parser(
        inline_parser=parser, skip_inline=True
    )
    html = block_parser(markdown_text)
    return html


def generate_cover(title: str, output_path: str = "cover.png"):
    """生成文章封面图"""
    width, height = 900, 383
    img = Image.new("RGB", (width, height), color="#0d1117")
    draw = ImageDraw.Draw(img)

    # 装饰线条
    draw.rectangle([0, 0, width, 4], fill="#07c160")
    draw.rectangle([0, height-4, width, height], fill="#07c160")

    # 大字标题
    try:
        font_large = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 48)
    except:
        font_large = ImageFont.load_default()

    # 小字副标题
    try:
        font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 24)
    except:
        font_small = ImageFont.load_default()

    # 计算文字位置
    bbox = draw.textbbox((0, 0), title, font=font_large)
    text_w = bbox[2] - bbox[0]
    x = (width - text_w) // 2
    y = (height - 120) // 2

    draw.text((x, y), title, fill="white", font=font_large)
    draw.text((x, y + 65), "AI Auto Formatter", fill="#07c160", font=font_small)

    img.save(output_path)
    print(f"封面图已保存: {output_path}")


def ai_generate_image(prompt: str, output_path: str = "ai_image.png"):
    """通过AI API生成配图"""
    # 使用 OpenAI 兼容接口
    api_key = "sk-your-key-here"  # 替换为你的API Key
    api_url = "https://api.openai.com/v1/images/generations"  # 或兼容接口地址

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    payload = {
        "model": "dall-e-3",
        "prompt": prompt,
        "size": "1024x1024",
        "quality": "standard",
        "n": 1
    }

    resp = requests.post(api_url, headers=headers, json=payload)
    if resp.status_code == 200:
        url = resp.json()["data"][0]["url"]
        img_data = requests.get(url).content
        with open(output_path, "wb") as f:
            f.write(img_data)
        print(f"AI配图已保存: {output_path}")
        return output_path
    else:
        print(f"AI配图生成失败: {resp.status_code}")
        return None


def wrap_with_template(html_content: str, article_url: str = "") -> str:
    """用 Jinja2 模板包裹 HTML 内容"""
    template_path = Path("template.html")
    if not template_path.exists():
        return html_content

    with open(template_path, "r", encoding="utf-8") as f:
        template_content = f.read()

    from jinja2 import Template
    tmpl = Template(template_content)
    return tmpl.render(
        content=html_content,
        url=article_url or "navbox.com.cn",
        time=datetime.now().strftime("%Y-%m-%d %H:%M")
    )


def format_wechat(md_source: str, url: str = "") -> str:
    """完整流程:Markdown → 排版HTML"""
    # 1. Markdown 转 HTML
    html = markdown_to_html(md_source)

    # 2. 用模板包裹
    final_html = wrap_with_template(html, url)

    return final_html


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python wechat_formatter.py <input.md> [output.html]")
        print("      python wechat_formatter.py --cover <title>")
        sys.exit(1)

    if sys.argv[1] == "--cover":
        generate_cover(sys.argv[2] if len(sys.argv) > 2 else "文章标题")
        sys.exit(0)

    input_file = sys.argv[1]
    output_file = sys.argv[2] if len(sys.argv) > 2 else "output.html"

    with open(input_file, "r", encoding="utf-8") as f:
        md_text = f.read()

    result = format_wechat(md_text, "navbox.com.cn")

    with open(output_file, "w", encoding="utf-8") as f:
        f.write(result)

    print(f"✅ 排版完成: {output_file}")
    print("📋 打开 output.html 查看效果,复制内容粘贴到公众号后台")

第四步:示例输入

创建 demo.md

# AI排版工具:告别公众号排版噩梦

你是不是也这样?写完文章,花30分钟调整格式。

## 为什么要自动化

手动排版效率太低了。同样的内容,换个主题就要重新配色。

> 好的工具,让重复劳动自动化。

## 核心功能

- Markdown 一键转 HTML
- 微信公众号默认样式
- AI 配图自动生成
- 支持代码高亮

## 使用示例

```bash
python wechat_formatter.py demo.md output.html
python wechat_formatter.py --cover "我的文章标题"

运行后打开 output.html,全选复制,粘贴到公众号编辑器。


这个工具是我用来处理所有公众号文章的。每天省下半小时,一个月就是十几个小时。


### 第五步:运行

```bash
# 排版文章
python wechat_formatter.py demo.md output.html

# 生成封面图
python wechat_formatter.py --cover "AI排版工具:告别公众号排版噩梦"

# 如果配置了API Key,还可以生成AI配图(在模板中扩展img标签支持AI图)
python -c "from wechat_formatter import ai_generate_image; ai_generate_image('tech illustration minimalist green')"

运行效果

输出 output.html 后,浏览器打开:

  • 标题左侧绿色竖线装饰
  • 二级标题灰色背景块
  • 代码块深色背景
  • 引用块绿色左边框
  • 底部自动带上原文链接和时间

公众号后台打开编辑器 → 粘贴内容 → 自动保留所有样式。

封面图 cover.png 直接上传到公众号文章封面位置。

优化方向

  1. API接入优化:支持多模型(DALL-E、Midjourney、Stable Diffusion),增加失败重试
  2. 图片插入:扫描Markdown中的图片占位符,自动替换为AI生成的配图
  3. 模板市场:提供多种配色方案模板(商务蓝、科技黑、清新绿),用户按需切换
  4. 定时发布:对接微信公众号API,实现定时自动群发
  5. 批量模式:读取目录中所有Markdown文件,批量生成HTML
  6. 云部署:搭一个简单Flask页面,上传Markdown直接返回HTML,手机也能用

这个工具最实用的地方在于——写的时候只管写,排交给机器。

你平时写公众号,最头疼的排版问题是啥?

这篇文章对你有帮助吗?