122 lines
3.4 KiB
JavaScript
122 lines
3.4 KiB
JavaScript
/**
|
||
* demo.js — 使用示例
|
||
*
|
||
* 两种启动方式:
|
||
*
|
||
* 方式 1(推荐):先手动启动浏览器,再运行 demo
|
||
* chrome --remote-debugging-port=9222 --user-data-dir="~/.gemini-skill/browser-data"
|
||
* (也可以用 Edge:msedge --remote-debugging-port=9222 --user-data-dir=...)
|
||
* node src/demo.js
|
||
*
|
||
* 方式 2:让 skill 自动检测并启动浏览器
|
||
* node src/demo.js
|
||
* (或指定路径:BROWSER_PATH="C:/..." node src/demo.js)
|
||
*
|
||
* 所有配置项见 .env,可直接编辑或通过命令行设环境变量。
|
||
*/
|
||
import { execSync } from 'node:child_process';
|
||
import { platform } from 'node:os';
|
||
import { createGeminiSession, disconnect } from './index.js';
|
||
|
||
// ── Demo 专用:杀掉所有 Chromium 系浏览器进程 ──
|
||
function killAllBrowserProcesses() {
|
||
const os = platform();
|
||
const commands = os === 'win32'
|
||
? [
|
||
'taskkill /F /IM msedge.exe /T',
|
||
'taskkill /F /IM chrome.exe /T',
|
||
'taskkill /F /IM chromium.exe /T',
|
||
]
|
||
: [
|
||
'pkill -f msedge || true',
|
||
'pkill -f chrome || true',
|
||
'pkill -f chromium || true',
|
||
];
|
||
|
||
for (const cmd of commands) {
|
||
try {
|
||
execSync(cmd, { stdio: 'ignore', timeout: 5000 });
|
||
} catch {
|
||
// 进程不存在时会报错,忽略
|
||
}
|
||
}
|
||
console.log('[demo] 已清理所有浏览器进程');
|
||
}
|
||
|
||
/** 异步等待 */
|
||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||
|
||
/**
|
||
* 创建会话,如果因浏览器目录被锁而失败,自动杀掉全部浏览器进程后重试一次
|
||
*/
|
||
async function createSessionWithRetry() {
|
||
// 禁止 Puppeteer 在 Ctrl+C 等信号时自动杀浏览器进程,
|
||
// 由 demo 自己处理 SIGINT → disconnect,浏览器保持运行可复用。
|
||
const opts = {
|
||
debugOpts: {
|
||
handleSIGINT: false,
|
||
handleSIGTERM: false,
|
||
handleSIGHUP: false,
|
||
},
|
||
};
|
||
|
||
try {
|
||
return await createGeminiSession(opts);
|
||
} catch (err) {
|
||
const msg = err.message || '';
|
||
const isLocked = msg.includes('EPERM') || msg.includes('lock') || msg.includes('already');
|
||
|
||
if (!isLocked) throw err;
|
||
|
||
console.warn(
|
||
`[demo] 浏览器数据目录被占用,正在清理所有浏览器进程后重试...\n` +
|
||
` 原始错误:${msg}`
|
||
);
|
||
|
||
killAllBrowserProcesses();
|
||
await sleep(2000);
|
||
|
||
// 重试一次,还失败就直接抛出
|
||
return await createGeminiSession(opts);
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
console.log('=== Gemini Skill Demo ===\n');
|
||
|
||
// 创建会话:自带杀进程重试逻辑
|
||
const { ops } = await createSessionWithRetry();
|
||
|
||
// ── Ctrl+C 时只断开连接,不杀浏览器进程(下次可复用) ──
|
||
process.on('SIGINT', () => {
|
||
console.log('\n[demo] Ctrl+C 收到,断开浏览器连接(浏览器保持运行)...');
|
||
disconnect();
|
||
process.exit(0);
|
||
});
|
||
|
||
try {
|
||
// 1. 探测页面状态
|
||
console.log('[1] 探测页面元素...');
|
||
const probe = await ops.probe();
|
||
console.log('probe:', JSON.stringify(probe, null, 2));
|
||
|
||
// 2. 发送一句话
|
||
console.log('\n[2] 发送提示词...');
|
||
const result = await ops.sendAndWait('Hello Gemini!', {
|
||
timeout: 60_000,
|
||
onPoll(poll) {
|
||
console.log(` polling... status=${poll.status}`);
|
||
},
|
||
});
|
||
console.log('result:', JSON.stringify(result, null, 2));
|
||
|
||
} catch (err) {
|
||
console.error('Error:', err);
|
||
} finally {
|
||
disconnect();
|
||
console.log('\n[done]');
|
||
}
|
||
}
|
||
|
||
main().catch(console.error);
|