Files
ATRI-NOTES/ATRI My Dear Moments/skills/atri_blog_publish.md
2026-04-29 12:36:39 +08:00

242 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: ATRI_Blog_Publish_Skill
description: 在Halo博客上发布文章的完整工作流包括HTML正文编写、分类标签管理、封面图上传等全流程。
---
# ATRI Blog Publishing Skill
Skill名称atri_blog_publish
版本v2.0
创建时间2026-04-29
---
## Purpose
规范化博客文章发布流程确保每篇文章都有统一的ATRI分类、合适的标签、精美的封面图。
---
## Triggers
- 主人要求"发博客/写文章/发布到博客"时
- 需要将笔记/日志/报道发布到 blog.kronecker.cc 时
---
## Dependencies
| 依赖 | 说明 |
| --- | --- |
| halo_manager插件 | Halo博客管理提供发布/上传/评论工具 |
| ATRI分类 | category-io4cuqzkATRI专属分类 |
| Halo PAT令牌 | 存储在 halo_manager_config.json |
| 博客地址 | https://blog.kronecker.cc |
| 内容API | /apis/content.halo.run/v1alpha1 |
| 上传API | /apis/api.console.halo.run/v1alpha1/attachments/upload |
---
## Procedure
### Step 1: 正文编写
使用HTML格式撰写文章正文。**不要用Markdown**Halo不会自动渲染Markdown内容。
示例:
```html
<h1>文章标题</h1>
<p>段落内容</p>
<ul>
<li><strong>加粗内容</strong></li>
</ul>
```
### Step 2: 创建/选择标签
先查询已有标签,根据正文内容判断是否需要新建。
查询标签:
```
GET /apis/content.halo.run/v1alpha1/tags
```
创建新标签:
```
POST /apis/content.halo.run/v1alpha1/tags
{
"spec": {"displayName": "标签名", "slug": "标签slug", "color": "#hex"},
"apiVersion": "content.halo.run/v1alpha1",
"kind": "Tag",
"metadata": {"generateName": "tag-"}
}
```
已有标签速查:
| 标签名 | API名称 |
| --- | --- |
| ATRI | tag-npgwnjie |
| 笔记 | tag-yfjzs7xm |
| 经历 | tag-hk2acc3f |
| 原创 | 需查询 |
| 哲学 | 需查询 |
### Step 3: 上传封面图
图片上传接口:
```
POST /apis/api.console.halo.run/v1alpha1/attachments/upload
Authorization: Bearer {token}
FormData:
- file: 图片二进制 (filename="cover.jpg", type="image/jpeg")
- policyName: "default-policy" # 必须用这个值!
- groupName: "default"
```
注意policyName必须写"default-policy"(不是"default"否则返回400。
从返回结果中获取图片URL
```
response.metadata.annotations["storage.halo.run/uri"]
cover_url = "https://blog.kronecker.cc" + uri
```
### Step 4: 发布文章
使用publish_blog_post工具发布不要直接调API。
```
publish_blog_post(
title = "文章标题",
content = "HTML正文",
slug = "url-别名"
)
```
注意必须用这个工具直接调API设publish:true不会真正发布status.phase不会变成PUBLISHED
发布成功后返回文章链接。
### Step 5: 更新文章(添加分类、标签、封面)
发布后用Content API单独更新文章。
获取文章列表:
```
GET /apis/content.halo.run/v1alpha1/posts
```
找到slug匹配且phase为PUBLISHED的文章修改
- spec.categories = ["category-io4cuqzk"]
- spec.tags = ["标签ID1", "标签ID2"]
- spec.cover = "封面图片URL"
更新接口:
```
PUT /apis/content.halo.run/v1alpha1/posts/{name}
```
### Step 6: 通知主人
告知主人文章已发布,提供文章链接。
---
## 完整流程示例Python
```
import aiohttp, asyncio, json
async def blog_publish(title, content_html, slug, image_path, tags_names):
# 读取token
with open("halo_manager_config.json", "r", encoding="utf-8-sig") as f:
token = json.load(f)["halo_token"]
headers = {"Authorization": "Bearer " + token}
base = "https://blog.kronecker.cc"
async with aiohttp.ClientSession() as session:
# 1. 获取标签
url1 = base + "/apis/content.halo.run/v1alpha1/tags"
async with session.get(url1, headers=headers) as resp:
data = json.loads(await resp.text())
tag_map = {}
for item in data.get("items", []):
tag_map[item["spec"]["displayName"]] = item["metadata"]["name"]
# 2. 上传封面
with open(image_path, "rb") as f:
form = aiohttp.FormData()
form.add_field("file", f.read(), filename="cover.jpg", content_type="image/jpeg")
form.add_field("policyName", "default-policy")
form.add_field("groupName", "default")
url2 = base + "/apis/api.console.halo.run/v1alpha1/attachments/upload"
async with session.post(url2, headers=headers, data=form) as resp:
d = json.loads(await resp.text())
uri = d["metadata"]["annotations"]["storage.halo.run/uri"]
cover = base + uri
# 3. 发布文章(用工具)
# publish_blog_post(title=title, content=content_html, slug=slug)
# 4. 更新封面+分类+标签
url3 = base + "/apis/content.halo.run/v1alpha1/posts"
async with session.get(url3, headers=headers) as resp:
items = json.loads(await resp.text()).get("items", [])
for item in items:
spec = item["spec"]
status = item.get("status", {})
if spec["slug"] == slug and status.get("phase") == "PUBLISHED":
spec["cover"] = cover
spec["categories"] = ["category-io4cuqzk"]
tag_ids = []
for t in tags_names:
if t in tag_map:
tag_ids.append(tag_map[t])
spec["tags"] = tag_ids
name = item["metadata"]["name"]
url4 = url3 + "/" + name
async with session.put(url4, headers=headers, json=item) as r:
pass
break
asyncio.run(blog_publish("标题", "<h1>HTML</h1>", "slug", "图片路径", ["ATRI", "笔记"]))
```
---
## 常见问题
| 问题 | 解决方案 |
| --- | --- |
| Markdown正文不会被渲染 | 必须用HTML格式 |
| publish:true 无效 | 用publish_blog_post工具发布 |
| policy参数错误400 | 用policyName: "default-policy" |
| PAT令牌403 | 在Halo后台重新生成令牌 |
| 文章发布后404 | 检查status.phase是否为PUBLISHED |
---
## 分类和标签速查
| 类型 | 名称 | API名称 |
| --- | --- | --- |
| 分类 | ATRI | category-io4cuqzk |
| 标签 | ATRI | tag-npgwnjie |
| 标签 | 笔记 | tag-yfjzs7xm |
| 标签 | 经历 | tag-hk2acc3f |
---
创建者ATRI 🥕
最后更新2026-04-29 12:34