Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,6 @@ compose*.yaml
# vscode
.vscode/

# Google Cloud Service Account credentials
marvel-ai-backend-credentials.json

3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ COPY requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir -r /code/requirements.txt

# Copy credentials file
COPY marvel-ai-backend-credentials.json /code/marvel-ai-backend-credentials.json

COPY ./app /code/app

# Local development key set
Expand Down
5 changes: 4 additions & 1 deletion app/services/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,7 @@ class SlideGeneratorInput(BaseModel):
slides_titles: List[str]
instructional_level: str
topic: str
lang: Optional[str] = "en"
lang: Optional[str] = "en"

class SlideImageGeneratorInput(BaseModel):
slides: List[dict]
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ def compile_context(self):
)
chain = prompt | self.model | self.parser

logger.info(f"Chain compilation complete")
logger.info("Chain compilation complete")

return chain

def generate_slides(self):
logger.info(f"Creating the Outlines for the Presentation")
logger.info("Creating the Outlines for the Presentation")
chain = self.compile_context()

input_parameters = {
Expand All @@ -126,7 +126,7 @@ def generate_slides(self):
logger.info(f"Response validation: {validation_results}")

if not validation_results["valid"]:
logger.warning(f"Generated content may not fully match the requested topic")
logger.warning("Generated content may not fully match the requested topic")
return response

class Slide(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import List, Dict
from app.services.logger import setup_logger
from app.tools.presentation_generator_updated.slide_image_generator.tools import SlideImageGenerator

logger = setup_logger(__name__)

def executor(slides: List[dict], verbose: bool = False) -> dict:
"""
Execute the slide image generation process.

Args:
slides (List[dict]): List of slide dictionaries from the slide generator
verbose (bool): Enable verbose logging

Returns:
dict: Dictionary containing processed slides with generated images
"""
try:
if verbose:
logger.info("Starting slide image generation process")
generator = SlideImageGenerator(slides=slides, verbose=verbose)

if verbose:
logger.info("Generating slides images")
result = generator.generate_slides()

if verbose:
logger.info("Slides images generated successfully")
return result

except Exception as e:
error_message = f"Error in slide image generation: {str(e)}"
logger.error(error_message)
raise ValueError(error_message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"inputs": [
{
"label": "Slides",
"name": "slides",
"type": "list",
"item_type": "object",
"properties": {
"title": {
"type": "string"
},
"template": {
"type": "string"
},
"content": {
"type": "any"
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# test_service_account.py
import os
import io
from pathlib import Path
from PIL import Image
from google.cloud import storage
import vertexai
from vertexai.preview.vision_models import ImageGenerationModel
from dotenv import load_dotenv

# Find the project root directory and load environment variables
current_file = Path(__file__)
project_root = current_file.parent
# Navigate up until we find the project root (where the app directory is)
while not (project_root / 'app').exists() and project_root != project_root.parent:
project_root = project_root.parent

# Look for .env in common locations
env_paths = [
project_root / 'app' / '.env', # app/.env
project_root / '.env', # .env in project root
]

# Try to load from the first .env file found
env_loaded = False
for env_path in env_paths:
if env_path.exists():
print(f"Loading environment from: {env_path}")
load_dotenv(env_path)
env_loaded = True
break

if not env_loaded:
print("Warning: No .env file found. Using environment variables as is.")

def test_service_account():
print("\n=== Testing Google Cloud Service Account ===\n")

# 1. Find and verify credentials
print("Step 1: Finding credentials file")
creds_path = os.getenv('GOOGLE_APPLICATION_CREDENTIALS')

# Make relative path absolute if needed
if creds_path and not os.path.isabs(creds_path):
creds_path = os.path.join(project_root, creds_path)

# Use default location if not specified
if not creds_path:
creds_path = project_root / 'marvel-ai-backend-credentials.json' # as per your credentials file name

# Check if file exists
if os.path.exists(creds_path):
print(f"✅ Credentials file found at: {creds_path}")
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = str(creds_path)
else:
print(f"❌ Credentials file not found at: {creds_path}")
return

# 2. Generate a test image with Vertex AI
print("\nStep 2: Generating test image with Vertex AI")
project_id = os.getenv('PROJECT_ID')
if not project_id:
print("❌ PROJECT_ID not set in environment")
return

print(f"Initializing Vertex AI with project: {project_id}")
vertexai.init(project=project_id)

# Generate a simple test image
print("Generating image...")
image_model = ImageGenerationModel.from_pretrained("imagen-3.0-fast-generate-001")
prompt = "A simple blue circle on a white background, abstract, no text"

try:
response = image_model.generate_images(
prompt=prompt,
number_of_images=1,
)

if response and hasattr(response[0], '_image_bytes'):
image_bytes = response[0]._image_bytes
print(f"✅ Successfully generated image ({len(image_bytes)} bytes)")

# Save image locally for verification
with open("test_image.png", "wb") as f:
f.write(image_bytes)
print("✅ Saved test image to test_image.png")
else:
print("❌ Failed to generate image")
return
except Exception as e:
print(f"❌ Image generation error: {str(e)}")
return

# 3. Store the image in Cloud Storage
print("\nStep 3: Storing image in Cloud Storage")
bucket_name = os.getenv('SLIDE_IMAGES_BUCKET_NAME', 'presentation-slide-images')
print(f"Using bucket: {bucket_name}")

try:
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)

# Upload the generated image
blob = bucket.blob("test_image.png")
blob.upload_from_string(image_bytes, content_type="image/png")
print(f"✅ Successfully uploaded image to: gs://{bucket_name}/test_image.png")

# Make it publicly accessible and get URL
blob.make_public()
print(f"✅ Public URL: {blob.public_url}")

# Clean up (optional)
# blob.delete()
# print("✅ Deleted test image from bucket")

except Exception as e:
print(f"❌ Storage error: {str(e)}")

if __name__ == "__main__":
test_service_account()
Loading