Spaces:
Sleeping
Sleeping
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"
|