From 08e812ec566b2e7dd20e2350aefa81285a32849c Mon Sep 17 00:00:00 2001 From: MichaelDecent Date: Fri, 10 Jan 2025 10:42:23 +0100 Subject: [PATCH] feat: add Swarmauri Text Length Tool package with README, configuration, and unit tests --- .../README.md | 1 + .../pyproject.toml | 57 ++++++++++ .../TextLengthTool.py | 107 ++++++++++++++++++ .../__init__.py | 14 +++ .../tests/unit/TextLength_unit_test.py | 63 +++++++++++ 5 files changed, 242 insertions(+) create mode 100644 pkgs/community/swarmauri_tool_communitytextlength/README.md create mode 100644 pkgs/community/swarmauri_tool_communitytextlength/pyproject.toml create mode 100644 pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/TextLengthTool.py create mode 100644 pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/__init__.py create mode 100644 pkgs/community/swarmauri_tool_communitytextlength/tests/unit/TextLength_unit_test.py diff --git a/pkgs/community/swarmauri_tool_communitytextlength/README.md b/pkgs/community/swarmauri_tool_communitytextlength/README.md new file mode 100644 index 00000000..cd26902a --- /dev/null +++ b/pkgs/community/swarmauri_tool_communitytextlength/README.md @@ -0,0 +1 @@ +# Swarmauri Example Community Package \ No newline at end of file diff --git a/pkgs/community/swarmauri_tool_communitytextlength/pyproject.toml b/pkgs/community/swarmauri_tool_communitytextlength/pyproject.toml new file mode 100644 index 00000000..c0a53c4e --- /dev/null +++ b/pkgs/community/swarmauri_tool_communitytextlength/pyproject.toml @@ -0,0 +1,57 @@ +[tool.poetry] +name = "swarmauri_tool_communitytextlength" +version = "0.6.0.dev1" +description = "This repository includes an example of a First Class Swarmauri Example." +authors = ["Jacob Stewart "] +license = "Apache-2.0" +readme = "README.md" +repository = "http://github.com/swarmauri/swarmauri-sdk" +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" +] + +[tool.poetry.dependencies] +python = ">=3.10,<3.13" + +# Swarmauri +swarmauri_core = { path = "../../core" } +swarmauri_base = { path = "../../base" } + +# Dependencies +nltk = "^3.9.1" + + +[tool.poetry.group.dev.dependencies] +flake8 = "^7.0" +pytest = "^8.0" +pytest-asyncio = ">=0.24.0" +pytest-xdist = "^3.6.1" +pytest-json-report = "^1.5.0" +python-dotenv = "*" +requests = "^2.32.3" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +norecursedirs = ["combined", "scripts"] + +markers = [ + "test: standard test", + "unit: Unit tests", + "integration: Integration tests", + "acceptance: Acceptance tests", + "experimental: Experimental tests" +] +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(asctime)s [%(levelname)s] %(message)s" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" +asyncio_default_fixture_loop_scope = "function" + +[tool.poetry.plugins."swarmauri.tools"] +TextLengthTool = "swarmauri_tool_communitytextlength:TextLengthTool" \ No newline at end of file diff --git a/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/TextLengthTool.py b/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/TextLengthTool.py new file mode 100644 index 00000000..be9fd56f --- /dev/null +++ b/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/TextLengthTool.py @@ -0,0 +1,107 @@ +from swarmauri_core.typing import SubclassUnion +from typing import List, Literal, Dict +from pydantic import Field +from swarmauri._base.tools.ToolBase import ToolBase +from swarmauri_standard.tools.Parameter import Parameter +import nltk +from nltk.tokenize import sent_tokenize, word_tokenize + +# Download required NLTK data once during module load +nltk.download("punkt", quiet=True) + + +class TextLengthTool(ToolBase): + version: str = "0.1.dev1" + parameters: List[Parameter] = Field( + default_factory=lambda: [ + Parameter( + name="text", + type="string", + description="The text to analyze for length.", + required=True, + ) + ] + ) + name: str = "TextLengthTool" + description: str = "Calculates the length of the provided text in terms of characters, words, and sentences." + type: Literal["TextLengthTool"] = "TextLengthTool" + + def __call__(self, text: str) -> Dict[str, int]: + """ + Calculates the length of the provided text in terms of characters, words, and sentences. + + Parameters: + text (str): The text to analyze. + + Returns: + dict: A dictionary containing the number of characters, words, and sentences. + """ + return self.calculate_text_length(text) + + def calculate_text_length(self, text: str) -> Dict[str, int]: + """ + Calculate the length of the text in characters, words, and sentences. + + Parameters: + text (str): The text to analyze. + + Returns: + dict: A dictionary containing: + - 'num_characters': Number of characters in the text. + - 'num_words': Number of words in the text. + - 'num_sentences': Number of sentences in the text. + """ + num_characters = self.count_characters(text) + num_words = self.count_words(text) + num_sentences = self.count_sentences(text) + + return { + "num_characters": num_characters, + "num_words": num_words, + "num_sentences": num_sentences, + } + + def count_characters(self, text: str) -> int: + """ + Count the number of characters in the text, excluding spaces. + + Parameters: + text (str): The text to analyze. + + Returns: + int: The number of characters in the text. + """ + return len(text.replace(" ", "")) + + def count_words(self, text: str) -> int: + """ + Count the number of words in the text. + + Parameters: + text (str): The text to analyze. + + Returns: + int: The number of words in the text. + """ + words = word_tokenize(text) + return len(words) + + def count_sentences(self, text: str) -> int: + """ + Count the number of sentences in the text. + + Parameters: + text (str): The text to analyze. + + Returns: + int: The number of sentences in the text. + """ + sentences = sent_tokenize(text) + return len(sentences) + + +SubclassUnion.update( + baseclass=ToolBase, + type_name="TextLengthTool", + obj=TextLengthTool, +) diff --git a/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/__init__.py b/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/__init__.py new file mode 100644 index 00000000..5792092e --- /dev/null +++ b/pkgs/community/swarmauri_tool_communitytextlength/swarmauri_tool_communitytextlength/__init__.py @@ -0,0 +1,14 @@ +from .TextLengthTool import TextLengthTool + +__version__ = "0.6.0.dev26" +__long_desc__ = """ + +# Swarmauri Example Plugin + +This repository includes an example of a Swarmauri Plugin. + +Visit us at: https://swarmauri.com +Follow us at: https://github.com/swarmauri +Star us at: https://github.com/swarmauri/swarmauri-sdk + +""" diff --git a/pkgs/community/swarmauri_tool_communitytextlength/tests/unit/TextLength_unit_test.py b/pkgs/community/swarmauri_tool_communitytextlength/tests/unit/TextLength_unit_test.py new file mode 100644 index 00000000..84cb1345 --- /dev/null +++ b/pkgs/community/swarmauri_tool_communitytextlength/tests/unit/TextLength_unit_test.py @@ -0,0 +1,63 @@ +import pytest +from swarmauri_tool_communitytextlength.TextLengthTool import TextLengthTool as Tool + + +@pytest.mark.unit +def test_ubc_resource(): + tool = Tool() + assert tool.resource == "Tool" + + +@pytest.mark.unit +def test_ubc_type(): + assert Tool().type == "TextLengthTool" + + +@pytest.mark.unit +def test_initialization(): + tool = Tool() + assert type(tool.id) == str + + +@pytest.mark.unit +def test_serialization(): + tool = Tool() + assert tool.id == Tool.model_validate_json(tool.model_dump_json()).id + + +@pytest.mark.unit +def test_call(): + tool = Tool() + text = "This is a simple test sentence." + + num_characters = 26 + num_words = 7 + num_sentences = 1 + + expected_keys = {"num_characters", "num_words", "num_sentences"} + + result = tool(text) + + assert isinstance(result, dict), f"Expected dict, but got {type(result).__name__}" + assert expected_keys.issubset( + result.keys() + ), f"Expected keys {expected_keys} but got {result.keys()}" + assert isinstance( + result.get("num_characters"), int + ), f"Expected int, but got {type(result.get('num_characters')).__name__}" + assert isinstance( + result.get("num_words"), int + ), f"Expected int, but got {type(result.get('num_words')).__name__}" + assert isinstance( + result.get("num_sentences"), int + ), f"Expected int, but got {type(result.get('num_sentences')).__name__}" + + assert ( + result.get("num_characters") == num_characters + ), f"Expected Number of Characters is {num_characters}, but got {result.get('num_characters')}" + assert ( + result.get("num_words") == num_words + ), f"Expected Number of Words is {num_words}, but got {result.get('num_words')}" + assert ( + result.get("num_sentences") == num_sentences + ), f"Expected Number of Sentence is {num_sentences}, but got {result.get('num_sentences')}"