Files
skill-template/scripts/service/example_adapter/sim_rpa.py

98 lines
3.8 KiB
Python

"""仿真 RPA 档位:演示共享库 browser / anti_detect 用法(需浏览器,默认开发档)。"""
from __future__ import annotations
import asyncio
import os
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 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 = "sim-demo"
data_dir = get_skill_data_dir()
profile_dir = os.path.join(data_dir, "browser-profile")
os.makedirs(profile_dir, exist_ok=True)
record_video = config.get_bool("OPENCLAW_RECORD_VIDEO")
video_dir = os.path.join(data_dir, "rpa-artifacts", batch_id, "video") if record_video else None
if video_dir:
os.makedirs(video_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 = {}
try:
async with async_playwright() as pw:
context = await launch_persistent_browser(
pw,
profile_dir=profile_dir,
headless=config.get_bool("OPENCLAW_BROWSER_HEADLESS"),
record_video_dir=video_dir,
)
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 输入框则尝试输入
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"
await anti_detect.human_type(page, search, demo_text)
await anti_detect.human_delay_short()
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,
)
await context.close()
except Exception as exc:
return ExampleResult(
ok=False,
serial_no=None,
error_msg=str(exc),
artifacts=artifact_paths,
)
return ExampleResult(
ok=True,
serial_no=f"SIM-{len(items)}",
error_msg=None,
artifacts={"mode": "sim_rpa", "url": url, **artifact_paths},
)