File size: 6,327 Bytes
dd96071 33bd9e1 dd96071 33bd9e1 c9d4051 dd96071 7dd4b5c 11695a6 7dd4b5c 11695a6 dd96071 c9d4051 039ac0d c9d4051 dd96071 039ac0d c9d4051 039ac0d c9d4051 33bd9e1 c9d4051 33bd9e1 c9d4051 039ac0d c9d4051 dd96071 c9d4051 dd96071 039ac0d c9d4051 dd96071 039ac0d dd96071 c9d4051 dd96071 039ac0d dd96071 039ac0d dd96071 039ac0d dd96071 c9d4051 dd96071 c9d4051 dd96071 c9d4051 dd96071 039ac0d |
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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
import os
import json
import gradio as gr
import vertexai
from vertexai.preview.vision_models import ImageGenerationModel
from huggingface_hub import login
from google.oauth2 import service_account # Added for secure in-memory auth
# --- 1. Configuration and Authentication ---
# Load configuration from Hugging Face Secrets instead of hardcoding.
GCP_PROJECT_ID = os.environ.get("GCP_PROJECT_ID")
GCP_LOCATION = os.environ.get("GCP_LOCATION")
# --- Authentication and Sanity Checks Block ---
# Part A: Hugging Face Hub Authentication
hf_token = os.environ.get("IMAGEN_TOKEN")
if hf_token:
print("Hugging Face token found. Logging in.")
login(token=hf_token)
else:
print("WARNING: Hugging Face token ('IMAGEN_TOKEN') not found. Hub-related features may be disabled.")
# Part B: Google Cloud Credentials and Initialization
creds_json_str = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS_JSON")
# This global variable will hold a generic error message for the UI if initialization fails.
generic_init_error_message = "FATAL: The image generation service is not configured correctly. Please contact the administrator."
# Check if all necessary secrets are loaded
if not all([GCP_PROJECT_ID, GCP_LOCATION, creds_json_str]):
missing_secrets = []
if not GCP_PROJECT_ID: missing_secrets.append("GCP_PROJECT_ID")
if not GCP_LOCATION: missing_secrets.append("GCP_LOCATION")
if not creds_json_str: missing_secrets.append("GOOGLE_APPLICATION_CREDENTIALS_JSON")
# Log the detailed error for the administrator
error_message_for_logs = f"FATAL: The following required secrets are missing: {', '.join(missing_secrets)}. Please set them in the Space settings."
print(error_message_for_logs)
# Set the global error message to the generic one for the UI
error_message = generic_init_error_message
INITIALIZATION_SUCCESS = False
else:
# This block runs only if all secrets are present.
print("All required GCP secrets (Project, Location, Credentials) are loaded.")
try:
# <<< START: SECURITY FIX >>>
# Securely initialize the Vertex AI client by passing credentials in-memory.
# This avoids writing sensitive credential files to the container's filesystem.
# 1. Parse the JSON string from the environment variable into a Python dict.
creds_info = json.loads(creds_json_str)
# 2. Create a credentials object from the dictionary.
credentials = service_account.Credentials.from_service_account_info(creds_info)
# 3. Initialize Vertex AI with the in-memory credentials object.
vertexai.init(project=GCP_PROJECT_ID, location=GCP_LOCATION, credentials=credentials)
# <<< END: SECURITY FIX >>>
generation_model = ImageGenerationModel.from_pretrained("imagen-4.0-generate-preview-06-06")
print("Vertex AI and Imagen Model initialized successfully.")
INITIALIZATION_SUCCESS = True
except Exception as e:
# Log the detailed, sensitive error for the administrator ONLY.
print(f"ERROR: Failed to initialize Vertex AI or the model. Exception: {e}")
# Set the generic error message for the UI. DO NOT expose the raw exception 'e'.
error_message = generic_init_error_message
INITIALIZATION_SUCCESS = False
# --- 2. The Core Image Generation Function ---
def generate_image(prompt: str, negative_prompt: str, seed: int):
"""Generates an image using the Vertex AI Imagen model."""
if not INITIALIZATION_SUCCESS:
# Provide the clear, generic error message in the UI if initialization failed.
raise gr.Error(error_message)
# <<< START: PRIVACY UPDATE >>>
# Do not log the user's prompt content.
print("Received new image generation request.")
# <<< END: PRIVACY UPDATE >>>
try:
images = generation_model.generate_images(
prompt=prompt, number_of_images=1, aspect_ratio="1:1",
negative_prompt=negative_prompt, add_watermark=False,
safety_filter_level="block_few", person_generation="allow_adult",
seed=seed
)
print("Image generation successful for the request.")
return images[0]._pil_image
except Exception as e:
# <<< START: SECURITY UPDATE >>>
# Log the detailed error for the administrator's review.
print(f"An error occurred during image generation: {e}")
# Raise a generic, user-friendly error in the UI instead of the raw exception.
raise gr.Error("An unexpected error occurred while generating the image. Please try again or contact support if the issue persists.")
# <<< END: SECURITY UPDATE >>>
# --- 3. Gradio User Interface Definition ---
with gr.Blocks(theme=gr.themes.Soft(), css=".gradio-container {max-width: 960px !important}") as demo:
gr.Markdown("# 🎨 Vertex AI Imagen 4.0 Image Generator")
gr.Markdown("Generate high-quality images with Google's latest Imagen 4.0 model.")
with gr.Row():
with gr.Column(scale=2):
prompt_input = gr.Textbox(label="Prompt", placeholder="A photorealistic image of a futuristic city...", lines=3)
negative_prompt_input = gr.Textbox(label="Negative Prompt", placeholder="text, watermark, blurry...", lines=2)
seed_input = gr.Slider(label="Seed", minimum=0, maximum=99999, step=1, randomize=True, info="Controls randomness.")
submit_button = gr.Button("Generate Image", variant="primary")
with gr.Column(scale=1):
image_output = gr.Image(label="Generated Image", type="pil", interactive=False)
gr.Examples(
[
["An epic oil painting of a lone astronaut discovering a lush, alien jungle.", "blurry"],
["A cute, fluffy corgi wearing a tiny chef's hat, in a kitchen, cinematic lighting.", "text"],
],
inputs=[prompt_input, negative_prompt_input]
)
submit_button.click(
fn=generate_image,
inputs=[prompt_input, negative_prompt_input, seed_input],
outputs=image_output
)
# Launch the Gradio app
# <<< START: SECURITY UPDATE >>>
# Disabled debug mode for production to prevent leaking sensitive information through stack traces.
demo.launch(debug=False)
# <<< END: SECURITY UPDATE >>> |