mgbam's picture
Update modules/utils.py
51d35a8 verified
# modules/utils.py
"""
A toolbox of essential, reusable utility functions for Project Asclepius.
This module helps with common tasks like data cleaning, formatting, and
safe string evaluation, promoting code reuse and maintainability.
"""
import ast
from PIL import Image
import io
import base64
def clean_user_input(text: str) -> str:
"""
Sanitizes user input by removing leading/trailing whitespace and excessive newlines.
This is a basic but important step to ensure consistent input for the APIs and AI models.
Args:
text (str): The raw user input string.
Returns:
str: The cleaned string.
"""
if not isinstance(text, str):
return ""
return " ".join(text.strip().split())
def safe_literal_eval(s: str) -> list | dict | None:
"""
Safely evaluates a string that should contain a Python literal (like a list or dict).
Uses `ast.literal_eval` to prevent arbitrary code execution, which is a major
security risk with the standard `eval()` function.
This is crucial for parsing the string-based list output from Gemini's
term extraction prompt.
Args:
s (str): The string to evaluate.
Returns:
list | dict | None: The parsed Python object, or None if evaluation fails.
"""
try:
return ast.literal_eval(s)
except (ValueError, SyntaxError, TypeError, MemoryError, KeyError):
# Catches a wide range of potential parsing errors
print(f"Warning: safe_literal_eval failed to parse string: {s}")
return None
def format_list_as_markdown(items: list[str]) -> str:
"""
Converts a simple Python list of strings into a formatted Markdown bulleted list.
Args:
items (list[str]): A list of strings.
Returns:
str: A Markdown formatted string.
"""
if not items:
return "N/A"
return "\n".join(f"- {item}" for item in items)
def create_placeholder_image(width: int = 400, height: int = 300, text: str = "Awaiting Image") -> Image.Image:
"""
Generates a simple placeholder PIL Image.
Useful for testing the vision pipeline without needing actual images.
Args:
width (int): The width of the placeholder image.
height (int): The height of the placeholder image.
text (str): The text to display on the placeholder.
Returns:
Image.Image: A PIL Image object.
"""
# This function would typically use a library like Pillow's ImageDraw
# to create an image from scratch. For simplicity in this example,
# we'll assume a pre-made placeholder or skip detailed implementation.
# For a real implementation, you'd do:
# from PIL import Image, ImageDraw, ImageFont
# img = Image.new('RGB', (width, height), color = (73, 109, 137))
# d = ImageDraw.Draw(img)
# d.text((10,10), text, fill=(255,255,0))
# return img
# Returning a simple blank image for now
return Image.new('RGB', (width, height), 'grey')
def image_to_base64(image: Image.Image, format: str = "PNG") -> str:
"""
Encodes a PIL Image into a Base64 string.
Useful for embedding images directly in Markdown or HTML if needed,
though our current approach sends the PIL object directly to Gemini.
Args:
image (Image.Image): The PIL image to encode.
format (str): The image format (e.g., "PNG", "JPEG").
Returns:
str: The Base64 encoded string.
"""
buffered = io.BytesIO()
image.save(buffered, format=format)
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return f"data:image/{format.lower()};base64,{img_str}"