"""仿真 RPA 档位:演示 RpaVideoSession + launch_persistent_browser(需浏览器,默认开发档)。""" from __future__ import annotations import asyncio import os from datetime import datetime from jiangchang_skill_core import config from jiangchang_skill_core.rpa import anti_detect, artifacts, errors, launch_persistent_browser from jiangchang_skill_core.rpa.human_login import wait_for_captcha_pass from jiangchang_skill_core.rpa.video_session import RpaVideoSession from util.constants import SKILL_SLUG from util.runtime_paths import get_skill_data_dir, get_skill_root from .base import AdapterBase, ExampleItem, ExampleResult class SimRpaAdapter(AdapterBase): name = "sim_rpa" def do_batch(self, target: str, items: list[ExampleItem]) -> ExampleResult: return asyncio.run(self._do_batch_async(target, items)) async def _do_batch_async(self, target: str, items: list[ExampleItem]) -> ExampleResult: example_path = os.path.join(get_skill_root(), ".env.example") config.ensure_env_file(SKILL_SLUG, example_path) url = config.get("TARGET_BASE_URL") or target or "https://example.com" batch_id = f"sim_{datetime.now().strftime('%Y%m%d_%H%M%S')}" data_dir = get_skill_data_dir() profile_dir = os.path.join(data_dir, "browser-profile") os.makedirs(profile_dir, exist_ok=True) try: from playwright.async_api import async_playwright except ImportError: return ExampleResult( ok=False, serial_no=None, error_msg="playwright not installed", artifacts={}, ) artifact_paths: dict = {} async with RpaVideoSession( skill_slug=SKILL_SLUG, skill_data_dir=data_dir, batch_id=batch_id, title="技能仿真演示", ) as video: video.add_step("正在打开目标页面") try: async with async_playwright() as pw: context = await launch_persistent_browser( pw, profile_dir=profile_dir, headless=config.get_bool("OPENCLAW_BROWSER_HEADLESS"), ) page = context.pages[0] if context.pages else await context.new_page() await page.goto(url, wait_until="domcontentloaded", timeout=60_000) await anti_detect.human_mouse_wiggle(page) search = page.locator('input[type="search"], input[name="q"]').first if await search.count() > 0: demo_text = items[0].label if items else "openclaw-demo" video.step("正在填写演示内容") await anti_detect.human_type(page, search, demo_text) await anti_detect.human_delay_short() video.step("正在等待人工验证(如有)") if not await wait_for_captcha_pass( page, timeout_sec=config.get_int("HUMAN_WAIT_TIMEOUT", 180), ): shot = await artifacts.capture_failure( page, data_dir, batch_id, "captcha" ) if shot: artifact_paths["captcha"] = shot return ExampleResult( ok=False, serial_no=None, error_msg=errors.ERR_CAPTCHA_NEED_HUMAN, artifacts={**artifact_paths, **video.to_artifact_dict()}, ) video.step("演示任务完成") await context.close() except Exception as exc: video.step("演示异常结束") return ExampleResult( ok=False, serial_no=None, error_msg=str(exc), artifacts={**artifact_paths, **video.to_artifact_dict()}, ) arts = {"mode": "sim_rpa", "url": url, **artifact_paths, **video.to_artifact_dict()} if video.output_video_path: arts["video_path"] = video.output_video_path return ExampleResult( ok=True, serial_no=f"SIM-{len(items)}", error_msg=None, artifacts=arts, )