Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| import os | |
| from typing import List, Optional, Tuple | |
| from .models import Storyboard | |
| from .placeholders import synthesize_character_card | |
| DEFAULT_IMAGE_MODEL = os.environ.get("CINEGEN_CHARACTER_MODEL", "gemini-2.5-flash-image") | |
| def _load_google_client(api_key: Optional[str]): | |
| if not api_key: | |
| return None | |
| try: | |
| from google import genai | |
| return genai.Client(api_key=api_key) | |
| except Exception: # pragma: no cover - optional dependency | |
| return None | |
| class CharacterDesigner: | |
| def __init__(self, api_key: Optional[str] = None): | |
| self.api_key = api_key or os.environ.get("GOOGLE_API_KEY") | |
| self.client = _load_google_client(self.api_key) | |
| def design(self, storyboard: Storyboard) -> Tuple[List[Tuple[str, str]], Storyboard]: | |
| gallery: List[Tuple[str, str]] = [] | |
| for character in storyboard.characters: | |
| gallery.append(self._refresh_reference(character, storyboard.style)) | |
| return gallery, storyboard | |
| def redesign_character(self, storyboard: Storyboard, character_id: str) -> Tuple[Tuple[str, str], Storyboard]: | |
| target = next((char for char in storyboard.characters if char.identifier == character_id), None) | |
| if not target: | |
| raise ValueError(f"Character {character_id} not found.") | |
| card = self._refresh_reference(target, storyboard.style) | |
| return card, storyboard | |
| def _refresh_reference(self, character, style: str) -> Tuple[str, str]: | |
| image_path = None | |
| if self.client: | |
| image_path = self._try_generate(character, style) | |
| if not image_path: | |
| image_path = synthesize_character_card(character, style) | |
| character.reference_image = image_path | |
| caption = f"{character.name} — {character.role}" | |
| return image_path, caption | |
| def _try_generate(self, character, style: str) -> Optional[str]: # pragma: no cover | |
| prompt = ( | |
| f"Create a portrait for {character.name}, a {character.role} in a {style} short film. " | |
| f"Traits: {', '.join(character.traits)}. Description: {character.description}." | |
| ) | |
| try: | |
| response = self.client.models.generate_content( | |
| model=DEFAULT_IMAGE_MODEL, | |
| contents=[prompt], | |
| ) | |
| for part in response.parts: | |
| if getattr(part, "inline_data", None): | |
| image = part.as_image() | |
| tmp_dir = os.path.join("/tmp", "cinegen-characters") | |
| os.makedirs(tmp_dir, exist_ok=True) | |
| path = os.path.join(tmp_dir, f"{character.identifier.lower()}.png") | |
| image.save(path) | |
| return path | |
| except Exception: | |
| return None | |
| return None | |