File size: 6,677 Bytes
6b509f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#
# SPDX-FileCopyrightText: Hadad <[email protected]>
# SPDX-License-Identifier: Apache-2.0
#

import httpx  # Import httpx library for performing asynchronous HTTP requests efficiently
from urllib.parse import quote  # Import quote function to safely encode strings for use in URLs
from typing import Optional  # Import Optional type hint for parameters that can be None
from src.utils.ip_generator import generate_ip  # Import custom utility to generate random IP addresses for request headers
from src.utils.tools import initialize_tools  # Import utility function to initialize and retrieve tool endpoints

# Define a class named ImageGeneration to encapsulate functionalities related to generating image content
class ImageGeneration:
    # This class provides methods to create image files based on text instructions

    """
    A class to handle image generation requests to an external image generation service.

    Attributes:
        FORMATS (dict): A dictionary mapping image format names to their (width, height) dimensions.

    Methods:
        create_image: Asynchronously generates an image based on a textual instruction and parameters,
                      returning the URL of the generated image.
    """

    # Image formats
    FORMATS = {
        "default": (1024, 1024),  # Default square image size (width x height)
        "square": (1024, 1024),  # Square image format with equal width and height
        "landscape": (1024, 768),  # Landscape format with wider width than height
        "landscape_large": (1440, 1024),  # Larger landscape format with increased resolution
        "portrait": (768, 1024),  # Portrait format with taller height than width
        "portrait_large": (1024, 1440),  # Larger portrait format with increased resolution
    }

    @staticmethod  # Decorator indicating that the following method does not depend on instance state and can be called on the class itself
    # Define an asynchronous method to create image from a text instruction
    async def create_image(
        generate_image_instruction: str,  # Text instruction describing the image to generate
        image_format: str = "default",  # Desired image format key from FORMATS dictionary
        model: Optional[str] = "flux-realism",  # Optional model name for image generation; defaults to 'flux-realism'
        seed: Optional[int] = None,  # Optional seed value for randomization control in image generation
        nologo: bool = True,  # Whether to generate image without logo watermark; defaults to True
        private: bool = True,  # Whether the generated image should be private; defaults to True
        enhance: bool = True,  # Whether to apply enhancement filters to the generated image; defaults to True
    ) -> str:
        """
        Asynchronously generate an image URL by sending a request to the image generation service.
        This method will keep retrying until a successful response with status code 200 is received.

        Args:
            generate_image_instruction (str): The textual instruction or description for the desired image.
            image_format (str, optional): The format key specifying image dimensions. Defaults to "default".
            model (Optional[str], optional): The image generation model to use. Defaults to "flux-realism".
            seed (Optional[int], optional): Seed for randomization to reproduce images. Defaults to None.
            nologo (bool, optional): Flag to exclude logo watermark. Defaults to True.
            private (bool, optional): Flag to mark image as private. Defaults to True.
            enhance (bool, optional): Flag to apply image enhancement. Defaults to True.

        Returns:
            str: The URL of the generated image if the request is successful.

        Raises:
            ValueError: If the specified image_format is not supported.
            Exception: If the image generation continuously fails (currently infinite retry).
        """
        # Validate that the requested image format exists in the FORMATS dictionary
        if image_format not in ImageGeneration.FORMATS:
            raise ValueError("Invalid image format.")

        # Retrieve width and height based on the requested image format
        width, height = ImageGeneration.FORMATS[image_format]

        # Initialize tools and retrieve the image generation service endpoint
        _, image_tool, _ = initialize_tools()

        # Encode the image instruction to safely include it in the URL path
        generate_image_instruct = quote(generate_image_instruction)

        # Construct the full URL for the image generation request by appending the encoded instruction
        url = f"{image_tool}{generate_image_instruct}"  # Full endpoint URL for image generation

        # Prepare query parameters including image dimensions, model, and flags converted to string "true"/"false"
        params = {
            "width": width,  # Image width parameter
            "height": height,  # Image height parameter
            "model": model,  # Model name for image generation
            "nologo": "true" if nologo else "false",  # Flag to exclude logo watermark as string
            "private": "true" if private else "false",  # Flag to mark image as private as string
            "enhance": "true" if enhance else "false"  # Flag to apply enhancement as string
        }

        # Include seed parameter if provided to control randomness in image generation
        if seed is not None:
            params["seed"] = seed  # Add seed to parameters to reproduce images

        # Prepare HTTP headers with a generated random IP to simulate different client origins
        headers = {
            "X-Forwarded-For": generate_ip()  # Random IP address for request header to simulate client origin
        }

        # Create an asynchronous HTTP client with no timeout limit to perform the request
        async with httpx.AsyncClient(timeout=None) as client:
            # Keep retrying the request until a successful response with status 200 is received
            while True:
                # Send a GET request to the image generation service with URL, parameters, and headers
                resp = await client.get(url, params=params, headers=headers)

                # Check if the response status code indicates success
                if resp.status_code == 200:
                    # Return the URL of the generated image as a string
                    return str(resp.url)
                else:
                    # Wait briefly before retrying to avoid overwhelming the server
                    await asyncio.sleep(15)  # Pause 15 second before retrying