diff --git a/public/download/hydata-skill.zip b/public/download/hydata-skill.zip new file mode 100644 index 0000000..66eabae Binary files /dev/null and b/public/download/hydata-skill.zip differ diff --git a/public/download/hydata-skill/SKILL.md b/public/download/hydata-skill/SKILL.md new file mode 100644 index 0000000..826cad6 --- /dev/null +++ b/public/download/hydata-skill/SKILL.md @@ -0,0 +1,372 @@ +# 海宇数据 API 对接 Skill + +> 海宇数据 (haiyudata.com) 企业级大数据 API 接口对接 +> 官网: https://www.haiyudata.com/ | 控制台: https://console.haiyudata.com/ + +## 核心理解 + +**所有接口调用方式完全一致**,区别仅在于: +1. **接口编码**(下表第二列)— 决定调用哪个产品 +2. **入参** — 不同接口需要的参数不同 + +## ⚠️ 重要:入参仅为示例! + +下方所有入参中的身份证号、手机号、姓名、车牌号等**均为示例占位值**,调用时**必须替换为真实数据**。 + +## 标准入参字段 + +所有接口统一使用以下字段名: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id_card` | string | 身份证号 | +| `name` | string | 姓名 | +| `mobile_no` | string | 手机号 | +| `vin` | string | 车架号 | +| `plate` | string | 车牌号 | +| `image` | string | 图片 URL 或 Base64 | +| `bankcard` | string | 银行卡号 | +| `ent_code` | string | 企业统一社会信用代码 | +| `ent_name` | string | 企业名称 | +| `callback_url` | string | 回调地址 | +| `token` | string | 任务凭证 | + +> 单人查询传 `id_card` + `name`;双人查询传双方的 `id_card` + `name`;企业查询传 `ent_code` 或 `ent_name`。 + +## 调用方式 + +### 请求 + +``` +POST https://api.haiyudata.com/api/v1/{接口编码}?t={13位时间戳} +``` + +- URL 中的 `t` 为当前时间的 13 位毫秒级时间戳,需实时生成 + +### 请求头 + +``` +Content-Type: application/json +Access-Id: 你的 Access-Id +``` + +### 请求体(AES 加密) + +业务参数需先 JSON 序列化,再用 **AES-128-CBC** 加密,最后 Base64 编码,放入 `data` 字段: + +```json +{ + "data": "加密后的Base64字符串" +} +``` + +#### 加密规则 + +- 算法:AES-128-CBC +- 密钥:账户的 Access Key(16 进制字符串,`bytes.fromhex()` 转为 16 字节密钥) +- IV:每次随机生成 16 字节 +- 填充:PKCS7 +- 传输格式:`Base64( IV + 密文 )` + +#### 解密规则 + +返回的 `data` 字段同样为加密数据: +1. Base64 解码 +2. 前 16 字节为 IV,其余为密文 +3. AES-128-CBC 解密 +4. 去除 PKCS7 填充 + +### 返回格式 + +#### 外层(明文,所有接口统一) + +```json +{ + "code": 0, + "message": "业务成功", + "transaction_id": "平台流水号(海宇计费流水号,重要!)", + "data": "加密后的Base64字符串(需解密后才是真正的业务数据)" +} +``` + +> ⚠️ **`transaction_id` 是海宇数据的计费流水号,每次调用都会返回。** +> 如果对某次调用有疑问(如重复扣费、结果异常、数据争议),**凭此 ID 向海宇客服提交查询**。 +> 请务必在日志中记录每次调用的 `transaction_id`。 + +**先看 `code`,只有 `code = 0` 时 `data` 才有意义的业务数据。** + +| code | 含义 | 说明 | +|------|------|------| +| 0 | 业务成功 | data 中为查询结果 | +| 1003 | 参数校验不正确 | 入参字段名错误或缺失,检查字段拼写 | +| 1004 | 未经授权的IP | 调用方IP未加入白名单,需到控制台添加 | +| 1005 | 缺少Access-Id | 请求头未传 Access-Id | + +#### data 解密后(业务数据,因接口而异) + +`data` 字段是 AES 加密的 JSON 字符串,解密后得到该接口的具体业务结果。 + +**以 `IVYZSQ0E`(公安二要素)为例,解密后:** + +```json +{ + "result": 0, // 核验结果:0=一致,1=不一致,2=查无 + "desc": "一致", // 结果中文描述 + "address": "XX省XX市", // 身份证登记地址 + "sex": "男", // 性别 + "birthday": "19790713",// 出生日期 + "order_no": "xxxxx" // 本次计费订单号 +} +``` + +**常见业务返回字段:** + +| 字段 | 说明 | +|------|------| +| `result` | 核验结论编码(0=一致/通过,1=不一致/不通过,2=查无/未命中) | +| `desc` | 结论中文描述 | +| `order_no` | 计费订单号(每次调用消耗费用的凭证) | +| `address` | 身份证登记地址(身份验证类接口) | +| `sex` | 性别(身份验证类接口) | +| `birthday` | 出生日期(身份验证类接口) | + +> ⚠️ 不同接口返回的 data 字段结构不同,以上为身份验证类的示例。金融风控、企业信息、车辆等接口返回字段更多,以实际返回为准。 + +**调用完成后,应该向用户说明:** +1. 接口是否调用成功(code 是否为 0) +2. 查询的核验结论(result / desc) +3. 返回的关键信息(地址、性别、评分等) +4. 如调用失败,说明失败原因(IP未授权/参数错误/余额不足等) + +--- + +## 接口编码清单(真实编码) + +### 📱 运营商验证 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 移动手机号易诉分 | `YYSYS7Y1` | `mobile_no` | +| 手机停机验证 | `YYSY7R4V` | `mobile_no` | +| 手机消费区间验证 | `YYSY2M8Q` | `mobile_no` | +| 全网手机三要素验证 | `YYSYGLSF` | `mobile_no, id_card, name` | +| 运营商二要素V即时版 | `YYSY0YYV` | `mobile_no, name` | +| 运营商三要素简版V即时版 | `YYSYXHHO` | `mobile_no, id_card, name` | +| 运营商三要素简版V政务版 | `YYSYN8DI` | `mobile_no, id_card, name` | +| 运营商三要素详版V即时版 | `YYSYS66T` | `mobile_no, id_card, name` | +| 号码二次放号V即时版 | `YYSYP7PL` | `mobile_no` | +| 手机空号检测V即时版 | `YYSYJXZF` | `mobile_no` | +| 手机携号转网V即时版 | `YYSYXAES` | `mobile_no` | +| 手机在网状态V即时版 | `YYSYKTQO` | `mobile_no` | +| 手机号码在网时长V即时版 | `YYSYUO7E` | `mobile_no` | + +### 🪪 身份验证 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 公安二要素认证即时版 | `IVYZSQ0E` | `id_card, name` | +| 公安二要素政务版 | `IVYZFO5K` | `id_card, name` | +| 公安三要素即时版 | `IVYZE42I` | `id_card, name, mobile_no` | +| 人脸身份证比对 | `IVYZDXMD` | `id_card, name, image` | +| 身份证OCR | `IVYZZSCG` | `image` | +| 身份证OCR-A | `IVYZ9OHN` | `image` | +| 活体识别V步骤1 | `IVYZWVYA` | `callback_url` | +| 活体识别步骤二 | `IVYZKJ31` | `token` | +| 收入等级VJJ6 | `IVYZ6W0U` | `id_card, name` | +| 身份风险V106 | `IVYZOQFB` | `id_card, name` | +| 消费能力 | `IVYZBI6F` | `id_card, name` | +| 双人婚姻评估查询V1 | `IVYZPYSO` | 双方 `id_card, name` | +| 双人婚姻状态查询 | `IVYZRHT5` | 双方 `id_card, name` | +| 双人婚姻状况核验 | `IVYZYDQM` | 双方 `id_card, name` | +| 单人婚姻状态查询 | `IVYZO4RX` | `id_card, name` | +| 单人婚姻状况核验 | `IVYZYQKX` | `id_card, name` | + +### 🚗 汽车相关 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 汽车车辆五项 | `QCXG1S2L` | `vin` 或 `plate` | +| 全国车辆配置查验 | `QCXGA8V3` | `vin` | +| 全国车辆配置查验(车辆详情) | `QCXGCP77` | `vin` | +| 行驶证信息核验V2 | `QCXGX2X6` | `vin` | +| 名下车辆 | `QCXGIJY3` | `id_card, name` | +| 车辆静态信息查询 | `QCXG521L` | `vin` | +| 车辆维保记录 | `QCXGC6W8` | `vin` | +| 新能源车检测报告V1 | `QCXGX7N1` | `vin` | +| 新能源车检测报告(里程查询) | `QCXGX7N2` | `vin` | +| 疑似营运车辆注册平台数 | `QCXGFV9W` | `plate` | +| 疑似运营车辆查询(月度里程) | `QCXG76VA` | `plate` | +| 疑似运营车辆查询(季度里程) | `QCXGYQDC` | `plate` | +| 疑似运营车辆查询(半年度里程) | `QCXGGFWW` | `plate` | +| 疑似运营车辆查询(年度里程) | `QCXGYWSV` | `plate` | + +### 🏢 企业相关 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 企业全量信息核验V2 | `QYGLALPK` | `ent_code` 或 `ent_name` | +| 企业综合风险报告V2 | `QYGL7HBN` | `ent_code` 或 `ent_name` | +| 企业涉诉V2版 | `QYGLLUCM` | `ent_code` 或 `ent_name` | +| 企业年报信息核验 | `QYGLUDJG` | `ent_code` 或 `ent_name` | +| 企业进出口信用核查 | `QYGLM7AZ` | `ent_code` 或 `ent_name` | +| 企业税收违法核查 | `QYGLWYEK` | `ent_code` 或 `ent_name` | +| 企业股权结构全景 | `QYGL9MYB` | `ent_code` 或 `ent_name` | + +### ⚖️ 风险管控 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 个人涉诉V2版 | `FLXGC4CT` | `id_card, name` | +| 董监高司法综合信息核验A | `FLXGJI17` | `id_card` | + +### 💰 金融验证 + +| 接口名称 | 编码 | 入参(示例值,请替换为真实数据) | +|---------|------|------| +| 银行卡四要素验证(详版) | `JRZQOICN` | `name, id_card, bankcard, mobile_no` | +| 银行卡OCR | `JRZQMDQ1` | `image` | +| 银行卡OCR-A | `JRZQDMLO` | `image` | +| 洞侦多头履约行为 | `JRZQ1AIJ` | `id_card, name, mobile_no` | +| 信用全景V21 | `JRZQV7YZ` | `id_card, name, mobile_no` | +| 借贷意向验证 | `JRZQX5DM` | `id_card, name, mobile_no` | +| 风险量级V8 | `JRZQNKEI` | `id_card, name, mobile_no` | +| 风险量级V9 | `JRZQQKEC` | `id_card, name, mobile_no` | +| 风险量级V10 | `JRZQI079` | `id_card, name, mobile_no` | +| 智瞳分尊享版 | `JRZQAH34` | `id_card, name` | +| 智瞳-通用版 | `JRZQLY6D` | `id_card, name` | +| 智享分 | `JRZQNEP0` | `id_card, name` | +| 支付行为指数 | `JRZQ65ZO` | `id_card, name` | +| 坤羽模型V3-标签版 | `JRZQML9G` | `id_card, name, mobile_no` | +| 租赁申请意向 | `JRZQZ05I` | `id_card, name, mobile_no` | +| 租赁申请意向V22 | `JRZQNK43` | `id_card, name, mobile_no` | +| 人企关联 | `QYGLWV7U` | `id_card, name` | +| 个人涉诉定制版 | `FLXGMMG7` | `id_card, name` | +| 企业诉讼定制版 | `QYGL7Z0O` | `ent_code` 或 `ent_name` | +| 行为黑名单 | `JRZQTM1V` | `id_card, name, mobile_no` | +| 黑名单V110_c10 | `JRZQBQIR` | `id_card, name, mobile_no` | +| 特殊名单 | `JRZQMLZX` | `id_card, name, mobile_no` | +| 债务逾期黑名单V3_1 | `JRZQQD4F` | `id_card, name, mobile_no` | +| 风险变量V5F4 | `JRZQNVM8` | `id_card, name, mobile_no` | +| 投诉风险筛查V709 | `JRZQVBHJ` | `id_card, name, mobile_no` | + +--- + +## Python 完整调用代码 + +```python +import json, time, base64, os, requests +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad, unpad + +ACCESS_ID = os.getenv("HAIYU_ACCESS_ID", "") # 控制台获取 +ACCESS_KEY = os.getenv("HAIYU_ACCESS_KEY", "") # 控制台获取(16进制字符串) +BASE_URL = "https://api.haiyudata.com" + + +def _encrypt(plaintext: str, key_hex: str) -> str: + """AES-128-CBC 加密,返回 Base64(IV + 密文)""" + key = bytes.fromhex(key_hex) + iv = os.urandom(16) + cipher = AES.new(key, AES.MODE_CBC, iv) + enc = cipher.encrypt(pad(plaintext.encode("utf-8"), AES.block_size)) + return base64.b64encode(iv + enc).decode() + + +def _decrypt(b64_str: str, key_hex: str) -> str: + """AES-128-CBC 解密""" + key = bytes.fromhex(key_hex) + raw = base64.b64decode(b64_str) + iv, ct = raw[:16], raw[16:] + cipher = AES.new(key, AES.MODE_CBC, iv) + return unpad(cipher.decrypt(ct), AES.block_size).decode("utf-8") + + +def call_api(api_code: str, **params) -> dict: + """ + 调用海宇数据接口(统一入口) + + :param api_code: 接口编码,如 "IVYZSQ0E" + :param params: 入参(请传入真实值),如 id_card="...", name="..." + :return: {"code": 0, "message": "...", "data": {...}, ...} + + 示例: + call_api("IVYZSQ0E", id_card="真实身份证号", name="真实姓名") + call_api("YYSYJXZF", mobile_no="真实手机号") + """ + ts = str(int(time.time() * 1000)) + url = f"{BASE_URL}/api/v1/{api_code}?t={ts}" + + encrypted = _encrypt(json.dumps(params, ensure_ascii=False), ACCESS_KEY) + + resp = requests.post( + url, + headers={ + "Content-Type": "application/json", + "Access-Id": ACCESS_ID, + }, + json={"data": encrypted}, + timeout=30, + ) + resp.raise_for_status() + raw = resp.json() + + # 解密 data 字段 + if raw.get("data") and isinstance(raw["data"], str): + try: + decrypted = _decrypt(raw["data"], ACCESS_KEY) + raw["data"] = json.loads(decrypted) + except Exception: + pass # data 可能不是 JSON + + return raw +``` + +### 调用示例(入参请替换为真实值) + +```python +# 公安二要素 +result = call_api("IVYZSQ0E", id_card="真实身份证号", name="真实姓名") + +# 手机空号检测 +result = call_api("YYSYJXZF", mobile_no="真实手机号") + +# 个人涉诉V2版 +result = call_api("FLXGC4CT", id_card="真实身份证号", name="真实姓名") + +# 企业全量信息核验 +result = call_api("QYGLALPK", ent_name="真实企业名称") + +# 汽车车辆五项 +result = call_api("QCXG1S2L", vin="真实车架号") + +# 银行卡四要素验证 +result = call_api("JRZQOICN", name="真实姓名", id_card="真实身份证号", bankcard="真实银行卡号", mobile_no="真实手机号") + +# 运营商三要素详版 +result = call_api("YYSYS66T", mobile_no="真实手机号", id_card="真实身份证号", name="真实姓名") +``` + +--- + +## ⚠️ 注意事项 + +### 入参相关 +1. **入参为示例值** — 文档中所有身份证、手机号、姓名等均为占位示例,调用时必须替换为真实数据 +2. **字段名严格匹配** — 必须用 `id_card`(不是 idcard/idCard)、`mobile_no`(不是 mobile/phone)、`name` 等标准字段名,字段名错误会返回 `code: 1003 参数校验不正确` + +### 鉴权与网络 +3. **IP 白名单** — 需在控制台添加调用方服务器公网 IP,否则返回 `code: 1004 未经授权的IP` +4. **Access Key 是 16 进制字符串** — 加密时用 `bytes.fromhex()` 转为 16 字节密钥,不是直接把字符串当 key +5. **时间戳实时生成** — URL 中的 `t` 参数每次请求都要重新生成当前的 13 位毫秒时间戳 +6. **Access-Id 在请求头** — 不是放在请求体里,是在 HTTP Header 中 + +### 加密 +7. **请求和响应都加密** — 发送的参数和返回的 data 都是 AES-128-CBC 加密的 +8. **IV 每次随机** — 加密时随机生成 16 字节 IV,拼在密文前面一起 Base64 编码 +9. **解密时先取 IV** — Base64 解码后,前 16 字节是 IV,剩余是密文 + +### 合规与安全 +10. **敏感数据合规** — 查询个人信息需确保业务合规、用户已授权 +11. **日志脱敏** — 记录日志时对身份证、手机号等做脱敏处理(如 110101****1234) +12. **按次计费** — 所有接口按调用次数扣费,注意余额;失败请求(code 非 0)一般不计费 +13. **保留 transaction_id** — 每次调用都会返回 `transaction_id`(计费流水号),如对调用结果有疑问(重复扣费、数据异常等),凭此 ID 向海宇客服提交查询,务必在日志中记录 diff --git a/src/components/skill-detail.tsx b/src/components/skill-detail.tsx index 6deb6e1..3e08e0b 100644 --- a/src/components/skill-detail.tsx +++ b/src/components/skill-detail.tsx @@ -5,6 +5,12 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import type { Skill } from "@/content/skills"; import { categoryMeta } from "@/content/skills"; +import { + buildNaturalLanguageExample, + buildSkillLoadLink, + buildSlashCommand, + skillInstallPackage, +} from "@/content/skill-install-package"; import { site } from "@/content/site"; import { SkillExampleContent } from "@/components/skill-example-content"; @@ -32,7 +38,16 @@ export function SkillDetail({ skill }: SkillDetailProps) { const [company, setCompany] = useState(skill.detail.runDefaultCompany); const [promptCopied, setPromptCopied] = useState(false); + const [loadLinkCopied, setLoadLinkCopied] = useState(false); + const [skillMdCopied, setSkillMdCopied] = useState(false); const [configCopied, setConfigCopied] = useState(false); + const [skillMdOpen, setSkillMdOpen] = useState(false); + const [skillMd, setSkillMd] = useState(""); + const [skillMdLoading, setSkillMdLoading] = useState(false); + + const loadLink = buildSkillLoadLink(skill.title); + const usageExample = buildNaturalLanguageExample(skill.id, skill.title); + const slashCommand = buildSlashCommand(skill.slug); const reports = site.intelligentReport.reports; const reportById = useMemo(() => { @@ -54,10 +69,16 @@ export function SkillDetail({ skill }: SkillDetailProps) { ); useEffect(() => { - if (!promptCopied) return; - const t = setTimeout(() => setPromptCopied(false), 1800); + if (!loadLinkCopied) return; + const t = setTimeout(() => setLoadLinkCopied(false), 1800); return () => clearTimeout(t); - }, [promptCopied]); + }, [loadLinkCopied]); + + useEffect(() => { + if (!skillMdCopied) return; + const t = setTimeout(() => setSkillMdCopied(false), 1800); + return () => clearTimeout(t); + }, [skillMdCopied]); useEffect(() => { if (!configCopied) return; @@ -65,10 +86,40 @@ export function SkillDetail({ skill }: SkillDetailProps) { return () => clearTimeout(t); }, [configCopied]); - const copyPrompt = async () => { + useEffect(() => { + if (tab !== "install" || skillMd) return; + let cancelled = false; + setSkillMdLoading(true); + fetch(skillInstallPackage.skillMdPath) + .then((res) => (res.ok ? res.text() : "")) + .then((text) => { + if (!cancelled && text) setSkillMd(text); + }) + .catch(() => { + /* ignore */ + }) + .finally(() => { + if (!cancelled) setSkillMdLoading(false); + }); + return () => { + cancelled = true; + }; + }, [tab, skillMd]); + + const copyLoadLink = async () => { try { - await navigator.clipboard.writeText(skill.detail.installPrompt); - setPromptCopied(true); + await navigator.clipboard.writeText(loadLink); + setLoadLinkCopied(true); + } catch { + /* ignore */ + } + }; + + const copySkillMd = async () => { + if (!skillMd) return; + try { + await navigator.clipboard.writeText(skillMd); + setSkillMdCopied(true); } catch { /* ignore */ } @@ -173,7 +224,10 @@ export function SkillDetail({ skill }: SkillDetailProps) { 完成海宇数科 MCP 接入

