Spaces:
Running
Running
Update core/image_services.py
Browse files- core/image_services.py +107 -112
core/image_services.py
CHANGED
@@ -1,132 +1,127 @@
|
|
1 |
# storyverse_weaver/core/image_services.py
|
2 |
import os
|
3 |
-
import requests
|
4 |
import base64
|
5 |
from io import BytesIO
|
6 |
from PIL import Image
|
7 |
-
|
8 |
-
# load_dotenv()
|
9 |
|
10 |
-
# --- API Key Configuration
|
11 |
STABILITY_API_KEY = os.getenv("STORYVERSE_STABILITY_API_KEY")
|
12 |
-
OPENAI_API_KEY = os.getenv("STORYVERSE_OPENAI_API_KEY")
|
13 |
-
|
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 |
-
|
18 |
|
19 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
print("INFO: image_services.py - Initializing Image Generation services...")
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
#
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
"height": height,
|
52 |
"width": width,
|
53 |
-
"
|
54 |
-
"
|
55 |
}
|
56 |
-
|
57 |
-
|
58 |
|
59 |
-
|
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 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
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 |
-
|
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.")
|
|
|
1 |
# storyverse_weaver/core/image_services.py
|
2 |
import os
|
3 |
+
import requests
|
4 |
import base64
|
5 |
from io import BytesIO
|
6 |
from PIL import Image
|
7 |
+
from huggingface_hub import InferenceClient # Ensure this is imported
|
|
|
8 |
|
9 |
+
# --- API Key Configuration ---
|
10 |
STABILITY_API_KEY = os.getenv("STORYVERSE_STABILITY_API_KEY")
|
11 |
+
OPENAI_API_KEY = os.getenv("STORYVERSE_OPENAI_API_KEY")
|
12 |
+
HF_TOKEN = os.getenv("STORYVERSE_HF_TOKEN") # Reuse from llm_services or get it here
|
13 |
|
14 |
STABILITY_API_CONFIGURED = bool(STABILITY_API_KEY and STABILITY_API_KEY.strip())
|
15 |
OPENAI_DALLE_CONFIGURED = bool(OPENAI_API_KEY and OPENAI_API_KEY.strip())
|
16 |
+
HF_IMAGE_API_CONFIGURED = bool(HF_TOKEN and HF_TOKEN.strip()) # New flag
|
17 |
|
18 |
+
hf_inference_image_client = None # Separate client instance for image tasks if needed, or reuse
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
+
class ImageGenResponse: # Keep this class
|
21 |
+
def __init__(self, image: Image.Image = None, image_url: str = None, error: str = None, success: bool = True, provider: str = "unknown", model_id_used: str = None):
|
22 |
+
self.image, self.image_url, self.error, self.success, self.provider, self.model_id_used = \
|
23 |
+
image, image_url, error, success, provider, model_id_used
|
24 |
+
|
25 |
+
def initialize_image_llms():
|
26 |
+
global STABILITY_API_CONFIGURED, OPENAI_DALLE_CONFIGURED, HF_IMAGE_API_CONFIGURED, hf_inference_image_client
|
27 |
+
|
28 |
print("INFO: image_services.py - Initializing Image Generation services...")
|
29 |
+
# Stability AI (as before)
|
30 |
+
if STABILITY_API_KEY and STABILITY_API_KEY.strip():
|
31 |
+
STABILITY_API_CONFIGURED = True
|
32 |
+
print("SUCCESS: image_services.py - Stability AI API Key detected.")
|
33 |
+
else:
|
34 |
+
STABILITY_API_CONFIGURED = False
|
35 |
+
print("WARNING: image_services.py - STORYVERSE_STABILITY_API_KEY not found. Stability AI disabled.")
|
36 |
+
|
37 |
+
# OpenAI DALL-E (as before)
|
38 |
+
if OPENAI_API_KEY and OPENAI_API_KEY.strip():
|
39 |
+
OPENAI_DALLE_CONFIGURED = True
|
40 |
+
print("SUCCESS: image_services.py - OpenAI API Key detected (for DALL-E).")
|
41 |
+
else:
|
42 |
+
OPENAI_DALLE_CONFIGURED = False
|
43 |
+
print("WARNING: image_services.py - STORYVERSE_OPENAI_API_KEY not found. DALL-E disabled.")
|
44 |
+
|
45 |
+
# Hugging Face Image Models
|
46 |
+
if HF_TOKEN and HF_TOKEN.strip():
|
47 |
+
try:
|
48 |
+
# You can use the same token for text and image clients if the permissions cover it
|
49 |
+
# Or, if you want a dedicated client for image tasks (maybe different default model types)
|
50 |
+
hf_inference_image_client = InferenceClient(token=HF_TOKEN) # Reusing the token
|
51 |
+
HF_IMAGE_API_CONFIGURED = True
|
52 |
+
print("SUCCESS: image_services.py - Hugging Face InferenceClient (for images) ready.")
|
53 |
+
except Exception as e:
|
54 |
+
HF_IMAGE_API_CONFIGURED = False
|
55 |
+
print(f"ERROR: image_services.py - Failed to initialize HF InferenceClient for images: {e}")
|
56 |
+
else:
|
57 |
+
HF_IMAGE_API_CONFIGURED = False
|
58 |
+
print("WARNING: image_services.py - STORYVERSE_HF_TOKEN not found. HF Image models disabled.")
|
59 |
+
|
60 |
+
print("INFO: image_services.py - Image Service Init complete.")
|
61 |
+
|
62 |
+
|
63 |
+
# --- Stability AI (Keep as is, it will just be disabled if no key) ---
|
64 |
+
def generate_image_stabilityai(prompt: str, ...) -> ImageGenResponse:
|
65 |
+
# ... (your existing generate_image_stabilityai function)
|
66 |
+
if not STABILITY_API_CONFIGURED: return ImageGenResponse(error="Stability AI API key not configured.", success=False, provider="StabilityAI")
|
67 |
+
# ... rest of the function
|
68 |
+
api_host = os.getenv('API_HOST', 'https://api.stability.ai'); request_url = f"{api_host}/v1/generation/{engine_id if 'engine_id' in locals() else 'stable-diffusion-xl-1024-v1-0'}/text-to-image"; payload = {"text_prompts": [{"text": prompt}], "steps": steps if 'steps' in locals() else 30}; headers = {"Authorization": f"Bearer {STABILITY_API_KEY}", "Accept":"application/json", "Content-Type":"application/json"}; try: response = requests.post(request_url, headers=headers, json=payload, timeout=60); response.raise_for_status(); artifacts = response.json().get("artifacts"); img_data = base64.b64decode(artifacts[0]["base64"]); img = Image.open(BytesIO(img_data)); return ImageGenResponse(image=img, provider="StabilityAI")
|
69 |
+
except Exception as e: return ImageGenResponse(error=f"Stability AI Error: {str(e)}", success=False, provider="StabilityAI", raw_response=e)
|
70 |
+
|
71 |
+
|
72 |
+
# --- DALL-E (Keep as is, conceptual) ---
|
73 |
+
def generate_image_dalle(prompt: str, ...) -> ImageGenResponse:
|
74 |
+
# ... (your existing generate_image_dalle function)
|
75 |
+
if not OPENAI_DALLE_CONFIGURED: return ImageGenResponse(error="OpenAI DALL-E API key not configured.", success=False, provider="DALL-E")
|
76 |
+
dummy_image = Image.new('RGB', (512, 512), color = 'skyblue'); return ImageGenResponse(image=dummy_image, provider="DALL-E (Simulated)")
|
77 |
+
|
78 |
+
|
79 |
+
# --- NEW: Hugging Face Image Model via Inference API ---
|
80 |
+
def generate_image_hf_model(prompt: str,
|
81 |
+
model_id: str = "stabilityai/stable-diffusion-xl-base-1.0", # A popular choice
|
82 |
+
# model_id: str = "runwayml/stable-diffusion-v1-5", # Another option
|
83 |
+
# model_id: str = "prompthero/openjourney", # Midjourney-like style
|
84 |
+
negative_prompt: str = None,
|
85 |
+
height: int = 768, # Adjust for different models
|
86 |
+
width: int = 768,
|
87 |
+
num_inference_steps: int = 25,
|
88 |
+
guidance_scale: float = 7.5
|
89 |
+
) -> ImageGenResponse:
|
90 |
+
global hf_inference_image_client # Use the initialized client
|
91 |
+
if not HF_IMAGE_API_CONFIGURED or not hf_inference_image_client:
|
92 |
+
return ImageGenResponse(error="Hugging Face API (for images) not configured.", success=False, provider="HF Image API", model_id_used=model_id)
|
93 |
+
|
94 |
+
params = {
|
95 |
+
"negative_prompt": negative_prompt,
|
96 |
"height": height,
|
97 |
"width": width,
|
98 |
+
"num_inference_steps": num_inference_steps,
|
99 |
+
"guidance_scale": guidance_scale
|
100 |
}
|
101 |
+
# Remove None params as some models might not like them
|
102 |
+
params = {k: v for k, v in params.items() if v is not None}
|
103 |
|
104 |
+
print(f"DEBUG: image_services.py - Calling HF Image API ({model_id}) with prompt: {prompt[:50]}...")
|
|
|
|
|
|
|
|
|
|
|
105 |
try:
|
106 |
+
# The `text_to_image` method of InferenceClient returns a PIL Image directly
|
107 |
+
image_result: Image.Image = hf_inference_image_client.text_to_image(
|
108 |
+
prompt,
|
109 |
+
model=model_id,
|
110 |
+
**params
|
111 |
+
)
|
112 |
+
print(f"DEBUG: image_services.py - HF Image API ({model_id}) image generated successfully.")
|
113 |
+
return ImageGenResponse(image=image_result, provider="HF Image API", model_id_used=model_id)
|
114 |
+
except Exception as e:
|
115 |
+
error_msg = f"HF Image API Error ({model_id}): {type(e).__name__} - {str(e)}"
|
116 |
+
# Check for common HF API errors
|
117 |
+
if "Rate limit reached" in str(e):
|
118 |
+
error_msg += " You may have hit free tier limits."
|
119 |
+
elif "Model is currently loading" in str(e):
|
120 |
+
error_msg += " The model might be loading, please try again in a moment."
|
121 |
+
elif "Authorization header is correct" in str(e) or "401" in str(e):
|
122 |
+
error_msg += " Issue with your HF_TOKEN authentication."
|
|
|
|
|
|
|
123 |
|
124 |
+
print(f"ERROR: image_services.py - {error_msg}")
|
125 |
+
return ImageGenResponse(error=error_msg, success=False, provider="HF Image API", model_id_used=model_id, raw_response=e)
|
126 |
|
127 |
+
print("DEBUG: core.image_services (for StoryVerseWeaver) - Module defined with HF Image support.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|