Spaces:
Running
Running
Create image_services.py
Browse files- core/image_services.py +132 -0
core/image_services.py
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# storyverse_weaver/core/image_services.py
|
2 |
+
import os
|
3 |
+
import requests # For generic API calls
|
4 |
+
import base64
|
5 |
+
from io import BytesIO
|
6 |
+
from PIL import Image
|
7 |
+
# from dotenv import load_dotenv
|
8 |
+
# load_dotenv()
|
9 |
+
|
10 |
+
# --- API Key Configuration (Use specific names for StoryVerse) ---
|
11 |
+
STABILITY_API_KEY = os.getenv("STORYVERSE_STABILITY_API_KEY")
|
12 |
+
OPENAI_API_KEY = os.getenv("STORYVERSE_OPENAI_API_KEY") # For DALL-E
|
13 |
+
# HUGGINGFACE_TOKEN also used by llm_services, can be reused if using HF image models
|
14 |
+
|
15 |
+
STABILITY_API_CONFIGURED = bool(STABILITY_API_KEY and STABILITY_API_KEY.strip())
|
16 |
+
OPENAI_DALLE_CONFIGURED = bool(OPENAI_API_KEY and OPENAI_API_KEY.strip())
|
17 |
+
# HF_IMAGE_CONFIGURED = bool(HF_TOKEN and HF_TOKEN.strip()) # Assuming HF_TOKEN is also for image models
|
18 |
+
|
19 |
+
class ImageGenResponse:
|
20 |
+
def __init__(self, image: Image.Image = None, image_url: str = None, error: str = None, success: bool = True, provider: str = "unknown"):
|
21 |
+
self.image = image # PIL Image object
|
22 |
+
self.image_url = image_url # If API returns a URL
|
23 |
+
self.error = error
|
24 |
+
self.success = success
|
25 |
+
self.provider = provider
|
26 |
+
|
27 |
+
def initialize_image_llms(): # Simple function to print status
|
28 |
+
print("INFO: image_services.py - Initializing Image Generation services...")
|
29 |
+
if STABILITY_API_CONFIGURED: print("SUCCESS: image_services.py - Stability AI API Key detected.")
|
30 |
+
else: print("WARNING: image_services.py - STORYVERSE_STABILITY_API_KEY not found. Stability AI disabled.")
|
31 |
+
if OPENAI_DALLE_CONFIGURED: print("SUCCESS: image_services.py - OpenAI API Key detected (for DALL-E).")
|
32 |
+
else: print("WARNING: image_services.py - STORYVERSE_OPENAI_API_KEY not found. DALL-E disabled.")
|
33 |
+
# if HF_IMAGE_CONFIGURED: print("INFO: image_services.py - Hugging Face Token detected (can be used for HF image models).")
|
34 |
+
print("INFO: image_services.py - Image LLM Init complete.")
|
35 |
+
|
36 |
+
|
37 |
+
# --- Stability AI (Example) ---
|
38 |
+
def generate_image_stabilityai(prompt: str, style_preset: str = None, negative_prompt: str = None,
|
39 |
+
engine_id: str = "stable-diffusion-xl-1024-v1-0",
|
40 |
+
steps: int = 30, cfg_scale: float = 7.0,
|
41 |
+
width: int = 1024, height: int = 1024) -> ImageGenResponse:
|
42 |
+
if not STABILITY_API_CONFIGURED:
|
43 |
+
return ImageGenResponse(error="Stability AI API key not configured.", success=False, provider="StabilityAI")
|
44 |
+
|
45 |
+
api_host = os.getenv('API_HOST', 'https://api.stability.ai')
|
46 |
+
request_url = f"{api_host}/v1/generation/{engine_id}/text-to-image"
|
47 |
+
|
48 |
+
payload = {
|
49 |
+
"text_prompts": [{"text": prompt}],
|
50 |
+
"cfg_scale": cfg_scale,
|
51 |
+
"height": height,
|
52 |
+
"width": width,
|
53 |
+
"steps": steps,
|
54 |
+
"samples": 1,
|
55 |
+
}
|
56 |
+
if style_preset: payload["style_preset"] = style_preset
|
57 |
+
if negative_prompt: payload["text_prompts"].append({"text": negative_prompt, "weight": -1.0})
|
58 |
+
|
59 |
+
headers = {
|
60 |
+
"Accept": "application/json",
|
61 |
+
"Content-Type": "application/json",
|
62 |
+
"Authorization": f"Bearer {STABILITY_API_KEY}"
|
63 |
+
}
|
64 |
+
print(f"DEBUG: image_services.py - Calling Stability AI with prompt: {prompt[:50]}...")
|
65 |
+
try:
|
66 |
+
response = requests.post(request_url, headers=headers, json=payload, timeout=60) # Increased timeout
|
67 |
+
response.raise_for_status() # Will raise an HTTPError if the HTTP request returned an unsuccessful status code
|
68 |
+
|
69 |
+
artifacts = response.json().get("artifacts")
|
70 |
+
if not artifacts:
|
71 |
+
return ImageGenResponse(error="No image artifacts found in Stability AI response.", success=False, provider="StabilityAI", raw_response=response.text)
|
72 |
+
|
73 |
+
image_data = base64.b64decode(artifacts[0]["base64"])
|
74 |
+
image = Image.open(BytesIO(image_data))
|
75 |
+
print("DEBUG: image_services.py - Stability AI image generated successfully.")
|
76 |
+
return ImageGenResponse(image=image, provider="StabilityAI")
|
77 |
+
except requests.exceptions.RequestException as e:
|
78 |
+
error_msg = f"Stability AI API request failed: {type(e).__name__} - {str(e)}"
|
79 |
+
if hasattr(e, 'response') and e.response is not None: error_msg += f" - Response: {e.response.text[:200]}"
|
80 |
+
print(f"ERROR: image_services.py - {error_msg}")
|
81 |
+
return ImageGenResponse(error=error_msg, success=False, provider="StabilityAI", raw_response=e)
|
82 |
+
except Exception as e: # Catch other potential errors like JSON decoding
|
83 |
+
error_msg = f"Error processing Stability AI response: {type(e).__name__} - {str(e)}"
|
84 |
+
print(f"ERROR: image_services.py - {error_msg}")
|
85 |
+
return ImageGenResponse(error=error_msg, success=False, provider="StabilityAI", raw_response=e)
|
86 |
+
|
87 |
+
|
88 |
+
# --- DALL-E (Conceptual - you'd need 'openai' library and setup) ---
|
89 |
+
def generate_image_dalle(prompt: str, size="1024x1024", quality="standard", n=1) -> ImageGenResponse:
|
90 |
+
if not OPENAI_DALLE_CONFIGURED:
|
91 |
+
return ImageGenResponse(error="OpenAI DALL-E API key not configured.", success=False, provider="DALL-E")
|
92 |
+
try:
|
93 |
+
# from openai import OpenAI # Would be imported at top level
|
94 |
+
# client = OpenAI(api_key=OPENAI_API_KEY)
|
95 |
+
# response = client.images.generate(
|
96 |
+
# model="dall-e-3", # or "dall-e-2"
|
97 |
+
# prompt=prompt,
|
98 |
+
# size=size,
|
99 |
+
# quality=quality,
|
100 |
+
# n=n,
|
101 |
+
# response_format="url" # or "b64_json"
|
102 |
+
# )
|
103 |
+
# image_url = response.data[0].url
|
104 |
+
# image_content = requests.get(image_url).content
|
105 |
+
# image = Image.open(BytesIO(image_content))
|
106 |
+
# return ImageGenResponse(image=image, image_url=image_url, provider="DALL-E")
|
107 |
+
print("DEBUG: image_services.py - DALL-E call placeholder.") # Placeholder
|
108 |
+
# Simulate an image for now
|
109 |
+
dummy_image = Image.new('RGB', (512, 512), color = 'skyblue')
|
110 |
+
return ImageGenResponse(image=dummy_image, provider="DALL-E (Simulated)")
|
111 |
+
except Exception as e:
|
112 |
+
return ImageGenResponse(error=f"DALL-E API Error: {type(e).__name__} - {str(e)}", success=False, provider="DALL-E")
|
113 |
+
|
114 |
+
|
115 |
+
# --- Hugging Face Image Model (Conceptual - via Inference API or local Diffusers) ---
|
116 |
+
# def generate_image_hf_model(prompt: str, model_id="stabilityai/stable-diffusion-xl-base-1.0") -> ImageGenResponse:
|
117 |
+
# if not HF_IMAGE_CONFIGURED:
|
118 |
+
# return ImageGenResponse(error="HF Token not configured for image models.", success=False, provider="HF")
|
119 |
+
# try:
|
120 |
+
# You might use a client similar to hf_inference_text_client but for image generation task
|
121 |
+
# Or if it's a diffusers pipeline, you'd load and run it.
|
122 |
+
# This requires the `diffusers` library and often significant compute.
|
123 |
+
# response_bytes = hf_some_image_client.text_to_image(prompt, model=model_id) # Hypothetical client method
|
124 |
+
# image = Image.open(BytesIO(response_bytes))
|
125 |
+
# return ImageGenResponse(image=image, provider=f"HF ({model_id})")
|
126 |
+
# print("DEBUG: image_services.py - HF Image Model call placeholder.")
|
127 |
+
# dummy_image = Image.new('RGB', (512, 512), color = 'lightgreen')
|
128 |
+
# return ImageGenResponse(image=dummy_image, provider=f"HF ({model_id} - Simulated)")
|
129 |
+
# except Exception as e:
|
130 |
+
# return ImageGenResponse(error=f"HF Image Model Error: {type(e).__name__} - {str(e)}", success=False, provider=f"HF ({model_id})")
|
131 |
+
|
132 |
+
print("DEBUG: core.image_services (for StoryVerseWeaver) - Module defined.")
|