added loads of project management functions

This commit is contained in:
Saifeddine ALOUI 2024-06-11 23:25:42 +02:00
parent 98d064608c
commit 47494edb05
9 changed files with 416 additions and 24 deletions

View File

@ -1125,7 +1125,7 @@ class LollmsApplication(LoLLMsCom):
# Build the final discussion messages by detokenizing the full_message_list
discussion_messages = ""
for i in range(len(full_message_list)-1):
for i in range(len(full_message_list)-1 if not is_continue else len(full_message_list)):
message_tokens = full_message_list[i]
discussion_messages += self.model.detokenize(message_tokens)
@ -1134,7 +1134,7 @@ class LollmsApplication(LoLLMsCom):
else:
ai_prefix = ""
# Build the final prompt by concatenating the conditionning and discussion messages
prompt_data = conditionning + internet_search_results + documentation + knowledge + user_description + discussion_messages + positive_boost + negative_boost + fun_mode + start_ai_header_id_template + ai_prefix + end_ai_header_id_template
prompt_data = conditionning + internet_search_results + documentation + knowledge + user_description + discussion_messages + positive_boost + negative_boost + fun_mode + (start_ai_header_id_template + ai_prefix + end_ai_header_id_template if not is_continue else '')
# Tokenize the prompt data
tokens = self.model.tokenize(prompt_data)

View File

