From 547717f1c1b9327969a27e0c2e9d6f7bc3b8f1f2 Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Tue, 25 Jun 2024 23:15:27 +0200 Subject: [PATCH] upgraded memes function calls --- lollms/functions/memes/memes_builder.py | 149 ++++++++++++++++++ .../endpoints/lollms_binding_files_server.py | 1 + 2 files changed, 150 insertions(+) create mode 100644 lollms/functions/memes/memes_builder.py diff --git a/lollms/functions/memes/memes_builder.py b/lollms/functions/memes/memes_builder.py new file mode 100644 index 0000000..ded5c0e --- /dev/null +++ b/lollms/functions/memes/memes_builder.py @@ -0,0 +1,149 @@ +# Lollms function call definition file +# File Name: drake_meme_generator.py +# Author: ParisNeo +# Description: This function generates a Drake meme by overlaying positive and negative text onto a predefined image template. + +from functools import partial +from typing import Dict +from lollms.utilities import PackageManager, discussion_path_to_url +from lollms.client_session import Client +from ascii_colors import trace_exception +from pathlib import Path + +# Ensure required libraries are installed +if not PackageManager.check_package_installed("PIL"): + PackageManager.install_package("Pillow") + +from pathlib import Path +import requests +from PIL import Image +from io import BytesIO + +# Now we can import the library +from PIL import Image, ImageDraw, ImageFont + +import textwrap + +def load_image_from_url(url: str) -> Image.Image: + """ + Load an image from a given URL. + + Args: + url (str): The URL of the image to load. + + Returns: + Image.Image: The loaded image. + """ + response = requests.get(url) + response.raise_for_status() # Ensure we notice bad responses + image = Image.open(BytesIO(response.content)) + return image +def draw_text_with_outline(draw: ImageDraw.Draw, text: str, position: tuple, font: ImageFont.FreeTypeFont, outline_width: int = 2, fill: str = "white", outline_fill: str = "black"): + """ + Draw text with an outline. + + Args: + draw (ImageDraw.Draw): The drawing context. + text (str): The text to draw. + position (tuple): The position to draw the text (x, y). + font (ImageFont.FreeTypeFont): The font to use. + outline_width (int): The width of the outline. + fill (str): Color to fill the text with. + outline_fill (str): Color to fill the outline with. + """ + x, y = position + # Draw outline + for dx in range(-outline_width, outline_width + 1): + for dy in range(-outline_width, outline_width + 1): + if dx != 0 or dy != 0: + draw.text((x + dx, y + dy), text, font=font, fill=outline_fill) + # Draw text + draw.text(position, text, font=font, fill=fill) + +def draw_text_within_box(draw: ImageDraw.Draw, text: str, box_coords: tuple, font_path: Path, initial_font_size: int, fill: str = "white", outline_fill: str = "black"): + """ + Draw text within a specified box, adjusting font size and wrapping text as needed, and center it within the box. + + Args: + draw (ImageDraw.Draw): The drawing context. + text (str): The text to draw. + box_coords (tuple): The coordinates of the box (top_left_x, top_left_y, bottom_right_x, bottom_right_y). + font_path (Path): Path to the font file. + initial_font_size (int): Initial font size to start with. + fill (str): Color to fill the text with. + outline_fill (str): Color to fill the outline with. + """ + top_left_x, top_left_y, bottom_right_x, bottom_right_y = box_coords + box_width = bottom_right_x - top_left_x + box_height = bottom_right_y - top_left_y + font_size = initial_font_size + font = ImageFont.truetype(str(font_path), font_size) + + # Ensure box width is positive + if box_width <= 0: + raise ValueError("Box width must be greater than 0") + + # Wrap text to fit within the box width + wrapped_text = textwrap.fill(text, width=box_width // font.getbbox('A')[2]) + + # Adjust font size to fit within the box height + while font.getbbox(wrapped_text)[3] > box_height and font_size > 1: + font_size -= 1 + font = ImageFont.truetype(str(font_path), font_size) + wrapped_text = textwrap.fill(text, width=box_width // font.getbbox('A')[2]) + + # Calculate text size and position to center it + text_left, text_top, text_width, text_height = font.getbbox(wrapped_text) + text_x = top_left_x + (box_width - text_width) / 2 + text_y = top_left_y + (box_height - text_height) / 2 + + # Draw the text with outline + draw_text_with_outline(draw, wrapped_text, (text_x, text_y), font, outline_width=2, fill=fill, outline_fill=outline_fill) + +def drake_meme_generator(positive_text: str, negative_text: str, client:Client) -> str: + """ + Generates a Drake meme using the provided positive and negative text. + + Args: + positive_text (str): Text to be placed in the second box (Drake approving). + negative_text (str): Text to be placed in the first box (Drake disapproving). + + Returns: + str: HTML string containing the path to the generated meme image. + """ + try: + # Load the Drake meme template image + template_url = "https://i.pinimg.com/originals/0e/90/91/0e9091993fc0289656646088f0ea93f7.jpg" + image = load_image_from_url(template_url) + + # Define positions for text boxes + first_box_coords = (627, 129, 1173, 407) + second_box_coords = (627, 763, 1173, 1046) + + # Initialize drawing context + draw = ImageDraw.Draw(image) + font_path = Path("arial.ttf") # Ensure you have a suitable font file + + # Add text to the image + draw_text_within_box(draw, negative_text, first_box_coords, font_path, initial_font_size=40, fill="black") + draw_text_within_box(draw, positive_text, second_box_coords, font_path, initial_font_size=40, fill="black") + + # Save the modified image + output_path = client.discussion_path/"drake_meme_output.jpg" + image.save(output_path) + + # Return HTML string with the image path + return f'Drake Meme' + except Exception as e: + return trace_exception(e) + +def drake_meme_generator_function(client:Client) -> Dict: + return { + "function_name": "drake_meme_generator", + "function": partial(drake_meme_generator, client=client), + "function_description": "Generates a Drake meme using the provided positive and negative text.", + "function_parameters": [ + {"name": "positive_text", "type": "str"}, + {"name": "negative_text", "type": "str"} + ] + } diff --git a/lollms/server/endpoints/lollms_binding_files_server.py b/lollms/server/endpoints/lollms_binding_files_server.py index 496e19b..f9dcae8 100644 --- a/lollms/server/endpoints/lollms_binding_files_server.py +++ b/lollms/server/endpoints/lollms_binding_files_server.py @@ -67,6 +67,7 @@ async def serve_bindings(path: str): raise HTTPException(status_code=400, detail="File not found") return FileResponse(str(file_path)) + @router.get("/personalities/{path:path}") async def serve_personalities(path: str): """