API 自动化器

UFO 目前支持使用 Win32 API API 自动化器与应用程序的原生 API 进行交互。我们使用 pywin32 库在 Python 中实现它们。API 自动化器现在支持 WordExcel 应用程序,我们正在努力将支持扩展到其他应用程序。

配置

在使用 API 自动化器之前,需要在 config_dev.yaml 文件中设置一些配置。以下是与 API 自动化器相关的配置列表:

配置选项 描述 类型 默认值
USE_APIS 是否允许使用应用程序 API。 布尔值 True
APP_API_PROMPT_ADDRESS 应用程序 API 的提示词地址。 字典 {"WINWORD.EXE": "ufo/prompts/apps/word/api.yaml", "EXCEL.EXE": "ufo/prompts/apps/excel/api.yaml", "msedge.exe": "ufo/prompts/apps/web/api.yaml", "chrome.exe": "ufo/prompts/apps/web/api.yaml"}

注意

API 自动化器目前仅支持 WINWORD.EXEEXCEL.EXE

接收器

API 自动化器接收器的基类是 ufo/automator/app_apis/basic 模块中定义的 WinCOMReceiverBasic 类。它使用应用程序的 win32 COM 对象进行初始化,并提供与应用程序原生 API 交互的功能。以下是 WinCOMReceiverBasic 类的参考:

基类:ReceiverBasic

Windows COM 客户端的基类。

初始化 Windows COM 客户端。

参数
  • app_root_name (str) –

    应用程序的根名称。

  • process_name (str) –

    进程名称。

  • clsid (str) –

    COM 对象的 CLSID。

源代码位于 automator/app_apis/basic.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def __init__(self, app_root_name: str, process_name: str, clsid: str) -> None:
    """
    Initialize the Windows COM client.
    :param app_root_name: The app root name.
    :param process_name: The process name.
    :param clsid: The CLSID of the COM object.
    """

    self.app_root_name = app_root_name
    self.process_name = process_name

    self.clsid = clsid

    self.client = win32com.client.Dispatch(self.clsid)
    self.com_object = self.get_object_from_process_name()

full_path property

获取进程的完整路径。

返回
  • 字符串

    进程的完整路径。

app_match(object_name_list)

检查进程名称是否与应用程序根匹配。

参数
  • object_name_list (List[str]) –

    对象名称列表。

返回
  • 字符串

    匹配的对象名称。

源代码位于 automator/app_apis/basic.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def app_match(self, object_name_list: List[str]) -> str:
    """
    Check if the process name matches the app root.
    :param object_name_list: The list of object name.
    :return: The matched object name.
    """

    suffix = self.get_suffix_mapping()

    if self.process_name.endswith(suffix):
        clean_process_name = self.process_name[: -len(suffix)]
    else:
        clean_process_name = self.process_name

    if not object_name_list:
        return ""

    return max(
        object_name_list,
        key=lambda x: self.longest_common_substring_length(clean_process_name, x),
    )

close()

关闭应用程序。

源代码位于 automator/app_apis/basic.py
110
111
112
113
114
115
116
117
def close(self) -> None:
    """
    Close the app.
    """
    try:
        self.com_object.Close()
    except:
        pass

get_object_from_process_name() abstractmethod

从进程名称获取对象。

源代码位于 automator/app_apis/basic.py
36
37
38
39
40
41
@abstractmethod
def get_object_from_process_name(self) -> win32com.client.CDispatch:
    """
    Get the object from the process name.
    """
    pass

get_suffix_mapping()

获取后缀映射。

返回
  • 字典[字符串, 字符串]

    后缀映射。

源代码位于 automator/app_apis/basic.py
43
44
45
46
47
48
49
50
51
52
53
54
55
def get_suffix_mapping(self) -> Dict[str, str]:
    """
    Get the suffix mapping.
    :return: The suffix mapping.
    """
    suffix_mapping = {
        "WINWORD.EXE": "docx",
        "EXCEL.EXE": "xlsx",
        "POWERPNT.EXE": "pptx",
        "olk.exe": "msg",
    }

    return suffix_mapping.get(self.app_root_name, None)

longest_common_substring_length(str1, str2) staticmethod

获取两个字符串的最长公共子字符串。

参数
  • str1 (str) –

    第一个字符串。

  • str2 (str) –

    第二个字符串。

返回
  • int

    最长公共子字符串的长度。

源代码位于 automator/app_apis/basic.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@staticmethod
def longest_common_substring_length(str1: str, str2: str) -> int:
    """
    Get the longest common substring of two strings.
    :param str1: The first string.
    :param str2: The second string.
    :return: The length of the longest common substring.
    """

    m = len(str1)
    n = len(str2)

    dp = [[0] * (n + 1) for _ in range(m + 1)]

    max_length = 0

    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
                if dp[i][j] > max_length:
                    max_length = dp[i][j]
            else:
                dp[i][j] = 0

    return max_length

save()

保存应用程序的当前状态。

源代码位于 automator/app_apis/basic.py
91
92
93
94
95
96
97
98
def save(self) -> None:
    """
    Save the current state of the app.
    """
    try:
        self.com_object.Save()
    except:
        pass

save_to_xml(file_path)

将应用程序的当前状态保存到 XML。

参数
  • file_path (字符串) –

    保存 XML 的文件路径。

源代码位于 automator/app_apis/basic.py
100
101
102
103
104
105
106
107
108
def save_to_xml(self, file_path: str) -> None:
    """
    Save the current state of the app to XML.
    :param file_path: The file path to save the XML.
    """
    try:
        self.com_object.SaveAs(file_path, self.xml_format_code)
    except:
        pass

WordExcel 应用程序的接收器继承自 WinCOMReceiverBasic 类。WordReceiverExcelReceiver 类分别在 ufo/automator/app_apis/wordufo/automator/app_apis/excel 模块中定义。

命令

WordExcel 应用程序的 API 自动化器命令位于 ufo/automator/app_apis/{app_name} 文件夹中的 client 模块,继承自 WinCOMCommand 类。它封装了执行操作所需的功能和参数。下面是一个继承自 SelectTextCommand 类的 WordCommand 示例:

@WordWinCOMReceiver.register
class SelectTextCommand(WinCOMCommand):
    """
    The command to select text.
    """

    def execute(self):
        """
        Execute the command to select text.
        :return: The selected text.
        """
        return self.receiver.select_text(self.params.get("text"))

    @classmethod
    def name(cls) -> str:
        """
        The name of the command.
        """
        return "select_text"

注意

具体的命令类必须实现 execute 方法来执行操作,以及 name 方法来返回原子命令的名称。

注意

每个命令都必须使用 register 装饰器向具体的 WinCOMReceiver 注册才能执行。

以下是 UFO 目前支持的 API 自动化器中的可用命令列表:

Word API 命令

命令名称 函数名称 描述
InsertTableCommand insert_table 在 Word 文档中插入表格。
SelectTextCommand select_text 选择 Word 文档中的文本。
SelectTableCommand select_table 选择 Word 文档中的表格。

Excel API 命令

命令名称 函数名称 描述
GetSheetContentCommand get_sheet_content 获取 Excel 应用程序中工作表的内容。
Table2MarkdownCommand table2markdown 将 Excel 应用程序工作表中的表格内容转换为 Markdown 格式。
InsertExcelTableCommand insert_excel_table 向 Excel 工作表中插入表格。

提示

有关命令的提示详细信息,请参阅 ufo/prompts/apps/{app_name}/api.yaml 文件。

提示

您可以通过向 ufo/automator/app_apis/{app_name}/ 模块添加新的命令类来自定义命令。