fix: 优化股票skill

This commit is contained in:
hp0912 2026-06-05 21:43:49 +08:00
parent 51b01b9234
commit cd7a27fd82
2 changed files with 62 additions and 29 deletions

View File

@ -22,6 +22,7 @@ argument-hint: "无需参数,直接调用即可"
4. 网页上有这个类名(`topzs`)的 div 元素,展示了`上证指数`、`深证成指`、`创业板指`、`科创综指`、`北证50`的涨跌情况。优先截图这个元素,然后使用图像识别技能识别具体内容。 4. 网页上有这个类名(`topzs`)的 div 元素,展示了`上证指数`、`深证成指`、`创业板指`、`科创综指`、`北证50`的涨跌情况。优先截图这个元素,然后使用图像识别技能识别具体内容。
5. 网页上有这个 id(`stockmap`)的 div 元素,展示了各个板块的涨跌情况。如果用户想看板块涨跌情况,直接截图并使用发送图片技能发送图片。 5. 网页上有这个 id(`stockmap`)的 div 元素,展示了各个板块的涨跌情况。如果用户想看板块涨跌情况,直接截图并使用发送图片技能发送图片。
6. 如果没有获取到具体涨跌情况,则截图 id(`stockmap`) 的 div 元素并使用发送图片技能发送图片。 6. 如果没有获取到具体涨跌情况,则截图 id(`stockmap`) 的 div 元素并使用发送图片技能发送图片。
7. 调用 `web-page` 的 selector 截图模式时,`selector` 参数必须传真实 CSS 选择器字符串;当值以 `#` 开头时必须加引号,例如 `--selector '#stockmap'``--selector="#stockmap"`
## 回复要求 ## 回复要求

View File

@ -8,6 +8,7 @@ import os from "node:os";
import path from "node:path"; import path from "node:path";
import { spawn, type ChildProcess } from "node:child_process"; import { spawn, type ChildProcess } from "node:child_process";
import type { IncomingMessage } from "node:http"; import type { IncomingMessage } from "node:http";
import { parseArgs as parseNodeArgs } from "node:util";
const DEFAULT_VIEWPORT_WIDTH = 1365; const DEFAULT_VIEWPORT_WIDTH = 1365;
const DEFAULT_VIEWPORT_HEIGHT = 900; const DEFAULT_VIEWPORT_HEIGHT = 900;
@ -47,7 +48,30 @@ type ActionType =
| "scroll" | "scroll"
| "scroll_to"; | "scroll_to";
type RawArgs = Record<string, string>; type RawArgKey =
| "url"
| "mode"
| "screenshot_mode"
| "selector"
| "x"
| "y"
| "width"
| "height"
| "viewport_width"
| "viewport_height"
| "wait_ms"
| "timeout_ms"
| "max_chars"
| "max_full_height"
| "action_timeout_ms"
| "actions"
| "actions_file"
| "region_width"
| "region_height"
| "output"
| "send";
type RawArgs = Partial<Record<RawArgKey, string>>;
interface NormalizedAction { interface NormalizedAction {
type: ActionType; type: ActionType;
@ -139,33 +163,40 @@ function stdout(message: string): void {
process.stdout.write(`${message}\n`); process.stdout.write(`${message}\n`);
} }
function parseArgs(argv: string[]): RawArgs { function parseCliArgs(argv: string[]): RawArgs {
const result: RawArgs = {}; try {
for (let index = 0; index < argv.length; index += 1) { const parsed = parseNodeArgs({
const token = argv[index]; args: argv,
if (!token.startsWith("--")) { allowPositionals: false,
throw new Error(`存在不支持的参数: ${token}`); strict: true,
options: {
url: { type: "string" },
mode: { type: "string" },
screenshot_mode: { type: "string" },
selector: { type: "string" },
x: { type: "string" },
y: { type: "string" },
width: { type: "string" },
height: { type: "string" },
viewport_width: { type: "string" },
viewport_height: { type: "string" },
wait_ms: { type: "string" },
timeout_ms: { type: "string" },
max_chars: { type: "string" },
max_full_height: { type: "string" },
action_timeout_ms: { type: "string" },
actions: { type: "string" },
actions_file: { type: "string" },
region_width: { type: "string" },
region_height: { type: "string" },
output: { type: "string" },
send: { type: "string" },
},
});
return parsed.values as RawArgs;
} catch (error) {
throw new Error(`命令行参数解析失败: ${errorMessage(error)}`);
} }
const equalIndex = token.indexOf("=");
let key = token.slice(2);
let value: string;
if (equalIndex >= 0) {
key = token.slice(2, equalIndex);
value = token.slice(equalIndex + 1);
} else {
const next = argv[index + 1];
if (next === undefined || next.startsWith("--")) {
value = "true";
} else {
value = next;
index += 1;
}
}
result[key] = value;
}
return result;
} }
function parseNumber( function parseNumber(
@ -421,11 +452,12 @@ function normalizeParams(raw: RawArgs): Params {
throw new Error("send 只能是 auto、true 或 false"); throw new Error("send 只能是 auto、true 或 false");
} }
const selector = (raw.selector || "").trim();
const params: Params = { const params: Params = {
url, url,
mode: mode as Params["mode"], mode: mode as Params["mode"],
screenshotMode: screenshotMode as Params["screenshotMode"], screenshotMode: screenshotMode as Params["screenshotMode"],
selector: raw.selector || "", selector,
x: parseNumber(raw.x, "x"), x: parseNumber(raw.x, "x"),
y: parseNumber(raw.y, "y"), y: parseNumber(raw.y, "y"),
regionWidth: parseNumber( regionWidth: parseNumber(
@ -1715,7 +1747,7 @@ async function maybeSendScreenshot(
} }
async function run(): Promise<void> { async function run(): Promise<void> {
const params = normalizeParams(parseArgs(process.argv.slice(2))); const params = normalizeParams(parseCliArgs(process.argv.slice(2)));
const browser = await launchChromium(params); const browser = await launchChromium(params);
const client = new CdpClient(browser.websocketUrl); const client = new CdpClient(browser.websocketUrl);
try { try {