← 返回
未分类 Key

财报下载归集

财报归集下载 —— 根据公司名称或股票代码自动下载上市公司财报PDF, 并自动归档至 ima 知识库指定文件夹。 触发关键词:财报、年报、季报、半年报、上市公司报告
|--- name: financial-report-collector description: | 财报归集下载 —— 根据公司名称或股票代码自动下载上市公司财报PDF, 并自动归档至 ima 知识库指定文件夹。 触发关键词:财报、年报、季报、半年报、上市公司报告 homepage: "" metadata: requires: env: - IMA_CLIENT_ID - IMA_API_KEY skills: - ima-skill security: allowed_domains: - www.cninfo.com.cn - static.cninfo.com.cn - ima.qq.com - '*.myqcloud.com' --- # 财报归集下载 (Financial Report Collector) 根据用户提供的 **公司名称** 或 **股票代码**,自动从巨潮资讯网下载对应上市公司财报 PDF,随后上传至 ima 知识库的指定文件夹。 --- ## ⛔ 核心规则(执行任何操作前必读) 1. **串行执行,不可并行**:整个流程严格按「先下载 → 再归档」的顺序执行。阶段二的任何步骤必须在阶段一**完全成功**之后启动。 2. **出错即停**:任一环节失败,立即终止并向用户报告失败原因,不继续后续步骤。 3. **仅输出一个 SKILL.md**:本文件为唯一配置,不产生任何附属文件(如 api.md、示例 PDF 等)。 4. **依赖 ima-skill**:阶段二的 COS 上传必须使用 ima-skill 内封装的 `ima_api.cjs`、`preflight-check.cjs`、`cos-upload.cjs` 脚本。 5. **凭证来源**:ima API 凭证从 `~/.config/ima/client_id` 和 `~/.config/ima/api_key` 自动读取;也可通过环境变量 `IMA_CLIENT_ID` / `IMA_API_KEY` 传入。 --- ## 触发条件 当用户消息中包含以下关键词之一时触发本技能: - `财报` — 最核心触发词 - `年报` / `年度报告` / `年度财报` - `季报` / `季度报告` / `一季报` / `半年报` / `三季报` - `下载财报` / `下载年报` / `下载季报` - `上市公司报告` **触发后的预设行为**:若用户同时提供了公司名称/股票代码 + 目标 ima 文件夹名称,直接执行完整流程;若信息不完整,分步收集。 --- ## 交互边界 | 缺少项 | 行为 | |--------|------| | 缺少公司名称/股票代码 | 询问:"请提供要下载财报的公司名称或股票代码" | | 缺少报告类型 | 默认下载最新「年度报告」;若用户提及季报/半年报则按需筛选 | | 缺少目标 ima 文件夹 | 上传至 ima 知识库根目录 | | 搜索结果多个匹配 | 列出候选报告让用户选择(展示标题、日期、大小) | | 目标文件夹不存在 | 告知用户文件夹不存在,上传至根目录或让用户先创建 | | ima 凭证未配置 | 引导用户完成凭证配置(见下方凭证检查) | --- ## 凭证检查 在发起任何 API 请求之前检查: ```bash test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key && echo "✅" || echo "⚠️ NO CREDENTIALS" ``` 若未配置,提示用户: 1. 访问 https://ima.qq.com/agent-interface 获取 Client ID 和 API Key 2. 提供后将凭证写入: ```bash mkdir -p ~/.config/ima echo "your_client_id" > ~/.config/ima/client_id echo "your_api_key" > ~/.config/ima/api_key ``` --- ## 完整工作流 ``` ┌─────────────────────────────────────────────────────┐ │ 阶段一:从巨潮资讯下载财报 PDF │ │ Step 1 → Step 2 → Step 3 → Step 4 │ │ 构造查询 发送请求 解析结果 下载PDF │ │ │ │ ✅ 阶段一成功完成(PDF 已落盘) │ │ │ │ │ ▼ │ │ 阶段二:上传 PDF 至 ima 知识库 │ │ Step 5 → Step 6 → Step 7 → Step 8 → Step 9 │ │ 前置检查 获取知识库 定位文件夹 上传COS 添加知识 │ │ │ │ ✅ 全部完成 → 向用户报告结果 + 清理临时文件 │ └─────────────────────────────────────────────────────┘ ``` --- ## 阶段一:从巨潮资讯下载财报 PDF ### Step 1 — 构造查询请求 **请求接口:** ``` POST http://www.cninfo.com.cn/new/hisAnnouncement/query Content-Type: application/x-www-form-urlencoded ``` **核心参数:** | 参数 | 值 | 说明 | |------|-----|------| | `pageNum` | `1` | 页码 | | `pageSize` | `30` | 每页条数 | | `tabName` | `fulltext` | 全文搜索模式 | | `searchkey` | `{公司名/代码} {报告类型关键词}` | 空格分隔多词 | | `seDate` | 可选,如 `2024-01-01~2025-12-31` | 限定公告日期范围 | **报告类型关键词映射:** | 用户表述 | searchkey 追加关键词 | |----------|---------------------| | 年报 / 年度报告 | `年度报告` | | 一季报 / 一季度报告 | `第一季度报告` | | 半年报 / 半年度报告 | `半年度报告` | | 三季报 / 三季度报告 | `第三季度报告` | | 未指定 | `年度报告`(默认) | **示例 — 搜索平安银行 2024 年年度报告:** ```bash curl -s -X POST "http://www.cninfo.com.cn/new/hisAnnouncement/query" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "pageNum=1" \ --data-urlencode "pageSize=30" \ --data-urlencode "tabName=fulltext" \ --data-urlencode "searchkey=平安银行 年度报告" \ --data-urlencode "seDate=2024-01-01~2025-06-01" ``` ### Step 2 — 发送请求 & 解析响应 响应为 JSON 格式,路径 `announcements[]`,每条包含: | 字段 | 说明 | 用法 | |------|------|------| | `secCode` | 股票代码 | 展示给用户 | | `secName` | 公司简称 | 展示给用户 | | `announcementId` | 公告唯一 ID | 构造下载 URL | | `announcementTitle` | 公告标题 | 展示给用户,帮助判断 | | `announcementTime` | Unix 毫秒时间戳 | 展示发布日期 | | `adjunctUrl` | PDF 相对路径 | 拼装下载 URL(核心字段) | | `adjunctSize` | 文件大小(字节) | 展示给用户 | | `adjunctType` | 附件类型 | 应为 `PDF` | 用 `python3` / `node` 解析 JSON,筛选 `adjunctType=PDF` 且标题匹配报告类型的条目。 ### Step 3 — 让用户确认(多条时) 若 `totalAnnouncement > 1`,列出候选报告: ``` 🔍 找到 {N} 份 {公司名} 的财报: 1. 📄 {announcementTitle} — 发布于 {日期},{大小} 2. 📄 {announcementTitle} — 发布于 {日期},{大小} ... 请输入序号选择要下载的报告(输入 "全部" 下载所有) ``` 仅 1 条匹配时,直接进入下载步骤。 ### Step 4 — 下载 PDF **下载 URL 格式:** ``` http://static.cninfo.com.cn/{adjunctUrl} ``` **下载方式:** ```bash # 保存到临时目录,文件名取公告标题 TMP_DIR=$(mktemp -d) PDF_NAME="{公告标题}.pdf" curl -sL -o "$TMP_DIR/$PDF_NAME" "http://static.cninfo.com.cn/{adjunctUrl}" ``` **下载后验证:** ```bash # 检查文件存在且大小 > 0 test -s "$TMP_DIR/$PDF_NAME" && echo "✅ 下载成功: $(ls -lh "$TMP_DIR/$PDF_NAME" | awk '{print $5}')" || echo "❌ 下载失败" ``` 若下载失败:终止流程,向用户报告错误。 --- ## 阶段二:上传 PDF 至 ima 知识库 > ⚠️ **前置条件**:阶段一必须成功完成(PDF 已存在于本地临时目录)。 **环境变量设置(每次调用前):** ```bash export IMA_CLIENT_ID=$(cat ~/.config/ima/client_id) export IMA_API_KEY=$(cat ~/.config/ima/api_key) export IMA_SKILL_VERSION="1.1.7" export SKILL_DIR="/workspace/skills/ima-skill" export IMA_BASE_DIR="$SKILL_DIR" ``` ### Step 5 — Preflight 前置检查 ```bash PREFLIGHT=$(node "$SKILL_DIR/knowledge-base/scripts/preflight-check.cjs" --file "$PDF_FILE") echo "$PREFLIGHT" # 若 pass=false → 终止,将 reason 展示给用户 ``` 提取关键字段: ```bash FILE_NAME=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).file_name)") FILE_SIZE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync(0,'utf8')).file_size))") MEDIA_TYPE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync(0,'utf8')).media_type))") CONTENT_TYPE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).content_type)") FILE_EXT=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).file_ext)") ``` ### Step 6 — 获取知识库 ID **情况 A — 用户指定了知识库名称:** ```bash # 搜索知识库 ima_api "openapi/wiki/v1/search_knowledge_base" '{"query":"{知识库名称}","cursor":"","limit":20}' # 从 info_list 中匹配目标知识库,提取 id ``` **情况 B — 用户未指定知识库:** ```bash # 列出可添加的知识库 ima_api "openapi/wiki/v1/get_addable_knowledge_base_list" '{"cursor":"","limit":20}' # 展示列表让用户选择;仅有 1 个时自动选择 ``` ### Step 7 — 定位目标文件夹 **当用户指定了文件夹名称时:** ```bash # 在知识库中搜索文件夹 ima_api "openapi/wiki/v1/search_knowledge" "{ \"query\": \"{文件夹名称}\", \"knowledge_base_id\": \"{kb_id}\", \"cursor\": \"\" }" ``` - 从 `info_list` 中筛选 `media_id` 以 `folder_` 开头的条目 - 若找到匹配 → 提取 `media_id` 作为 `FOLDER_ID` - 若未找到 → 告知用户文件夹不存在,改为上传至根目录(不传 `folder_id`) **当用户未指定文件夹时:** 跳过此步,上传至知识库根目录(后续步骤中不传 `folder_id`)。 ### Step 8 — 检查重名 + 创建媒体 + COS 上传 **8a. 重名检查:** ```bash ima_api "openapi/wiki/v1/check_repeated_names" "{ \"params\": [{\"name\": \"$FILE_NAME\", \"media_type\": $MEDIA_TYPE}], \"knowledge_base_id\": \"{kb_id}\" ${FOLDER_ID:+, \"folder_id\": \"$FOLDER_ID\"} }" ``` 若 `is_repeated=true` → 在文件名后追加时间戳:`{name}_20250101120000.{ext}` **8b. 创建媒体:** ```bash CREATE_RESP=$(ima_api "openapi/wiki/v1/create_media" "{ \"file_name\": \"$FILE_NAME\", \"file_size\": $FILE_SIZE, \"content_type\": \"$CONTENT_TYPE\", \"knowledge_base_id\": \"{kb_id}\", \"file_ext\": \"$FILE_EXT\" }") # code≠0 → 终止,将 msg 展示给用户 MEDIA_ID=$(echo "$CREATE_RESP" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).data.media_id)") ``` 提取 COS 凭证字段:`secret_id`、`secret_key`、`token`、`bucket_name`、`region`、`cos_key`、`start_time`、`expired_time`。 **8c. COS 上传:** ```bash node "$SKILL_DIR/knowledge-base/scripts/cos-upload.cjs" \ --file "$PDF_FILE" \ --secret-id "{secret_id}" \ --secret-key "{secret_key}" \ --token "{token}" \ --bucket "{bucket_name}" \ --region "{region}" \ --cos-key "{cos_key}" \ --content-type "$CONTENT_TYPE" \ --start-time "{start_time}" \ --expired-time "{expired_time}" \ --timeout 300000 # ⛔ 非零退出 → 立即终止,不要执行 Step 9 ``` ### Step 9 — 添加知识 仅当 Step 8c 成功(退出码 0)后才执行: ```bash ima_api "openapi/wiki/v1/add_knowledge" "{ \"media_type\": $MEDIA_TYPE, \"media_id\": \"$MEDIA_ID\", \"title\": \"$FILE_NAME\", \"knowledge_base_id\": \"{kb_id}\" ${FOLDER_ID:+, \"folder_id\": \"$FOLDER_ID\"} \"file_info\": { \"cos_key\": \"{cos_key}\", \"file_size\": $FILE_SIZE, \"file_name\": \"$FILE_NAME\" } }" ``` --- ## 完成 & 清理 全部步骤成功后: ```bash # 清理临时下载文件 rm -rf "$TMP_DIR" ``` 向用户报告: ``` ✅ 财报归集完成! 📥 下载:{公告标题} 📊 公司:{公司名}({股票代码}) 📅 发布日期:{日期} 📦 大小:{文件大小} 📂 已存入:ima 知识库「{知识库名称}」{文件夹路径} ``` --- ## 错误处理汇总 | 阶段 | 步骤 | 常见错误 | 处理方式 | |------|------|----------|----------| | 阶段一 | Step 2 | 查询返回空结果 | 提示公司名/代码可能不正确,或该时间段无对应报告 | | 阶段一 | Step 4 | PDF 下载失败(404/网络错误) | 重试一次,仍失败则报告用户 | | 阶段二 | Step 5 | 文件类型不被支持 | 将 `reason` 展示给用户后终止 | | 阶段二 | Step 6 | 找不到可用的知识库 | 引导用户先在 ima 客户端创建知识库 | | 阶段二 | Step 7 | 文件夹不存在 | 告知用户后改为上传至根目录 | | 阶段二 | Step 8b | `create_media` 返回 `code≠0` | 将 `msg` 直接展示给用户 | | 阶段二 | Step 8c | COS 上传失败 | 终止流程,展示错误信息 | | 阶段二 | Step 9 | `add_knowledge` 返回 `code≠0` | 将 `msg` 直接展示给用户 | | 全局 | — | 凭证未配置 | 引导用户完成凭证设置 | --- ## ima_api 调用封装 为简化重复调用,阶段二中所有对 ima API 的调用统一通过以下方式: ```bash ima_api() { local api_path="$1" local body="$2" cd "$SKILL_DIR" node ima_api.cjs "$api_path" "$body" \ "{\"clientId\":\"$IMA_CLIENT_ID\",\"apiKey\":\"$IMA_API_KEY\"}" \ 2>/tmp/ima_api_err } ``` **错误检查**:每次 `ima_api` 调用后检查退出码,非零退出时解析 `/tmp/ima_api_err` 中的 `code` 和 `msg`。 --- ## 使用示例 **示例 1 — 基本用法:** > 用户:"下载平安银行的2024年年报到 ima 的「财务分析」文件夹" 流程:搜索"平安银行 年度报告" → 下载 PDF → 上传至「财务分析」文件夹 ✅ **示例 2 — 股票代码:** > 用户:"000001 的一季报下载到财报库" 流程:搜索"000001 第一季度报告" → 下载 PDF → 上传至「财报库」✅ **示例 3 — 批量下载:** > 用户:"把茅台、腾讯、阿里的最新年报都下载到研究库里" 流程:逐家公司依次执行完整流程(串行,一家完成再下一家)。
user_f7659217
未分类 community v1.0.0 1 版本 96428.6 Key: 需要
★ 0
Stars
📥 27
下载
💾 0
安装
1
版本
#latest

