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
11 changes: 11 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@
Comic Generator Flask Application
Main entry point - registers all Blueprints
"""
import logging
from flask import Flask
from flask_cors import CORS

# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler() # Output to console
]
)


# Configure Flask with explicit static folder
app = Flask(__name__, static_folder='static', static_url_path='/static')
CORS(app) # Enable CORS for frontend requests
Expand Down
2 changes: 1 addition & 1 deletion backend/comic_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def generate_social_media_image_core(
if not api_key:
raise ValueError("Google API key is required. Please provide google_api_key parameter or set GOOGLE_API_KEY environment variable.")

client = genai.Client(api_key=api_key, vertexai=False)
client = genai.Client(api_key=api_key, vertexai=False, http_options={'timeout':120000})
MODEL_ID = "gemini-3-pro-image-preview"

logger.info(f"Generating social media image for: {prompt}")
Expand Down
8 changes: 5 additions & 3 deletions backend/controllers/image_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,19 @@ def generate_comic_cover_endpoint():
return jsonify({"error": "Google API key is required"}), 400

comic_style = data.get('comic_style', 'doraemon')
language = data.get('language', 'en')
reference_imgs = data.get('reference_imgs')

print(f"[Cover Generation] Reference images count: {len(reference_imgs) if reference_imgs else 0}")
if reference_imgs:
print(f"[Cover Generation] First reference: {reference_imgs[0] if len(reference_imgs) > 0 else 'None'}")

# Generate cover using service
image_url, prompt = ImageService.generate_comic_cover(
comic_style=comic_style,
google_api_key=google_api_key,
reference_imgs=reference_imgs
reference_imgs=reference_imgs,
language=language
)

if not image_url:
Expand Down
26 changes: 20 additions & 6 deletions backend/services/image_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,23 @@ def generate_comic_image(
def generate_comic_cover(
comic_style: str = 'doraemon',
google_api_key: str = None,
reference_imgs: List[Union[str, Dict]] = None
reference_imgs: List[Union[str, Dict]] = None,
language: str = 'en'
) -> tuple[Optional[str], str]:
"""
Generate comic cover image

Args:
comic_style: Style of the comic
google_api_key: Google API key
reference_imgs: List of reference image URLs

language: Language for cover generation (en, zh, ja)

Returns:
Tuple of (image_url, prompt)
"""
# Create cover prompt
prompt = ImageService._create_cover_prompt(comic_style)
prompt = ImageService._create_cover_prompt(comic_style, language)

# Prepare reference images list (extract URLs from objects if needed)
processed_refs = []
Expand Down Expand Up @@ -168,8 +170,16 @@ def _convert_page_to_prompt(page_data: Dict[str, Any], comic_style: str = 'dorae
return final_prompt

@staticmethod
def _create_cover_prompt(comic_style: str) -> str:
def _create_cover_prompt(comic_style: str, language: str = 'en') -> str:
"""Create prompt for comic cover"""
# Language-specific text requirement
language_requirements = {
'zh': '生成的图片务必使用中文',
'en': 'Generated images must use English',
'ja': '生成された画像は必ず日本語を使用してください'
}
language_requirement = language_requirements.get(language, language_requirements['en'])

prompt_template = """Create a high-quality comic book cover in the style of {comic_style}.

# Requirements:
Expand All @@ -181,7 +191,11 @@ def _create_cover_prompt(comic_style: str) -> str:
- Clear and sharp text for the title, do not repeat all the titles in reference images.
- Vibrant colors and "Cover Art" aesthetic.
- Only present one row one panel in the cover.
- {language_requirement}
"""
final_prompt = prompt_template.format(comic_style=comic_style)
final_prompt = prompt_template.format(
comic_style=comic_style,
language_requirement=language_requirement
)
print(f"Cover Prompt: {final_prompt}")
return final_prompt
14 changes: 11 additions & 3 deletions frontend/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1428,10 +1428,18 @@ class UIController {
// Save current session state
this.saveCurrentSessionState();

// Create new session
// Get current options to reuse in new session
const currentOptions = {
style: this.comicStyleSelect.value,
language: this.comicLanguageSelect.value,
pageCount: parseInt(this.pageCountInput.value),
prompt: this.promptInput.value
};

// Create new session with current options
const sessionCount = this.sessionManager.getAllSessions().length + 1;
const defaultName = 'session ' + sessionCount;
const session = this.sessionManager.createSession(defaultName);
const session = this.sessionManager.createSession(defaultName, currentOptions);

// Switch to new session
this.sessionManager.switchSession(session.id);
Expand All @@ -1458,7 +1466,7 @@ class UIController {
// Update UI
this.updateSessionSelector();

// Load default state for new session (language, style)
// Load state for new session (will use the options we passed)
this.loadSessionState();
}

Expand Down
10 changes: 5 additions & 5 deletions frontend/js/sessionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SessionManager {
* @param {string} name - Session name
* @returns {Object} Created session
*/
createSession(name) {
createSession(name, options = {}) {
const sessionId = this.generateSessionId();
const now = new Date().toISOString();

Expand All @@ -48,10 +48,10 @@ class SessionManager {
comicData: null,
generatedImages: {},
currentPageIndex: 0,
style: 'doraemon', // Default style
language: (window.i18n && typeof window.i18n.getLanguage === 'function') ? window.i18n.getLanguage() : 'en',
pageCount: 3,
prompt: '',
style: options.style || 'doraemon', // Use provided style or default
language: options.language || ((window.i18n && typeof window.i18n.getLanguage === 'function') ? window.i18n.getLanguage() : 'en'),
pageCount: options.pageCount || 3,
prompt: options.prompt || '',
createdAt: now,
updatedAt: now
};
Expand Down