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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't to commit this file

Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,6 @@ compose*.yaml
# vscode
.vscode/

# Firebase credentials
credentials/
*.json
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 ImageGeneratorInput(BaseModel):
presentation_content: List[dict]
Empty file.
33 changes: 33 additions & 0 deletions app/tools/presentation_generator_updated/image_generator/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from app.api.error_utilities import LoaderError, ToolExecutorError
from typing import List
from app.services.schemas import SlideGeneratorInput, ImageGeneratorInput
# from app.tools.presentation_generator_updated.slide_generator.tools import SlideGenerator
from app.tools.presentation_generator_updated.image_generator.tools import ImagePromptGenerator, image_generation_handler
from app.services.logger import setup_logger
logger = setup_logger()


def executor(presentation_content, verbose=False):
try:
if not presentation_content:
logger.info("Missing required inputs.")
raise ValueError("Missing required inputs")

# Extract the slides list from the dictionary if needed
slides_list = (
presentation_content["slides"]
if isinstance(presentation_content, dict) and "slides" in presentation_content
else presentation_content
)

# Create ImageGeneratorInput with the correct format
image_generator_args = ImageGeneratorInput(presentation_content=slides_list)
output = image_generation_handler(image_generator_args) # Reurns a dictionary of image titles and correswponding image URLs
logger.info("Image generation completed successfully")

return output

except Exception as e:
error_message = f"Error in image generation: {str(e)}"
logger.error(error_message)

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Categorize the the slide title: {title} into one of the 7 groups given below:

1. STEM (Science, Technology, Engineering, Mathematics)
Examples:
- Science
- Technology
- Engineering
- Mathematics
2. Humanities and Social Sciences
Examples:
- Humanities
- Social Sciences
- Philosophy and Ethics
3. Arts and Design
Examples:
- Arts
- Architecture and Design
4. Business and Law
Examples:
- Business and Management
- Law
5. Health and Medicine
Examples:
- Medicine and Healthcare
6. Education and Communication
Examples:
- Education
- Communication and Media
7. Environmental and Sustainability Studies
Examples:
- Environmental Studies

Based on your categorization, select the corresponding theme from the table given below:
STEM (Science, Technology, Engineering, Mathematics) -> Theme: Futuristic Innovation and Discovery (depicting scientific experiments, technological advancements, coding, and engineering blueprints).
Humanities and Social Sciences -> Theme: Cultural Heritage and Human Connections (showing historical artifacts, diverse people, societal development, and philosophical discourse).
Arts and Design -> Theme: Creative Expression and Artistic Vision (featuring colorful palettes, design tools, and abstract forms that showcase the creative process).
Business and Law -> Theme: Corporate Strategy and Legal Framework (representing growth graphs, business meetings, legal scales, and decision-making processes).
Health and Medicine -> Theme: Healthcare Innovation and Human Well-being (depicting medical technology, healthcare professionals, and anatomical illustrations).
Education and Communication -> Theme: Interactive Learning and Knowledge Sharing (featuring classrooms, digital learning platforms, books, and communication symbols).
Environmental and Sustainability Studies -> Theme: Nature Preservation and Green Future (depicting renewable energy, forests, oceans, and sustainable practices).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Analyze the given title: {title} and content: {content} and determine a suitable visual to support the contents of the slide.
Write a precise prompt indicating the step by step process to generate an image for the determined visual, while aligning with the theme: {theme}.
Strictly ensure that the text does not include any special formatting symbols like **, *, _, or ~
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pytest
import os
from dotenv import load_dotenv

# Load environment variables for testing
load_dotenv()

@pytest.fixture(autouse=True)
def mock_env_vars():
"""Mock environment variables needed for testing"""
os.environ['GOOGLE_CLOUD_PROJECT'] = 'test-project'
os.environ['GCS_BUCKET_NAME'] = 'test-bucket'
os.environ['TOGETHER_API_KEY'] = 'test-key'

@pytest.fixture
def mock_gcs_client():
"""Mock Google Cloud Storage client"""
class MockGCSClient:
def bucket(self, name):
return MockBucket()

class MockBucket:
def blob(self, name):
return MockBlob()

class MockBlob:
def upload_from_string(self, data, content_type):
pass

