返回 ViMax
image_generator_nanobanana_yunwu_api.py
根目录 / tools / image_generator_nanobanana_yunwu_api.py
1 # https://ai.google.dev/gemini-api/docs/image-generation?hl=zh-cn
2
3 import logging
4 from PIL import Image
5 from typing import List, Optional
6 from google import genai
7 from google.genai import types
8 from tenacity import retry, stop_after_attempt, wait_exponential
9 from interfaces.image_output import ImageOutput
10 from tools.image_orientation import ensure_not_portrait, landscape_guard_requested
11 from tools.image_response import image_from_response_part
12 from utils.retry import after_func
13
14
15 class ImageGeneratorNanobananaYunwuAPI:
16 def __init__(
17 self,
18 api_key: str,
19 model: str = "gemini-2.5-flash-image-preview",
20 base_url: str = "https://yunwu.ai",
21 ):
22 self.client = genai.Client(
23 api_key=api_key,
24 http_options=types.HttpOptions(
25 base_url=base_url.rstrip("/"),
26 api_version="v1beta",
27 ),
28 )
29 self.model = model
30
31
32 @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10), after=after_func, reraise=True)
33 async def generate_single_image(
34 self,
35 prompt: str,
36 reference_image_paths: List[str] = [],
37 aspect_ratio: Optional[str] = "16:9",
38 **kwargs,
39 ) -> ImageOutput:
40 """
41 aspect_ratio: The aspect ratio of the image.
42 """
43
44 logging.info(f"Calling {self.model} to generate image...")
45
46 reference_images = [Image.open(path) for path in reference_image_paths]
47
48 response = await self.client.aio.models.generate_content(
49 model=self.model,
50 contents=reference_images + [prompt],
51 config=types.GenerateContentConfig(
52 response_modalities=["TEXT", "IMAGE"],
53 image_config=types.ImageConfig(
54 aspect_ratio=aspect_ratio,
55 ),
56 ),
57 )
58
59 image = None
60 text = ""
61 for part in response.candidates[0].content.parts:
62 if part.text is not None:
63 text += part.text
64 elif part.inline_data is not None:
65 image = image_from_response_part(part)
66
67 if image is None:
68 logging.error(f"No image generated. The response text is: {text}")
69 raise ValueError(f"Error occurred while generating image.")
70
71 if landscape_guard_requested(
72 size=kwargs.get("size"),
73 aspect_ratio=aspect_ratio,
74 enforce_landscape=kwargs.get("enforce_landscape", True),
75 allow_portrait=kwargs.get("allow_portrait", False),
76 ):
77 ensure_not_portrait(image)
78
79 return ImageOutput(fmt="pil", ext="png", data=image)
80
80 lines PYTHON