- 注册账号、获取 API Key、粘贴配置到你的 AI 工具。只需做一次,所有 SKILL 共用。 + 注册账号、获取 API Key、粘贴配置到你的 AI 工具。只需做一次,所有 SKILL 共用。{" "} + + {skillInstallPackage.guideLabel} +

@@ -201,26 +255,148 @@ export function SkillDetail({ skill }: SkillDetailProps) {

加载本 SKILL 到 AI 工具

-

- 复制下方提示词,粘贴到 AI 对话框即可加载「{skill.title}」技能。 -

-
-
- - - AI 加载提示词 - -
- -
+ +
+
+

+ 方式 A · 下载 Skill 安装包 +

+ 推荐 +
+

+ {skillInstallPackage.zipDescription} +

+
+ + {skillInstallPackage.zipFileName} + + + 下载安装包 + +
+
+ +
+
+

+ 方式 B · 复制 AI 加载链接 +

+
+

+ {skillInstallPackage.loadLinkHint} +

+
+
+ + + AI 加载链接 + +
+ +
+
+
+                    {loadLink}
+                  
+
+
+ +
+
+

+ 方式 C · 兜底:复制 SKILL.md 全文 +

+
+

+ {skillInstallPackage.skillMdFallbackHint} +

+
+
+ + + 完整 SKILL.md 全文({skillInstallPackage.skillMdSizeLabel} · 含 API + 对接规则与接口清单) + +
+ + +
+
+ {skillMdOpen ? ( +
+                      
+                        {skillMdLoading
+                          ? "加载中…"
+                          : skillMd || "SKILL.md 暂时无法加载,请稍后重试或直接下载安装包。"}
+                      
+                    
+ ) : null} +
+
+
+ +
+

+ 使用本 SKILL +

+ +
+
+

+ 方式 A · 自然语言对话 +

+
+

+ AI 加载本 SKILL 后,像平时聊天一样说出你的需求,AI 会自动识别并调用本 + SKILL: +

+
+ {usageExample} +
+
+ +
+
+

+ 方式 B · 精准命令调用(专业用户) +

+
+

+ 熟悉本 SKILL 后可直接用 slash 命令精准触发,节省 token 与等待时间: +

+
+
+                    {slashCommand}
+                  
-
-                  {skill.detail.installPrompt}
-                
diff --git a/src/content/skill-install-package.ts b/src/content/skill-install-package.ts new file mode 100644 index 0000000..cf387a0 --- /dev/null +++ b/src/content/skill-install-package.ts @@ -0,0 +1,35 @@ +import { absoluteUrl } from "@/lib/site-url"; + +export const skillInstallPackage = { + zipHref: "/download/hydata-skill.zip", + zipFileName: "hydata-skill.zip", + skillMdPath: "/download/hydata-skill/SKILL.md", + skillMdSizeLabel: "14 KB", + zipDescription: + "包含 SKILL.md、Python 客户端(haiyu_client.py)与测试脚本。解压后放入 Cursor / Claude Code / 小龙虾 等工具的 skills 目录即可。", + loadLinkHint: + "兼容 Cursor / Claude Code / 小龙虾 / OpenClaw 等主流 AI 应用。复制后粘贴到 AI 对话框即可。", + skillMdFallbackHint: + "适用于不会主动 fetch URL 的 AI 工具(如 CherryStudio)。", + guideHref: "/docs/getting-started", + guideLabel: "查看接入指南 →", +} as const; + +export function buildSkillLoadLink(title: string): string { + return `请加载海宇数科 SKILL(${title}):${absoluteUrl(skillInstallPackage.skillMdPath)}`; +} + +export function buildNaturalLanguageExample( + skillId: string, + title: string +): string { + if (skillId === "kyb-verification") { + return "「请帮我对 [公司名称] 做一份完整 KYB 核验报告,重点看主体真实性、股东结构、最近 3 年的司法风险」"; + } + return `「请使用 ${title},对 [公司名称] 做一次完整尽调并输出结构化报告」`; +} + +export function buildSlashCommand(slug: string): string { + const cmd = slug.replace(/^\//, ""); + return `/${cmd} [公司名称]`; +} diff --git a/src/styles/components.css b/src/styles/components.css index 52921d6..bba93ac 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -2292,6 +2292,78 @@ margin: 0; } + .skill-install__guide-link { + color: var(--color-accent-ink); + text-decoration: none; + font-weight: 500; + transition: opacity 0.2s ease; + } + + .skill-install__guide-link:hover { + opacity: 0.85; + text-decoration: underline; + } + + .skill-install__method { + display: flex; + flex-direction: column; + gap: var(--spacing-md); + padding: var(--spacing-lg); + border: 1px solid var(--color-hairline); + border-radius: var(--radius-md); + background-color: var(--color-canvas); + } + + .skill-install__method-head { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--spacing-sm); + } + + .skill-install__method-title { + margin: 0; + } + + .skill-install__badge { + display: inline-flex; + align-items: center; + padding: 2px 8px; + border-radius: var(--radius-full); + font-size: 11px; + font-weight: 600; + line-height: 1.4; + color: var(--color-accent-ink); + background-color: var(--color-accent-wash); + border: 1px solid color-mix(in srgb, var(--color-accent-ink) 18%, transparent); + } + + .skill-install__download { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--spacing-md); + flex-wrap: wrap; + padding: var(--spacing-md); + border: 1px solid var(--color-hairline); + border-radius: var(--radius-sm); + background-color: var(--color-canvas-muted); + } + + .skill-install__download-name { + font-family: var(--font-mono-caps); + letter-spacing: 0.04em; + } + + .skill-install__quote { + margin: 0; + padding: var(--spacing-md) var(--spacing-lg); + border-left: 3px solid var(--color-accent-ink); + background-color: var(--color-canvas-muted); + border-radius: 0 var(--radius-sm) var(--radius-sm) 0; + line-height: 1.65; + } + .skill-code-block__pre--text { white-space: pre-wrap; word-break: break-word;