Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
2d3e7bb
1
Parent(s):
085be2c
wip
Browse files- .flake8 +3 -0
- Makefile +12 -0
- age_estimation/age_estimation.py +1 -6
- age_estimation/predict.py +0 -1
- app.py +5 -5
- detection/face_detection.py +1 -3
- detection/object_detection.py +31 -21
- tests/test_utils.py +211 -0
- utils/face_detector.py +1 -0
- utils/image_utils.py +10 -9
- utils/ui_utils.py +4 -3
.flake8
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
[flake8]
|
2 |
+
ignore = E501
|
3 |
+
max-line-length = 79
|
Makefile
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.PHONY: lint format test
|
2 |
+
|
3 |
+
lint:
|
4 |
+
flake8 .
|
5 |
+
|
6 |
+
format:
|
7 |
+
black .
|
8 |
+
|
9 |
+
test:
|
10 |
+
python tests/test_utils.py
|
11 |
+
|
12 |
+
all: lint format test
|
age_estimation/age_estimation.py
CHANGED
@@ -1,12 +1,7 @@
|
|
1 |
-
import os
|
2 |
-
import tempfile
|
3 |
import torch
|
4 |
-
import dlib
|
5 |
-
|
6 |
-
from PIL import Image
|
7 |
|
8 |
from .model import load_model
|
9 |
-
from utils.image_utils import
|
10 |
from utils.face_detector import load_face_detector
|
11 |
from .predict import predict_age
|
12 |
|
|
|
|
|
|
|
1 |
import torch
|
|
|
|
|
|
|
2 |
|
3 |
from .model import load_model
|
4 |
+
from utils.image_utils import preprocess_image, get_image_from_input
|
5 |
from utils.face_detector import load_face_detector
|
6 |
from .predict import predict_age
|
7 |
|
age_estimation/predict.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1 |
import cv2
|
2 |
import numpy as np
|
3 |
-
import dlib
|
4 |
import torch
|
5 |
import torch.nn.functional as F
|
6 |
|
|
|
1 |
import cv2
|
2 |
import numpy as np
|
|
|
3 |
import torch
|
4 |
import torch.nn.functional as F
|
5 |
|
app.py
CHANGED
@@ -1,8 +1,6 @@
|
|
1 |
# Standard library imports
|
2 |
import os
|
3 |
import gradio as gr
|
4 |
-
import torch.nn.functional as F
|
5 |
-
import torch.nn as nn
|
6 |
|
7 |
# Local imports
|
8 |
from age_estimation.age_estimation import age_estimation
|
@@ -139,8 +137,10 @@ with gr.Blocks() as demo:
|
|
139 |
obj_process_btn = gr.Button("Detect Objects")
|
140 |
|
141 |
# Output Components
|
142 |
-
obj_image_output = gr.Image(
|
143 |
-
|
|
|
|
|
144 |
|
145 |
# Link radio button change to visibility update function
|
146 |
obj_input_type.change(
|
@@ -156,7 +156,7 @@ with gr.Blocks() as demo:
|
|
156 |
obj_process_btn.click(
|
157 |
fn=object_detection,
|
158 |
inputs=[obj_input_type, obj_img_upload, obj_url_input, obj_base64_input],
|
159 |
-
outputs=[obj_image_output, obj_raw_output],
|
160 |
)
|
161 |
|
162 |
# Launch the Gradio demo
|
|
|
1 |
# Standard library imports
|
2 |
import os
|
3 |
import gradio as gr
|
|
|
|
|
4 |
|
5 |
# Local imports
|
6 |
from age_estimation.age_estimation import age_estimation
|
|
|
137 |
obj_process_btn = gr.Button("Detect Objects")
|
138 |
|
139 |
# Output Components
|
140 |
+
obj_image_output = gr.Image(
|
141 |
+
label="Detected Objects Image"
|
142 |
+
) # Updated label for clarity
|
143 |
+
obj_raw_output = gr.JSON(label="Raw Object Detection Data") # Added JSON output
|
144 |
|
145 |
# Link radio button change to visibility update function
|
146 |
obj_input_type.change(
|
|
|
156 |
obj_process_btn.click(
|
157 |
fn=object_detection,
|
158 |
inputs=[obj_input_type, obj_img_upload, obj_url_input, obj_base64_input],
|
159 |
+
outputs=[obj_image_output, obj_raw_output], # Updated outputs
|
160 |
)
|
161 |
|
162 |
# Launch the Gradio demo
|
detection/face_detection.py
CHANGED
@@ -3,11 +3,9 @@ import os
|
|
3 |
|
4 |
# Third-party imports
|
5 |
import cv2
|
6 |
-
import numpy as np
|
7 |
-
from PIL import Image
|
8 |
|
9 |
# Local imports
|
10 |
-
from utils.image_utils import
|
11 |
from utils.face_detector import (
|
12 |
load_face_detector,
|
13 |
) # Assuming this is the dlib detector loader
|
|
|
3 |
|
4 |
# Third-party imports
|
5 |
import cv2
|
|
|
|
|
6 |
|
7 |
# Local imports
|
8 |
+
from utils.image_utils import preprocess_image, get_image_from_input
|
9 |
from utils.face_detector import (
|
10 |
load_face_detector,
|
11 |
) # Assuming this is the dlib detector loader
|
detection/object_detection.py
CHANGED
@@ -1,10 +1,7 @@
|
|
1 |
# Standard library imports
|
2 |
# (Add any necessary imports for future object detection implementation)
|
3 |
-
import json
|
4 |
|
5 |
# Third-party imports
|
6 |
-
from PIL import Image
|
7 |
-
import numpy as np
|
8 |
from ultralytics import YOLO
|
9 |
|
10 |
# Local imports
|
@@ -19,7 +16,7 @@ try:
|
|
19 |
print("YOLO model loaded successfully.")
|
20 |
except Exception as e:
|
21 |
print(f"Error loading YOLO model: {e}")
|
22 |
-
model = None
|
23 |
|
24 |
|
25 |
def object_detection(input_type, uploaded_image, image_url, base64_string):
|
@@ -39,7 +36,7 @@ def object_detection(input_type, uploaded_image, image_url, base64_string):
|
|
39 |
"""
|
40 |
if model is None:
|
41 |
print("YOLO model is not loaded. Cannot perform object detection.")
|
42 |
-
return None, None
|
43 |
|
44 |
image = None
|
45 |
input_value = None
|
@@ -54,22 +51,22 @@ def object_detection(input_type, uploaded_image, image_url, base64_string):
|
|
54 |
|
55 |
elif input_type == "Enter Base64" and base64_string and base64_string.strip():
|
56 |
input_value = base64_string
|
57 |
-
print(
|
58 |
|
59 |
else:
|
60 |
print("No valid input provided for object detection based on selected type.")
|
61 |
-
return None, None
|
62 |
|
63 |
# If input_value is set (URL or Base64), use load_image
|
64 |
if input_value:
|
65 |
image = load_image(input_value)
|
66 |
if image is None:
|
67 |
-
return None, None
|
68 |
|
69 |
# Now 'image' should be a PIL Image or None
|
70 |
if image is None:
|
71 |
print("Image is None after loading/selection for object detection.")
|
72 |
-
return None, None
|
73 |
|
74 |
try:
|
75 |
# Preprocess the image (convert PIL to numpy, ensure RGB)
|
@@ -85,24 +82,37 @@ def object_detection(input_type, uploaded_image, image_url, base64_string):
|
|
85 |
# box.xywh contains [x_center, y_center, width, height]
|
86 |
# box.conf contains confidence score
|
87 |
# box.cls contains class index
|
88 |
-
x_center, y_center, width, height = [
|
|
|
|
|
89 |
confidence = round(float(box.conf[0]), 4)
|
90 |
class_id = int(box.cls[0])
|
91 |
-
class_name =
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
# Draw results on the image
|
101 |
-
result_image_np =
|
|
|
|
|
102 |
|
103 |
print("Object detection performed successfully.")
|
104 |
-
return result_image_np, raw_data
|
105 |
|
106 |
except Exception as e:
|
107 |
print(f"Error during YOLO object detection: {e}")
|
108 |
-
return None, None
|
|
|
1 |
# Standard library imports
|
2 |
# (Add any necessary imports for future object detection implementation)
|
|
|
3 |
|
4 |
# Third-party imports
|
|
|
|
|
5 |
from ultralytics import YOLO
|
6 |
|
7 |
# Local imports
|
|
|
16 |
print("YOLO model loaded successfully.")
|
17 |
except Exception as e:
|
18 |
print(f"Error loading YOLO model: {e}")
|
19 |
+
model = None # Set model to None if loading fails
|
20 |
|
21 |
|
22 |
def object_detection(input_type, uploaded_image, image_url, base64_string):
|
|
|
36 |
"""
|
37 |
if model is None:
|
38 |
print("YOLO model is not loaded. Cannot perform object detection.")
|
39 |
+
return None, None # Return None for both outputs
|
40 |
|
41 |
image = None
|
42 |
input_value = None
|
|
|
51 |
|
52 |
elif input_type == "Enter Base64" and base64_string and base64_string.strip():
|
53 |
input_value = base64_string
|
54 |
+
print("Using Base64 string for object detection") # Debug print
|
55 |
|
56 |
else:
|
57 |
print("No valid input provided for object detection based on selected type.")
|
58 |
+
return None, None # Return None for both outputs
|
59 |
|
60 |
# If input_value is set (URL or Base64), use load_image
|
61 |
if input_value:
|
62 |
image = load_image(input_value)
|
63 |
if image is None:
|
64 |
+
return None, None # load_image failed
|
65 |
|
66 |
# Now 'image' should be a PIL Image or None
|
67 |
if image is None:
|
68 |
print("Image is None after loading/selection for object detection.")
|
69 |
+
return None, None # Return None for both outputs
|
70 |
|
71 |
try:
|
72 |
# Preprocess the image (convert PIL to numpy, ensure RGB)
|
|
|
82 |
# box.xywh contains [x_center, y_center, width, height]
|
83 |
# box.conf contains confidence score
|
84 |
# box.cls contains class index
|
85 |
+
x_center, y_center, width, height = [
|
86 |
+
round(float(coord)) for coord in box.xywh[0].tolist()
|
87 |
+
] # Changed to xywh
|
88 |
confidence = round(float(box.conf[0]), 4)
|
89 |
class_id = int(box.cls[0])
|
90 |
+
class_name = (
|
91 |
+
model.names[class_id] if model.names else str(class_id)
|
92 |
+
) # Get class name if available
|
93 |
+
|
94 |
+
raw_data.append(
|
95 |
+
{
|
96 |
+
"box": {
|
97 |
+
"x": x_center,
|
98 |
+
"y": y_center,
|
99 |
+
"w": width,
|
100 |
+
"h": height,
|
101 |
+
}, # Updated keys
|
102 |
+
"confidence": confidence,
|
103 |
+
"class_id": class_id,
|
104 |
+
"class_name": class_name,
|
105 |
+
}
|
106 |
+
)
|
107 |
|
108 |
# Draw results on the image
|
109 |
+
result_image_np = (
|
110 |
+
results[0].plot() if results else processed_image_np
|
111 |
+
) # Plot if results exist
|
112 |
|
113 |
print("Object detection performed successfully.")
|
114 |
+
return result_image_np, raw_data # Return both the image and raw data
|
115 |
|
116 |
except Exception as e:
|
117 |
print(f"Error during YOLO object detection: {e}")
|
118 |
+
return None, None # Return None for both outputs
|
tests/test_utils.py
ADDED
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from utils.image_utils import load_image, preprocess_image, get_image_from_input
|
3 |
+
from utils.ui_utils import update_input_visibility
|
4 |
+
import numpy as np
|
5 |
+
from PIL import Image
|
6 |
+
import io
|
7 |
+
import unittest.mock
|
8 |
+
import urllib.request # Import urllib.request for patching
|
9 |
+
import os # Keep os for file cleanup
|
10 |
+
|
11 |
+
|
12 |
+
# Mock object to mimic gr.update return value
|
13 |
+
class MockGradioUpdateReturn:
|
14 |
+
def __init__(self, visible=None):
|
15 |
+
self.visible = visible
|
16 |
+
|
17 |
+
|
18 |
+
# Simple mock class for urllib.request.urlopen response
|
19 |
+
class SimpleMockURLResponse:
|
20 |
+
def __init__(self, content):
|
21 |
+
self._content = content
|
22 |
+
|
23 |
+
def read(self):
|
24 |
+
return self._content
|
25 |
+
|
26 |
+
def __enter__(self):
|
27 |
+
return self
|
28 |
+
|
29 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
30 |
+
pass
|
31 |
+
|
32 |
+
|
33 |
+
# Use patch as a class decorator for gr.update
|
34 |
+
class TestUtils(unittest.TestCase):
|
35 |
+
|
36 |
+
# Patch urllib.request.urlopen for this specific test
|
37 |
+
@unittest.mock.patch("urllib.request.urlopen")
|
38 |
+
def test_load_image_from_url(
|
39 |
+
self, mock_urlopen
|
40 |
+
): # Added mock_urlopen and mock_gr_update
|
41 |
+
# Create a dummy image and get its bytes
|
42 |
+
dummy_image = Image.new("RGB", (10, 10), color="purple")
|
43 |
+
byte_arr = io.BytesIO()
|
44 |
+
dummy_image.save(byte_arr, format="PNG")
|
45 |
+
mock_image_bytes = byte_arr.getvalue()
|
46 |
+
|
47 |
+
# Configure the mock urlopen response using SimpleMockURLResponse
|
48 |
+
mock_urlopen.return_value = SimpleMockURLResponse(mock_image_bytes)
|
49 |
+
|
50 |
+
url = "https://www.example.com/dummy_image.png" # Use a dummy URL
|
51 |
+
image = load_image(url)
|
52 |
+
self.assertIsNotNone(image)
|
53 |
+
self.assertIsInstance(image, Image.Image)
|
54 |
+
self.assertEqual(image.size, (10, 10))
|
55 |
+
mock_urlopen.assert_called_once_with(url) # Verify urlopen was called
|
56 |
+
|
57 |
+
def test_load_image_from_base64(self): # Added mock_gr_update
|
58 |
+
# A simple 1x1 black PNG as a base64 string
|
59 |
+
base64_string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5ErkJggg==" # Corrected padding
|
60 |
+
image = load_image(base64_string)
|
61 |
+
self.assertIsNotNone(image)
|
62 |
+
self.assertIsInstance(image, Image.Image)
|
63 |
+
self.assertEqual(image.size, (1, 1))
|
64 |
+
|
65 |
+
def test_load_image_from_file(self): # Added mock_gr_update
|
66 |
+
# Create a dummy image file for testing
|
67 |
+
dummy_image = Image.new("RGB", (10, 10), color="red")
|
68 |
+
dummy_file_path = "dummy_test_image.png"
|
69 |
+
dummy_image.save(dummy_file_path)
|
70 |
+
|
71 |
+
image = load_image(dummy_file_path)
|
72 |
+
self.assertIsNotNone(image)
|
73 |
+
self.assertIsInstance(image, Image.Image)
|
74 |
+
self.assertEqual(image.size, (10, 10))
|
75 |
+
|
76 |
+
# Clean up the dummy file
|
77 |
+
os.remove(dummy_file_path)
|
78 |
+
|
79 |
+
@unittest.mock.patch("urllib.request.urlopen")
|
80 |
+
def test_load_image_invalid_url(
|
81 |
+
self, mock_urlopen
|
82 |
+
): # Added mock_urlopen and mock_gr_update
|
83 |
+
# Configure the mock urlopen to raise an exception
|
84 |
+
mock_urlopen.side_effect = urllib.error.URLError("Simulated network error")
|
85 |
+
|
86 |
+
url = "http://invalid.url/image.jpg"
|
87 |
+
image = load_image(url)
|
88 |
+
self.assertIsNone(image)
|
89 |
+
mock_urlopen.assert_called_once_with(url)
|
90 |
+
|
91 |
+
def test_load_image_invalid_base64(self): # Added mock_gr_update
|
92 |
+
base64_string = "data:image/png;base64,invalidbase64string"
|
93 |
+
image = load_image(base64_string)
|
94 |
+
self.assertIsNone(image)
|
95 |
+
|
96 |
+
def test_preprocess_image(self): # Added mock_gr_update
|
97 |
+
# Create a dummy PIL image
|
98 |
+
dummy_image = Image.new("RGB", (20, 20), color="blue")
|
99 |
+
processed_image = preprocess_image(dummy_image)
|
100 |
+
self.assertIsNotNone(processed_image)
|
101 |
+
self.assertIsInstance(processed_image, np.ndarray)
|
102 |
+
self.assertEqual(processed_image.shape, (20, 20, 3)) # Check shape for RGB
|
103 |
+
|
104 |
+
@unittest.mock.patch("urllib.request.urlopen")
|
105 |
+
def test_get_image_from_input_url(
|
106 |
+
self, mock_urlopen
|
107 |
+
): # Added mock_urlopen and mock_gr_update
|
108 |
+
# Create a dummy image and get its bytes
|
109 |
+
dummy_image = Image.new("RGB", (30, 30), color="orange")
|
110 |
+
byte_arr = io.BytesIO()
|
111 |
+
dummy_image.save(byte_arr, format="PNG")
|
112 |
+
mock_image_bytes = byte_arr.getvalue()
|
113 |
+
|
114 |
+
# Configure the mock urlopen response using SimpleMockURLResponse
|
115 |
+
mock_urlopen.return_value = SimpleMockURLResponse(mock_image_bytes)
|
116 |
+
|
117 |
+
url = "https://www.example.com/another_dummy_image.png"
|
118 |
+
image = get_image_from_input("Enter URL", None, url, "")
|
119 |
+
self.assertIsNotNone(image)
|
120 |
+
self.assertIsInstance(image, Image.Image)
|
121 |
+
self.assertEqual(image.size, (30, 30))
|
122 |
+
mock_urlopen.assert_called_once_with(url)
|
123 |
+
|
124 |
+
def test_get_image_from_input_upload(self): # Added mock_gr_update
|
125 |
+
# Mock an uploaded PIL image
|
126 |
+
mock_uploaded_image = Image.new("RGB", (30, 30), color="green")
|
127 |
+
image = get_image_from_input("Upload File", mock_uploaded_image, "", "")
|
128 |
+
self.assertIsNotNone(image)
|
129 |
+
self.assertIsInstance(image, Image.Image)
|
130 |
+
self.assertEqual(image.size, (30, 30))
|
131 |
+
|
132 |
+
def test_get_image_from_input_base64(self): # Added mock_gr_update
|
133 |
+
base64_string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" # Corrected padding
|
134 |
+
image = get_image_from_input("Enter Base64", None, "", base64_string)
|
135 |
+
self.assertIsNotNone(image)
|
136 |
+
self.assertIsInstance(image, Image.Image)
|
137 |
+
self.assertEqual(image.size, (1, 1))
|
138 |
+
|
139 |
+
def test_get_image_from_input_no_input(self): # Added mock_gr_update
|
140 |
+
image = get_image_from_input("Upload File", None, "", "")
|
141 |
+
self.assertIsNone(image)
|
142 |
+
|
143 |
+
def test_get_image_from_input_invalid_type(self): # Added mock_gr_update
|
144 |
+
image = get_image_from_input(
|
145 |
+
"Invalid Type", Image.new("RGB", (10, 10)), "url", "base64"
|
146 |
+
)
|
147 |
+
self.assertIsNone(image)
|
148 |
+
|
149 |
+
# Tests for update_input_visibility now use the class-level patch
|
150 |
+
# Configure the side_effect of mock_gr_update to return specific MockGradioUpdateReturn objects
|
151 |
+
@unittest.mock.patch("gradio.update")
|
152 |
+
def test_update_input_visibility_upload(
|
153 |
+
self, mock_gr_update
|
154 |
+
): # Added mock_gr_update
|
155 |
+
mock_gr_update.side_effect = [
|
156 |
+
MockGradioUpdateReturn(visible=True),
|
157 |
+
MockGradioUpdateReturn(visible=False),
|
158 |
+
MockGradioUpdateReturn(visible=False),
|
159 |
+
]
|
160 |
+
updates = update_input_visibility("Upload File")
|
161 |
+
self.assertEqual(len(updates), 3)
|
162 |
+
self.assertTrue(updates[0].visible)
|
163 |
+
self.assertFalse(updates[1].visible)
|
164 |
+
self.assertFalse(updates[2].visible)
|
165 |
+
|
166 |
+
@unittest.mock.patch("gradio.update")
|
167 |
+
def test_update_input_visibility_url(self, mock_gr_update): # Added mock_gr_update
|
168 |
+
mock_gr_update.side_effect = [
|
169 |
+
MockGradioUpdateReturn(visible=False),
|
170 |
+
MockGradioUpdateReturn(visible=True),
|
171 |
+
MockGradioUpdateReturn(visible=False),
|
172 |
+
]
|
173 |
+
updates = update_input_visibility("Enter URL")
|
174 |
+
self.assertEqual(len(updates), 3)
|
175 |
+
self.assertFalse(updates[0].visible)
|
176 |
+
self.assertTrue(updates[1].visible)
|
177 |
+
self.assertFalse(updates[2].visible)
|
178 |
+
|
179 |
+
@unittest.mock.patch("gradio.update")
|
180 |
+
def test_update_input_visibility_base64(
|
181 |
+
self, mock_gr_update
|
182 |
+
): # Added mock_gr_update
|
183 |
+
mock_gr_update.side_effect = [
|
184 |
+
MockGradioUpdateReturn(visible=False),
|
185 |
+
MockGradioUpdateReturn(visible=False),
|
186 |
+
MockGradioUpdateReturn(visible=True),
|
187 |
+
]
|
188 |
+
updates = update_input_visibility("Enter Base64")
|
189 |
+
self.assertEqual(len(updates), 3)
|
190 |
+
self.assertFalse(updates[0].visible)
|
191 |
+
self.assertFalse(updates[1].visible)
|
192 |
+
self.assertTrue(updates[2].visible)
|
193 |
+
|
194 |
+
@unittest.mock.patch("gradio.update")
|
195 |
+
def test_update_input_visibility_default(
|
196 |
+
self, mock_gr_update
|
197 |
+
): # Added mock_gr_update
|
198 |
+
mock_gr_update.side_effect = [
|
199 |
+
MockGradioUpdateReturn(visible=True),
|
200 |
+
MockGradioUpdateReturn(visible=False),
|
201 |
+
MockGradioUpdateReturn(visible=False),
|
202 |
+
]
|
203 |
+
updates = update_input_visibility("Invalid Choice")
|
204 |
+
self.assertEqual(len(updates), 3)
|
205 |
+
self.assertTrue(updates[0].visible)
|
206 |
+
self.assertFalse(updates[1].visible)
|
207 |
+
self.assertFalse(updates[2].visible)
|
208 |
+
|
209 |
+
|
210 |
+
if __name__ == "__main__":
|
211 |
+
unittest.main()
|
utils/face_detector.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import dlib
|
2 |
|
|
|
3 |
def load_face_detector():
|
4 |
"""
|
5 |
Loads the dlib face detector.
|
|
|
1 |
import dlib
|
2 |
|
3 |
+
|
4 |
def load_face_detector():
|
5 |
"""
|
6 |
Loads the dlib face detector.
|
utils/image_utils.py
CHANGED
@@ -6,7 +6,7 @@ import urllib.request
|
|
6 |
# Third-party imports
|
7 |
from PIL import Image
|
8 |
import numpy as np
|
9 |
-
|
10 |
|
11 |
def load_image(image_path):
|
12 |
"""
|
@@ -50,12 +50,13 @@ def preprocess_image(image):
|
|
50 |
"""
|
51 |
# Ensure image is a PIL Image before converting
|
52 |
if not isinstance(image, Image.Image):
|
53 |
-
|
54 |
|
55 |
image = image.convert("RGB")
|
56 |
image = np.array(image)
|
57 |
return image
|
58 |
|
|
|
59 |
def get_image_from_input(input_type, uploaded_image, image_url, base64_string):
|
60 |
"""
|
61 |
Centralized function to get an image from various input types.
|
@@ -73,31 +74,31 @@ def get_image_from_input(input_type, uploaded_image, image_url, base64_string):
|
|
73 |
input_value = None
|
74 |
|
75 |
if input_type == "Upload File" and uploaded_image is not None:
|
76 |
-
image = uploaded_image
|
77 |
-
print("Using uploaded image (PIL)")
|
78 |
|
79 |
elif input_type == "Enter URL" and image_url and image_url.strip():
|
80 |
input_value = image_url
|
81 |
-
print(f"Using URL: {input_value}")
|
82 |
|
83 |
elif input_type == "Enter Base64" and base64_string and base64_string.strip():
|
84 |
input_value = base64_string
|
85 |
-
print(
|
86 |
|
87 |
else:
|
88 |
print("No valid input provided based on selected type.")
|
89 |
-
return None
|
90 |
|
91 |
# If input_value is set (URL or Base64), use the local load_image
|
92 |
if input_value:
|
93 |
image = load_image(input_value)
|
94 |
if image is None:
|
95 |
print("Error: Could not load image from provided input.")
|
96 |
-
return None
|
97 |
|
98 |
# Now 'image' should be a PIL Image or None
|
99 |
if image is None:
|
100 |
print("Image is None after loading/selection.")
|
101 |
return None
|
102 |
|
103 |
-
return image
|
|
|
6 |
# Third-party imports
|
7 |
from PIL import Image
|
8 |
import numpy as np
|
9 |
+
|
10 |
|
11 |
def load_image(image_path):
|
12 |
"""
|
|
|
50 |
"""
|
51 |
# Ensure image is a PIL Image before converting
|
52 |
if not isinstance(image, Image.Image):
|
53 |
+
image = Image.fromarray(image)
|
54 |
|
55 |
image = image.convert("RGB")
|
56 |
image = np.array(image)
|
57 |
return image
|
58 |
|
59 |
+
|
60 |
def get_image_from_input(input_type, uploaded_image, image_url, base64_string):
|
61 |
"""
|
62 |
Centralized function to get an image from various input types.
|
|
|
74 |
input_value = None
|
75 |
|
76 |
if input_type == "Upload File" and uploaded_image is not None:
|
77 |
+
image = uploaded_image # This is a PIL Image from gr.Image(type="pil")
|
78 |
+
print("Using uploaded image (PIL)") # Debug print
|
79 |
|
80 |
elif input_type == "Enter URL" and image_url and image_url.strip():
|
81 |
input_value = image_url
|
82 |
+
print(f"Using URL: {input_value}") # Debug print
|
83 |
|
84 |
elif input_type == "Enter Base64" and base64_string and base64_string.strip():
|
85 |
input_value = base64_string
|
86 |
+
print("Using Base64 string") # Debug print
|
87 |
|
88 |
else:
|
89 |
print("No valid input provided based on selected type.")
|
90 |
+
return None # No valid input
|
91 |
|
92 |
# If input_value is set (URL or Base64), use the local load_image
|
93 |
if input_value:
|
94 |
image = load_image(input_value)
|
95 |
if image is None:
|
96 |
print("Error: Could not load image from provided input.")
|
97 |
+
return None # load_image failed
|
98 |
|
99 |
# Now 'image' should be a PIL Image or None
|
100 |
if image is None:
|
101 |
print("Image is None after loading/selection.")
|
102 |
return None
|
103 |
|
104 |
+
return image
|
utils/ui_utils.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
# Utility functions for UI components
|
2 |
import gradio as gr
|
3 |
|
|
|
4 |
def update_input_visibility(choice):
|
5 |
"""
|
6 |
Returns updates to the visibility of input components based on the selected input method.
|
@@ -29,9 +30,9 @@ def update_input_visibility(choice):
|
|
29 |
gr.update(visible=False),
|
30 |
gr.update(visible=True),
|
31 |
)
|
32 |
-
else:
|
33 |
-
|
34 |
gr.update(visible=True),
|
35 |
gr.update(visible=False),
|
36 |
gr.update(visible=False),
|
37 |
-
|
|
|
1 |
# Utility functions for UI components
|
2 |
import gradio as gr
|
3 |
|
4 |
+
|
5 |
def update_input_visibility(choice):
|
6 |
"""
|
7 |
Returns updates to the visibility of input components based on the selected input method.
|
|
|
30 |
gr.update(visible=False),
|
31 |
gr.update(visible=True),
|
32 |
)
|
33 |
+
else: # Default or unexpected
|
34 |
+
return (
|
35 |
gr.update(visible=True),
|
36 |
gr.update(visible=False),
|
37 |
gr.update(visible=False),
|
38 |
+
)
|