Skill: pokemummaster/cloud-game (version 1.0.0)

--- name: cloud-game displayName: Cloud Game version: 1.0.0 license: MIT-0 description: 天翼云游戏平台的搜索、推荐与启动技能。当用户明确表达游戏相关意图时使用，包括：想玩游戏、打开游戏、搜索游戏、推荐游戏、找某类游戏、询问某个游戏或游戏类型。即使用户没有提到天翼云游戏平台，只要意图明确与游戏有关，也应触发此技能。不要在纯泛意图下触发，例如用户只说"无聊了""有什么好玩的"且未提到游戏。 metadata: openclaw: emoji: "☁️" homepage: https://h5.play.cn/ --- # 天翼云游戏搜索与启动 通过自然语言帮用户在天翼云游戏平台搜索游戏、推荐游戏，并在确认后快速打开游戏页面。 ## 触发条件 触发本技能： - 用户想玩、打开、搜索、查找某个具体游戏，例如“我要玩原神”“打开飞速骑行”。 - 用户询问游戏类型、玩法、题材或推荐，例如“有什么赛车游戏”“推荐冒险类游戏”“来点二次元游戏”。 - 用户明确提到“天翼云游戏”“云游戏”“play.cn”等平台相关表达。 - 用户上一轮正在推荐列表中选择游戏，例如“第 2 个”“打开第二个”“就它了”。 不要触发本技能： - 用户只表达泛泛的无聊、娱乐或休闲需求，但没有提到游戏，例如“无聊了”“有什么好玩的”。 - 用户讨论游戏新闻、攻略、配置、账号、充值、故障排查等非搜索/启动需求，除非同时要求在平台里找或打开游戏。 ## 交互原则 目标是让用户感觉“说一句就能玩”，不要暴露内部工具、接口、缓存、解析等过程。 只允许在这些节点输出： - 查询开始：一句搜索提示，可附带一条小贴士。 - 结果展示：游戏卡片或推荐列表。 - 打开完成：一句成功提示。 - 异常失败：直接给友好的失败原因和下一步建议。 严禁输出这类内部过程话术： - “让我检查文件”“我来调用接口”“我需要解析结果”。 - “让我先检查一下缓存”“我看看缓存里有没有”“缓存命中了”“缓存没命中”。 - “正在准备终端”“准备请求”“发送请求”“接口返回了”“读取本地文件”。 - “首先/然后/接着”式流程旁白。 - curl、API、缓存命中、JSON 解析等实现细节。 缓存、接口、终端、文件读取、URL 清理都属于内部实现，不要向用户描述。即使正在执行缓存门禁，也只能输出用户可见提示，例如： ```text 🔍 正在帮你搜「关键词」，稍等一下下～ ``` 或缓存命中时： ```text 🔍 刚搜过「关键词」，直接拿结果给你，不用再等～ ``` ## 快速流程 1. 判断用户意图：精确打开、模糊推荐、模糊混合、继续选择。 2. 提取并归一化关键词。 3. 执行“缓存门禁”：先查本地缓存，命中则直接使用缓存，严禁请求 API。 4. 对模糊混合意图并发请求 `gameList` 和 `search`。 5. 统一解析、去重、排序和摘要。 6. 精确高置信结果直接展示并打开；推荐结果展示列表并等待用户选择。 7. 打开前清理 URL，只保留必要功能参数。 ## 意图判断 ### 精确打开 用户明显给出具体游戏名时，优先使用 `gameList API`。 示例： - “我要玩原神” - “打开飞速骑行” - “云游戏里启动王者荣耀” 处理规则： - 如果返回结果中有高置信匹配，直接展示卡片并打开。 - 如果结果多且匹配不够确定，不要擅自打开，展示前 3 个候选并让用户选。 - 高置信判断优先级：标题完全匹配 > 标题包含关键词 > 别名/常见写法匹配 > 标签或简介弱相关。 ### 模糊推荐 用户描述类型、玩法、题材、风格时，使用 `search API`。 示例： - “有什么赛车游戏” - “推荐冒险类的” - “来点适合小朋友玩的” - “随便推荐几个热门游戏” 处理规则： - 明确类型直接作为搜索关键词，例如“赛车”“冒险”“RPG”“二次元”。 - 没有明确关键词时，使用稳定的热门关键词，例如“热门”或“角色扮演”。 - 默认展示 5 个结果，结果不足时展示实际数量。 ### 模糊混合 当用户输入既像游戏名又像类型描述时，并发请求 `gameList API` 和 `search API`。 示例： - “给我推荐王者荣耀那种” - “来点原神类似的游戏” - “玩一下二次元开放世界” 处理规则： - 两个接口都有结果：精确结果在前，相关推荐在后。 - 只有一个接口有结果：直接使用该结果。 - 两个接口都无结果：进入兜底搜索。 - 并发请求的总等待时间按较慢接口计算，但单个接口超时后不要拖住另一个接口的可用结果。 ### 继续选择 如果上一轮已经展示推荐列表，并保存了候选项，本轮用户说“第 1 个”“第二款”“就这个”“打开它”时： - 根据上一轮候选列表定位游戏。 - 清理 URL 后直接打开。 - 若用户表达不清，例如“那个”，而候选不唯一，则请用户说序号或游戏名。 ## 用户可见提示 ### 查询开始 缓存未命中时： ```text 🔍 正在帮你搜「关键词」，稍等一下下～ 💡 小贴士：{随机小贴士} ``` 缓存命中时： ```text 🔍 刚搜过「关键词」，直接拿结果给你，不用再等～ ``` 小贴士从下面随机选择，避免连续两次相同： - 云游戏最大的好处就是不用下载，点开就能玩～ - 游戏跑在云端服务器上，本地设备主要负责显示画面，省空间也省心。 - 手机、电脑、电视都能接着玩，换个屏幕也不耽误进度。 - 网络状态好的时候，云游戏的操作延迟会明显更稳。 - 设备性能不是门槛，能不能马上开玩才是重点。 - 云端存档能减少换设备时的麻烦。 - 热门游戏更新通常比较快，不用一直等下载和安装。 ### 精确结果卡片 ```markdown > 🎮 **游戏名称** 评分文案 > > *一句话简介，不超过 50 字* > > 🚀 已经帮你找到啦，马上打开～ ``` 打开成功后： ```text ✅ 搞定！**游戏名称** 已经在浏览器里等着你了，冲吧！🎮 ``` ### 推荐列表 汇总文案： - 结果数 >= 3：`🎯 帮你找到了 N 款，来看看有没有对味的～` - 结果数为 1 或 2：`🎯 目前搜到 N 款，先看看合不合你胃口～` - 结果数为 0：走兜底搜索或错误提示。 列表模板： ```markdown 1. 🥇 **游戏名称** 评分文案 *一句话简介，不超过 50 字* 2. 🥈 **游戏名称** 评分文案 *一句话简介，不超过 50 字* ``` 列表结尾： ```text 挑中哪个了？跟我说序号或游戏名就行～ ``` 展示列表后，必须在会话状态中保留候选项的 `title`、`url`、`rate`、`summary`，用于下一轮选择。 ## 缓存策略 调用 API 前必须先检查本地缓存，减少重复请求和等待。缓存不是可选优化，而是 API 调用的前置门禁。 强制规则： - 每次准备调用 `gameList API` 或 `search API` 前，必须先按接口名和归一化关键词查缓存。 - 缓存命中且未过期时，直接使用缓存中的 `response` 或 `items`，不要再执行 curl。 - 缓存未命中、已过期、读取失败时，才允许请求 API。 - API 请求成功后，必须立刻写入缓存，再进入结果展示或打开流程。 - 同一轮对话内，相同接口和相同关键词只能请求一次；后续复用内存结果或文件缓存。 - 对用户连续输入同一句，例如连续两次“我要玩原神”，第二次必须命中缓存，不能再次请求 `gameList API`。 缓存文件：`d:\skill\tianyi-cloud-game\.cache\api_cache.json` 缓存结构： ```json { "search:赛车": { "timestamp": 1714000000000, "api": "search", "keyword": "赛车", "response": {}, "items": [] } } ``` 缓存键： - 先归一化关键词。 - 前缀区分接口：`gameList:`、`search:`。 - 模糊混合请求分别缓存两个接口结果。 归一化规则： 1. 去除首尾空白。 2. 去掉常见动作前缀：`我要玩`、`我想玩`、`帮我打开`、`打开`、`启动`、`玩`、`给我来个`、`给我推荐`、`推荐`、`来点`、`搜搜`、`搜索`、`搜`、`找找`、`找`。 3. 去掉常见尾词：`吧`、`呗`、`啊`、`呀`、`一下`、`看看`、`类的`、`之类的`、`那种`、`游戏`。 4. 英文转小写。 5. 合并连续空格。 缓存有效期： - 成功结果：5 分钟。 - 空结果：1 分钟，避免短时间反复请求同一无结果关键词。 - 接口失败不写入成功缓存。 缓存降级： - 缓存文件不存在时自动创建。 - 读取、解析、写入失败时静默跳过缓存，不影响搜索。 - API 失败但缓存里有 30 分钟内的旧成功结果时，可以使用旧结果，并提示“先拿最近一次结果给你看看”。 ### 缓存门禁流程 在任何 curl 前执行： 1. 计算 `normalizedKeyword`。 2. 计算 `cacheKey = apiName + ":" + normalizedKeyword`。 3. 读取 `api_cache.json`。 4. 如果 `cacheKey` 存在，并且 `now - timestamp` 未超过有效期，返回缓存结果并跳过 API。 5. 如果缓存未命中，执行 API。 6. API 成功后写入 `api_cache.json`。 7. 后续展示只使用统一后的结果对象，不再重复请求。 推荐用一个脚本块完成“读缓存/请求 API/写缓存”，不要分散在多次终端调用里，否则容易出现已经查过但仍继续 curl 的问题。 ### PowerShell 实现参考 当运行环境是 PowerShell 时，优先使用下面这种结构，把缓存检查和 API 请求放在同一个脚本里。示例中的请求体必须由对象转 JSON，不要手写拼接 JSON。 ```powershell $ErrorActionPreference = "Stop" $cacheDir = "d:\skill\tianyi-cloud-game\.cache" $cacheFile = Join-Path $cacheDir "api_cache.json" $apiName = "gameList" $rawKeyword = "我要玩原神" $ttlMs = 5 * 60 * 1000 function Normalize-Keyword([string]$text) { $value = $text.Trim() $value = $value -replace "^(我要玩|我想玩|帮我打开|打开|启动|玩|给我来个|给我推荐|推荐|来点|搜搜|搜索|搜|找找|找)", "" $value = $value -replace "(吧|呗|啊|呀|一下|看看|类的|之类的|那种|游戏)$", "" $value = ($value.Trim().ToLower() -replace "\s+", " ") return $value } if (!(Test-Path $cacheDir)) { New-Item -ItemType Directory -Path $cacheDir | Out-Null } $cache = @{} if (Test-Path $cacheFile) { try { $json = Get-Content -Path $cacheFile -Raw -Encoding UTF8 if ($json.Trim()) { $cache = $json | ConvertFrom-Json -AsHashtable } } catch { $cache = @{} } } $keyword = Normalize-Keyword $rawKeyword $cacheKey = "$apiName`:$keyword" $now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() if ($cache.ContainsKey($cacheKey)) { $entry = $cache[$cacheKey] if (($now - [int64]$entry.timestamp) -lt $ttlMs) { $entry.response | ConvertTo-Json -Depth 20 -Compress exit 0 } } $body = @{ text = $rawKeyword } | ConvertTo-Json -Depth 10 -Compress $response = Invoke-RestMethod ` -Uri "https://api.play.cn/api/v1/ai/conversation/gameList" ` -Method Post ` -ContentType "application/json" ` -Body $body ` -TimeoutSec 10 $cache[$cacheKey] = @{ timestamp = $now api = $apiName keyword = $keyword response = $response } $cache | ConvertTo-Json -Depth 30 | Set-Content -Path $cacheFile -Encoding UTF8 $response | ConvertTo-Json -Depth 20 -Compress ``` `search API` 使用同样结构，只需把 `$apiName` 改为 `search`，请求体改为： ```powershell $body = @{ keyword = $keyword; pageSize = 5 } | ConvertTo-Json -Depth 10 -Compress ``` 请求地址改为： ```text https://api.play.cn/api/v1/cloud_phone/search ``` ## API 调用 所有请求都要设置 10 秒超时，并对用户输入做 JSON 转义。不要把未转义的用户输入直接拼接到命令字符串里。 API 调用前置条件： - 已执行缓存门禁。 - 已确认缓存未命中或已过期。 - 已确认同一轮内没有相同接口和关键词的可复用结果。 如果这三个条件不满足，禁止请求 API。 ### gameList API 用途：具体游戏名精确匹配。 请求地址：`https://api.play.cn/api/v1/ai/conversation/gameList` 请求方式：`POST` 请求头：`Content-Type: application/json` 请求体： ```json { "text": "用户原始输入" } ``` 成功判断： - `code` 为 `200` - `ext` 是数组 结果路径： - 名称：`ext[].title` - 简介：`ext[].description` - 评分：`ext[].rate` - 标签：`ext[].tags` - 链接：`ext[].url` ### search API 用途：类型、玩法、题材、相关推荐。 请求地址：`https://api.play.cn/api/v1/cloud_phone/search` 请求方式：`POST` 请求头：`Content-Type: application/json` 请求体： ```json { "keyword": "搜索关键词", "pageSize": 5 } ``` 成功判断： - `code` 为 `0` - `msg` 为 `success` - `info` 是数组 结果路径： - 名称：`info[].title` - 简介：`info[].introduction` - 评分：`info[].rate` - 标签：`info[].tags` - 链接：`info[].url` ## 结果处理 ### 统一字段 把不同接口返回统一成： ```json { "title": "游戏名称", "summary": "一句话简介", "rate": "4.5", "tags": [], "url": "https://h5.play.cn/...", "source": "gameList 或 search", "score": 0.92 } ``` ### 去重 按以下顺序去重： 1. URL 主路径相同。 2. 标题完全相同。 3. 标题去空格、标点、大小写后相同。 重复项保留信息更完整、评分更高、来源更精确的一条。 ### 排序 推荐列表排序规则： 1. 标题与关键词匹配度高的在前。 2. `gameList` 精确结果优先于 `search` 推荐结果。 3. 评分高的在前。 4. 简介、标签、URL 都完整的在前。 精确打开排序规则： 1. 标题完全匹配。 2. 标题包含关键词。 3. 关键词包含标题。 4. 标签或简介相关。 5. 评分和信息完整度。 ### 简介压缩 从 `description` 或 `introduction` 提取一句话： - 保留核心玩法、题材、特色。 - 去掉重复营销话术。 - 控制在 50 字以内。 - 没有简介时用标签补一句，例如“主打赛车竞速玩法，适合想快速开一局。” ### 评分文案 - 评分 >= 4.5：`⭐ 4.8，口碑很不错！` - 评分 3.0 到 4.4：`⭐ 3.8，还算不错` - 评分 < 3.0、为空或无法解析：`⭐ 暂无评分，先玩玩看？` ## URL 清理与打开 打开前必须清理 URL： - 只允许打开 `https://h5.play.cn/`、`https://play.cn/` 及其可信子路径。 - 移除跟踪参数：`caf`、`topRouterId`、`utm_source`、`utm_medium`、`utm_campaign`、`utm_term`、`utm_content`、`spm`。 - 保留功能参数：`type`、`needLand`、`gameId`、`id`、`channel`。 - 如果 URL 缺失、非法或不属于天翼云游戏域名，不要打开，提示用户该结果暂时无法启动。 打开成功后输出完成提示。若系统打开浏览器失败，展示游戏链接并说明可以手动打开。 ## 空结果与错误处理 错误提示要短、轻松、有下一步建议。 ### API 失败 ```text 😅 网络有点小情绪，连不上天翼云游戏平台，等会儿再试一次？ ``` 如果有 30 分钟内的旧缓存： ```text 😅 平台这会儿有点慢，我先拿最近一次结果给你看看～ ``` ### 请求超时 ```text ⏳ 这会儿网络有点慢，请求卡住了，要不换个关键词再试一次？ ``` ### 无结果兜底 第一次无结果时，不要立即失败。根据关键词推断一个相关标签，再调用 `search API` 搜一次。 推断示例： - `原神`、`开放世界`、`塞尔达` -> `开放世界` - `CS`、`枪战`、`吃鸡` -> `射击` - `王者`、`MOBA` -> `竞技` - `赛车`、`飞车` -> `赛车` - `三国`、`仙侠`、`武侠` -> `角色扮演` - 识别不出 -> `冒险` 兜底成功： ```text 🤔 没找到「原关键词」诶，帮你挑了几款「推断标签」类的，看看合不合眼？ ``` 兜底仍失败： ```text 🤔 平台里暂时没找到跟「关键词」相关的游戏，换个词试试？比如搜搜「冒险」「射击」「赛车」之类的～ ``` ### 候选不明确 ```text 我找到了几个相近的，怕打开错。你选个序号，我再帮你启动～ ``` ## 性能优化要求 - 缓存门禁必须发生在 curl 或 `Invoke-RestMethod` 之前，命中时禁止请求接口。 - 模糊混合意图并发请求两个接口。 - 单接口超时不阻塞另一个接口的可用结果。 - 推荐默认 `pageSize` 为 5，不要无意义拉取过多数据。 - 同一轮不要重复请求相同接口和关键词。 - 空结果短缓存 1 分钟，避免连续无效请求。 - API 返回后先统一解析和去重，再生成用户可见内容。 ## 会话状态 展示推荐列表后保存最近一轮候选： ```json { "lastCandidates": [ { "index": 1, "title": "游戏名称", "url": "https://h5.play.cn/...", "summary": "一句话简介", "rate": "4.5" } ], "lastKeyword": "赛车", "lastUpdatedAt": 1714000000000 } ``` 候选状态有效期为 10 分钟。超过有效期后，如果用户只说“第几个”，提示重新搜索或让用户补充游戏名。 ## 输出示例 ### 指定游戏 ```markdown 🔍 正在帮你搜「原神」，稍等一下下～ 💡 小贴士：云游戏最大的好处就是不用下载，点开就能玩～ > 🎮 **原神** ⭐ 4.8，口碑很不错！ > > *开放世界冒险 RPG，自由探索、战斗和养成内容都很丰富。* > > 🚀 已经帮你找到啦，马上打开～ ✅ 搞定！**原神** 已经在浏览器里等着你了，冲吧！🎮 ``` ### 推荐游戏 ```markdown 🔍 正在帮你搜「赛车」，稍等一下下～ 💡 小贴士：手机、电脑、电视都能接着玩，换个屏幕也不耽误进度。 🎯 帮你找到了 5 款，来看看有没有对味的～ 1. 🥇 **飞速骑行** ⭐ 4.6，口碑很不错！ *主打高速竞速和赛道挑战，适合想快速开跑的玩家。* 2. 🥈 **真实赛车** ⭐ 4.1，还算不错 *偏真实驾驶手感，车辆和赛道选择比较丰富。* 挑中哪个了？跟我说序号或游戏名就行～ ```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)