diff --git a/desktop_env/evaluators/metrics/table.py b/desktop_env/evaluators/metrics/table.py index 78e4090..ebb5fbd 100644 --- a/desktop_env/evaluators/metrics/table.py +++ b/desktop_env/evaluators/metrics/table.py @@ -1,5 +1,5 @@ import logging -import operator +#import operator from numbers import Number from typing import Any, Union, cast, Callable from typing import Dict, List, Tuple @@ -14,7 +14,8 @@ from openpyxl.worksheet.worksheet import Worksheet #from openpyxl.worksheet.cell_range import MultiCellRange from openpyxl.worksheet.datavalidation import DataValidation -from .utils import load_charts, load_sparklines, _match_value_to_rule +from .utils import load_charts, load_sparklines, load_rows_or_cols, load_xlsx_styles +from .utils import _match_value_to_rule logger = logging.getLogger("desktopenv.metric.table") @@ -160,18 +161,19 @@ def compare_table(result: str, expected: str, **options) -> float: logger.debug("Assertion: %s[chart] == %s[chart] - %s", r["sheet_idx0"], r["sheet_idx1"], metric) # }}} Compare Charts # - elif r["type"] == "number_format": - # Compare Number Formats {{{ # + elif r["type"] == "style": + # Compare Style (Also Conditional Formatiing) {{{ # # sheet_idx0: 0 == "RI0" == "RNSheet1" | "EI0" == "ENSheet1" # sheet_idx1: as sheet_idx0 + # props: list of str indicating concerned styles - sheet1: Worksheet = _load_sheet(*parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke)) - sheet2: Worksheet = _load_sheet(*parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke)) - number_formats1: List[str] = [c.number_format.lower() for col in sheet1.iter_cols() for c in col if c.data_type=="n"] - number_formats2: List[str] = [c.number_format.lower() for col in sheet2.iter_cols() for c in col if c.data_type=="n"] - metric: bool = number_formats1 == number_formats2 - logger.debug("Assertion: %s.nf == %s.nf - %s", r["sheet_idx0"], r["sheet_idx1"], metric) - # }}} Compare Number Formats # + styles1: Dict[str, List[Any]] = load_xlsx_styles(*parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke), **r) + styles2: Dict[str, List[Any]] = load_xlsx_styles(*parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke), **r) + #number_formats1: List[str] = [c.number_format.lower() for col in sheet1.iter_cols() for c in col if c.value is not None and c.data_type=="n"] + #number_formats2: List[str] = [c.number_format.lower() for col in sheet2.iter_cols() for c in col if c.value is not None and c.data_type=="n"] + metric: bool = styles1 == styles2 + logger.debug("Assertion: %s.style == %s.style - %s", r["sheet_idx0"], r["sheet_idx1"], metric) + # }}} Compare Style (Also Conditional Formatiing) # elif r["type"] == "freeze": # Compare Freezing {{{ # @@ -203,7 +205,7 @@ def compare_table(result: str, expected: str, **options) -> float: elif r["type"] == "data_validation": # Check Data Validation {{{ # # sheet_idx: 0 == "RI0" == "RNSheet1" | "EI0" == "ENSheet1" - # dv_props: list of dict like {attribute: "method": str, "ref": anythin} + # dv_props: list of dict like {attribute: {"method": str, "ref": anything}} # available attributes: # * ranges # * type @@ -224,14 +226,14 @@ def compare_table(result: str, expected: str, **options) -> float: sheet: Worksheet = _load_sheet(*parse_idx(r["sheet_idx"], xlworkbookr, xlworkbooke)) data_validators: List[DataValidation] = sheet.data_validations.dataValidation - total_metric = True + total_metric = len(data_validators)>=len(r["dv_props"]) for dat_vldt in data_validators: metric = False - for r in r["dv_props"]: + for prpt in r["dv_props"]: metric = metric or all( _match_value_to_rule( getattr(dat_vldt, attrbt) , mr )\ - for attrbt, mr in r.items() + for attrbt, mr in prpt.items() ) if metric: break @@ -243,6 +245,44 @@ def compare_table(result: str, expected: str, **options) -> float: metric: bool = total_metric # }}} Check Data Validation # + elif r["type"] == "row_props": + # Check Row Properties {{{ # + # sheet_idx0: 0 == "RI0" == "RNSheet1" | "EI0" == "ENSheet1" + # sheet_idx1: as sheet_idx0 + # props: list of str, see utils.load_rows_or_cols + + rows1: Dict[str, Any] = load_rows_or_cols( *parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke) + , obj="row" + , **r + ) + rows2: Dict[str, Any] = load_rows_or_cols( *parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke) + , obj="row" + , **r + ) + logger.debug("Rows1: %s", repr(rows1)) + logger.debug("Rows2: %s", repr(rows2)) + metric: bool = rows1 == rows2 + logger.debug("Assertion: %s[rows] == %s[rows] - %s", r["sheet_idx0"], r["sheet_idx1"], metric) + # }}} Check Row Properties # + + elif r["type"] == "col_props": + # Check Row Properties {{{ # + # sheet_idx0: 0 == "RI0" == "RNSheet1" | "EI0" == "ENSheet1" + # sheet_idx1: as sheet_idx0 + # props: list of str, see utils.load_rows_or_cols + + cols1: Dict[str, Any] = load_rows_or_cols( *parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke) + , obj="column" + , **r + ) + cols2: Dict[str, Any] = load_rows_or_cols( *parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke) + , obj="column" + , **r + ) + metric: bool = cols1 == cols2 + logger.debug("Assertion: %s[cols] == %s[cols] - %s", r["sheet_idx0"], r["sheet_idx1"], metric) + # }}} Check Row Properties # + else: raise NotImplementedError("Unimplemented sheet check: {:}".format(r["type"])) @@ -254,15 +294,48 @@ def compare_table(result: str, expected: str, **options) -> float: # }}} function compare_table # if __name__ == '__main__': - path1 = "../../任务数据/LibreOffice Calc/Freeze_row_column.xlsx" - path2 = "../../任务数据/LibreOffice Calc/Freeze_row_column_gold.xlsx" + import datetime + import sys + + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + datetime_str: str = datetime.datetime.now().strftime("%Y%m%d@%H%M%S") + + file_handler = logging.FileHandler(os.path.join("logs", "normal-{:}.log".format(datetime_str))) + debug_handler = logging.FileHandler(os.path.join("logs", "debug-{:}.log".format(datetime_str))) + stdout_handler = logging.StreamHandler(sys.stdout) + sdebug_handler = logging.FileHandler(os.path.join("logs", "sdebug-{:}.log".format(datetime_str))) + + file_handler.setLevel(logging.INFO) + debug_handler.setLevel(logging.DEBUG) + stdout_handler.setLevel(logging.INFO) + sdebug_handler.setLevel(logging.DEBUG) + + formatter = logging.Formatter(fmt="\x1b[1;33m[%(asctime)s \x1b[31m%(levelname)s \x1b[32m%(module)s/%(lineno)d-%(processName)s\x1b[1;33m] \x1b[0m%(message)s") + file_handler.setFormatter(formatter) + debug_handler.setFormatter(formatter) + stdout_handler.setFormatter(formatter) + sdebug_handler.setFormatter(formatter) + + stdout_handler.addFilter(logging.Filter("desktopenv")) + sdebug_handler.addFilter(logging.Filter("desktopenv")) + + logger.addHandler(file_handler) + logger.addHandler(debug_handler) + logger.addHandler(stdout_handler) + logger.addHandler(sdebug_handler) + + path1 = "../../任务数据/LibreOffice Calc/Calendar_Highlight_Weekend_Days.xlsx" + path2 = "../../任务数据/LibreOffice Calc/Calendar_Highlight_Weekend_Days_gold.xlsx" rules = [ { "type": "sheet_data" , "sheet_idx0": 0 , "sheet_idx1": "EI0" } - , { "type": "freeze" + , { "type": "style" , "sheet_idx0": 0 , "sheet_idx1": "EI0" + , "props": ["bgcolor"] } ] print( compare_table( path1, path2 @@ -274,17 +347,31 @@ if __name__ == '__main__': ) ) - #path = "../../任务数据/LibreOffice Calc/Order_Id_Mark_Pass_Fail_gold.xlsx" - #print( check_data_validations( path, [ { "ranges": { "method": "spreadsheet_range" - #, "ref": ["D2:D29", "D2:D1048576"] - #} - #, "type": { "method": "eq" - #, "ref": "list" - #} - #, "formula1": { "method": "str_set_eq" - #, "ref": ["Pass", "Fail", "Held"] - #} - #} - #] - #) - #) + # Row Properties + #path1 = "../../任务数据/LibreOffice Calc/Date_Budget_Variance_HideNA.xlsx" + #path2 = "../../任务数据/LibreOffice Calc/Date_Budget_Variance_HideNA_gold.xlsx" + #workbook: Workbook = openpyxl.load_workbook(filename=path1) + #worksheet: Worksheet = workbook.active + #for r_no, dms in worksheet.column_dimensions.items(): + #print(r_no, type(r_no), type(dms), dms.hidden) + + # Conditional Formats + #import formulas + #path1 = "../../任务数据/LibreOffice Calc/Calendar_Highlight_Weekend_Days.xlsx" + #path2 = "../../任务数据/LibreOffice Calc/Calendar_Highlight_Weekend_Days_gold.xlsx" + #path3 = "../../任务数据/LibreOffice Calc/Calendar_Highlight_Weekend_Days_gold_test.xlsx" + #workbook: Workbook = openpyxl.load_workbook(filename=path2) + #worksheet: Worksheet = workbook.active + #print(worksheet.conditional_formatting) + #for itm in worksheet.conditional_formatting: + #print(itm.cells) + #for r in itm.rules: + #print( r.type, r.formula, r.dxf.font.color.rgb + #, r.dxf.fill.fgColor.rgb, r.dxf.fill.bgColor.rgb + #) + #condition = formulas.Parser().ast("=" + r.formula[0])[1].compile() + ##print(r.type, r.operator, r.dxfId, r.dxf) + #for r in itm.cells: + #for c in r.cells: + #value = worksheet.cell(row=c[0], column=c[1]).value + #print(value, condition(str(value))) diff --git a/desktop_env/evaluators/metrics/utils.py b/desktop_env/evaluators/metrics/utils.py index 841222c..42b4c91 100644 --- a/desktop_env/evaluators/metrics/utils.py +++ b/desktop_env/evaluators/metrics/utils.py @@ -1,6 +1,6 @@ import logging import zipfile -from typing import Any, TypeVar, Union, Iterable, Optional +from typing import Any, TypeVar, Union, Iterable, Optional, Callable from typing import Dict, List, Set, Match from urllib.parse import urlparse, urlunparse import re @@ -17,6 +17,12 @@ from openpyxl import Workbook from openpyxl.chart._chart import ChartBase from openpyxl.worksheet.worksheet import Worksheet from openpyxl.worksheet.cell_range import MultiCellRange +from openpyxl.worksheet.dimensions import DimensionHolder +from openpyxl.formatting.formatting import ConditionalFormattingList +#from openpyxl.utils import get_column_letter +from openpyxl.cell.cell import Cell +from openpyxl.styles.differential import DifferentialStyle +import formulas V = TypeVar("Value") @@ -31,9 +37,8 @@ _xlsx_ns_imapping = dict(map(lambda itm: (itm[1], itm[0]), _xlsx_namespaces)) _sheet_name_selector = lxml.cssselect.CSSSelector("oo|sheets>oo|sheet", namespaces=_xlsx_ns_mapping) _sparklines_selector = lxml.cssselect.CSSSelector("x14|sparkline", namespaces=_xlsx_ns_mapping) def load_sparklines(xlsx_file: str, sheet_name: str) -> Dict[str, str]: + # function load_sparklines {{{ # """ - This function modifies data_frame in-place - Args: xlsx_file (str): path to xlsx sheet_name (str): sheet name @@ -64,6 +69,7 @@ def load_sparklines(xlsx_file: str, sheet_name: str) -> Dict[str, str]: ) sparklines_dict[sparkline["x14:sparkline"]["xm:sqref"]] = sparkline["x14:sparkline"]["xm:f"] return sparklines_dict + # }}} function load_sparklines # # Available Chart Properties: @@ -75,6 +81,7 @@ def load_sparklines(xlsx_file: str, sheet_name: str) -> Dict[str, str]: # direction: "bar" (hori) | "col" (vert) # xtitle, ytitle, ztitle: str def load_charts(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[str, Any]: + # function load_charts {{{ # """ Args: xlsx_file (Workbook): concerned excel book @@ -83,7 +90,12 @@ def load_charts(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[str, An giving the concerned chart properties Returns: - Dict[str, Any]: information of charts + Dict[str, Any]: information of charts, dict like + { + : { + : anything + } + } """ # workbook: Workbook = openpyxl.load_workbook(filename=xlsx_file) @@ -140,7 +152,132 @@ def load_charts(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[str, An info["ztitle"] = ch.z_axis.title.tx.rich.p[0].r[0].t chart_set[series] = info return chart_set + # }}} function load_charts # +# Supported Styles: +# number_format +# font_name - str +# font_family - float +# font_color - in aRGB, e.g., FF000000 is black +# font_bold - bool +# font_italic - bool +# fill_type - "patternFill" | "gradientFill" +# bgcolor - in aRGB, e.g., FFFF0000 is red +# fgcolor - in aRGB, e.g., FF00FFFF is yellow +def _read_cell_style(style_name: str, cell: Cell, diff_style: Optional[DifferentialStyle] = None) -> Any: + if style_name=="number_format": + return (cell.number_format if diff_style is None else diff_style.numFmt.formatCode)\ + if cell.value is not None and cell.data_type=="n" else None + elif style_name=="font_name": + return (diff_style or cell).font.name if cell.value is not None else None + elif style_name=="font_family": + return (diff_style or cell).font.family if cell.value is not None else None + elif style_name=="font_color": + return (diff_style or cell).font.color.rgb if cell.value is not None else None + elif style_name=="font_bold": + return (diff_style or cell).font.bold if cell.value is not None else None + elif style_name=="font_italic": + return (diff_style or cell).font.italic if cell.value is not None else None + elif style_name=="fill_type": + return (diff_style or cell).fill.tagname + elif style_name=="bgcolor": + return (diff_style or cell).fill.bgColor.rgb + elif style_name=="fgcolor": + return (diff_style or cell).fill.fgColor.rgb + else: + raise NotImplementedError("Unsupported Style: {:}".format(style_name)) + +def load_xlsx_styles(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[str, List[Any]]: + # function load_xlsx_styles {{{ # + """ + Args: + xlsx_file (Workbook): concerned excel book + sheet_name (str): sheet name + options (Dict[str, List[str]): dick like {"props": list of str} giving + the concerned styles + + Returns: + Dict[str, List[Any]]: dict like + { + : list of anything indicating concerned + property values + } + """ + + worksheet: Worksheet = xlsx_file[sheet_name] + + style_dict: Dict[str, List[Any]] = {} + concerned_styles: List[str] = options.get("props", []) + + # Handles Cell Styles + for col in worksheet.iter_cols(): + for c in col: + style_list: List[Any] = [] + for st in concerned_styles: + style_list.append(_read_cell_style(st, c)) + style_dict[c.coordinate] = style_list + + # Handles Conditional Formatting + conditional_formattings: ConditionalFormattingList = worksheet.conditional_formatting + formula_parser = formulas.Parser() + for fmt in conditional_formattings: + for r in fmt.rules: + active_cells: List[Cell] = [] + if r.type == "expression": + condition: Callable[[str], bool] = formula_parser.ast("=" + r.formula[0])[1].compile() + for rge in fmt.cells: + for c in rge.cells: + cell: Cell = worksheet.cell(row=c[0], column=c[1]) + if condition(str(cell.value)): + active_cells.append(cell) + else: + raise NotImplementedError("Not Implemented Condition Type: {:}".format(r.type)) + + for c in active_cells: + style_dict[c.coordinate] = [_read_cell_style(st, c, r.dxf) for st in concerned_styles] + + return style_dict + # }}} function load_xlsx_styles # + +# Available Row Properties: +# hidden +# collapsed +# height +# +# Available Column Properties: +# width +# auto_size +# hidden +# collapsed +# min +# max +def load_rows_or_cols(xlsx_file: Workbook, sheet_name: str, **options)\ + -> Dict[Union[int, str], Dict[str, Any]]: + # function load_rows_or_cols {{{ # + """ + Args: + xlsx_file (Workbook): concerned excel book + sheet_name (str): sheet name + options (Dict[str, List[str]]): dict like + {"obj": "row" | "column", "props": list of str} giving the concerned + row/column properties + + Returns: + Dict[Union[int, str], Dict[str, Any]]: row/column information + """ + + worksheet: Worksheet = xlsx_file[sheet_name] + objs: DimensionHolder = getattr(worksheet, "{:}_dimensions".format(options["obj"])) + + obj_set: Dict[int, Any] = {} + obj_props: Set[str] = set(options.get("props", [])) + for obj_no, obj_dms in objs.items(): + info_dict: Dict[str, Any] = {} + for prop in obj_props: + info_dict[prop] = getattr(obj_dms, prop) + obj_set[obj_no] = info_dict + return obj_set + # }}} function load_rows_or_cols # def _match_record(pattern: Dict[str, Any], item: Dict[str, Any]) -> bool: return all(k in item and item[k] == val for k, val in pattern.items()) diff --git a/evaluation_examples/examples/libreoffice_calc/01b269ae-2111-4a07-81fd-3fcd711993b0.json b/evaluation_examples/examples/libreoffice_calc/01b269ae-2111-4a07-81fd-3fcd711993b0.json new file mode 100644 index 0000000..07bd39e --- /dev/null +++ b/evaluation_examples/examples/libreoffice_calc/01b269ae-2111-4a07-81fd-3fcd711993b0.json @@ -0,0 +1,76 @@ +{ + "id": "01b269ae-2111-4a07-81fd-3fcd711993b0", + "snapshot": "libreoffice_calc", + "instruction": "Fill all the blank cells with the value in the cell above it", + "source": "https://www.youtube.com/shorts/VrUzPTIwQ04", + "config": [ + { + "type": "download", + "parameters": { + "files": [ + { + "url": "https://drive.usercontent.google.com/download?id=1FuOZ-5YoKgLLwl_oZd4R3D8pZACf_ukS&export=download&authuser=0&confirm=t&uuid=2051e7a6-5930-4cef-8d77-20ebf66ec6e6&at=APZUnTX1fXqlxy6rluq-Kw-LUhS5:1705919461032", + "path": "/home/user/Student_Level_Fill_Blank.xlsx" + } + ] + } + }, + { + "type": "open", + "parameters": { + "path": "/home/user/Student_Level_Fill_Blank.xlsx" + } + } + ], + "trajectory": "trajectories/01b269ae-2111-4a07-81fd-3fcd711993b0", + "related_apps": [ + "libreoffice calc" + ], + "evaluator": { + "postconfig": [ + { + "type": "activate_window", + "parameters": { + "window_name": "Student_Level_Fill_Blank.xlsx - LibreOffice Calc", + "strict": true + } + }, + { + "type": "sleep", + "parameters": { + "seconds": 0.5 + } + }, + { + "type": "execute", + "parameters": { + "command": [ + "python", + "-c", + "import pyautogui; pyautogui.press([\"ctrl\", \"s\"]);" + ] + } + } + ], + "func": "compare_table", + "expected": { + "type": "cloud_file", + "path": "https://drive.usercontent.google.com/download?id=1HTle3vgdZSjJIK_wjXyjtWwbiYJeguwv&export=download&authuser=0&confirm=t&uuid=c5d0868b-bed2-48fb-949b-8a9f3f61e8cf&at=APZUnTVqS9CTZFJ1rPqCGQPDCv3p:1705919542916", + "dest": "Student_Level_Fill_Blank_gold.xlsx" + }, + "result": { + "type": "vm_file", + "path": "/home/user/Student_Level_Fill_Blank.xlsx", + "dest": "Student_Level_Fill_Blank.xlsx" + }, + "options": { + "rules": [ + { + "type": "sheet_data", + "sheet_idx0": 0, + "sheet_idx1": "EI0" + } + ] + } + } +} diff --git a/evaluation_examples/examples/libreoffice_calc/4e6fcf72-daf3-439f-a232-c434ce416af6.json b/evaluation_examples/examples/libreoffice_calc/4e6fcf72-daf3-439f-a232-c434ce416af6.json new file mode 100644 index 0000000..772c3b1 --- /dev/null +++ b/evaluation_examples/examples/libreoffice_calc/4e6fcf72-daf3-439f-a232-c434ce416af6.json @@ -0,0 +1,76 @@ +{ + "id": "4e6fcf72-daf3-439f-a232-c434ce416af6", + "snapshot": "libreoffice_calc", + "instruction": "Please calculate the ages of the employees according to their birthday.", + "source": "https://www.youtube.com/shorts/0uxJccNCKcE", + "config": [ + { + "type": "download", + "parameters": { + "files": [ + { + "url": "https://drive.usercontent.google.com/download?id=1WIyJbssCCscQ96be2hF9N7tXPz23JoBT&export=download&authuser=0&confirm=t&uuid=503cdbf3-2fe3-4019-bfd1-5d1faab8d049&at=APZUnTV-XLlF8KEx7zMjtX2kYSuM:1705909207212", + "path": "/home/user/Employee_Age_By_Birthday.xlsx" + } + ] + } + }, + { + "type": "open", + "parameters": { + "path": "/home/user/Employee_Age_By_Birthday.xlsx" + } + } + ], + "trajectory": "trajectories/4e6fcf72-daf3-439f-a232-c434ce416af6", + "related_apps": [ + "libreoffice calc" + ], + "evaluator": { + "postconfig": [ + { + "type": "activate_window", + "parameters": { + "window_name": "Employee_Age_By_Birthday.xlsx - LibreOffice Calc", + "strict": true + } + }, + { + "type": "sleep", + "parameters": { + "seconds": 0.5 + } + }, + { + "type": "execute", + "parameters": { + "command": [ + "python", + "-c", + "import pyautogui; pyautogui.press([\"ctrl\", \"s\"]);" + ] + } + } + ], + "func": "compare_table", + "expected": { + "type": "cloud_file", + "path": "https://drive.usercontent.google.com/download?id=1sRI72UGfHiVBRFuV4uwhr173u3Sf46Y6&export=download&authuser=0&confirm=t&uuid=90da5e2b-39c0-449d-b753-09dfed73b509&at=APZUnTVFInccKo2QB9JNnIidFfG3:1705909465173", + "dest": "Employee_Age_By_Birthday_gold.xlsx" + }, + "result": { + "type": "vm_file", + "path": "/home/user/Employee_Age_By_Birthday.xlsx", + "dest": "Employee_Age_By_Birthday.xlsx" + }, + "options": { + "rules": [ + { + "type": "sheet_data", + "sheet_idx0": 0, + "sheet_idx1": "EI0" + } + ] + } + } +} diff --git a/evaluation_examples/examples/libreoffice_calc/6054afcb-5bab-4702-90a0-b259b5d3217c.json b/evaluation_examples/examples/libreoffice_calc/6054afcb-5bab-4702-90a0-b259b5d3217c.json new file mode 100644 index 0000000..b5e9241 --- /dev/null +++ b/evaluation_examples/examples/libreoffice_calc/6054afcb-5bab-4702-90a0-b259b5d3217c.json @@ -0,0 +1,82 @@ +{ + "id": "6054afcb-5bab-4702-90a0-b259b5d3217c", + "snapshot": "libreoffice_calc", + "instruction": "Some data are missed by now and are filled by 'N/A' temporarily. Please hide them in the table for now. Do not delete them and filter is no needed.", + "source": "https://www.youtube.com/shorts/JTbZ8sRxkdU", + "config": [ + { + "type": "download", + "parameters": { + "files": [ + { + "url": "https://drive.usercontent.google.com/download?id=1e1Ccsr_CQau9-boF92GxzZ0RtEHPtfdX&export=download&authuser=0&confirm=t&uuid=a1d4518d-e085-4bfa-ae6f-2514ed48efba&at=APZUnTU_ng4YNBQO7u6Dsuj21Gmq:1705911243359", + "path": "/home/user/Date_Budget_Variance_HideNA.xlsx" + } + ] + } + }, + { + "type": "open", + "parameters": { + "path": "/home/user/Date_Budget_Variance_HideNA.xlsx" + } + } + ], + "trajectory": "trajectories/6054afcb-5bab-4702-90a0-b259b5d3217c", + "related_apps": [ + "libreoffice calc" + ], + "evaluator": { + "postconfig": [ + { + "type": "activate_window", + "parameters": { + "window_name": "Date_Budget_Variance_HideNA.xlsx - LibreOffice Calc", + "strict": true + } + }, + { + "type": "sleep", + "parameters": { + "seconds": 0.5 + } + }, + { + "type": "execute", + "parameters": { + "command": [ + "python", + "-c", + "import pyautogui; pyautogui.press([\"ctrl\", \"s\"]);" + ] + } + } + ], + "func": "compare_table", + "expected": { + "type": "cloud_file", + "path": "https://drive.usercontent.google.com/download?id=1ReZexJAvbAAUng0JD3lEHN70J0WcS0_i&export=download&authuser=0&confirm=t&uuid=a11148b1-93e8-4634-a413-26e0e433c2c9&at=APZUnTV6KulVQf6LpHl4IVNqE5hA:1705914637572", + "dest": "Date_Budget_Variance_HideNA_gold.xlsx" + }, + "result": { + "type": "vm_file", + "path": "/home/user/Date_Budget_Variance_HideNA.xlsx", + "dest": "Date_Budget_Variance_HideNA.xlsx" + }, + "options": { + "rules": [ + { + "type": "sheet_data", + "sheet_idx0": 0, + "sheet_idx1": "EI0" + }, + { + "type": "row_props", + "sheet_idx0": 0, + "sheet_idx1": "EI0", + "props": ["hidden"] + } + ] + } + } +} diff --git a/evaluation_examples/examples/libreoffice_calc/8b1ce5f2-59d2-4dcc-b0b0-666a714b9a14.json b/evaluation_examples/examples/libreoffice_calc/8b1ce5f2-59d2-4dcc-b0b0-666a714b9a14.json new file mode 100644 index 0000000..084bab4 --- /dev/null +++ b/evaluation_examples/examples/libreoffice_calc/8b1ce5f2-59d2-4dcc-b0b0-666a714b9a14.json @@ -0,0 +1,82 @@ +{ + "id": "8b1ce5f2-59d2-4dcc-b0b0-666a714b9a14", + "snapshot": "libreoffice_calc", + "instruction": "Given a partial calendar, please highlight all the weekends (Satureday & Sunday) by setting the cell background as red (#ff0000).", + "source": "https://www.youtube.com/shorts/Hbcwu6IQ1ns", + "config": [ + { + "type": "download", + "parameters": { + "files": [ + { + "url": "https://drive.usercontent.google.com/download?id=1_gyig5Vs3VOuvkjRoLt2ZpXBIyCZfUmV&export=download&authuser=0&confirm=t&uuid=ed113cdd-4279-454b-a66d-07447e31c818&at=APZUnTVztf5DcbF0DjLJitkpUUxt:1705920417565", + "path": "/home/user/Calendar_Highlight_Weekend_Days.xlsx" + } + ] + } + }, + { + "type": "open", + "parameters": { + "path": "/home/user/Calendar_Highlight_Weekend_Days.xlsx" + } + } + ], + "trajectory": "trajectories/8b1ce5f2-59d2-4dcc-b0b0-666a714b9a14", + "related_apps": [ + "libreoffice calc" + ], + "evaluator": { + "postconfig": [ + { + "type": "activate_window", + "parameters": { + "window_name": "Calendar_Highlight_Weekend_Days.xlsx - LibreOffice Calc", + "strict": true + } + }, + { + "type": "sleep", + "parameters": { + "seconds": 0.5 + } + }, + { + "type": "execute", + "parameters": { + "command": [ + "python", + "-c", + "import pyautogui; pyautogui.press([\"ctrl\", \"s\"]);" + ] + } + } + ], + "func": "compare_table", + "expected": { + "type": "cloud_file", + "path": "https://drive.usercontent.google.com/download?id=1URKsHvPdWDvB-qwsIZ-SqHAmiXaosXKW&export=download&authuser=0&confirm=t&uuid=849064c9-7402-48c5-87f6-e5c290e4bd24&at=APZUnTXarmqM0cO4I0z-Lv7MElzX:1705920495794", + "dest": "Calendar_Highlight_Weekend_Days_gold.xlsx" + }, + "result": { + "type": "vm_file", + "path": "/home/user/Calendar_Highlight_Weekend_Days.xlsx", + "dest": "Calendar_Highlight_Weekend_Days.xlsx" + }, + "options": { + "rules": [ + { + "type": "sheet_data", + "sheet_idx0": 0, + "sheet_idx1": "EI0" + }, + { + "type": "style", + "sheet_idx0": 0, + "sheet_idx1": "EI0", + "props": "bgcolor" + } + ] + } + } +} diff --git a/evaluation_examples/examples/libreoffice_calc/abed40dc-063f-4598-8ba5-9fe749c0615d.json b/evaluation_examples/examples/libreoffice_calc/abed40dc-063f-4598-8ba5-9fe749c0615d.json new file mode 100644 index 0000000..4683d1d --- /dev/null +++ b/evaluation_examples/examples/libreoffice_calc/abed40dc-063f-4598-8ba5-9fe749c0615d.json @@ -0,0 +1,76 @@ +{ + "id": "abed40dc-063f-4598-8ba5-9fe749c0615d", + "snapshot": "libreoffice_calc", + "instruction": "Check the names in column \"Names with duplicates\" and put the unique ones in column \"Unique Names\". Keep the original order.", + "source": "https://help.libreoffice.org/7.6/ro/text/scalc/guide/remove_duplicates.html?&DbPAR=SHARED&System=UNIX", + "config": [ + { + "type": "download", + "parameters": { + "files": [ + { + "url": "https://drive.usercontent.google.com/download?id=1A3O37a2M_tkmXHUn6G8kYu73cUMRUZnt&export=download&authuser=0&confirm=t&uuid=9a44147f-15e4-426c-9235-74fdda7439dc&at=APZUnTU4MAD7rODyryb9r0YolrrN:1705918712764", + "path": "/home/user/Names_Duplicate_Unique.xlsx" + } + ] + } + }, + { + "type": "open", + "parameters": { + "path": "/home/user/Names_Duplicate_Unique.xlsx" + } + } + ], + "trajectory": "trajectories/abed40dc-063f-4598-8ba5-9fe749c0615d", + "related_apps": [ + "libreoffice calc" + ], + "evaluator": { + "postconfig": [ + { + "type": "activate_window", + "parameters": { + "window_name": "Names_Duplicate_Unique.xlsx - LibreOffice Calc", + "strict": true + } + }, + { + "type": "sleep", + "parameters": { + "seconds": 0.5 + } + }, + { + "type": "execute", + "parameters": { + "command": [ + "python", + "-c", + "import pyautogui; pyautogui.press([\"ctrl\", \"s\"]);" + ] + } + } + ], + "func": "compare_table", + "expected": { + "type": "cloud_file", + "path": "https://drive.usercontent.google.com/download?id=1GYG97VdmPG9mlhSBjMlMpjsuDsEDWXNB&export=download&authuser=0&confirm=t&uuid=6dd49f77-6a87-4f99-9027-0c74bad23d6d&at=APZUnTWzHV6JFiTPuo2ICUSEZqq8:1705918802025", + "dest": "Names_Duplicate_Unique_gold.xlsx" + }, + "result": { + "type": "vm_file", + "path": "/home/user/Names_Duplicate_Unique.xlsx", + "dest": "Names_Duplicate_Unique.xlsx" + }, + "options": { + "rules": [ + { + "type": "sheet_data", + "sheet_idx0": 0, + "sheet_idx1": "EI0" + } + ] + } + } +} diff --git a/evaluation_examples/examples/libreoffice_calc/ecb0df7a-4e8d-4a03-b162-053391d3afaf.json b/evaluation_examples/examples/libreoffice_calc/ecb0df7a-4e8d-4a03-b162-053391d3afaf.json index 93fb992..2bc7183 100644 --- a/evaluation_examples/examples/libreoffice_calc/ecb0df7a-4e8d-4a03-b162-053391d3afaf.json +++ b/evaluation_examples/examples/libreoffice_calc/ecb0df7a-4e8d-4a03-b162-053391d3afaf.json @@ -52,7 +52,7 @@ } } ], - "func": "check_data_validations", + "func": "compare_table", "options": { "rules": [ { diff --git a/requirements.txt b/requirements.txt index 97019b3..a31275c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,3 +33,4 @@ pymupdf chardet playwright backoff +formulas