Spaces:
Sleeping
Sleeping
Commit
·
3eefc8f
1
Parent(s):
692f363
add: detail logging
Browse files- src/api/image_prep_api.py +75 -0
- src/api/image_regeneration_api.py +21 -2
- src/api/nto_api.py +87 -5
src/api/image_prep_api.py
CHANGED
@@ -19,6 +19,7 @@ from fastapi.responses import JSONResponse
|
|
19 |
from src.components.auto_crop import crop_transparent_image
|
20 |
from src.components.color_extraction import ColorExtractionRMBG
|
21 |
from src.components.title_des_gen import NecklaceProductListing
|
|
|
22 |
|
23 |
preprocessing_router = APIRouter()
|
24 |
|
@@ -49,12 +50,16 @@ def replicate_enhancer(input):
|
|
49 |
|
50 |
@preprocessing_router.post("/rem_bg")
|
51 |
async def remove_background(image: UploadFile = File(...)):
|
|
|
|
|
52 |
start_time = time.time()
|
53 |
|
54 |
try:
|
55 |
image_bytes = await image.read()
|
56 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
|
|
57 |
except Exception as e:
|
|
|
58 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
59 |
|
60 |
try:
|
@@ -62,13 +67,17 @@ async def remove_background(image: UploadFile = File(...)):
|
|
62 |
image.save(act_img_base_64, format="WEBP")
|
63 |
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
64 |
image_data_uri = f"data:image/WEBP;base64,{image_bytes_}"
|
|
|
65 |
except Exception as e:
|
|
|
66 |
return JSONResponse(status_code=500,
|
67 |
content={"error": f"Error converting image to base64: {str(e)}", "code": 500})
|
68 |
|
69 |
try:
|
70 |
output = replicate_bg({"image": image_data_uri})
|
|
|
71 |
except Exception as e:
|
|
|
72 |
return JSONResponse(status_code=500,
|
73 |
content={"error": f"Error running background removal: {str(e)}", "code": 500})
|
74 |
|
@@ -84,21 +93,30 @@ async def remove_background(image: UploadFile = File(...)):
|
|
84 |
"inference_time": total_inference_time,
|
85 |
"code": 200
|
86 |
}
|
|
|
|
|
|
|
|
|
87 |
return JSONResponse(content=response, status_code=200)
|
88 |
|
89 |
except Exception as e:
|
|
|
90 |
return JSONResponse(status_code=500,
|
91 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
92 |
|
93 |
|
94 |
@preprocessing_router.post("/upscale_image")
|
95 |
async def upscale_image(image: UploadFile = File(...), scale: int = 1):
|
|
|
|
|
96 |
start_time = time.time()
|
97 |
|
98 |
try:
|
99 |
image_bytes = await image.read()
|
100 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
|
|
101 |
except Exception as e:
|
|
|
102 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
103 |
|
104 |
try:
|
@@ -106,7 +124,9 @@ async def upscale_image(image: UploadFile = File(...), scale: int = 1):
|
|
106 |
image.save(act_img_base_64, format="PNG")
|
107 |
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
108 |
image_data_uri = f"data:image/png;base64,{image_bytes_}"
|
|
|
109 |
except Exception as e:
|
|
|
110 |
return JSONResponse(status_code=500,
|
111 |
content={"error": f"Error converting image to base64: {str(e)}", "code": 500})
|
112 |
|
@@ -117,7 +137,9 @@ async def upscale_image(image: UploadFile = File(...), scale: int = 1):
|
|
117 |
"face_enhance": False
|
118 |
}
|
119 |
output = replicate_enhancer(input)
|
|
|
120 |
except Exception as e:
|
|
|
121 |
return JSONResponse(status_code=500,
|
122 |
content={"error": f"Error running image enhancement: {str(e)}", "code": 500})
|
123 |
|
@@ -133,29 +155,40 @@ async def upscale_image(image: UploadFile = File(...), scale: int = 1):
|
|
133 |
"inference_time": total_inference_time,
|
134 |
"code": 200
|
135 |
}
|
|
|
|
|
|
|
|
|
136 |
return JSONResponse(content=response, status_code=200)
|
137 |
|
138 |
except Exception as e:
|
|
|
139 |
return JSONResponse(status_code=500,
|
140 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
141 |
|
142 |
|
143 |
@preprocessing_router.post("/crop_transparent")
|
144 |
async def crop_transparent(image: UploadFile):
|
|
|
|
|
145 |
start_time = time.time()
|
146 |
|
147 |
try:
|
148 |
if not image.content_type == "image/png":
|
|
|
149 |
return JSONResponse(status_code=400,
|
150 |
content={"error": "Only PNG files are supported", "code": 400})
|
151 |
except Exception as e:
|
|
|
152 |
return JSONResponse(status_code=500,
|
153 |
content={"error": f"Error checking file type: {str(e)}", "code": 500})
|
154 |
|
155 |
try:
|
156 |
contents = await image.read()
|
157 |
cropped_image_bytes, metadata = crop_transparent_image(contents)
|
|
|
158 |
except Exception as e:
|
|
|
159 |
return JSONResponse(status_code=500,
|
160 |
content={"error": f"Error cropping image: {str(e)}", "code": 500})
|
161 |
|
@@ -165,6 +198,11 @@ async def crop_transparent(image: UploadFile):
|
|
165 |
|
166 |
total_inference_time = round((time.time() - start_time), 2)
|
167 |
|
|
|
|
|
|
|
|
|
|
|
168 |
return JSONResponse(content={
|
169 |
"status": "success",
|
170 |
"code": 200,
|
@@ -175,12 +213,15 @@ async def crop_transparent(image: UploadFile):
|
|
175 |
}
|
176 |
}, status_code=200)
|
177 |
except Exception as e:
|
|
|
178 |
return JSONResponse(status_code=500,
|
179 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
180 |
|
181 |
|
182 |
@preprocessing_router.post("/background_replace")
|
183 |
async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(...)):
|
|
|
|
|
184 |
start_time = time.time()
|
185 |
|
186 |
try:
|
@@ -188,7 +229,9 @@ async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(
|
|
188 |
bg_bytes = await bg_image.read()
|
189 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
190 |
bg_image = Image.open(BytesIO(bg_bytes)).convert("RGB")
|
|
|
191 |
except Exception as e:
|
|
|
192 |
return JSONResponse(status_code=500,
|
193 |
content={"error": f"Error reading images: {str(e)}", "code": 500})
|
194 |
|
@@ -197,7 +240,9 @@ async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(
|
|
197 |
background = Image.fromarray(np.array(bg_image)).resize((width, height))
|
198 |
orig_img = Image.fromarray(np.array(image)).resize((width, height))
|
199 |
background.paste(orig_img, (0, 0), mask=orig_img)
|
|
|
200 |
except Exception as e:
|
|
|
201 |
return JSONResponse(status_code=500,
|
202 |
content={"error": f"Error processing images: {str(e)}", "code": 500})
|
203 |
|
@@ -209,12 +254,18 @@ async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(
|
|
209 |
|
210 |
total_inference_time = round((time.time() - start_time), 2)
|
211 |
|
|
|
|
|
|
|
|
|
|
|
212 |
return JSONResponse(content={
|
213 |
"output": image_data_uri,
|
214 |
"code": 200,
|
215 |
"inference_time": total_inference_time
|
216 |
}, status_code=200)
|
217 |
except Exception as e:
|
|
|
218 |
return JSONResponse(status_code=500,
|
219 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
220 |
|
@@ -223,20 +274,26 @@ async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(
|
|
223 |
async def remove_background_color_extraction(image: UploadFile = File(...),
|
224 |
hex_color: str = "#FFFFFF",
|
225 |
threshold: int = 30):
|
|
|
|
|
226 |
start_time = time.time()
|
227 |
|
228 |
try:
|
229 |
image_bytes = await image.read()
|
230 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
231 |
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
|
|
232 |
except Exception as e:
|
|
|
233 |
return JSONResponse(status_code=500,
|
234 |
content={"error": f"Error reading image: {str(e)}", "code": 500})
|
235 |
|
236 |
try:
|
237 |
result = color_extraction_rmbg.extract_color(image, hex_color, threshold)
|
238 |
result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_RGB2BGRA)).convert("RGBA")
|
|
|
239 |
except Exception as e:
|
|
|
240 |
return JSONResponse(status_code=500,
|
241 |
content={"error": f"Error extracting colors: {str(e)}", "code": 500})
|
242 |
|
@@ -248,24 +305,34 @@ async def remove_background_color_extraction(image: UploadFile = File(...),
|
|
248 |
|
249 |
total_inference_time = round((time.time() - start_time), 2)
|
250 |
|
|
|
|
|
|
|
|
|
|
|
251 |
return JSONResponse(content={
|
252 |
"output": image_data_uri,
|
253 |
"code": 200,
|
254 |
"inference_time": total_inference_time
|
255 |
}, status_code=200)
|
256 |
except Exception as e:
|
|
|
257 |
return JSONResponse(status_code=500,
|
258 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
259 |
|
260 |
|
261 |
@preprocessing_router.post("/title_description_generator")
|
262 |
async def product_title_description_generator(image: UploadFile = File(...)):
|
|
|
|
|
263 |
start_time = time.time()
|
264 |
|
265 |
try:
|
266 |
image_bytes = await image.read()
|
267 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
|
|
268 |
except Exception as e:
|
|
|
269 |
return JSONResponse(status_code=500,
|
270 |
content={"error": f"Error reading image: {str(e)}", "code": 500})
|
271 |
|
@@ -273,7 +340,9 @@ async def product_title_description_generator(image: UploadFile = File(...)):
|
|
273 |
result = product_listing_obj.gen_title_desc(image=image)
|
274 |
title = result.split("Title:")[1].split("Description:")[0]
|
275 |
description = result.split("Description:")[1]
|
|
|
276 |
except Exception as e:
|
|
|
277 |
return JSONResponse(status_code=500,
|
278 |
content={"error": "Please make sure the image is clear and necklaces are visible",
|
279 |
"code": 500})
|
@@ -281,6 +350,11 @@ async def product_title_description_generator(image: UploadFile = File(...)):
|
|
281 |
try:
|
282 |
total_inference_time = round((time.time() - start_time), 2)
|
283 |
|
|
|
|
|
|
|
|
|
|
|
284 |
return JSONResponse(content={
|
285 |
"code": 200,
|
286 |
"title": title,
|
@@ -288,5 +362,6 @@ async def product_title_description_generator(image: UploadFile = File(...)):
|
|
288 |
"inference_time": total_inference_time
|
289 |
}, status_code=200)
|
290 |
except Exception as e:
|
|
|
291 |
return JSONResponse(status_code=500,
|
292 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
|
|
19 |
from src.components.auto_crop import crop_transparent_image
|
20 |
from src.components.color_extraction import ColorExtractionRMBG
|
21 |
from src.components.title_des_gen import NecklaceProductListing
|
22 |
+
from src.utils import logger
|
23 |
|
24 |
preprocessing_router = APIRouter()
|
25 |
|
|
|
50 |
|
51 |
@preprocessing_router.post("/rem_bg")
|
52 |
async def remove_background(image: UploadFile = File(...)):
|
53 |
+
logger.info("-" * 50)
|
54 |
+
logger.info(">>> REMOVE BACKGROUND STARTED <<<")
|
55 |
start_time = time.time()
|
56 |
|
57 |
try:
|
58 |
image_bytes = await image.read()
|
59 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
60 |
+
logger.info(">>> IMAGE LOADED SUCCESSFULLY <<<")
|
61 |
except Exception as e:
|
62 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
63 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
64 |
|
65 |
try:
|
|
|
67 |
image.save(act_img_base_64, format="WEBP")
|
68 |
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
69 |
image_data_uri = f"data:image/WEBP;base64,{image_bytes_}"
|
70 |
+
logger.info(">>> IMAGE ENCODING COMPLETED <<<")
|
71 |
except Exception as e:
|
72 |
+
logger.error(f">>> IMAGE ENCODING ERROR: {str(e)} <<<")
|
73 |
return JSONResponse(status_code=500,
|
74 |
content={"error": f"Error converting image to base64: {str(e)}", "code": 500})
|
75 |
|
76 |
try:
|
77 |
output = replicate_bg({"image": image_data_uri})
|
78 |
+
logger.info(">>> BACKGROUND REMOVAL COMPLETED <<<")
|
79 |
except Exception as e:
|
80 |
+
logger.error(f">>> BACKGROUND REMOVAL ERROR: {str(e)} <<<")
|
81 |
return JSONResponse(status_code=500,
|
82 |
content={"error": f"Error running background removal: {str(e)}", "code": 500})
|
83 |
|
|
|
93 |
"inference_time": total_inference_time,
|
94 |
"code": 200
|
95 |
}
|
96 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
97 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
98 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
99 |
+
logger.info("-" * 50)
|
100 |
return JSONResponse(content=response, status_code=200)
|
101 |
|
102 |
except Exception as e:
|
103 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
104 |
return JSONResponse(status_code=500,
|
105 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
106 |
|
107 |
|
108 |
@preprocessing_router.post("/upscale_image")
|
109 |
async def upscale_image(image: UploadFile = File(...), scale: int = 1):
|
110 |
+
logger.info("-" * 50)
|
111 |
+
logger.info(">>> IMAGE UPSCALING STARTED <<<")
|
112 |
start_time = time.time()
|
113 |
|
114 |
try:
|
115 |
image_bytes = await image.read()
|
116 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
117 |
+
logger.info(">>> IMAGE LOADED SUCCESSFULLY <<<")
|
118 |
except Exception as e:
|
119 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
120 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
121 |
|
122 |
try:
|
|
|
124 |
image.save(act_img_base_64, format="PNG")
|
125 |
image_bytes_ = base64.b64encode(act_img_base_64.getvalue()).decode("utf-8")
|
126 |
image_data_uri = f"data:image/png;base64,{image_bytes_}"
|
127 |
+
logger.info(">>> IMAGE ENCODING COMPLETED <<<")
|
128 |
except Exception as e:
|
129 |
+
logger.error(f">>> IMAGE ENCODING ERROR: {str(e)} <<<")
|
130 |
return JSONResponse(status_code=500,
|
131 |
content={"error": f"Error converting image to base64: {str(e)}", "code": 500})
|
132 |
|
|
|
137 |
"face_enhance": False
|
138 |
}
|
139 |
output = replicate_enhancer(input)
|
140 |
+
logger.info(">>> IMAGE ENHANCEMENT COMPLETED <<<")
|
141 |
except Exception as e:
|
142 |
+
logger.error(f">>> IMAGE ENHANCEMENT ERROR: {str(e)} <<<")
|
143 |
return JSONResponse(status_code=500,
|
144 |
content={"error": f"Error running image enhancement: {str(e)}", "code": 500})
|
145 |
|
|
|
155 |
"inference_time": total_inference_time,
|
156 |
"code": 200
|
157 |
}
|
158 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
159 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
160 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
161 |
+
logger.info("-" * 50)
|
162 |
return JSONResponse(content=response, status_code=200)
|
163 |
|
164 |
except Exception as e:
|
165 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
166 |
return JSONResponse(status_code=500,
|
167 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
168 |
|
169 |
|
170 |
@preprocessing_router.post("/crop_transparent")
|
171 |
async def crop_transparent(image: UploadFile):
|
172 |
+
logger.info("-" * 50)
|
173 |
+
logger.info(">>> CROP TRANSPARENT STARTED <<<")
|
174 |
start_time = time.time()
|
175 |
|
176 |
try:
|
177 |
if not image.content_type == "image/png":
|
178 |
+
logger.error(">>> INVALID FILE TYPE: NOT PNG <<<")
|
179 |
return JSONResponse(status_code=400,
|
180 |
content={"error": "Only PNG files are supported", "code": 400})
|
181 |
except Exception as e:
|
182 |
+
logger.error(f">>> FILE TYPE CHECK ERROR: {str(e)} <<<")
|
183 |
return JSONResponse(status_code=500,
|
184 |
content={"error": f"Error checking file type: {str(e)}", "code": 500})
|
185 |
|
186 |
try:
|
187 |
contents = await image.read()
|
188 |
cropped_image_bytes, metadata = crop_transparent_image(contents)
|
189 |
+
logger.info(">>> IMAGE CROPPING COMPLETED <<<")
|
190 |
except Exception as e:
|
191 |
+
logger.error(f">>> IMAGE CROPPING ERROR: {str(e)} <<<")
|
192 |
return JSONResponse(status_code=500,
|
193 |
content={"error": f"Error cropping image: {str(e)}", "code": 500})
|
194 |
|
|
|
198 |
|
199 |
total_inference_time = round((time.time() - start_time), 2)
|
200 |
|
201 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
202 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
203 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
204 |
+
logger.info("-" * 50)
|
205 |
+
|
206 |
return JSONResponse(content={
|
207 |
"status": "success",
|
208 |
"code": 200,
|
|
|
213 |
}
|
214 |
}, status_code=200)
|
215 |
except Exception as e:
|
216 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
217 |
return JSONResponse(status_code=500,
|
218 |
content={"error": f"Error processing response: {str(e)}", "code": 500})
|
219 |
|
220 |
|
221 |
@preprocessing_router.post("/background_replace")
|
222 |
async def bg_replace(image: UploadFile = File(...), bg_image: UploadFile = File(...)):
|
223 |
+
logger.info("-" * 50)
|
224 |
+
logger.info(">>> BACKGROUND REPLACE STARTED <<<")
|
225 |
start_time = time.time()
|
226 |
|
227 |
try:
|
|
|
229 |
bg_bytes = await bg_image.read()
|
230 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
231 |
bg_image = Image.open(BytesIO(bg_bytes)).convert("RGB")
|
232 |
+
logger.info(">>> IMAGES LOADED SUCCESSFULLY <<<")
|
233 |
except Exception as e:
|
234 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
235 |
return JSONResponse(status_code=500,
|
236 |
content={"error": f"Error reading images: {str(e)}", "code": 500})
|
237 |
|
|
|
240 |
background = Image.fromarray(np.array(bg_image)).resize((width, height))
|
241 |
orig_img = Image.fromarray(np.array(image)).resize((width, height))
|
242 |
background.paste(orig_img, (0, 0), mask=orig_img)
|
243 |
+
logger.info(">>> IMAGE PROCESSING COMPLETED <<<")
|
244 |
except Exception as e:
|
245 |
+
logger.error(f">>> IMAGE PROCESSING ERROR: {str(e)} <<<")
|
246 |
return JSONResponse(status_code=500,
|
247 |
content={"error": f"Error processing images: {str(e)}", "code": 500})
|
248 |
|
|
|
254 |
|
255 |
total_inference_time = round((time.time() - start_time), 2)
|
256 |
|
257 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
258 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
259 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
260 |
+
logger.info("-" * 50)
|
261 |
+
|
262 |
return JSONResponse(content={
|
263 |
"output": image_data_uri,
|
264 |
"code": 200,
|
265 |
"inference_time": total_inference_time
|
266 |
}, status_code=200)
|
267 |
except Exception as e:
|
268 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
269 |
return JSONResponse(status_code=500,
|
270 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
271 |
|
|
|
274 |
async def remove_background_color_extraction(image: UploadFile = File(...),
|
275 |
hex_color: str = "#FFFFFF",
|
276 |
threshold: int = 30):
|
277 |
+
logger.info("-" * 50)
|
278 |
+
logger.info(">>> COLOR EXTRACTION STARTED <<<")
|
279 |
start_time = time.time()
|
280 |
|
281 |
try:
|
282 |
image_bytes = await image.read()
|
283 |
image = Image.open(BytesIO(image_bytes)).convert("RGBA")
|
284 |
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
285 |
+
logger.info(">>> IMAGE LOADED SUCCESSFULLY <<<")
|
286 |
except Exception as e:
|
287 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
288 |
return JSONResponse(status_code=500,
|
289 |
content={"error": f"Error reading image: {str(e)}", "code": 500})
|
290 |
|
291 |
try:
|
292 |
result = color_extraction_rmbg.extract_color(image, hex_color, threshold)
|
293 |
result = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_RGB2BGRA)).convert("RGBA")
|
294 |
+
logger.info(">>> COLOR EXTRACTION COMPLETED <<<")
|
295 |
except Exception as e:
|
296 |
+
logger.error(f">>> COLOR EXTRACTION ERROR: {str(e)} <<<")
|
297 |
return JSONResponse(status_code=500,
|
298 |
content={"error": f"Error extracting colors: {str(e)}", "code": 500})
|
299 |
|
|
|
305 |
|
306 |
total_inference_time = round((time.time() - start_time), 2)
|
307 |
|
308 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
309 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
310 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
311 |
+
logger.info("-" * 50)
|
312 |
+
|
313 |
return JSONResponse(content={
|
314 |
"output": image_data_uri,
|
315 |
"code": 200,
|
316 |
"inference_time": total_inference_time
|
317 |
}, status_code=200)
|
318 |
except Exception as e:
|
319 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
320 |
return JSONResponse(status_code=500,
|
321 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
322 |
|
323 |
|
324 |
@preprocessing_router.post("/title_description_generator")
|
325 |
async def product_title_description_generator(image: UploadFile = File(...)):
|
326 |
+
logger.info("-" * 50)
|
327 |
+
logger.info(">>> TITLE DESCRIPTION GENERATION STARTED <<<")
|
328 |
start_time = time.time()
|
329 |
|
330 |
try:
|
331 |
image_bytes = await image.read()
|
332 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
333 |
+
logger.info(">>> IMAGE LOADED SUCCESSFULLY <<<")
|
334 |
except Exception as e:
|
335 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
336 |
return JSONResponse(status_code=500,
|
337 |
content={"error": f"Error reading image: {str(e)}", "code": 500})
|
338 |
|
|
|
340 |
result = product_listing_obj.gen_title_desc(image=image)
|
341 |
title = result.split("Title:")[1].split("Description:")[0]
|
342 |
description = result.split("Description:")[1]
|
343 |
+
logger.info(">>> TITLE AND DESCRIPTION GENERATION COMPLETED <<<")
|
344 |
except Exception as e:
|
345 |
+
logger.error(">>> TITLE DESCRIPTION GENERATION ERROR <<<")
|
346 |
return JSONResponse(status_code=500,
|
347 |
content={"error": "Please make sure the image is clear and necklaces are visible",
|
348 |
"code": 500})
|
|
|
350 |
try:
|
351 |
total_inference_time = round((time.time() - start_time), 2)
|
352 |
|
353 |
+
logger.info(">>> RESPONSE PREPARATION COMPLETED <<<")
|
354 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
355 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
356 |
+
logger.info("-" * 50)
|
357 |
+
|
358 |
return JSONResponse(content={
|
359 |
"code": 200,
|
360 |
"title": title,
|
|
|
362 |
"inference_time": total_inference_time
|
363 |
}, status_code=200)
|
364 |
except Exception as e:
|
365 |
+
logger.error(f">>> RESPONSE PROCESSING ERROR: {str(e)} <<<")
|
366 |
return JSONResponse(status_code=500,
|
367 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
src/api/image_regeneration_api.py
CHANGED
@@ -13,6 +13,7 @@ import requests
|
|
13 |
from PIL import Image
|
14 |
from fastapi import APIRouter, UploadFile, File, Form
|
15 |
from fastapi.responses import JSONResponse
|
|
|
16 |
|
17 |
image_regeneration_router = APIRouter()
|
18 |
|
@@ -48,6 +49,8 @@ async def image_re_gen(
|
|
48 |
reference_image_c4_weight: Optional[float] = Form(default=0.0),
|
49 |
reference_image_c4_stop: Optional[float] = Form(default=0.0),
|
50 |
):
|
|
|
|
|
51 |
start_time = time.time()
|
52 |
|
53 |
try:
|
@@ -60,8 +63,10 @@ async def image_re_gen(
|
|
60 |
reference_image_b64 = base64.b64encode(ref_img_base64.getvalue()).decode("utf-8")
|
61 |
return f"data:image/WEBP;base64,{reference_image_b64}"
|
62 |
return None
|
|
|
63 |
except Exception as e:
|
64 |
-
|
|
|
65 |
content={"error": f"Error processing reference image: {str(e)}", "code": 500})
|
66 |
|
67 |
try:
|
@@ -70,7 +75,9 @@ async def image_re_gen(
|
|
70 |
img_base64 = BytesIO()
|
71 |
image.save(img_base64, format="WEBP")
|
72 |
image_data_uri = f"data:image/WEBP;base64,{base64.b64encode(img_base64.getvalue()).decode('utf-8')}"
|
|
|
73 |
except Exception as e:
|
|
|
74 |
return JSONResponse(status_code=500,
|
75 |
content={"error": f"Error processing main image: {str(e)}", "code": 500})
|
76 |
|
@@ -81,7 +88,9 @@ async def image_re_gen(
|
|
81 |
'c3': await process_reference_image(reference_image_c3),
|
82 |
'c4': await process_reference_image(reference_image_c4)
|
83 |
}
|
|
|
84 |
except Exception as e:
|
|
|
85 |
return JSONResponse(status_code=500,
|
86 |
content={"error": f"Error processing reference images: {str(e)}", "code": 500})
|
87 |
|
@@ -106,7 +115,9 @@ async def image_re_gen(
|
|
106 |
mask_image.save(mask_base64, format="WEBP")
|
107 |
mask_image_data_uri = f"data:image/WEBP;base64,{base64.b64encode(mask_base64.getvalue()).decode('utf-8')}"
|
108 |
input_data["inpaint_input_mask"] = mask_image_data_uri
|
|
|
109 |
except Exception as e:
|
|
|
110 |
return JSONResponse(status_code=500,
|
111 |
content={"error": f"Error preparing input data: {str(e)}", "code": 500})
|
112 |
|
@@ -127,7 +138,9 @@ async def image_re_gen(
|
|
127 |
stop_value = locals()[f'reference_image_{c}_stop']
|
128 |
if stop_value != 0.0 or stop_value != 0:
|
129 |
input_data[f"cn_stop{i}"] = stop_value
|
|
|
130 |
except Exception as e:
|
|
|
131 |
return JSONResponse(status_code=500,
|
132 |
content={"error": f"Error processing reference image parameters: {str(e)}", "code": 500})
|
133 |
|
@@ -136,18 +149,24 @@ async def image_re_gen(
|
|
136 |
response = requests.get(output[0])
|
137 |
output_base64 = base64.b64encode(response.content).decode('utf-8')
|
138 |
base64_prefix = image_data_uri.split(",")[0] + ","
|
|
|
139 |
except Exception as e:
|
|
|
140 |
return JSONResponse(status_code=500,
|
141 |
content={"error": f"Error generating image: {str(e)}", "code": 500})
|
142 |
|
143 |
try:
|
144 |
-
inference_time = time.time() - start_time
|
145 |
response = {
|
146 |
"output": f"{base64_prefix}{output_base64}",
|
147 |
"inference_time": inference_time,
|
148 |
"code": 200,
|
149 |
}
|
|
|
|
|
|
|
150 |
return JSONResponse(content=response, status_code=200)
|
151 |
except Exception as e:
|
|
|
152 |
return JSONResponse(status_code=500,
|
153 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
|
|
13 |
from PIL import Image
|
14 |
from fastapi import APIRouter, UploadFile, File, Form
|
15 |
from fastapi.responses import JSONResponse
|
16 |
+
from src.utils import logger
|
17 |
|
18 |
image_regeneration_router = APIRouter()
|
19 |
|
|
|
49 |
reference_image_c4_weight: Optional[float] = Form(default=0.0),
|
50 |
reference_image_c4_stop: Optional[float] = Form(default=0.0),
|
51 |
):
|
52 |
+
logger.info("-" * 50)
|
53 |
+
logger.info(">>> IMAGE REDESIGN STARTED <<<")
|
54 |
start_time = time.time()
|
55 |
|
56 |
try:
|
|
|
63 |
reference_image_b64 = base64.b64encode(ref_img_base64.getvalue()).decode("utf-8")
|
64 |
return f"data:image/WEBP;base64,{reference_image_b64}"
|
65 |
return None
|
66 |
+
logger.info(">>> REFERENCE IMAGE PROCESSING FUNCTION INITIALIZED <<<")
|
67 |
except Exception as e:
|
68 |
+
logger.error(f">>> REFERENCE IMAGE PROCESSING ERROR: {str(e)} <<<")
|
69 |
+
return JSONResponse(status_code=500,
|
70 |
content={"error": f"Error processing reference image: {str(e)}", "code": 500})
|
71 |
|
72 |
try:
|
|
|
75 |
img_base64 = BytesIO()
|
76 |
image.save(img_base64, format="WEBP")
|
77 |
image_data_uri = f"data:image/WEBP;base64,{base64.b64encode(img_base64.getvalue()).decode('utf-8')}"
|
78 |
+
logger.info(">>> MAIN IMAGE PROCESSED SUCCESSFULLY <<<")
|
79 |
except Exception as e:
|
80 |
+
logger.error(f">>> MAIN IMAGE PROCESSING ERROR: {str(e)} <<<")
|
81 |
return JSONResponse(status_code=500,
|
82 |
content={"error": f"Error processing main image: {str(e)}", "code": 500})
|
83 |
|
|
|
88 |
'c3': await process_reference_image(reference_image_c3),
|
89 |
'c4': await process_reference_image(reference_image_c4)
|
90 |
}
|
91 |
+
logger.info(">>> REFERENCE IMAGES PROCESSED SUCCESSFULLY <<<")
|
92 |
except Exception as e:
|
93 |
+
logger.error(f">>> REFERENCE IMAGES PROCESSING ERROR: {str(e)} <<<")
|
94 |
return JSONResponse(status_code=500,
|
95 |
content={"error": f"Error processing reference images: {str(e)}", "code": 500})
|
96 |
|
|
|
115 |
mask_image.save(mask_base64, format="WEBP")
|
116 |
mask_image_data_uri = f"data:image/WEBP;base64,{base64.b64encode(mask_base64.getvalue()).decode('utf-8')}"
|
117 |
input_data["inpaint_input_mask"] = mask_image_data_uri
|
118 |
+
logger.info(">>> INPUT DATA PREPARED SUCCESSFULLY <<<")
|
119 |
except Exception as e:
|
120 |
+
logger.error(f">>> INPUT DATA PREPARATION ERROR: {str(e)} <<<")
|
121 |
return JSONResponse(status_code=500,
|
122 |
content={"error": f"Error preparing input data: {str(e)}", "code": 500})
|
123 |
|
|
|
138 |
stop_value = locals()[f'reference_image_{c}_stop']
|
139 |
if stop_value != 0.0 or stop_value != 0:
|
140 |
input_data[f"cn_stop{i}"] = stop_value
|
141 |
+
logger.info(">>> REFERENCE IMAGE PARAMETERS PROCESSED <<<")
|
142 |
except Exception as e:
|
143 |
+
logger.error(f">>> REFERENCE IMAGE PARAMETERS ERROR: {str(e)} <<<")
|
144 |
return JSONResponse(status_code=500,
|
145 |
content={"error": f"Error processing reference image parameters: {str(e)}", "code": 500})
|
146 |
|
|
|
149 |
response = requests.get(output[0])
|
150 |
output_base64 = base64.b64encode(response.content).decode('utf-8')
|
151 |
base64_prefix = image_data_uri.split(",")[0] + ","
|
152 |
+
logger.info(">>> IMAGE REGENERATION COMPLETED <<<")
|
153 |
except Exception as e:
|
154 |
+
logger.error(f">>> IMAGE REGENERATION ERROR: {str(e)} <<<")
|
155 |
return JSONResponse(status_code=500,
|
156 |
content={"error": f"Error generating image: {str(e)}", "code": 500})
|
157 |
|
158 |
try:
|
159 |
+
inference_time = round(time.time() - start_time, 2)
|
160 |
response = {
|
161 |
"output": f"{base64_prefix}{output_base64}",
|
162 |
"inference_time": inference_time,
|
163 |
"code": 200,
|
164 |
}
|
165 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {inference_time}s <<<")
|
166 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
167 |
+
logger.info("-" * 50)
|
168 |
return JSONResponse(content=response, status_code=200)
|
169 |
except Exception as e:
|
170 |
+
logger.error(f">>> RESPONSE CREATION ERROR: {str(e)} <<<")
|
171 |
return JSONResponse(status_code=500,
|
172 |
content={"error": f"Error creating response: {str(e)}", "code": 500})
|
src/api/nto_api.py
CHANGED
@@ -22,6 +22,7 @@ import os
|
|
22 |
from pydantic import BaseModel
|
23 |
import replicate
|
24 |
import requests
|
|
|
25 |
|
26 |
pipeline = Pipeline()
|
27 |
|
@@ -55,18 +56,25 @@ class NecklaceTryOnIDEntity(BaseModel):
|
|
55 |
|
56 |
@nto_cto_router.post("/clothingTryOnV2")
|
57 |
async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str = Form(...)):
|
|
|
|
|
58 |
start_time = time.time()
|
|
|
59 |
try:
|
60 |
image_bytes = await image.read()
|
61 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
|
|
62 |
except Exception as e:
|
|
|
63 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
64 |
|
65 |
try:
|
66 |
mask = await pipeline.shoulderPointMaskGeneration_(image=image)
|
|
|
67 |
except Exception as e:
|
|
|
68 |
return JSONResponse(status_code=500,
|
69 |
-
|
70 |
|
71 |
try:
|
72 |
mask_img_base_64, act_img_base_64 = BytesIO(), BytesIO()
|
@@ -77,9 +85,11 @@ async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str =
|
|
77 |
|
78 |
mask_data_uri = f"data:image/webp;base64,{mask_bytes_}"
|
79 |
image_data_uri = f"data:image/webp;base64,{image_bytes_}"
|
|
|
80 |
except Exception as e:
|
|
|
81 |
return JSONResponse(status_code=500,
|
82 |
-
|
83 |
|
84 |
input = {
|
85 |
"mask": mask_data_uri,
|
@@ -91,10 +101,15 @@ async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str =
|
|
91 |
|
92 |
try:
|
93 |
output = replicate_run_cto(input)
|
|
|
94 |
except Exception as e:
|
|
|
95 |
return JSONResponse(content={"error": f"Error running CTO Replicate: {str(e)}", "code": 500}, status_code=500)
|
96 |
|
97 |
total_inference_time = round((time.time() - start_time), 2)
|
|
|
|
|
|
|
98 |
|
99 |
response = {
|
100 |
"code": 200,
|
@@ -108,12 +123,17 @@ async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str =
|
|
108 |
@nto_cto_router.post("/clothingTryOn")
|
109 |
async def clothing_try_on(image: UploadFile = File(...),
|
110 |
mask: UploadFile = File(...), clothing_type: str = Form(...)):
|
|
|
|
|
111 |
start_time = time.time()
|
|
|
112 |
try:
|
113 |
image_bytes = await image.read()
|
114 |
mask_bytes = await mask.read()
|
115 |
image, mask = Image.open(BytesIO(image_bytes)).convert("RGB"), Image.open(BytesIO(mask_bytes)).convert("RGB")
|
|
|
116 |
except Exception as e:
|
|
|
117 |
return JSONResponse(status_code=500, content={"error": f"Error reading image or mask: {str(e)}", "code": 500})
|
118 |
|
119 |
try:
|
@@ -129,7 +149,9 @@ async def clothing_try_on(image: UploadFile = File(...),
|
|
129 |
arr[mask_y:, :] = 255
|
130 |
|
131 |
mask = Image.fromarray(arr).resize((512, 512))
|
|
|
132 |
except Exception as e:
|
|
|
133 |
return JSONResponse(status_code=500,
|
134 |
content={"error": f"Error processing image or mask: {str(e)}", "code": 500})
|
135 |
|
@@ -142,7 +164,9 @@ async def clothing_try_on(image: UploadFile = File(...),
|
|
142 |
|
143 |
mask_data_uri = f"data:image/webp;base64,{mask_bytes_}"
|
144 |
image_data_uri = f"data:image/webp;base64,{image_bytes_}"
|
|
|
145 |
except Exception as e:
|
|
|
146 |
return JSONResponse(status_code=500,
|
147 |
content={"error": f"Error encoding images to base64: {str(e)}", "code": 500})
|
148 |
|
@@ -156,8 +180,11 @@ async def clothing_try_on(image: UploadFile = File(...),
|
|
156 |
|
157 |
try:
|
158 |
output = replicate_run_cto(input)
|
|
|
159 |
except Exception as e:
|
|
|
160 |
return JSONResponse(content={"error": f"Error running CTO Replicate: {str(e)}", "code": 500}, status_code=500)
|
|
|
161 |
try:
|
162 |
response = requests.get(output[0])
|
163 |
output_image = Image.open(BytesIO(response.content)).resize(actual_image.size)
|
@@ -169,6 +196,7 @@ async def clothing_try_on(image: UploadFile = File(...),
|
|
169 |
result.save(in_mem_file, format="WEBP", quality=85)
|
170 |
base_64_output = base64.b64encode(in_mem_file.getvalue()).decode('utf-8')
|
171 |
total_inference_time = round((time.time() - start_time), 2)
|
|
|
172 |
|
173 |
response = {
|
174 |
"output": f"data:image/WEBP;base64,{base_64_output}",
|
@@ -176,10 +204,14 @@ async def clothing_try_on(image: UploadFile = File(...),
|
|
176 |
"inference_time": total_inference_time
|
177 |
}
|
178 |
except Exception as e:
|
|
|
179 |
return JSONResponse(status_code=500, content={"error": f"Error processing output image: {str(e)}", "code": 500})
|
180 |
|
181 |
-
|
|
|
|
|
182 |
|
|
|
183 |
|
184 |
@nto_cto_router.post("/productData/{storeId}")
|
185 |
async def product_data(
|
@@ -327,21 +359,29 @@ async def parse_necklace_try_on_id(necklaceImageId: str = Form(...),
|
|
327 |
@nto_cto_router.post("/necklaceTryOnID")
|
328 |
async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends(parse_necklace_try_on_id),
|
329 |
image: UploadFile = File(...)):
|
|
|
|
|
330 |
start_time = time.time()
|
|
|
331 |
try:
|
332 |
data, _ = supabase.table("APIKeyList").select("*").filter("API_KEY", "eq",
|
333 |
necklace_try_on_id.api_token).execute()
|
334 |
api_key_actual = data[1][0]['API_KEY']
|
335 |
if api_key_actual != necklace_try_on_id.api_token:
|
|
|
336 |
return JSONResponse(content={"error": "Invalid API Key"}, status_code=401)
|
|
|
337 |
except Exception as e:
|
|
|
338 |
return JSONResponse(content={"error": f"Error validating API key: {str(e)}", "code": 500}, status_code=500)
|
339 |
|
340 |
try:
|
341 |
imageBytes = await image.read()
|
342 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
343 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
|
|
344 |
except Exception as e:
|
|
|
345 |
return JSONResponse(content={
|
346 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
347 |
"code": 404}, status_code=404)
|
@@ -349,7 +389,9 @@ async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends
|
|
349 |
try:
|
350 |
result, headetText, mask = await pipeline.necklaceTryOn_(image=image, jewellery=jewellery,
|
351 |
storename=necklace_try_on_id.storename)
|
|
|
352 |
except Exception as e:
|
|
|
353 |
return JSONResponse(content={"error": f"Error during necklace try-on process: {str(e)}", "code": 500},
|
354 |
status_code=500)
|
355 |
|
@@ -360,7 +402,9 @@ async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends
|
|
360 |
mask.save(inMemFileMask, format="WEBP", quality=85)
|
361 |
outputBytes = inMemFile.getvalue()
|
362 |
maskBytes = inMemFileMask.getvalue()
|
|
|
363 |
except Exception as e:
|
|
|
364 |
return JSONResponse(content={"error": f"Error saving result images: {str(e)}", "code": 500}, status_code=500)
|
365 |
|
366 |
try:
|
@@ -373,22 +417,34 @@ async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends
|
|
373 |
"inference_time": total_backend_time
|
374 |
}
|
375 |
if creditResponse == "No Credits Available":
|
|
|
376 |
response = {"error": "No Credits Remaining"}
|
377 |
return JSONResponse(content=response, status_code=402)
|
|
|
378 |
except Exception as e:
|
|
|
379 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
380 |
|
381 |
-
|
|
|
|
|
382 |
|
|
|
383 |
|
384 |
@nto_cto_router.post("/canvasPoints")
|
385 |
async def canvas_points(necklace_try_on_id: NecklaceTryOnIDEntity = Depends(parse_necklace_try_on_id),
|
386 |
image: UploadFile = File(...)):
|
|
|
|
|
|
|
|
|
387 |
try:
|
388 |
imageBytes = await image.read()
|
389 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
390 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
|
|
391 |
except Exception as e:
|
|
|
392 |
return JSONResponse(content={
|
393 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
394 |
"code": 404}, status_code=404)
|
@@ -396,18 +452,28 @@ async def canvas_points(necklace_try_on_id: NecklaceTryOnIDEntity = Depends(pars
|
|
396 |
try:
|
397 |
response = await pipeline.canvasPoint(image=image, jewellery=jewellery, storename=necklace_try_on_id.storename)
|
398 |
response = {"code": 200, "output": response}
|
|
|
399 |
except Exception as e:
|
|
|
400 |
return JSONResponse(content={"error": f"Error during canvas point process: {str(e)}", "code": 500},
|
401 |
status_code=500)
|
402 |
|
403 |
try:
|
404 |
creditResponse = deductAndTrackCredit(storename=necklace_try_on_id.storename, endpoint="/necklaceTryOnID")
|
405 |
if creditResponse == "No Credits Available":
|
|
|
406 |
return JSONResponse(content={"error": "No Credits Remaining", "code": 402}, status_code=402)
|
|
|
407 |
except Exception as e:
|
|
|
408 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
409 |
|
410 |
-
|
|
|
|
|
|
|
|
|
|
|
411 |
|
412 |
|
413 |
@nto_cto_router.post("/necklaceTryOnWithPoints")
|
@@ -417,12 +483,17 @@ async def necklace_try_on_with_points(necklace_try_on_id: NecklaceTryOnIDEntity
|
|
417 |
left_y: int = Form(...),
|
418 |
right_x: int = Form(...),
|
419 |
right_y: int = Form(...)):
|
|
|
|
|
420 |
start_time = time.time()
|
|
|
421 |
try:
|
422 |
imageBytes = await image.read()
|
423 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
424 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
|
|
425 |
except Exception as e:
|
|
|
426 |
return JSONResponse(content={
|
427 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
428 |
"code": 404}, status_code=404)
|
@@ -432,7 +503,9 @@ async def necklace_try_on_with_points(necklace_try_on_id: NecklaceTryOnIDEntity
|
|
432 |
image=image, jewellery=jewellery, left_shoulder=(left_x, left_y), right_shoulder=(right_x, right_y),
|
433 |
storename=necklace_try_on_id.storename
|
434 |
)
|
|
|
435 |
except Exception as e:
|
|
|
436 |
return JSONResponse(content={"error": f"Error during necklace try-on process: {str(e)}", "code": 500},
|
437 |
status_code=500)
|
438 |
|
@@ -443,7 +516,9 @@ async def necklace_try_on_with_points(necklace_try_on_id: NecklaceTryOnIDEntity
|
|
443 |
mask.save(inMemFileMask, format="WEBP", quality=85)
|
444 |
outputBytes = inMemFile.getvalue()
|
445 |
maskBytes = inMemFileMask.getvalue()
|
|
|
446 |
except Exception as e:
|
|
|
447 |
return JSONResponse(content={"error": f"Error saving result images: {str(e)}", "code": 500}, status_code=500)
|
448 |
|
449 |
try:
|
@@ -456,9 +531,16 @@ async def necklace_try_on_with_points(necklace_try_on_id: NecklaceTryOnIDEntity
|
|
456 |
"inference_time": total_inference_time
|
457 |
}
|
458 |
if creditResponse == "No Credits Available":
|
|
|
459 |
response = {"error": "No Credits Remaining"}
|
460 |
return JSONResponse(content=response, status_code=402)
|
|
|
461 |
except Exception as e:
|
|
|
462 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
463 |
|
|
|
|
|
|
|
|
|
464 |
return JSONResponse(content=response, status_code=200)
|
|
|
22 |
from pydantic import BaseModel
|
23 |
import replicate
|
24 |
import requests
|
25 |
+
from src.utils.logger import logger
|
26 |
|
27 |
pipeline = Pipeline()
|
28 |
|
|
|
56 |
|
57 |
@nto_cto_router.post("/clothingTryOnV2")
|
58 |
async def clothing_try_on_v2(image: UploadFile = File(...), clothing_type: str = Form(...)):
|
59 |
+
logger.info("-" * 50)
|
60 |
+
logger.info(">>> CLOTHING TRY ON V2 STARTED <<<")
|
61 |
start_time = time.time()
|
62 |
+
|
63 |
try:
|
64 |
image_bytes = await image.read()
|
65 |
image = Image.open(BytesIO(image_bytes)).convert("RGB")
|
66 |
+
logger.info(">>> IMAGE LOADED SUCCESSFULLY <<<")
|
67 |
except Exception as e:
|
68 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
69 |
return JSONResponse(status_code=500, content={"error": f"Error reading image: {str(e)}", "code": 500})
|
70 |
|
71 |
try:
|
72 |
mask = await pipeline.shoulderPointMaskGeneration_(image=image)
|
73 |
+
logger.info(">>> MASK GENERATION COMPLETED <<<")
|
74 |
except Exception as e:
|
75 |
+
logger.error(f">>> MASK GENERATION ERROR: {str(e)} <<<")
|
76 |
return JSONResponse(status_code=500,
|
77 |
+
content={"error": f"Error generating mask: {str(e)}", "code": 500})
|
78 |
|
79 |
try:
|
80 |
mask_img_base_64, act_img_base_64 = BytesIO(), BytesIO()
|
|
|
85 |
|
86 |
mask_data_uri = f"data:image/webp;base64,{mask_bytes_}"
|
87 |
image_data_uri = f"data:image/webp;base64,{image_bytes_}"
|
88 |
+
logger.info(">>> IMAGE ENCODING COMPLETED <<<")
|
89 |
except Exception as e:
|
90 |
+
logger.error(f">>> IMAGE ENCODING ERROR: {str(e)} <<<")
|
91 |
return JSONResponse(status_code=500,
|
92 |
+
content={"error": f"Error converting images to base64: {str(e)}", "code": 500})
|
93 |
|
94 |
input = {
|
95 |
"mask": mask_data_uri,
|
|
|
101 |
|
102 |
try:
|
103 |
output = replicate_run_cto(input)
|
104 |
+
logger.info(">>> REPLICATE PROCESSING COMPLETED <<<")
|
105 |
except Exception as e:
|
106 |
+
logger.error(f">>> REPLICATE PROCESSING ERROR: {str(e)} <<<")
|
107 |
return JSONResponse(content={"error": f"Error running CTO Replicate: {str(e)}", "code": 500}, status_code=500)
|
108 |
|
109 |
total_inference_time = round((time.time() - start_time), 2)
|
110 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
111 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
112 |
+
logger.info("-" * 50)
|
113 |
|
114 |
response = {
|
115 |
"code": 200,
|
|
|
123 |
@nto_cto_router.post("/clothingTryOn")
|
124 |
async def clothing_try_on(image: UploadFile = File(...),
|
125 |
mask: UploadFile = File(...), clothing_type: str = Form(...)):
|
126 |
+
logger.info("-" * 50)
|
127 |
+
logger.info(">>> CLOTHING TRY ON STARTED <<<")
|
128 |
start_time = time.time()
|
129 |
+
|
130 |
try:
|
131 |
image_bytes = await image.read()
|
132 |
mask_bytes = await mask.read()
|
133 |
image, mask = Image.open(BytesIO(image_bytes)).convert("RGB"), Image.open(BytesIO(mask_bytes)).convert("RGB")
|
134 |
+
logger.info(">>> IMAGES LOADED SUCCESSFULLY <<<")
|
135 |
except Exception as e:
|
136 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
137 |
return JSONResponse(status_code=500, content={"error": f"Error reading image or mask: {str(e)}", "code": 500})
|
138 |
|
139 |
try:
|
|
|
149 |
arr[mask_y:, :] = 255
|
150 |
|
151 |
mask = Image.fromarray(arr).resize((512, 512))
|
152 |
+
logger.info(">>> IMAGE PROCESSING COMPLETED <<<")
|
153 |
except Exception as e:
|
154 |
+
logger.error(f">>> IMAGE PROCESSING ERROR: {str(e)} <<<")
|
155 |
return JSONResponse(status_code=500,
|
156 |
content={"error": f"Error processing image or mask: {str(e)}", "code": 500})
|
157 |
|
|
|
164 |
|
165 |
mask_data_uri = f"data:image/webp;base64,{mask_bytes_}"
|
166 |
image_data_uri = f"data:image/webp;base64,{image_bytes_}"
|
167 |
+
logger.info(">>> IMAGE ENCODING COMPLETED <<<")
|
168 |
except Exception as e:
|
169 |
+
logger.error(f">>> IMAGE ENCODING ERROR: {str(e)} <<<")
|
170 |
return JSONResponse(status_code=500,
|
171 |
content={"error": f"Error encoding images to base64: {str(e)}", "code": 500})
|
172 |
|
|
|
180 |
|
181 |
try:
|
182 |
output = replicate_run_cto(input)
|
183 |
+
logger.info(">>> REPLICATE PROCESSING COMPLETED <<<")
|
184 |
except Exception as e:
|
185 |
+
logger.error(f">>> REPLICATE PROCESSING ERROR: {str(e)} <<<")
|
186 |
return JSONResponse(content={"error": f"Error running CTO Replicate: {str(e)}", "code": 500}, status_code=500)
|
187 |
+
|
188 |
try:
|
189 |
response = requests.get(output[0])
|
190 |
output_image = Image.open(BytesIO(response.content)).resize(actual_image.size)
|
|
|
196 |
result.save(in_mem_file, format="WEBP", quality=85)
|
197 |
base_64_output = base64.b64encode(in_mem_file.getvalue()).decode('utf-8')
|
198 |
total_inference_time = round((time.time() - start_time), 2)
|
199 |
+
logger.info(">>> OUTPUT IMAGE PROCESSING COMPLETED <<<")
|
200 |
|
201 |
response = {
|
202 |
"output": f"data:image/WEBP;base64,{base_64_output}",
|
|
|
204 |
"inference_time": total_inference_time
|
205 |
}
|
206 |
except Exception as e:
|
207 |
+
logger.error(f">>> OUTPUT IMAGE PROCESSING ERROR: {str(e)} <<<")
|
208 |
return JSONResponse(status_code=500, content={"error": f"Error processing output image: {str(e)}", "code": 500})
|
209 |
|
210 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
211 |
+
logger.info(">>> REQUEST COMPLETED SUCCESSFULLY <<<")
|
212 |
+
logger.info("-" * 50)
|
213 |
|
214 |
+
return JSONResponse(content=response, status_code=200)
|
215 |
|
216 |
@nto_cto_router.post("/productData/{storeId}")
|
217 |
async def product_data(
|
|
|
359 |
@nto_cto_router.post("/necklaceTryOnID")
|
360 |
async def necklace_try_on_id(necklace_try_on_id: NecklaceTryOnIDEntity = Depends(parse_necklace_try_on_id),
|
361 |
image: UploadFile = File(...)):
|
362 |
+
logger.info("-" * 50)
|
363 |
+
logger.info(f">>> NECKLACE TRY ON ID STARTED :: {necklace_try_on_id.storename} <<<")
|
364 |
start_time = time.time()
|
365 |
+
|
366 |
try:
|
367 |
data, _ = supabase.table("APIKeyList").select("*").filter("API_KEY", "eq",
|
368 |
necklace_try_on_id.api_token).execute()
|
369 |
api_key_actual = data[1][0]['API_KEY']
|
370 |
if api_key_actual != necklace_try_on_id.api_token:
|
371 |
+
logger.error(">>> API KEY VALIDATION FAILED <<<")
|
372 |
return JSONResponse(content={"error": "Invalid API Key"}, status_code=401)
|
373 |
+
logger.info(">>> API KEY VALIDATION SUCCESSFUL <<<")
|
374 |
except Exception as e:
|
375 |
+
logger.error(f">>> API KEY VALIDATION ERROR: {str(e)} <<<")
|
376 |
return JSONResponse(content={"error": f"Error validating API key: {str(e)}", "code": 500}, status_code=500)
|
377 |
|
378 |
try:
|
379 |
imageBytes = await image.read()
|
380 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
381 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
382 |
+
logger.info(">>> IMAGES LOADED SUCCESSFULLY <<<")
|
383 |
except Exception as e:
|
384 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
385 |
return JSONResponse(content={
|
386 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
387 |
"code": 404}, status_code=404)
|
|
|
389 |
try:
|
390 |
result, headetText, mask = await pipeline.necklaceTryOn_(image=image, jewellery=jewellery,
|
391 |
storename=necklace_try_on_id.storename)
|
392 |
+
logger.info(">>> NECKLACE TRY ON PROCESSING COMPLETED <<<")
|
393 |
except Exception as e:
|
394 |
+
logger.error(f">>> NECKLACE TRY ON PROCESSING ERROR: {str(e)} <<<")
|
395 |
return JSONResponse(content={"error": f"Error during necklace try-on process: {str(e)}", "code": 500},
|
396 |
status_code=500)
|
397 |
|
|
|
402 |
mask.save(inMemFileMask, format="WEBP", quality=85)
|
403 |
outputBytes = inMemFile.getvalue()
|
404 |
maskBytes = inMemFileMask.getvalue()
|
405 |
+
logger.info(">>> RESULT IMAGES SAVED <<<")
|
406 |
except Exception as e:
|
407 |
+
logger.error(f">>> RESULT SAVING ERROR: {str(e)} <<<")
|
408 |
return JSONResponse(content={"error": f"Error saving result images: {str(e)}", "code": 500}, status_code=500)
|
409 |
|
410 |
try:
|
|
|
417 |
"inference_time": total_backend_time
|
418 |
}
|
419 |
if creditResponse == "No Credits Available":
|
420 |
+
logger.error(">>> NO CREDITS REMAINING <<<")
|
421 |
response = {"error": "No Credits Remaining"}
|
422 |
return JSONResponse(content=response, status_code=402)
|
423 |
+
logger.info(">>> CREDITS DEDUCTED SUCCESSFULLY <<<")
|
424 |
except Exception as e:
|
425 |
+
logger.error(f">>> CREDIT DEDUCTION ERROR: {str(e)} <<<")
|
426 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
427 |
|
428 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_backend_time}s <<<")
|
429 |
+
logger.info(f">>> NECKLACE TRY ON COMPLETED :: {necklace_try_on_id.storename} <<<")
|
430 |
+
logger.info("-" * 50)
|
431 |
|
432 |
+
return JSONResponse(content=response, status_code=200)
|
433 |
|
434 |
@nto_cto_router.post("/canvasPoints")
|
435 |
async def canvas_points(necklace_try_on_id: NecklaceTryOnIDEntity = Depends(parse_necklace_try_on_id),
|
436 |
image: UploadFile = File(...)):
|
437 |
+
logger.info("-" * 50)
|
438 |
+
logger.info(f">>> CANVAS POINTS STARTED :: {necklace_try_on_id.storename} <<<")
|
439 |
+
start_time = time.time()
|
440 |
+
|
441 |
try:
|
442 |
imageBytes = await image.read()
|
443 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
444 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
445 |
+
logger.info(">>> IMAGES LOADED SUCCESSFULLY <<<")
|
446 |
except Exception as e:
|
447 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
448 |
return JSONResponse(content={
|
449 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
450 |
"code": 404}, status_code=404)
|
|
|
452 |
try:
|
453 |
response = await pipeline.canvasPoint(image=image, jewellery=jewellery, storename=necklace_try_on_id.storename)
|
454 |
response = {"code": 200, "output": response}
|
455 |
+
logger.info(">>> CANVAS POINTS PROCESSING COMPLETED <<<")
|
456 |
except Exception as e:
|
457 |
+
logger.error(f">>> CANVAS POINTS PROCESSING ERROR: {str(e)} <<<")
|
458 |
return JSONResponse(content={"error": f"Error during canvas point process: {str(e)}", "code": 500},
|
459 |
status_code=500)
|
460 |
|
461 |
try:
|
462 |
creditResponse = deductAndTrackCredit(storename=necklace_try_on_id.storename, endpoint="/necklaceTryOnID")
|
463 |
if creditResponse == "No Credits Available":
|
464 |
+
logger.error(">>> NO CREDITS REMAINING <<<")
|
465 |
return JSONResponse(content={"error": "No Credits Remaining", "code": 402}, status_code=402)
|
466 |
+
logger.info(">>> CREDITS DEDUCTED SUCCESSFULLY <<<")
|
467 |
except Exception as e:
|
468 |
+
logger.error(f">>> CREDIT DEDUCTION ERROR: {str(e)} <<<")
|
469 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
470 |
|
471 |
+
total_inference_time = round((time.time() - start_time), 2)
|
472 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
473 |
+
logger.info(f">>> CANVAS POINTS COMPLETED :: {necklace_try_on_id.storename} <<<")
|
474 |
+
logger.info("-" * 50)
|
475 |
+
|
476 |
+
return JSONResponse(status_code=200, content=response)
|
477 |
|
478 |
|
479 |
@nto_cto_router.post("/necklaceTryOnWithPoints")
|
|
|
483 |
left_y: int = Form(...),
|
484 |
right_x: int = Form(...),
|
485 |
right_y: int = Form(...)):
|
486 |
+
logger.info("-" * 50)
|
487 |
+
logger.info(f">>> NECKLACE TRY ON WITH POINTS STARTED :: {necklace_try_on_id.storename} <<<")
|
488 |
start_time = time.time()
|
489 |
+
|
490 |
try:
|
491 |
imageBytes = await image.read()
|
492 |
jewellery_url = f"https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/Stores/{necklace_try_on_id.storename}/{necklace_try_on_id.necklaceCategory}/image/{necklace_try_on_id.necklaceImageId}.png"
|
493 |
image, jewellery = Image.open(BytesIO(imageBytes)), Image.open(returnBytesData(url=jewellery_url))
|
494 |
+
logger.info(">>> IMAGES LOADED SUCCESSFULLY <<<")
|
495 |
except Exception as e:
|
496 |
+
logger.error(f">>> IMAGE LOADING ERROR: {str(e)} <<<")
|
497 |
return JSONResponse(content={
|
498 |
"error": f"The requested resource (Image, necklace category, or store) is not available. Please verify the availability and try again. Error: {str(e)}",
|
499 |
"code": 404}, status_code=404)
|
|
|
503 |
image=image, jewellery=jewellery, left_shoulder=(left_x, left_y), right_shoulder=(right_x, right_y),
|
504 |
storename=necklace_try_on_id.storename
|
505 |
)
|
506 |
+
logger.info(">>> NECKLACE TRY ON PROCESSING COMPLETED <<<")
|
507 |
except Exception as e:
|
508 |
+
logger.error(f">>> NECKLACE TRY ON PROCESSING ERROR: {str(e)} <<<")
|
509 |
return JSONResponse(content={"error": f"Error during necklace try-on process: {str(e)}", "code": 500},
|
510 |
status_code=500)
|
511 |
|
|
|
516 |
mask.save(inMemFileMask, format="WEBP", quality=85)
|
517 |
outputBytes = inMemFile.getvalue()
|
518 |
maskBytes = inMemFileMask.getvalue()
|
519 |
+
logger.info(">>> RESULT IMAGES SAVED <<<")
|
520 |
except Exception as e:
|
521 |
+
logger.error(f">>> RESULT SAVING ERROR: {str(e)} <<<")
|
522 |
return JSONResponse(content={"error": f"Error saving result images: {str(e)}", "code": 500}, status_code=500)
|
523 |
|
524 |
try:
|
|
|
531 |
"inference_time": total_inference_time
|
532 |
}
|
533 |
if creditResponse == "No Credits Available":
|
534 |
+
logger.error(">>> NO CREDITS REMAINING <<<")
|
535 |
response = {"error": "No Credits Remaining"}
|
536 |
return JSONResponse(content=response, status_code=402)
|
537 |
+
logger.info(">>> CREDITS DEDUCTED SUCCESSFULLY <<<")
|
538 |
except Exception as e:
|
539 |
+
logger.error(f">>> CREDIT DEDUCTION ERROR: {str(e)} <<<")
|
540 |
return JSONResponse(content={"error": f"Error deducting credits: {str(e)}", "code": 500}, status_code=500)
|
541 |
|
542 |
+
logger.info(f">>> TOTAL INFERENCE TIME: {total_inference_time}s <<<")
|
543 |
+
logger.info(f">>> NECKLACE TRY ON WITH POINTS COMPLETED :: {necklace_try_on_id.storename} <<<")
|
544 |
+
logger.info("-" * 50)
|
545 |
+
|
546 |
return JSONResponse(content=response, status_code=200)
|