@ -0,0 +1,66 @@
# Lollms function call definition file
# File Name: add_code_to_file.py
# Author: ParisNeo
# Description: This function adds given code to a specified Python file in a project directory.
# Import necessary modules
from functools import partial
from lollms.utilities import PackageManager
from ascii_colors import trace_exception
from typing import Union
from pathlib import Path
# Function to add code to a file
def add_code_to_file(file_name: str, code_content: str, project_path: Union[str, Path] = "") -> str:
"""
Adds the specified code content to the given file in the project path.
Args:
file_name (str): The name of the file to add code to.
code_content (str): The code content to be added.
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."
file_path = project_path / file_name
# Check if the file exists
if not file_path.exists():
return f"File {file_name} does not exist in the specified project."
# Read the current content of the file
with open(file_path, "r", encoding="utf-8") as file:
current_content = file.read()
# Add the new code content
updated_content = current_content + "\n\n" + code_content
# Write the updated content back to the file
with open(file_path, "w", encoding="utf-8") as file:
file.write(updated_content)
return f"Code added successfully to file {file_name}."
except Exception as e:
return trace_exception(e)
# Metadata function
def add_code_to_file_function(project_path: str):
return {
"function_name": "add_code_to_file", # The function name in string
"function": partial(add_code_to_file, project_path=project_path), # The function to be called
"function_description": "Adds the specified code content to the given file in the project path.", # Description of the function
"function_parameters": [ # The set of parameters
{"name": "file_name", "type": "str"},
{"name": "code_content", "type": "str"},
]
}

View File

@ -1,8 +1,3 @@
"""
"""
from functools import partial
from typing import List, Dict, Union, Any
from lollms.utilities import PackageManager
@ -17,7 +12,7 @@ import json
if not PackageManager.check_package_installed("sqlite3"):
PackageManager.install_package("sqlite3")
def create_project_database(project_path: Union[str, Path], max_summary_size:str=512, llm: APScript=None) -> str:
def create_project_database(project_path: Union[str, Path], max_summary_size: str = 512, llm: APScript = None) -> str:
"""
Creates a database containing structured information about a Python project.
@ -54,6 +49,7 @@ def create_project_database(project_path: Union[str, Path], max_summary_size:str
name TEXT NOT NULL,
docstring TEXT,
parameters TEXT,
core TEXT,
FOREIGN KEY (file_id) REFERENCES files (id)
)''')
@ -62,11 +58,20 @@ def create_project_database(project_path: Union[str, Path], max_summary_size:str
file_id INTEGER,
name TEXT NOT NULL,
docstring TEXT,
methods TEXT,
static_methods TEXT,
core TEXT,
FOREIGN KEY (file_id) REFERENCES files (id)
)''')
cursor.execute('''CREATE TABLE IF NOT EXISTS methods (
id INTEGER PRIMARY KEY,
class_id INTEGER,
name TEXT NOT NULL,
docstring TEXT,
parameters TEXT,
core TEXT,
FOREIGN KEY (class_id) REFERENCES classes (id)
)''')
cursor.execute('''CREATE TABLE IF NOT EXISTS project_info (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
@ -83,12 +88,12 @@ def create_project_database(project_path: Union[str, Path], max_summary_size:str
readme_content = readme_file.read()
structure = "\n".join([str(p.relative_to(project_path)) for p in project_path.rglob("*")])
readme_content += f"## Project Structure:\n{structure}"
project_description = llm.summerize_text(readme_content, "Build a comprehensive description of this project from the available information", max_generation_size=max_summary_size, callback=llm.sink)
project_description = llm.summarize_text(readme_content, "Build a comprehensive description of this project from the available information", max_generation_size=max_summary_size, callback=llm.sink)
else:
# Construct a description based on the project structure
structure = "\n".join([str(p.relative_to(project_path)) for p in project_path.rglob("*")])
constructed_text = f"Project Name: {project_name}\n\nProject Structure:\n{structure}"
project_description = llm.summerize_text(constructed_text, "Build a comprehensive description of this project from the available information", max_generation_size=max_summary_size, callback=llm.sink)
project_description = llm.summarize_text(constructed_text, "Build a comprehensive description of this project from the available information", max_generation_size=max_summary_size, callback=llm.sink)
# Insert project information into the database
cursor.execute("INSERT INTO project_info (name, description) VALUES (?, ?)", (project_name, project_description))
@ -103,20 +108,22 @@ def create_project_database(project_path: Union[str, Path], max_summary_size:str
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
parameters = [arg.arg for arg in node.args.args]
cursor.execute("INSERT INTO functions (file_id, name, docstring, parameters) VALUES (?, ?, ?, ?)",
(file_id, node.name, ast.get_docstring(node), str(parameters)))
parameters = [(arg.arg, arg.annotation.id if arg.annotation else None) for arg in node.args.args]
core = ast.get_source_segment(content, node)
cursor.execute("INSERT INTO functions (file_id, name, docstring, parameters, core) VALUES (?, ?, ?, ?, ?)",
(file_id, node.name, ast.get_docstring(node), json.dumps(parameters), core))
elif isinstance(node, ast.ClassDef):
methods = []
static_methods = []
core = ast.get_source_segment(content, node)
class_id = cursor.execute("INSERT INTO classes (file_id, name, docstring, core) VALUES (?, ?, ?, ?)",
(file_id, node.name, ast.get_docstring(node), core)).lastrowid
for class_node in node.body:
if isinstance(class_node, ast.FunctionDef):
if any(isinstance(decorator, ast.Name) and decorator.id == 'staticmethod' for decorator in class_node.decorator_list):
static_methods.append(class_node.name)
else:
methods.append(class_node.name)
cursor.execute("INSERT INTO classes (file_id, name, docstring, methods, static_methods) VALUES (?, ?, ?, ?, ?)",
(file_id, node.name, ast.get_docstring(node), str(methods), str(static_methods)))
parameters = [(arg.arg, arg.annotation.id if arg.annotation else None) for arg in class_node.args.args]
method_core = ast.get_source_segment(content, class_node)
cursor.execute("INSERT INTO methods (class_id, name, docstring, parameters, core) VALUES (?, ?, ?, ?, ?)",
(class_id, class_node.name, ast.get_docstring(class_node), json.dumps(parameters), method_core))
# Commit changes and close the connection
conn.commit()
@ -130,7 +137,7 @@ def create_project_database(project_path: Union[str, Path], max_summary_size:str
def create_project_database_function(project_path, llm):
return {
"function_name": "create_project_database",
"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_parameters": []
}
}

View File

@ -0,0 +1,64 @@
# Lollms function call definition file
# File Name: git_commit.py
# Author: ParisNeo
# Description: This function commits changes to a Git repository with a specified commit message.
# Import necessary libraries
from functools import partial
from typing import Union
from pathlib import Path
import subprocess
from ascii_colors import trace_exception
# Ensure Git is installed
from lollms.utilities import PackageManager
if not PackageManager.check_package_installed("git"):
PackageManager.install_package("gitpython")
import git
def git_commit(commit_message: str, repo_path: Union[str, Path]) -> str:
"""
Commits changes to a Git repository with a specified commit message.
Args:
repo_path (Union[str, Path]): The path to the Git repository.
commit_message (str): The commit message.
Returns:
str: Success or error message.
"""
try:
repo_path = Path(repo_path)
if not repo_path.exists():
return "Repository path does not exist."
repo = git.Repo(repo_path)
# Stage all changes
repo.git.add(A=True)
# Commit changes
repo.index.commit(commit_message)
return "Changes committed successfully."
except Exception as e:
return trace_exception(e)
def git_commit_function(repo_path:Path|str):
return {
"function_name": "git_commit",
"function": partial(git_commit, repo_path=repo_path),
"function_description": "Commits changes to a Git repository with a specified commit message.",
"function_parameters": [
{"name": "commit_message", "type": "str"}
]
}
if __name__ == "__main__":
# Example usage
repo_path = "path/to/repo"
commit_message = "Your commit message"
print(git_commit(repo_path, commit_message))

View File

@ -0,0 +1,59 @@
# Lollms function call definition file
# File Name: git_pull.py
# Author: ParisNeo
# Description: This function pulls the latest changes from the remote repository to the local Git repository.
# Import necessary libraries
from functools import partial
from typing import Union
from pathlib import Path
import subprocess
from ascii_colors import trace_exception
# Ensure Git is installed
from lollms.utilities import PackageManager
if not PackageManager.check_package_installed("git"):
PackageManager.install_package("gitpython")
import git
def git_pull(repo_path: Union[str, Path]) -> str:
"""
Pulls the latest changes from the remote repository to the local Git repository.
Args:
repo_path (Union[str, Path]): The path to the Git repository.
Returns:
str: Success or error message.
"""
try:
repo_path = Path(repo_path)
if not repo_path.exists():
return "Repository path does not exist."
repo = git.Repo(repo_path)
# Pull latest changes
repo.remotes.origin.pull()
return "Latest changes pulled successfully."
except Exception as e:
return trace_exception(e)
def git_pull_function(repo_path:Path|str):
return {
"function_name": "git_pull",
"function": partial(git_pull, repo_path=repo_path),
"function_description": "Pulls the latest changes from the remote repository to the local Git repository.",
"function_parameters": [
{"name": "repo_path", "type": "str"}
]
}
if __name__ == "__main__":
# Example usage
repo_path = "path/to/repo"
print(git_pull(repo_path))

View File

@ -0,0 +1,61 @@
# Lollms function call definition file
# File Name: list_project_classes.py
# Author: Saif
# Description: This script defines a function to list all classes in a given Python project.
# Import necessary libraries
from functools import partial
from pathlib import Path
from typing import Union, List
import ast
import sqlite3
# Import PackageManager if there are potential libraries that need to be installed
from lollms.utilities import PackageManager
# ascii_colors offers advanced console coloring and bug tracing
from ascii_colors import trace_exception
# Here is the core of the function to be built
def list_project_classes(project_path: Union[str, Path]) -> List[str]:
"""
Lists all classes in a given Python project.
Args:
project_path (Union[str, Path]): The path to the Python project directory.
Returns:
List[str]: A list of class names found in the project.
"""
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_names = []
# Traverse the project directory and extract class names
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):
class_names.append(node.name)
return class_names
except Exception as e:
return [trace_exception(e)]
# Metadata function
def list_project_classes_function(project_path):
return {
"function_name": "list_project_classes",
"function": partial(list_project_classes, project_path=project_path),
"function_description": "Lists all classes in a given Python project.",
"function_parameters": []
}

View File

@ -0,0 +1,51 @@
# Lollms function call definition file
# File Name: list_project_structure.py
# Author: ParisNeo
# Description: This function lists and displays the structure of the project directory.
from functools import partial
from pathlib import Path
from typing import Union, List
from ascii_colors import trace_exception
def list_project_structure(project_path: Union[str, Path]) -> str:
"""
Lists and displays the structure of the project directory, excluding certain directories.
Args:
project_path (Union[str, Path]): The path to the project directory.
Returns:
str: A string representation of the project directory structure.
"""
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."
# Directories to exclude
exclude_dirs = {'.git', '.vscode', '__pycache__'}
structure = []
for file in project_path.rglob("*"):
# Skip excluded directories
if any(part in exclude_dirs or part.endswith('.egg-info') for part in file.parts):
continue
indent_level = len(file.relative_to(project_path).parts) - 1
structure.append(f"{' ' * indent_level}{file.name}")
return "\n".join(structure)
except Exception as e:
return trace_exception(e)
def list_project_structure_function(project_path: Union[str, Path]):
return {
"function_name": "list_project_structure",
"function": partial(list_project_structure, project_path=project_path),
"function_description": "Lists and displays the structure of the project directory.",
"function_parameters": []
}

View File

@ -0,0 +1,84 @@
from typing import Optional, Union
from pathlib import Path
import sqlite3
import difflib
import json
from ascii_colors import trace_exception
from functools import partial
def search_class_in_project(class_name: str, db_path: Union[str, Path]) -> Optional[str]:
"""
Searches for a specific class by name in the project database and returns detailed information.
Args:
db_path (Union[str, Path]): The path to the project database file.
class_name (str): The name of the class to search for.
Returns:
Optional[str]: A string with detailed information about the class, or None if not found.
"""
try:
db_path = Path(db_path)
if not db_path.exists():
return "Database file does not exist."
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Fetch all class names to find the closest match
cursor.execute("SELECT id, name FROM classes")
classes = cursor.fetchall()
class_names = [name for _, name in classes]
closest_matches = difflib.get_close_matches(class_name, class_names, n=1, cutoff=0.1)
if not closest_matches:
return f"No class found with a name similar to '{class_name}'."
closest_class_name = closest_matches[0]
cursor.execute("SELECT id, file_id, name, docstring, core FROM classes WHERE name = ?", (closest_class_name,))
class_info = cursor.fetchone()
if not class_info:
return f"No class found with the name '{closest_class_name}'."
class_id, file_id, name, docstring, core = class_info
# Fetch the file path
cursor.execute("SELECT path FROM files WHERE id = ?", (file_id,))
file_path = cursor.fetchone()[0]
# Fetch methods of the class
cursor.execute("SELECT name, docstring, parameters FROM methods WHERE class_id = ?", (class_id,))
methods = cursor.fetchall()
# Construct the detailed information string
details = f"Class: {name}\n"
details += f"File: {file_path}\n"
details += f"Description: {docstring}\n\n"
details += "Methods:\n"
for method_name, method_docstring, method_parameters in methods:
details += f" - {method_name}({', '.join([f'{param[0]}: {param[1]}' for param in json.loads(method_parameters)])})\n"
details += f" Description: {method_docstring}\n"
conn.close()
return details
except Exception as e:
return trace_exception(e)
def search_class_in_project_function(project_path):
return {
"function_name": "create_project_database",
"function": partial(search_class_in_project, project_path=project_path),
"function_description": "Searches for a specific class by name in the project database and returns detailed information.",
"function_parameters": [{"name":"class_name", "type":"str", "description":"Name of the class to search"}]
}
if __name__ == "__main__":
# Example usage
db_path = "path/to/project_info.db"
class_name = "MyClass"
print(search_class_in_project(db_path, class_name))

View File

@ -3587,7 +3587,7 @@ The AI should respond in this format using data from actions_list:
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
out += f"{separator_template}{start_header_id_template}function calls results{end_header_id_template}\n" + final_output + "\n"
if prompt_after_execution:
if separate_output:
self.full(final_output)