Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge code mark 1 #3

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions .github/workflows/pylint.yml

This file was deleted.

131 changes: 88 additions & 43 deletions API/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
from datetime import datetime
from io import BytesIO
from typing import List

from bson import ObjectId
from deepface import DeepFace
Expand All @@ -14,24 +15,13 @@
from pymongo import MongoClient

from API.database import Database
from API.utils import init_logging_config

# Create a logger object
logger = logging.getLogger(__name__)
# Create a file handler
handler = logging.FileHandler("log.log")
handler.setLevel(logging.INFO)
# Create a logging format
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
init_logging_config()

router = APIRouter()

# To create connection with Mongodb
# mongodb_uri = "mongodb://localhost:27017/"
# port = 8000
# client = MongoClient(mongodb_uri, port)

# db = client["ImageDB"]
client = Database()

collection = "faceEntries"
Expand All @@ -43,42 +33,59 @@
Name: str
gender: str
Department: str
Image: str
Images: List[str]


class UpdateEmployee(BaseModel):
Name: str
gender: str
Department: str
Image: str
Images: List[str]


# To create new entries of employee
@router.post("/create_new_faceEntry")
async def create_new_faceEntry(Employee: Employee):
"""
Create a new face entry for an employee.

Args:
Employee (Employee): The employee object containing the employee details.

Returns:
dict: A dictionary with a success message.

Raises:
None
"""
Name = Employee.Name
EmployeeCode = Employee.EmployeeCode
gender = Employee.gender
Department = Employee.Department
encoded_image = Employee.Image
encoded_images = Employee.Images
time = datetime.now()
img_recovered = base64.b64decode(encoded_image) # decode base64string
# print(img_recovered)
pil_image = Image.open(BytesIO(img_recovered))
image_filename = f"{Name}.png"
pil_image.save(image_filename)
# print path of the current working directory
pil_image.save(f"Images\dbImages\{Name}.jpg")
# Extract the face from the image
face_image_data = DeepFace.extract_faces(
image_filename, detector_backend="mtcnn", enforce_detection=False
)
# Calculate the embeddings of the face image
plt.imsave(f"Images/Faces/{Name}.jpg", face_image_data[0]["face"])
embeddings = DeepFace.represent(
image_filename, model_name="Facenet", detector_backend="mtcnn"
)
os.remove(image_filename)

embeddings = []
for encoded_image in encoded_images:
img_recovered = base64.b64decode(encoded_image) # decode base64string
pil_image = Image.open(BytesIO(img_recovered))
logging.info(f"Image opened {Name}")
image_filename = f"{Name}.png"
pil_image.save(image_filename)
pil_image.save(f"Images\dbImages\{Name}.jpg")
face_image_data = DeepFace.extract_faces(
image_filename, detector_backend="mtcnn", enforce_detection=False
)
plt.imsave(f"Images/Faces/{Name}.jpg", face_image_data[0]["face"])
logging.info(f"Face saved {Name}")
embedding = DeepFace.represent(
image_filename, model_name="Facenet", detector_backend="mtcnn"
)
embeddings.append(embedding)
logging.info(f"Embedding created Embeddings for {Name}")
os.remove(image_filename)
Dismissed Show dismissed Hide dismissed

logging.debug(f"About to insert Embeddings: {embeddings}")
# Store the data in the database
client.insert_one(
collection,
Expand All @@ -89,26 +96,30 @@
"Department": Department,
"time": time,
"embeddings": embeddings,
"Image": encoded_image,
"Images": encoded_images,
},
)
# db.faceEntries.insert_one(

# )
return {"message": "Face entry created successfully"}


