Files changed (2) hide show
  1. DOCUMENTATION%20.md +225 -0
  2. app .py +109 -0
DOCUMENTATION%20.md ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Smart Statue Detector API - Documentation
2
+
3
+ ## Overview
4
+
5
+ REST API built with **FastAPI** + **YOLOv8** for detecting **persons** and **Egyptian statues** in images.
6
+
7
+ - 🟒 **Green box** β†’ Person
8
+ - πŸ”΄ **Red box** β†’ Statue (with real name)
9
+
10
+ **Base URL:**
11
+ ```
12
+ https://morefaat69-smart-statue-detector.hf.space
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Endpoints
18
+
19
+ ### `GET /`
20
+ Health check - ΨͺΨ£ΩƒΨ― Ψ₯Ω† Ψ§Ω„Ω€ API Ψ΄ΨΊΨ§Ω„.
21
+
22
+ **Response:**
23
+ ```json
24
+ {
25
+ "message": "AI API is running "
26
+ }
27
+ ```
28
+
29
+ ---
30
+
31
+ ### `POST /predict-image`
32
+ Upload an image β†’ get detections + annotated output image.
33
+
34
+ #### Request
35
+ | Field | Type | Description |
36
+ |-------|------|-------------|
37
+ | `file` | `multipart/form-data` | Image file (jpg, jpeg, png) |
38
+
39
+ #### Response
40
+ | Field | Type | Description |
41
+ |-------|------|-------------|
42
+ | `total_count` | `int` | Total detections (persons + statues) |
43
+ | `persons` | `int` | Number of persons detected |
44
+ | `statues` | `int` | Number of statues detected |
45
+ | `output_image_url` | `string` | URL of annotated image (temporary) |
46
+ | `output_image_base64` | `string` | Base64 encoded annotated image |
47
+ | `detections` | `array` | List of all detections |
48
+
49
+ #### Detection Object
50
+ | Field | Type | Description |
51
+ |-------|------|-------------|
52
+ | `type` | `string` | `"person"` or `"statue"` |
53
+ | `name` | `string` | `"Person"` or statue name (e.g. `"Hathor Capital"`) |
54
+ | `confidence` | `float` | Confidence score (0.0 β†’ 1.0) |
55
+ | `bbox` | `array` | Bounding box `[x1, y1, x2, y2]` |
56
+
57
+ #### Example Response
58
+ ```json
59
+ {
60
+ "total_count": 2,
61
+ "persons": 1,
62
+ "statues": 1,
63
+ "output_image_url": "https://morefaat69-smart-statue-detector.hf.space/uploads/output_test.jpeg",
64
+ "output_image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgAB...",
65
+ "detections": [
66
+ {
67
+ "type": "person",
68
+ "name": "Person",
69
+ "confidence": 0.9128,
70
+ "bbox": [56, 399, 577, 892]
71
+ },
72
+ {
73
+ "type": "statue",
74
+ "name": "Hathor Capital",
75
+ "confidence": 0.3147,
76
+ "bbox": [329, 0, 683, 721]
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ ---
83
+
84
+ ## How to Connect (Integration Examples)
85
+
86
+ ### cURL
87
+ ```bash
88
+ curl -X POST "https://morefaat69-smart-statue-detector.hf.space/predict-image" \
89
+ -H "accept: application/json" \
90
+ -F "file=@your_image.jpg;type=image/jpeg"
91
+ ```
92
+
93
+ ---
94
+
95
+ ### Python
96
+ ```python
97
+ import requests
98
+ import base64
99
+ from PIL import Image
100
+ from io import BytesIO
101
+
102
+ url = "https://morefaat69-smart-statue-detector.hf.space/predict-image"
103
+
104
+ with open("your_image.jpg", "rb") as f:
105
+ response = requests.post(url, files={"file": f})
106
+
107
+ data = response.json()
108
+
109
+ print(f"Persons: {data['persons']}")
110
+ print(f"Statues: {data['statues']}")
111
+
112
+ for d in data["detections"]:
113
+ print(f"{d['type']} β†’ {d['name']} ({d['confidence']:.2%})")
114
+
115
+ # ΨΉΨ±ΨΆ Ψ§Ω„Ψ΅ΩˆΨ±Ψ© Ψ§Ω„Ω†Ψ§ΨͺΨ¬Ψ©
116
+ img_data = base64.b64decode(data["output_image_base64"].split(",")[1])
117
+ img = Image.open(BytesIO(img_data))
118
+ img.show()
119
+ ```
120
+
121
+ ---
122
+
123
+ ### JavaScript / React
124
+ ```javascript
125
+ const detectObjects = async (imageFile) => {
126
+ const formData = new FormData();
127
+ formData.append("file", imageFile);
128
+
129
+ const response = await fetch(
130
+ "https://morefaat69-smart-statue-detector.hf.space/predict-image",
131
+ {
132
+ method: "POST",
133
+ body: formData,
134
+ }
135
+ );
136
+
137
+ const data = await response.json();
138
+
139
+ console.log(`Persons: ${data.persons}`);
140
+ console.log(`Statues: ${data.statues}`);
141
+
142
+ // ΨΉΨ±ΨΆ Ψ§Ω„Ψ΅ΩˆΨ±Ψ© Ψ§Ω„Ω†Ψ§ΨͺΨ¬Ψ© Ω…Ψ¨Ψ§Ψ΄Ψ±Ψ©
143
+ return (
144
+ <div>
145
+ <img src={data.output_image_base64} alt="Detection Result" />
146
+ {data.detections.map((d, i) => (
147
+ <p key={i}>
148
+ {d.type === "statue" ? "πŸ›οΈ" : "πŸ‘€"} {d.name} β€” {(d.confidence * 100).toFixed(1)}%
149
+ </p>
150
+ ))}
151
+ </div>
152
+ );
153
+ };
154
+ ```
155
+
156
+ ---
157
+
158
+ ### Flutter / Dart
159
+ ```dart
160
+ import 'dart:convert';
161
+ import 'dart:io';
162
+ import 'package:http/http.dart' as http;
163
+
164
+ Future<Map<String, dynamic>> detectObjects(File imageFile) async {
165
+ final uri = Uri.parse(
166
+ 'https://morefaat69-smart-statue-detector.hf.space/predict-image'
167
+ );
168
+
169
+ final request = http.MultipartRequest('POST', uri);
170
+ request.files.add(
171
+ await http.MultipartFile.fromPath('file', imageFile.path)
172
+ );
173
+
174
+ final response = await request.send();
175
+ final body = await response.stream.bytesToString();
176
+ final data = jsonDecode(body);
177
+
178
+ print('Persons: ${data['persons']}');
179
+ print('Statues: ${data['statues']}');
180
+
181
+ // فك Ψ§Ω„Ω€ Base64 وعرآ Ψ§Ω„Ψ΅ΩˆΨ±Ψ©
182
+ final imageBytes = base64Decode(
183
+ data['output_image_base64'].split(',')[1]
184
+ );
185
+
186
+ return data;
187
+ }
188
+
189
+ // ΨΉΨ±ΨΆ Ψ§Ω„Ψ΅ΩˆΨ±Ψ© في Flutter
190
+ Image.memory(imageBytes)
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Models
196
+
197
+ | Model | Purpose | Classes |
198
+ |-------|---------|---------|
199
+ | `yolov8n.pt` | Person detection | 1 class: Person |
200
+ | `best.pt` | Egyptian statue detection | 84 classes |
201
+
202
+ ### Supported Statues (84 classes)
203
+ The model can identify statues including:
204
+ `Akhenaten`, `Amenhotep III`, `Nefertiti`, `Sphinx`, `Mask of Tutankhamun`,
205
+ `Great Pyramids of Giza`, `Colossal Statue of Ramesses II`, `Hathor Capital`,
206
+ `Seated Statue of Djoser`, `Statue of Khafre` ... and 74 more.
207
+
208
+ ---
209
+
210
+ ## Configuration
211
+
212
+ | Parameter | Value | Description |
213
+ |-----------|-------|-------------|
214
+ | `CONF_THRESHOLD` | `0.25` | Minimum confidence to show detection |
215
+ | Person box color | 🟒 Green `(0,255,0)` | BGR format |
216
+ | Statue box color | πŸ”΄ Red `(0,0,255)` | BGR format |
217
+ | Max image size | No limit | Processed as-is |
218
+
219
+ ---
220
+
221
+ ## Interactive Docs
222
+ Swagger UI available at:
223
+ ```
224
+ https://morefaat69-smart-statue-detector.hf.space/docs
225
+ ```
app .py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, APIRouter, UploadFile, File, Request
2
+ from fastapi.staticfiles import StaticFiles
3
+ import shutil
4
+ import os
5
+ import cv2
6
+ import base64
7
+ from ultralytics import YOLO
8
+ # ─── Load Models
9
+ person_model = YOLO("yolov8n.pt")
10
+ statue_model = YOLO("best.pt")
11
+ # ─── App Setup
12
+ app = FastAPI()
13
+ UPLOAD_FOLDER = "/tmp/uploads"
14
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
15
+ app.mount("/uploads", StaticFiles(directory=UPLOAD_FOLDER), name="uploads")
16
+ CONF_THRESHOLD = 0.30
17
+ router = APIRouter()
18
+ def draw_label(image, label, x1, y1, x2, y2, box_color, text_color):
19
+
20
+ font = cv2.FONT_HERSHEY_SIMPLEX
21
+ font_scale = 0.6
22
+ thickness = 2
23
+ (tw, th), _ = cv2.getTextSize(label, font, font_scale, thickness)
24
+
25
+ if y1 - th - 8 >= 0:
26
+ label_y1 = y1 - th - 8
27
+ label_y2 = y1
28
+ text_y = y1 - 5
29
+ else:
30
+
31
+ label_y1 = y1
32
+ label_y2 = y1 + th + 8
33
+ text_y = y1 + th + 3
34
+ cv2.rectangle(image, (x1, label_y1), (x1 + tw + 4, label_y2), box_color, -1)
35
+ cv2.putText(image, label, (x1 + 2, text_y), font, font_scale, text_color, thickness)
36
+ @app.get("/")
37
+ def root():
38
+ return {"message": "AI API is running πŸš€"}
39
+ @router.post("/predict-image")
40
+ async def predict_image(
41
+ request: Request,
42
+ file: UploadFile = File(...)
43
+ ):
44
+ safe_filename = file.filename.replace(" ", "_")
45
+ file_path = os.path.join(UPLOAD_FOLDER, safe_filename)
46
+ with open(file_path, "wb") as buffer:
47
+ shutil.copyfileobj(file.file, buffer)
48
+ image = cv2.imread(file_path)
49
+ if image is None:
50
+ return {"error": "Invalid image"}
51
+ detections = []
52
+ person_count = 0
53
+ statue_count = 0
54
+ # ── Person Detection
55
+ person_results = person_model(file_path)
56
+ for box in person_results[0].boxes:
57
+ cls_id = int(box.cls)
58
+ if cls_id != 0:
59
+ continue
60
+ conf = float(box.conf)
61
+ if conf < CONF_THRESHOLD:
62
+ continue
63
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
64
+ cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
65
+ draw_label(image, f"Person {conf:.2f}", x1, y1, x2, y2,
66
+ box_color=(0, 255, 0), text_color=(0, 0, 0))
67
+ detections.append({
68
+ "type": "person",
69
+ "name": "Person",
70
+ "confidence": round(conf, 4),
71
+ "bbox": [x1, y1, x2, y2]
72
+ })
73
+ person_count += 1
74
+ # ── Statue Detection
75
+ statue_results = statue_model(file_path)
76
+ for box in statue_results[0].boxes:
77
+ conf = float(box.conf)
78
+ if conf < CONF_THRESHOLD:
79
+ continue
80
+ cls_id = int(box.cls)
81
+ statue_name = statue_results[0].names[cls_id]
82
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
83
+ cv2.rectangle(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
84
+ draw_label(image, f"{statue_name} {conf:.2f}", x1, y1, x2, y2,
85
+ box_color=(0, 0, 255), text_color=(255, 255, 255))
86
+ detections.append({
87
+ "type": "statue",
88
+ "name": statue_name,
89
+ "confidence": round(conf, 4),
90
+ "bbox": [x1, y1, x2, y2]
91
+ })
92
+ statue_count += 1
93
+ # ── Save Output Image
94
+ output_filename = f"output_{safe_filename}"
95
+ output_path = os.path.join(UPLOAD_FOLDER, output_filename)
96
+ cv2.imwrite(output_path, image)
97
+ with open(output_path, "rb") as img_file:
98
+ image_base64 = base64.b64encode(img_file.read()).decode("utf-8")
99
+ image_url = f"{request.base_url}uploads/{output_filename}"
100
+ return {
101
+ "total_count": len(detections),
102
+ "persons": person_count,
103
+ "statues": statue_count,
104
+ "output_image_url": image_url,
105
+ "output_image_base64": f"data:image/jpeg;base64,{image_base64}",
106
+ "detections": detections
107
+ }
108
+ app.include_router(router)
109
+