Files
X-Agents/account/admin/skills/yuque-skills/SKILL.md
2026-03-11 16:26:22 +08:00

547 lines
13 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: openakita/skills@yuque-skills
description: Manage Yuque (语雀) knowledge bases, documents, and team collaboration through API integration. Supports personal search, weekly reports, knowledge base management, document CRUD, and group collaboration workflows. Based on yuque/yuque-skills.
license: MIT
metadata:
author: openakita
version: "1.0.0"
---
# Yuque Skills — 语雀知识管理
## When to Use
- 用户需要搜索语雀中的文档和知识
- 需要创建、编辑、发布语雀文档
- 需要生成周报/月报并发布到语雀
- 需要管理知识库结构(目录、分类)
- 需要在团队知识库中进行协作
- 需要从语雀导出文档或同步内容
- 需要统计知识库的使用数据
---
## Prerequisites
### 必需配置
| 配置项 | 说明 |
|--------|------|
| `YUQUE_TOKEN` | 语雀 API Token |
| `YUQUE_HOST` | 语雀 API 地址(默认 `https://www.yuque.com/api/v2` |
**获取 Token**
1. 登录语雀 → 点击头像 → 设置 → Token
2. 或访问https://www.yuque.com/settings/tokens
3. 创建新 Token勾选所需权限
`.env` 中配置:
```
YUQUE_TOKEN=your_yuque_token_here
YUQUE_HOST=https://www.yuque.com/api/v2
```
> 企业版语雀的 Host 格式为 `https://your-company.yuque.com/api/v2`
### 必需依赖
| 依赖 | 用途 | 安装方式 |
|------|------|---------|
| `httpx` | HTTP API 调用 | `pip install httpx` |
### 可选依赖
| 依赖 | 用途 | 安装方式 |
|------|------|---------|
| `markdownify` | HTML → Markdown 转换 | `pip install markdownify` |
| `beautifulsoup4` | HTML 解析 | `pip install beautifulsoup4` |
### 验证配置
```bash
curl -s -H "X-Auth-Token: $YUQUE_TOKEN" "https://www.yuque.com/api/v2/user" | python -m json.tool
```
---
## Instructions
### 语雀核心概念
| 概念 | 英文 | 说明 |
|------|------|------|
| 用户 | User | 个人账号 |
| 团队 | Group | 组织/团队空间 |
| 知识库 | Book/Repo | 文档集合,类似文件夹 |
| 文档 | Doc | 具体的内容页面 |
| 目录 | TOC | 知识库内的文档组织结构 |
| 协作者 | Collaborator | 知识库的共同维护者 |
### API 基础调用
所有 API 请求需携带 Token
```python
import httpx
YUQUE_HOST = os.environ.get("YUQUE_HOST", "https://www.yuque.com/api/v2")
YUQUE_TOKEN = os.environ["YUQUE_TOKEN"]
headers = {
"X-Auth-Token": YUQUE_TOKEN,
"Content-Type": "application/json",
"User-Agent": "OpenAkita-Agent/1.0"
}
async def yuque_api(method, path, data=None):
async with httpx.AsyncClient() as client:
url = f"{YUQUE_HOST}{path}"
response = await client.request(method, url, headers=headers, json=data)
response.raise_for_status()
return response.json()["data"]
```
### 权限说明
| 权限 | 可执行操作 |
|------|-----------|
| 只读 | 搜索、查看文档、导出 |
| 读写 | 创建、编辑、删除文档 |
| 管理 | 知识库设置、成员管理 |
---
## Workflows
### Workflow 1: 个人文档搜索
**步骤 1 — 获取用户信息**
```python
user = await yuque_api("GET", "/user")
user_login = user["login"]
print(f"当前用户: {user['name']} ({user_login})")
```
**步骤 2 — 搜索文档**
```python
async def search_docs(query, scope="user"):
"""搜索语雀文档"""
params = {
"q": query,
"type": "doc",
"scope": scope,
}
result = await yuque_api("GET", f"/search?q={query}&type=doc")
return result
```
**步骤 3 — 获取文档内容**
```python
async def get_doc(repo_slug, doc_slug):
"""获取文档详细内容"""
doc = await yuque_api("GET", f"/repos/{repo_slug}/docs/{doc_slug}")
return {
"title": doc["title"],
"body": doc["body"], # Markdown 格式
"body_html": doc["body_html"], # HTML 格式
"word_count": doc["word_count"],
"updated_at": doc["updated_at"],
}
```
**步骤 4 — 返回搜索结果摘要**
---
### Workflow 2: 周报/月报生成
**步骤 1 — 收集周报内容**
向用户询问或从其他来源汇总:
| 模块 | 内容 |
|------|------|
| 本周完成 | 已完成的工作项列表 |
| 进行中 | 正在推进的工作 |
| 下周计划 | 下周的工作安排 |
| 风险与阻塞 | 需要协助的问题 |
| 数据指标 | 关键 KPI 变化 |
**步骤 2 — 生成 Markdown 内容**
```python
def generate_weekly_report(data):
"""生成周报 Markdown"""
report = f"""# 周报 | {data['date_range']}
## ✅ 本周完成
{format_task_list(data['completed'])}
## 🔄 进行中
{format_task_list(data['in_progress'])}
## 📋 下周计划
{format_task_list(data['next_week'])}
## ⚠️ 风险与阻塞
{format_risk_list(data['risks'])}
## 📊 关键指标
{format_metrics_table(data['metrics'])}
"""
return report
```
**步骤 3 — 发布到语雀**
```python
async def publish_report(repo_slug, title, content):
"""发布周报到指定知识库"""
doc_data = {
"title": title,
"slug": generate_slug(title),
"body": content,
"format": "markdown",
"status": 1, # 0=草稿, 1=发布
}
result = await yuque_api("POST", f"/repos/{repo_slug}/docs", data=doc_data)
return result
```
**步骤 4 — 返回文档链接**
---
### Workflow 3: 知识库管理
**列出所有知识库**
```python
async def list_repos(user_login=None, group_login=None):
"""列出知识库"""
if group_login:
repos = await yuque_api("GET", f"/groups/{group_login}/repos")
else:
repos = await yuque_api("GET", f"/users/{user_login}/repos")
return [{
"id": r["id"],
"name": r["name"],
"slug": r["slug"],
"description": r["description"],
"docs_count": r["items_count"],
"namespace": r["namespace"],
"public": r["public"],
"updated_at": r["updated_at"],
} for r in repos]
```
**获取知识库目录**
```python
async def get_toc(repo_namespace):
"""获取知识库的目录结构"""
toc = await yuque_api("GET", f"/repos/{repo_namespace}/toc")
return toc
```
**创建知识库**
```python
async def create_repo(user_or_group_login, name, description="", public=0):
"""创建新知识库"""
data = {
"name": name,
"slug": slugify(name),
"description": description,
"public": public, # 0=私有, 1=公开
"type": "Book",
}
result = await yuque_api("POST", f"/users/{user_or_group_login}/repos", data=data)
return result
```
---
### Workflow 4: 文档 CRUD 操作
**创建文档**
```python
async def create_doc(repo_namespace, title, body, format="markdown"):
data = {
"title": title,
"slug": generate_slug(title),
"body": body,
"format": format,
}
return await yuque_api("POST", f"/repos/{repo_namespace}/docs", data=data)
```
**更新文档**
```python
async def update_doc(repo_namespace, doc_id, title=None, body=None):
data = {}
if title:
data["title"] = title
if body:
data["body"] = body
return await yuque_api("PUT", f"/repos/{repo_namespace}/docs/{doc_id}", data=data)
```
**删除文档**
```python
async def delete_doc(repo_namespace, doc_id):
return await yuque_api("DELETE", f"/repos/{repo_namespace}/docs/{doc_id}")
```
**导出文档**
```python
async def export_doc(repo_namespace, doc_slug, format="markdown"):
"""导出文档为指定格式"""
doc = await get_doc(repo_namespace, doc_slug)
if format == "markdown":
return doc["body"]
elif format == "html":
return doc["body_html"]
elif format == "text":
from bs4 import BeautifulSoup
return BeautifulSoup(doc["body_html"], "html.parser").get_text()
```
---
### Workflow 5: 团队协作
**列出团队**
```python
async def list_groups():
"""列出用户加入的所有团队"""
groups = await yuque_api("GET", "/users/groups")
return [{
"id": g["id"],
"name": g["name"],
"login": g["login"],
"description": g["description"],
"members_count": g["members_count"],
} for g in groups]
```
**团队知识库报告**
```python
async def generate_team_report(group_login):
"""生成团队知识库使用报告"""
repos = await list_repos(group_login=group_login)
report = {
"total_repos": len(repos),
"total_docs": sum(r["docs_count"] for r in repos),
"repos_detail": [],
}
for repo in repos:
docs = await yuque_api("GET", f"/repos/{repo['namespace']}/docs")
recent_docs = sorted(docs, key=lambda d: d["updated_at"], reverse=True)[:5]
report["repos_detail"].append({
"name": repo["name"],
"doc_count": repo["docs_count"],
"recent_updates": [d["title"] for d in recent_docs],
})
return report
```
**知识库协作者管理**
```python
async def add_collaborator(repo_namespace, user_login, role="writer"):
"""添加知识库协作者"""
data = {
"login": user_login,
"role": role, # reader, writer, admin
}
return await yuque_api("POST", f"/repos/{repo_namespace}/collaborators", data=data)
```
---
### Workflow 6: 知识库内容同步
将外部内容同步到语雀,或从语雀同步到本地:
**从 Markdown 文件同步到语雀**
```python
async def sync_markdown_to_yuque(md_dir, repo_namespace):
"""将本地 Markdown 文件目录同步到语雀知识库"""
import glob
md_files = glob.glob(f"{md_dir}/**/*.md", recursive=True)
for md_file in md_files:
with open(md_file, "r", encoding="utf-8") as f:
content = f.read()
title = os.path.splitext(os.path.basename(md_file))[0]
existing = await search_doc_by_title(repo_namespace, title)
if existing:
await update_doc(repo_namespace, existing["id"], body=content)
print(f"更新: {title}")
else:
await create_doc(repo_namespace, title, content)
print(f"创建: {title}")
```
**从语雀导出到本地**
```python
async def export_repo_to_local(repo_namespace, output_dir):
"""将语雀知识库导出为本地 Markdown 文件"""
docs = await yuque_api("GET", f"/repos/{repo_namespace}/docs")
os.makedirs(output_dir, exist_ok=True)
for doc_info in docs:
doc = await get_doc(repo_namespace, doc_info["slug"])
file_path = os.path.join(output_dir, f"{doc_info['slug']}.md")
with open(file_path, "w", encoding="utf-8") as f:
f.write(f"# {doc['title']}\n\n{doc['body']}")
print(f"导出: {doc['title']} -> {file_path}")
```
---
## Output Format
### 搜索结果
```
🔍 搜索 "项目规范" 共找到 5 条结果:
1. 📄 代码规范 v2.0
- 知识库: 工程团队/开发规范
- 更新时间: 2025-02-28
- 链接: https://www.yuque.com/team/repo/doc-slug
2. 📄 项目管理规范
- 知识库: PMO/流程文档
- 更新时间: 2025-02-25
- 链接: https://www.yuque.com/team/repo/doc-slug2
...
```
### 周报输出
生成后返回发布链接和摘要。
### 知识库统计
```
📊 团队知识库统计
- 总知识库数: 12
- 总文档数: 456
- 本月新增: 28 篇
- 最活跃知识库: "产品设计" (本月 12 篇更新)
- 最近更新:
1. API 接口文档 v3 (2 小时前)
2. Q1 OKR 复盘 (昨天)
3. 新员工入职手册 (3 天前)
```
---
## Common Pitfalls
### 1. Token 权限不足
**症状**API 返回 401 或 403
**解决**
- 确认 Token 有读写权限
- 企业版语雀可能需要管理员授权
- 检查 Token 是否过期
### 2. namespace 格式错误
语雀的 namespace 格式为 `{user_or_group_login}/{repo_slug}`,例如 `myteam/dev-docs`
**错误**:使用 repo 名称代替 slug
**正确**:使用 URL 中的 slug
### 3. Markdown 与 HTML 格式混淆
语雀文档有两种内容格式:
- `body`Markdown 格式(创建时使用 `format: "markdown"`
- `body_html`HTML 格式
创建文档时需明确指定 `format` 参数。
### 4. API 频率限制
语雀 API 有请求频率限制:
- 个人版:约 100 次/分钟
- 企业版:通常更高
**解决**:批量操作时添加延迟:
```python
import asyncio
for doc in docs:
await process_doc(doc)
await asyncio.sleep(0.5)
```
### 5. 文档 slug 冲突
同一知识库中 slug 必须唯一。创建文档前先检查是否已存在:
```python
async def safe_create_doc(repo_namespace, title, body):
slug = generate_slug(title)
existing = await find_doc_by_slug(repo_namespace, slug)
if existing:
slug = f"{slug}-{int(time.time())}"
return await create_doc(repo_namespace, title, body, slug=slug)
```
### 6. 企业版与个人版 API 差异
企业版语雀的部分 API 路径和参数可能有差异:
- Host 不同(`your-company.yuque.com`
- 部分接口需要额外权限
- 团队管理接口更丰富
### 7. 大文档性能问题
超过 5 万字的文档在创建/更新时可能超时。建议:
- 拆分为多篇文档
- 使用分页上传
- 图片先上传到 CDN 再引用
---
## EXTEND.md 扩展
用户可在技能同目录下创建 `EXTEND.md` 添加:
- 默认知识库 namespace
- 团队的语雀 Host 地址
- 周报/月报模板定制
- 常用知识库列表和别名
- 自定义文档模板