概述

财报归集下载 (Financial Report Collector)

根据用户提供的 公司名称股票代码,自动从巨潮资讯网下载对应上市公司财报 PDF,随后上传至 ima 知识库的指定文件夹。


⛔ 核心规则(执行任何操作前必读)

  1. 串行执行,不可并行:整个流程严格按「先下载 → 再归档」的顺序执行。阶段二的任何步骤必须在阶段一完全成功之后启动。
  2. 出错即停:任一环节失败,立即终止并向用户报告失败原因,不继续后续步骤。
  3. 仅输出一个 SKILL.md:本文件为唯一配置,不产生任何附属文件(如 api.md、示例 PDF 等)。
  4. 依赖 ima-skill:阶段二的 COS 上传必须使用 ima-skill 内封装的 ima_api.cjspreflight-check.cjscos-upload.cjs 脚本。
  5. 凭证来源:ima API 凭证从 ~/.config/ima/client_id~/.config/ima/api_key 自动读取;也可通过环境变量 IMA_CLIENT_ID / IMA_API_KEY 传入。

触发条件

当用户消息中包含以下关键词之一时触发本技能:

  • 财报 — 最核心触发词
  • 年报 / 年度报告 / 年度财报
  • 季报 / 季度报告 / 一季报 / 半年报 / 三季报
  • 下载财报 / 下载年报 / 下载季报
  • 上市公司报告

