diff --git a/lollms/functions/calculator.py b/lollms/functions/calculator.py new file mode 100644 index 0000000..ef3728f --- /dev/null +++ b/lollms/functions/calculator.py @@ -0,0 +1,22 @@ +import math +from functools import partial + +def calculate(expression: str) -> float: + try: + # Add the math module functions to the local namespace + allowed_names = {k: v for k, v in math.__dict__.items() if not k.startswith("__")} + + # Evaluate the expression safely using the allowed names + result = eval(expression, {"__builtins__": None}, allowed_names) + return result + except Exception as e: + return str(e) + + +def calculate_function(processor, client): + return { + "function_name": "calculate", + "function": calculate, + "function_description": "Whenever you need to perform mathematic computations, you can call this function with the math expression and you will get the answer.", + "function_parameters": [{"name": "expression", "type": "str"}] + } \ No newline at end of file diff --git a/lollms/functions/take_a_photo.py b/lollms/functions/take_a_photo.py index a0379eb..620f030 100644 --- a/lollms/functions/take_a_photo.py +++ b/lollms/functions/take_a_photo.py @@ -72,7 +72,7 @@ class CameraWindow(QtWidgets.QWidget): self.cap.release() event.accept() -def take_photo(processor, client, use_ui=False): +def take_photo(processor, client, use_ui=False, use_a_single_photo_at_a_time=True): if use_ui: def run_app(): app = QtWidgets.QApplication(sys.argv) @@ -113,15 +113,17 @@ def take_photo(processor, client, use_ui=False): fn = image/f"screen_shot_{index}.png" cv2.imwrite(str(fn), frame) client.discussion.image_files.append(fn) + if use_a_single_photo_at_a_time: + client.discussion.image_files = [client.discussion.image_files[-1]] processor.full(f'') processor.new_message("") return "Image shot successful" -def take_a_photo_function(processor, client, use_ui = False): +def take_a_photo_function(processor, client, use_ui = False, use_a_single_photo_at_a_time=True): return { "function_name": "take_photo", - "function": partial(take_photo, processor=processor, client=client, use_ui = use_ui), + "function": partial(take_photo, processor=processor, client=client, use_ui = use_ui, use_a_single_photo_at_a_time = use_a_single_photo_at_a_time), "function_description": "Uses the webcam to take a photo, displays it so that you can take a look.", "function_parameters": [] } diff --git a/lollms/functions/take_screen_shot.py b/lollms/functions/take_screen_shot.py index 683b4c6..a5ad71d 100644 --- a/lollms/functions/take_screen_shot.py +++ b/lollms/functions/take_screen_shot.py @@ -14,12 +14,13 @@ from functools import partial class ScreenshotWindow(QtWidgets.QWidget): - def __init__(self, client, screenshot, fn_view, fn): + def __init__(self, client, screenshot, fn_view, fn, use_a_single_photo_at_a_time= True): super().__init__() self.client = client self.screenshot = screenshot self.fn_view = fn_view self.fn = fn + self.use_a_single_photo_at_a_time = use_a_single_photo_at_a_time self.initUI() @@ -42,10 +43,13 @@ class ScreenshotWindow(QtWidgets.QWidget): self.screenshot.save(self.fn_view) self.screenshot.save(self.fn) self.client.discussion.image_files.append(self.fn) + if self.use_a_single_photo_at_a_time: + self.client.discussion.image_files = [self.client.discussion.image_files[-1]] + self.close() -def take_screenshot(self, client: Client, use_ui: bool = False): +def take_screenshot(self, client: Client, use_ui: bool = False, use_a_single_photo_at_a_time= True): screenshot = pyautogui.screenshot() view_image = client.discussion.discussion_folder / "view_images" image = client.discussion.discussion_folder / "images" @@ -55,7 +59,7 @@ def take_screenshot(self, client: Client, use_ui: bool = False): if use_ui: app = QtWidgets.QApplication(sys.argv) - window = ScreenshotWindow(client, screenshot, fn_view, fn) + window = ScreenshotWindow(client, screenshot, fn_view, fn, use_a_single_photo_at_a_time) window.show() app.exec_() return f'' @@ -63,15 +67,15 @@ def take_screenshot(self, client: Client, use_ui: bool = False): screenshot.save(fn_view) screenshot.save(fn) client.discussion.image_files.append(fn) + if use_a_single_photo_at_a_time: + client.discussion.image_files = [client.discussion.image_files[-1]] + return f'' -def take_screenshot_function(client): +def take_screenshot_function(client, use_ui=True, use_a_single_photo_at_a_time= True): return { "function_name": "take_screenshot", - "function": partial(take_screenshot, client=client), - "function_description": "Takes a screenshot of the current screen. Optionally allows user interface for image cropping and saving.", - "function_parameters": [ - {"name": "client", "type": "Client", "description": "The client object managing the discussion and images."}, - {"name": "use_ui", "type": "bool", "default": False, "description": "Flag to determine if a user interface should be used for editing the screenshot."} - ] + "function": partial(take_screenshot, client=client, use_ui = use_ui, use_a_single_photo_at_a_time= use_a_single_photo_at_a_time), + "function_description": "Takes a screenshot of the current screen.", + "function_parameters": [] } \ No newline at end of file diff --git a/lollms/media.py b/lollms/media.py index e97feca..1bd20d5 100644 --- a/lollms/media.py +++ b/lollms/media.py @@ -148,7 +148,9 @@ class RTCom: self.snd_input_device = snd_input_device self.snd_output_device = snd_output_device - self.logs_folder = logs_folder + self.logs_folder = Path(logs_folder) + + self.logs_folder.mkdir(exist_ok=True, parents=True) self.frames = [] self.silence_counter = 0 diff --git a/lollms/personality.py b/lollms/personality.py index 770c844..85c6e3c 100644 --- a/lollms/personality.py +++ b/lollms/personality.py @@ -3435,12 +3435,14 @@ The AI should respond in this format using data from actions_list: return function_calls - def interact_with_function_call(self, prompt, function_definitions, prompt_after_execution=True, callback = None): + def interact_with_function_call(self, prompt, function_definitions, prompt_after_execution=True, callback = None, hide_function_call=False): if len(self.personality.image_files)>0: out, function_calls = self.generate_with_function_calls_and_images(prompt, self.personality.image_files, function_definitions, callback=callback) else: out, function_calls = self.generate_with_function_calls(prompt, function_definitions, callback=callback) if len(function_calls)>0: + if hide_function_call: + self.full("") #Hide function call outputs = self.execute_function_calls(function_calls,function_definitions) out += "\n!@>function calls results:\n" + "\n".join([str(o) for o in outputs]) if prompt_after_execution: diff --git a/lollms/services/open_ai_tts/lollms_openai_tts.py b/lollms/services/open_ai_tts/lollms_openai_tts.py index ddaba40..7c11628 100644 --- a/lollms/services/open_ai_tts/lollms_openai_tts.py +++ b/lollms/services/open_ai_tts/lollms_openai_tts.py @@ -109,6 +109,7 @@ class LollmsOpenAITTS(LollmsTTS): def tts_file(self, text, speaker=None, file_name_or_path:Path|str=None, language="en", use_threading=False): speech_file_path = file_name_or_path + text = self.clean_text(text) response = self.client.audio.speech.create( model=self.model, voice=self.voice, diff --git a/lollms/services/xtts/lollms_xtts.py b/lollms/services/xtts/lollms_xtts.py index 641e693..5cecfb6 100644 --- a/lollms/services/xtts/lollms_xtts.py +++ b/lollms/services/xtts/lollms_xtts.py @@ -260,6 +260,7 @@ class LollmsXTTS(LollmsTTS): return False def tts_file(self, text, file_name_or_path, speaker=None, language="en")->str: + text = self.clean_text(text) url = f"{self.xtts_base_url}/tts_to_file" # Define the request body @@ -316,14 +317,7 @@ class LollmsXTTS(LollmsTTS): return {"status":False,"error":f"{ex}"} def xtts_audio(self, text, speaker, file_name_or_path:Path|str=None, language="en", use_threading=True): - # Remove HTML tags - text = re.sub(r'<.*?>', '', text) - # Remove code blocks (assuming they're enclosed in backticks or similar markers) - text = re.sub(r'```.*?```', '', text, flags=re.DOTALL) - text = re.sub(r'`.*?`', '', text) - # Remove any remaining code-like patterns (this can be adjusted as needed) - text = re.sub(r'[\{\}\[\]\(\)<>]', '', text) - text = text.replace("\\","") + text = self.clean_text(text) def tts2_audio_th(thread_uid=None): url = f"{self.xtts_base_url}/tts_to_audio" diff --git a/lollms/tts.py b/lollms/tts.py index 68650a7..ed8dc6f 100644 --- a/lollms/tts.py +++ b/lollms/tts.py @@ -10,6 +10,7 @@ from lollms.app import LollmsApplication from lollms.utilities import PackageManager from pathlib import Path from ascii_colors import ASCIIColors +import re try: if not PackageManager.check_package_installed("sounddevice"): # os.system("sudo apt-get install portaudio19-dev") @@ -147,4 +148,16 @@ class LollmsTTS: return { "status": True, "device_names": [device['name'] for device in devices if device["max_output_channels"]>0] - } \ No newline at end of file + } + + @staticmethod + def clean_text(text): + # Remove HTML tags + text = re.sub(r'<.*?>', '', text) + # Remove code blocks (assuming they're enclosed in backticks or similar markers) + text = re.sub(r'```.*?```', '', text, flags=re.DOTALL) + text = re.sub(r'`.*?`', '', text) + # Remove any remaining code-like patterns (this can be adjusted as needed) + text = re.sub(r'[\{\}\[\]\(\)<>]', '', text) + text = text.replace("\\","") + return text \ No newline at end of file