66 lines
2.2 KiB
Python
Raw Permalink Normal View History

2025-12-19 16:24:04 +08:00
# MIT License
# Copyright (c) 2024
"""LLM 抽象与 Dummy 实现。"""
from abc import ABC, abstractmethod
from typing import Any, Dict, List
import yaml
from .schema import DSLSpec, EventRecord
PROMPT_TEMPLATE = """你是一名自动化工程师,请将以下事件序列归纳为可参数化的自动化 DSL。
事件序列使用 JSON 描述每个事件包含 kindcontrolAutomationId/Name/ClassName/ControlType/BoundingRect
输出 YAML字段包括paramsstepsassertionsretry_policywaits支持 steps 内的 if/elsefor_each
输出示例
params:
text: "示例参数"
steps:
- action: click
target: {{AutomationId: "15", ControlType: "Edit"}}
- action: type
target: {{AutomationId: "15"}}
text: "{{text}}"
assertions:
- "输入框非空"
retry_policy: {{max_attempts: 2, interval: 1.0}}
waits: {{appear: 5.0, disappear: 5.0}}
现在请基于输入事件生成 YAML"""
class LLMClient(ABC):
"""LLM 抽象接口。"""
@abstractmethod
def generate(self, events: List[EventRecord]) -> DSLSpec:
"""将事件序列转为 DSL 规格。"""
class DummyLLM(LLMClient):
"""离线 dummy实现一个简单的规则映射。"""
def generate(self, events: List[EventRecord]) -> DSLSpec:
steps: List[Dict[str, Any]] = []
for ev in events:
ctrl = ev.control.dict(by_alias=True) if ev.control else {}
if ev.kind == "mouse_click":
steps.append({"action": "click", "target": ctrl})
elif ev.kind == "key_down" and ev.data.get("name"):
# 仅在按键时记录输入
steps.append({"action": "type", "target": ctrl, "text": ev.data.get("name")})
if not steps:
steps.append({"action": "assert_exists", "target": {"Name": "dummy"}})
spec = DSLSpec(
params={},
steps=steps,
assertions=["dummy generated"],
)
return spec
def render_prompt(events: List[EventRecord]) -> str:
"""把事件序列渲染到 prompt。"""
event_dicts = [ev.dict(by_alias=True) for ev in events]
return f"{PROMPT_TEMPLATE}\n\n{yaml.safe_dump(event_dicts, allow_unicode=True)}"