CoolFace
Apppublic

tsystems/visual_document_retrieval

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
2likes
vdr_utils.py180 linesDownload Raw Back to app
1from PIL import Image2import numpy as np3import base644import io5from io import BytesIO6from PIL import Image, ImageFile7from pdf2image import convert_from_path8import tempfile9from multiprocessing import Pool10import os11from loguru import logger12import uuid13 14from typing import Any, List, Tuple, Type, Literal, Optional, Union, Dict15 16def encode_image(image_path):17  with open(image_path, "rb") as image_file:18    return base64.b64encode(image_file.read()).decode('utf-8')19 20def load_image_from_base64(image):21    return Image.open(BytesIO(base64.b64decode(image)))22 23def pil_image_to_base64(image: Image) -> str:24    """25    Convert a PIL Image object to its base64 representation.26 27    Args:28        image (Image): The PIL Image object to be converted.29 30    Returns:31        str: The base64 representation of the image.32    """33 34    # Create a bytes buffer35    buffer = io.BytesIO()36 37    # Save the image to the buffer38    image.save(buffer, format="PNG")39 40    # Get the bytes from the buffer41    img_bytes = buffer.getvalue()42 43    # Convert the bytes to base6444    img_base64 = base64.b64encode(img_bytes).decode("utf-8")45 46    return img_base6447 48def scale_image(image: Image.Image, new_height: int = 1024) -> Image.Image:49    """50    Scale an image to a new height while maintaining the aspect ratio.51    """52    width, height = image.size53    aspect_ratio = width / height54    new_width = int(new_height * aspect_ratio)55 56    scaled_image = image.resize((new_width, new_height))57 58    return scaled_image59 60def unflatten_array(flat_list, vector_size=128):61    return np.array(flat_list).reshape(-1, vector_size)62 63def get_image_embedding(image_list: list[Image], openai_client, model: str, flatten: bool = False) -> list:64    """65    Get the embedding of an image.66 67    Args:68        image (Image): The image to be embedded.69 70    Returns:71        list[list[float]] if flatten, 72        else: list[list[list[float]]] with shape = (number of images (m), number of vector for each text (n), vector dim = 128)73    """74    if not isinstance(image_list, list):75        image_list = [image_list]76 77    input_base64_list = [f"data:image/png;base64,{pil_image_to_base64(image)}" for image in image_list]78    # Get the embedding of the image79    embedding = openai_client.embeddings.create(80        input=input_base64_list,81        model=model,82        extra_body={83            "modality": "image",84            "encoding_format":"float" if not flatten else "base64",85        },86    )87 88    result = []89    for embed in embedding.data:90        result.append(embed.embedding) # embed.embedding is a list[float] in case of flatten, else: list[list[float]]91    return result92 93def get_text_embedding(texts: list[str], openai_client, model: str, flatten: bool = False) -> list:94    """95    Get the embedding of a text.96 97    Args:98        text (str): The text to be embedded.99 100    Returns:101        list[list[float]] if flatten, 102        else: list[list[list[float]]] with shape = (number of texts (m), number of vector for each text (n), vector dim = 128)103    """104    if not isinstance(texts, list):105        texts = [texts]106 107    # Get the embedding of the text108    embedding = openai_client.embeddings.create(109        input=texts,110        model=model,111        extra_body={112            "encoding_format":"float" if not flatten else "base64",113        },114    )115 116    result = []117    for embed in embedding.data:118        result.append(embed.embedding) # embed.embedding is a list[float] in case of flatten, else: list[list[float]]119    return result120 121def load_images(image_paths):122    """123    Load images from a list of paths and return a list of PIL image objects.124 125    Args:126        image_paths (list): List of image paths.127 128    Returns:129        list: List of PIL image objects.130    """131    images = []132    for path in image_paths:133        try:134            img = Image.open(path)135            images.append(img)136        except Exception as e:137            logger.error(f"Error loading image at path {path}: {str(e)}")138    return images139    140 141def process_pdf(pdf_path: str, output_folder: str, thread_count=1):142    result_image_paths = []143 144    with tempfile.TemporaryDirectory() as temp_dir:145        images = convert_from_path(pdf_path, dpi=200, output_folder=temp_dir, thread_count=thread_count)146 147    # for page_num, image in enumerate(images):148    #     image_filename = f"{str(uuid.uuid4())}.png"149    #     image_path = os.path.join(output_folder, image_filename)150    #     image.save(image_path, "PNG")151    #     result_image_paths.append(image_path)152    153    # del images154    # return result_image_paths155    return images156 157 158def pdf_folder_to_images(pdf_folder: str, output_folder: str, process_count: int = 2):159    try:160        if process_count is None:161            process_count = os.cpu_count()162 163        pdf_files = [os.path.join(pdf_folder, f) for f in os.listdir(pdf_folder)164                     if f.lower().endswith('.pdf')]165        166        # Create a list of tuples containing (pdf_file, output_folder)167        args = [(pdf_file, output_folder) for pdf_file in pdf_files]168        169        with Pool(process_count) as pool:170            all_images = pool.starmap(process_pdf, args)171        172        result = [img for sublist in all_images for img in sublist]173 174        logger.debug(f"Number of pdfs processed: {len(all_images)} - Number of images: {len(result)}")175        return result176    except Exception as e:177        logger.exception(f"Error during processing pdf: {e}")178 179 180