skillfree 0.1.65 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +13 -5
- package/install.sh +74 -6
- package/package.json +1 -1
- package/postinstall.js +84 -26
- package/scripts/commands/auth.js +23 -6
- package/scripts/commands/pilot.js +46 -3
package/SKILL.md
CHANGED
|
@@ -156,8 +156,11 @@ skillfree pilot --type pharma --target "IL-4" --status "III期临床"
|
|
|
156
156
|
# 翻页(默认第1页)
|
|
157
157
|
skillfree pilot --type pharma --target "STAT6" --page 2
|
|
158
158
|
|
|
159
|
-
#
|
|
160
|
-
skillfree pilot --type pharma --model bcpm-drug-detail --
|
|
159
|
+
# 查询药物详情(自动查 keyid)
|
|
160
|
+
skillfree pilot --type pharma --model bcpm-drug-detail --drug "替雷利珠单抗"
|
|
161
|
+
|
|
162
|
+
# 查询全球临床试验结果(自动查 keyid)⭐ 新增
|
|
163
|
+
skillfree pilot --type pharma --model bcpm-clinical-result --drug "信迪利单抗"
|
|
161
164
|
|
|
162
165
|
# 查询中国临床试验
|
|
163
166
|
skillfree pilot --type pharma --model bcpm-cn-clinical --drug "度普利尤单抗"
|
|
@@ -175,18 +178,23 @@ skillfree pilot --type pharma --target "STAT6" --output result.json
|
|
|
175
178
|
| model | 说明 | 主要参数 |
|
|
176
179
|
|-------|------|---------|
|
|
177
180
|
| `bcpm-drug-dev`(默认)| 全球药物研发管线 | --target / --drug / --indication / --company / --status |
|
|
178
|
-
| `bcpm-drug-detail` | 药物详细信息(含销售额、适应症进展)| --keyid
|
|
181
|
+
| `bcpm-drug-detail` | 药物详细信息(含销售额、适应症进展)| --drug(自动查 keyid)或 --keyid |
|
|
182
|
+
| `bcpm-clinical-result` | 全球临床试验结果 ⭐ 新增 | --drug(自动查 keyid)或 --keyid |
|
|
179
183
|
| `bcpm-cn-clinical` | 中国临床试验注册 | --drug / --sponsor / --indication |
|
|
180
184
|
| `bcpm-cn-evaluation` | 中国药品申报/评审 | --drug / --company |
|
|
181
185
|
|
|
182
|
-
|
|
186
|
+
**典型工作流(已简化):**
|
|
183
187
|
|
|
184
188
|
```bash
|
|
189
|
+
# 方式一:直接用药品名(推荐)⭐
|
|
190
|
+
skillfree pilot --type pharma --model bcpm-clinical-result --drug "信迪利单抗"
|
|
191
|
+
|
|
192
|
+
# 方式二:手动两步(如果需要精确控制)
|
|
185
193
|
# 第一步:查管线,找到目标药物的 keyid
|
|
186
194
|
skillfree pilot --type pharma --target "STAT6"
|
|
187
195
|
# 输出中会显示每个药物的 keyid
|
|
188
196
|
|
|
189
|
-
# 第二步:用 keyid
|
|
197
|
+
# 第二步:用 keyid 查详情
|
|
190
198
|
skillfree pilot --type pharma --model bcpm-drug-detail --keyid 0b0566619e92554c97b384c0e4c9ddfd
|
|
191
199
|
```
|
|
192
200
|
|
package/install.sh
CHANGED
|
@@ -39,7 +39,7 @@ echo -e " ${DIM}─────────────────────
|
|
|
39
39
|
echo ""
|
|
40
40
|
|
|
41
41
|
# ── Step 1: 检查环境 ──────────────────────────────────────────────────────────
|
|
42
|
-
step "[ 1 /
|
|
42
|
+
step "[ 1 / 4 ] 检查环境"
|
|
43
43
|
|
|
44
44
|
if ! command -v node &>/dev/null; then
|
|
45
45
|
err "未检测到 Node.js,请先安装:https://nodejs.org(需要 18+)"
|
|
@@ -55,8 +55,76 @@ if ! command -v npm &>/dev/null; then
|
|
|
55
55
|
fi
|
|
56
56
|
success "npm $(npm -v)"
|
|
57
57
|
|
|
58
|
-
# ── Step 2:
|
|
59
|
-
step "[ 2 /
|
|
58
|
+
# ── Step 2: 选择 AI 平台 ──────────────────────────────────────────────────────
|
|
59
|
+
step "[ 2 / 4 ] 选择你使用的 AI 平台"
|
|
60
|
+
echo ""
|
|
61
|
+
echo -e " SkillFree 将作为 Skill 安装到对应平台,${DIM}可多选,用逗号或空格分隔${NC}"
|
|
62
|
+
echo ""
|
|
63
|
+
|
|
64
|
+
# 自动检测已安装的平台
|
|
65
|
+
DETECTED=()
|
|
66
|
+
[ -d "$HOME/.openclaw" ] && DETECTED+=("openclaw")
|
|
67
|
+
[ -d "$HOME/.claude" ] && DETECTED+=("claude")
|
|
68
|
+
[ -d "$HOME/.codex" ] && DETECTED+=("codex")
|
|
69
|
+
[ -d "$HOME/.continue" ] && DETECTED+=("continue")
|
|
70
|
+
[ -d "$HOME/.cursor/extensions" ] && DETECTED+=("cursor")
|
|
71
|
+
|
|
72
|
+
echo -e " ${BOLD}可选平台:${NC}"
|
|
73
|
+
echo -e " ${CYAN} 1)${NC} OpenClaw ${DIM}→ ~/.openclaw/skills/skillfree/${NC}"
|
|
74
|
+
echo -e " ${CYAN} 2)${NC} Claude Code ${DIM}→ ~/.claude/skills/skillfree/${NC}"
|
|
75
|
+
echo -e " ${CYAN} 3)${NC} Codex CLI ${DIM}→ ~/.codex/skills/skillfree/${NC}"
|
|
76
|
+
echo -e " ${CYAN} 4)${NC} Continue.dev ${DIM}→ ~/.continue/skills/skillfree/${NC}"
|
|
77
|
+
echo -e " ${CYAN} 5)${NC} Cursor ${DIM}→ ~/.cursor/skills/skillfree/${NC}"
|
|
78
|
+
echo -e " ${CYAN} 0)${NC} 跳过(仅安装 CLI)"
|
|
79
|
+
echo ""
|
|
80
|
+
|
|
81
|
+
if [ ${#DETECTED[@]} -gt 0 ]; then
|
|
82
|
+
echo -e " ${GREEN}已检测到:${DETECTED[*]}${NC}"
|
|
83
|
+
echo ""
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
printf " 请输入编号(如 1 或 1,2,3),直接回车选全部检测到的平台: "
|
|
87
|
+
read -r PLATFORM_INPUT </dev/tty
|
|
88
|
+
|
|
89
|
+
# 解析选择
|
|
90
|
+
SELECTED_PLATFORMS=()
|
|
91
|
+
|
|
92
|
+
if [ -z "$PLATFORM_INPUT" ]; then
|
|
93
|
+
# 回车 → 使用检测到的平台,没检测到则选 all
|
|
94
|
+
if [ ${#DETECTED[@]} -gt 0 ]; then
|
|
95
|
+
SELECTED_PLATFORMS=("${DETECTED[@]}")
|
|
96
|
+
else
|
|
97
|
+
SELECTED_PLATFORMS=("openclaw" "claude" "codex")
|
|
98
|
+
fi
|
|
99
|
+
elif [ "$PLATFORM_INPUT" = "0" ]; then
|
|
100
|
+
SELECTED_PLATFORMS=()
|
|
101
|
+
else
|
|
102
|
+
# 解析数字(支持逗号/空格分隔)
|
|
103
|
+
INPUT_CLEAN="${PLATFORM_INPUT//,/ }"
|
|
104
|
+
for num in $INPUT_CLEAN; do
|
|
105
|
+
case "$num" in
|
|
106
|
+
1) SELECTED_PLATFORMS+=("openclaw") ;;
|
|
107
|
+
2) SELECTED_PLATFORMS+=("claude") ;;
|
|
108
|
+
3) SELECTED_PLATFORMS+=("codex") ;;
|
|
109
|
+
4) SELECTED_PLATFORMS+=("continue") ;;
|
|
110
|
+
5) SELECTED_PLATFORMS+=("cursor") ;;
|
|
111
|
+
esac
|
|
112
|
+
done
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
if [ ${#SELECTED_PLATFORMS[@]} -gt 0 ]; then
|
|
116
|
+
echo ""
|
|
117
|
+
echo -e " ${GREEN}将安装到:${SELECTED_PLATFORMS[*]}${NC}"
|
|
118
|
+
else
|
|
119
|
+
echo ""
|
|
120
|
+
warn "未选择平台,仅安装 CLI 命令行工具"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# 导出给 postinstall.js 使用
|
|
124
|
+
export SKILLFREE_PLATFORMS="${SELECTED_PLATFORMS[*]}"
|
|
125
|
+
|
|
126
|
+
# ── Step 3: 安装 CLI ──────────────────────────────────────────────────────────
|
|
127
|
+
step "[ 3 / 4 ] 安装 SkillFree CLI"
|
|
60
128
|
echo ""
|
|
61
129
|
echo -e " ${DIM}正在从 npm 安装 skillfree...${NC}"
|
|
62
130
|
echo ""
|
|
@@ -91,8 +159,8 @@ if ! command -v skillfree &>/dev/null; then
|
|
|
91
159
|
exit 0
|
|
92
160
|
fi
|
|
93
161
|
|
|
94
|
-
# ── Step
|
|
95
|
-
step "[
|
|
162
|
+
# ── Step 4: 登录(从 /dev/tty 读取,兼容 curl | bash)────────────────────────
|
|
163
|
+
step "[ 4 / 4 ] 登录账号"
|
|
96
164
|
echo ""
|
|
97
165
|
echo -e " 还没有账号?${CYAN}https://skillfree.tech/app${NC} 免费注册,注册即送 ¥5"
|
|
98
166
|
echo -e " 注册后进入控制台 → ${BOLD}API Keys${NC} → 创建一个 Key,粘贴到下方"
|
|
@@ -120,7 +188,7 @@ while true; do
|
|
|
120
188
|
done
|
|
121
189
|
|
|
122
190
|
if [ -n "$API_KEY" ]; then
|
|
123
|
-
SKILLFREE_API_KEY="$API_KEY" skillfree auth save "$API_KEY"
|
|
191
|
+
SKILLFREE_API_KEY="$API_KEY" SKILLFREE_PLATFORMS="$SKILLFREE_PLATFORMS" skillfree auth save "$API_KEY"
|
|
124
192
|
fi
|
|
125
193
|
|
|
126
194
|
# ── 完成 ──────────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -2,24 +2,60 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* postinstall.js
|
|
4
4
|
* npm install -g skillfree 后自动:
|
|
5
|
-
* 1.
|
|
6
|
-
* 2. 将 API Key 写入
|
|
5
|
+
* 1. 将技能文件部署到各 AI 平台的 skills/skillfree/ 目录
|
|
6
|
+
* 2. 将 API Key 写入 OpenClaw 配置(如果已安装)
|
|
7
|
+
*
|
|
8
|
+
* 支持的平台(通过 SKILLFREE_PLATFORMS 环境变量控制):
|
|
9
|
+
* openclaw → ~/.openclaw/skills/skillfree/ + ~/.agents/skills/skillfree/
|
|
10
|
+
* claude → ~/.claude/skills/skillfree/
|
|
11
|
+
* codex → ~/.codex/skills/skillfree/
|
|
12
|
+
* continue → ~/.continue/skills/skillfree/
|
|
13
|
+
* cursor → ~/.cursor/skills/skillfree/
|
|
7
14
|
*/
|
|
8
15
|
|
|
9
16
|
const fs = require('fs')
|
|
10
17
|
const path = require('path')
|
|
11
18
|
const os = require('os')
|
|
12
19
|
|
|
13
|
-
const PKG_DIR
|
|
14
|
-
const HOME
|
|
15
|
-
const API_KEY
|
|
20
|
+
const PKG_DIR = __dirname
|
|
21
|
+
const HOME = os.homedir()
|
|
22
|
+
const API_KEY = process.env.SKILLFREE_API_KEY || ''
|
|
23
|
+
|
|
24
|
+
// ── 平台 → 技能安装路径映射 ─────────────────────────────────────────────────
|
|
25
|
+
const PLATFORM_PATHS = {
|
|
26
|
+
openclaw: [
|
|
27
|
+
path.join(HOME, '.openclaw', 'skills', 'skillfree'),
|
|
28
|
+
path.join(HOME, '.agents', 'skills', 'skillfree'),
|
|
29
|
+
],
|
|
30
|
+
claude: [
|
|
31
|
+
path.join(HOME, '.claude', 'skills', 'skillfree'),
|
|
32
|
+
],
|
|
33
|
+
codex: [
|
|
34
|
+
path.join(HOME, '.codex', 'skills', 'skillfree'),
|
|
35
|
+
],
|
|
36
|
+
continue: [
|
|
37
|
+
path.join(HOME, '.continue', 'skills', 'skillfree'),
|
|
38
|
+
],
|
|
39
|
+
cursor: [
|
|
40
|
+
path.join(HOME, '.cursor', 'skills', 'skillfree'),
|
|
41
|
+
],
|
|
42
|
+
}
|
|
16
43
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
// 解析目标平台
|
|
45
|
+
function getTargetPlatforms() {
|
|
46
|
+
const envVal = process.env.SKILLFREE_PLATFORMS || ''
|
|
47
|
+
if (!envVal.trim()) {
|
|
48
|
+
// 未指定时:自动检测已安装的平台
|
|
49
|
+
return Object.keys(PLATFORM_PATHS).filter(p => {
|
|
50
|
+
const baseDir = path.join(HOME, '.' + p)
|
|
51
|
+
return fs.existsSync(baseDir)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
// 支持空格/逗号分隔
|
|
55
|
+
return envVal.split(/[\s,]+/).filter(p => p && PLATFORM_PATHS[p])
|
|
56
|
+
}
|
|
22
57
|
|
|
58
|
+
// ── 文件部署 ─────────────────────────────────────────────────────────────────
|
|
23
59
|
const FILES = ['SKILL.md', 'package.json']
|
|
24
60
|
const DIRS = ['bin', 'scripts']
|
|
25
61
|
|
|
@@ -48,33 +84,32 @@ function deploySkill(skillDir) {
|
|
|
48
84
|
}
|
|
49
85
|
fs.writeFileSync(
|
|
50
86
|
path.join(skillDir, '.skillfree-installed'),
|
|
51
|
-
JSON.stringify({
|
|
87
|
+
JSON.stringify({
|
|
88
|
+
installedAt: new Date().toISOString(),
|
|
89
|
+
version: require('./package.json').version,
|
|
90
|
+
}, null, 2) + '\n'
|
|
52
91
|
)
|
|
53
92
|
}
|
|
54
93
|
|
|
94
|
+
// ── OpenClaw 特有:写入 openclaw.json ────────────────────────────────────────
|
|
55
95
|
function injectOpenclawConfig(apiKey) {
|
|
56
|
-
// 只在有 openclaw 目录时注入
|
|
57
96
|
const openclawDir = path.join(HOME, '.openclaw')
|
|
58
97
|
if (!fs.existsSync(openclawDir)) return
|
|
59
98
|
|
|
60
99
|
const cfgPath = path.join(openclawDir, 'openclaw.json')
|
|
61
|
-
|
|
62
|
-
// ⚠️ 关键:文件不存在时直接 return,绝不用空对象覆盖
|
|
63
100
|
if (!fs.existsSync(cfgPath)) return
|
|
64
101
|
|
|
65
102
|
let cfg = {}
|
|
66
103
|
try {
|
|
67
104
|
cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'))
|
|
68
105
|
} catch (e) {
|
|
69
|
-
|
|
70
|
-
console.warn('⚠️ openclaw.json 解析失败,跳过自动配置(文件可能损坏)')
|
|
106
|
+
console.warn('⚠️ openclaw.json 解析失败,跳过自动配置')
|
|
71
107
|
return
|
|
72
108
|
}
|
|
73
109
|
|
|
74
110
|
cfg.skills = cfg.skills || {}
|
|
75
111
|
cfg.skills.entries = cfg.skills.entries || {}
|
|
76
112
|
|
|
77
|
-
// 只写 enabled,不覆盖用户已有的 apiKey
|
|
78
113
|
const existing = cfg.skills.entries['skillfree'] || {}
|
|
79
114
|
cfg.skills.entries['skillfree'] = {
|
|
80
115
|
...existing,
|
|
@@ -84,23 +119,46 @@ function injectOpenclawConfig(apiKey) {
|
|
|
84
119
|
|
|
85
120
|
try {
|
|
86
121
|
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + '\n')
|
|
87
|
-
console.log('✅ openclaw.json 已更新,skill 下次启动自动生效')
|
|
122
|
+
console.log(' ✅ openclaw.json 已更新,skill 下次启动自动生效')
|
|
88
123
|
} catch (e) {
|
|
89
124
|
// 权限问题静默跳过
|
|
90
125
|
}
|
|
91
126
|
}
|
|
92
127
|
|
|
128
|
+
// ── 主流程 ───────────────────────────────────────────────────────────────────
|
|
93
129
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
130
|
+
const platforms = getTargetPlatforms()
|
|
131
|
+
|
|
132
|
+
if (platforms.length === 0) {
|
|
133
|
+
// 没有检测到任何平台,保底装到 ~/.agents/skills/
|
|
134
|
+
const fallback = path.join(HOME, '.agents', 'skills', 'skillfree')
|
|
135
|
+
deploySkill(fallback)
|
|
136
|
+
console.log(`✅ SkillFree skill 已安装到 ${fallback}`)
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const installed = []
|
|
141
|
+
|
|
142
|
+
for (const platform of platforms) {
|
|
143
|
+
const targets = PLATFORM_PATHS[platform] || []
|
|
144
|
+
for (const skillDir of targets) {
|
|
145
|
+
deploySkill(skillDir)
|
|
146
|
+
installed.push({ platform, skillDir })
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// OpenClaw 额外注入 openclaw.json
|
|
150
|
+
if (platform === 'openclaw') {
|
|
151
|
+
injectOpenclawConfig(API_KEY)
|
|
152
|
+
}
|
|
97
153
|
}
|
|
98
|
-
console.log('✅ SkillFree skill 已安装到:')
|
|
99
|
-
SKILL_TARGETS.forEach(t => console.log(` ${t}`))
|
|
100
154
|
|
|
101
|
-
|
|
102
|
-
|
|
155
|
+
if (installed.length > 0) {
|
|
156
|
+
console.log('✅ SkillFree skill 已安装到:')
|
|
157
|
+
for (const { platform, skillDir } of installed) {
|
|
158
|
+
console.log(` [${platform}] ${skillDir}`)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
103
161
|
|
|
104
162
|
} catch (e) {
|
|
105
|
-
//
|
|
163
|
+
// 静默失败,不影响正常 npm 安装
|
|
106
164
|
}
|
package/scripts/commands/auth.js
CHANGED
|
@@ -4,15 +4,34 @@ const path = require('path')
|
|
|
4
4
|
const os = require('os')
|
|
5
5
|
const { saveConfig, BASE_URL } = require('../lib/client')
|
|
6
6
|
|
|
7
|
+
// ── 平台 → 技能安装路径映射(与 postinstall.js 保持一致)─────────────────
|
|
8
|
+
const PLATFORM_PATHS = {
|
|
9
|
+
openclaw: [
|
|
10
|
+
path.join(os.homedir(), '.openclaw', 'skills', 'skillfree'),
|
|
11
|
+
path.join(os.homedir(), '.agents', 'skills', 'skillfree'),
|
|
12
|
+
],
|
|
13
|
+
claude: [
|
|
14
|
+
path.join(os.homedir(), '.claude', 'skills', 'skillfree'),
|
|
15
|
+
],
|
|
16
|
+
codex: [
|
|
17
|
+
path.join(os.homedir(), '.codex', 'skills', 'skillfree'),
|
|
18
|
+
],
|
|
19
|
+
continue: [
|
|
20
|
+
path.join(os.homedir(), '.continue', 'skills', 'skillfree'),
|
|
21
|
+
],
|
|
22
|
+
cursor: [
|
|
23
|
+
path.join(os.homedir(), '.cursor', 'skills', 'skillfree'),
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
|
|
7
27
|
/**
|
|
8
|
-
* 将 apiKey
|
|
9
|
-
* 同时设置当前进程的 SKILLFREE_API_KEY 环境变量
|
|
28
|
+
* 将 apiKey 写入各平台配置 + shell 环境变量
|
|
10
29
|
*/
|
|
11
30
|
function injectToOpenclaw(apiKey) {
|
|
12
|
-
// 1. 写入 openclaw.json
|
|
31
|
+
// 1. OpenClaw: 写入 openclaw.json
|
|
13
32
|
const openclawDir = path.join(os.homedir(), '.openclaw')
|
|
14
33
|
const cfgPath = path.join(openclawDir, 'openclaw.json')
|
|
15
|
-
if (fs.existsSync(openclawDir)) {
|
|
34
|
+
if (fs.existsSync(openclawDir) && fs.existsSync(cfgPath)) {
|
|
16
35
|
let cfg = {}
|
|
17
36
|
try { cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8')) } catch {}
|
|
18
37
|
cfg.skills = cfg.skills || {}
|
|
@@ -41,7 +60,6 @@ function injectToOpenclaw(apiKey) {
|
|
|
41
60
|
if (fs.existsSync(f)) {
|
|
42
61
|
const content = fs.readFileSync(f, 'utf8')
|
|
43
62
|
if (content.includes('SKILLFREE_API_KEY')) {
|
|
44
|
-
// 替换已有行
|
|
45
63
|
const updated = content.replace(/\nexport SKILLFREE_API_KEY=.*\n?/g, exportLine)
|
|
46
64
|
fs.writeFileSync(f, updated)
|
|
47
65
|
} else {
|
|
@@ -53,7 +71,6 @@ function injectToOpenclaw(apiKey) {
|
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
if (!wrote) {
|
|
56
|
-
// 创建 .zshrc
|
|
57
74
|
fs.writeFileSync(shellFiles[0], `# SkillFree API Key${exportLine}`)
|
|
58
75
|
console.log('✅ ~/.zshrc 已创建并写入 SKILLFREE_API_KEY')
|
|
59
76
|
}
|
|
@@ -224,9 +224,38 @@ async function pilot(flags) {
|
|
|
224
224
|
if (flags.title) search.title = flags.title
|
|
225
225
|
if (flags.sponsor) search.sponsor = flags.sponsor
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
let inputs
|
|
228
|
+
let keyid = flags.keyid ?? prompt
|
|
229
|
+
|
|
230
|
+
// bcpm-clinical-result / bcpm-drug-detail 特殊处理:如果没有 keyid 但有 drug,自动查询获取 keyid
|
|
231
|
+
if ((pharmaModel === 'bcpm-clinical-result' || pharmaModel === 'bcpm-drug-detail') && !keyid && search.drug_name) {
|
|
232
|
+
console.log(`🔍 自动查询 "${search.drug_name}" 的 keyid...`)
|
|
233
|
+
const drugRes = await post('/pharma', {
|
|
234
|
+
model: 'bcpm-drug-dev',
|
|
235
|
+
inputs: { search: { drug_name: search.drug_name }, page: 1 }
|
|
236
|
+
})
|
|
237
|
+
if (drugRes.error) {
|
|
238
|
+
console.error(`❌ 查询药物失败: ${drugRes.error.message}`)
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
const list = drugRes.data?.list || []
|
|
242
|
+
if (list.length === 0) {
|
|
243
|
+
console.error(`❌ 未找到药物: ${search.drug_name}`)
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
keyid = list[0].keyid
|
|
247
|
+
console.log(`✅ 找到药物: ${list[0].drug_name_cn || list[0].drug_name} (keyid: ${keyid})\n`)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (pharmaModel === 'bcpm-drug-detail' || pharmaModel === 'bcpm-clinical-result') {
|
|
251
|
+
if (!keyid) {
|
|
252
|
+
console.error(`❌ ${pharmaModel} 需要 --keyid 或 --drug 参数`)
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
inputs = { keyid, page: Number(flags.page ?? 1) }
|
|
256
|
+
} else {
|
|
257
|
+
inputs = { search, page: Number(flags.page ?? 1) }
|
|
258
|
+
}
|
|
230
259
|
|
|
231
260
|
const res = await post('/pharma', { model: pharmaModel, inputs })
|
|
232
261
|
|
|
@@ -267,6 +296,20 @@ async function pilot(flags) {
|
|
|
267
296
|
console.log(` • ${s.year} ${s.company}: ${s.sales}`)
|
|
268
297
|
})
|
|
269
298
|
}
|
|
299
|
+
} else if (pharmaModel === 'bcpm-clinical-result') {
|
|
300
|
+
// 临床试验结果
|
|
301
|
+
const list = data.list || []
|
|
302
|
+
const total = data.total || list.length
|
|
303
|
+
console.log(`共 ${total} 条结果,当前显示 ${list.length} 条\n`)
|
|
304
|
+
list.slice(0, 10).forEach((item, i) => {
|
|
305
|
+
console.log(`${i + 1}. [${item.registration_number}] ${item.title}`)
|
|
306
|
+
console.log(` 适应症: ${(item.indication || []).join(', ')}`)
|
|
307
|
+
console.log(` 分期: ${item.phase}`)
|
|
308
|
+
if (item.representative_data) console.log(` 代表性数据: ${item.representative_data}`)
|
|
309
|
+
if (item.result_tendency) console.log(` 结果趋势: ${item.result_tendency}`)
|
|
310
|
+
if (item.abstract?.length) console.log(` 摘要: ${item.abstract[0].slice(0, 150)}...`)
|
|
311
|
+
console.log('')
|
|
312
|
+
})
|
|
270
313
|
} else {
|
|
271
314
|
const list = data.list || []
|
|
272
315
|
const total = data.total || list.length
|