触发后的预设行为:若用户同时提供了公司名称/股票代码 + 目标 ima 文件夹名称,直接执行完整流程;若信息不完整,分步收集。


交互边界

缺少项行为
--------------
缺少公司名称/股票代码询问:"请提供要下载财报的公司名称或股票代码"
缺少报告类型默认下载最新「年度报告」;若用户提及季报/半年报则按需筛选
缺少目标 ima 文件夹上传至 ima 知识库根目录
搜索结果多个匹配列出候选报告让用户选择(展示标题、日期、大小)
目标文件夹不存在告知用户文件夹不存在,上传至根目录或让用户先创建
ima 凭证未配置引导用户完成凭证配置(见下方凭证检查)

凭证检查

在发起任何 API 请求之前检查:

test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key && echo "✅" || echo "⚠️ NO CREDENTIALS"

若未配置,提示用户:

  1. 访问 https://ima.qq.com/agent-interface 获取 Client ID 和 API Key
  2. 提供后将凭证写入:
mkdir -p ~/.config/ima
echo "your_client_id" > ~/.config/ima/client_id
echo "your_api_key" > ~/.config/ima/api_key

完整工作流

┌─────────────────────────────────────────────────────┐
│  阶段一:从巨潮资讯下载财报 PDF                        │
│  Step 1  →  Step 2  →  Step 3  →  Step 4            │
│  构造查询    发送请求    解析结果    下载PDF           │
│                                                      │
│  ✅ 阶段一成功完成(PDF 已落盘)                       │
│         │                                            │
│         ▼                                            │
│  阶段二:上传 PDF 至 ima 知识库                        │
│  Step 5  →  Step 6  →  Step 7  →  Step 8  →  Step 9 │
│  前置检查   获取知识库  定位文件夹  上传COS  添加知识   │
│                                                      │
│  ✅ 全部完成 → 向用户报告结果 + 清理临时文件            │
└─────────────────────────────────────────────────────┘

