codewithRiz commited on
Commit
b177e35
Β·
1 Parent(s): f98ae68
Files changed (2) hide show
  1. api/detection.py +175 -3
  2. api/main.py +1 -1
api/detection.py CHANGED
@@ -1,7 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from fastapi import APIRouter, UploadFile, File, Form, HTTPException
 
2
  from pathlib import Path
 
3
  import cv2
4
  import numpy as np
 
5
 
6
  from .config import UPLOAD_DIR
7
  from .utils import (
@@ -10,10 +68,15 @@ from .utils import (
10
  save_image,
11
  load_json,
12
  save_json,
13
- validate_user_and_camera,extract_metadata
 
14
  )
15
 
16
  router = APIRouter()
 
 
 
 
17
  @router.post("/predict")
18
  async def predict(
19
  user_id: str = Form(...),
@@ -23,7 +86,7 @@ async def predict(
23
  images = validate_form(user_id, camera_name, images)
24
  validate_user_and_camera(user_id, camera_name)
25
  base = Path(UPLOAD_DIR) / user_id / camera_name
26
- base.mkdir(parents=True, exist_ok=True)
27
  json_path = base / f"{camera_name}_detections.json"
28
  data = load_json(json_path)
29
  new_results = []
@@ -40,7 +103,7 @@ async def predict(
40
  "filename": file.filename,
41
  "image_url": url,
42
  "detections": detections,
43
- "metadata": metadata
44
  }
45
  data.append(record)
46
  new_results.append(record)
@@ -50,3 +113,112 @@ async def predict(
50
  "camera": camera_name,
51
  "results": new_results
52
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from fastapi import APIRouter, UploadFile, File, Form, HTTPException
2
+ # from pathlib import Path
3
+ # import cv2
4
+ # import numpy as np
5
+
6
+ # from .config import UPLOAD_DIR
7
+ # from .utils import (
8
+ # validate_form,
9
+ # process_image,
10
+ # save_image,
11
+ # load_json,
12
+ # save_json,
13
+ # validate_user_and_camera,extract_metadata
14
+ # )
15
+
16
+ # router = APIRouter()
17
+ # @router.post("/predict")
18
+ # async def predict(
19
+ # user_id: str = Form(...),
20
+ # camera_name: str = Form(...),
21
+ # images: list[UploadFile] = File(...)
22
+ # ):
23
+ # images = validate_form(user_id, camera_name, images)
24
+ # validate_user_and_camera(user_id, camera_name)
25
+ # base = Path(UPLOAD_DIR) / user_id / camera_name
26
+ # base.mkdir(parents=True, exist_ok=True)
27
+ # json_path = base / f"{camera_name}_detections.json"
28
+ # data = load_json(json_path)
29
+ # new_results = []
30
+ # for file in images:
31
+ # raw = await file.read()
32
+ # metadata = extract_metadata(raw)
33
+ # nparr = np.frombuffer(raw, np.uint8)
34
+ # img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
35
+ # if img is None:
36
+ # raise HTTPException(400, f"Invalid image: {file.filename}")
37
+ # detections = process_image(img)
38
+ # url = save_image(user_id, camera_name, file.filename, raw)
39
+ # record = {
40
+ # "filename": file.filename,
41
+ # "image_url": url,
42
+ # "detections": detections,
43
+ # "metadata": metadata
44
+ # }
45
+ # data.append(record)
46
+ # new_results.append(record)
47
+ # save_json(json_path, data)
48
+ # return {
49
+ # "message": "Images processed successfully",
50
+ # "camera": camera_name,
51
+ # "results": new_results
52
+ # }
53
+
54
+
55
+
56
  from fastapi import APIRouter, UploadFile, File, Form, HTTPException
57
+ from pydantic import BaseModel
58
  from pathlib import Path
59
+ from typing import Optional, List
60
  import cv2
61
  import numpy as np
62
+ import logging
63
 
64
  from .config import UPLOAD_DIR
65
  from .utils import (
 
68
  save_image,
69
  load_json,
70
  save_json,
71
+ validate_user_and_camera,
72
+ extract_metadata
73
  )
74
 
75
  router = APIRouter()
76
+ logger = logging.getLogger(__name__)
77
+
78
+
79
+ # ─── existing endpoint (unchanged) ───────────────────────────────────────────
80
  @router.post("/predict")
81
  async def predict(
82
  user_id: str = Form(...),
 
86
  images = validate_form(user_id, camera_name, images)
87
  validate_user_and_camera(user_id, camera_name)
88
  base = Path(UPLOAD_DIR) / user_id / camera_name
89
+ base.mkdir(parents=True, exist_ok=True)
90
  json_path = base / f"{camera_name}_detections.json"
91
  data = load_json(json_path)
92
  new_results = []
 
103
  "filename": file.filename,
104
  "image_url": url,
105
  "detections": detections,
106
+ "metadata": metadata
107
  }
108
  data.append(record)
109
  new_results.append(record)
 
113
  "camera": camera_name,
114
  "results": new_results
115
  }
116
+
117
+
118
+ # ─── NEW: request model ───────────────────────────────────────────────────────
119
+ class UpdateDetectionRequest(BaseModel):
120
+ user_id: str
121
+ camera_name: str
122
+ image_url: str # used to locate the record
123
+ detection_index: int = 0 # which detection inside the image to edit
124
+ new_label: str # e.g. "Buck", "Doe", "Unknown"
125
+ new_bbox: Optional[List[float]] = None # [x1,y1,x2,y2] in natural px, or null
126
+
127
+
128
+ # ─── NEW: endpoint ────────────────────────────────────────────────────────────
129
+ @router.post("/update_detection")
130
+ async def update_detection(req: UpdateDetectionRequest):
131
+ """
132
+ Edit the label and/or bounding box of one detection on an already-processed image.
133
+ Writes the change back into user_data/<user_id>/<camera_name>/<camera_name>_detections.json
134
+ """
135
+
136
+ # ── 1. First check if user directory exists ─────────────────────────
137
+ user_path = Path(UPLOAD_DIR) / req.user_id
138
+ if not user_path.exists() or not user_path.is_dir():
139
+ raise HTTPException(
140
+ status_code=404,
141
+ detail="user not found"
142
+ )
143
+
144
+ # ── 2. Check if camera directory exists ────────────────────────────
145
+ camera_path = user_path / req.camera_name
146
+ if not camera_path.exists() or not camera_path.is_dir():
147
+ raise HTTPException(
148
+ status_code=404,
149
+ detail="camera not found"
150
+ )
151
+
152
+ # ── 3. Check if detections JSON file exists ─────────────────────────
153
+ json_path = camera_path / f"{req.camera_name}_detections.json"
154
+ if not json_path.exists():
155
+ raise HTTPException(
156
+ status_code=404,
157
+ detail="camera not found" # Camera ke hisaab se JSON file nahi hai
158
+ )
159
+
160
+ # ── 4. Load the JSON data ───────────────────────────────────────────
161
+ data = load_json(json_path)
162
+
163
+ # ── 5. Find the record by matching the filename ─────────────────────
164
+ target_filename = req.image_url.split("/")[-1].split("?")[0]
165
+
166
+ record = None
167
+ for item in data:
168
+ stored = item.get("image_url", item.get("filename", ""))
169
+ stored_filename = stored.split("/")[-1].split("?")[0]
170
+ if stored_filename == target_filename:
171
+ record = item
172
+ break
173
+
174
+ if record is None:
175
+ raise HTTPException(
176
+ status_code=404,
177
+ detail="image not found"
178
+ )
179
+
180
+ # ── 6. Apply the edit ───────────────────────────────────────────────
181
+ dets = record.get("detections", [])
182
+
183
+ if not dets:
184
+ # Image had zero detections before β€” create the first one manually
185
+ record["detections"] = [{
186
+ "label": req.new_label,
187
+ "confidence": 1.0,
188
+ "bbox": req.new_bbox or [],
189
+ "manually_edited": True
190
+ }]
191
+
192
+ elif req.detection_index < len(dets):
193
+ # Normal case: update the detection at the requested index
194
+ dets[req.detection_index]["label"] = req.new_label
195
+ dets[req.detection_index]["manually_edited"] = True
196
+ if req.new_bbox is not None:
197
+ dets[req.detection_index]["bbox"] = req.new_bbox
198
+
199
+ else:
200
+ raise HTTPException(
201
+ status_code=400,
202
+ detail=f"detection_index {req.detection_index} is out of range "
203
+ f"(image has {len(dets)} detection(s))"
204
+ )
205
+
206
+ # ── 7. Save back ────────────────────────────────────────────────────
207
+ save_json(json_path, data)
208
+
209
+ logger.info(
210
+ "Detection updated | user=%s camera=%s file=%s idx=%d label=%s bbox=%s",
211
+ req.user_id, req.camera_name, target_filename,
212
+ req.detection_index, req.new_label, req.new_bbox
213
+ )
214
+
215
+ return {
216
+ "success": True,
217
+ "message": "Detection updated successfully",
218
+ "updated": {
219
+ "filename": target_filename,
220
+ "detection_index": req.detection_index,
221
+ "new_label": req.new_label,
222
+ "new_bbox": req.new_bbox,
223
+ }
224
+ }
api/main.py CHANGED
@@ -31,7 +31,7 @@ def create_app() -> FastAPI:
31
  CORSMiddleware,
32
  allow_origins=[
33
  'https://embroiderywala.myshopify.com',
34
- 'https://www.daleandcompany.com','http://127.0.0.1:8080'
35
  ],
36
  allow_credentials=True,
37
  allow_methods=["*"],
 
31
  CORSMiddleware,
32
  allow_origins=[
33
  'https://embroiderywala.myshopify.com',
34
+ 'https://www.daleandcompany.com','http://127.0.0.1:8080','https://a8a2-185-134-22-81.ngrok-free.app'
35
  ],
36
  allow_credentials=True,
37
  allow_methods=["*"],