Runde

Ein Round ist eine einzelne Interaktion zwischen dem Benutzer und UFO, die eine einzelne Benutzeranfrage verarbeitet. Ein Round ist verantwortlich für die Orchestrierung des HostAgent und des AppAgent, um die Benutzeranfrage zu erfüllen.

Round Lebenszyklus

In einem Round werden die folgenden Schritte ausgeführt

1. Initialisierung der Runde

Zu Beginn einer Round wird das Round-Objekt erstellt, und die Benutzeranfrage wird vom HostAgent verarbeitet, um die geeignete Anwendung zur Erfüllung der Anfrage zu ermitteln.

2. Ausführung der Aktion

Nach der Erstellung orchestriert die Round den HostAgent und den AppAgent zur Ausführung der notwendigen Aktionen, um die Benutzeranfrage zu erfüllen. Die Kernlogik einer Round ist unten dargestellt

def run(self) -> None:
    """
    Run the round.
    """

    while not self.is_finished():

        self.agent.handle(self.context)

        self.state = self.agent.state.next_state(self.agent)
        self.agent = self.agent.state.next_agent(self.agent)
        self.agent.set_state(self.state)

        # If the subtask ends, capture the last snapshot of the application.
        if self.state.is_subtask_end():
            time.sleep(configs["SLEEP_TIME"])
            self.capture_last_snapshot(sub_round_id=self.subtask_amount)
            self.subtask_amount += 1

    self.agent.blackboard.add_requests(
        {"request_{i}".format(i=self.id), self.request}
    )

    if self.application_window is not None:
        self.capture_last_snapshot()

    if self._should_evaluate:
        self.evaluation()

Bei jedem Schritt verarbeitet die Round die Benutzeranfrage, indem sie die handle-Methode des AppAgent oder HostAgent basierend auf dem aktuellen Zustand aufruft. Der Zustand bestimmt den nächsten Agenten zur Bearbeitung der Anfrage und den nächsten zu übernehmenden Zustand.

3. Abschluss der Anfrage

Der AppAgent schließt die Aktionen innerhalb der Anwendung ab. Wenn die Anfrage mehrere Anwendungen umfasst, kann der HostAgent zu einer anderen Anwendung wechseln, um die Aufgabe fortzusetzen.

4. Beendigung der Runde

Sobald die Benutzeranfrage erfüllt ist, wird die Round beendet und die Ergebnisse werden an den Benutzer zurückgegeben. Falls konfiguriert, evaluiert der EvaluationAgent die Vollständigkeit der Round.

Referenz

Basen: ABC

Eine Runde einer Sitzung in UFO. Eine Runde verwaltet eine einzelne Benutzeranfrage und besteht aus mehreren Schritten. Eine Sitzung kann aus mehreren Runden von Interaktionen bestehen.

Initialisiert eine Runde.

Parameter
  • request (str) –

    Die Anfrage der Runde.

  • agent (BasicAgent) –

    Der initiale Agent der Runde.

  • context (Context) –

    Der gemeinsame Kontext der Runde.

  • should_evaluate (bool) –

    Ob die Runde evaluiert werden soll.

  • id (int) –

    Die ID der Runde.

Quellcode in module/basic.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def __init__(
    self,
    request: str,
    agent: BasicAgent,
    context: Context,
    should_evaluate: bool,
    id: int,
) -> None:
    """
    Initialize a round.
    :param request: The request of the round.
    :param agent: The initial agent of the round.
    :param context: The shared context of the round.
    :param should_evaluate: Whether to evaluate the round.
    :param id: The id of the round.
    """

    self._request = request
    self._context = context
    self._agent = agent
    self._state = agent.state
    self._id = id
    self._should_evaluate = should_evaluate

    self._init_context()

agent Eigenschaft beschreibbar

Gibt den Agenten der Runde zurück. Rückgabe: Der Agent der Runde.

application_window Eigenschaft beschreibbar

Gibt die Anwendung der Sitzung zurück. Rückgabe: Die Anwendung der Sitzung.

context Eigenschaft

Gibt den Kontext der Runde zurück. Rückgabe: Der Kontext der Runde.

cost Eigenschaft

Gibt die Kosten der Runde zurück. Rückgabe: Die Kosten der Runde.

id Eigenschaft

Gibt die ID der Runde zurück. Rückgabe: Die ID der Runde.

log_path Eigenschaft

Gibt den Protokollpfad der Runde zurück.

Rückgabe: Der Protokollpfad der Runde.

request Eigenschaft

Gibt die Anfrage der Runde zurück. Rückgabe: Die Anfrage der Runde.

state Eigenschaft beschreibbar

Gibt den Status der Runde zurück. Rückgabe: Der Status der Runde.

step Eigenschaft

Gibt den lokalen Schritt der Runde zurück. Rückgabe: Der Schritt der Runde.

subtask_amount Eigenschaft beschreibbar

