Files
sci-gui-agent-benchmark/mm_agents/aworldguiagent/grounding.py
2025-09-23 16:50:29 +08:00

5253 lines
207 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
This code is adapted from AgentS2 (https://github.com/simular-ai/Agent-S)
with modifications to suit specific requirements.
"""
import ast
import re
import textwrap
from collections import defaultdict
from io import BytesIO
from typing import Any, Dict, List, Optional, Tuple, Union
import pytesseract
from PIL import Image
from pytesseract import Output
from aworld.models.llm import get_llm_model, call_llm_model
from aworld.config.conf import AgentConfig
from mm_agents.aworldguiagent.utils import encode_image, parse_single_code_from_string
class ACI:
def __init__(self):
self.notes: List[str] = []
# Agent action decorator
def agent_action(func):
func.is_agent_action = True
return func
UBUNTU_APP_SETUP = f"""import subprocess;
import difflib;
import pyautogui;
pyautogui.press('escape');
time.sleep(0.5);
output = subprocess.check_output(['wmctrl', '-lx']);
output = output.decode('utf-8').splitlines();
window_titles = [line.split(None, 4)[2] for line in output];
closest_matches = difflib.get_close_matches('APP_NAME', window_titles, n=1, cutoff=0.1);
if closest_matches:
closest_match = closest_matches[0];
for line in output:
if closest_match in line:
window_id = line.split()[0]
break;
subprocess.run(['wmctrl', '-ia', window_id])
subprocess.run(['wmctrl', '-ir', window_id, '-b', 'add,maximized_vert,maximized_horz'])
"""
SET_CELL_VALUES_CMD = """import uno
import subprocess
def identify_document_type(component):
if component.supportsService("com.sun.star.sheet.SpreadsheetDocument"):
return "Calc"
if component.supportsService("com.sun.star.text.TextDocument"):
return "Writer"
if component.supportsService("com.sun.star.sheet.PresentationDocument"):
return "Impress"
return None
def cell_ref_to_indices(cell_ref):
column_letters = ''.join(filter(str.isalpha, cell_ref))
row_number = ''.join(filter(str.isdigit, cell_ref))
col = sum((ord(char.upper()) - ord('A') + 1) * (26**idx) for idx, char in enumerate(reversed(column_letters))) - 1
row = int(row_number) - 1
return col, row
def set_cell_values(new_cell_values: dict[str, str], app_name: str = "Untitled 1", sheet_name: str = "Sheet1"):
new_cell_values_idx = {{}}
for k, v in new_cell_values.items():
try:
col, row = cell_ref_to_indices(k)
except:
col = row = None
if col is not None and row is not None:
new_cell_values_idx[(col, row)] = v
# Clean up previous TCP connections.
# subprocess.run(
# 'echo \"osworld-public-evaluation\" | sudo -S ss --kill --tcp state TIME-WAIT sport = :2002',
# shell=True,
# check=True,
# text=True,
# capture_output=True
# )
# Dynamically allow soffice to listen on port 2002.
subprocess.run(
[
"soffice",
"--accept=socket,host=localhost,port=2002;urp;StarOffice.Service"
]
)
local_context = uno.getComponentContext()
resolver = local_context.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", local_context
)
context = resolver.resolve(
f"uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext"
)
desktop = context.ServiceManager.createInstanceWithContext(
"com.sun.star.frame.Desktop", context
)
# Collect all LibreOffice-related opened windows.
documents = []
for i, component in enumerate(desktop.Components):
title = component.Title
doc_type = identify_document_type(component)
documents.append((i, component, title, doc_type))
# Find the LibreOffice Calc app and the sheet of interest.
spreadsheet = [doc for doc in documents if doc[3] == "Calc"]
selected_spreadsheet = [doc for doc in spreadsheet if doc[2] == app_name]
if spreadsheet:
try:
if selected_spreadsheet:
spreadsheet = selected_spreadsheet[0][1]
else:
spreadsheet = spreadsheet[0][1]
sheet = spreadsheet.Sheets.getByName(sheet_name)
except:
raise ValueError(f"Could not find sheet {{sheet_name}} in {{app_name}}.")
for (col, row), value in new_cell_values_idx.items():
cell = sheet.getCellByPosition(col, row)
# Set the cell value.
if isinstance(value, (int, float)):
cell.Value = value
elif isinstance(value, str):
if value.startswith("="):
cell.Formula = value
else:
cell.String = value
elif isinstance(value, bool):
cell.Value = 1 if value else 0
elif value is None:
cell.clearContents(0)
else:
raise ValueError(f"Unsupported cell value type: {{type(value)}}")
else:
raise ValueError(f"Could not find LibreOffice Calc app corresponding to {{app_name}}.")
set_cell_values(new_cell_values={cell_values}, app_name="{app_name}", sheet_name="{sheet_name}")
"""
# ACI primitives are parameterized by description, and coordinate generation uses a pretrained grounding model
class OSWorldACI(ACI):
def __init__(
self,
platform: str,
engine_params_for_generation: Dict,
engine_params_for_grounding: Dict,
width: int = 1920,
height: int = 1080,
):
self.platform = (
platform # Dictates how the switch_applications agent action works.
)
# Configure scaling
self.width = width
self.height = height
# Maintain state for save_to_knowledge
self.notes = []
# Coordinates used during ACI execution
self.coords1 = None
self.coords2 = None
# Configure the visual grounding model responsible for coordinate generation
llm_config = AgentConfig(
llm_provider=engine_params_for_grounding.get("engine_type", "openai"),
llm_model_name=engine_params_for_grounding.get("model", "bytedance/ui-tars-1.5-7b"),
llm_temperature=1,
llm_base_url=engine_params_for_grounding.get("base_url", "https://openrouter.ai/api/v1"),
llm_api_key=engine_params_for_grounding.get("api_key", "")
)
self.grounding_model = get_llm_model(llm_config)
self.engine_params_for_grounding = engine_params_for_grounding
# Configure text grounding agent
self.text_span_model = get_llm_model(llm_config)
# Given the state and worker's referring expression, use the grounding model to generate (x,y)
def generate_coords(self, ref_expr: str, obs: Dict) -> List[int]:
# Reset the grounding model state
# self.grounding_model.reset()
# Configure the context, UI-TARS demo does not use system prompt
prompt = f"Query:{ref_expr}\nOutput only the coordinate of one point in your response.\n"
# self.grounding_model.add_message(
# text_content=prompt, image_content=obs["screenshot"], put_text_last=True
# )
grounding_message = [{
"role": "user",
"content": [
{
"type": "text",
"text": prompt
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64," + encode_image(obs["screenshot"])
}
}
]
}]
response = call_llm_model(
llm_model=self.grounding_model,
messages=grounding_message
).content
# Generate and parse coordinates
# response = call_llm_safe(self.grounding_model)
print("RAW GROUNDING MODEL RESPONSE:", response)
numericals = re.findall(r"\d+", response)
assert len(numericals) >= 2
return [int(numericals[0]), int(numericals[1])]
# Calls pytesseract to generate word level bounding boxes for text grounding
def get_ocr_elements(self, b64_image_data: str) -> Tuple[str, List]:
image = Image.open(BytesIO(b64_image_data))
image_data = pytesseract.image_to_data(image, output_type=Output.DICT)
# Clean text by removing leading and trailing spaces and non-alphabetical characters, but keeping punctuation
for i, word in enumerate(image_data["text"]):
image_data["text"][i] = re.sub(
r"^[^a-zA-Z\s.,!?;:\-\+]+|[^a-zA-Z\s.,!?;:\-\+]+$", "", word
)
ocr_elements = []
ocr_table = "Text Table:\nWord id\tText\n"
# Obtain the <id, text, group number, word number> for each valid element
grouping_map = defaultdict(list)
ocr_id = 0
for i in range(len(image_data["text"])):
block_num = image_data["block_num"][i]
if image_data["text"][i]:
grouping_map[block_num].append(image_data["text"][i])
ocr_table += f"{ocr_id}\t{image_data['text'][i]}\n"
ocr_elements.append(
{
"id": ocr_id,
"text": image_data["text"][i],
"group_num": block_num,
"word_num": len(grouping_map[block_num]),
"left": image_data["left"][i],
"top": image_data["top"][i],
"width": image_data["width"][i],
"height": image_data["height"][i],
}
)
ocr_id += 1
return ocr_table, ocr_elements
# Given the state and worker's text phrase, generate the coords of the first/last word in the phrase
def generate_text_coords(
self, phrase: str, obs: Dict, alignment: str = ""
) -> List[int]:
ocr_table, ocr_elements = self.get_ocr_elements(obs["screenshot"])
PHRASE_TO_WORD_COORDS_PROMPT = textwrap.dedent(
"""
You are an expert in graphical user interfaces. Your task is to process a phrase of text, and identify the most relevant word on the computer screen.
You are provided with a phrase, a table with all the text on the screen, and a screenshot of the computer screen. You will identify the single word id that is best associated with the provided phrase.
This single word must be displayed on the computer screenshot, and its location on the screen should align with the provided phrase.
Each row in the text table provides 2 pieces of data in the following order. 1st is the unique word id. 2nd is the corresponding word.
To be successful, it is very important to follow all these rules:
1. First, think step by step and generate your reasoning about which word id to click on.
2. Then, output the unique word id. Remember, the word id is the 1st number in each row of the text table.
3. If there are multiple occurrences of the same word, use the surrounding context in the phrase to choose the correct one. Pay very close attention to punctuation and capitalization.
"""
)
grounding_message = []
system_message = {
"role": "system",
"content": [{
"type": "text",
"text": PHRASE_TO_WORD_COORDS_PROMPT
}]}
grounding_message.append(system_message)
alignment_prompt = ""
if alignment == "start":
alignment_prompt = "**Important**: Output the word id of the FIRST word in the provided phrase.\n"
elif alignment == "end":
alignment_prompt = "**Important**: Output the word id of the LAST word in the provided phrase.\n"
# Load LLM prompt
# self.text_span_agent.reset()
grounding_message.append(
{
"role": "user",
"content": [{
"type": "text",
"text": alignment_prompt + "Phrase: " + phrase + "\n" + ocr_table
}]}
)
# Obtain the target element
# response = call_llm_safe(self.text_span_agent)
response = call_llm_model(
llm_model=self.text_span_model,
messages=grounding_message
).content
print("TEXT SPAN AGENT RESPONSE:", response)
numericals = re.findall(r"\d+", response)
if len(numericals) > 0:
text_id = int(numericals[-1])
else:
text_id = 0
elem = ocr_elements[text_id]
# Compute the element coordinates
if alignment == "start":
coords = [elem["left"], elem["top"] + (elem["height"] // 2)]
elif alignment == "end":
coords = [elem["left"] + elem["width"], elem["top"] + (elem["height"] // 2)]
else:
coords = [
elem["left"] + (elem["width"] // 2),
elem["top"] + (elem["height"] // 2),
]
return coords
# Takes a description based action and assigns the coordinates for any coordinate based action
# Raises an error if function can't be parsed
def assign_coordinates(self, plan: str, obs: Dict):
# Reset coords from previous action generation
self.coords1, self.coords2 = None, None
try:
# Extract the function name and args
action = parse_single_code_from_string(plan.split("Grounded Action")[-1])
function_name = re.match(r"(\w+\.\w+)\(", action).group(1)
args = self.parse_function_args(action)
except Exception as e:
raise RuntimeError(f"Error in parsing grounded action: {e}") from e
# arg0 is a description
if (
function_name in ["agent.click", "agent.type", "agent.scroll"]
and len(args) >= 1
and args[0] != None
):
self.coords1 = self.generate_coords(args[0], obs)
# arg0 and arg1 are descriptions
elif function_name == "agent.drag_and_drop" and len(args) >= 2:
self.coords1 = self.generate_coords(args[0], obs)
self.coords2 = self.generate_coords(args[1], obs)
# arg0 and arg1 are text phrases
elif function_name == "agent.highlight_text_span" and len(args) >= 2:
self.coords1 = self.generate_text_coords(args[0], obs, alignment="start")
self.coords2 = self.generate_text_coords(args[1], obs, alignment="end")
# Resize from grounding model dim into OSWorld dim (1920 * 1080)
def resize_coordinates(self, coordinates: List[int]) -> List[int]:
grounding_width = self.engine_params_for_grounding["grounding_width"]
grounding_height = self.engine_params_for_grounding["grounding_height"]
return [
round(coordinates[0] * self.width / grounding_width),
round(coordinates[1] * self.height / grounding_height),
]
# Given a generated ACI function, returns a list of argument values, where descriptions are at the front of the list
def parse_function_args(self, function: str) -> List[str]:
tree = ast.parse(function)
call_node = tree.body[0].value
def safe_eval(node):
if isinstance(
node, ast.Constant
): # Handles literals like numbers, strings, etc.
return node.value
else:
return ast.unparse(node) # Return as a string if not a literal
positional_args = [safe_eval(arg) for arg in call_node.args]
keyword_args = {kw.arg: safe_eval(kw.value) for kw in call_node.keywords}
res = []
for key, val in keyword_args.items():
if "description" in key:
res.append(val)
for arg in positional_args:
res.append(arg)
return res
@agent_action
def click(
self,
element_description: str,
num_clicks: int = 1,
button_type: str = "left",
hold_keys: List = [],
):
"""Click on the element
Args:
element_description:str, a detailed descriptions of which element to click on. This description should be at least a full sentence.
num_clicks:int, number of times to click the element
button_type:str, which mouse button to press can be "left", "middle", or "right"
hold_keys:List, list of keys to hold while clicking
"""
x, y = self.resize_coordinates(self.coords1)
command = "import pyautogui; "
# TODO: specified duration?
for k in hold_keys:
command += f"pyautogui.keyDown({repr(k)}); "
command += f"""import pyautogui; pyautogui.click({x}, {y}, clicks={num_clicks}, button={repr(button_type)}); """
for k in hold_keys:
command += f"pyautogui.keyUp({repr(k)}); "
# === 新增代码在这里添加1秒的等待 ===
command += "time.sleep(2); "
# Return pyautoguicode to click on the element
return command
@agent_action
def switch_applications(self, app_code):
"""Switch to a different application that is already open
Args:
app_code:str the code name of the application to switch to from the provided list of open applications
"""
if self.platform == "darwin":
return f"import pyautogui; import time; pyautogui.hotkey('command', 'space', interval=0.5); pyautogui.typewrite({repr(app_code)}); pyautogui.press('enter'); time.sleep(1.0)"
elif self.platform == "linux":
return UBUNTU_APP_SETUP.replace("APP_NAME", app_code)
elif self.platform == "windows":
return f"import pyautogui; import time; pyautogui.hotkey('win', 'd', interval=0.5); pyautogui.typewrite({repr(app_code)}); pyautogui.press('enter'); time.sleep(1.0)"
@agent_action
def open(self, app_or_filename: str):
"""Open any application or file with name app_or_filename. Use this action to open applications or files on the desktop, do not open manually.
Args:
app_or_filename:str, the name of the application or filename to open
"""
if self.platform == "linux":
return f"import pyautogui; pyautogui.hotkey('win'); time.sleep(0.5); pyautogui.write({repr(app_or_filename)}); time.sleep(1.0); pyautogui.hotkey('enter'); time.sleep(0.5)"
elif self.platform == "darwin":
return f"import pyautogui; import time; pyautogui.hotkey('command', 'space', interval=0.5); pyautogui.typewrite({repr(app_or_filename)}); pyautogui.press('enter'); time.sleep(1.0)"
@agent_action
def type(
self,
element_description: Optional[str] = None,
text: str = "",
overwrite: bool = False,
enter: bool = False,
):
"""Type text into a specific element
Args:
element_description:str, a detailed description of which element to enter text in. This description should be at least a full sentence.
text:str, the text to type
overwrite:bool, Assign it to True if the text should overwrite the existing text, otherwise assign it to False. Using this argument clears all text in an element.
enter:bool, Assign it to True if the enter key should be pressed after typing the text, otherwise assign it to False.
"""
select_mod = "command" if self.platform == "darwin" else "ctrl"
if self.coords1 is not None:
# If a node is found, retrieve its coordinates and size
# Start typing at the center of the element
x, y = self.resize_coordinates(self.coords1)
command = "import pyautogui; "
# command += f"pyautogui.click({x}, {y}); "
# 修改成double click
command += f"pyautogui.doubleClick({x}, {y}); "
if overwrite:
command += (
f"pyautogui.hotkey({repr(select_mod)}, 'a'); "
"pyautogui.press('backspace'); "
)
command += f"pyautogui.write({repr(text)}); "
if enter:
command += "pyautogui.press('enter'); "
else:
# If no element is found, start typing at the current cursor location
command = "import pyautogui; "
if overwrite:
command += (
f"pyautogui.hotkey({repr(select_mod)}, 'a'); "
"pyautogui.press('backspace'); "
)
command += f"pyautogui.write({repr(text)}); "
if enter:
command += "pyautogui.press('enter'); "
# === 新增代码在这里添加1秒的等待 ===
command += "time.sleep(2); "
return command
@agent_action
def save_to_knowledge(self, text: List[str]):
"""Save facts, elements, texts, etc. to a long-term knowledge bank for reuse during this task. Can be used for copy-pasting text, saving elements, etc.
Args:
text:List[str] the text to save to the knowledge
"""
self.notes.extend(text)
return """WAIT"""
@agent_action
def drag_and_drop(
self, starting_description: str, ending_description: str, hold_keys: List = []
):
"""Drag from the starting description to the ending description
Args:
starting_description:str, a very detailed description of where to start the drag action. This description should be at least a full sentence.
ending_description:str, a very detailed description of where to end the drag action. This description should be at least a full sentence.
hold_keys:List list of keys to hold while dragging
"""
x1, y1 = self.resize_coordinates(self.coords1)
x2, y2 = self.resize_coordinates(self.coords2)
command = "import pyautogui; "
command += f"pyautogui.moveTo({x1}, {y1}); "
# TODO: specified duration?
for k in hold_keys:
command += f"pyautogui.keyDown({repr(k)}); "
command += f"pyautogui.dragTo({x2}, {y2}, duration=1., button='left'); pyautogui.mouseUp(); "
for k in hold_keys:
command += f"pyautogui.keyUp({repr(k)}); "
# Return pyautoguicode to drag and drop the elements
# === 新增代码在这里添加1秒的等待 ===
command += "time.sleep(2); "
return command
@agent_action
def highlight_text_span(
self, starting_phrase: str, ending_phrase: str, button: str = "left"
):
"""Highlight a text span between a provided starting phrase and ending phrase. Use this to highlight words, lines, and paragraphs.
Args:
starting_phrase:str, the phrase that denotes the start of the text span you want to highlight. If you only want to highlight one word, just pass in that single word.
ending_phrase:str, the phrase that denotes the end of the text span you want to highlight. If you only want to highlight one word, just pass in that single word.
button:str, the button to use to highlight the text span. Defaults to "left". Can be "left", "right", or "middle".
"""
x1, y1 = self.coords1
x2, y2 = self.coords2
command = "import pyautogui; "
command += f"pyautogui.moveTo({x1}, {y1}); "
command += f"pyautogui.dragTo({x2}, {y2}, duration=1., button='{button}'); pyautogui.mouseUp(); "
# Return pyautoguicode to drag and drop the elements
# === 新增代码在这里添加1秒的等待 ===
command += "time.sleep(2); "
return command
@agent_action
def set_cell_values(
self, cell_values: Dict[str, Any], app_name: str, sheet_name: str
):
"""Use this to set individual cell values in a spreadsheet. For example, setting A2 to "hello" would be done by passing {"A2": "hello"} as cell_values. The sheet must be opened before this command can be used.
Args:
cell_values: Dict[str, Any], A dictionary of cell values to set in the spreadsheet. The keys are the cell coordinates in the format "A1", "B2", etc.
Supported value types include: float, int, string, bool, formulas.
app_name: str, The name of the spreadsheet application. For example, "Some_sheet.xlsx".
sheet_name: str, The name of the sheet in the spreadsheet. For example, "Sheet1".
"""
return SET_CELL_VALUES_CMD.format(
cell_values=cell_values, app_name=app_name, sheet_name=sheet_name
)
@agent_action
def scroll(self, element_description: str, clicks: int, shift: bool = False):
"""Scroll the element in the specified direction
Args:
element_description:str, a very detailed description of which element to enter scroll in. This description should be at least a full sentence.
clicks:int, the number of clicks to scroll can be positive (up) or negative (down).
shift:bool, whether to use shift+scroll for horizontal scrolling
"""
x, y = self.resize_coordinates(self.coords1)
if shift:
return f"import pyautogui; import time; pyautogui.moveTo({x}, {y}); time.sleep(0.5); pyautogui.hscroll({clicks})"
else:
return f"import pyautogui; import time; pyautogui.moveTo({x}, {y}); time.sleep(0.5); pyautogui.vscroll({clicks})"
@agent_action
def hotkey(self, keys: List):
"""Press a hotkey combination
Args:
keys:List the keys to press in combination in a list format (e.g. ['ctrl', 'c'])
"""
# add quotes around the keys
keys = [f"'{key}'" for key in keys]
return f"import pyautogui; pyautogui.hotkey({', '.join(keys)}); time.sleep(2);"
@agent_action
def hold_and_press(self, hold_keys: List, press_keys: List):
"""Hold a list of keys and press a list of keys
Args:
hold_keys:List, list of keys to hold
press_keys:List, list of keys to press in a sequence
"""
press_keys_str = "[" + ", ".join([f"'{key}'" for key in press_keys]) + "]"
command = "import pyautogui; "
for k in hold_keys:
command += f"pyautogui.keyDown({repr(k)}); "
command += f"pyautogui.press({press_keys_str}); "
for k in hold_keys:
command += f"pyautogui.keyUp({repr(k)}); "
return command
@agent_action
def wait(self, time: float):
"""Wait for a specified amount of time
Args:
time:float the amount of time to wait in seconds
"""
return f"""import time; time.sleep({time})"""
@agent_action
def done(
self,
return_value: Optional[Union[Dict, str, List, Tuple, int, float, bool]] = None,
):
"""End the current task with a success and the required return value"""
self.returned_info = return_value
return """DONE"""
@agent_action
def fail(self):
"""End the current task with a failure, and replan the whole task."""
return """FAIL"""
CODE_LAUNCH_VSCODE_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_launch_vscode(path):
global ret
try:
subprocess.run(["code", "-r", path], check=True)
ret = "Successfully launched VS Code"
except subprocess.CalledProcessError as e:
ret = f"Error launching VS Code: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_launch_vscode(path={path})
print(ret)
"""
@agent_action
def code_launch_vscode(self, path):
return self.CODE_LAUNCH_VSCODE_CMD.format(path=repr(path))
CODE_COMPARE_FILES_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_compare_files(file1, file2):
global ret
try:
# 获取compare结果
subprocess.run(["code", "-d", file1, file2], check=True)
ret = "The compared files are opened in VSCode"
except subprocess.CalledProcessError as e:
ret = f"Error comparing files: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_compare_files(file1={file1}, file2={file2})
print(ret)
"""
@agent_action
def code_compare_files(self, file1, file2):
return self.CODE_COMPARE_FILES_CMD.format(file1=repr(file1), file2=repr(file2))
CODE_ADD_FOLDER_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_add_folder(folder):
global ret
try:
subprocess.run(["code", "-a", folder], check=True)
ret = "Successfully added folder"
except subprocess.CalledProcessError as e:
ret = f"Error adding folder: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_add_folder(folder={folder})
print(ret)
"""
@agent_action
def code_add_folder(self, folder):
return self.CODE_ADD_FOLDER_CMD.format(folder=repr(folder))
CODE_GOTO_FILE_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_goto_file(file_path, line=1, character=1):
global ret
try:
command = f"{{file_path}}:{{line}}:{{character}}"
subprocess.run(["code", "-g", command], check=True)
ret = "Successfully opened file, line: {{}}, character: {{}}".format(line, character)
except subprocess.CalledProcessError as e:
ret = f"Error going to file: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_goto_file(file_path={file_path}, line={line}, character={character})
print(ret)
"""
@agent_action
def code_goto_file(self, file_path, line, character):
return self.CODE_GOTO_FILE_CMD.format(file_path=repr(file_path), line=repr(line), character=repr(character))
LIBREOFFICE_CALC_SET_COLUMN_AS_TEXT_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_set_column_as_text(column_name):
global ret
try:
# 获取列索引
column_index = libreoffice_calc_get_column_index(column_name)
if column_index is None:
ret = f"Error: Invalid column name '{{column_name}}'"
return False
# 获取最后使用的行
last_row = libreoffice_calc_get_last_used_row()
if last_row == -1:
ret = "Error: No data found in sheet"
return False
# 获取整列的范围
cell_range = sheet.getCellRangeByPosition(column_index, 0, column_index, last_row)
# 设置数字格式为文本格式
# 使用 "@" 表示文本格式
cell_range.NumberFormat = 0 # 重置格式
# 获取格式对象并设置为文本
formats = doc.NumberFormats
locale = uno.createUnoStruct("com.sun.star.lang.Locale")
locale.Language = "en"
locale.Country = "US"
# 创建文本格式
text_format_key = formats.queryKey("@", locale, False)
if text_format_key == -1:
text_format_key = formats.addNew("@", locale)
# 应用文本格式到整列
cell_range.NumberFormat = text_format_key
# 将现有数值转换为文本
data_array = cell_range.getDataArray()
for row_idx, row in enumerate(data_array):
cell = sheet.getCellByPosition(column_index, row_idx)
current_value = cell.getValue() if cell.getType().value == "VALUE" else cell.getString()
if current_value != 0 or cell.getString() != "":
# 将值设置为字符串
cell.setString(str(current_value))
ret = f"Successfully set column {{column_name}} as text format"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_set_column_as_text(column_name={column_name})
print(ret)
"""
@agent_action
def libreoffice_calc_set_column_as_text(self, column_name):
return self.LIBREOFFICE_CALC_SET_COLUMN_AS_TEXT_CMD.format(column_name=repr(column_name))
CODE_PERFORM_MERGE_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_perform_merge(path1, path2, base, result):
global ret
try:
subprocess.run(["code", "-m", path1, path2, base, result], check=True)
ret = "Successfully performed merge"
except subprocess.CalledProcessError as e:
ret = f"Error performing merge: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_perform_merge(path1={path1}, path2={path2}, base={base}, result={result})
print(ret)
"""
@agent_action
def code_perform_merge(self, path1, path2, base, result):
return self.CODE_PERFORM_MERGE_CMD.format(path1=repr(path1), path2=repr(path2), base=repr(base),
result=repr(result))
CODE_REMOVE_FOLDER_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_remove_folder(folder):
global ret
try:
subprocess.run(["code", "--remove", folder], check=True)
ret = "Successfully removed folder"
except subprocess.CalledProcessError as e:
ret = f"Error removing folder: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_remove_folder(folder={folder})
print(ret)
"""
@agent_action
def code_remove_folder(self, folder):
return self.CODE_REMOVE_FOLDER_CMD.format(folder=repr(folder))
CODE_INSTALL_EXTENSION_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_install_extension(extension_id, pre_release=False):
global ret
try:
command = ["code", "--install-extension", extension_id]
if pre_release:
command.append("--pre-release")
subprocess.run(command, check=True)
ret = "Successfully installed extension"
except subprocess.CalledProcessError as e:
ret = f"Error installing extension: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_install_extension(extension_id={extension_id}, pre_release={pre_release})
print(ret)
"""
@agent_action
def code_install_extension(self, extension_id, pre_release):
return self.CODE_INSTALL_EXTENSION_CMD.format(extension_id=repr(extension_id), pre_release=repr(pre_release))
CODE_UNINSTALL_EXTENSION_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_uninstall_extension(extension_id):
global ret
try:
subprocess.run(["code", "--uninstall-extension", extension_id], check=True)
ret = "Successfully uninstalled extension"
except subprocess.CalledProcessError as e:
ret = f"Error uninstalling extension: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_uninstall_extension(extension_id={extension_id})
print(ret)
"""
@agent_action
def code_uninstall_extension(self, extension_id):
return self.CODE_UNINSTALL_EXTENSION_CMD.format(extension_id=repr(extension_id))
CODE_LIST_EXTENSIONS_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_list_extensions(show_versions=False, category=None):
global ret
try:
command = ["code", "--list-extensions"]
if show_versions:
command.append("--show-versions")
if category:
command.extend(["--category", category])
ret = subprocess.run(command, check=True, capture_output=True, text=True).stdout
except subprocess.CalledProcessError as e:
ret = f"Error listing extensions: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_list_extensions(show_versions={show_versions}, category={category})
print(ret)
"""
@agent_action
def code_list_extensions(self, show_versions, category):
return self.CODE_LIST_EXTENSIONS_CMD.format(show_versions=repr(show_versions), category=repr(category))
CODE_UPDATE_EXTENSIONS_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_update_extensions():
global ret
try:
subprocess.run(["code", "--update-extensions"], check=True)
ret = "Successfully updated extensions"
except subprocess.CalledProcessError as e:
ret = f"Error updating extensions: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_update_extensions()
print(ret)
"""
@agent_action
def code_update_extensions(self):
return self.CODE_UPDATE_EXTENSIONS_CMD.format()
CODE_DISABLE_EXTENSION_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_disable_extension(extension_id):
global ret
try:
subprocess.run(["code", "--disable-extension", extension_id], check=True)
ret = "Successfully disabled extension"
except subprocess.CalledProcessError as e:
ret = f"Error disabling extension: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_disable_extension(extension_id={extension_id})
print(ret)
"""
@agent_action
def code_disable_extension(self, extension_id):
return self.CODE_DISABLE_EXTENSION_CMD.format(extension_id=repr(extension_id))
CODE_TOGGLE_SYNC_CMD = """import json
import os
import subprocess
from pathlib import Path
ret = ""
def code_toggle_sync(state):
global ret
try:
command = ["code", "--sync", state]
subprocess.run(command, check=True)
ret = "Successfully toggled sync"
except subprocess.CalledProcessError as e:
ret = f"Error toggling sync: {{e}}"
except Exception as e:
ret = f"Unexpected error: {{e}}"
return ret
code_toggle_sync(state={state})
print(ret)
"""
@agent_action
def code_toggle_sync(self, state):
return self.CODE_TOGGLE_SYNC_CMD.format(state=repr(state))
LIBREOFFICE_IMPRESS_SAVE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_save():
global ret
try:
if doc.hasLocation():
doc.store()
ret = "Success"
else:
ret = "Error: Document has no save location"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_impress_save()
print(ret)
"""
@agent_action
def libreoffice_impress_save(self):
return self.LIBREOFFICE_IMPRESS_SAVE_CMD.format()
LIBREOFFICE_IMPRESS_GO_TO_SLIDE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_go_to_slide(slide_index):
global ret
try:
zero_based_index = slide_index - 1
controller = doc.getCurrentController()
if not controller:
ret = "Error: Could not get document controller"
return False
pages = doc.getDrawPages()
if zero_based_index < 0 or zero_based_index >= pages.getCount():
ret = f"Error: Slide index {{slide_index}} is out of range. Valid range is 1-{{pages.getCount()}}"
return False
target_slide = pages.getByIndex(zero_based_index)
controller.setCurrentPage(target_slide)
ret = f"Successfully navigated to slide {{slide_index}}"
return True
except Exception as e:
ret = f"Error navigating to slide: {{str(e)}}"
return False
libreoffice_impress_go_to_slide(slide_index={slide_index})
print(ret)
"""
@agent_action
def libreoffice_impress_go_to_slide(self, slide_index):
return self.LIBREOFFICE_IMPRESS_GO_TO_SLIDE_CMD.format(slide_index=repr(slide_index))
LIBREOFFICE_IMPRESS_GET_SLIDE_COUNT_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_get_slide_count():
global ret
try:
pages = doc.getDrawPages()
count = pages.getCount()
ret = count
return count
except Exception as e:
ret = f"Error: {{str(e)}}"
return 0
libreoffice_impress_get_slide_count()
print(ret)
"""
@agent_action
def libreoffice_impress_get_slide_count(self):
return self.LIBREOFFICE_IMPRESS_GET_SLIDE_COUNT_CMD.format()
LIBREOFFICE_IMPRESS_DUPLICATE_SLIDE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_duplicate_slide(slide_index):
global ret
try:
zero_based_index = slide_index - 1
draw_pages = doc.getDrawPages()
if zero_based_index < 0 or zero_based_index >= draw_pages.getCount():
ret = f"Error: Invalid slide index {{slide_index}}. Valid range is 1 to {{draw_pages.getCount()}}"
return False
controller = doc.getCurrentController()
controller.setCurrentPage(draw_pages.getByIndex(zero_based_index))
dispatcher = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.DispatchHelper", ctx)
frame = controller.getFrame()
dispatcher.executeDispatch(frame, ".uno:DuplicatePage", "", 0, ())
duplicated_slide_index = zero_based_index + 1
slide_count = draw_pages.getCount()
if duplicated_slide_index < slide_count - 1:
controller.setCurrentPage(draw_pages.getByIndex(duplicated_slide_index))
moves_needed = slide_count - duplicated_slide_index - 1
for _ in range(moves_needed):
dispatcher.executeDispatch(frame, ".uno:MovePageDown", "", 0, ())
ret = f"Slide {{slide_index}} duplicated successfully and moved to the end"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_duplicate_slide(slide_index={slide_index})
print(ret)
"""
@agent_action
def libreoffice_impress_duplicate_slide(self, slide_index):
return self.LIBREOFFICE_IMPRESS_DUPLICATE_SLIDE_CMD.format(slide_index=repr(slide_index))
LIBREOFFICE_IMPRESS_SET_SLIDE_FONT_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_slide_font(slide_index, font_name):
global ret
try:
zero_based_index = slide_index - 1
slides = doc.getDrawPages()
if zero_based_index < 0 or zero_based_index >= slides.getCount():
ret = f"Error: Slide index {{slide_index}} is out of range. Valid range is 1 to {{slides.getCount()}}."
return False
slide = slides.getByIndex(zero_based_index)
for i in range(slide.getCount()):
shape = slide.getByIndex(i)
if hasattr(shape, "getText"):
text = shape.getText()
if text:
cursor = text.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
cursor.setPropertyValue("CharFontName", font_name)
ret = f"Successfully set font to '{{font_name}}' for all text elements in slide {{slide_index}}."
return True
except Exception as e:
ret = f"Error setting font: {{str(e)}}"
return False
libreoffice_impress_set_slide_font(slide_index={slide_index}, font_name={font_name})
print(ret)
"""
@agent_action
def libreoffice_impress_set_slide_font(self, slide_index, font_name):
return self.LIBREOFFICE_IMPRESS_SET_SLIDE_FONT_CMD.format(slide_index=repr(slide_index),
font_name=repr(font_name))
LIBREOFFICE_IMPRESS_WRITE_TEXT_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_write_text(content, page_index, box_index, bold=False, italic=False, size=None, append=False):
global ret
try:
zero_based_page_index = page_index - 1
pages = doc.getDrawPages()
if zero_based_page_index < 0 or zero_based_page_index >= pages.getCount():
ret = f"Error: Page index {{page_index}} is out of range"
return False
page = pages.getByIndex(zero_based_page_index)
if box_index < 0 or box_index >= page.getCount():
ret = f"Error: Box index {{box_index}} is out of range"
return False
shape = page.getByIndex(box_index)
if not hasattr(shape, "String"):
ret = f"Error: The shape at index {{box_index}} cannot contain text"
return False
if append:
shape.String = shape.String + content
else:
shape.String = content
if hasattr(shape, "getCharacterProperties"):
char_props = shape.getCharacterProperties()
if bold:
char_props.CharWeight = BOLD
else:
char_props.CharWeight = NORMAL
if italic:
char_props.CharPosture = ITALIC
else:
char_props.CharPosture = NONE
if size is not None:
char_props.CharHeight = size
ret = f"Text successfully written to page {{page_index}}, box {{box_index}}"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_write_text(content={content}, page_index={page_index}, box_index={box_index}, bold={bold}, italic={italic}, size={size}, append={append})
print(ret)
"""
@agent_action
def libreoffice_impress_write_text(self, content, page_index, box_index, bold, italic, size, append):
return self.LIBREOFFICE_IMPRESS_WRITE_TEXT_CMD.format(content=repr(content), page_index=repr(page_index),
box_index=repr(box_index), bold=repr(bold),
italic=repr(italic), size=repr(size), append=repr(append))
LIBREOFFICE_IMPRESS_SET_STYLE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_style(slide_index, box_index, bold=None, italic=None, underline=None):
global ret
try:
pages = doc.getDrawPages()
if slide_index < 1 or slide_index > pages.getCount():
ret = f"Error: Invalid slide index {{slide_index}}. Valid range is 1 to {{pages.getCount()}}"
return False
page = pages.getByIndex(slide_index - 1)
if box_index < 0 or box_index >= page.getCount():
ret = f"Error: Invalid box index {{box_index}}. Valid range is 0 to {{page.getCount() - 1}}"
return False
shape = page.getByIndex(box_index)
if not hasattr(shape, "getText"):
ret = "Error: The specified shape does not contain text"
return False
text = shape.getText()
cursor = text.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
if bold is not None:
cursor.setPropertyValue("CharWeight", BOLD if bold else NORMAL)
if italic is not None:
cursor.setPropertyValue("CharPosture", ITALIC if italic else NONE)
if underline is not None:
cursor.setPropertyValue("CharUnderline", 1 if underline else 0)
ret = "Style applied successfully"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_set_style(slide_index={slide_index}, box_index={box_index}, bold={bold}, italic={italic}, underline={underline})
print(ret)
"""
@agent_action
def libreoffice_impress_set_style(self, slide_index, box_index, bold, italic, underline):
return self.LIBREOFFICE_IMPRESS_SET_STYLE_CMD.format(slide_index=repr(slide_index), box_index=repr(box_index),
bold=repr(bold), italic=repr(italic),
underline=repr(underline))
LIBREOFFICE_IMPRESS_CONFIGURE_AUTO_SAVE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_configure_auto_save(enabled, interval_minutes):
global ret
try:
if interval_minutes < 1:
interval_minutes = 1
config_provider = ctx.ServiceManager.createInstanceWithContext(
"com.sun.star.configuration.ConfigurationProvider", ctx
)
prop = PropertyValue()
prop.Name = "nodepath"
prop.Value = "/org.openoffice.Office.Common/Save/Document"
config_access = config_provider.createInstanceWithArguments(
"com.sun.star.configuration.ConfigurationUpdateAccess", (prop,)
)
config_access.setPropertyValue("AutoSave", enabled)
config_access.setPropertyValue("AutoSaveTimeIntervall", interval_minutes)
config_access.commitChanges()
ret = f"Auto-save {{'enabled' if enabled else 'disabled'}} with interval of {{interval_minutes}} minutes"
return True
except Exception as e:
ret = f"Error configuring auto-save: {{str(e)}}"
return False
libreoffice_impress_configure_auto_save(enabled={enabled}, interval_minutes={interval_minutes})
print(ret)
"""
@agent_action
def libreoffice_impress_configure_auto_save(self, enabled, interval_minutes):
return self.LIBREOFFICE_IMPRESS_CONFIGURE_AUTO_SAVE_CMD.format(enabled=repr(enabled),
interval_minutes=repr(interval_minutes))
LIBREOFFICE_IMPRESS_SET_BACKGROUND_COLOR_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_background_color(slide_index, box_index, color):
global ret
try:
zero_based_slide_index = slide_index - 1
slides = doc.getDrawPages()
if zero_based_slide_index < 0 or zero_based_slide_index >= slides.getCount():
ret = f"Error: Slide index {{slide_index}} is out of range"
return False
slide = slides.getByIndex(zero_based_slide_index)
if box_index < 0 or box_index >= slide.getCount():
ret = f"Error: Box index {{box_index}} is out of range"
return False
shape = slide.getByIndex(box_index)
color_int = 0
color_map = {{
"red": 16711680,
"green": 65280,
"blue": 255,
"yellow": 16776960,
"black": 0,
"white": 16777215,
"purple": 8388736,
"orange": 16753920,
"pink": 16761035,
"gray": 8421504,
"brown": 10824234,
"cyan": 65535,
"magenta": 16711935,
}}
if color.lower() in color_map:
color_int = color_map[color.lower()]
elif color.startswith("#") and len(color) == 7:
color_int = int(color[1:], 16)
else:
ret = f"Error: Invalid color format: {{color}}"
return False
shape.FillStyle = uno.Enum("com.sun.star.drawing.FillStyle", "SOLID")
shape.FillColor = color_int
ret = f"Background color of textbox {{box_index}} on slide {{slide_index}} set to {{color}}"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_set_background_color(slide_index={slide_index}, box_index={box_index}, color={color})
print(ret)
"""
@agent_action
def libreoffice_impress_set_background_color(self, slide_index, box_index, color):
return self.LIBREOFFICE_IMPRESS_SET_BACKGROUND_COLOR_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index), color=repr(color))
LIBREOFFICE_IMPRESS_SET_TEXT_COLOR_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_text_color(slide_index, box_index, color):
global ret
try:
zero_based_slide_index = slide_index - 1
slides = doc.getDrawPages()
if zero_based_slide_index < 0 or zero_based_slide_index >= slides.getCount():
ret = f"Error: Slide index {{slide_index}} is out of range"
return False
slide = slides.getByIndex(zero_based_slide_index)
if box_index < 0 or box_index >= slide.getCount():
ret = f"Error: Box index {{box_index}} is out of range"
return False
shape = slide.getByIndex(box_index)
if not hasattr(shape, "getText"):
ret = f"Error: Shape at index {{box_index}} does not contain text"
return False
color_int = 0
if color.startswith("#"):
color_int = int(color[1:], 16)
else:
color_map = {{
"red": 16711680,
"green": 43315,
"blue": 255,
"black": 0,
"white": 16777215,
"yellow": 16776960,
"cyan": 65535,
"magenta": 16711935,
"gray": 8421504,
}}
if color.lower() in color_map:
color_int = color_map[color.lower()]
else:
ret = f"Error: Unsupported color '{{color}}'"
return False
text = shape.getText()
cursor = text.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
cursor.setPropertyValue("CharColor", color_int)
ret = f"Successfully set text color to {{color}} for textbox {{box_index}} on slide {{slide_index}}"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_set_text_color(slide_index={slide_index}, box_index={box_index}, color={color})
print(ret)
"""
@agent_action
def libreoffice_impress_set_text_color(self, slide_index, box_index, color):
return self.LIBREOFFICE_IMPRESS_SET_TEXT_COLOR_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index), color=repr(color))
LIBREOFFICE_IMPRESS_DELETE_CONTENT_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_delete_content(slide_index, box_index):
global ret
try:
pages = doc.getDrawPages()
zero_based_slide_index = slide_index - 1
if zero_based_slide_index < 0 or zero_based_slide_index >= pages.getCount():
ret = f"Error: Invalid slide index {{slide_index}}. Valid range is 1 to {{pages.getCount()}}"
return False
slide = pages.getByIndex(zero_based_slide_index)
if box_index < 0 or box_index >= slide.getCount():
ret = f"Error: Invalid box index {{box_index}}. Valid range is 0 to {{slide.getCount() - 1}}"
return False
shape = slide.getByIndex(box_index)
slide.remove(shape)
ret = f"Successfully deleted textbox {{box_index}} from slide {{slide_index}}"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_delete_content(slide_index={slide_index}, box_index={box_index})
print(ret)
"""
@agent_action
def libreoffice_impress_delete_content(self, slide_index, box_index):
return self.LIBREOFFICE_IMPRESS_DELETE_CONTENT_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index))
LIBREOFFICE_IMPRESS_SET_SLIDE_ORIENTATION_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_slide_orientation(orientation):
global ret
try:
draw_pages = doc.getDrawPages()
first_page = draw_pages.getByIndex(0)
current_width = first_page.Width
current_height = first_page.Height
if orientation == "portrait" and current_width > current_height:
new_width, new_height = current_height, current_width
elif orientation == "landscape" and current_width < current_height:
new_width, new_height = current_height, current_width
else:
ret = f"Slides are already in {{orientation}} orientation"
return True
for i in range(draw_pages.getCount()):
page = draw_pages.getByIndex(i)
page.Width = new_width
page.Height = new_height
ret = f"Changed slide orientation to {{orientation}}"
return True
except Exception as e:
ret = f"Error changing slide orientation: {{str(e)}}"
return False
libreoffice_impress_set_slide_orientation(orientation={orientation})
print(ret)
"""
@agent_action
def libreoffice_impress_set_slide_orientation(self, orientation):
return self.LIBREOFFICE_IMPRESS_SET_SLIDE_ORIENTATION_CMD.format(orientation=repr(orientation))
LIBREOFFICE_IMPRESS_POSITION_BOX_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_position_box(slide_index, box_index, position):
global ret
try:
pages = doc.getDrawPages()
if slide_index < 1 or slide_index > pages.getCount():
ret = f"Error: Invalid slide index {{slide_index}}"
return False
page = pages.getByIndex(slide_index - 1)
if box_index < 0 or box_index >= page.getCount():
ret = f"Error: Invalid box index {{box_index}}"
return False
shape = page.getByIndex(box_index)
controller = doc.getCurrentController()
slide_width = 28000
slide_height = 21000
shape_width = shape.Size.Width
shape_height = shape.Size.Height
margin = 500
if position == "left":
new_x = margin
new_y = (slide_height - shape_height) / 2
elif position == "right":
new_x = slide_width - shape_width - margin
new_y = (slide_height - shape_height) / 2
elif position == "center":
new_x = (slide_width - shape_width) / 2
new_y = (slide_height - shape_height) / 2
elif position == "top":
new_x = (slide_width - shape_width) / 2
new_y = margin
elif position == "bottom":
new_x = (slide_width - shape_width) / 2
new_y = slide_height - shape_height - margin
elif position == "top-left":
new_x = margin
new_y = margin
elif position == "top-right":
new_x = slide_width - shape_width - margin
new_y = margin
elif position == "bottom-left":
new_x = margin
new_y = slide_height - shape_height - margin
elif position == "bottom-right":
new_x = slide_width - shape_width - margin
new_y = slide_height - shape_height - margin
else:
ret = f"Error: Invalid position '{{position}}'"
return False
try:
shape.Position.X = int(new_x)
shape.Position.Y = int(new_y)
except:
try:
shape.setPropertyValue("PositionX", int(new_x))
shape.setPropertyValue("PositionY", int(new_y))
except:
point = uno.createUnoStruct("com.sun.star.awt.Point", int(new_x), int(new_y))
shape.setPosition(point)
ret = f"Box positioned at {{position}} (X: {{new_x}}, Y: {{new_y}})"
return True
except Exception as e:
ret = f"Error positioning box: {{str(e)}}"
return False
libreoffice_impress_position_box(slide_index={slide_index}, box_index={box_index}, position={position})
print(ret)
"""
@agent_action
def libreoffice_impress_position_box(self, slide_index, box_index, position):
return self.LIBREOFFICE_IMPRESS_POSITION_BOX_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index), position=repr(position))
LIBREOFFICE_IMPRESS_INSERT_FILE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_insert_file(file_path, slide_index=None, position=None, size=None, autoplay=False):
global ret
try:
expanded_file_path = os.path.expanduser(file_path)
if not os.path.exists(expanded_file_path):
ret = f"Error: File not found: {{expanded_file_path}}"
return False
file_url = uno.systemPathToFileUrl(os.path.abspath(expanded_file_path))
pages = doc.getDrawPages()
if slide_index is not None:
zero_based_index = slide_index - 1
if zero_based_index < 0 or zero_based_index >= pages.getCount():
ret = f"Error: Invalid slide index: {{slide_index}}"
return False
slide = pages.getByIndex(zero_based_index)
else:
controller = doc.getCurrentController()
slide = controller.getCurrentPage()
slide_width = 21000
slide_height = 12750
if position is None:
position = {{"x": 10, "y": 10}}
if size is None:
size = {{"width": 80, "height": 60}}
x = int(position["x"] * slide_width / 100)
y = int(position["y"] * slide_height / 100)
width = int(size["width"] * slide_width / 100)
height = int(size["height"] * slide_height / 100)
media_shape = doc.createInstance("com.sun.star.presentation.MediaShape")
slide.add(media_shape)
media_shape.setPosition(uno.createUnoStruct("com.sun.star.awt.Point", x, y))
media_shape.setSize(uno.createUnoStruct("com.sun.star.awt.Size", width, height))
media_shape.setPropertyValue("MediaURL", file_url)
if autoplay:
try:
media_shape.setPropertyValue("MediaIsAutoPlay", True)
except:
pass
ret = f"Video inserted successfully from {{expanded_file_path}}"
return True
except Exception as e:
ret = f"Error inserting video: {{str(e)}}"
return False
libreoffice_impress_insert_file(file_path={file_path}, slide_index={slide_index}, position={position}, size={size}, autoplay={autoplay})
print(ret)
"""
@agent_action
def libreoffice_impress_insert_file(self, file_path, slide_index, position, size, autoplay):
return self.LIBREOFFICE_IMPRESS_INSERT_FILE_CMD.format(file_path=repr(file_path), slide_index=repr(slide_index),
position=repr(position), size=repr(size),
autoplay=repr(autoplay))
LIBREOFFICE_IMPRESS_SET_SLIDE_BACKGROUND_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_slide_background(slide_index=None, color=None, image_path=None):
global ret
try:
if not color and not image_path:
ret = "Error: Either color or image_path must be provided"
return False
pages = doc.getDrawPages()
page_count = pages.getCount()
rgb_color = None
if color:
if color.startswith("#"):
color = color.lstrip("#")
rgb_color = int(color, 16)
else:
color_map = {{
"red": 16711680,
"green": 43315,
"blue": 255,
"black": 0,
"white": 16777215,
"yellow": 16776960,
"cyan": 65535,
"magenta": 16711935,
"gray": 8421504,
}}
rgb_color = color_map.get(color.lower(), 0)
if slide_index is not None:
slide_index = slide_index - 1
if slide_index < 0 or slide_index >= page_count:
ret = f"Error: Slide index {{slide_index + 1}} is out of range (1-{{page_count}})"
return False
slides_to_modify = [pages.getByIndex(slide_index)]
else:
slides_to_modify = [pages.getByIndex(i) for i in range(page_count)]
for slide in slides_to_modify:
fill_props = ctx.ServiceManager.createInstanceWithContext(
"com.sun.star.drawing.FillProperties", ctx
)
if image_path and os.path.exists(image_path):
abs_path = os.path.abspath(image_path)
file_url = uno.systemPathToFileUrl(abs_path)
fill_props.FillStyle = uno.Enum("com.sun.star.drawing.FillStyle", "BITMAP")
fill_props.FillBitmapURL = file_url
fill_props.FillBitmapMode = uno.Enum("com.sun.star.drawing.BitmapMode", "STRETCH")
elif rgb_color is not None:
fill_props.FillStyle = uno.Enum("com.sun.star.drawing.FillStyle", "SOLID")
fill_props.FillColor = rgb_color
slide.setPropertyValue("Background", fill_props)
ret = "Background set successfully"
return True
except Exception as e:
ret = f"Error setting background: {{str(e)}}"
return False
libreoffice_impress_set_slide_background(slide_index={slide_index}, color={color}, image_path={image_path})
print(ret)
"""
@agent_action
def libreoffice_impress_set_slide_background(self, slide_index, color, image_path):
return self.LIBREOFFICE_IMPRESS_SET_SLIDE_BACKGROUND_CMD.format(slide_index=repr(slide_index),
color=repr(color), image_path=repr(image_path))
LIBREOFFICE_IMPRESS_SAVE_AS_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_save_as(file_path, overwrite=False):
global ret
try:
if os.path.exists(file_path) and not overwrite:
ret = f"File already exists and overwrite is set to False: {{file_path}}"
return False
abs_path = os.path.abspath(file_path)
if os.name == "nt":
url = "file:///" + abs_path.replace("\\", "/")
else:
url = "file://" + abs_path
properties = []
overwrite_prop = PropertyValue()
overwrite_prop.Name = "Overwrite"
overwrite_prop.Value = overwrite
properties.append(overwrite_prop)
extension = os.path.splitext(file_path)[1].lower()
if extension == ".odp":
filter_name = "impress8"
elif extension == ".ppt":
filter_name = "MS PowerPoint 97"
elif extension == ".pptx":
filter_name = "Impress MS PowerPoint 2007 XML"
elif extension == ".pdf":
filter_name = "impress_pdf_Export"
else:
filter_name = "impress8"
filter_prop = PropertyValue()
filter_prop.Name = "FilterName"
filter_prop.Value = filter_name
properties.append(filter_prop)
doc.storeAsURL(url, tuple(properties))
ret = f"Document saved successfully to {{file_path}}"
return True
except Exception as e:
ret = f"Error saving document: {{str(e)}}"
return False
libreoffice_impress_save_as(file_path={file_path}, overwrite={overwrite})
print(ret)
"""
@agent_action
def libreoffice_impress_save_as(self, file_path, overwrite):
return self.LIBREOFFICE_IMPRESS_SAVE_AS_CMD.format(file_path=repr(file_path), overwrite=repr(overwrite))
LIBREOFFICE_IMPRESS_INSERT_IMAGE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_insert_image(slide_index, image_path, width=None, height=None, position=None):
global ret
try:
if not os.path.exists(image_path):
ret = f"Error: Image file not found at {{image_path}}"
return False
zero_based_index = slide_index - 1
slides = doc.getDrawPages()
if zero_based_index < 0 or zero_based_index >= slides.getCount():
ret = f"Error: Slide index {{slide_index}} is out of range. Valid range is 1 to {{slides.getCount()}}"
return False
slide = slides.getByIndex(zero_based_index)
bitmap = doc.createInstance("com.sun.star.drawing.BitmapTable")
image_url = uno.systemPathToFileUrl(os.path.abspath(image_path))
shape = doc.createInstance("com.sun.star.drawing.GraphicObjectShape")
shape.setPropertyValue("GraphicURL", image_url)
slide.add(shape)
x_pos = 0
y_pos = 0
slide_width = slide.Width
slide_height = slide.Height
if position:
if "x" in position:
x_pos = int(position["x"] / 100 * slide_width)
if "y" in position:
y_pos = int(position["y"] / 100 * slide_height)
current_width = shape.Size.Width
current_height = shape.Size.Height
new_width = int(width * 1000) if width is not None else current_width
new_height = int(height * 1000) if height is not None else current_height
size = uno.createUnoStruct("com.sun.star.awt.Size")
size.Width = new_width
size.Height = new_height
point = uno.createUnoStruct("com.sun.star.awt.Point")
point.X = x_pos
point.Y = y_pos
shape.Size = size
shape.Position = point
ret = f"Image inserted successfully on slide {{slide_index}}"
return True
except Exception as e:
ret = f"Error inserting image: {{str(e)}}"
return False
libreoffice_impress_insert_image(slide_index={slide_index}, image_path={image_path}, width={width}, height={height}, position={position})
print(ret)
"""
@agent_action
def libreoffice_impress_insert_image(self, slide_index, image_path, width, height, position):
return self.LIBREOFFICE_IMPRESS_INSERT_IMAGE_CMD.format(slide_index=repr(slide_index),
image_path=repr(image_path), width=repr(width),
height=repr(height), position=repr(position))
LIBREOFFICE_IMPRESS_CONFIGURE_DISPLAY_SETTINGS_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_configure_display_settings(use_presenter_view=None, primary_monitor_only=None, monitor_for_presentation=None
):
global ret
try:
controller = doc.getCurrentController()
if not hasattr(controller, "getPropertyValue"):
ret = "Error: Not an Impress presentation or controller not available"
return False
if use_presenter_view is not None:
try:
controller.setPropertyValue("IsPresentationViewEnabled", use_presenter_view)
except Exception as e:
ret = f"Warning: Could not set presenter view: {{str(e)}}"
if primary_monitor_only is not None:
try:
controller.setPropertyValue("UsePrimaryMonitorOnly", primary_monitor_only)
except Exception as e:
ret = f"Warning: Could not set primary monitor usage: {{str(e)}}"
if monitor_for_presentation is not None:
try:
controller.setPropertyValue("MonitorForPresentation", monitor_for_presentation - 1)
except Exception as e:
ret = f"Warning: Could not set presentation monitor: {{str(e)}}"
ret = "Display settings configured successfully"
return True
except Exception as e:
ret = f"Error configuring display settings: {{str(e)}}"
return False
libreoffice_impress_configure_display_settings(use_presenter_view={use_presenter_view}, primary_monitor_only={primary_monitor_only}, monitor_for_presentation={monitor_for_presentation})
print(ret)
"""
@agent_action
def libreoffice_impress_configure_display_settings(self, use_presenter_view, primary_monitor_only,
monitor_for_presentation):
return self.LIBREOFFICE_IMPRESS_CONFIGURE_DISPLAY_SETTINGS_CMD.format(
use_presenter_view=repr(use_presenter_view), primary_monitor_only=repr(primary_monitor_only),
monitor_for_presentation=repr(monitor_for_presentation))
LIBREOFFICE_IMPRESS_SET_TEXT_STRIKETHROUGH_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_text_strikethrough(slide_index, box_index, line_numbers, apply):
global ret
try:
slides = doc.getDrawPages()
slide = slides.getByIndex(slide_index - 1)
shape = slide.getByIndex(box_index)
if not hasattr(shape, "getText"):
ret = f"Error: Shape at index {{box_index}} does not contain text"
return False
text = shape.getText()
cursor = text.createTextCursor()
text_content = text.getString()
lines = text_content.split("\n")
for line_number in line_numbers:
if 1 <= line_number <= len(lines):
start_pos = 0
for i in range(line_number - 1):
start_pos += len(lines[i]) + 1
end_pos = start_pos + len(lines[line_number - 1])
cursor.gotoStart(False)
cursor.goRight(start_pos, False)
cursor.goRight(len(lines[line_number - 1]), True)
cursor.CharStrikeout = apply
ret = f"Strike-through {{'applied' if apply else 'removed'}} successfully"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_set_text_strikethrough(slide_index={slide_index}, box_index={box_index}, line_numbers={line_numbers}, apply={apply})
print(ret)
"""
@agent_action
def libreoffice_impress_set_text_strikethrough(self, slide_index, box_index, line_numbers, apply):
return self.LIBREOFFICE_IMPRESS_SET_TEXT_STRIKETHROUGH_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index),
line_numbers=repr(line_numbers),
apply=repr(apply))
LIBREOFFICE_IMPRESS_SET_TEXTBOX_ALIGNMENT_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_textbox_alignment(slide_index, box_index, alignment):
global ret
try:
zero_based_slide_index = slide_index - 1
slides = doc.getDrawPages()
if zero_based_slide_index < 0 or zero_based_slide_index >= slides.getCount():
ret = f"Error: Slide index {{slide_index}} out of range"
return False
slide = slides.getByIndex(zero_based_slide_index)
if box_index < 0 or box_index >= slide.getCount():
ret = f"Error: Box index {{box_index}} out of range"
return False
shape = slide.getByIndex(box_index)
if not hasattr(shape, "getText"):
ret = "Error: Selected shape does not support text"
return False
if alignment == "left":
shape.TextHorizontalAdjust = LEFT
elif alignment == "center":
shape.TextHorizontalAdjust = CENTER
elif alignment == "right":
shape.TextHorizontalAdjust = RIGHT
elif alignment == "justify":
text = shape.getText()
cursor = text.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
cursor.ParaAdjust = 3
else:
ret = f"Error: Invalid alignment value: {{alignment}}"
return False
ret = f"Successfully set text alignment to {{alignment}} for textbox {{box_index}} on slide {{slide_index}}"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_impress_set_textbox_alignment(slide_index={slide_index}, box_index={box_index}, alignment={alignment})
print(ret)
"""
@agent_action
def libreoffice_impress_set_textbox_alignment(self, slide_index, box_index, alignment):
return self.LIBREOFFICE_IMPRESS_SET_TEXTBOX_ALIGNMENT_CMD.format(slide_index=repr(slide_index),
box_index=repr(box_index),
alignment=repr(alignment))
LIBREOFFICE_IMPRESS_SET_SLIDE_NUMBER_COLOR_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_set_slide_number_color(color):
global ret
try:
color_map = {{
"black": 0,
"white": 16777215,
"red": 16711680,
"green": 65280,
"blue": 255,
"yellow": 16776960,
"cyan": 65535,
"magenta": 16711935,
"gray": 8421504,
"orange": 16753920,
"purple": 8388736,
}}
if color.lower() in color_map:
rgb_color = color_map[color.lower()]
else:
if color.startswith("#"):
color = color[1:]
try:
if len(color) == 6:
rgb_color = int(color, 16)
else:
rgb_color = 0
except ValueError:
rgb_color = 0
found = False
master_pages = doc.getMasterPages()
for i in range(master_pages.getCount()):
master_page = master_pages.getByIndex(i)
for j in range(master_page.getCount()):
shape = master_page.getByIndex(j)
if hasattr(shape, "getText") and shape.getText() is not None:
text = shape.getText()
try:
enum = text.createEnumeration()
while enum.hasMoreElements():
para = enum.nextElement()
if hasattr(para, "createEnumeration"):
para_enum = para.createEnumeration()
while para_enum.hasMoreElements():
portion = para_enum.nextElement()
if (
hasattr(portion, "TextPortionType")
and portion.TextPortionType == "TextField"
):
if hasattr(portion, "TextField") and portion.TextField is not None:
field = portion.TextField
if hasattr(field, "supportsService") and (
field.supportsService(
"com.sun.star.presentation.TextField.PageNumber"
)
or field.supportsService("com.sun.star.text.TextField.PageNumber")
):
portion.CharColor = rgb_color
found = True
except Exception as e:
continue
draw_pages = doc.getDrawPages()
for i in range(draw_pages.getCount()):
page = draw_pages.getByIndex(i)
for j in range(page.getCount()):
shape = page.getByIndex(j)
if hasattr(shape, "getText") and shape.getText() is not None:
text = shape.getText()
try:
enum = text.createEnumeration()
while enum.hasMoreElements():
para = enum.nextElement()
if hasattr(para, "createEnumeration"):
para_enum = para.createEnumeration()
while para_enum.hasMoreElements():
portion = para_enum.nextElement()
if (
hasattr(portion, "TextPortionType")
and portion.TextPortionType == "TextField"
):
if hasattr(portion, "TextField") and portion.TextField is not None:
field = portion.TextField
if hasattr(field, "supportsService") and (
field.supportsService(
"com.sun.star.presentation.TextField.PageNumber"
)
or field.supportsService("com.sun.star.text.TextField.PageNumber")
):
portion.CharColor = rgb_color
found = True
except Exception as e:
continue
for i in range(draw_pages.getCount()):
page = draw_pages.getByIndex(i)
for j in range(page.getCount()):
shape = page.getByIndex(j)
if hasattr(shape, "getText") and shape.getText() is not None:
text = shape.getText()
text_string = text.getString()
if text_string.isdigit() and len(text_string) <= 3:
try:
cursor = text.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
cursor.CharColor = rgb_color
found = True
except Exception as e:
continue
if found:
ret = f"Slide number color set to {{color}}"
return True
else:
ret = "Could not find slide numbers to change color"
return False
except Exception as e:
ret = f"Error setting slide number color: {{str(e)}}"
return False
libreoffice_impress_set_slide_number_color(color={color})
print(ret)
"""
@agent_action
def libreoffice_impress_set_slide_number_color(self, color):
return self.LIBREOFFICE_IMPRESS_SET_SLIDE_NUMBER_COLOR_CMD.format(color=repr(color))
LIBREOFFICE_IMPRESS_EXPORT_TO_IMAGE_CMD = """import json
import os
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.drawing.TextHorizontalAdjust import CENTER, LEFT, RIGHT
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_impress_export_to_image(file_path, format, slide_index=None):
global ret
try:
format = format.lower()
valid_formats = ["png", "jpeg", "jpg", "gif", "bmp", "tiff"]
if format not in valid_formats:
ret = f"Error: Invalid format '{{format}}'. Valid formats are: {{', '.join(valid_formats)}}"
return False
if format == "jpg":
format = "jpeg"
pages = doc.getDrawPages()
page_count = pages.getCount()
if slide_index is not None:
slide_index = slide_index - 1
if slide_index < 0 or slide_index >= page_count:
ret = f"Error: Invalid slide index {{slide_index + 1}}. Valid range is 1 to {{page_count}}"
return False
controller = doc.getCurrentController()
filter_name = f"draw_{{format}}_Export"
filter_data = PropertyValue(Name="FilterData", Value=())
if slide_index is not None:
controller.setCurrentPage(pages.getByIndex(slide_index))
props = PropertyValue(Name="FilterName", Value=filter_name), filter_data
doc.storeToURL(uno.systemPathToFileUrl(file_path), props)
ret = f"Successfully exported slide {{slide_index + 1}} to {{file_path}}"
return True
else:
base_name, ext = os.path.splitext(file_path)
for i in range(page_count):
controller.setCurrentPage(pages.getByIndex(i))
if page_count == 1:
current_file = f"{{base_name}}.{{format}}"
else:
current_file = f"{{base_name}}_{{i + 1}}.{{format}}"
props = PropertyValue(Name="FilterName", Value=filter_name), filter_data
doc.storeToURL(uno.systemPathToFileUrl(current_file), props)
if page_count == 1:
ret = f"Successfully exported {{page_count}} slides to {{base_name}}.{{format}}"
else:
ret = f"Successfully exported {{page_count}} slides to {{base_name}}_[1-{{page_count}}].{{format}}"
return True
except Exception as e:
ret = f"Error exporting to image: {{str(e)}}"
return False
libreoffice_impress_export_to_image(file_path={file_path}, format={format}, slide_index={slide_index})
print(ret)
"""
@agent_action
def libreoffice_impress_export_to_image(self, file_path, format, slide_index):
return self.LIBREOFFICE_IMPRESS_EXPORT_TO_IMAGE_CMD.format(file_path=repr(file_path), format=repr(format),
slide_index=repr(slide_index))
LIBREOFFICE_WRITER_SAVE_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_save():
global ret
try:
if doc.hasLocation():
doc.store()
else:
raise Exception("文档没有保存位置,请使用另存为功能")
return True
except Exception as e:
return False
libreoffice_writer_save()
print(ret)
"""
@agent_action
def libreoffice_writer_save(self):
return self.LIBREOFFICE_WRITER_SAVE_CMD.format()
LIBREOFFICE_WRITER_WRITE_TEXT_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
global_text = doc.Text
cursor = global_text.createTextCursor()
ret = ""
def libreoffice_writer_write_text(text, bold=False, italic=False, size=None):
global ret
cursor.CharWeight = 150 if bold else 100
cursor.CharPosture = ITALIC if italic else NONE
if size:
cursor.CharHeight = size
global_text.insertString(cursor, text, False)
ret = "Success"
libreoffice_writer_write_text(text={text}, bold={bold}, italic={italic}, size={size})
print(ret)
"""
@agent_action
def libreoffice_writer_write_text(self, text, bold, italic, size):
return self.LIBREOFFICE_WRITER_WRITE_TEXT_CMD.format(text=repr(text), bold=repr(bold), italic=repr(italic),
size=repr(size))
LIBREOFFICE_WRITER_SET_COLOR_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_color(pattern, color, paragraph_indices=None):
global ret
try:
enum = doc.Text.createEnumeration()
paragraphs = []
while enum.hasMoreElements():
paragraphs.append(enum.nextElement())
if not paragraph_indices:
paragraphs_to_process = range(len(paragraphs))
else:
paragraphs_to_process = paragraph_indices
regex = re.compile(pattern)
for idx in paragraphs_to_process:
if idx < 0 or idx >= len(paragraphs):
continue
paragraph = paragraphs[idx]
if not paragraph.supportsService("com.sun.star.text.Paragraph"):
continue
para_text = paragraph.getString()
matches = regex.finditer(para_text)
for match in matches:
para_cursor = text.createTextCursorByRange(paragraph.getStart())
para_cursor.goRight(match.start(), False)
para_cursor.goRight(match.end() - match.start(), True)
para_cursor.CharColor = color
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_writer_set_color(pattern={pattern}, color={color}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_set_color(self, pattern, color, paragraph_indices):
return self.LIBREOFFICE_WRITER_SET_COLOR_CMD.format(pattern=repr(pattern), color=repr(color),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_FIND_AND_REPLACE_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_find_and_replace(pattern, replacement, paragraph_indices=None):
global ret
try:
enum = doc.Text.createEnumeration()
paragraphs = []
while enum.hasMoreElements():
paragraphs.append(enum.nextElement())
total_replacements = 0
if not paragraph_indices:
paragraphs_to_process = list(range(len(paragraphs)))
else:
paragraphs_to_process = [i for i in paragraph_indices if 0 <= i < len(paragraphs)]
regex = re.compile(pattern)
for idx in paragraphs_to_process:
if idx >= len(paragraphs):
continue
paragraph = paragraphs[idx]
if paragraph.supportsService("com.sun.star.text.Paragraph"):
text_content = paragraph.getString()
new_text, count = regex.subn(replacement, text_content)
if count > 0:
paragraph.setString(new_text)
total_replacements += count
ret = f"Successfully made {{total_replacements}} replacements"
return ret
except Exception as e:
ret = f"Error during find and replace: {{str(e)}}"
return ret
libreoffice_writer_find_and_replace(pattern={pattern}, replacement={replacement}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_find_and_replace(self, pattern, replacement, paragraph_indices=None):
return self.LIBREOFFICE_WRITER_FIND_AND_REPLACE_CMD.format(pattern=repr(pattern), replacement=repr(replacement),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_SET_FONT_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_font(font_name, paragraph_indices=None):
global ret
try:
text = doc.getText()
enum = text.createEnumeration()
paragraphs = []
while enum.hasMoreElements():
paragraphs.append(enum.nextElement())
if not paragraph_indices:
paragraph_indices = range(len(paragraphs))
for idx in paragraph_indices:
if 0 <= idx < len(paragraphs):
paragraph = paragraphs[idx]
cursor = text.createTextCursorByRange(paragraph)
cursor.CharFontName = font_name
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_writer_set_font(font_name={font_name}, paragraph_indices={paragraph_indices})
print(ret)
"""
# @agent_action
# def libreoffice_writer_set_font(self, font_name, paragraph_indices):
#
# return self.LIBREOFFICE_WRITER_SET_FONT_CMD.format(font_name=repr(font_name),
# paragraph_indices=repr(paragraph_indices))
@agent_action
def libreoffice_writer_set_font(self, font_name, paragraph_indices=None):
return self.LIBREOFFICE_WRITER_SET_FONT_CMD.format(font_name=repr(font_name),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_SET_LINE_SPACING_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_line_spacing(spacing_value, paragraph_indices=None):
global ret
try:
text = doc.getText()
paragraph_enum = text.createEnumeration()
line_spacing_value = int(spacing_value * 100)
current_index = 0
while paragraph_enum.hasMoreElements():
paragraph = paragraph_enum.nextElement()
if not paragraph_indices or current_index in paragraph_indices:
line_spacing = uno.createUnoStruct("com.sun.star.style.LineSpacing")
line_spacing.Mode = 0
line_spacing.Height = line_spacing_value
paragraph.ParaLineSpacing = line_spacing
if paragraph.String.strip():
current_index += 1
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{str(e)}}"
return False
libreoffice_writer_set_line_spacing(spacing_value={spacing_value}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_set_line_spacing(self, spacing_value, paragraph_indices):
return self.LIBREOFFICE_WRITER_SET_LINE_SPACING_CMD.format(spacing_value=repr(spacing_value),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_REMOVE_HIGHLIGHTING_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_remove_highlighting(paragraph_indices=None):
global ret
try:
text = doc.getText()
paragraphs = text.createEnumeration()
target_indices = set(paragraph_indices) if paragraph_indices else None
current_index = 0
while paragraphs.hasMoreElements():
paragraph = paragraphs.nextElement()
if target_indices is None or current_index in target_indices:
if paragraph.supportsService("com.sun.star.text.Paragraph"):
para_cursor = text.createTextCursorByRange(paragraph)
# Remove all highlighting by setting back color to -1
para_cursor.CharBackColor = -1
# Additional cleanup for individual text portions (optional)
text_portions = paragraph.createEnumeration()
while text_portions.hasMoreElements():
text_portion = text_portions.nextElement()
if hasattr(text_portion, "CharBackColor"):
portion_cursor = text.createTextCursorByRange(text_portion)
portion_cursor.CharBackColor = -1
current_index += 1
ret = "Successfully removed all highlighting"
return ret
except Exception as e:
ret = f"Error removing highlighting: {{str(e)}}"
return ret
libreoffice_writer_remove_highlighting(paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_remove_highlighting(self, paragraph_indices):
return self.LIBREOFFICE_WRITER_REMOVE_HIGHLIGHTING_CMD.format(paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_FIND_HIGHLIGHTED_TEXT_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_find_highlighted_text(highlight_color):
global ret
color_map = {{
"yellow": 16776960,
"green": 65280,
"blue": 255,
"red": 16711680,
"cyan": 65535,
"magenta": 16711935,
"black": 0,
"white": 16777215,
"gray": 8421504,
"lightgray": 12632256,
}}
target_color = None
if highlight_color.lower() in color_map:
target_color = color_map[highlight_color.lower()]
elif highlight_color.startswith("#") and len(highlight_color) == 7:
try:
hex_color = highlight_color[1:]
r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16)
target_color = (r << 16) + (g << 8) + b
except ValueError:
ret = f"Invalid hex color format: {{highlight_color}}"
return []
else:
ret = f"Unsupported color format: {{highlight_color}}"
return []
highlighted_text = []
text = doc.getText()
enum_paragraphs = text.createEnumeration()
while enum_paragraphs.hasMoreElements():
paragraph = enum_paragraphs.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"):
enum_portions = paragraph.createEnumeration()
while enum_portions.hasMoreElements():
text_portion = enum_portions.nextElement()
if hasattr(text_portion, "CharBackColor") and text_portion.CharBackColor == target_color:
if text_portion.getString().strip():
highlighted_text.append(text_portion.getString())
ret = f"Found {{len(highlighted_text)}} text segments with highlight color {{highlight_color}}"
return highlighted_text
libreoffice_writer_find_highlighted_text(highlight_color={highlight_color})
print(ret)
"""
@agent_action
def libreoffice_writer_find_highlighted_text(self, highlight_color):
return self.LIBREOFFICE_WRITER_FIND_HIGHLIGHTED_TEXT_CMD.format(highlight_color=repr(highlight_color))
LIBREOFFICE_WRITER_INSERT_FORMULA_AT_CURSOR_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_insert_formula_at_cursor(formula):
global ret
try:
embedded_obj = doc.createInstance("com.sun.star.text.TextEmbeddedObject")
embedded_obj.setPropertyValue("CLSID", "078B7ABA-54FC-457F-8551-6147e776a997")
embedded_obj.setPropertyValue("AnchorType", AS_CHARACTER)
text.insertTextContent(cursor, embedded_obj, False)
math_obj = embedded_obj.getEmbeddedObject()
math_obj.Formula = formula
ret = "Formula inserted successfully"
return True
except Exception as e:
ret = f"Error inserting formula: {{str(e)}}"
return False
libreoffice_writer_insert_formula_at_cursor(formula={formula})
print(ret)
"""
@agent_action
def libreoffice_writer_insert_formula_at_cursor(self, formula):
return self.LIBREOFFICE_WRITER_INSERT_FORMULA_AT_CURSOR_CMD.format(formula=repr(formula))
LIBREOFFICE_WRITER_INSERT_IMAGE_AT_CURSOR_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_insert_image_at_cursor(image_path, width=None, height=None):
global ret
try:
if image_path.startswith("~"):
image_path = os.path.expanduser(image_path)
if not os.path.exists(image_path):
ret = f"Error: Image file not found at {{image_path}}"
return ret
image_path = os.path.abspath(image_path)
if os.name == "nt":
file_url = "file:///" + image_path.replace("\\", "/")
else:
file_url = "file://" + image_path
graphic = doc.createInstance("com.sun.star.text.GraphicObject")
graphic.GraphicURL = file_url
graphic.AnchorType = AS_CHARACTER
if width is not None:
graphic.Width = width * 100
if height is not None:
graphic.Height = height * 100
text.insertTextContent(cursor, graphic, False)
ret = "Success: Image inserted"
return ret
except Exception as e:
ret = f"Error: {{str(e)}}"
return ret
libreoffice_writer_insert_image_at_cursor(image_path={image_path}, width={width}, height={height})
print(ret)
"""
@agent_action
def libreoffice_writer_insert_image_at_cursor(self, image_path, width, height):
return self.LIBREOFFICE_WRITER_INSERT_IMAGE_AT_CURSOR_CMD.format(image_path=repr(image_path), width=repr(width),
height=repr(height))
LIBREOFFICE_WRITER_SET_STRIKETHROUGH_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_strikethrough(pattern, paragraph_indices=None):
global ret
try:
paragraphs = doc.getText().createEnumeration()
para_index = 0
found_matches = 0
while paragraphs.hasMoreElements():
paragraph = paragraphs.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"):
if paragraph_indices and para_index not in paragraph_indices:
para_index += 1
continue
para_text = paragraph.getString()
matches = list(re.finditer(pattern, para_text))
for match in matches:
text_range = paragraph.getStart()
cursor = doc.getText().createTextCursorByRange(text_range)
cursor.goRight(match.start(), False)
cursor.goRight(match.end() - match.start(), True)
cursor.CharStrikeout = 1
found_matches += 1
para_index += 1
ret = f"Successfully applied strikethrough to {{found_matches}} matches of pattern: {{pattern}}"
return ret
except Exception as e:
ret = f"Error applying strikethrough: {{str(e)}}"
return ret
libreoffice_writer_set_strikethrough(pattern={pattern}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_set_strikethrough(self, pattern, paragraph_indices):
return self.LIBREOFFICE_WRITER_SET_STRIKETHROUGH_CMD.format(pattern=repr(pattern),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_SET_FONT_SIZE_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_font_size(font_size, pattern, paragraph_indices=None):
global ret
try:
regex = re.compile(pattern)
paragraphs = doc.getText().createEnumeration()
current_index = 0
while paragraphs.hasMoreElements():
paragraph = paragraphs.nextElement()
if paragraph_indices and current_index not in paragraph_indices:
current_index += 1
continue
if paragraph.supportsService("com.sun.star.text.Paragraph"):
para_cursor = text.createTextCursorByRange(paragraph)
para_text = paragraph.getString()
matches = list(regex.finditer(para_text))
for match in reversed(matches):
start_pos = match.start()
end_pos = match.end()
para_cursor.gotoStart(False)
para_cursor.goRight(start_pos, False)
para_cursor.goRight(end_pos - start_pos, True)
para_cursor.CharHeight = font_size
current_index += 1
ret = f"Successfully changed font size to {{font_size}} for text matching '{{pattern}}'"
return ret
except Exception as e:
ret = f"Error changing font size: {{str(e)}}"
return ret
libreoffice_writer_set_font_size(font_size={font_size}, pattern={pattern}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_set_font_size(self, font_size, pattern, paragraph_indices):
return self.LIBREOFFICE_WRITER_SET_FONT_SIZE_CMD.format(font_size=repr(font_size), pattern=repr(pattern),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_EXPORT_TO_PDF_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_export_to_pdf(output_path=None, output_filename=None, include_comments=False, quality="standard"):
global ret
try:
doc_url = doc.getURL()
if not doc_url and not output_path:
return "Error: Document has not been saved and no output path provided"
if doc_url:
doc_path = uno.fileUrlToSystemPath(os.path.dirname(doc_url))
doc_filename = os.path.basename(doc_url)
doc_name = os.path.splitext(doc_filename)[0]
else:
doc_path = ""
doc_name = "export"
final_path = output_path if output_path else doc_path
final_filename = output_filename if output_filename else f"{{doc_name}}.pdf"
if not final_filename.lower().endswith(".pdf"):
final_filename += ".pdf"
full_output_path = os.path.join(final_path, final_filename)
output_url = uno.systemPathToFileUrl(full_output_path)
export_props = []
if quality == "high":
export_props.append(PropertyValue(Name="SelectPdfVersion", Value=1))
elif quality == "print":
export_props.append(PropertyValue(Name="SelectPdfVersion", Value=2))
else:
export_props.append(PropertyValue(Name="SelectPdfVersion", Value=0))
export_props.append(PropertyValue(Name="ExportNotes", Value=include_comments))
export_props.extend(
[
PropertyValue(Name="FilterName", Value="writer_pdf_Export"),
PropertyValue(Name="Overwrite", Value=True),
]
)
doc.storeToURL(output_url, tuple(export_props))
ret = f"PDF exported to: {{full_output_path}}"
return full_output_path
except Exception as e:
ret = f"Error exporting to PDF: {{str(e)}}"
return ret
libreoffice_writer_export_to_pdf(output_path={output_path}, output_filename={output_filename}, include_comments={include_comments}, quality={quality})
print(ret)
"""
@agent_action
def libreoffice_writer_export_to_pdf(self, output_path=None, output_filename=None, include_comments=False,
quality="standard"):
return self.LIBREOFFICE_WRITER_EXPORT_TO_PDF_CMD.format(output_path=repr(output_path),
output_filename=repr(output_filename),
include_comments=repr(include_comments),
quality=repr(quality))
# @agent_action
# def libreoffice_writer_export_to_pdf(self, output_path, output_filename, include_comments, quality):
#
# return self.LIBREOFFICE_WRITER_EXPORT_TO_PDF_CMD.format(output_path=repr(output_path),
# output_filename=repr(output_filename),
# include_comments=repr(include_comments),
# quality=repr(quality))
LIBREOFFICE_WRITER_SET_PARAGRAPH_ALIGNMENT_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_paragraph_alignment(alignment, paragraph_indices=None):
global ret
try:
alignment_map = {{"left": LEFT, "center": CENTER, "right": RIGHT, "justify": 3}}
if alignment.lower() not in alignment_map:
ret = f"Error: Invalid alignment '{{alignment}}'. Use 'left', 'center', 'right', or 'justify'."
return ret
alignment_value = alignment_map[alignment.lower()]
text = doc.getText()
paragraph_enum = text.createEnumeration()
paragraphs = []
while paragraph_enum.hasMoreElements():
paragraph = paragraph_enum.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"):
paragraphs.append(paragraph)
if paragraph_indices:
valid_indices = [i for i in paragraph_indices if 0 <= i < len(paragraphs)]
if len(valid_indices) != len(paragraph_indices):
ret = f"Warning: Some paragraph indices were out of range (0-{{len(paragraphs) - 1}})"
for idx in valid_indices:
paragraphs[idx].ParaAdjust = alignment_value
else:
for paragraph in paragraphs:
paragraph.ParaAdjust = alignment_value
ret = f"Successfully applied '{{alignment}}' alignment to paragraphs"
return ret
except Exception as e:
ret = f"Error setting paragraph alignment: {{str(e)}}"
return ret
libreoffice_writer_set_paragraph_alignment(alignment={alignment}, paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_set_paragraph_alignment(self, alignment, paragraph_indices):
return self.LIBREOFFICE_WRITER_SET_PARAGRAPH_ALIGNMENT_CMD.format(alignment=repr(alignment),
paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_CAPITALIZE_WORDS_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_capitalize_words(paragraph_indices=None):
global ret
try:
text = doc.getText()
enum = text.createEnumeration()
paragraphs = []
while enum.hasMoreElements():
paragraph = enum.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"):
paragraphs.append(paragraph)
if not paragraph_indices:
target_paragraphs = list(range(len(paragraphs)))
else:
target_paragraphs = paragraph_indices
valid_indices = [idx for idx in target_paragraphs if 0 <= idx < len(paragraphs)]
for idx in valid_indices:
paragraph = paragraphs[idx]
text_content = paragraph.getString()
if not text_content.strip():
continue
capitalized_text = " ".join(word.capitalize() if word else "" for word in text_content.split(" "))
para_cursor = text.createTextCursorByRange(paragraph.getStart())
para_cursor.gotoRange(paragraph.getEnd(), True)
para_cursor.setString(capitalized_text)
ret = f"Successfully capitalized words in {{len(valid_indices)}} paragraphs"
return ret
except Exception as e:
ret = f"Error capitalizing words: {{str(e)}}"
return ret
libreoffice_writer_capitalize_words(paragraph_indices={paragraph_indices})
print(ret)
"""
@agent_action
def libreoffice_writer_capitalize_words(self, paragraph_indices):
return self.LIBREOFFICE_WRITER_CAPITALIZE_WORDS_CMD.format(paragraph_indices=repr(paragraph_indices))
LIBREOFFICE_WRITER_SET_DEFAULT_FONT_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_set_default_font(font_name, font_size=None):
global ret
try:
style_families = doc.getStyleFamilies()
paragraph_styles = style_families.getByName("ParagraphStyles")
default_style_names = ["Default", "Standard", "Normal"]
standard_style = None
for style_name in default_style_names:
if paragraph_styles.hasByName(style_name):
standard_style = paragraph_styles.getByName(style_name)
break
if standard_style is None:
style_names = paragraph_styles.getElementNames()
if style_names:
standard_style = paragraph_styles.getByName(style_names[0])
else:
raise Exception("Could not find default paragraph style")
standard_style.setPropertyValue("CharFontName", font_name)
standard_style.setPropertyValue("CharFontNameAsian", font_name)
standard_style.setPropertyValue("CharFontNameComplex", font_name)
if font_size is not None:
standard_style.setPropertyValue("CharHeight", float(font_size))
standard_style.setPropertyValue("CharHeightAsian", float(font_size))
standard_style.setPropertyValue("CharHeightComplex", float(font_size))
cursor.setPropertyValue("CharFontName", font_name)
cursor.setPropertyValue("CharFontNameAsian", font_name)
cursor.setPropertyValue("CharFontNameComplex", font_name)
if font_size is not None:
cursor.setPropertyValue("CharHeight", float(font_size))
cursor.setPropertyValue("CharHeightAsian", float(font_size))
cursor.setPropertyValue("CharHeightComplex", float(font_size))
ret = f"Default font set to '{{font_name}}'" + (f" with size {{font_size}}pt" if font_size else "")
return ret
except Exception as e:
ret = f"Error setting default font: {{str(e)}}"
return ret
libreoffice_writer_set_default_font(font_name={font_name}, font_size={font_size})
print(ret)
"""
@agent_action
def libreoffice_writer_set_default_font(self, font_name, font_size=None):
return self.LIBREOFFICE_WRITER_SET_DEFAULT_FONT_CMD.format(font_name=repr(font_name), font_size=repr(font_size))
# @agent_action
# def libreoffice_writer_set_default_font(self, font_name, font_size):
#
# return self.LIBREOFFICE_WRITER_SET_DEFAULT_FONT_CMD.format(font_name=repr(font_name), font_size=repr(font_size))
LIBREOFFICE_WRITER_ADD_PAGE_NUMBERS_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_add_page_numbers(position, start_number=1, format=None):
global ret
try:
page_styles = doc.StyleFamilies.getByName("PageStyles")
default_style = page_styles.getByName("Standard")
try:
default_style.setPropertyValue("PageNumberOffset", start_number)
except:
pass
if position.startswith("top"):
default_style.HeaderIsOn = True
target = default_style.HeaderText
else:
default_style.FooterIsOn = True
target = default_style.FooterText
cursor = target.createTextCursor()
cursor.gotoStart(False)
cursor.gotoEnd(True)
cursor.setString("")
cursor.gotoStart(False)
if position.endswith("_left"):
cursor.ParaAdjust = LEFT
elif position.endswith("_center"):
cursor.ParaAdjust = CENTER
elif position.endswith("_right"):
cursor.ParaAdjust = RIGHT
if not format or format == "1":
page_number = doc.createInstance("com.sun.star.text.TextField.PageNumber")
page_number.NumberingType = 4
target.insertTextContent(cursor, page_number, False)
elif format == "Page 1" or "Page" in format and "of" not in format:
target.insertString(cursor, "Page ", False)
page_number = doc.createInstance("com.sun.star.text.TextField.PageNumber")
page_number.NumberingType = 4
target.insertTextContent(cursor, page_number, False)
elif format == "1 of N" or format == "Page {{page}} of {{total}}" or "of" in format:
if "Page" in format:
target.insertString(cursor, "Page ", False)
page_number = doc.createInstance("com.sun.star.text.TextField.PageNumber")
page_number.NumberingType = 4
target.insertTextContent(cursor, page_number, False)
target.insertString(cursor, " of ", False)
page_count = doc.createInstance("com.sun.star.text.TextField.PageCount")
page_count.NumberingType = 4
target.insertTextContent(cursor, page_count, False)
else:
page_number = doc.createInstance("com.sun.star.text.TextField.PageNumber")
page_number.NumberingType = 4
target.insertTextContent(cursor, page_number, False)
ret = "Successfully added page numbers"
return ret
except Exception as e:
ret = f"Error adding page numbers: {{str(e)}}"
return ret
libreoffice_writer_add_page_numbers(position={position}, start_number={start_number}, format={format})
print(ret)
"""
@agent_action
def libreoffice_writer_add_page_numbers(self, position, start_number=1, format=None):
return self.LIBREOFFICE_WRITER_ADD_PAGE_NUMBERS_CMD.format(position=repr(position),
start_number=repr(start_number),
format=repr(format))
# @agent_action
# def libreoffice_writer_add_page_numbers(self, position, start_number, format):
#
# return self.LIBREOFFICE_WRITER_ADD_PAGE_NUMBERS_CMD.format(position=repr(position),
# start_number=repr(start_number), format=repr(format))
LIBREOFFICE_WRITER_INSERT_PAGE_BREAK_CMD = """import os
import re
import uno
from com.sun.star.awt.FontSlant import ITALIC, NONE, OBLIQUE
from com.sun.star.awt.FontWeight import BOLD, NORMAL
from com.sun.star.beans import PropertyValue
from com.sun.star.style.ParagraphAdjust import CENTER, LEFT, RIGHT
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
text = doc.Text
cursor = text.createTextCursor()
ret = ""
def libreoffice_writer_insert_page_break(position="at_cursor"):
global ret
try:
if position == "end_of_document":
cursor.gotoEnd(False)
text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False)
cursor.gotoStartOfParagraph(True)
cursor.BreakType = uno.Enum("com.sun.star.style.BreakType", "PAGE_BEFORE")
ret = "Page break inserted successfully"
return True
except Exception as e:
ret = f"Error inserting page break: {{str(e)}}"
return False
libreoffice_writer_insert_page_break(position={position})
print(ret)
"""
@agent_action
def libreoffice_writer_insert_page_break(self, position):
return self.LIBREOFFICE_WRITER_INSERT_PAGE_BREAK_CMD.format(position=repr(position))
LIBREOFFICE_CALC_SAVE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_save():
global ret
try:
# Just save the document
doc.store()
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_save()
print(ret)
"""
@agent_action
def libreoffice_calc_save(self):
return self.LIBREOFFICE_CALC_SAVE_CMD.format()
LIBREOFFICE_CALC_GET_WORKBOOK_INFO_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_workbook_info():
global ret
try:
info = {{
"file_path": doc.getLocation(),
"file_title": doc.getTitle(),
"sheets": [],
"active_sheet": sheet.Name,
}}
# Get sheets information
sheets = doc.getSheets()
info["sheet_count"] = sheets.getCount()
# Get all sheet names and info
for i in range(sheets.getCount()):
sheet = sheets.getByIndex(i)
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
end_col = cursor.getRangeAddress().EndColumn
end_row = cursor.getRangeAddress().EndRow
sheet_info = {{
"name": sheet.getName(),
"index": i,
"visible": sheet.IsVisible,
"row_count": end_row + 1,
"column_count": end_col + 1,
}}
info["sheets"].append(sheet_info)
# Check if this is the active sheet
if sheet == sheet:
info["active_sheet"] = sheet_info
ret = json.dumps(info, ensure_ascii=False)
return info
except Exception as e:
ret = f"Error: {{e}}"
libreoffice_calc_get_workbook_info()
print(ret)
"""
@agent_action
def libreoffice_calc_get_workbook_info(self):
return self.LIBREOFFICE_CALC_GET_WORKBOOK_INFO_CMD.format()
LIBREOFFICE_CALC_GET_COLUMN_DATA_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_get_column_data(column_name):
global ret
column_index = libreoffice_calc_get_column_index(column_name)
if column_index is None:
return "Column not found"
last_row = libreoffice_calc_get_last_used_row()
_range = sheet.getCellRangeByPosition(column_index, 0, column_index, last_row)
# 获取数据数组并展平
ret = json.dumps([row[0] for row in _range.getDataArray()], ensure_ascii=False)
return [row[0] for row in _range.getDataArray()]
libreoffice_calc_get_column_data(column_name={column_name})
print(ret)
"""
@agent_action
def libreoffice_calc_get_column_data(self, column_name):
return self.LIBREOFFICE_CALC_GET_COLUMN_DATA_CMD.format(column_name=repr(column_name))
LIBREOFFICE_CALC_SWITCH_ACTIVE_SHEET_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_switch_active_sheet(sheet_name):
global ret
try:
# 获取所有工作表
sheets = doc.getSheets()
# 检查工作表是否存在
if not sheets.hasByName(sheet_name):
# 创建新工作表
new_sheet = doc.createInstance("com.sun.star.sheet.Spreadsheet")
sheets.insertByName(sheet_name, new_sheet)
# 获取目标工作表
sheet = sheets.getByName(sheet_name)
# 切换到目标工作表
doc.getCurrentController().setActiveSheet(sheet)
# 更新当前工作表引用
sheet = sheet
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_switch_active_sheet(sheet_name={sheet_name})
print(ret)
"""
LIBREOFFICE_CALC_GET_ACTIVE_SHEET_DATA_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_get_last_used_column():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndColumn
def libreoffice_calc_get_active_sheet_data():
global ret
try:
# 获取使用范围的最后行和列
last_row = libreoffice_calc_get_last_used_row()
last_col = libreoffice_calc_get_last_used_column()
# 如果没有数据,返回空结果
if last_row == -1 or last_col == -1:
ret = json.dumps({{"data": [], "rows": 0, "columns": 0}}, ensure_ascii=False)
return {{"data": [], "rows": 0, "columns": 0}}
# 获取整个使用范围的数据
data_range = sheet.getCellRangeByPosition(0, 0, last_col, last_row)
data_array = data_range.getDataArray()
# 转换为带坐标信息的数据结构
sheet_data = []
for row_idx, row in enumerate(data_array):
row_data = []
for col_idx, cell in enumerate(row):
# 计算Excel风格的列名 (A, B, C, ...)
col_name = chr(ord('A') + col_idx) if col_idx < 26 else f"A{{chr(ord('A') + col_idx - 26)}}"
cell_address = f"{{col_name}}{{row_idx + 1}}"
# 处理不同类型的单元格值
if isinstance(cell, (int, float)):
cell_value = cell
elif isinstance(cell, str):
cell_value = cell
else:
cell_value = str(cell)
row_data.append({{
"address": cell_address,
"value": cell_value,
"row": row_idx + 1,
"col": col_idx + 1,
"col_name": col_name,
"is_empty": cell_value == "" or cell_value == "--"
}})
sheet_data.append(row_data)
result = {{
"data": sheet_data,
"rows": last_row + 1,
"columns": last_col + 1,
"range": f"A1:{{chr(ord('A') + last_col)}}{{last_row + 1}}"
}}
ret = json.dumps(result, ensure_ascii=False)
return result
except Exception as e:
ret = f"Error: {{e}}"
return None
libreoffice_calc_get_active_sheet_data()
print(ret)
"""
@agent_action
def libreoffice_calc_get_active_sheet_data(self):
return self.LIBREOFFICE_CALC_GET_ACTIVE_SHEET_DATA_CMD.format()
@agent_action
def libreoffice_calc_switch_active_sheet(self, sheet_name):
return self.LIBREOFFICE_CALC_SWITCH_ACTIVE_SHEET_CMD.format(sheet_name=repr(sheet_name))
LIBREOFFICE_CALC_SET_COLUMN_VALUES_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_set_column_values(column_name, data, start_index=2):
global ret
column_index = libreoffice_calc_get_column_index(column_name)
if column_index is None:
ret = "Column not found"
return False
for i, value in enumerate(data):
cell = sheet.getCellByPosition(column_index, i + start_index - 1)
if isinstance(value, str) and value.startswith("="):
cell.setFormula(value) # ✅ 关键修复:公式用 setFormula
elif isinstance(value, float) and value.is_integer():
cell.setNumber(int(value))
else:
cell.setString(str(value))
ret = "Success"
return True
libreoffice_calc_set_column_values(column_name={column_name}, data={data}, start_index={start_index})
print(ret)
"""
@agent_action
def libreoffice_calc_set_column_values(self, column_name, data, start_index):
return self.LIBREOFFICE_CALC_SET_COLUMN_VALUES_CMD.format(column_name=repr(column_name), data=repr(data),
start_index=repr(start_index))
LIBREOFFICE_CALC_HIGHLIGHT_RANGE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_highlight_range(range_str, color=0xFF0000):
global ret
try:
_range = sheet.getCellRangeByName(range_str)
_range.CellBackColor = color
ret = "Success"
return True
except:
ret = "False"
return False
libreoffice_calc_highlight_range(range_str={range_str}, color={color})
print(ret)
"""
@agent_action
def libreoffice_calc_highlight_range(self, range_str, color):
"""
highlight the specified range with the specified color
Args:
range_str (str): Range to highlight, in the format of "A1:B10"
color (str): Color to highlight with, default is '0xFF0000' (red)
Returns:
bool: True if successful, False otherwise
"""
return self.LIBREOFFICE_CALC_HIGHLIGHT_RANGE_CMD.format(range_str=repr(range_str), color=repr(color))
LIBREOFFICE_CALC_TRANSPOSE_RANGE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_transpose_range(source_range, target_cell):
global ret
try:
source = sheet.getCellRangeByName(source_range)
target = sheet.getCellRangeByName(target_cell)
data = source.getDataArray()
# 转置数据
transposed_data = list(map(list, zip(*data)))
# 设置转置后的数据
target_range = sheet.getCellRangeByPosition(
target.CellAddress.Column,
target.CellAddress.Row,
target.CellAddress.Column + len(transposed_data[0]) - 1,
target.CellAddress.Row + len(transposed_data) - 1,
)
target_range.setDataArray(transposed_data)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_transpose_range(source_range={source_range}, target_cell={target_cell})
print(ret)
"""
@agent_action
def libreoffice_calc_transpose_range(self, source_range, target_cell):
"""
Transpose the specified range and paste it to the target cell
Args:
source_range (str): Range to transpose, in the format of "A1:B10"
target_cell (str): Target cell to paste the transposed data, in the format of "A1"
Returns:
bool: True if successful, False otherwise
"""
return self.LIBREOFFICE_CALC_TRANSPOSE_RANGE_CMD.format(source_range=repr(source_range),
target_cell=repr(target_cell))
LIBREOFFICE_CALC_EXPORT_TO_CSV_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_export_to_csv():
global ret
try:
# 获取当前文档的URL
doc_url = doc.getURL()
if not doc_url:
raise ValueError("Document must be saved first")
# 构造CSV文件路径
if doc_url.startswith("file://"):
base_path = doc_url[7:] # 移除 'file://' 前缀
else:
base_path = doc_url
# 获取基本路径和文件名
csv_path = os.path.splitext(base_path)[0] + ".csv"
# 确保路径是绝对路径
csv_path = os.path.abspath(csv_path)
# 转换为 LibreOffice URL 格式
csv_url = uno.systemPathToFileUrl(csv_path)
# 设置CSV导出选项
props = (
PropertyValue(Name="FilterName", Value="Text - txt - csv (StarCalc)"),
PropertyValue(
Name="FilterOptions", Value="44,0,76,0"
), # 44=comma, 34=quote, 76=UTF-8, 1=first row as header
)
# 导出文件
doc.storeToURL(csv_url, props)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_export_to_csv()
print(ret)
"""
@agent_action
def libreoffice_calc_export_to_csv(self):
return self.LIBREOFFICE_CALC_EXPORT_TO_CSV_CMD.format()
LIBREOFFICE_CALC_SORT_COLUMN_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_get_column_data(column_name):
global ret
column_index = libreoffice_calc_get_column_index(column_name)
if column_index is None:
return "Column not found"
last_row = libreoffice_calc_get_last_used_row()
_range = sheet.getCellRangeByPosition(column_index, 0, column_index, last_row)
# 获取数据数组并展平
ret = json.dumps([row[0] for row in _range.getDataArray()], ensure_ascii=False)
return [row[0] for row in _range.getDataArray()]
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_set_column_values(column_name, data, start_index=2):
global ret
# 获取列的索引
column_index = libreoffice_calc_get_column_index(column_name)
if column_index is None:
ret = "Column not found"
return False
for i, value in enumerate(data):
cell = sheet.getCellByPosition(column_index, i + start_index - 1)
if type(value) == float and value.is_integer():
cell.setNumber(int(value))
else:
cell.setString(str(value))
ret = "Success"
return True
def libreoffice_calc_sort_column(column_name, ascending=True, start_index=2):
global ret
try:
column_data = libreoffice_calc_get_column_data(column_name)[start_index - 1 :]
column_data = sorted(column_data, key=lambda x: float(x), reverse=not ascending)
except:
ret = "Error: Invalid column name or data type"
return False
return libreoffice_calc_set_column_values(column_name, column_data, start_index)
libreoffice_calc_sort_column(column_name={column_name}, ascending={ascending}, start_index={start_index})
print(ret)
"""
@agent_action
def libreoffice_calc_sort_column(self, column_name, ascending, start_index):
return self.LIBREOFFICE_CALC_SORT_COLUMN_CMD.format(column_name=repr(column_name), ascending=repr(ascending),
start_index=repr(start_index))
LIBREOFFICE_CALC_SET_VALIDATION_LIST_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_set_validation_list(column_name, values):
global ret
try:
column_index = libreoffice_calc_get_column_index(column_name)
last_row = libreoffice_calc_get_last_used_row()
cell_range = sheet.getCellRangeByPosition(column_index, 1, column_index, last_row)
# 获取现有的验证对象
validation = cell_range.getPropertyValue("Validation")
# 设置基本验证类型
validation.Type = uno.Enum("com.sun.star.sheet.ValidationType", "LIST")
validation.Operator = uno.Enum("com.sun.star.sheet.ConditionOperator", "EQUAL")
# 设置下拉列表
validation.ShowList = True
# 调试:打印实际的值
print(f"Debug: Original values = {{{{values}}}}")
# 用双引号包围每个值,这是 LibreOffice 的标准格式
values_str = ";".join('"' + str(val) + '"' for val in values)
print(f"Debug: values_str = '{{{{values_str}}}}'")
validation.Formula1 = values_str
# 应用验证设置回单元格范围
cell_range.setPropertyValue("Validation", validation)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_set_validation_list(column_name={column_name}, values={values})
print(ret)
"""
@agent_action
def libreoffice_calc_set_validation_list(self, column_name, values):
return self.LIBREOFFICE_CALC_SET_VALIDATION_LIST_CMD.format(column_name=repr(column_name), values=repr(values))
LIBREOFFICE_CALC_HIDE_ROW_DATA_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_last_used_column():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndColumn
def libreoffice_calc_get_last_used_row():
cursor = sheet.createCursor()
cursor.gotoEndOfUsedArea(False)
return cursor.RangeAddress.EndRow
def libreoffice_calc_hide_row_data(value="N/A"):
global ret
last_row = libreoffice_calc_get_last_used_row()
last_col = libreoffice_calc_get_last_used_column()
for row in range(1, last_row + 1):
has_value = False
for col in range(last_col + 1):
cell = sheet.getCellByPosition(col, row)
if cell.getString() == value:
has_value = True
break
row_range = sheet.getRows().getByIndex(row)
row_range.IsVisible = not has_value
ret = "Success"
return True
libreoffice_calc_hide_row_data(value={value})
print(ret)
"""
@agent_action
def libreoffice_calc_hide_row_data(self, value):
return self.LIBREOFFICE_CALC_HIDE_ROW_DATA_CMD.format(value=repr(value))
LIBREOFFICE_CALC_REORDER_COLUMNS_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_reorder_columns(column_order):
global ret
try:
# 获取新的列索引
new_indices = [libreoffice_calc_get_column_index(col) for col in column_order]
# 创建新的列顺序
for new_index, old_index in enumerate(new_indices):
if new_index != old_index:
sheet.Columns.insertByIndex(new_index, 1)
source = sheet.Columns[old_index + (old_index > new_index)]
target = sheet.Columns[new_index]
target.setDataArray(source.getDataArray())
sheet.Columns.removeByIndex(old_index + (old_index > new_index), 1)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_reorder_columns(column_order={column_order})
print(ret)
"""
@agent_action
def libreoffice_calc_reorder_columns(self, column_order):
return self.LIBREOFFICE_CALC_REORDER_COLUMNS_CMD.format(column_order=repr(column_order))
LIBREOFFICE_CALC_CREATE_PIVOT_TABLE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_get_column_index(column_name, sheet=None):
try:
return ord(column_name[0]) - ord("A")
except ValueError:
return None
def libreoffice_calc_create_pivot_table(source_sheet,
table_name,
row_fields=None,
col_fields=None,
value_fields=None,
aggregation_function="sum",
target_cell="A1",
):
global ret
try:
source = doc.getSheets().getByName(source_sheet)
# 获取数据范围
cursor = source.createCursor()
cursor.gotoEndOfUsedArea(False)
end_col = cursor.getRangeAddress().EndColumn
end_row = cursor.getRangeAddress().EndRow
# 获取完整的数据范围
source_range = source.getCellRangeByPosition(0, 0, end_col, end_row)
# 获取数据透视表集合
dp_tables = sheet.getDataPilotTables()
# 创建数据透视表描述符
dp_descriptor = dp_tables.createDataPilotDescriptor()
# 设置数据源
dp_descriptor.setSourceRange(source_range.getRangeAddress())
# 设置行字段
if row_fields:
for field in row_fields:
field_index = libreoffice_calc_get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "ROW")
# 设置列字段
if col_fields:
for field in col_fields:
field_index = libreoffice_calc_get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "COLUMN")
# 设置数据字段
for field in value_fields:
field_index = libreoffice_calc_get_column_index(field)
dimension = dp_descriptor.getDataPilotFields().getByIndex(field_index)
dimension.Orientation = uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", "DATA")
# 设置聚合函数
function_map = {{"Count": "COUNT", "Sum": "SUM", "Average": "AVERAGE", "Min": "MIN", "Max": "MAX"}}
if aggregation_function in function_map:
dimension.Function = uno.Enum(
"com.sun.star.sheet.GeneralFunction", function_map[aggregation_function]
)
# 在当前工作表中创建数据透视表
dp_tables.insertNewByName(
table_name, # 透视表名称
sheet.getCellRangeByName(target_cell).CellAddress, # 目标位置
dp_descriptor, # 描述符
)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_create_pivot_table(source_sheet={source_sheet}, table_name={table_name}, row_fields={row_fields}, col_fields={col_fields}, value_fields={value_fields}, aggregation_function={aggregation_function}, target_cell={target_cell})
print(ret)
"""
@agent_action
def libreoffice_calc_create_pivot_table(self, source_sheet, table_name, row_fields, col_fields, value_fields,
aggregation_function, target_cell):
return self.LIBREOFFICE_CALC_CREATE_PIVOT_TABLE_CMD.format(source_sheet=repr(source_sheet),
table_name=repr(table_name),
row_fields=repr(row_fields),
col_fields=repr(col_fields),
value_fields=repr(value_fields),
aggregation_function=repr(aggregation_function),
target_cell=repr(target_cell))
LIBREOFFICE_CALC_MERGE_CELLS_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
ret = ""
def libreoffice_calc_merge_cells(sheet_name, range_str):
global ret
try:
# 通过名称获取指定的工作表
sheet = doc.getSheets().getByName(sheet_name)
# 获取单元格范围
cell_range = sheet.getCellRangeByName(range_str)
# 检查单元格是否已经合并
is_merged = cell_range.getIsMerged()
# 如果单元格范围尚未合并,则进行合并
if not is_merged:
cell_range.merge(True)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
# 调用函数时需要传入 sheet_name 和 range_str 两个参数
libreoffice_calc_merge_cells(sheet_name={sheet_name}, range_str={range_str})
print(ret)
"""
@agent_action
def libreoffice_calc_merge_cells(self, sheet_name, range_str):
"""
Merges a specified range of cells within a specific worksheet.
Args:
sheet_name (str): The name of the worksheet, e.g., 'Sheet1'.
range_str (str): The cell range to merge, e.g., 'A1:B10'.
Returns:
str: A formatted command string to be executed.
"""
return self.LIBREOFFICE_CALC_MERGE_CELLS_CMD.format(
sheet_name=repr(sheet_name),
range_str=repr(range_str)
)
LIBREOFFICE_CALC_SET_CELL_VALUE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_set_cell_value(cell, value):
global ret
try:
# 获取单元格对象
cell_obj = sheet.getCellRangeByName(cell)
if isinstance(value, str) and value.startswith("="):
# 设置公式
cell_obj.Formula = value
ret = "Success"
return True
# 尝试将值转换为数字
try:
# 尝试转换为整数
int_value = int(value)
cell_obj.Value = int_value
except ValueError:
try:
# 尝试转换为浮点数
float_value = float(value)
cell_obj.Value = float_value
except ValueError:
# 如果不是数字,则设置为字符串
cell_obj.String = value
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_set_cell_value(cell={cell}, value={value})
print(ret)
"""
@agent_action
def libreoffice_calc_set_cell_value(self, cell, value):
return self.LIBREOFFICE_CALC_SET_CELL_VALUE_CMD.format(cell=repr(cell), value=repr(value))
LIBREOFFICE_CALC_FORMAT_RANGE_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_format_range(range_str, background_color=None, font_color=None, bold=None, alignment=None):
global ret
try:
# 获取指定范围
cell_range = sheet.getCellRangeByName(range_str)
# 设置背景颜色
if background_color:
# 将十六进制颜色转换为整数
bg_color_int = int(background_color.replace("#", ""), 16)
cell_range.CellBackColor = bg_color_int
# 设置字体颜色
if font_color:
# 将十六进制颜色转换为整数
font_color_int = int(font_color.replace("#", ""), 16)
cell_range.CharColor = font_color_int
# 设置粗体
if bold is not None:
cell_range.CharWeight = 150.0 if bold else 100.0 # 150.0 是粗体100.0 是正常
# 设置对齐方式
if alignment:
# 设置水平对齐方式
struct = cell_range.getPropertyValue("HoriJustify")
if alignment == "left":
struct.value = "LEFT"
elif alignment == "center":
struct.value = "CENTER"
elif alignment == "right":
struct.value = "RIGHT"
cell_range.setPropertyValue("HoriJustify", struct)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_format_range(range_str={range_str}, background_color={background_color}, font_color={font_color}, bold={bold}, alignment={alignment})
print(ret)
"""
@agent_action
def libreoffice_calc_format_range(self, range_str, background_color, font_color, bold, alignment):
return self.LIBREOFFICE_CALC_FORMAT_RANGE_CMD.format(range_str=repr(range_str),
background_color=repr(background_color),
font_color=repr(font_color), bold=repr(bold),
alignment=repr(alignment))
LIBREOFFICE_CALC_INSERT_CHART_CMD = """import json
import os
import subprocess
import sys
import uno
import time
from com.sun.star.beans import PropertyValue
from com.sun.star.awt import Rectangle
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_insert_chart(
chart_type="column",
data_ranges=None,
first_row_as_label=True,
first_column_as_label=True,
data_series_in_rows=False,
title=None,
subtitle=None,
x_axis_title=None,
y_axis_title=None,
display_x_grid=False,
display_y_grid=True,
chart_name=None,
chart_position=None,
chart_size=None
):
global ret
try:
# 生成唯一的图表名称
if chart_name is None:
import time
timestamp = str(int(time.time() * 1000)) # 使用毫秒时间戳
chart_name = f"Chart_{{timestamp}}"
# 图表类型映射
chart_type_map = {{
"column": "com.sun.star.chart.ColumnDiagram",
"line": "com.sun.star.chart.LineDiagram"
}}
if chart_type not in chart_type_map:
ret = f"Error: Unsupported chart type '{{chart_type}}'. Supported: column, line"
return False
# 处理数据范围
if isinstance(data_ranges, str):
if "," in data_ranges:
range_list = [r.strip() for r in data_ranges.split(",")]
else:
range_list = [data_ranges]
elif isinstance(data_ranges, list):
range_list = data_ranges
else:
ret = "Error: data_ranges must be string or list"
return False
# 转换数据范围为CellRangeAddress对象
cell_ranges = []
for range_str in range_list:
try:
cell_range = sheet.getCellRangeByName(range_str.replace("$", ""))
cell_ranges.append(cell_range.getRangeAddress())
except Exception as e:
ret = f"Error processing range '{{range_str}}': {{e}}"
return False
# 设置图表位置和大小
if chart_position and chart_size:
rect = Rectangle(
chart_position.get("x", 1000),
chart_position.get("y", 1000),
chart_size.get("width", 10000),
chart_size.get("height", 7000)
)
elif chart_position:
rect = Rectangle(
chart_position.get("x", 1000),
chart_position.get("y", 1000),
10000, 7000
)
else:
rect = Rectangle(1000, 1000, 10000, 7000)
# 创建图表
charts = sheet.Charts
charts.addNewByName(chart_name, rect, tuple(cell_ranges), first_row_as_label, first_column_as_label)
# 获取图表对象
chart_obj = charts.getByName(chart_name)
chart_doc = chart_obj.EmbeddedObject
# 创建并设置图表类型
diagram = chart_doc.createInstance(chart_type_map[chart_type])
chart_doc.setDiagram(diagram)
# 设置数据系列排列方向
try:
if hasattr(chart_doc, 'setDataSourceLabelsInFirstRow'):
chart_doc.setDataSourceLabelsInFirstRow(not data_series_in_rows)
if hasattr(chart_doc, 'setDataSourceLabelsInFirstColumn'):
chart_doc.setDataSourceLabelsInFirstColumn(data_series_in_rows)
except Exception as e:
print(f"Warning: Failed to set data series orientation: {{e}}")
# 设置图表标题
if title:
try:
title_obj = chart_doc.getTitle()
if not title_obj:
title_obj = chart_doc.createInstance("com.sun.star.chart.Title")
chart_doc.setTitleObject(title_obj)
title_obj.String = title
except Exception as e:
print(f"Warning: Failed to set title: {{e}}")
# 设置副标题
if subtitle:
try:
subtitle_obj = chart_doc.getSubTitle()
if not subtitle_obj:
subtitle_obj = chart_doc.createInstance("com.sun.star.chart.Title")
chart_doc.setSubTitleObject(subtitle_obj)
subtitle_obj.String = subtitle
except Exception as e:
print(f"Warning: Failed to set subtitle: {{e}}")
# 设置坐标轴标题
if x_axis_title or y_axis_title:
try:
if hasattr(diagram, 'XAxisTitle') and x_axis_title:
diagram.HasXAxisTitle = True
x_title = diagram.XAxisTitle
x_title.String = x_axis_title
if hasattr(diagram, 'YAxisTitle') and y_axis_title:
diagram.HasYAxisTitle = True
y_title = diagram.YAxisTitle
y_title.String = y_axis_title
except Exception as e:
print(f"Warning: Failed to set axis titles: {{e}}")
# 设置网格线
try:
if hasattr(diagram, 'HasXAxisGrid'):
diagram.HasXAxisGrid = display_x_grid
if hasattr(diagram, 'HasYAxisGrid'):
diagram.HasYAxisGrid = display_y_grid
except Exception as e:
print(f"Warning: Failed to set grid lines: {{e}}")
ret = "Chart created successfully"
return True
except Exception as e:
ret = f"Error creating chart: {{e}}"
return False
libreoffice_calc_insert_chart(chart_type={chart_type}, data_ranges={data_ranges}, first_row_as_label={first_row_as_label}, first_column_as_label={first_column_as_label}, data_series_in_rows={data_series_in_rows}, title={title}, subtitle={subtitle}, x_axis_title={x_axis_title}, y_axis_title={y_axis_title}, display_x_grid={display_x_grid}, display_y_grid={display_y_grid}, chart_name={chart_name}, chart_position={chart_position}, chart_size={chart_size})
print(ret)"""
@agent_action
def libreoffice_calc_insert_chart(self, chart_type="column", data_ranges=None, first_row_as_label=True,
first_column_as_label=True, data_series_in_rows=False, title=None,
subtitle=None, x_axis_title=None, y_axis_title=None, display_x_grid=False,
display_y_grid=True, chart_name=None, chart_position=None, chart_size=None):
return self.LIBREOFFICE_CALC_INSERT_CHART_CMD.format(chart_type=repr(chart_type), data_ranges=repr(data_ranges),
first_row_as_label=repr(first_row_as_label),
first_column_as_label=repr(first_column_as_label),
data_series_in_rows=repr(data_series_in_rows),
title=repr(title), subtitle=repr(subtitle),
x_axis_title=repr(x_axis_title),
y_axis_title=repr(y_axis_title),
display_x_grid=repr(display_x_grid),
display_y_grid=repr(display_y_grid),
chart_name=repr(chart_name),
chart_position=repr(chart_position),
chart_size=repr(chart_size))
LIBREOFFICE_CALC_FREEZE_PANES_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_freeze_panes(rows=0, columns=0):
global ret
try:
# 获取当前视图
view = doc.getCurrentController()
# 设置冻结窗格
view.freezeAtPosition(columns, rows)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_freeze_panes(rows={rows}, columns={columns})
print(ret)
"""
@agent_action
def libreoffice_calc_freeze_panes(self, rows, columns):
return self.LIBREOFFICE_CALC_FREEZE_PANES_CMD.format(rows=repr(rows), columns=repr(columns))
LIBREOFFICE_CALC_RENAME_SHEET_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_rename_sheet(old_name, new_name):
global ret
try:
# 获取所有工作表
sheets = doc.getSheets()
# 检查原工作表是否存在
if not sheets.hasByName(old_name):
return False
# 检查新名称是否已存在
if sheets.hasByName(new_name):
return False
# 获取要重命名的工作表
sheet = sheets.getByName(old_name)
# 重命名工作表
sheet.setName(new_name)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_rename_sheet(old_name={old_name}, new_name={new_name})
print(ret)
"""
@agent_action
def libreoffice_calc_rename_sheet(self, old_name, new_name):
return self.LIBREOFFICE_CALC_RENAME_SHEET_CMD.format(old_name=repr(old_name), new_name=repr(new_name))
LIBREOFFICE_CALC_COPY_SHEET_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_copy_sheet(source_sheet, new_sheet_name=None):
global ret
try:
# 获取所有工作表
sheets = doc.getSheets()
# 检查源工作表是否存在
if not sheets.hasByName(source_sheet):
return None
# 如果没有提供新名称,则生成一个
if not new_sheet_name:
# 生成类似 "Sheet1 (2)" 的名称
base_name = source_sheet
counter = 1
new_sheet_name = f"{{base_name}} ({{counter}})"
# 确保名称不重复
while sheets.hasByName(new_sheet_name):
counter += 1
new_sheet_name = f"{{base_name}} ({{counter}})"
# 检查新名称是否已存在
if sheets.hasByName(new_sheet_name):
return None # 名称已存在,无法创建
# 获取源工作表的索引
source_index = -1
for i in range(sheets.getCount()):
if sheets.getByIndex(i).getName() == source_sheet:
source_index = i
break
if source_index == -1:
return None
# 复制工作表
sheets.copyByName(source_sheet, new_sheet_name, source_index + 1)
ret = f"New sheet created: {{new_sheet_name}}"
return new_sheet_name
except Exception as e:
ret = f"Error: {{e}}"
return None
libreoffice_calc_copy_sheet(source_sheet={source_sheet}, new_sheet_name={new_sheet_name})
print(ret)
"""
@agent_action
def libreoffice_calc_copy_sheet(self, source_sheet, new_sheet_name):
return self.LIBREOFFICE_CALC_COPY_SHEET_CMD.format(source_sheet=repr(source_sheet),
new_sheet_name=repr(new_sheet_name))
LIBREOFFICE_CALC_REORDER_SHEETS_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_reorder_sheets(sheet_name, position):
global ret
try:
# 获取所有工作表
sheets = doc.getSheets()
# 检查工作表是否存在
if not sheets.hasByName(sheet_name):
return False
# 获取工作表总数
sheet_count = sheets.getCount()
# 检查位置是否有效
if position < 0 or position >= sheet_count:
return False
# 获取要移动的工作表
sheet = sheets.getByName(sheet_name)
# 获取工作表当前索引
current_index = -1
for i in range(sheet_count):
if sheets.getByIndex(i).Name == sheet_name:
current_index = i
break
if current_index == -1:
return False
# 移动工作表到指定位置
sheets.moveByName(sheet_name, position)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_reorder_sheets(sheet_name={sheet_name}, position={position})
print(ret)
"""
@agent_action
def libreoffice_calc_reorder_sheets(self, sheet_name, position):
return self.LIBREOFFICE_CALC_REORDER_SHEETS_CMD.format(sheet_name=repr(sheet_name), position=repr(position))
LIBREOFFICE_CALC_SET_CHART_LEGEND_POSITION_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_set_chart_legend_position(position):
global ret
try:
# 获取当前工作表中的所有图表
charts = sheet.getCharts()
if charts.getCount() == 0:
return False
# 获取第一个图表(假设我们要修改的是第一个图表)
chart = charts.getByIndex(0)
chart_obj = chart.getEmbeddedObject()
# 获取图表的图例
diagram = chart_obj.getDiagram()
legend = chart_obj.getLegend()
# 根据指定的位置设置图例位置
if position == "none":
# 如果选择"none",则隐藏图例
chart_obj.HasLegend = False
else:
# 确保图例可见
chart_obj.HasLegend = True
import inspect
print(inspect.getmembers(legend))
# 设置图例位置
if position == "top":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "TOP")
elif position == "bottom":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "BOTTOM")
elif position == "left":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "LEFT")
elif position == "right":
pos = uno.Enum("com.sun.star.chart.ChartLegendPosition", "RIGHT")
legend.Alignment = pos
ret = "Success"
return True
except Exception:
ret = "Error"
return False
libreoffice_calc_set_chart_legend_position(position={position})
print(ret)
"""
@agent_action
def libreoffice_calc_set_chart_legend_position(self, position):
return self.LIBREOFFICE_CALC_SET_CHART_LEGEND_POSITION_CMD.format(position=repr(position))
LIBREOFFICE_CALC_SET_NUMBER_FORMAT_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_set_number_format(range_str, format_type, decimal_places=None):
global ret
try:
# 获取单元格范围
cell_range = sheet.getCellRangeByName(range_str)
# 获取数字格式化服务
number_formats = doc.NumberFormats
locale = doc.CharLocale
# 根据格式类型设置格式字符串
format_string = ""
if format_type == "general":
format_string = "General"
elif format_type == "number":
if decimal_places is not None:
format_string = f"0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}"
else:
format_string = "0"
elif format_type == "currency":
if decimal_places is not None:
format_string = f"[$¥-804]#,##0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}"
else:
format_string = "[$¥-804]#,##0.00"
elif format_type == "accounting":
if decimal_places is not None:
format_string = f"_-[$¥-804]* #,##0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}_-;-[$¥-804]* #,##0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}_-;_-[$¥-804]* \"-\"_-;_-@_-"
else:
format_string = '_-[$¥-804]* #,##0.00_-;-[$¥-804]* #,##0.00_-;_-[$¥-804]* "-"??_-;_-@_-'
elif format_type == "date":
format_string = "YYYY/MM/DD"
elif format_type == "time":
format_string = "HH:MM:SS"
elif format_type == "percentage":
if decimal_places is not None:
format_string = f"0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}%"
else:
format_string = "0.00%"
elif format_type == "fraction":
format_string = "# ?/?"
elif format_type == "scientific":
if decimal_places is not None:
format_string = f"0{{('.' + '0' * decimal_places) if decimal_places > 0 else ''}}E+00"
else:
format_string = "0.00E+00"
elif format_type == "text":
format_string = "@"
# 获取格式键
format_key = number_formats.queryKey(format_string, locale, True)
# 如果格式不存在,则添加
if format_key == -1:
format_key = number_formats.addNew(format_string, locale)
# 应用格式
cell_range.NumberFormat = format_key
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_set_number_format(range_str={range_str}, format_type={format_type}, decimal_places={decimal_places})
print(ret)
"""
@agent_action
def libreoffice_calc_set_number_format(self, range_str, format_type, decimal_places):
return self.LIBREOFFICE_CALC_SET_NUMBER_FORMAT_CMD.format(range_str=repr(range_str),
format_type=repr(format_type),
decimal_places=repr(decimal_places))
LIBREOFFICE_CALC_ADJUST_COLUMN_WIDTH_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_column_name_to_index(column_name):
column_name = column_name.upper()
result = 0
for char in column_name:
result = result * 26 + (ord(char) - ord("A") + 1)
return result - 1
def libreoffice_calc_adjust_column_width(columns, width=None, autofit=False):
global ret
try:
# 解析列范围
col_range = columns.split(":")
start_col = libreoffice_calc_column_name_to_index(col_range[0])
if len(col_range) > 1:
end_col = libreoffice_calc_column_name_to_index(col_range[1])
else:
end_col = start_col
# 获取列对象
columns_obj = sheet.getColumns()
# 遍历指定的列范围
for col_idx in range(start_col, end_col + 1):
column = columns_obj.getByIndex(col_idx)
if autofit:
# 自动调整列宽
column.OptimalWidth = True
elif width is not None:
# 设置指定宽度转换为1/100毫米
# 大约一个字符宽度为256 (1/100 mm)
column.Width = int(width * 256)
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_adjust_column_width(columns={columns}, width={width}, autofit={autofit})
print(ret)
"""
@agent_action
def libreoffice_calc_adjust_column_width(self, columns, width, autofit):
return self.LIBREOFFICE_CALC_ADJUST_COLUMN_WIDTH_CMD.format(columns=repr(columns), width=repr(width),
autofit=repr(autofit))
LIBREOFFICE_CALC_ADJUST_ROW_HEIGHT_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_adjust_row_height(rows, height=None, autofit=False):
global ret
try:
# 解析行范围
row_range = rows.split(":")
start_row = int(row_range[0])
end_row = int(row_range[1]) if len(row_range) > 1 else start_row
# 获取行对象
for row_index in range(start_row, end_row + 1):
row = sheet.getRows().getByIndex(row_index - 1) # 索引从0开始
if autofit:
# 自动调整行高以适应内容
row.OptimalHeight = True
elif height is not None:
# 设置指定高度将点转换为1/100毫米LibreOffice使用的单位
# 1点 ≈ 35.28 1/100毫米
row.Height = int(height * 35.28)
row.OptimalHeight = False
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_adjust_row_height(rows={rows}, height={height}, autofit={autofit})
print(ret)
"""
@agent_action
def libreoffice_calc_adjust_row_height(self, rows, height, autofit):
return self.LIBREOFFICE_CALC_ADJUST_ROW_HEIGHT_CMD.format(rows=repr(rows), height=repr(height),
autofit=repr(autofit))
LIBREOFFICE_CALC_EXPORT_TO_PDF_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_export_to_pdf(file_path=None, sheets=None, open_after_export=False):
global ret
try:
# 如果未指定文件路径,则使用当前文档路径并更改扩展名为.pdf
if not file_path:
if doc.hasLocation():
url = doc.getLocation()
file_path = uno.fileUrlToSystemPath(url)
file_path = os.path.splitext(file_path)[0] + ".pdf"
else:
# 如果文档尚未保存,则在用户桌面创建临时文件
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
file_path = os.path.join(desktop_path, "LibreOffice_Export.pdf")
# 确保文件路径是系统路径然后转换为URL
pdf_url = uno.systemPathToFileUrl(os.path.abspath(file_path))
# 创建导出属性
export_props = []
# 设置过滤器名称
export_props.append(PropertyValue(Name="FilterName", Value="calc_pdf_Export"))
# 如果指定了特定工作表,则只导出这些工作表
if sheets and isinstance(sheets, list) and len(sheets) > 0:
# 获取所有工作表
all_sheets = doc.getSheets()
selection = []
# 查找指定的工作表
for sheet_name in sheets:
if all_sheets.hasByName(sheet_name):
sheet = all_sheets.getByName(sheet_name)
selection.append(sheet)
# 如果找到了指定的工作表,则设置导出选择
if selection:
export_props.append(PropertyValue(Name="Selection", Value=tuple(selection)))
# 导出PDF
doc.storeToURL(pdf_url, tuple(export_props))
# 如果需要导出后打开PDF
if open_after_export:
if sys.platform.startswith("darwin"): # macOS
subprocess.call(("open", file_path))
elif os.name == "nt": # Windows
os.startfile(file_path)
elif os.name == "posix": # Linux
subprocess.call(("xdg-open", file_path))
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_export_to_pdf(file_path={file_path}, sheets={sheets}, open_after_export={open_after_export})
print(ret)
"""
@agent_action
def libreoffice_calc_export_to_pdf(self, file_path, sheets, open_after_export):
return self.LIBREOFFICE_CALC_EXPORT_TO_PDF_CMD.format(file_path=repr(file_path), sheets=repr(sheets),
open_after_export=repr(open_after_export))
LIBREOFFICE_CALC_SET_ZOOM_LEVEL_CMD = """import json
import os
import subprocess
import sys
import uno
from com.sun.star.beans import PropertyValue
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
desktop = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.CurrentController.ActiveSheet
ret = ""
def libreoffice_calc_set_zoom_level(zoom_percentage):
global ret
try:
# 获取当前控制器
controller = doc.getCurrentController()
# 设置缩放值
# 确保缩放值在合理范围内
if zoom_percentage < 10:
zoom_percentage = 10
elif zoom_percentage > 400:
zoom_percentage = 400
# 应用缩放值
controller.ZoomValue = zoom_percentage
ret = "Success"
return True
except Exception as e:
ret = f"Error: {{e}}"
return False
libreoffice_calc_set_zoom_level(zoom_percentage={zoom_percentage})
print(ret)
"""
@agent_action
def libreoffice_calc_set_zoom_level(self, zoom_percentage):
return self.LIBREOFFICE_CALC_SET_ZOOM_LEVEL_CMD.format(zoom_percentage=repr(zoom_percentage))
# ACI that supports the worker-only mode: done() and fail() become task scoped instead
class OSWorldWorkerOnlyACI(OSWorldACI):
@agent_action
def done(
self,
):
"""End the current task with a success. Use this when you believe the entire task has been fully completed."""
return """DONE"""
@agent_action
def fail(self):
"""End the current task with a failure. Use this when you believe the entire task is impossible to complete."""
return """FAIL"""