From f49c2a78bdabc7f5abfd5fe5e2bec0087cd0ac77 Mon Sep 17 00:00:00 2001 From: Noble Date: Mon, 22 Jul 2024 22:43:52 +0200 Subject: [PATCH 01/19] Add functionality to send requests and generate stories; update requirements.txt --- llm.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 ++ 2 files changed, 73 insertions(+) create mode 100644 llm.py create mode 100644 requirements.txt diff --git a/llm.py b/llm.py new file mode 100644 index 0000000..1c4c8a6 --- /dev/null +++ b/llm.py @@ -0,0 +1,71 @@ +import requests +from llamaapi import LlamaAPI +from dotenv import load_dotenv +import os + +# Load environment variables from a .env file +load_dotenv() + +# Retrieve the Llama API token from the environment variables +llama_api_token = os.getenv("LLAMA_API_TOKEN") + +# Initialize the LlamaAPI SDK with the API token +llama = LlamaAPI(llama_api_token) + +def generate_complete_story(name): + # Construct the API request to generate a funny story + api_request_json = { + "messages": [ + {"role": "user", "content": f"Generate a funny story about a person named {name}."} + ], + "max_tokens": 500, # Set the maximum number of tokens to get a short story + "stream": False + } + + # Execute the API request + response = llama.run(api_request_json) + + # Extract the generated text from the API response + generated_text = response.json()["choices"][0]["message"]["content"] + + return generated_text + +def get_names_from_file(filename): + try: + with open(filename, 'r') as file: + names = file.readlines() + return [name.strip() for name in names] # Remove whitespace and newline characters + except FileNotFoundError: + print(f"The file {filename} does not exist.") + return [] + +# Read names from the names.txt file +names = get_names_from_file('names.txt') + +# URL of the target server +# url = os.getenv("URL") + +# Iterate through each name in the list and send a request to the server +for i, name in enumerate(names, start=1): + print(f"{i}: ", end="") + + # Generate a funny story for the current name + story = generate_complete_story(name) + + # Form data to send with the POST request + data = { + "wnd_ShortTextField_670972831": name, + "wnd_RadioGroupField_714859850": "wnd_RadioGroupOption_74325105", + "wnd_LongTextField_230983133": story, + "send": "wnd_FormBlock_2860052" + } + + # Send the POST request to the server + response = requests.post(url, data=data) + + # Check the status of the response and print an appropriate message + if response.status_code == 200: + print("Request sent successfully") + else: + print("Error in request") + print("Status code:", response.status_code) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..560db37 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +llamaapi \ No newline at end of file From f71d10acbc1490ecb52c70417ed090374eadb535 Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Mon, 22 Jul 2024 13:10:14 +0200 Subject: [PATCH 02/19] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b04a72 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# PrankLineCrafter +PrankLineCrafter generates funny and quirky text using AI. With Python and LlamaAPI, it creates amusing lines for pranks, playful content, or just for fun. Perfect for adding a humorous twist to your projects or surprising friends with witty AI-generated text! From e5aba810e1678a452eba520a1a5c1d93cbff3f08 Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:58:58 +0200 Subject: [PATCH 03/19] Update llm.py --- llm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llm.py b/llm.py index 1c4c8a6..a2ac031 100644 --- a/llm.py +++ b/llm.py @@ -43,7 +43,7 @@ def get_names_from_file(filename): names = get_names_from_file('names.txt') # URL of the target server -# url = os.getenv("URL") +url = os.getenv("URL") # Iterate through each name in the list and send a request to the server for i, name in enumerate(names, start=1): From ca507c0f10a8b12d21df749f3d2c8863e5c0ecfd Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Tue, 23 Jul 2024 00:05:05 +0200 Subject: [PATCH 04/19] Update README.md --- README.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b04a72..e90f908 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,80 @@ # PrankLineCrafter -PrankLineCrafter generates funny and quirky text using AI. With Python and LlamaAPI, it creates amusing lines for pranks, playful content, or just for fun. Perfect for adding a humorous twist to your projects or surprising friends with witty AI-generated text! + +PrankLineCrafter is a Python script that generates humorous stories based on names provided in a text file and submits these stories to a server via HTTP POST requests. The stories are generated using the LlamaAPI, which is integrated into the script to create engaging and amusing content. + +## Features + +- Reads names from a `names.txt` file. +- Generates a funny story for each name using the LlamaAPI. +- Sends each name and its corresponding story to a specified server URL via HTTP POST requests. +- Handles environment variables for sensitive information such as API tokens and server URLs. + +## Requirements + +- Python 3.6 or higher +- `requests` library +- `llamaapi` library +- `python-dotenv` library + +## Setup + +To set up and run the script, follow these steps: + +1. Clone this repository: + + ```bash + git clone https://github.com/yourusername/your-repository.git + cd your-repository + ``` + +2. Install the required packages: + + ```bash + pip install -r requirements.txt + ``` + +3. Create a `.env` file in the root directory of the repository with the following content: + + ```plaintext + LLAMA_API_TOKEN=your_llama_api_token + URL=your_target_url + ``` + + Replace `your_llama_api_token` with your LlamaAPI token and `your_target_url` with the URL of the server where you want to send the generated stories. + +## Usage + +1. Prepare a `names.txt` file in the root directory with one name per line. + +2. Run the `llm.py` script: + + ```bash + python llm.py + ``` + + The script will read names from `names.txt`, generate a story for each name, and send the results to the specified URL. + +## Configuration + +- **LLAMA_API_TOKEN**: Your LlamaAPI token for accessing the API. +- **URL**: The target server URL where the POST requests will be sent. + +## Error Handling + +- If the `names.txt` file is missing, the script will notify you with an error message. +- If the server responds with an error, the script will print the status code for debugging purposes. + +## Example + +Given a `names.txt` file with the following content: +```plaintext +Alice +Bob +Charlie +``` + +The script will generate and send stories for "Alice", "Bob", and "Charlie" to the specified server. + +## Contributing + +Contributions are welcome! Please open an issue or submit a pull request with improvements or bug fixes. From 564dc885c3945bdf489612b5673fa1891a50f643 Mon Sep 17 00:00:00 2001 From: Noble Date: Wed, 24 Jul 2024 11:59:39 +0200 Subject: [PATCH 05/19] Add unit tests for story generation and name extraction --- tests/test_main.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_main.py diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..bf1325e --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,44 @@ +import unittest +from unittest.mock import patch, MagicMock +from main import generate_complete_story, get_names_from_file +import os + + +class TestMain(unittest.TestCase): + + # Patch the 'run' method of the 'llama' object in the 'main' module + @patch('main.llama.run') + def test_generate_complete_story(self, mock_run): + # Mock the JSON response of the API call + mock_response = MagicMock() + mock_response.json.return_value = { + "choices": [ + { + "message": { + "content": "Once upon a time, a person named Alice..." + } + } + ] + } + mock_run.return_value = mock_response + + # Call the function to generate a story + story = generate_complete_story("Alice") + + # Assert that the generated story contains the expected content + self.assertIn("Once upon a time, a person named Alice", story) + + def test_get_names_from_file(self): + # Get the absolute path of names.txt relative to main.py + base_dir = os.path.dirname(os.path.abspath(__file__)) + names_file_path = os.path.join(base_dir, '..', 'names.txt') + + # Call the function to read names from the file + names = get_names_from_file(names_file_path) + + # Assert that the names list matches the expected list + self.assertEqual(names, ['Alice', 'Bob', 'Charlie']) + + +if __name__ == '__main__': + unittest.main() From 8f665c13799cbcc0f325c4bc1343041f8ac22f81 Mon Sep 17 00:00:00 2001 From: Noble Date: Wed, 24 Jul 2024 12:00:23 +0200 Subject: [PATCH 06/19] Add GitHub Actions for build and lint --- .github/workflows/build.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f124b63 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,36 @@ +name: Build and Test Python Application + +on: + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m venv venv + . venv/bin/activate + pip install -r requirements.txt + + - name: Run tests + run: | + . venv/bin/activate + python -m unittest discover tests + + - name: Lint code + run: | + . venv/bin/activate + pip install flake8 + flake8 . From 3d02f99b943b4229d1b9f0d77355c73991d10cb0 Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:18:29 +0200 Subject: [PATCH 07/19] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f124b63..6e3844f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.8' + python-version: '3.9' - name: Install dependencies run: | From c29763012dbf95ce7c68416f70b13013623f204f Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:19:43 +0200 Subject: [PATCH 08/19] Update requirements.txt --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 560db37..9231d7d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -requests -llamaapi \ No newline at end of file +requests==2.32.3 +llamaapi==0.1.36 From 7861b16c89bfef21fd657ed56a075534f98679b5 Mon Sep 17 00:00:00 2001 From: Francesco Ricciardi <124498572+Noblesix960@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:41:44 +0200 Subject: [PATCH 09/19] Update README.md --- README.md | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e90f908..55a20d9 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,12 @@ PrankLineCrafter is a Python script that generates humorous stories based on nam ## Requirements -- Python 3.6 or higher +- Python 3.9 or higher - `requests` library - `llamaapi` library - `python-dotenv` library -## Setup - -To set up and run the script, follow these steps: +## Setup and Usage 1. Clone this repository: @@ -42,22 +40,14 @@ To set up and run the script, follow these steps: Replace `your_llama_api_token` with your LlamaAPI token and `your_target_url` with the URL of the server where you want to send the generated stories. -## Usage - -1. Prepare a `names.txt` file in the root directory with one name per line. +4. Prepare a `names.txt` file in the root directory with one name per line. -2. Run the `llm.py` script: +5. Run the script: ```bash - python llm.py + python main.py ``` - - The script will read names from `names.txt`, generate a story for each name, and send the results to the specified URL. - -## Configuration - -- **LLAMA_API_TOKEN**: Your LlamaAPI token for accessing the API. -- **URL**: The target server URL where the POST requests will be sent. + The script will read names from names.txt, generate a story for each name, and send the results to the specified server. ## Error Handling From 7b26db822fe17497928ef46db9b3dd0877efe5d8 Mon Sep 17 00:00:00 2001 From: Noble Date: Wed, 24 Jul 2024 12:54:46 +0200 Subject: [PATCH 10/19] Added a structure to the project --- llm.py | 71 --------------------------- main.py | 30 +++++++++++ names.txt | 3 ++ prank_line_crafter/__init__.py | 1 + prank_line_crafter/config.py | 10 ++++ prank_line_crafter/sender.py | 21 ++++++++ prank_line_crafter/story_generator.py | 22 +++++++++ requirements.txt | 1 + 8 files changed, 88 insertions(+), 71 deletions(-) delete mode 100644 llm.py create mode 100644 main.py create mode 100644 names.txt create mode 100644 prank_line_crafter/__init__.py create mode 100644 prank_line_crafter/config.py create mode 100644 prank_line_crafter/sender.py create mode 100644 prank_line_crafter/story_generator.py diff --git a/llm.py b/llm.py deleted file mode 100644 index a2ac031..0000000 --- a/llm.py +++ /dev/null @@ -1,71 +0,0 @@ -import requests -from llamaapi import LlamaAPI -from dotenv import load_dotenv -import os - -# Load environment variables from a .env file -load_dotenv() - -# Retrieve the Llama API token from the environment variables -llama_api_token = os.getenv("LLAMA_API_TOKEN") - -# Initialize the LlamaAPI SDK with the API token -llama = LlamaAPI(llama_api_token) - -def generate_complete_story(name): - # Construct the API request to generate a funny story - api_request_json = { - "messages": [ - {"role": "user", "content": f"Generate a funny story about a person named {name}."} - ], - "max_tokens": 500, # Set the maximum number of tokens to get a short story - "stream": False - } - - # Execute the API request - response = llama.run(api_request_json) - - # Extract the generated text from the API response - generated_text = response.json()["choices"][0]["message"]["content"] - - return generated_text - -def get_names_from_file(filename): - try: - with open(filename, 'r') as file: - names = file.readlines() - return [name.strip() for name in names] # Remove whitespace and newline characters - except FileNotFoundError: - print(f"The file {filename} does not exist.") - return [] - -# Read names from the names.txt file -names = get_names_from_file('names.txt') - -# URL of the target server -url = os.getenv("URL") - -# Iterate through each name in the list and send a request to the server -for i, name in enumerate(names, start=1): - print(f"{i}: ", end="") - - # Generate a funny story for the current name - story = generate_complete_story(name) - - # Form data to send with the POST request - data = { - "wnd_ShortTextField_670972831": name, - "wnd_RadioGroupField_714859850": "wnd_RadioGroupOption_74325105", - "wnd_LongTextField_230983133": story, - "send": "wnd_FormBlock_2860052" - } - - # Send the POST request to the server - response = requests.post(url, data=data) - - # Check the status of the response and print an appropriate message - if response.status_code == 200: - print("Request sent successfully") - else: - print("Error in request") - print("Status code:", response.status_code) diff --git a/main.py b/main.py new file mode 100644 index 0000000..04a78e7 --- /dev/null +++ b/main.py @@ -0,0 +1,30 @@ +from prank_line_crafter.story_generator import generate_complete_story +from prank_line_crafter.sender import send_story +import os + +def get_names_from_file(filename): + """Read names from the specified file.""" + try: + with open(filename, 'r') as file: + names = file.readlines() + return [name.strip() for name in names if name.strip()] + except FileNotFoundError: + print(f"The file {filename} does not exist.") + return [] + +def main(): + names_file = 'names.txt' + names = get_names_from_file(names_file) + + for i, name in enumerate(names, start=1): + print(f"{i}: Processing {name}... ", end="") + + # Generate a funny story for the current name + story = generate_complete_story(name) + + # Send the story to the server + result = send_story(name, story) + print(result) + +if __name__ == "__main__": + main() diff --git a/names.txt b/names.txt new file mode 100644 index 0000000..606113a --- /dev/null +++ b/names.txt @@ -0,0 +1,3 @@ +Alice +Bob +Charlie diff --git a/prank_line_crafter/__init__.py b/prank_line_crafter/__init__.py new file mode 100644 index 0000000..1f356cc --- /dev/null +++ b/prank_line_crafter/__init__.py @@ -0,0 +1 @@ +__version__ = '1.0.0' diff --git a/prank_line_crafter/config.py b/prank_line_crafter/config.py new file mode 100644 index 0000000..33836a6 --- /dev/null +++ b/prank_line_crafter/config.py @@ -0,0 +1,10 @@ +import os +from dotenv import load_dotenv + +load_dotenv() + +LLAMA_API_TOKEN = os.getenv("LLAMA_API_TOKEN") +URL = os.getenv("URL") + +if not LLAMA_API_TOKEN or not URL: + raise ValueError("Missing required environment variables: LLAMA_API_TOKEN or URL") diff --git a/prank_line_crafter/sender.py b/prank_line_crafter/sender.py new file mode 100644 index 0000000..1e3a440 --- /dev/null +++ b/prank_line_crafter/sender.py @@ -0,0 +1,21 @@ +import requests +from .config import URL + +def send_story(name, story): + """Send the generated story to the server.""" + data = { + "wnd_ShortTextField_670972831": name, + "wnd_RadioGroupField_714859850": "wnd_RadioGroupOption_74325105", + "wnd_LongTextField_230983133": story, + "send": "wnd_FormBlock_2860052" + } + + try: + response = requests.post(URL, data=data) + response.raise_for_status() # Ensure we notice bad responses + if response.status_code == 200: + return "Request sent successfully" + else: + return f"Error in request: Status code {response.status_code}" + except requests.RequestException as e: + return f"Request failed: {e}" diff --git a/prank_line_crafter/story_generator.py b/prank_line_crafter/story_generator.py new file mode 100644 index 0000000..febfd97 --- /dev/null +++ b/prank_line_crafter/story_generator.py @@ -0,0 +1,22 @@ +from llamaapi import LlamaAPI +from .config import LLAMA_API_TOKEN + +def generate_complete_story(name): + """Generate a funny story about the given name using LlamaAPI.""" + llama = LlamaAPI(LLAMA_API_TOKEN) + api_request_json = { + "messages": [ + {"role": "user", "content": f"Generate a funny story about a person named {name}."} + ], + "max_tokens": 500, + "stream": False + } + + try: + response = llama.run(api_request_json) + response.raise_for_status() # Ensure we notice bad responses + generated_text = response.json()["choices"][0]["message"]["content"] + return generated_text + except Exception as e: + print(f"Error generating story for {name}: {e}") + return "Story generation failed." diff --git a/requirements.txt b/requirements.txt index 9231d7d..cf46c76 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests==2.32.3 llamaapi==0.1.36 +python-dotenv==1.0.1 From ee968da0ebf3005235238ae90fb657373f52410e Mon Sep 17 00:00:00 2001 From: Noble Date: Wed, 24 Jul 2024 17:42:31 +0200 Subject: [PATCH 11/19] Uploaded test_main.py --- tests/test_main.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/test_main.py b/tests/test_main.py index e69de29..c637baf 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -0,0 +1,44 @@ +import unittest +from unittest.mock import patch, MagicMock +from prank_line_crafter.story_generator import generate_complete_story +from main import get_names_from_file, main +import os +import io +import sys + +class TestMain(unittest.TestCase): + + @patch('prank_line_crafter.story_generator.LlamaAPI.run') + def test_generate_complete_story(self, mock_run): + # Mock the JSON response of the API call + mock_response = MagicMock() + mock_response.json.return_value = { + "choices": [ + { + "message": { + "content": "Once upon a time, a person named Alice..." + } + } + ] + } + mock_run.return_value = mock_response + + # Call the function to generate a story + story = generate_complete_story("Alice") + + # Assert that the generated story contains the expected content + self.assertIn("Once upon a time, a person named Alice", story) + + def test_get_names_from_file(self): + # Get the absolute path of names.txt relative to main.py + base_dir = os.path.dirname(os.path.abspath(__file__)) + names_file_path = os.path.join(base_dir, '..', 'names.txt') + + # Call the function to read names from the file + names = get_names_from_file(names_file_path) + + # Assert that the names list matches the expected list + self.assertEqual(names, ['Alice', 'Bob', 'Charlie']) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From a23d56a554a4477b212369c8979fb70767914d07 Mon Sep 17 00:00:00 2001 From: Noble Date: Thu, 25 Jul 2024 00:53:17 +0200 Subject: [PATCH 12/19] conform all files to PEP8 standards --- main.py | 8 +++++--- prank_line_crafter/config.py | 2 +- prank_line_crafter/sender.py | 1 + prank_line_crafter/story_generator.py | 4 +++- tests/test_main.py | 8 ++++---- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index 04a78e7..8e1f356 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ from prank_line_crafter.story_generator import generate_complete_story from prank_line_crafter.sender import send_story -import os + def get_names_from_file(filename): """Read names from the specified file.""" @@ -12,19 +12,21 @@ def get_names_from_file(filename): print(f"The file {filename} does not exist.") return [] + def main(): names_file = 'names.txt' names = get_names_from_file(names_file) for i, name in enumerate(names, start=1): print(f"{i}: Processing {name}... ", end="") - + # Generate a funny story for the current name story = generate_complete_story(name) - + # Send the story to the server result = send_story(name, story) print(result) + if __name__ == "__main__": main() diff --git a/prank_line_crafter/config.py b/prank_line_crafter/config.py index 33836a6..e8d806f 100644 --- a/prank_line_crafter/config.py +++ b/prank_line_crafter/config.py @@ -7,4 +7,4 @@ URL = os.getenv("URL") if not LLAMA_API_TOKEN or not URL: - raise ValueError("Missing required environment variables: LLAMA_API_TOKEN or URL") + raise ValueError("Missing: LLAMA_API_TOKEN or URL") diff --git a/prank_line_crafter/sender.py b/prank_line_crafter/sender.py index 1e3a440..f440043 100644 --- a/prank_line_crafter/sender.py +++ b/prank_line_crafter/sender.py @@ -1,6 +1,7 @@ import requests from .config import URL + def send_story(name, story): """Send the generated story to the server.""" data = { diff --git a/prank_line_crafter/story_generator.py b/prank_line_crafter/story_generator.py index febfd97..ea8058c 100644 --- a/prank_line_crafter/story_generator.py +++ b/prank_line_crafter/story_generator.py @@ -1,12 +1,14 @@ from llamaapi import LlamaAPI from .config import LLAMA_API_TOKEN + def generate_complete_story(name): """Generate a funny story about the given name using LlamaAPI.""" llama = LlamaAPI(LLAMA_API_TOKEN) api_request_json = { "messages": [ - {"role": "user", "content": f"Generate a funny story about a person named {name}."} + {"role": "user", + "content": f"Generate a funny story about a person named {name}"} ], "max_tokens": 500, "stream": False diff --git a/tests/test_main.py b/tests/test_main.py index c637baf..4929d93 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,10 +1,9 @@ import unittest from unittest.mock import patch, MagicMock from prank_line_crafter.story_generator import generate_complete_story -from main import get_names_from_file, main +from main import get_names_from_file import os -import io -import sys + class TestMain(unittest.TestCase): @@ -40,5 +39,6 @@ def test_get_names_from_file(self): # Assert that the names list matches the expected list self.assertEqual(names, ['Alice', 'Bob', 'Charlie']) + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() From 26a86c5808687b030552e347f6e40cbf46c50cd5 Mon Sep 17 00:00:00 2001 From: Noble Date: Thu, 25 Jul 2024 01:11:35 +0200 Subject: [PATCH 13/19] Added env variables in build.yml --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e3844f..0d7ec2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,10 @@ jobs: build: runs-on: ubuntu-latest + env: + LLAMA_API_TOKEN: ${{ secrets.LLAMA_API_TOKEN }} + URL: ${{ secrets.URL }} + steps: - name: Checkout repository uses: actions/checkout@v2 From 8e6c9f6888b9c2fc46b6156fec3d9f4b6bdf4b32 Mon Sep 17 00:00:00 2001 From: Noble Date: Thu, 25 Jul 2024 01:21:53 +0200 Subject: [PATCH 14/19] Added env variables in build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d7ec2f..3e5bbd3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,8 +10,8 @@ jobs: runs-on: ubuntu-latest env: - LLAMA_API_TOKEN: ${{ secrets.LLAMA_API_TOKEN }} - URL: ${{ secrets.URL }} + LLAMA_API_TOKEN: ${{ secrets.dev.LLAMA_API_TOKEN }} + URL: ${{ secrets.dev.URL }} steps: - name: Checkout repository From 06cc8fdac9724a79c9a96b93930311a8275a4931 Mon Sep 17 00:00:00 2001 From: Noble Date: Thu, 25 Jul 2024 01:27:36 +0200 Subject: [PATCH 15/19] Added env variables in build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e5bbd3..0d7ec2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,8 +10,8 @@ jobs: runs-on: ubuntu-latest env: - LLAMA_API_TOKEN: ${{ secrets.dev.LLAMA_API_TOKEN }} - URL: ${{ secrets.dev.URL }} + LLAMA_API_TOKEN: ${{ secrets.LLAMA_API_TOKEN }} + URL: ${{ secrets.URL }} steps: - name: Checkout repository From b67726edd6c902e000c08e6583c5be9ccb70987f Mon Sep 17 00:00:00 2001 From: Noble Date: Thu, 25 Jul 2024 01:29:16 +0200 Subject: [PATCH 16/19] Added .flake8 --- .flake8 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..d6f41f5 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +exclude = venv/ From 97fc78e240723b6fcc54f14f464300355a4054f7 Mon Sep 17 00:00:00 2001 From: Noble Date: Fri, 26 Jul 2024 00:15:19 +0200 Subject: [PATCH 17/19] removed hardcoded file name in main.py --- main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 8e1f356..1703630 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ from prank_line_crafter.story_generator import generate_complete_story from prank_line_crafter.sender import send_story +import sys def get_names_from_file(filename): @@ -13,8 +14,7 @@ def get_names_from_file(filename): return [] -def main(): - names_file = 'names.txt' +def main(names_file='names.txt'): names = get_names_from_file(names_file) for i, name in enumerate(names, start=1): @@ -29,4 +29,7 @@ def main(): if __name__ == "__main__": - main() + if len(sys.argv) > 1: + main(sys.argv[1]) + else: + main() From 8726577616eb6852c156645b089b6a561910f6e0 Mon Sep 17 00:00:00 2001 From: Noble Date: Sat, 27 Jul 2024 11:27:46 +0200 Subject: [PATCH 18/19] Added a Python linter for code quality checks --- .flake8 | 2 -- .github/workflows/build.yml | 18 +++++++++------- .pylintrc | 5 +++++ main.py | 30 +++++++++++++++++++++----- prank_line_crafter/__init__.py | 8 ++++++- prank_line_crafter/config.py | 12 +++++++++++ prank_line_crafter/sender.py | 31 +++++++++++++++++++++------ prank_line_crafter/story_generator.py | 31 +++++++++++++++++++++------ tests/test_main.py | 21 ++++++++---------- 9 files changed, 117 insertions(+), 41 deletions(-) delete mode 100644 .flake8 create mode 100644 .pylintrc diff --git a/.flake8 b/.flake8 deleted file mode 100644 index d6f41f5..0000000 --- a/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -exclude = venv/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d7ec2f..b5df5b1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,17 +24,19 @@ jobs: - name: Install dependencies run: | - python -m venv venv - . venv/bin/activate + python -m pip install --upgrade pip pip install -r requirements.txt + export PYTHONPATH=/opt/hostedtoolcache/Python/3.9.19/x64/lib/python3.9/site-packages - name: Run tests run: | - . venv/bin/activate python -m unittest discover tests - - name: Lint code - run: | - . venv/bin/activate - pip install flake8 - flake8 . + - name: Python Linter + uses: sunnysid3up/python-linter@master + with: + source: "prank_line_crafter/" + mypy-options: "--ignore-missing-imports --show-error-codes" + isort-options: "-w 100" + + diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..627f899 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,5 @@ +[MASTER] +init-hook='sys.path = ["/opt/hostedtoolcache/Python/3.9.19/x64/lib/python3.9/site-packages"]' + + + diff --git a/main.py b/main.py index 1703630..719563b 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,27 @@ -from prank_line_crafter.story_generator import generate_complete_story -from prank_line_crafter.sender import send_story +""" +Main module for prank_line_crafter. + +This module reads names from a file, generates funny stories using LlamaAPI, +and sends them to a server. +""" + import sys +from prank_line_crafter.sender import send_story +from prank_line_crafter.story_generator import generate_complete_story + def get_names_from_file(filename): - """Read names from the specified file.""" + """Read names from the specified file. + + Args: + filename (str): The path to the file containing the names. + + Returns: + list: A list of names read from the file. + """ try: - with open(filename, 'r') as file: + with open(filename, "r", encoding="utf-8") as file: # Specify encoding names = file.readlines() return [name.strip() for name in names if name.strip()] except FileNotFoundError: @@ -14,7 +29,12 @@ def get_names_from_file(filename): return [] -def main(names_file='names.txt'): +def main(names_file="names.txt"): + """Main function to process names and generate/send stories. + + Args: + names_file (str, optional): The path to the file containing the names. Default: "names.txt". + """ names = get_names_from_file(names_file) for i, name in enumerate(names, start=1): diff --git a/prank_line_crafter/__init__.py b/prank_line_crafter/__init__.py index 1f356cc..1a34abb 100644 --- a/prank_line_crafter/__init__.py +++ b/prank_line_crafter/__init__.py @@ -1 +1,7 @@ -__version__ = '1.0.0' +""" +prank_line_crafter package. + +This package provides functionality for creating and sending prank lines. +""" + +__version__ = "1.0.0" diff --git a/prank_line_crafter/config.py b/prank_line_crafter/config.py index e8d806f..9d931d0 100644 --- a/prank_line_crafter/config.py +++ b/prank_line_crafter/config.py @@ -1,4 +1,16 @@ +""" +Configuration module for prank_line_crafter package. + +This module loads environment variables and provides configuration +constants such as API tokens and URLs. + +Attributes: + LLAMA_API_TOKEN (str): The API token for LlamaAPI. + URL (str): The URL to which the stories will be sent. +""" + import os + from dotenv import load_dotenv load_dotenv() diff --git a/prank_line_crafter/sender.py b/prank_line_crafter/sender.py index f440043..13f0dfc 100644 --- a/prank_line_crafter/sender.py +++ b/prank_line_crafter/sender.py @@ -1,22 +1,39 @@ +""" +Sender module for prank_line_crafter package. + +This module contains functions to send generated stories to a server. + +Functions: + send_story(name, story): Sends the generated story to the server. +""" + import requests + from .config import URL def send_story(name, story): - """Send the generated story to the server.""" + """Send the generated story to the server. + + Args: + name (str): The name of the person the story is about. + story (str): The generated story content. + + Returns: + str: The result of the request, indicating success or failure. + """ data = { "wnd_ShortTextField_670972831": name, "wnd_RadioGroupField_714859850": "wnd_RadioGroupOption_74325105", "wnd_LongTextField_230983133": story, - "send": "wnd_FormBlock_2860052" + "send": "wnd_FormBlock_2860052", } try: - response = requests.post(URL, data=data) + response = requests.post(URL, data=data, timeout=10) response.raise_for_status() # Ensure we notice bad responses if response.status_code == 200: return "Request sent successfully" - else: - return f"Error in request: Status code {response.status_code}" - except requests.RequestException as e: - return f"Request failed: {e}" + return f"Error in request: Status code {response.status_code}" + except requests.RequestException as http_error: + return f"Request failed: {http_error}" diff --git a/prank_line_crafter/story_generator.py b/prank_line_crafter/story_generator.py index ea8058c..55f8d4f 100644 --- a/prank_line_crafter/story_generator.py +++ b/prank_line_crafter/story_generator.py @@ -1,4 +1,15 @@ +""" +Story generator module for prank_line_crafter package. + +This module generates funny stories about a given name using the LlamaAPI. + +Functions: + generate_complete_story(name): Generates a funny story about the given name. +""" + +import requests from llamaapi import LlamaAPI + from .config import LLAMA_API_TOKEN @@ -7,11 +18,13 @@ def generate_complete_story(name): llama = LlamaAPI(LLAMA_API_TOKEN) api_request_json = { "messages": [ - {"role": "user", - "content": f"Generate a funny story about a person named {name}"} + { + "role": "user", + "content": f"Generate a funny story about a person named {name}", + } ], "max_tokens": 500, - "stream": False + "stream": False, } try: @@ -19,6 +32,12 @@ def generate_complete_story(name): response.raise_for_status() # Ensure we notice bad responses generated_text = response.json()["choices"][0]["message"]["content"] return generated_text - except Exception as e: - print(f"Error generating story for {name}: {e}") - return "Story generation failed." + except requests.exceptions.RequestException as req_err: + print(f"Request error generating story for {name}: {req_err}") + return "Story generation failed due to request error." + except ValueError as val_err: + print(f"Value error generating story for {name}: {val_err}") + return "Story generation failed due to value error." + except KeyError as key_err: + print(f"Key error generating story for {name}: {key_err}") + return "Story generation failed due to key error." diff --git a/tests/test_main.py b/tests/test_main.py index 4929d93..243b24f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,23 +1,20 @@ +import os import unittest -from unittest.mock import patch, MagicMock -from prank_line_crafter.story_generator import generate_complete_story +from unittest.mock import MagicMock, patch + from main import get_names_from_file -import os +from prank_line_crafter.story_generator import generate_complete_story class TestMain(unittest.TestCase): - @patch('prank_line_crafter.story_generator.LlamaAPI.run') + @patch("prank_line_crafter.story_generator.LlamaAPI.run") def test_generate_complete_story(self, mock_run): # Mock the JSON response of the API call mock_response = MagicMock() mock_response.json.return_value = { "choices": [ - { - "message": { - "content": "Once upon a time, a person named Alice..." - } - } + {"message": {"content": "Once upon a time, a person named Alice..."}} ] } mock_run.return_value = mock_response @@ -31,14 +28,14 @@ def test_generate_complete_story(self, mock_run): def test_get_names_from_file(self): # Get the absolute path of names.txt relative to main.py base_dir = os.path.dirname(os.path.abspath(__file__)) - names_file_path = os.path.join(base_dir, '..', 'names.txt') + names_file_path = os.path.join(base_dir, "..", "names.txt") # Call the function to read names from the file names = get_names_from_file(names_file_path) # Assert that the names list matches the expected list - self.assertEqual(names, ['Alice', 'Bob', 'Charlie']) + self.assertEqual(names, ["Alice", "Bob", "Charlie"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() From 55b9bc1d8e8b5e66e101b81789e2e088e8b7ffbe Mon Sep 17 00:00:00 2001 From: Noble Date: Sat, 27 Jul 2024 11:31:12 +0200 Subject: [PATCH 19/19] Added a Python linter for code quality checks --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5df5b1..8f773ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,7 @@ jobs: with: source: "prank_line_crafter/" mypy-options: "--ignore-missing-imports --show-error-codes" + pylint-options: "--rcfile=.pylintrc" isort-options: "-w 100"