5253 lines
207 KiB
Python
5253 lines
207 KiB
Python
"""
|
||
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"""
|