公众号双风格发布

SKILL内容创作
内容创作 未标注权限 许可证不明确
安装这个技能

两种写作风格交叉发布到两个公众号。自动化素材抓取、写作、排版、发布全流程。

一句话选型结论

按资料字段整理

公众号双风格发布是内容创作类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类内容创作 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_d8831e99/wechat-dual-style-publisher
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

内容创作
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_d8831e99仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791667922
正文体量18.1 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
写文章与脚本

按主题产出初稿与分镜脚本。

改稿与润色

把草稿改顺、统一语气。

多平台文案改写

同一内容按平台改成长短不同的版本。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在内容创作场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
公众号双风格发布当前 未标注权限 未标注 未标注 未标注 有
AI 视频生成 调用外部服务 GitHub 仓库 431.3 万 Codex、Claude、Cursor 有
视频帧 联网访问 ClawHub 市场 262.1 万 OpenClaw 有
Markdown 转换器 写入文件 ClawHub 市场 135.3 万 OpenClaw 有
哔哩哔哩全合一 接触敏感数据 ClawHub 市场 64.1 万 OpenClaw 有
Remotion video toolkit 命令行 浏览器控制 ClawHub 市场 63.9 万 OpenClaw 有

SKILL.md 全文

18.1 KB
模型实际读到的说明书原文,来自技能仓库

微信公众号双风格发布 Skill

功能概述

本 Skill 实现:
1. 两种写作风格:原风格(接地气)+ 卡斯克风格(数字生命卡兹克风格)
2. 两个公众号:西安广源光电(公众号1)+ 西安手机配件报价(公众号2)
3. 交叉发布逻辑:文章风格1 → 公众号2,文章风格2 → 公众号1
4. 素材来源:从 IMA 知识库抓取
5. IP白名单检查:发布前自动检查服务器IP是否已加白名单


使用流程

第一步:确认 IP 白名单

在开始写作前,必须先确认服务器IP已加入公众号后台白名单!

# 检查 IP 白名单(获取 access_token)
def check_ip_whitelist(app_id, app_secret):
    url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={app_id}&secret={app_secret}"
    r = requests.get(url, timeout=10)
    data = r.json()
    if "access_token" in data:
        print(f"✅ IP白名单通过!")
        return data["access_token"]
    else:
        print(f"❌ IP白名单未通过!错误:{data}")
        print(f"   请登录公众号后台,将服务器IP加入白名单")
        print(f"   服务器IP:117.36.8.124")
        return None

⚠️ 如果用户还未添加IP白名单,停止后续操作,提示用户先添加!


第二步:从 IMA 知识库抓取素材

素材来源:IMA 知识库「工作大脑」或「龙虾大脑」

def fetch_material_from_ima(keyword):
    """
    从 IMA 知识库搜索素材
    keyword: 搜索关键词(如"手机配件趋势"、"AI工具")
    """
    # 使用 IMA skill 搜索
    # 具体实现参考 ~/.qclaw/skills/ima/SKILL.md
    # 返回相关笔记内容
    pass

搜索策略:
1. 优先搜索「工作大脑」知识库(行业洞察)
2. 其次搜索「龙虾大脑」知识库(写作技巧)
3. 提取前3篇最相关的笔记作为素材


第三步:生成两种风格的文章

风格1:原风格(接地气、口语化)

特点:
- 面向手机店老板
- 口语化、接地气
- 强调利润、好卖、质量稳
- 标题格式:「西安鑫源光电为您推荐 XXX」

Prompt 模板:

你是一个手机配件批发行业的老炮儿,给手机店老板们写篇干货。

要求:
1. 语气像隔壁老王聊天,别整那些虚的
2. 突出这款产品怎么帮店老板赚钱(利润高、好卖、质量稳)
3. 用短句,别写长句,手机上看着累
4. 加点感情,比如"我跟你讲"、"说实话"、"你信我"
5. 结尾引导:"微信搜索:西安膜世界 或 西安贴膜送彩票"

