Spaces:
Sleeping
Sleeping
Changed saving file location to /tmp
Browse files
api.py
CHANGED
@@ -15,9 +15,13 @@ from app.scene_graph_service import process_image
|
|
15 |
logging.basicConfig(level=logging.INFO)
|
16 |
logger = logging.getLogger(__name__)
|
17 |
|
|
|
|
|
|
|
|
|
18 |
# Create necessary directories
|
19 |
-
os.makedirs(
|
20 |
-
os.makedirs(
|
21 |
os.makedirs("app/models", exist_ok=True)
|
22 |
|
23 |
# Initialize FastAPI app
|
@@ -47,10 +51,21 @@ async def generate_scene_graph(
|
|
47 |
use_fixed_boxes: bool = Form(False),
|
48 |
) -> Dict[str, Any]:
|
49 |
try:
|
50 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
if not image.content_type.startswith("image/"):
|
52 |
raise HTTPException(
|
53 |
-
status_code=400, detail="Uploaded file must be an image"
|
54 |
)
|
55 |
|
56 |
if not (0 <= confidence_threshold <= 1):
|
@@ -62,27 +77,57 @@ async def generate_scene_graph(
|
|
62 |
job_id = str(uuid.uuid4())
|
63 |
short_id = job_id.split("-")[0]
|
64 |
|
65 |
-
# Create directories for this job
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
# Define model paths
|
84 |
model_path = "app/models/model.pth"
|
85 |
vocabulary_path = "app/models/vocabulary.json"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
# Process the image
|
88 |
objects, relationships, annotated_image_path, graph_path = process_image(
|
@@ -91,16 +136,33 @@ async def generate_scene_graph(
|
|
91 |
vocabulary_path=vocabulary_path,
|
92 |
confidence_threshold=confidence_threshold,
|
93 |
use_fixed_boxes=use_fixed_boxes,
|
94 |
-
output_dir=
|
95 |
base_filename=short_id,
|
96 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
# Read the generated images as base64
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
# Prepare response with base64 encoded images
|
106 |
response = {
|
@@ -112,15 +174,16 @@ async def generate_scene_graph(
|
|
112 |
|
113 |
# Clean up
|
114 |
try:
|
115 |
-
shutil.rmtree(
|
116 |
-
shutil.rmtree(
|
|
|
117 |
except Exception as e:
|
118 |
logger.warning(f"Error cleaning up temporary files: {str(e)}")
|
119 |
|
120 |
return response
|
121 |
|
122 |
except Exception as e:
|
123 |
-
logger.error(f"Error processing image: {str(e)}")
|
124 |
raise HTTPException(status_code=500, detail=f"Error processing image: {str(e)}")
|
125 |
|
126 |
|
|
|
15 |
logging.basicConfig(level=logging.INFO)
|
16 |
logger = logging.getLogger(__name__)
|
17 |
|
18 |
+
# Use /tmp directory which should be writable
|
19 |
+
UPLOAD_DIR = "/tmp/uploads"
|
20 |
+
OUTPUT_DIR = "/tmp/outputs"
|
21 |
+
|
22 |
# Create necessary directories
|
23 |
+
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
24 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
25 |
os.makedirs("app/models", exist_ok=True)
|
26 |
|
27 |
# Initialize FastAPI app
|
|
|
51 |
use_fixed_boxes: bool = Form(False),
|
52 |
) -> Dict[str, Any]:
|
53 |
try:
|
54 |
+
# Debug information
|
55 |
+
logger.info(f"Received file: {image.filename}, content_type: {image.content_type}")
|
56 |
+
|
57 |
+
# Input validation with improved error handling
|
58 |
+
if image is None:
|
59 |
+
raise HTTPException(status_code=400, detail="No image file provided")
|
60 |
+
|
61 |
+
if not image.content_type:
|
62 |
+
# Set a default content type if none provided
|
63 |
+
logger.warning("No content type provided, assuming image/jpeg")
|
64 |
+
image.content_type = "image/jpeg"
|
65 |
+
|
66 |
if not image.content_type.startswith("image/"):
|
67 |
raise HTTPException(
|
68 |
+
status_code=400, detail=f"Uploaded file must be an image, got {image.content_type}"
|
69 |
)
|
70 |
|
71 |
if not (0 <= confidence_threshold <= 1):
|
|
|
77 |
job_id = str(uuid.uuid4())
|
78 |
short_id = job_id.split("-")[0]
|
79 |
|
80 |
+
# Create directories for this job in /tmp which should be writable
|
81 |
+
upload_job_dir = os.path.join(UPLOAD_DIR, job_id)
|
82 |
+
output_job_dir = os.path.join(OUTPUT_DIR, job_id)
|
83 |
+
|
84 |
+
# Create directories with explicit permission setting
|
85 |
+
os.makedirs(upload_job_dir, exist_ok=True, mode=0o777)
|
86 |
+
os.makedirs(output_job_dir, exist_ok=True, mode=0o777)
|
87 |
+
|
88 |
+
logger.info(f"Created upload directory: {upload_job_dir}")
|
89 |
+
logger.info(f"Created output directory: {output_job_dir}")
|
90 |
+
|
91 |
+
# Determine file extension
|
92 |
+
file_ext = os.path.splitext(image.filename)[1] if image.filename else ".jpg"
|
93 |
+
if not file_ext:
|
94 |
+
file_ext = ".jpg"
|
95 |
+
|
96 |
+
# Save the uploaded image to /tmp
|
97 |
+
image_filename = f"{short_id}{file_ext}"
|
98 |
+
image_path = os.path.join(upload_job_dir, image_filename)
|
99 |
+
|
100 |
+
# Save the file with error handling
|
101 |
+
try:
|
102 |
+
# Explicitly open with write permissions
|
103 |
+
with open(image_path, "wb") as buffer:
|
104 |
+
contents = await image.read()
|
105 |
+
buffer.write(contents)
|
106 |
+
|
107 |
+
# Check if file was created and has size
|
108 |
+
if not os.path.exists(image_path):
|
109 |
+
raise HTTPException(status_code=400, detail=f"Failed to save uploaded file to {image_path}")
|
110 |
+
|
111 |
+
if os.path.getsize(image_path) == 0:
|
112 |
+
raise HTTPException(status_code=400, detail="Uploaded file is empty")
|
113 |
+
|
114 |
+
logger.info(f"Image saved to {image_path} ({os.path.getsize(image_path)} bytes)")
|
115 |
+
except Exception as e:
|
116 |
+
logger.error(f"Error saving file: {str(e)}")
|
117 |
+
raise HTTPException(status_code=500, detail=f"Error saving uploaded file: {str(e)}")
|
118 |
|
119 |
# Define model paths
|
120 |
model_path = "app/models/model.pth"
|
121 |
vocabulary_path = "app/models/vocabulary.json"
|
122 |
+
|
123 |
+
# Check if model files exist
|
124 |
+
if not os.path.exists(model_path):
|
125 |
+
logger.error(f"Model file not found: {model_path}")
|
126 |
+
raise HTTPException(status_code=500, detail=f"Model file not found: {model_path}")
|
127 |
+
|
128 |
+
if not os.path.exists(vocabulary_path):
|
129 |
+
logger.error(f"Vocabulary file not found: {vocabulary_path}")
|
130 |
+
raise HTTPException(status_code=500, detail=f"Vocabulary file not found: {vocabulary_path}")
|
131 |
|
132 |
# Process the image
|
133 |
objects, relationships, annotated_image_path, graph_path = process_image(
|
|
|
136 |
vocabulary_path=vocabulary_path,
|
137 |
confidence_threshold=confidence_threshold,
|
138 |
use_fixed_boxes=use_fixed_boxes,
|
139 |
+
output_dir=output_job_dir,
|
140 |
base_filename=short_id,
|
141 |
)
|
142 |
+
|
143 |
+
logger.info(f"Processing complete. Annotated image: {annotated_image_path}, Graph: {graph_path}")
|
144 |
+
|
145 |
+
# Verify output files exist
|
146 |
+
if not os.path.exists(annotated_image_path):
|
147 |
+
logger.error(f"Annotated image not generated: {annotated_image_path}")
|
148 |
+
raise HTTPException(status_code=500, detail="Failed to generate annotated image")
|
149 |
+
|
150 |
+
if not os.path.exists(graph_path):
|
151 |
+
logger.error(f"Graph image not generated: {graph_path}")
|
152 |
+
raise HTTPException(status_code=500, detail="Failed to generate graph image")
|
153 |
|
154 |
# Read the generated images as base64
|
155 |
+
try:
|
156 |
+
with open(annotated_image_path, "rb") as img_file:
|
157 |
+
annotated_image_base64 = base64.b64encode(img_file.read()).decode("utf-8")
|
158 |
+
|
159 |
+
with open(graph_path, "rb") as img_file:
|
160 |
+
graph_image_base64 = base64.b64encode(img_file.read()).decode("utf-8")
|
161 |
+
|
162 |
+
logger.info("Successfully encoded images as base64")
|
163 |
+
except Exception as e:
|
164 |
+
logger.error(f"Error reading output images: {str(e)}")
|
165 |
+
raise HTTPException(status_code=500, detail=f"Error reading output images: {str(e)}")
|
166 |
|
167 |
# Prepare response with base64 encoded images
|
168 |
response = {
|
|
|
174 |
|
175 |
# Clean up
|
176 |
try:
|
177 |
+
shutil.rmtree(upload_job_dir)
|
178 |
+
shutil.rmtree(output_job_dir)
|
179 |
+
logger.info("Cleaned up temporary directories")
|
180 |
except Exception as e:
|
181 |
logger.warning(f"Error cleaning up temporary files: {str(e)}")
|
182 |
|
183 |
return response
|
184 |
|
185 |
except Exception as e:
|
186 |
+
logger.error(f"Error processing image: {str(e)}", exc_info=True)
|
187 |
raise HTTPException(status_code=500, detail=f"Error processing image: {str(e)}")
|
188 |
|
189 |
|