Spaces:
Running
Running
Commit
·
ad78edb
1
Parent(s):
e61e906
feat: implement DALL-E fallback mechanism in image generation service to handle API failures and enhance error logging
Browse files- backend/app/main.py +1 -1
- backend/app/services/image_service.py +54 -3
backend/app/main.py
CHANGED
@@ -72,7 +72,7 @@ async def health_check():
|
|
72 |
|
73 |
|
74 |
# OpenAI connection test endpoint
|
75 |
-
@app.get("/test-openai")
|
76 |
async def test_openai():
|
77 |
"""Test OpenAI connection without making actual API calls"""
|
78 |
try:
|
|
|
72 |
|
73 |
|
74 |
# OpenAI connection test endpoint
|
75 |
+
@app.get("/api/test-openai")
|
76 |
async def test_openai():
|
77 |
"""Test OpenAI connection without making actual API calls"""
|
78 |
try:
|
backend/app/services/image_service.py
CHANGED
@@ -40,6 +40,57 @@ class ImageGenerationService:
|
|
40 |
if not os.path.exists(self.output_dir):
|
41 |
os.makedirs(self.output_dir)
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
async def generate_image(
|
44 |
self,
|
45 |
prompt: str,
|
@@ -153,9 +204,9 @@ class ImageGenerationService:
|
|
153 |
continue
|
154 |
|
155 |
if not generated_filenames:
|
156 |
-
|
157 |
-
|
158 |
-
)
|
159 |
|
160 |
logger.info(
|
161 |
f"Successfully generated {len(generated_filenames)}/{n} images"
|
|
|
40 |
if not os.path.exists(self.output_dir):
|
41 |
os.makedirs(self.output_dir)
|
42 |
|
43 |
+
async def _fallback_to_dalle(self, prompt: str, size: str, n: int, model: str) -> dict:
|
44 |
+
"""
|
45 |
+
Fallback to regular DALL-E when responses API is blocked
|
46 |
+
This sacrifices reference image capability but ensures the app works on Hugging Face
|
47 |
+
"""
|
48 |
+
try:
|
49 |
+
logger.info("Using DALL-E fallback (reference image will be ignored)")
|
50 |
+
|
51 |
+
response = self.client.images.generate(
|
52 |
+
model=model,
|
53 |
+
prompt=prompt,
|
54 |
+
n=n,
|
55 |
+
size=size,
|
56 |
+
response_format="b64_json",
|
57 |
+
)
|
58 |
+
|
59 |
+
generated_filenames = []
|
60 |
+
|
61 |
+
for i, image_data in enumerate(response.data):
|
62 |
+
try:
|
63 |
+
image_bytes = base64.b64decode(image_data.b64_json)
|
64 |
+
|
65 |
+
# Generate unique filename and save
|
66 |
+
filename = f"{uuid.uuid4()}.png"
|
67 |
+
filepath = os.path.join(self.output_dir, filename)
|
68 |
+
|
69 |
+
with open(filepath, "wb") as f:
|
70 |
+
f.write(image_bytes)
|
71 |
+
|
72 |
+
generated_filenames.append(filename)
|
73 |
+
logger.info(f"Fallback image {i+1} saved successfully: {filename}")
|
74 |
+
|
75 |
+
except Exception as e:
|
76 |
+
logger.warning(f"Failed to save fallback image {i+1}: {str(e)}")
|
77 |
+
continue
|
78 |
+
|
79 |
+
if generated_filenames:
|
80 |
+
return {
|
81 |
+
"success": True,
|
82 |
+
"message": f"Generated {len(generated_filenames)}/{n} images using DALL-E fallback (reference image ignored due to network restrictions)",
|
83 |
+
"filename": generated_filenames[0],
|
84 |
+
"filenames": generated_filenames,
|
85 |
+
"count": len(generated_filenames),
|
86 |
+
}
|
87 |
+
else:
|
88 |
+
raise Exception("Fallback also failed to generate any images")
|
89 |
+
|
90 |
+
except Exception as e:
|
91 |
+
logger.error(f"Fallback to DALL-E also failed: {str(e)}")
|
92 |
+
raise Exception(f"Both responses API and DALL-E fallback failed: {str(e)}")
|
93 |
+
|
94 |
async def generate_image(
|
95 |
self,
|
96 |
prompt: str,
|
|
|
204 |
continue
|
205 |
|
206 |
if not generated_filenames:
|
207 |
+
# If responses API failed due to network restrictions, try fallback to regular DALL-E
|
208 |
+
logger.warning("Responses API failed, attempting fallback to regular DALL-E")
|
209 |
+
return await self._fallback_to_dalle(prompt, size, n, model)
|
210 |
|
211 |
logger.info(
|
212 |
f"Successfully generated {len(generated_filenames)}/{n} images"
|