Skip to content

Commit

Permalink
Merge pull request #3 from devansh-shah-11/merge-code-mark-1
Browse files Browse the repository at this point in the history
Merge code mark 1
  • Loading branch information
devansh-shah-11 authored Mar 8, 2024
2 parents 648c6e5 + be9f403 commit c465bcc
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 89 deletions.
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 @@ class Employee(BaseModel):
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)

logging.debug(f"About to insert Embeddings: {embeddings}")
# Store the data in the database
client.insert_one(
collection,
Expand All @@ -89,26 +96,30 @@ async def create_new_faceEntry(Employee: Employee):
"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 @@ async def get_employees():
# 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 @@ async def read_employee(EmployeeCode: int):
# 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 @@ async def update_employees(EmployeeCode: int, Employee: UpdateEmployee):
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

0 comments on commit c465bcc

Please sign in to comment.