阶段一:从巨潮资讯下载财报 PDF

Step 1 — 构造查询请求

请求接口:

POST http://www.cninfo.com.cn/new/hisAnnouncement/query
Content-Type: application/x-www-form-urlencoded

核心参数:

参数说明
-----------------
pageNum1页码
pageSize30每页条数
tabNamefulltext全文搜索模式
searchkey{公司名/代码} {报告类型关键词}空格分隔多词
seDate可选,如 2024-01-01~2025-12-31限定公告日期范围

报告类型关键词映射:

用户表述searchkey 追加关键词
-------------------------------
年报 / 年度报告年度报告
一季报 / 一季度报告第一季度报告
半年报 / 半年度报告半年度报告
三季报 / 三季度报告第三季度报告
未指定年度报告(默认)

示例 — 搜索平安银行 2024 年年度报告:

curl -s -X POST "http://www.cninfo.com.cn/new/hisAnnouncement/query" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "pageNum=1" \
  --data-urlencode "pageSize=30" \
  --data-urlencode "tabName=fulltext" \
  --data-urlencode "searchkey=平安银行 年度报告" \
  --data-urlencode "seDate=2024-01-01~2025-06-01"

Step 2 — 发送请求 & 解析响应

响应为 JSON 格式,路径 announcements[],每条包含:

