Spaces:
Sleeping
Sleeping
Commit ·
e61e906
1
Parent(s): 6455cee
chore: enhance OpenAI integration with connection test endpoint, improved error handling, and validate API key presence
Browse files- app/page.tsx +1 -1
- backend/app/api/v1/endpoints/images.py +3 -3
- backend/app/core/config.py +1 -0
- backend/app/main.py +32 -2
- backend/app/services/image_service.py +40 -3
app/page.tsx
CHANGED
|
@@ -32,7 +32,7 @@ interface ImageGenerationResponse {
|
|
| 32 |
|
| 33 |
const DEFAULT_PROMPT = `這是我創作的角色,叫做狐狸貓,請完全保留圖片中的狐狸貓外觀,包括:
|
| 34 |
五官大小、頭身比例、身體各部位大小、耳朵大小及陰影角度。
|
| 35 |
-
注意,狐狸貓角色「沒有」筆觸描邊、圖片上不要有任何文字
|
| 36 |
請直接給我圖片,不需要回復任何文字`;
|
| 37 |
|
| 38 |
export default function Home() {
|
|
|
|
| 32 |
|
| 33 |
const DEFAULT_PROMPT = `這是我創作的角色,叫做狐狸貓,請完全保留圖片中的狐狸貓外觀,包括:
|
| 34 |
五官大小、頭身比例、身體各部位大小、耳朵大小及陰影角度。
|
| 35 |
+
注意,狐狸貓角色「沒有」筆觸描邊、圖片上不要有任何文字
|
| 36 |
請直接給我圖片,不需要回復任何文字`;
|
| 37 |
|
| 38 |
export default function Home() {
|
backend/app/api/v1/endpoints/images.py
CHANGED
|
@@ -32,11 +32,11 @@ async def generate_image(request: ImageGenerationRequest):
|
|
| 32 |
)
|
| 33 |
|
| 34 |
return ImageGenerationResponse(
|
| 35 |
-
success=True,
|
| 36 |
-
message=result["message"],
|
| 37 |
filename=result["filename"],
|
| 38 |
filenames=result.get("filenames", []),
|
| 39 |
-
count=result.get("count", 0)
|
| 40 |
)
|
| 41 |
|
| 42 |
except HTTPException:
|
|
|
|
| 32 |
)
|
| 33 |
|
| 34 |
return ImageGenerationResponse(
|
| 35 |
+
success=True,
|
| 36 |
+
message=result["message"],
|
| 37 |
filename=result["filename"],
|
| 38 |
filenames=result.get("filenames", []),
|
| 39 |
+
count=result.get("count", 0),
|
| 40 |
)
|
| 41 |
|
| 42 |
except HTTPException:
|
backend/app/core/config.py
CHANGED
|
@@ -6,6 +6,7 @@ from dotenv import load_dotenv
|
|
| 6 |
|
| 7 |
load_dotenv()
|
| 8 |
|
|
|
|
| 9 |
class Settings(BaseSettings):
|
| 10 |
"""
|
| 11 |
Application settings configuration
|
|
|
|
| 6 |
|
| 7 |
load_dotenv()
|
| 8 |
|
| 9 |
+
|
| 10 |
class Settings(BaseSettings):
|
| 11 |
"""
|
| 12 |
Application settings configuration
|
backend/app/main.py
CHANGED
|
@@ -3,6 +3,7 @@ from fastapi import FastAPI
|
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
| 5 |
import logging
|
|
|
|
| 6 |
|
| 7 |
from .core.config import settings
|
| 8 |
from .api.v1.router import api_router
|
|
@@ -45,8 +46,8 @@ def create_app() -> FastAPI:
|
|
| 45 |
"http://localhost:8000",
|
| 46 |
"http://127.0.0.1:8000",
|
| 47 |
"https://*.hf.space",
|
| 48 |
-
"https://*.huggingface.co",
|
| 49 |
-
"*" # Allow all origins for Hugging Face deployment
|
| 50 |
],
|
| 51 |
allow_credentials=True,
|
| 52 |
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
@@ -69,5 +70,34 @@ app = create_app()
|
|
| 69 |
async def health_check():
|
| 70 |
return {"status": "healthy", "message": "Backend is running"}
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
# Include API router
|
| 73 |
app.include_router(api_router, prefix=settings.API_V1_STR)
|
|
|
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
| 5 |
import logging
|
| 6 |
+
import os
|
| 7 |
|
| 8 |
from .core.config import settings
|
| 9 |
from .api.v1.router import api_router
|
|
|
|
| 46 |
"http://localhost:8000",
|
| 47 |
"http://127.0.0.1:8000",
|
| 48 |
"https://*.hf.space",
|
| 49 |
+
"https://*.huggingface.co",
|
| 50 |
+
"*", # Allow all origins for Hugging Face deployment
|
| 51 |
],
|
| 52 |
allow_credentials=True,
|
| 53 |
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
|
|
| 70 |
async def health_check():
|
| 71 |
return {"status": "healthy", "message": "Backend is running"}
|
| 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:
|
| 79 |
+
from .core.config import settings
|
| 80 |
+
|
| 81 |
+
if not settings.OPENAI_API_KEY:
|
| 82 |
+
return {"status": "error", "message": "OPENAI_API_KEY not configured"}
|
| 83 |
+
|
| 84 |
+
api_key_preview = (
|
| 85 |
+
settings.OPENAI_API_KEY[:10] + "..."
|
| 86 |
+
if len(settings.OPENAI_API_KEY) > 10
|
| 87 |
+
else "Too short"
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
return {
|
| 91 |
+
"status": "ok",
|
| 92 |
+
"message": "OpenAI API key is configured",
|
| 93 |
+
"api_key_preview": api_key_preview,
|
| 94 |
+
"environment": (
|
| 95 |
+
"production" if os.getenv("NODE_ENV") == "production" else "development"
|
| 96 |
+
),
|
| 97 |
+
}
|
| 98 |
+
except Exception as e:
|
| 99 |
+
return {"status": "error", "message": f"OpenAI configuration error: {str(e)}"}
|
| 100 |
+
|
| 101 |
+
|
| 102 |
# Include API router
|
| 103 |
app.include_router(api_router, prefix=settings.API_V1_STR)
|
backend/app/services/image_service.py
CHANGED
|
@@ -14,7 +14,24 @@ class ImageGenerationService:
|
|
| 14 |
"""Service for handling OpenAI image generation"""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
self.output_dir = "generated_images"
|
| 19 |
self._ensure_output_directory()
|
| 20 |
|
|
@@ -48,7 +65,6 @@ class ImageGenerationService:
|
|
| 48 |
logger.info(f"Generating {n} image(s) with prompt: {prompt}")
|
| 49 |
|
| 50 |
if reference_image:
|
| 51 |
-
logging.info(f"Reference image: {settings.OPENAI_API_KEY}")
|
| 52 |
# Use the newer responses API with image generation tools for reference images
|
| 53 |
logger.info("Using reference image with responses API")
|
| 54 |
|
|
@@ -112,7 +128,28 @@ class ImageGenerationService:
|
|
| 112 |
logger.info(f"Image {i+1} saved successfully: {filename}")
|
| 113 |
|
| 114 |
except Exception as e:
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
continue
|
| 117 |
|
| 118 |
if not generated_filenames:
|
|
|
|
| 14 |
"""Service for handling OpenAI image generation"""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
+
# Validate API key exists
|
| 18 |
+
if not settings.OPENAI_API_KEY:
|
| 19 |
+
logger.error("OPENAI_API_KEY not found in environment variables")
|
| 20 |
+
raise ValueError("OPENAI_API_KEY is required")
|
| 21 |
+
|
| 22 |
+
# Log API key status (first few characters only for security)
|
| 23 |
+
api_key_preview = (
|
| 24 |
+
settings.OPENAI_API_KEY[:10] + "..."
|
| 25 |
+
if settings.OPENAI_API_KEY
|
| 26 |
+
else "Not set"
|
| 27 |
+
)
|
| 28 |
+
logger.info(f"OpenAI API Key status: {api_key_preview}")
|
| 29 |
+
|
| 30 |
+
self.client = OpenAI(
|
| 31 |
+
api_key=settings.OPENAI_API_KEY,
|
| 32 |
+
timeout=60.0, # Increase timeout for Hugging Face environment
|
| 33 |
+
max_retries=2, # Reduce retries to fail faster
|
| 34 |
+
)
|
| 35 |
self.output_dir = "generated_images"
|
| 36 |
self._ensure_output_directory()
|
| 37 |
|
|
|
|
| 65 |
logger.info(f"Generating {n} image(s) with prompt: {prompt}")
|
| 66 |
|
| 67 |
if reference_image:
|
|
|
|
| 68 |
# Use the newer responses API with image generation tools for reference images
|
| 69 |
logger.info("Using reference image with responses API")
|
| 70 |
|
|
|
|
| 128 |
logger.info(f"Image {i+1} saved successfully: {filename}")
|
| 129 |
|
| 130 |
except Exception as e:
|
| 131 |
+
error_msg = str(e)
|
| 132 |
+
logger.warning(f"Failed to generate image {i+1}: {error_msg}")
|
| 133 |
+
|
| 134 |
+
# More specific error handling for network issues
|
| 135 |
+
if (
|
| 136 |
+
"Connection error" in error_msg
|
| 137 |
+
or "timeout" in error_msg.lower()
|
| 138 |
+
):
|
| 139 |
+
logger.error(
|
| 140 |
+
f"Network connectivity issue detected: {error_msg}"
|
| 141 |
+
)
|
| 142 |
+
logger.error(
|
| 143 |
+
"This might be due to Hugging Face network restrictions"
|
| 144 |
+
)
|
| 145 |
+
elif (
|
| 146 |
+
"api_key" in error_msg.lower()
|
| 147 |
+
or "unauthorized" in error_msg.lower()
|
| 148 |
+
):
|
| 149 |
+
logger.error(f"API key issue detected: {error_msg}")
|
| 150 |
+
elif "rate limit" in error_msg.lower():
|
| 151 |
+
logger.error(f"Rate limit issue detected: {error_msg}")
|
| 152 |
+
|
| 153 |
continue
|
| 154 |
|
| 155 |
if not generated_filenames:
|