enhanced functions

This commit is contained in:
Saifeddine ALOUI 2024-06-09 23:20:17 +02:00
parent a52db1fb9f
commit 7da874228b
15 changed files with 646 additions and 127 deletions

View File

@ -0,0 +1,7 @@
from lollms.functions.analyze_code.create_project_database import create_project_database, create_project_database_function
from lollms.functions.analyze_code.retreive_information_for_task import retrieve_information_for_task, retrieve_information_for_task_function
from lollms.functions.analyze_code.retrieve_classes_from_project import retrieve_classes_from_project, retrieve_classes_from_project_function
from lollms.functions.analyze_code.update_class_in_file import update_class_in_file, update_class_in_file_function
from lollms.functions.analyze_code.update_function_in_file import update_function_in_file, update_function_in_file_function
from lollms.functions.analyze_code.add_function_to_file import add_function_to_file, add_function_to_file_function

View File

@ -0,0 +1,58 @@
# Lollms function call definition file
from functools import partial
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from typing import List, Union
from pathlib import Path
import ast
def add_function_to_file(file_path: Union[str, Path], function_name: str, function_content: str) -> str:
"""
Adds a new function to the specified file.
Args:
file_path (Union[str, Path]): The path to the Python file.
function_name (str): The name of the function to add.
function_content (str): The content of the function to add.
Returns:
str: Success message or error message.
"""
try:
file_path = Path(file_path)
# Validate the file path
if not file_path.exists() or not file_path.is_file():
return "Invalid file path."
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
tree = ast.parse(content)
# Check if function already exists
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == function_name:
return f"Function {function_name} already exists in the file."
# Add the new function content at the end of the file
with open(file_path, "a", encoding="utf-8") as file:
file.write("\n\n" + function_content)
return f"Function {function_name} added successfully to file {file_path}."
except Exception as e:
return trace_exception(e)
# Metadata function
def add_function_to_file_function():
return {
"function_name": "add_function_to_file", # The function name in string
"function": add_function_to_file, # The function to be called
"function_description": "Adds a new function to the specified file.", # Description of the function
"function_parameters": [ # The set of parameters
{"name": "file_path", "type": "str"},
{"name": "function_name", "type": "str"},
{"name": "function_content", "type": "str"},
]
}

View File

