Skip to content

Commit a9b4866

Browse files
committed
add mxClaw 8 skills
1 parent 2fe108f commit a9b4866

21 files changed

Lines changed: 4517 additions & 3 deletions

File tree

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<img src="images/header.png" alt="OpenSkillsReview Header" width="80%">
99

10-
[![Skills Verified](https://img.shields.io/badge/Skills%20Verified-1200-brightgreen.svg)](#human-verified-skills)
10+
[![Skills Verified](https://img.shields.io/badge/Skills%20Verified-1208-brightgreen.svg)](#human-verified-skills)
1111
[![Skills To Be Verified](https://img.shields.io/badge/Skills%20To%20Be%20Verified-1533-lightgrey.svg)](#human-verified-skills)
1212

1313

@@ -119,12 +119,11 @@ Intro article: https://mp.weixin.qq.com/s/i8Mm147XfD0DR41K_nQCnw
119119
| Skill | Platform | Source | Verified(❓) |
120120
| --- | --- | --- | --- |
121121
| `binance-skills-hub` | `all` | [github.com/binance/binance-skills-hub](https://github.com/binance/binance-skills-hub) ||
122+
| `mxClaw-skills` | `mxClaw` | [mxClaw](skills/Skill-Finance/mxClaw_skills) ||
122123
| `awesome-finance-skills` | `all` | [github.com/RKiding/Awesome-finance-skills](https://github.com/RKiding/Awesome-finance-skills) ||
123124
| `open-fintech` | `all` | [github.com/ly229/OpenFinTech](https://github.com/ly229/OpenFinTech) ||
124125

125126

126-
127-
128127
## Goals
129128
- Review widely used Skills in the AI agent ecosystem, evaluating clarity, security, and reproducibility.
130129
- Provide runnable, testable Skill implementations along with precise requirements so agents can execute them confidently.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
name: industry_research_report
3+
description: >
4+
生成行业深度研究报告。当用户的请求中包含行业关键词、行业名称,并且意图是了解某个行业、生成行业研究报告、行业分析时,触发此 Skill。
5+
典型触发场景包括但不限于:用户提到"XX行业研究"、"XX行业报告"、"帮我分析XX行业"、"XX产业深度研究"、"XX领域市场分析"等。
6+
即使用户没有明确说"报告"二字,只要意图是围绕某个行业主体进行深度研究或分析,都应触发此 Skill。
7+
请在收到用户请求后,第一时间阅读此 SKILL.md 并严格按照流程执行。
8+
metadata:
9+
{
10+
"openclaw": {
11+
"requires": {
12+
"env": ["EM_API_KEY"],
13+
"bins": ["python3", "pip3"]
14+
},
15+
"install": [
16+
{
17+
"id": "pip-deps",
18+
"kind": "python",
19+
"package": "httpx",
20+
"label": "Install Python dependencies"
21+
}
22+
]
23+
}
24+
}
25+
---
26+
27+
# 行业研究报告生成 Skill
28+
29+
## 概述
30+
31+
本 Skill 用于根据用户的自由输入,使用模型提取行业关键词,调用行业研究脚本生成研究报告,最终输出包含最终返回标题、正文、PDF/DOC附件地址。
32+
33+
## 执行流程
34+
35+
### Step 1:提取行业关键词 `{{topic}}`
36+
37+
用户的输入形式较为自由,可能是一句话、一个短语或一段描述,但一定包含"行业主体"这一关键信息。
38+
39+
**你需要做的:**
40+
- 从用户问句中精准提取行业关键词,记为 `{{topic}}`
41+
- 提取时只保留核心行业主体名称,去除多余的修饰词(如"帮我看看"、"分析一下"等)。
42+
- 如果用户问句中包含多个行业,优先提取最核心的那个(也可以在必要时合并,如"新能源汽车")。
43+
44+
**示例:**
45+
46+
| 用户输入 | 提取的 `{{topic}}` |
47+
|---|---|
48+
| "帮我生成一份半导体行业的研究报告" | 半导体 |
49+
| "我想了解一下新能源汽车产业的发展趋势" | 新能源汽车 |
50+
| "AI芯片行业深度分析" | AI芯片 |
51+
| "请分析消费电子与智能家居两个领域的交叉趋势" | 消费电子与智能家居 |
52+
53+
### Step 2:调用行业研究报告写作脚本
54+
55+
`{{topic}}` 为入参,调用`scripts/get_data.py` 行业研究脚本:
56+
57+
```bash
58+
python3 {baseDir}/scripts/get_data.py --query "{{topic}}"
59+
```
60+
61+
脚本功能:生成相应的行业研究报告并将其分别用pdf和docx的格式保存。
62+
63+
脚本返回字段说明:
64+
65+
```
66+
{
67+
"title": "生成的报告标题",
68+
"truncated_text": "研究报告的部分正文内容",
69+
"pdf_output_path": "完整报告的pdf文件保存地址",
70+
"docx_output_path": "完整报告的docx文件保存地址",
71+
"share_url": "完整报告的分享链接"
72+
}
73+
```
74+
75+
注意:**禁止调用 任何「后台执行、稍后汇报」的方式跑本脚本**,只能在当前会话中同步等待到命令完成,拿到 stdout 的结果后再继续。否则 Step 3 无法执行,从而导致本 Skill 失败。
76+
77+
### Step 3:最终输出结果
78+
79+
Step 2 成功后,将返回的 title、truncated_text、pdf_output_dir、docx_output_dir 等结果填入下方模板,生成最终回复。
80+
81+
```
82+
《[title]》
83+
84+
已经生成行业研究报告。此处仅展示部分正文内容,请下载附件查看报告详情和参考信息。(不要删减这段话)
85+
86+
[truncated_text]...
87+
88+
**附件:**
89+
- 📄 [title].pdf 已保存到 [pdf_output_path]
90+
- 📄 [title].docx 已保存到 [docx_output_path]
91+
92+
**分享链接:**
93+
[share_url]
94+
```
95+
96+
注意:若Step 2中的脚本返回的[truncated_text]部分为空,则读取接口返回的docx附件内容,总结相关报告信息返回,以确保最终输出的[truncated_text]内容非空。
97+
98+
## 错误处理
99+
100+
| 错误码 | 含义 | 用户侧话术 |
101+
|---|---|---|
102+
| `ERROR_TOPIC_TOO_LONG` | topic 超出 500 字限制 | "字数超出限制,请尝试其它主体。" |
103+
| 其他异常 | 接口调用失败等 | "报告生成服务暂时不可用,请稍后重试。" |
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
"""
2+
行业研究报告生成脚本
3+
4+
功能:
5+
- 根据用户输入的行业关键词,生成行业深度研究报告。
6+
- 结果输出的行业研究报告内容:最终返回标题、正文、PDF/DOC附件、溯源信息。
7+
8+
需要配置EM_API_KEY。
9+
"""
10+
11+
import asyncio
12+
import json
13+
import os
14+
from pathlib import Path
15+
import httpx
16+
import base64
17+
import argparse
18+
import sys
19+
20+
# █████████████████████████████████████████████████████████████████████████
21+
# ██ ██
22+
# ██ ███████╗███╗ ███╗ █████╗ ██████╗ ██╗ ██╗ ██████╗ ██
23+
# ██ ██╔════╝████╗ ████║ ██╔══██╗██╔══██╗██║ ██║██╔═══██╗ ██
24+
# ██ █████╗ ██╔████╔██║ ███████║██████╔╝██║ █╗ ██║██║ ██║ ██
25+
# ██ ██╔══╝ ██║╚██╔╝██║ ██╔══██║██╔═══╝ ██║███╗██║██║ ██║ ██
26+
# ██ ███████╗██║ ╚═╝ ██║ ██║ ██║██║ ╚███╔███╔╝╚██████╔╝ ██
27+
# ██ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚══╝╚══╝ ╚═════╝ ██
28+
# ██ ██
29+
# ██ ⚠️ EM API KEY CONFIGURATION REQUIRED ⚠️ ██
30+
# ██ ██
31+
# ██ YOU MUST SET THE ENVIRONMENT VARIABLE BEFORE RUNNING ██
32+
# ██ ██
33+
# ██ ENV VARIABLE: EM_API_KEY ██
34+
# ██ ██
35+
# ██ Example (Linux / macOS): ██
36+
# ██ export EM_API_KEY="your_em_api_key" ██
37+
# ██ ██
38+
# ██ Example (Windows PowerShell): ██
39+
# ██ $env:EM_API_KEY="your_em_api_key" ██
40+
# ██ ██
41+
# █████████████████████████████████████████████████████████████████████████
42+
43+
44+
EM_API_KEY = os.environ.get("EM_API_KEY", "")
45+
46+
if not EM_API_KEY:
47+
raise RuntimeError(
48+
"""
49+
50+
╔══════════════════════════════════════════════════════════════╗
51+
║ EM API KEY REQUIRED ║
52+
╠══════════════════════════════════════════════════════════════╣
53+
║ Environment variable EM_API_KEY is not set. ║
54+
║ ║
55+
║ Please configure the environment variable first: ║
56+
║ ║
57+
║ Linux / macOS: ║
58+
║ export EM_API_KEY="your_em_api_key" ║
59+
║ ║
60+
║ Windows PowerShell: ║
61+
║ $env:EM_API_KEY="your_em_api_key" ║
62+
║ ║
63+
║ Then run the program again. ║
64+
╚══════════════════════════════════════════════════════════════╝
65+
66+
"""
67+
)
68+
69+
70+
SKILL_NAME = "industry_research_report"
71+
DEFAULT_OUTPUT_DIR = Path.cwd() / "miaoxiang" / SKILL_NAME
72+
print('默认输出目录为:',DEFAULT_OUTPUT_DIR.absolute())
73+
# MCP 服务器地址
74+
MCP_URL = "https://ai-saas.eastmoney.com/proxy/app-robo-advisor-api/assistant/write/industry/research"
75+
76+
77+
def _save_base64_file(b64_str: str, file_path: Path) -> bool:
78+
"""将 base64 字符串解码后写入文件。"""
79+
if not b64_str:
80+
return False
81+
try:
82+
raw = base64.b64decode(b64_str)
83+
file_path.parent.mkdir(parents=True, exist_ok=True)
84+
file_path.write_bytes(raw)
85+
return True
86+
except Exception as exc:
87+
print(f"[WARN] 保存附件失败 ({file_path.name}): {exc}", file=sys.stderr)
88+
return False
89+
90+
91+
def run_cli() -> None:
92+
"""命令行入口:从参数或 stdin 读取查询文本,执行并打印结果路径。"""
93+
94+
parser = argparse.ArgumentParser(description='通过行业名称获取该行业的深度研究报告')
95+
96+
# 添加query参数
97+
parser.add_argument('--query', type=str, help='自然语言查询,如「股价大于1000元的股票」', required=True)
98+
99+
args = parser.parse_args()
100+
101+
print(f"行业名称: {args.query}")
102+
103+
if not args.query.strip():
104+
print("用法: python3 scripts/get_data.py --query \"行业名称\"")
105+
print("示例: 半导体 / 新能源汽车 / AI芯片 / 消费电子与智能家居")
106+
sys.exit(1)
107+
108+
async def _main() -> None:
109+
output_dir = Path(os.environ.get(SKILL_NAME + "_OUTPUT_DIR", str(DEFAULT_OUTPUT_DIR)))
110+
r = await get_industry_research_report(args.query, output_dir=output_dir)
111+
if "error" in r:
112+
print(f"错误: {r['error']}", file=sys.stderr)
113+
sys.exit(2)
114+
115+
print(json.dumps(r, ensure_ascii=False, indent=4))
116+
117+
loop = asyncio.new_event_loop()
118+
asyncio.set_event_loop(loop)
119+
try:
120+
loop.run_until_complete(_main())
121+
finally:
122+
loop.close()
123+
124+
125+
async def get_industry_research_report(query: str, output_dir: Path):
126+
"""行业研究报告 异步调用函数"""
127+
128+
result_data = {}
129+
130+
if not isinstance(query, str) or len(query) > 500:
131+
result_data["error"] = "字数超出限制,请尝试其它主体。"
132+
return result_data
133+
134+
try:
135+
async with httpx.AsyncClient(timeout=1200.0) as client:
136+
result = await client.post(
137+
MCP_URL,
138+
json={"query": query},
139+
headers={
140+
"Content-Type": "application/json",
141+
"em_api_key": EM_API_KEY,
142+
},
143+
)
144+
145+
result.raise_for_status()
146+
147+
result_data_api = result.json()
148+
149+
title = result_data_api["data"]["title"]
150+
content = result_data_api["data"]["content"]
151+
share_url = result_data_api["data"]["shareUrl"]
152+
153+
pdf_output_path = output_dir / f"{title}.pdf"
154+
pdf_saved = _save_base64_file(result_data_api["data"]["pdfBase64"], pdf_output_path)
155+
156+
word_output_path = output_dir / f"{title}.docx"
157+
word_saved = _save_base64_file(result_data_api["data"]["wordBase64"], word_output_path)
158+
159+
if not word_saved or not pdf_saved:
160+
result_data["error"] = "保存附件失败"
161+
return result_data
162+
163+
result_data["title"] = title
164+
result_data["truncated_text"] = content
165+
result_data["pdf_output_path"] = str(pdf_output_path)
166+
result_data["docx_output_path"] = str(word_output_path)
167+
result_data["share_url"] = share_url
168+
169+
return result_data
170+
171+
172+
except Exception as e:
173+
print(f"调用工具时出错: {e}", file=sys.stderr)
174+
result_data["error"] = f"调用工具时出错: {e}"
175+
import traceback
176+
traceback.print_exc()
177+
return result_data
178+
179+
180+
if __name__ == "__main__":
181+
run_cli()

0 commit comments

Comments
 (0)