def public_url(self):
return "https://storage.googleapis.com/test-bucket/test-image.jpg"

return MockGCSClient()
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import pytest
from unittest.mock import patch, MagicMock
from app.tools.presentation_generator_updated.image_generator.core import executor
from app.tools.presentation_generator_updated.image_generator.tools import ImagePromptGenerator, image_generation_handler
from app.api.error_utilities import ToolExecutorError

@pytest.fixture
def mock_presentation_content():
return {
"slides": [
{
"title": "Introduction to AI",
"template": "titleAndBody",
"content": ["What is Artificial Intelligence?", "History of AI"]
},
{
"title": "Machine Learning",
"template": "twoColumn",
"content": ["Types of ML", "Applications"]
}
]
}

@pytest.fixture
def mock_image_generation_response():
return {
"status": "success",
"data": {
"Introduction to AI": "https://storage.googleapis.com/bucket/image1.jpg",
"Machine Learning": "https://storage.googleapis.com/bucket/image2.jpg"
}
}

def test_executor_valid_input(mock_presentation_content, mock_image_generation_response):
"""Test executor with valid presentation content"""
with patch('app.tools.presentation_generator_updated.image_generator.core.image_generation_handler') as mock_handler:
mock_handler.return_value = mock_image_generation_response

result = executor(mock_presentation_content)

assert isinstance(result, dict)
assert result["status"] == "success"
assert "data" in result
assert len(result["data"]) == 2
mock_handler.assert_called_once()

def test_executor_empty_input():
"""Test executor with empty input"""
with pytest.raises(ToolExecutorError) as exc_info:
executor({})
assert "Missing required inputs" in str(exc_info.value)

def test_executor_string_input():
"""Test executor with string input instead of dict"""
with pytest.raises(ToolExecutorError) as exc_info:
executor("Invalid input")
assert "Invalid presentation content format" in str(exc_info.value)

def test_executor_no_slides():
"""Test executor with dict but no slides"""
with pytest.raises(ToolExecutorError) as exc_info:
executor({"other_key": "value"})
assert "No slides content found" in str(exc_info.value)

def test_executor_invalid_handler_output():
"""Test executor when handler returns invalid output"""
mock_content = {
"slides": [{"title": "Test", "content": ["content"]}]
}

with patch('app.tools.presentation_generator_updated.image_generator.core.image_generation_handler') as mock_handler:
mock_handler.return_value = "invalid output"

with pytest.raises(ToolExecutorError) as exc_info:
executor(mock_content)
assert "Invalid output from image generation handler" in str(exc_info.value)

def test_executor_handler_error():
"""Test executor when handler raises an exception"""
mock_content = {
"slides": [{"title": "Test", "content": ["content"]}]
}

with patch('app.tools.presentation_generator_updated.image_generator.core.image_generation_handler') as mock_handler:
mock_handler.side_effect = Exception("Handler error")

with pytest.raises(ToolExecutorError) as exc_info:
executor(mock_content)
assert "Error in image generation: Handler error" in str(exc_info.value)

@pytest.mark.integration
def test_executor_integration(mock_presentation_content):
"""Integration test for executor with actual image generation"""
try:
result = executor(mock_presentation_content)
assert isinstance(result, dict)
assert "status" in result
assert "data" in result
assert all(isinstance(url, str) for url in result["data"].values())
except Exception as e:
pytest.skip(f"Integration test failed due to external dependencies: {str(e)}")

def test_executor_with_none_input():
"""Test executor with None input"""
with pytest.raises(ToolExecutorError) as exc_info:
executor(None)
assert "Missing required inputs" in str(exc_info.value)

def test_executor_with_empty_slides_list():
"""Test executor with empty slides list"""
with pytest.raises(ToolExecutorError) as exc_info:
executor({"slides": []})
assert "No slides content found" in str(exc_info.value)

def test_executor_with_malformed_slides():
"""Test executor with malformed slides structure"""
malformed_content = {
"slides": [
{"wrong_key": "value"} # Missing required title and content
]
}

with pytest.raises(ToolExecutorError) as exc_info:
executor(malformed_content)
assert "Invalid slide structure: missing required 'title' field" in str(exc_info.value)
Loading