素材:
{从IMA抓取的素材}

产品信息:
{产品名称、型号、卖点}

风格2:卡斯克风格(数字生命卡兹克风格)

特点(严格遵守 khazix-writer skill):
- ❌ 禁用:冒号、破折号、感叹号
- ✅ 使用:「」替代引号
- 短句分段
- 蓝色强调色(#1a73e8)
- 标题左侧蓝色边框 + 浅蓝背景
- 不带情绪,客观陈述

Prompt 模板:

你是一个理性、客观的行业观察者,用卡斯克的风格写文章。

严格遵守以下排版规范(来自 khazix-writer skill):
1. 不使用冒号、破折号、感叹号
2. 用「」替代所有引号
3. 短句分段,每段不超过3行
4. 标题用 ## 或 ###,不加粗
5. 加粗用 **文字**,表示强调

HTML排版要求:
- 一级标题:蓝色(#1a73e8) + 左侧4px蓝色边框 + 浅蓝背景(#f8f9fa)
- 二级标题:黑色(#333) + 加粗
- 正文:黑色(#333) + 15px + 行高1.8
- 加粗:蓝色(#1a73e8)强调

素材:
{从IMA抓取的素材}

产品信息:
{产品名称、型号、卖点}

第四步:交叉发布到两个公众号

核心逻辑:
- 风格1文章 → 用公众号2的凭证上传
- 风格2文章 → 用公众号1的凭证上传

# 公众号凭证配置
ACCOUNTS = {
    "公众号1": {
        "name": "西安广源光电",
        "app_id": "wx63d9199fe9053f19",
        "app_secret": "0138f21ddc3bbee57370c694c28b6540",
        "upload_target": "风格2文章"  # 风格2的文章上传到这里
    },
    "公众号2": {
        "name": "西安手机配件报价",
        "app_id": "wxdfba84c57701414f",
        "app_secret": "cb311d40f1d06e221b343a2f58d904a0",
        "upload_target": "风格1文章"  # 风格1的文章上传到这里
    }
}

发布函数:

def upload_article(token, article, thumb_media_id, account_name):
    """
    上传文章到草稿箱
    token: access_token
    article: 文章数据(title, author, digest, content)
    thumb_media_id: 封面图 media_id
    account_name: 目标公众号名称(用于日志)
    """
    # 构造草稿
    draft = {
        "articles": [{
            "title": article["title"],
            "author": article["author"],
            "digest": article["digest"],
            "content": article["content"],
            "content_source_url": "",
            "thumb_media_id": thumb_media_id,
            "need_open_comment": 0,
            "only_fans_can_comment": 0
        }]
    }

    # 🔥 关键:显式指定 UTF-8 编码(避免乱码)
    url = f"https://api.weixin.qq.com/cgi-bin/draft/add?access_token={token}"
    headers = {'Content-Type': 'application/json; charset=utf-8'}
    json_data = json.dumps(draft, ensure_ascii=False).encode('utf-8')
    r = requests.post(url, data=json_data, headers=headers, timeout=30)

    data = r.json()
    if data.get("media_id"):
        print(f"✅ 上传成功!目标:{account_name}")
        print(f"   media_id: {data['media_id']}")
        return True
    else:
        print(f"❌ 上传失败!错误:{data}")
        return False

完整工作流代码框架

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
微信公众号双风格发布 Skill
- 两种写作风格(原风格 + 卡斯克风格)
- 两个公众号(西安广源光电 + 西安手机配件报价)
- 交叉发布(风格1→公众号2,风格2→公众号1)
"""

import requests
import json
import re
from PIL import Image, ImageDraw, ImageFont
import io

# ========== 配置区 ==========
ACCOUNTS = {
    "公众号1": {
        "name": "西安广源光电",
        "app_id": "wx63d9199fe9053f19",
        "app_secret": "0138f21ddc3bbee57370c694c28b6540",
        "upload_target": "风格2"  # 风格2的文章上传到这里
    },
    "公众号2": {
        "name": "西安手机配件报价",
        "app_id": "wxdfba84c57701414f",
        "app_secret": "cb311d40f1d06e221b343a2f58d904a0",
        "upload_target": "风格1"  # 风格1的文章上传到这里
    }
}

SERVER_IP = "117.36.8.124"
# ========== 配置区结束 ==========


def check_ip_whitelist():
    """检查 IP 白名单(两个公众号都检查)"""
    print("🔍 检查 IP 白名单...")
    for account_name, config in ACCOUNTS.items():
        print(f"\n检查 {account_name} ({config['name']})...")
        token = get_token(config["app_id"], config["app_secret"])
        if not token:
            print(f"❌ {account_name} IP白名单未通过!")
            print(f"   请登录 https://mp.weixin.qq.com")
            print(f"   进入 设置与开发 → 基本配置 → IP白名单")
            print(f"   添加IP:{SERVER_IP}")
            return False
        else:
            print(f"✅ {account_name} IP白名单通过!")
    return True


def get_token(app_id, app_secret):
    """获取 access_token"""
    url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={app_id}&secret={app_secret}"
    r = requests.get(url, timeout=10)
    data = r.json()
    if "access_token" in data:
        return data["access_token"]
    else:
        return None


def fetch_material_from_ima(keyword):
    """从 IMA 知识库抓取素材"""
    # TODO: 调用 IMA skill 搜索
    # 参考 ~/.qclaw/skills/ima/SKILL.md
    print(f"📚 从 IMA 知识库搜索素材:{keyword}")
    # 模拟返回素材
    return [
        "素材1:手机配件行业趋势...",
        "素材2:AI工具使用方法...",
        "素材3:门店经营技巧..."
    ]


def generate_article_style1(keyword, materials):
    """生成风格1文章(原风格)"""
    print(f"✍️ 生成风格1文章(原风格):{keyword}")
    # TODO: 调用 LLM 生成
    # Prompt 模板见上文
    content = f"这是风格1文章(原风格)的内容...\n\n素材:{materials[0]}"
    return content


def generate_article_style2(keyword, materials):
    """生成风格2文章(卡斯克风格)"""
    print(f"✍️ 生成风格2文章(卡斯克风格):{keyword}")
    # TODO: 调用 LLM 生成
    # Prompt 模板见上文
    content = f"这是风格2文章(卡斯克风格)的内容...\n\n素材:{materials[0]}"
    return content


def md_to_html_style1(md_content):
    """Markdown 转 HTML(风格1:原风格)"""
    # 简化版,只用基础标签
    lines = md_content.split('\n')
    html_parts = []
    current_paragraph = []

    def flush_paragraph():
        if current_paragraph:
            text = ' '.join(current_paragraph)
            text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text)
            html_parts.append(f'<p style="margin:10px 0;line-height:1.8;color:#333;font-size:15px;">{text}</p>')
            current_paragraph.clear()

    for line in lines:
        line = line.rstrip()
        if not line:
            flush_paragraph()
            continue
        if line.startswith('# '):
            flush_paragraph()
            html_parts.append(f'<h2 style="color:#1a73e8;font-size:20px;margin:20px 0 10px;">{line[2:]}</h2>')
        elif line.startswith('## '):
            flush_paragraph()
            html_parts.append(f'<h3 style="color:#333;font-size:17px;margin:15px 0 8px;font-weight:bold;">{line[3:]}</h3>')
        elif line.startswith('- '):
            flush_paragraph()
            html_parts.append(f'<p style="margin:5px 0;line-height:1.8;color:#333;font-size:15px;padding-left:20px;">• {line[2:]}</p>')
        else:
            current_paragraph.append(line)

    flush_paragraph()
    html = '\n'.join(html_parts)
    html = f'<section style="padding:15px;background:#fff;">\n{html}\n</section>'
    return html


def md_to_html_style2(md_content):
    """Markdown 转 HTML(风格2:卡斯克风格)"""
    # 卡斯克排版:标题左侧蓝色边框 + 背景色
    lines = md_content.split('\n')
    html_parts = []
    current_paragraph = []

    def flush_paragraph():
        if current_paragraph:
            text = ' '.join(current_paragraph)
            text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text)
            html_parts.append(f'<p style="margin:10px 0;line-height:1.8;color:#333;font-size:15px;">{text}</p>')
            current_paragraph.clear()

    for line in lines:
        line = line.rstrip()
        if not line:
            flush_paragraph()
            continue
        if line.startswith('# '):
            flush_paragraph()
            title = line[2:]
            html_parts.append(f'<h2 style="color:#1a73e8;font-size:20px;margin:20px 0 10px;padding-left:12px;border-left:4px solid #1a73e8;background:#f8f9fa;padding:8px 0 8px 12px;">{title}</h2>')
        elif line.startswith('## '):
            flush_paragraph()
            title = line[3:]
            html_parts.append(f'<h3 style="color:#333;font-size:17px;margin:15px 0 8px;font-weight:bold;">{title}</h3>')
        elif line.startswith('- '):
            flush_paragraph()
            html_parts.append(f'<p style="margin:5px 0;line-height:1.8;color:#333;font-size:15px;padding-left:20px;">• {line[2:]}</p>')
        else:
            current_paragraph.append(line)

    flush_paragraph()
    html = '\n'.join(html_parts)
    html = f'<section style="padding:15px;background:#fff;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,sans-serif;font-size:15px;line-height:1.8;color:#333;">\n{html}\n</section>'
    return html


def create_cover(title, output_path):
    """生成封面图"""
    width, height = 900, 500
    img = Image.new('RGB', (width, height), color='#1a73e8')
    draw = ImageDraw.Draw(img)

    try:
        font_title = ImageFont.truetype("/System/Library/Fonts/STHeiti Medium.ttc", 48)
    except:
        font_title = ImageFont.load_default()

    display_title = title[:10]
    bbox = draw.textbbox((0, 0), text=display_title, font=font_title)
    text_width = bbox[2] - bbox[0]
    x = (width - text_width) // 2
    y = height // 2 - 50
    draw.text((x, y), text=display_title, fill='white', font=font_title)

    img.save(output_path, 'JPEG', quality=95)
    return output_path


def upload_cover(image_path, token):
    """上传封面图"""
    url = f"https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={token}&type=image"
    with open(image_path, 'rb') as f:
        files = {'media': f}
        r = requests.post(url, files=files, timeout=30)
    data = r.json()
    if data.get("media_id"):
        return data["media_id"]
    else:
        return None


def upload_article(token, article, thumb_media_id):
    """上传文章到草稿箱"""
    draft = {
        "articles": [{
            "title": article["title"],
            "author": article["author"],
            "digest": article["digest"],
            "content": article["content"],
            "content_source_url": "",
            "thumb_media_id": thumb_media_id,
            "need_open_comment": 0,
            "only_fans_can_comment": 0
        }]
    }

    # 🔥 关键:显式指定 UTF-8 编码
    url = f"https://api.weixin.qq.com/cgi-bin/draft/add?access_token={token}"
    headers = {'Content-Type': 'application/json; charset=utf-8'}
    json_data = json.dumps(draft, ensure_ascii=False).encode('utf-8')
    r = requests.post(url, data=json_data, headers=headers, timeout=30)

    data = r.json()
    if data.get("media_id"):
        return True, data["media_id"]
    else:
        return False, data


def main():
    """主流程"""
    print("🚀 微信公众号双风格发布 Skill 启动...")

    # 第一步:检查 IP 白名单
    if not check_ip_whitelist():
        print("\n❌ IP白名单未通过,请先添加IP后再运行!")
        return

    # 第二步:从 IMA 抓取素材
    keyword = "手机配件 AI工具"  # TODO: 让用户输入
    materials = fetch_material_from_ima(keyword)

    # 第三步:生成两种风格的文章
    article1_content = generate_article_style1(keyword, materials)
    article2_content = generate_article_style2(keyword, materials)

    # 第四步:转换 HTML
    article1_html = md_to_html_style1(article1_content)
    article2_html = md_to_html_style2(article2_content)

    # 第五步:生成封面图
    cover1_path = "/tmp/cover_style1.jpg"
    cover2_path = "/tmp/cover_style2.jpg"
    create_cover("风格1标题", cover1_path)
    create_cover("风格2标题", cover2_path)

    # 第六步:上传封面图 + 上传文章(交叉发布)
    # 风格1文章 → 公众号2
    token2 = get_token(ACCOUNTS["公众号2"]["app_id"], ACCOUNTS["公众号2"]["app_secret"])
    thumb_media_id1 = upload_cover(cover1_path, token2)
    if thumb_media_id1:
        article1 = {
            "title": "风格1标题",
            "author": "M",
            "digest": "风格1摘要",
            "content": article1_html
        }
        success, media_id = upload_article(token2, article1, thumb_media_id1)
        if success:
            print(f"✅ 风格1文章已上传到 {ACCOUNTS['公众号2']['name']}!")

    # 风格2文章 → 公众号1
    token1 = get_token(ACCOUNTS["公众号1"]["app_id"], ACCOUNTS["公众号1"]["app_secret"])
    thumb_media_id2 = upload_cover(cover2_path, token1)
    if thumb_media_id2:
        article2 = {
            "title": "风格2标题",
            "author": "M",
            "digest": "风格2摘要",
            "content": article2_html
        }
        success, media_id = upload_article(token1, article2, thumb_media_id2)
        if success:
            print(f"✅ 风格2文章已上传到 {ACCOUNTS['公众号1']['name']}!")

    print("\n🎊 全部完成!请到公众号后台查看草稿箱。")


if __name__ == "__main__":
    main()

使用说明

安装

  1. 将本 Skill 放到 ~/.agents/skills/wechat-dual-style-publisher/
  2. 确保已安装依赖:requests, Pillow
  3. 确保已安装 IMA skill(用于抓取素材)

调用方式

# 其他智能体调用本 Skill
from wechat_dual_style_publisher import main

# 运行主流程
main()

注意事项

  1. IP白名单必须先检查,否则无法上传
  2. 标题长度:≤8字节(2-3个中文字符),上传后手动改长标题
  3. 作者字段:只能用1-2个英文字符(如 "M"),不能用中文
  4. 编码问题:必须显式指定 charset=utf-8,否则中文乱码
  5. 素材来源:IMA 知识库,搜索「工作大脑」和「龙虾大脑」

常见问题

Q1:为什么风格1的文章上传到公众号2?

A:这是用户指定的交叉发布逻辑,目的是让两个公众号的内容风格差异化。

Q2:如何修改公众号凭证?

A:修改脚本开头的 ACCOUNTS 配置区。

Q3:如何添加更多写作风格?

A:在 generate_article_* 函数中添加新的风格生成逻辑。

Q4:IP白名单检查失败怎么办?

A:登录公众号后台,进入「设置与开发 → 基本配置 → IP白名单」,添加服务器IP 117.36.8.124。


版本历史

  • v1.0 (2026-06-23): 初始版本,支持双风格交叉发布
  • 风格1:原风格(接地气)
  • 风格2:卡斯克风格
  • 公众号1:西安广源光电
  • 公众号2:西安手机配件报价
  • 素材来源:IMA 知识库

作者:微信公众号文章写作智能体
创建时间:2026-06-23
最后更新:2026-06-23

常见问题

5 问
答案由本站依据条目字段整理
公众号双风格发布怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_d8831e99/wechat-dual-style-publisher。安装方式为未标注。装完刷新技能列表或重开客户端。

公众号双风格发布支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

公众号双风格发布权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

公众号双风格发布收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

公众号双风格发布用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。