diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bcd7163c..e12dc5a1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log for SD.Next +## Update for 2025-12-12 + +- Google models support for both Dev and Vertex access methods + see [docs](https://vladmandic.github.io/sdnext-docs/Google-GenAI/) for details + ## Update for 2025-12-11 ### Highlights for 2025-12-11 diff --git a/modules/shared.py b/modules/shared.py index 4f834b320..a1c58706a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -164,6 +164,11 @@ options_templates.update(options_section(('sd', "Model Loading"), { options_templates.update(options_section(('model_options', "Model Options"), { "model_modular_sep": OptionInfo("

Modular Pipelines

", "", gr.HTML), "model_modular_enable": OptionInfo(False, "Enable modular pipelines (experimental)"), + "model_google_sep": OptionInfo("

Google GenAI

", "", gr.HTML), + "google_use_vertexai": OptionInfo(False, "Google cloud use VertexAI endpoints"), + "google_api_key": OptionInfo("", "Google cloud API key", gr.Textbox), + "google_project_id": OptionInfo("", "Google Cloud project ID", gr.Textbox), + "google_location_id": OptionInfo("", "Google Cloud location ID", gr.Textbox), "model_sd3_sep": OptionInfo("

Stable Diffusion 3.x

", "", gr.HTML), "model_sd3_disable_te5": OptionInfo(False, "Disable T5 text encoder"), "model_h1_sep": OptionInfo("

HiDream

", "", gr.HTML), diff --git a/modules/video_models/google_veo.py b/modules/video_models/google_veo.py index 92ee43a2e..6e7f25a37 100644 --- a/modules/video_models/google_veo.py +++ b/modules/video_models/google_veo.py @@ -69,17 +69,38 @@ class GoogleVeoVideoPipeline(): image=genai.types.Image(image_bytes=image_bytes.getvalue(), mime_type='image/jpeg'), ) + def get_args(self): + from modules.shared import opts + api_key = os.getenv("GOOGLE_API_KEY") or opts.google_api_key + vertex_credentials = os.getenv("GOOGLE_APPLICATION_CREDENTIALS") + if (api_key is None or len(api_key) == 0) and (vertex_credentials is None or len(vertex_credentials) == 0): + log.error(f'Cloud: model="{self.model}" API key not provided') + return None + use_vertexai = (os.getenv("GOOGLE_GENAI_USE_VERTEXAI") is not None) or opts.google_use_vertexai + project_id = os.getenv("GOOGLE_CLOUD_PROJECT") or opts.google_project_id + location_id = os.getenv("GOOGLE_CLOUD_LOCATION") or opts.google_location_id + args = { + 'api_key': api_key, + 'vertexai': use_vertexai, + 'project': project_id if len(project_id) > 0 else None, + 'location': location_id if len(location_id) > 0 else None, + } + args_copy = args.copy() + args_copy['api_key'] = '...' + args_copy['api_key'][-4:] # last 4 chars + args_copy['credentials'] = vertex_credentials + log.debug(f'Cloud: model="{self.model}" args={args_copy}') + return args + def __call__(self, prompt: list[str], width: int, height: int, image: Image.Image = None, num_frames: int = 4*24): from google import genai if isinstance(prompt, list) and len(prompt) > 0: prompt = prompt[0] if self.client is None: - api_key = os.getenv("GOOGLE_API_KEY", None) - if api_key is None: - log.error(f'Cloud: model="{self.model}" GOOGLE_API_KEY environment variable not set') + args = self.get_args() + if args is None: return None - self.client = genai.Client(api_key=api_key, vertexai=False) + self.client = genai.Client(**args) resolution, aspect_ratio = get_size_buckets(width, height) duration = num_frames // 24 diff --git a/pipelines/model_google.py b/pipelines/model_google.py index 89089f211..ea608575e 100644 --- a/pipelines/model_google.py +++ b/pipelines/model_google.py @@ -67,14 +67,35 @@ class GoogleNanoBananaPipeline(): ], ) + def get_args(self): + from modules.shared import opts + api_key = os.getenv("GOOGLE_API_KEY") or opts.google_api_key + vertex_credentials = os.getenv("GOOGLE_APPLICATION_CREDENTIALS") + if (api_key is None or len(api_key) == 0) and (vertex_credentials is None or len(vertex_credentials) == 0): + log.error(f'Cloud: model="{self.model}" API key not provided') + return None + use_vertexai = (os.getenv("GOOGLE_GENAI_USE_VERTEXAI") is not None) or opts.google_use_vertexai + project_id = os.getenv("GOOGLE_CLOUD_PROJECT") or opts.google_project_id + location_id = os.getenv("GOOGLE_CLOUD_LOCATION") or opts.google_location_id + args = { + 'api_key': api_key, + 'vertexai': use_vertexai, + 'project': project_id if len(project_id) > 0 else None, + 'location': location_id if len(location_id) > 0 else None, + } + args_copy = args.copy() + args_copy['api_key'] = '...' + args_copy['api_key'][-4:] # last 4 chars + args_copy['credentials'] = vertex_credentials + log.debug(f'Cloud: model="{self.model}" args={args_copy}') + return args + def __call__(self, prompt: list[str], width: int, height: int, image: Image.Image = None): from google import genai if self.client is None: - api_key = os.getenv("GOOGLE_API_KEY", None) - if api_key is None: - log.error(f'Cloud: model="{self.model}" GOOGLE_API_KEY environment variable not set') + args = self.get_args() + if args is None: return None - self.client = genai.Client(api_key=api_key, vertexai=False) + self.client = genai.Client(**args) image_size, aspect_ratio = get_size_buckets(width, height) if 'gemini-3' in self.model: @@ -85,7 +106,7 @@ class GoogleNanoBananaPipeline(): response_modalities=["IMAGE"], image_config=image_config ) - log.debug(f'Cloud: prompt="{prompt}" size={image_size} ar={aspect_ratio} image={image} model="{self.model}"') + log.debug(f'Cloud: model="{self.model}" prompt="{prompt}" size={image_size} ar={aspect_ratio} image={image}') # log.debug(f'Cloud: config={self.config}') try: diff --git a/wiki b/wiki index 12af554d2..e77ba0086 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 12af554d26d12ce84d43e35f81da89bdbeac4057 +Subproject commit e77ba0086cdcfd5ae07aa7c4f5a7bb5c2203c0fb