Spaces:
Running
Running
# 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}" |