Einwickeln der nativen API Ihrer App
UFO führt Aktionen auf Anwendungen basierend auf UI-Steuerelementen durch, aber die Bereitstellung nativer API für seine Toolkits kann die Effizienz und Genauigkeit der Aktionen verbessern. Dieses Dokument bietet Anleitungen zum Einwickeln der nativen API Ihrer Anwendung in die Toolkits von UFO.
Wie wickeln Sie die native API Ihrer App ein?
Vor der Entwicklung der Wrapper für native APIs empfehlen wir dringend, sich mit dem Design des Automator vertraut zu machen.
Schritt 1: Erstellen Sie einen Empfänger für die native API
Der Receiver ist eine Klasse, die die Aufrufe der nativen API vom AppAgent empfängt und ausführt. Um die native API Ihrer Anwendung einzubinden, müssen Sie eine Receiver-Klasse erstellen, die die Methoden zur Ausführung der Aufrufe der nativen API enthält.
Um eine Receiver-Klasse zu erstellen, befolgen Sie diese Schritte:
1. Erstellen Sie einen Ordner für Ihre Anwendung
- Navigieren Sie zum Verzeichnis
ufo/automator/app_api/. - Erstellen Sie einen Ordner mit dem Namen Ihrer Anwendung.
2. Erstellen Sie eine Python-Datei
- Fügen Sie im gerade erstellten Ordner eine Python-Datei mit dem Namen Ihrer Anwendung hinzu, z. B.
{your_application}_client.py.
3. Definieren Sie die Empfängerklasse
- Definieren Sie in der Python-Datei eine Klasse namens
{Your_Receiver}, die von der KlasseReceiverBasicausufo/automator/basic.pyerbt. - Initialisieren Sie die Klasse
Your_Receivermit dem Objekt, das die Aufrufe der nativen API ausführt. Wenn Ihre API beispielsweise auf einemcom-Objekt basiert, initialisieren Sie dascom-Objekt in der Methode__init__der KlasseYour_Receiver.
Beispiel für die Klasse WinCOMReceiverBasic
class WinCOMReceiverBasic(ReceiverBasic):
"""
The base class for Windows COM client.
"""
_command_registry: Dict[str, Type[CommandBasic]] = {}
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()
4. Definieren Sie Methoden zur Ausführung von Aufrufen der nativen API
- Definieren Sie die Methoden in der Klasse
Your_Receiver, um die Aufrufe der nativen API auszuführen.
Beispiel für die Klasse ExcelWinCOMReceiver
def table2markdown(self, sheet_name: str) -> str:
"""
Convert the table in the sheet to a markdown table string.
:param sheet_name: The sheet name.
:return: The markdown table string.
"""
sheet = self.com_object.Sheets(sheet_name)
data = sheet.UsedRange()
df = pd.DataFrame(data[1:], columns=data[0])
df = df.dropna(axis=0, how="all")
df = df.applymap(self.format_value)
return df.to_markdown(index=False)
5. Erstellen Sie eine Factory-Klasse
- Erstellen Sie Ihre Factory-Klasse, die von der Klasse
APIReceiverFactoryerbt, um mehrereReceiver-Klassen zu verwalten, die denselben API-Typ gemeinsam nutzen. - Implementieren Sie die Methoden
create_receiverundnamein der KlasseReceiverFactory. Die Methodecreate_receiversollte dieReceiver-Klasse zurückgeben. - Standardmäßig nimmt
create_receiverdie Parameterapp_root_nameundprocess_nameentgegen und gibt dieReceiver-Klasse zurück. - Registrieren Sie die
ReceiverFactory-Klasse mit dem Decorator@ReceiverManager.register.
Beispiel für die Klasse COMReceiverFactory
from ufo.automator.puppeteer import ReceiverManager
@ReceiverManager.register
class COMReceiverFactory(APIReceiverFactory):
"""
The factory class for the COM receiver.
"""
def create_receiver(self, app_root_name: str, process_name: str) -> WinCOMReceiverBasic:
"""
Create the wincom receiver.
:param app_root_name: The app root name.
:param process_name: The process name.
:return: The receiver.
"""
com_receiver = self.__com_client_mapper(app_root_name)
clsid = self.__app_root_mappping(app_root_name)
if clsid is None or com_receiver is None:
# print_with_color(f"Warning: Win32COM API is not supported for {process_name}.", "yellow")
return None
return com_receiver(app_root_name, process_name, clsid)
@classmethod
def name(cls) -> str:
"""
Get the name of the receiver factory.
:return: The name of the receiver factory.
"""
return "COM"
Hinweis
Die Methode create_receiver sollte None zurückgeben, wenn die Anwendung nicht unterstützt wird.
Hinweis
Sie müssen Ihre ReceiverFactory mit dem Decorator @ReceiverManager.register registrieren, damit der ReceiverManager die ReceiverFactory verwalten kann.
Die Receiver-Klasse ist nun bereit, die Aufrufe der nativen API vom AppAgent zu empfangen.
Schritt 2: Erstellen Sie einen Befehl für die native API
Befehle sind die Aktionen, die der AppAgent auf der Anwendung ausführen kann. Um einen Befehl für die native API zu erstellen, müssen Sie eine Command-Klasse erstellen, die die Methode zur Ausführung der Aufrufe der nativen API enthält.
1. Erstellen Sie eine Befehlsklasse
- Erstellen Sie eine
Command-Klasse in derselben Python-Datei, in der sich dieReceiver-Klasse befindet. DieCommand-Klasse sollte von der KlasseCommandBasicausufo/automator/basic.pyerben.
Beispiel
class WinCOMCommand(CommandBasic):
"""
The abstract command interface.
"""
def __init__(self, receiver: WinCOMReceiverBasic, params=None) -> None:
"""
Initialize the command.
:param receiver: The receiver of the command.
"""
self.receiver = receiver
self.params = params if params is not None else {}
@abstractmethod
def execute(self):
pass
@classmethod
def name(cls) -> str:
"""
Get the name of the command.
:return: The name of the command.
"""
return cls.__name__
2. Definieren Sie die Execute-Methode
- Definieren Sie die Methode
executein derCommand-Klasse, um den Empfänger aufzurufen und die Aufrufe der nativen API auszuführen.
Beispiel
def execute(self):
"""
Execute the command to insert a table.
:return: The inserted table.
"""
return self.receiver.insert_excel_table(
sheet_name=self.params.get("sheet_name", 1),
table=self.params.get("table"),
start_row=self.params.get("start_row", 1),
start_col=self.params.get("start_col", 1),
)
3. Registrieren Sie die Befehlsklasse
- Registrieren Sie die
Command-Klasse in der entsprechendenReceiver-Klasse mit dem Decorator@your_receiver.register.
Beispiel
@ExcelWinCOMReceiver.register
class InsertExcelTable(WinCOMCommand):
...
Die Command-Klasse ist nun in der Receiver-Klasse registriert und für den AppAgent verfügbar, um die Aufrufe der nativen API auszuführen.
Schritt 3: Stellen Sie Prompt-Beschreibungen für die native API bereit
Damit der AppAgent die Nutzung der nativen API-Aufrufe versteht, müssen Sie Prompt-Beschreibungen bereitstellen.
1. Erstellen Sie eine api.yaml-Datei
- Create an `api.yaml` file in the `ufo/prompts/apps/{your_app_name}` directory.
2. Definieren Sie Prompt-Beschreibungen
- Definieren Sie die Prompt-Beschreibungen für die Aufrufe der nativen API in der Datei
api.yaml.
Beispiel
table2markdown:
summary: |-
"table2markdown" is to get the table content in a sheet of the Excel app and convert it to markdown format.
class_name: |-
GetSheetContent
usage: |-
[1] API call: table2markdown(sheet_name: str)
[2] Args:
- sheet_name: The name of the sheet in the Excel app.
[3] Example: table2markdown(sheet_name="Sheet1")
[4] Available control item: Any control item in the Excel app.
[5] Return: the markdown format string of the table content of the sheet.
Hinweis
table2markdown ist der Name des Aufrufs der nativen API. Er MUSS mit dem in der entsprechenden Command-Klasse definierten name() übereinstimmen!
3. Registrieren Sie die Prompt-Adresse in config_dev.yaml
- Registrieren Sie die Prompt-Adresse, indem Sie das Feld
APP_API_PROMPT_ADDRESSder Dateiconfig_dev.yamlmit dem Programmnamen der Anwendung als Schlüssel und der Adresse der Prompt-Datei als Wert hinzufügen.
Beispiel
APP_API_PROMPT_ADDRESS: {
"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"
"your_application_program_name": "YOUR_APPLICATION_API_PROMPT"
}
Hinweis
your_application_program_name muss dem Namen des Anwendungsprogramms entsprechen.
Der AppAgent kann nun die Prompt-Beschreibungen verwenden, um die Nutzung der Aufrufe der nativen API zu verstehen.
Wenn Sie diese Schritte befolgen, haben Sie die native API Ihrer Anwendung erfolgreich in die Toolkits von UFO integriert, sodass der AppAgent die Aufrufe der nativen API auf der Anwendung ausführen kann!