Gibt die Anzahl der Teilaufgaben der Runde zurück. Rückgabe: Die Anzahl der Teilaufgaben der Runde.

capture_last_snapshot(sub_round_id=None)

Erfasst den letzten Schnappschuss der Anwendung, einschließlich des Screenshots und der XML-Datei, falls konfiguriert.

Parameter
  • sub_round_id (Optional[int], Standard: None ) –

    Die ID der Unterrunde, Standard ist None.

Quellcode in module/basic.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def capture_last_snapshot(self, sub_round_id: Optional[int] = None) -> None:
    """
    Capture the last snapshot of the application, including the screenshot and the XML file if configured.
    :param sub_round_id: The id of the sub-round, default is None.
    """

    # Capture the final screenshot
    if sub_round_id is None:
        screenshot_save_path = self.log_path + f"action_round_{self.id}_final.png"
    else:
        screenshot_save_path = (
            self.log_path
            + f"action_round_{self.id}_sub_round_{sub_round_id}_final.png"
        )

    if self.application_window is not None:

        try:
            PhotographerFacade().capture_app_window_screenshot(
                self.application_window, save_path=screenshot_save_path
            )

        except Exception as e:
            utils.print_with_color(
                f"Warning: The last snapshot capture failed, due to the error: {e}",
                "yellow",
            )

        if configs.get("SAVE_UI_TREE", False):
            step_ui_tree = ui_tree.UITree(self.application_window)

            ui_tree_path = os.path.join(self.log_path, "ui_trees")

            ui_tree_file_name = (
                f"ui_tree_round_{self.id}_final.json"
                if sub_round_id is None
                else f"ui_tree_round_{self.id}_sub_round_{sub_round_id}_final.json"
            )

            step_ui_tree.save_ui_tree_to_json(
                os.path.join(
                    ui_tree_path,
                    ui_tree_file_name,
                )
            )

        if configs.get("SAVE_FULL_SCREEN", False):

            desktop_save_path = (
                self.log_path
                + f"desktop_round_{self.id}_sub_round_{sub_round_id}_final.png"
            )

            # Capture the desktop screenshot for all screens.
            PhotographerFacade().capture_desktop_screen_screenshot(
                all_screens=True, save_path=desktop_save_path
            )

        # Save the final XML file
        if configs["LOG_XML"]:
            log_abs_path = os.path.abspath(self.log_path)
            xml_save_path = os.path.join(
                log_abs_path,
                (
                    f"xml/action_round_{self.id}_final.xml"
                    if sub_round_id is None
                    else f"xml/action_round_{self.id}_sub_round_{sub_round_id}_final.xml"
                ),
            )

            if issubclass(type(self.agent), HostAgent):

                app_agent: AppAgent = self.agent.get_active_appagent()
                app_agent.Puppeteer.save_to_xml(xml_save_path)
            elif issubclass(type(self.agent), AppAgent):
                app_agent: AppAgent = self.agent
                app_agent.Puppeteer.save_to_xml(xml_save_path)

evaluation()

TODO: Evaluieren Sie die Runde.

Quellcode in module/basic.py
326
327
328
329
330
def evaluation(self) -> None:
    """
    TODO: Evaluate the round.
    """
    pass

is_finished()

Prüft, ob die Runde beendet ist. Rückgabe: True, wenn die Runde beendet ist, andernfalls False.

Quellcode in module/basic.py
129
130
131
132
133
134
135
136
137
def is_finished(self) -> bool:
    """
    Check if the round is finished.
    return: True if the round is finished, otherwise False.
    """
    return (
        self.state.is_round_end()
        or self.context.get(ContextNames.SESSION_STEP) >= configs["MAX_STEP"]
    )

print_cost()

Gibt die Gesamtkosten der Runde aus.

Quellcode in module/basic.py
227
228
229
230
231
232
233
234
235
236
237
def print_cost(self) -> None:
    """
    Print the total cost of the round.
    """

    total_cost = self.cost
    if isinstance(total_cost, float):
        formatted_cost = "${:.2f}".format(total_cost)
        utils.print_with_color(
            f"Request total cost for current round is {formatted_cost}", "yellow"
        )

run()

Führt die Runde aus.

Quellcode in module/basic.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def run(self) -> None:
    """
    Run the round.
    """

    while not self.is_finished():

        self.agent.handle(self.context)

        self.state = self.agent.state.next_state(self.agent)
        self.agent = self.agent.state.next_agent(self.agent)

        self.agent.set_state(self.state)

        # If the subtask ends, capture the last snapshot of the application.
        if self.state.is_subtask_end():
            time.sleep(configs["SLEEP_TIME"])
            self.capture_last_snapshot(sub_round_id=self.subtask_amount)
            self.subtask_amount += 1

    self.agent.blackboard.add_requests(
        {"request_{i}".format(i=self.id): self.request}
    )

    if self.application_window is not None:
        self.capture_last_snapshot()

    if self._should_evaluate:
        self.evaluation()