字段说明用法
------------------
secCode股票代码展示给用户
secName公司简称展示给用户
announcementId公告唯一 ID构造下载 URL
announcementTitle公告标题展示给用户,帮助判断
announcementTimeUnix 毫秒时间戳展示发布日期
adjunctUrlPDF 相对路径拼装下载 URL(核心字段)
adjunctSize文件大小(字节)展示给用户
adjunctType附件类型应为 PDF

python3 / node 解析 JSON,筛选 adjunctType=PDF 且标题匹配报告类型的条目。

Step 3 — 让用户确认(多条时)

totalAnnouncement > 1,列出候选报告:

🔍 找到 {N} 份 {公司名} 的财报:

1. 📄 {announcementTitle} — 发布于 {日期},{大小}
2. 📄 {announcementTitle} — 发布于 {日期},{大小}
...

请输入序号选择要下载的报告(输入 "全部" 下载所有)

仅 1 条匹配时,直接进入下载步骤。

Step 4 — 下载 PDF

下载 URL 格式:

http://static.cninfo.com.cn/{adjunctUrl}

下载方式:

# 保存到临时目录,文件名取公告标题
TMP_DIR=$(mktemp -d)
PDF_NAME="{公告标题}.pdf"
curl -sL -o "$TMP_DIR/$PDF_NAME" "http://static.cninfo.com.cn/{adjunctUrl}"

