File size: 4,107 Bytes
f8c1b4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""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)


# Global client instance
_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