# To display all records
@router.get("/Data/", response_model=list[Employee])
async def get_employees():
"""
Retrieve a list of employees from the database.

Returns:
list[Employee]: A list of Employee objects containing employee information.
"""
employees_mongo = client.find(collection)
employees = [
Employee(
EmployeeCode=int(employee.get("EmployeeCode", 0)),
Name=employee.get("Name", "N/A"),
gender=employee.get("gender", "N/A"),
Department=employee.get("Department", "N/A"),
Image=employee.get("Image", "N/A"),
Images=employee.get("Images", "N/A"),
)
for employee in employees_mongo
]
Expand All @@ -118,16 +129,29 @@
# To display specific record info
@router.get("/read/{EmployeeCode}", response_class=Response)
async def read_employee(EmployeeCode: int):
"""
Retrieve employee information based on the provided EmployeeCode.

Args:
EmployeeCode (int): The unique code of the employee.

Returns:
Response: A response object containing the employee information in JSON format.

Raises:
HTTPException: If the employee is not found.

"""
try:
# logger.info(f"Start {EmployeeCode}")
logging.info(f"Start {EmployeeCode}")
items = client.find_one(
collection,
filter={"EmployeeCode": EmployeeCode},
projection={
"Name": True,
"gender": True,
"Department": True,
"Image": True,
"Images": True,
"_id": False,
},
)
Expand All @@ -149,16 +173,29 @@
# For updating existing record
@router.put("/update/{EmployeeCode}", response_model=str)
async def update_employees(EmployeeCode: int, Employee: UpdateEmployee):
"""
Update employee information based on the provided EmployeeCode.

Args:
EmployeeCode (int): The unique code of the employee to be updated.
Employee (UpdateEmployee): The updated employee data.

Returns:
str: A message indicating the success of the update operation.

Raises:
HTTPException: If the employee with the given EmployeeCode is not found.
HTTPException: If no data was updated during the update operation.
HTTPException: If an internal server error occurs.
"""
try:
# logger.warning("Updating Start")
user_id = client.find_one(
collection, {"EmployeeCode": EmployeeCode}, projection={"_id": True}
)
print(user_id)
if not user_id:
raise HTTPException(status_code=404, detail="Employee not found")
Employee_data = Employee.model_dump(by_alias=True, exclude_unset=True)
# logger.info(f"Employee data to update: {Employee_data}")
try:
update_result = client.update_one(
collection,
Expand All @@ -169,16 +206,24 @@
raise HTTPException(status_code=400, detail="No data was updated")
return "Updated Successfully"
except Exception as e:
# logger.error(f"Error while updating: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
except Exception as e:
# logger.error(f"Error while fetching user_id: {e}")
raise HTTPException(status_code=500, detail="Internal server error")


# To delete employee record
@router.delete("/delete/{EmployeeCode}")
async def delete_employees(EmployeeCode: int):
"""
Delete an employee from the collection based on the provided EmployeeCode.

Args:
EmployeeCode (int): The unique code of the employee to be deleted.

Returns:
dict: A dictionary containing a success message.

"""
print(EmployeeCode)
client.find_one_and_delete(collection, {"EmployeeCode": EmployeeCode})

Expand Down
41 changes: 41 additions & 0 deletions API/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import logging


def init_logging_config():
class CustomFormatter(logging.Formatter):
def __init__(self, file=False):
super().__init__()
yellow = "\x1b[36;10m" if not file else ""
blue = "\x1b[35;10m" if not file else ""
green = "\x1b[32;10m" if not file else ""
red = "\x1b[31;10m" if not file else ""
bold_red = "\x1b[31;1m" if not file else ""
reset = "\x1b[0m" if not file else ""
log = "%(asctime)s (%(filename)s:%(lineno)d) - %(levelname)s: "
msg = reset + "%(message)s"

self.FORMATS = {
logging.DEBUG: blue + log + msg,
logging.INFO: green + log + msg,
logging.WARNING: yellow + log + msg,
logging.ERROR: red + log + msg,
logging.CRITICAL: bold_red + log + msg,
}

def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

stderr_handler = logging.StreamHandler()
stderr_handler.setLevel(logging.DEBUG)
stderr_handler.setFormatter(CustomFormatter())
logger.addHandler(stderr_handler)

file_handler = logging.FileHandler("app.log", mode="w")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(CustomFormatter(True))
logger.addHandler(file_handler)
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
## [Unreleased]
## [0.0.1] - 2024-03-08 - 2:30

### Added
- Implemented all test cases in `test_face_cycle`
- Implemented mock test cases for `test_face_cycle` to work on online runners
- Implemented mock test cases for `test_face_cycle` to work on online runners

## [0.1.0] - 2024-03-08 - 17:10

### Added
- Updated `create_new_faceEntry` function in [`route.py`](route/route.py) to handle multiple images for each employee.
- Updated `test_face_lifecycle` function in [`test_face_cycle.py`](testing/test_face_cycle.py) to handle multiple images for each employee in the test data.

### Changed
- Modified the `Employee` and `UpdateEmployee` models in [`route.py`](route/route.py) to include a list of images instead of a single image.
- Adjusted the mock data and assertions in [`test_face_cycle.py`](testing/test_face_cycle.py) to handle multiple images for each employee.

### Fixed
- Resolved an issue where the `create_new_faceEntry` function in [`route.py`](route/route.py) was not correctly processing multiple images for each employee.
39 changes: 23 additions & 16 deletions test.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -631,13 +631,16 @@
"outputs": [],
"source": [
"url = \"http://127.0.0.1:8000/create_new_faceEntry\"\n",
"resp = requests.post(url=url, json={\n",
" \"EmployeeCode\": 134,\n",
" \"Name\": \"Name\",\n",
" \"gender\": \"gender\",\n",
" \"Department\": \"Department\",\n",
" \"Image\": \"your_image\",\n",
"})"
"resp = requests.post(\n",
" url=url,\n",
" json={\n",
" \"EmployeeCode\": 134,\n",
" \"Name\": \"Name\",\n",
" \"gender\": \"gender\",\n",
" \"Department\": \"Department\",\n",
" \"Image\": \"your_image\",\n",
" },\n",
")"
]
},
{
Expand Down Expand Up @@ -676,16 +679,20 @@
],
"source": [
"from API.database import Database\n",
"\n",
"EmployeeCode = 1\n",
"client = Database()\n",
"client.find_one(\"faceEntries\", filter={\"EmployeeCode\": EmployeeCode},\n",
" projection={\n",
" \"Name\": True,\n",
" \"gender\": True,\n",
" \"Department\": True,\n",
" \"Image\": True,\n",
" \"_id\": False,\n",
" })"
"client.find_one(\n",
" \"faceEntries\",\n",
" filter={\"EmployeeCode\": EmployeeCode},\n",
" projection={\n",
" \"Name\": True,\n",
" \"gender\": True,\n",
" \"Department\": True,\n",
" \"Image\": True,\n",
" \"_id\": False,\n",
" },\n",
")"
]
}
],
Expand All @@ -705,7 +712,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
"version": "3.11.8"
}
},
"nbformat": 4,
Expand Down
Loading
Loading