下载后验证:

# 检查文件存在且大小 > 0
test -s "$TMP_DIR/$PDF_NAME" && echo "✅ 下载成功: $(ls -lh "$TMP_DIR/$PDF_NAME" | awk '{print $5}')" || echo "❌ 下载失败"

若下载失败:终止流程,向用户报告错误。


阶段二:上传 PDF 至 ima 知识库

> ⚠️ 前置条件:阶段一必须成功完成(PDF 已存在于本地临时目录)。

环境变量设置(每次调用前):

export IMA_CLIENT_ID=$(cat ~/.config/ima/client_id)
export IMA_API_KEY=$(cat ~/.config/ima/api_key)
export IMA_SKILL_VERSION="1.1.7"
export SKILL_DIR="/workspace/skills/ima-skill"
export IMA_BASE_DIR="$SKILL_DIR"

Step 5 — Preflight 前置检查

PREFLIGHT=$(node "$SKILL_DIR/knowledge-base/scripts/preflight-check.cjs" --file "$PDF_FILE")
echo "$PREFLIGHT"
# 若 pass=false → 终止,将 reason 展示给用户

提取关键字段:

FILE_NAME=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).file_name)")
FILE_SIZE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync(0,'utf8')).file_size))")
MEDIA_TYPE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync(0,'utf8')).media_type))")
CONTENT_TYPE=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).content_type)")
FILE_EXT=$(echo "$PREFLIGHT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).file_ext)")

Step 6 — 获取知识库 ID

情况 A — 用户指定了知识库名称:

# 搜索知识库
ima_api "openapi/wiki/v1/search_knowledge_base" '{"query":"{知识库名称}","cursor":"","limit":20}'
# 从 info_list 中匹配目标知识库,提取 id

情况 B — 用户未指定知识库:

# 列出可添加的知识库
ima_api "openapi/wiki/v1/get_addable_knowledge_base_list" '{"cursor":"","limit":20}'
# 展示列表让用户选择;仅有 1 个时自动选择

Step 7 — 定位目标文件夹

当用户指定了文件夹名称时:

# 在知识库中搜索文件夹
ima_api "openapi/wiki/v1/search_knowledge" "{
  \"query\": \"{文件夹名称}\",
  \"knowledge_base_id\": \"{kb_id}\",
  \"cursor\": \"\"
}"
  • info_list 中筛选 media_idfolder_ 开头的条目
  • 若找到匹配 → 提取 media_id 作为 FOLDER_ID
  • 若未找到 → 告知用户文件夹不存在,改为上传至根目录(不传 folder_id

当用户未指定文件夹时:

跳过此步,上传至知识库根目录(后续步骤中不传 folder_id)。

Step 8 — 检查重名 + 创建媒体 + COS 上传

8a. 重名检查:

ima_api "openapi/wiki/v1/check_repeated_names" "{
  \"params\": [{\"name\": \"$FILE_NAME\", \"media_type\": $MEDIA_TYPE}],
  \"knowledge_base_id\": \"{kb_id}\"
  ${FOLDER_ID:+, \"folder_id\": \"$FOLDER_ID\"}
}"

is_repeated=true → 在文件名后追加时间戳:{name}_20250101120000.{ext}

8b. 创建媒体:

CREATE_RESP=$(ima_api "openapi/wiki/v1/create_media" "{
  \"file_name\": \"$FILE_NAME\",
  \"file_size\": $FILE_SIZE,
  \"content_type\": \"$CONTENT_TYPE\",
  \"knowledge_base_id\": \"{kb_id}\",
  \"file_ext\": \"$FILE_EXT\"
}")
# code≠0 → 终止,将 msg 展示给用户
MEDIA_ID=$(echo "$CREATE_RESP" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync(0,'utf8')).data.media_id)")

提取 COS 凭证字段:secret_idsecret_keytokenbucket_nameregioncos_keystart_timeexpired_time

8c. COS 上传:

