| """Image generation client via the Hugging Face Inference API (text_to_image).""" |
| from typing import Optional |
| from PIL import Image |
|
|
| try: |
| from huggingface_hub import InferenceClient |
| except ImportError: |
| InferenceClient = None |
|
|
| import config |
|
|
|
|
| class ImageGenerationClient: |
| """Generate artifact images for alternate timelines via the HF Inference API.""" |
|
|
| def __init__(self, hf_token: Optional[str] = None): |
| self.hf_token = hf_token or config.HF_TOKEN |
| self.model = config.MODEL_NAME_IMAGE |
| self.fallback_model = config.FALLBACK_IMAGE_MODEL |
| self.client = None |
| self.available = False |
|
|
| if not config.ENABLE_IMAGE_GEN: |
| return |
| if not InferenceClient: |
| print("[warn]huggingface_hub not installed; image generation disabled") |
| return |
| if not self.hf_token: |
| print("[warn]HF_TOKEN not set; image generation disabled") |
| return |
|
|
| try: |
| self.client = InferenceClient(token=self.hf_token, timeout=config.TIMEOUT_IMAGE) |
| self.available = True |
| except Exception as e: |
| print(f"[warn]Image client initialization failed: {e}") |
| self.available = False |
|
|
| def generate(self, prompt: str) -> Optional[Image.Image]: |
| """Generate an image from a prompt, with a fallback model.""" |
| if not self.available: |
| return None |
|
|
| try: |
| return self.client.text_to_image(prompt, model=self.model) |
| except Exception as e: |
| print(f"[warn]Primary image generation failed ({self.model}): {e}") |
|
|
| try: |
| return self.client.text_to_image(prompt, model=self.fallback_model) |
| except Exception as e: |
| print(f"[warn]Fallback image generation failed ({self.fallback_model}): {e}") |
|
|
| return None |
|
|
| def generate_artifact_newspaper(self, headline: str, subheading: str) -> Optional[Image.Image]: |
| """Generate a vintage newspaper artifact.""" |
| prompt = ( |
| f'Vintage newspaper front page with headline "{headline}" and subheading ' |
| f'"{subheading}". Aged paper, period typography, realistic newspaper layout.' |
| ) |
| return self.generate(prompt) |
|
|
| def generate_artifact_product(self, product: str, context: str) -> Optional[Image.Image]: |
| """Generate a product advertisement or packaging.""" |
| prompt = ( |
| f'Vintage product advertisement for "{product}" in a world where {context}. ' |
| f"Period-appropriate packaging design, realistic product mockup, authentic styling." |
| ) |
| return self.generate(prompt) |
|
|
| def generate_artifact_document(self, doc_type: str, context: str) -> Optional[Image.Image]: |
| """Generate a historical document artifact.""" |
| prompt = ( |
| f"Historical {doc_type} from an alternate timeline where {context}. " |
| f"Aged paper, period authentic, realistic museum quality." |
| ) |
| return self.generate(prompt) |
|
|
|
|
| |
| _image_client = None |
|
|
|
|
| def get_image_client() -> ImageGenerationClient: |
| """Get or create the global image generation client.""" |
| global _image_client |
| if _image_client is None: |
| _image_client = ImageGenerationClient() |
| return _image_client |
|
|
|
|
| def generate_artifact(artifact_type: str, **kwargs) -> Optional[Image.Image]: |
| """Generate an artifact image by type.""" |
| client = get_image_client() |
|
|
| if artifact_type == "newspaper": |
| return client.generate_artifact_newspaper( |
| kwargs.get("headline", "Alternate History"), |
| kwargs.get("subheading", "A world that never was"), |
| ) |
| elif artifact_type == "product": |
| return client.generate_artifact_product( |
| kwargs.get("product", "Product"), |
| kwargs.get("context", "divergence occurred"), |
| ) |
| elif artifact_type == "document": |
| return client.generate_artifact_document( |
| kwargs.get("doc_type", "document"), |
| kwargs.get("context", "divergence occurred"), |
| ) |
|
|
| return None |
|
|