@ -1,4 +1,8 @@
# Lollms function call definition file """
"""
from functools import partial from functools import partial
from typing import List, Dict, Union, Any from typing import List, Dict, Union, Any
from lollms.utilities import PackageManager from lollms.utilities import PackageManager
@ -129,102 +133,4 @@ def create_project_database_function(project_path, llm):
"function": partial(create_project_database,project_path=project_path, llm=llm), "function": partial(create_project_database,project_path=project_path, llm=llm),
"function_description": "Creates a database containing structured information about a Python project.", "function_description": "Creates a database containing structured information about a Python project.",
"function_parameters": [] "function_parameters": []
} }
# Lollms function call definition file
from functools import partial
from typing import List, Dict
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from pathlib import Path
import sqlite3
# Ensure required packages are installed
if not PackageManager.check_package_installed("sqlite3"):
PackageManager.install_package("sqlite3")
def retrieve_information_for_task(project_path: str, task_description: str, llm: APScript) -> Union[str, Dict[str, str]]:
"""
Retrieves information from the database to perform a task given by the user.
Args:
project_path (str): The path to the project directory.
task_description (str): The description of the task to perform.
llm (APScript): The language model instance for generating SQL queries.
Returns:
Union[str, Dict[str, str]]: A string containing relevant information or an error message.
"""
try:
db_path = Path(project_path) / "project_info.db"
# Validate the database path
if not db_path.exists() or not db_path.is_file():
return "Invalid database path."
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Retrieve the list of classes and their descriptions
cursor.execute("SELECT name, docstring FROM classes")
classes = cursor.fetchall()
# Format the classes into a string
classes_text = "\n".join([f"Class: {cls[0]}, Description: {cls[1]}" for cls in classes])
# Ask the LLM which classes are needed for the task
prompt = f"{llm.personality.config.start_header_id_template}{llm.personality.config.system_message_template}{llm.personality.config.end_header_id_template}" \
f"Given the following list of classes and their descriptions:\n" \
f"{classes_text}\n\n" \
f"Task description: {task_description}\n\n" \
f"{llm.personality.config.start_header_id_template}instructions{llm.personality.config.end_header_id_template}" \
f"Which classes are needed to perform the task? List the class names.\n" \
f"Answer in form of a json list inside a json markdown tag.\n" \
f"{llm.personality.config.start_header_id_template}assistant{llm.personality.config.end_header_id_template}"
needed_classes = llm.fast_gen(prompt, callback=llm.sink).strip()
needed_classes = llm.extract_code_blocks(needed_classes)
if len(needed_classes)>0:
needed_classes = json.loads(needed_classes[0]["content"])
# Retrieve the relevant information for the needed classes
class_info = {}
for class_name in needed_classes:
cursor.execute("SELECT * FROM classes WHERE name = ?", (class_name,))
class_info[class_name] = cursor.fetchone()
# Retrieve the project description and structure
cursor.execute("SELECT name, description FROM project_info")
project_info = cursor.fetchone()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
conn.close()
# Format the results into a string
result_text = f"Project Name: {project_info[0]}\nProject Description: {project_info[1]}\n\n"
result_text += "Project Structure:\n" + "\n".join([table[0] for table in tables]) + "\n\n"
result_text += "Needed Classes Information:\n"
for class_name, info in class_info.items():
result_text += f"Class: {class_name}\n"
result_text += f"Description: {info[2]}\n"
result_text += f"Methods: {info[4]}\n"
result_text += f"Static Methods: {info[5]}\n\n"
return result_text.strip()
else:
return "Failed to ask the llm"
except Exception as e:
return str(e)
def retrieve_information_for_task_function(project_path, llm):
return {
"function_name": "retrieve_information_for_task",
"function": partial(retrieve_information_for_task, project_path=project_path, llm=llm),
"function_description": "Retrieves information from the database to perform a task given by the user.",
"function_parameters": [
{"name": "task_description", "type": "str", "description":"a description of "}
]
}

View File

@ -0,0 +1,96 @@
# Lollms function call definition file
from functools import partial
from typing import List, Dict, Union
from lollms.utilities import PackageManager
from lollms.personality import APScript
from ascii_colors import trace_exception
from pathlib import Path
import sqlite3
import json
# Ensure required packages are installed
if not PackageManager.check_package_installed("sqlite3"):
PackageManager.install_package("sqlite3")
def retrieve_information_for_task(project_path: str, task_description: str, llm: APScript) -> Union[str, Dict[str, str]]:
"""
Retrieves information from the database to perform a task given by the user.
Args:
project_path (str): The path to the project directory.
task_description (str): The description of the task to perform.
llm (APScript): The language model instance for generating SQL queries.
Returns:
Union[str, Dict[str, str]]: A string containing relevant information or an error message.
"""
try:
db_path = Path(project_path) / "project_info.db"
# Validate the database path
if not db_path.exists() or not db_path.is_file():
return "Invalid database path."
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Retrieve the list of classes and their descriptions
cursor.execute("SELECT name, docstring FROM classes")
classes = cursor.fetchall()
# Format the classes into a string
classes_text = "\n".join([f"Class: {cls[0]}, Description: {cls[1]}" for cls in classes])
# Ask the LLM which classes are needed for the task
prompt = f"{llm.personality.config.start_header_id_template}{llm.personality.config.system_message_template}{llm.personality.config.end_header_id_template}" \
f"Given the following list of classes and their descriptions:\n" \
f"{classes_text}\n\n" \
f"Task description: {task_description}\n\n" \
f"{llm.personality.config.start_header_id_template}instructions{llm.personality.config.end_header_id_template}" \
f"Which classes are needed to perform the task? List the class names.\n" \
f"Answer in form of a json list inside a json markdown tag.\n" \
f"{llm.personality.config.start_header_id_template}assistant{llm.personality.config.end_header_id_template}"
needed_classes = llm.fast_gen(prompt, callback=llm.sink).strip()
needed_classes = llm.extract_code_blocks(needed_classes)
if len(needed_classes)>0:
needed_classes = json.loads(needed_classes[0]["content"])
# Retrieve the relevant information for the needed classes
class_info = {}
for class_name in needed_classes:
cursor.execute("SELECT * FROM classes WHERE name = ?", (class_name,))
class_info[class_name] = cursor.fetchone()
# Retrieve the project description and structure
cursor.execute("SELECT name, description FROM project_info")
project_info = cursor.fetchone()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
conn.close()
# Format the results into a string
result_text = f"Project Name: {project_info[0]}\nProject Description: {project_info[1]}\n\n"
result_text += "Project Structure:\n" + "\n".join([table[0] for table in tables]) + "\n\n"
result_text += "Needed Classes Information:\n"
for class_name, info in class_info.items():
result_text += f"Class: {class_name}\n"
result_text += f"Description: {info[2]}\n"
result_text += f"Methods: {info[4]}\n"
result_text += f"Static Methods: {info[5]}\n\n"
return result_text.strip()
else:
return "Failed to ask the llm"
except Exception as e:
return str(e)
def retrieve_information_for_task_function(project_path, llm):
return {
"function_name": "retrieve_information_for_task",
"function": partial(retrieve_information_for_task, project_path=project_path, llm=llm),
"function_description": "Retrieves information from the database to perform a task given by the user.",
"function_parameters": [
{"name": "task_description", "type": "str", "description":"a description of "}
]
}

View File

@ -0,0 +1,59 @@
# Import necessary libraries
from pathlib import Path
from functools import partial
from typing import List, Union
import ast
# ascii_colors offers advanced console coloring and bug tracing
from ascii_colors import trace_exception
# Function to retrieve classes from the project files
def retrieve_classes_from_project(class_names: List[str], project_path: Union[str, Path]) -> str:
"""
Retrieves the code of specified classes from the given project path.
Args:
project_path (Union[str, Path]): The path to the Python project directory.
class_names (List[str]): List of class names to retrieve.
Returns:
str: The code of the specified classes as a string.
"""
try:
project_path = Path(project_path)
# Validate the project path
if not project_path.exists() or not project_path.is_dir():
return "Invalid project path."
class_code = "\n"
# Traverse the project directory and extract class code
for py_file in project_path.rglob("*.py"):
with open(py_file, "r", encoding="utf-8") as file:
content = file.read()
tree = ast.parse(content)
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef) and node.name in class_names:
class_code += f"\n\n# Class: {node.name} in file: {py_file.relative_to(project_path)}\n"
class_code += "```python\n"
class_code += "\n".join(content.split("\n")[node.lineno-1:node.end_lineno])
class_code += "\n```\n"
return class_code if class_code else "No specified classes found."
except Exception as e:
return trace_exception(e)
# Metadata function
def retrieve_classes_from_project_function(project_path:str):
return {
"function_name": "retrieve_classes_from_project",
"function": partial(retrieve_classes_from_project,project_path = project_path),
"function_description": "Retrieves the code of specified classes from the given project path.",
"function_parameters": [
{"name": "class_names", "type": "list", "description": "List of class names to retrieve."}
]
}

View File

@ -0,0 +1,85 @@
# Lollms function call definition file
from functools import partial
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from typing import List, Union
from pathlib import Path
import ast
def update_class_in_file(class_name: str, new_content: str, method_name: Union[str, None] = None, project_path: Union[str, Path] = "") -> str:
"""
Updates the specified class or method with new content in the given project path.
Args:
class_name (str): The name of the class to update.
new_content (str): The new content to replace the class or method with.
method_name (Union[str, None]): The name of the method to update. If None, updates the entire class.
project_path (Union[str, Path]): The path to the Python project directory.
Returns:
str: Success message or error message.
"""
try:
project_path = Path(project_path)
# Validate the project path
if not project_path.exists() or not project_path.is_dir():
return "Invalid project path."
# Traverse the project directory and update class or method content
for py_file in project_path.rglob("*.py"):
with open(py_file, "r", encoding="utf-8") as file:
content = file.read()
tree = ast.parse(content)
class_found = False
method_found = False
updated_content = []
lines = content.split("\n")
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef) and node.name == class_name:
class_found = True
if method_name is None:
# Update entire class content
updated_content.extend(lines[:node.lineno-1])
updated_content.append(new_content)
updated_content.extend(lines[node.end_lineno:])
else:
# Update specific method content
for class_node in node.body:
if isinstance(class_node, ast.FunctionDef) and class_node.name == method_name:
method_found = True
# Calculate the indentation level
indent_level = len(lines[class_node.lineno-1]) - len(lines[class_node.lineno-1].lstrip())
indented_new_content = "\n".join(" " * indent_level + line for line in new_content.split("\n"))
updated_content.extend(lines[:class_node.lineno-1])
updated_content.append(indented_new_content)
updated_content.extend(lines[class_node.end_lineno:])
break
if not method_found:
return f"Method {method_name} not found in class {class_name}."
break
if class_found:
with open(py_file, "w", encoding="utf-8") as file:
file.write("\n".join(updated_content))
return f"{'Method ' + method_name if method_name else 'Class ' + class_name} updated successfully in file {py_file.relative_to(project_path)}."
return "Class not found in the specified project."
except Exception as e:
return trace_exception(e)
# Metadata function
def update_class_in_file_function(project_path:str ):
return {
"function_name": "update_class_in_file", # The function name in string
"function": partial(update_class_in_file,project_path = project_path), # The function to be called
"function_description": "Updates the specified class with new content in the given project path.", # Description of the function
"function_parameters": [ # The set of parameters
{"name": "class_name", "type": "str"},
{"name": "new_content", "type": "str"},
{"name": "method_name", "type": "str", "description":"An optional method name, required only if you need to change a single method content. If you need to change the whole class, do not set this element"},
]
}

View File

@ -0,0 +1,70 @@
# Lollms function call definition file
from functools import partial
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from typing import List, Union
from pathlib import Path
import ast
def update_function_in_file(function_name: str, new_content: str, project_path: Union[str, Path] = "") -> str:
"""
Updates the specified function with new content in the given project path.
Args:
function_name (str): The name of the function to update.
new_content (str): The new content to replace the function with.
project_path (Union[str, Path]): The path to the Python project directory.
Returns:
str: Success message or error message.
"""
try:
project_path = Path(project_path)
# Validate the project path
if not project_path.exists() or not project_path.is_dir():
return "Invalid project path."
# Traverse the project directory and update function content
for py_file in project_path.rglob("*.py"):
with open(py_file, "r", encoding="utf-8") as file:
content = file.read()
tree = ast.parse(content)
function_found = False
updated_content = []
lines = content.split("\n")
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == function_name:
function_found = True
# Calculate the indentation level
indent_level = len(lines[node.lineno-1]) - len(lines[node.lineno-1].lstrip())
indented_new_content = "\n".join(" " * indent_level + line for line in new_content.split("\n"))
updated_content.extend(lines[:node.lineno-1])
updated_content.append(indented_new_content)
updated_content.extend(lines[node.end_lineno:])
break
if function_found:
with open(py_file, "w", encoding="utf-8") as file:
file.write("\n".join(updated_content))
return f"Function {function_name} updated successfully in file {py_file.relative_to(project_path)}."
return "Function not found in the specified project."
except Exception as e:
return trace_exception(e)
# Metadata function
def update_function_in_file_function(project_path:str ):
return {
"function_name": "update_function_in_file", # The function name in string
"function": partial(update_function_in_file, project_path=project_path), # The function to be called
"function_description": "Updates the specified function with new content in the given project path.", # Description of the function
"function_parameters": [ # The set of parameters
{"name": "function_name", "type": "str"},
{"name": "new_content", "type": "str"},
]
}

View File

@ -0,0 +1,75 @@
# Lollms function call definition file
# File Name: draw_bounding_boxes.py
# Author: Saif (ParisNeo)
# Description: This script defines a function that takes an image file path and a list of bounding boxes in the form of x, y, w, h in normalized mode along with the labels, and returns the bounding boxes placed on top of the images with the labels.
# Lollms function call definition file
from functools import partial
from typing import List, Tuple
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from pathlib import Path
# Ensure necessary packages are installed
if not PackageManager.check_package_installed("Pillow"):
PackageManager.install_package("Pillow")
from PIL import Image, ImageDraw, ImageFont
def draw_bounding_boxes(image_path: str, bounding_boxes: List[Tuple[float, float, float, float, str]]) -> str:
"""
Draws bounding boxes on an image and saves the result.
Args:
image_path (str): Path to the input image file.
bounding_boxes (List[Tuple[float, float, float, float, str]]): List of bounding boxes in normalized coordinates (x, y, w, h) along with labels.
Returns:
str: Path to the output image file with bounding boxes drawn.
"""
try:
image_path = Path(image_path)
if not image_path.exists():
raise FileNotFoundError(f"Image file not found: {image_path}")
# Load the image
image = Image.open(image_path)
draw = ImageDraw.Draw(image)
width, height = image.size
# Iterate over bounding boxes and draw them
for bbox in bounding_boxes:
x, y, w, h, label = bbox
left = x * width
top = y * height
right = left + (w * width)
bottom = top + (h * height)
# Draw rectangle
draw.rectangle([left, top, right, bottom], outline="red", width=2)
# Draw label
font = ImageFont.load_default()
text_size = draw.textsize(label, font=font)
text_background = [left, top - text_size[1], left + text_size[0], top]
draw.rectangle(text_background, fill="red")
draw.text((left, top - text_size[1]), label, fill="white", font=font)
# Save the output image
output_path = image_path.with_name(f"{image_path.stem}_with_boxes{image_path.suffix}")
image.save(output_path)
return str(output_path)
except Exception as e:
return trace_exception(e)
def draw_bounding_boxes_function():
return {
"function_name": "draw_bounding_boxes",
"function": draw_bounding_boxes,
"function_description": "Draws bounding boxes on an image and saves the result.",
"function_parameters": [
{"name": "image_path", "type": "str"},
{"name": "bounding_boxes", "type": "List[Tuple[float, float, float, float, str]]"}
]
}

View File

@ -1,4 +1,8 @@
# Lollms function call definition file # Lollms function call definition file
# File Name: set_timer_with_alert.py
# Author: Saif (ParisNeo)
# Description: This function sets a non-blocking timer that shows a PyQt window with a message and makes noise after a specified duration. It works on any operating system by using the pyautogui library for the alert sound.
# Here you need to import any necessary imports depending on the function requested by the user # Here you need to import any necessary imports depending on the function requested by the user
# example import math # example import math
@ -6,7 +10,7 @@
from functools import partial from functools import partial
# It is advised to import typing elements # It is advised to import typing elements
# from typing import List from typing import Any, Dict
# Import PackageManager if there are potential libraries that need to be installed # Import PackageManager if there are potential libraries that need to be installed
from lollms.utilities import PackageManager from lollms.utilities import PackageManager
@ -17,30 +21,35 @@ from ascii_colors import trace_exception
# Here is an example of how we install a non installed library using PackageManager # Here is an example of how we install a non installed library using PackageManager
if not PackageManager.check_package_installed("PyQt5"): if not PackageManager.check_package_installed("PyQt5"):
PackageManager.install_package("PyQt5") PackageManager.install_package("PyQt5")
if not PackageManager.check_package_installed("pyautogui"):
PackageManager.install_package("pyautogui")
# now we can import the library # now we can import the libraries
import threading import threading
import time import time
import sys import sys
from PyQt5.QtWidgets import QApplication, QMessageBox from PyQt5.QtWidgets import QApplication, QMessageBox
import winsound import pyautogui
# here is the core of the function to be built # here is the core of the function to be built
def set_timer_with_alert(duration: int, message: str) -> str: def set_timer_with_alert(duration: int, message: str) -> str:
def timer_callback(): """
if type(duration)==str and len(duration)>0: Sets a non-blocking timer that shows a PyQt window with a message and makes noise after a specified duration.
duration = float(duration.split()[0])
time.sleep(duration)
winsound.Beep(1000, 1000) # Make noise when time is up
app = QApplication(sys.argv) Parameters:
msg_box = QMessageBox() duration (int): The duration for the timer in seconds.
msg_box.setIcon(QMessageBox.Information) message (str): The message to be displayed in the alert window.
msg_box.setWindowTitle("Timer Alert")
msg_box.setText(message) Returns:
msg_box.setStandardButtons(QMessageBox.Ok) str: A success message indicating the timer has been set.
msg_box.buttonClicked.connect(app.quit) """
msg_box.exec_() def timer_callback():
try:
time.sleep(duration)
pyautogui.alert(text=message, title="Timer Alert", button='OK')
pyautogui.beep()
except Exception as e:
return trace_exception(e)
try: try:
# Start the timer in a new thread to make it non-blocking # Start the timer in a new thread to make it non-blocking
@ -53,7 +62,7 @@ def set_timer_with_alert(duration: int, message: str) -> str:
return trace_exception(e) return trace_exception(e)
# Here is the metadata function that should have the name in format function_name_function # Here is the metadata function that should have the name in format function_name_function
def set_timer_with_alert_function(processor, client): def set_timer_with_alert_function() -> Dict[str, Any]:
return { return {
"function_name": "set_timer_with_alert", # The function name in string "function_name": "set_timer_with_alert", # The function name in string
"function": set_timer_with_alert, # The function to be called "function": set_timer_with_alert, # The function to be called

View File

View File

@ -0,0 +1,45 @@
# Lollms function call definition file
# Import necessary modules
from pathlib import Path
from functools import partial
from typing import Union
from lollms.utilities import PackageManager
from lollms.personality import APScript
from lollms.tts import LollmsTTS
from safe_store import GenericDataLoader
from ascii_colors import trace_exception
# Here is the core of the function to be built
def read_text(text: str, tts_module:LollmsTTS, llm:APScript) -> str:
"""
This function takes a TTS module and a file path as input, reads the text from the file,
and uses the TTS module to generate audio from the text.
Parameters:
tts_module: The text-to-speech module with a method tts_audio.
text: The text to be read.
Returns:
str: The path to the generated audio file.
"""
try:
# Generate audio from the text
audio_file_path = tts_module.tts_audio(text)
llm.chunk(text)
llm.new_message("")
# Return the path to the generated audio file
return str(audio_file_path)
except Exception as e:
return trace_exception(e)
# Metadata function
def read_text_function(file_path:str,tts_module:LollmsTTS):
return {
"function_name": "read_text_from_file", # The function name in string
"function": partial(read_text, file_path=file_path, tts_module=tts_module), # The function to be called
"function_description": "Reads text from a file and uses a TTS module to generate audio from the text.", # Description of the function
"function_parameters": [] # The set of parameters
}

View File

@ -0,0 +1,50 @@
# Lollms function call definition file
# Import necessary modules
from pathlib import Path
from functools import partial
from typing import Union
from lollms.utilities import PackageManager
from lollms.personality import APScript
from lollms.tts import LollmsTTS
from safe_store import GenericDataLoader
from ascii_colors import trace_exception
# Here is the core of the function to be built
def read_text_from_file(file_path: Union[Path, str], tts_module:LollmsTTS, llm:APScript) -> str:
"""
This function takes a TTS module and a file path as input, reads the text from the file,
and uses the TTS module to generate audio from the text.
Parameters:
tts_module: The text-to-speech module with a method tts_audio.
file_path: The path to the text file containing the text to be read.
Returns:
str: The path to the generated audio file.
"""
try:
# Ensure file_path is of type Path
file_path = Path(file_path)
# Read the text from the file
text = GenericDataLoader.read_file(file_path)
# Generate audio from the text
audio_file_path = tts_module.tts_audio(text,use_threading=True)
llm.full(text)
# Return the path to the generated audio file
return str(audio_file_path)
except Exception as e:
return trace_exception(e)
# Metadata function
def read_text_from_file_function(file_path:str,tts_module:LollmsTTS, llm:APScript):
return {
"function_name": "read_text_from_file", # The function name in string
"function": partial(read_text_from_file, file_path=file_path, tts_module=tts_module, llm=llm), # The function to be called
"function_description": "Reads text from the current file and uses a TTS module to generate audio from the text.", # Description of the function
"function_parameters": [] # The set of parameters
}

View File

@ -0,0 +1 @@
from lollms.functions.web.google_search import google_search, google_search_function

View File

@ -0,0 +1,46 @@
# Lollms function call definition file
# Import necessary libraries
from functools import partial
from typing import List
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
# Ensure the webbrowser package is available
if not PackageManager.check_package_installed("webbrowser"):
PackageManager.install_package("webbrowser")
# Import the webbrowser library
import webbrowser
# Define the function to perform a Google search
def google_search(query: str) -> str:
"""
Perform a Google search using the default web browser.
Parameters:
- query (str): The search query.
Returns:
- str: A message indicating the search was performed.
"""
try:
# Construct the Google search URL
search_url = f"https://www.google.com/search?q={query}"
# Open the search URL in the default web browser
webbrowser.open(search_url)
# Return a success message
return f"Performed Google search for query: {query}"
except Exception as e:
return trace_exception(e)
# Define the metadata function
def google_search_function():
return {
"function_name": "google_search", # The function name in string
"function": google_search, # The function to be called
"function_description": "Performs a Google search using the default web browser.", # Description of the function
"function_parameters": [{"name": "query", "type": "str"}] # The set of parameters
}

View File

@ -3394,6 +3394,7 @@ The AI should respond in this format using data from actions_list:
result = function(**parameters) result = function(**parameters)
results.append(result) results.append(result)
except TypeError as e: except TypeError as e:
trace_exception(e)
# Handle cases where the function call fails due to incorrect parameters, etc. # Handle cases where the function call fails due to incorrect parameters, etc.
results.append(f"Error calling {function_name}: {e}") results.append(f"Error calling {function_name}: {e}")
else: else:
@ -3521,6 +3522,20 @@ The AI should respond in this format using data from actions_list:
return function_calls return function_calls
def interact(
self,
context_details,
callback = None
):
upgraded_prompt = self.build_prompt_from_context_details(context_details)
if len(self.personality.image_files)>0:
# Generate the initial text based on the upgraded prompt.
generated_text = self.fast_gen_with_images(upgraded_prompt, self.personality.image_files, callback=callback)
else:
generated_text = self.fast_gen(upgraded_prompt, callback=callback)
return generated_text
def interact_with_function_call( def interact_with_function_call(
self, self,
context_details, context_details,
@ -3528,24 +3543,26 @@ The AI should respond in this format using data from actions_list:
prompt_after_execution=True, prompt_after_execution=True,
callback = None, callback = None,
hide_function_call=False, hide_function_call=False,
separate_output=False): separate_output=False,
max_nested_function_calls=10):
start_header_id_template = self.config.start_header_id_template start_header_id_template = self.config.start_header_id_template
end_header_id_template = self.config.end_header_id_template end_header_id_template = self.config.end_header_id_template
system_message_template = self.config.system_message_template system_message_template = self.config.system_message_template
separator_template = self.config.separator_template separator_template = self.config.separator_template
final_output = "" final_output = ""
if len(self.personality.image_files)>0: if len(self.personality.image_files)>0:
out, function_calls = self.generate_with_function_calls_and_images(context_details, self.personality.image_files, function_definitions, callback=callback) out, function_calls = self.generate_with_function_calls_and_images(context_details, self.personality.image_files, function_definitions, callback=callback)
else: else:
out, function_calls = self.generate_with_function_calls(context_details, function_definitions, callback=callback) out, function_calls = self.generate_with_function_calls(context_details, function_definitions, callback=callback)
if len(function_calls)>0: nested_function_calls = 0
while len(function_calls)>0 and nested_function_calls<max_nested_function_calls:
nested_function_calls += 1
self.chunk("\n")
if hide_function_call: if hide_function_call:
self.full("") #Hide function self.full("") #Hide function
if self.config.debug: if self.config.debug:
self.print_prompt("Function calls", json.dumps(function_calls, indent=4)) self.print_prompt("Function calls", json.dumps(function_calls, indent=4))
@ -3562,11 +3579,6 @@ The AI should respond in this format using data from actions_list:
else: else:
out, function_calls = self.generate_with_function_calls(context_details, function_definitions, callback=callback) out, function_calls = self.generate_with_function_calls(context_details, function_definitions, callback=callback)
final_output += "\n" + out final_output += "\n" + out
if len(function_calls)>0:
outputs = self.execute_function_calls(function_calls,function_definitions)
final_output = "\n".join([str(o) if type(o)==str else str(o[0]) if (type(o)==tuple or type(0)==list) and len(o)>0 else "" for o in outputs])
out += f"{separator_template}{start_header_id_template}function calls results{end_header_id_template}\n" + final_output
context_details["discussion_messages"] +=out
else: else:
final_output = out final_output = out
return final_output return final_output