node "$SKILL_DIR/knowledge-base/scripts/cos-upload.cjs" \
  --file "$PDF_FILE" \
  --secret-id "{secret_id}" \
  --secret-key "{secret_key}" \
  --token "{token}" \
  --bucket "{bucket_name}" \
  --region "{region}" \
  --cos-key "{cos_key}" \
  --content-type "$CONTENT_TYPE" \
  --start-time "{start_time}" \
  --expired-time "{expired_time}" \
  --timeout 300000
# ⛔ 非零退出 → 立即终止,不要执行 Step 9

Step 9 — 添加知识

仅当 Step 8c 成功(退出码 0)后才执行:

ima_api "openapi/wiki/v1/add_knowledge" "{
  \"media_type\": $MEDIA_TYPE,
  \"media_id\": \"$MEDIA_ID\",
  \"title\": \"$FILE_NAME\",
  \"knowledge_base_id\": \"{kb_id}\"
  ${FOLDER_ID:+, \"folder_id\": \"$FOLDER_ID\"}
  \"file_info\": {
    \"cos_key\": \"{cos_key}\",
    \"file_size\": $FILE_SIZE,
    \"file_name\": \"$FILE_NAME\"
  }
}"

完成 & 清理

全部步骤成功后:

# 清理临时下载文件
rm -rf "$TMP_DIR"

向用户报告:

✅ 财报归集完成!

📥 下载:{公告标题}
📊 公司:{公司名}({股票代码})
📅 发布日期:{日期}
📦 大小:{文件大小}
📂 已存入:ima 知识库「{知识库名称}」{文件夹路径}

错误处理汇总

阶段步骤常见错误处理方式
--------------------------------
阶段一Step 2查询返回空结果提示公司名/代码可能不正确,或该时间段无对应报告
阶段一Step 4PDF 下载失败(404/网络错误)重试一次,仍失败则报告用户
阶段二Step 5文件类型不被支持reason 展示给用户后终止
阶段二Step 6找不到可用的知识库引导用户先在 ima 客户端创建知识库
阶段二Step 7文件夹不存在告知用户后改为上传至根目录
阶段二Step 8bcreate_media 返回 code≠0msg 直接展示给用户
阶段二Step 8cCOS 上传失败终止流程,展示错误信息
阶段二Step 9add_knowledge 返回 code≠0msg 直接展示给用户
全局凭证未配置引导用户完成凭证设置

ima_api 调用封装

为简化重复调用,阶段二中所有对 ima API 的调用统一通过以下方式:

ima_api() {
  local api_path="$1"
  local body="$2"
  cd "$SKILL_DIR"
  node ima_api.cjs "$api_path" "$body" \
    "{\"clientId\":\"$IMA_CLIENT_ID\",\"apiKey\":\"$IMA_API_KEY\"}" \
    2>/tmp/ima_api_err
}

错误检查:每次 ima_api 调用后检查退出码,非零退出时解析 /tmp/ima_api_err 中的 codemsg


使用示例

示例 1 — 基本用法:

> 用户:"下载平安银行的2024年年报到 ima 的「财务分析」文件夹"

流程:搜索"平安银行 年度报告" → 下载 PDF → 上传至「财务分析」文件夹 ✅

示例 2 — 股票代码:

> 用户:"000001 的一季报下载到财报库"

流程:搜索"000001 第一季度报告" → 下载 PDF → 上传至「财报库」✅

示例 3 — 批量下载:

> 用户:"把茅台、腾讯、阿里的最新年报都下载到研究库里"

流程:逐家公司依次执行完整流程(串行,一家完成再下一家)。

版本历史

共 1 个版本

  • v1.0.0 Initial release 当前
    2026-06-04 00:56 安全 安全

安全检测

腾讯云安全 (Keen)

安全,无风险
查看报告

腾讯云安全 (Sanbu)

安全,无风险
查看报告

🔗 相关推荐

ai-intelligence

self-improving agent

pskoett
捕获经验教训、错误和纠正,以实现持续改进。使用时机:(1)命令或操作意外失败;(2)用户纠正……
★ 4,056 📥 796,431
security-compliance

Skill Vetter

spclaudehome
AI智能体技能安全预审工具。安装ClawdHub、GitHub等来源技能前,检查风险信号、权限范围及可疑模式。
★ 1,211 📥 266,215
ai-intelligence

Self-Improving + Proactive Agent

ivangdavila
自我反思+自我批评+自我学习+自组织记忆。智能体评估自身工作、发现错误并持续改进。
★ 1,350 📥 317,751