66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
|
|
# 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 描述,每个事件包含 kind、control(AutomationId/Name/ClassName/ControlType/BoundingRect)等。
|
|||
|
|
输出 YAML,字段包括:params、steps、assertions、retry_policy、waits,支持 steps 内的 if/else、for_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)}"
|
|||
|
|
|