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

Last changes #29

Merged
merged 7 commits into from
May 7, 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
2 changes: 2 additions & 0 deletions .github/workflows/frontend_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:
ECS_SERVICE: medical_assistant_frontend
ECR_REPOSITORY: 891377268337.dkr.ecr.us-east-1.amazonaws.com/medical_assistant_frontend
API_KEY: ${{secrets.API_KEY}}
VITE_BACKEND_URL: http://lb-medical-assistant-503996398.us-east-1.elb.amazonaws.com:8000/

jobs:
build_image_frontend:
Expand All @@ -39,6 +40,7 @@ jobs:
IMAGE_TAG: lastest
run: |

echo VITE_BACKEND_URL=${{env.VITE_BACKEND_URL}} >> ./frontend/.env
docker build -t $ECR_REPOSITORY:$IMAGE_TAG ./frontend

docker push $ECR_REPOSITORY:$IMAGE_TAG
Expand Down
27 changes: 14 additions & 13 deletions backend/api/v1/post_suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

from controllers.v1.history_clinic import extract_text_from_pdf
from controllers.v1.MRI_image import predict_tumor_by_img
from controllers.v1.validate_files import processing_file_type_based
from controllers.v1.validate_files import (
check_files,
type_based_checking,
)

from dotenv import load_dotenv
from model import GenerativeModel
Expand Down Expand Up @@ -34,24 +37,22 @@


@router.post(
"/files",
"/uploadfiles",
status_code=200,
dependencies=[
Depends(processing_file_type_based),
],
response_model=dict[str, str],
dependencies=[Depends(check_files)],
)
async def predict_tumor(
files: list[UploadFile],
):
img = None
pdf = None

for file in files:
if file.filename.split(".")[0] == "brain_mri":
img = file
elif file.filename.split(".")[0] == "clinical_history":
pdf = file
# Check the type of the files pydantic model based
dict_files = {
file.filename.split(".")[1]: type_based_checking(file) for file in files
}

# Get the image and the pdf
img = dict_files.get("jpeg") or dict_files.get("png") or dict_files.get("jpg")
pdf = dict_files.get("pdf")

# Call the function to predict the tumor
classification = await predict_tumor_by_img(img=img)
Expand Down
67 changes: 31 additions & 36 deletions backend/controllers/v1/validate_files.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Check if the number of files is correct
from fastapi import HTTPException, UploadFile
from pydantic import ValidationError
import os

from schemas.ClinicHistoryFileUploaded import ClinicHistoryFileUploaded
from schemas.MRIFileUploaded import MRIFileUploaded
Expand All @@ -11,6 +10,17 @@ def validate_quantity_files(files: list):
return len(files) != 2


def check_files(files: list[UploadFile]):
# Check if each file has an extension
if not all(["." in file.filename for file in files]):
raise HTTPException(status_code=400, detail="File without extension.")

if validate_quantity_files(files):
raise HTTPException(
status_code=400, detail="The number of files is not correct."
)


def is_type_PDF(type_file):
return type_file == "application/pdf"

Expand All @@ -19,40 +29,25 @@ def is_type_image(type_file):
return type_file in ["image/jpeg", "image/png", "image/jpg"]


def processing_file_type_based(files: list[UploadFile]):
if validate_quantity_files(files):
def type_based_checking(file: MRIFileUploaded | ClinicHistoryFileUploaded):
# Check the model type based on defined schema
if is_type_image(file.content_type):
try:
MRIFileUploaded(file=file, type=file.content_type, size=file.size)

except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e).splitlines()[2])

elif is_type_PDF(file.content_type):
try:
ClinicHistoryFileUploaded(file=file, type=file.content_type, size=file.size)

except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e).splitlines()[2])

else:
raise HTTPException(
status_code=400, detail="The number of files is not correct."
status_code=400,
detail=f"The type of the file {file.filename} is not supported.",
)

img = None
pdf = None

for file in files:
# Assign the file to the corresponding variable
if is_type_image(file.content_type):
try:
name = os.path.splitext(file.filename)[0]
img = MRIFileUploaded(
file=file, name=name, type=file.content_type, size=file.size
)

except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e).splitlines()[2])

elif is_type_PDF(file.content_type):
try:
name = os.path.splitext(file.filename)[0]
pdf = ClinicHistoryFileUploaded(
file=file, name=name, type=file.content_type, size=file.size
)

except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e).splitlines()[2])

else:
raise HTTPException(
status_code=400,
detail=f"The type of the file {file.filename} is not supported.",
)
return [img, pdf]
return file
1 change: 0 additions & 1 deletion backend/schemas/ClinicHistoryFileUploaded.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@


class ClinicHistoryFileUploaded(BaseModel):
name: Literal["clinical_history"]
file: UploadFile
type: Literal["application/pdf"]
size: Annotated[int, field_validator("size")]
Expand Down
1 change: 0 additions & 1 deletion backend/schemas/MRIFileUploaded.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@


class MRIFileUploaded(BaseModel):
name: Literal["brain_mri"]
file: UploadFile
type: Literal["image/jpeg", "image/png", "image/jpg"]
size: int
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ function App() {
// The UploadFileWrapper component is used to render the form and the model's response data
return (
<div className="flex flex-col min-h-screen">
<h1 className="text-6xl font-bold p-6">Asistente Medico</h1>
<h1 className="text-6xl font-bold p-6">
Asistente de diagnóstico médico
</h1>
<Notification notification={notification} />
<main className="flex-1 flex max-w-7xl self-center pt-16 flex-col">
<UploadFileWrapper
Expand Down
77 changes: 40 additions & 37 deletions frontend/src/components/UploadFileForm.jsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
import React from "react";

function UploadFileForm({
handleFileUpload,
expectedFiles = ["clinical_history.pdf", "brain_mri.jpeg"],
notify,
disabled,
}) {
function UploadFileForm({ handleFileUpload, notify, disabled }) {
const submitHandler = async (e) => {
e.preventDefault();
const files = e.target.elements.file.files;

if (files.length === 0) {
notify("No hay archivos seleccionados", "error");
return;
}
const pdfFiles = e.target.elements.pdf.files;
const imgFiles = e.target.elements.img.files;

if (files.length !== expectedFiles.length) {
notify(
`Por favor, suba exactamente ${expectedFiles.length} archivos`,
"error",
);
if (pdfFiles.length === 0 && imgFiles.length === 0) {
notify("No ha seleccionado ningun archivo", "error");
return;
}

const filenames = Array.from(files).map((file) => file.name);

if (
!expectedFiles.every((expectedFile) => filenames.includes(expectedFile))
) {
notify("Los archivos no tienen el formato correcto", "error");
} else if (pdfFiles.length === 0) {
notify("No ha seleccionado la historia clinica", "error");
return;
} else if (imgFiles.length === 0) {
notify("No ha seleccionado la IRM (cerebro)", "error");
return;
}

const formData = new FormData();

for (let i = 0; i < expectedFiles.length; i++) {
formData.append("files", files[i]);
for (let i = 0; i < pdfFiles.length; i++) {
formData.append("files", pdfFiles[i]);
}

for (let i = 0; i < imgFiles.length; i++) {
formData.append("files", imgFiles[i]);
}

handleFileUpload(formData);
notify("Archivos enviados exitosamente. Procesando...");
notify(
"Archivos enviados exitosamente. Por favor no refresque la pagina...",
);
};

// la IRM (cerebro)
return (
<div className="pr-8">
<form encType="multipart/form-data" onSubmit={submitHandler}>
<label className="text-2xl font-semibold" htmlFor="file">
Seleccione la IRM (cerebro) e historia clínica:
</label>
<p className="text-sm text-gray-500">
Formato esperado: clinical_history.pdf, brain_mri.jpeg
</p>
<div className="flex flex-col ">
<label className="text-2xl font-semibold" htmlFor="pdf">
Seleccione la historia clínica
</label>
<p className="text-sm text-gray-500">
Solo se aceptan pdf con tamaño inferior a 2MB
</p>
<input
type="file"
className="file-input file-input-bordered w-full max-w-xs my-4"
id="pdf"
name="pdf"
/>
<label className="text-2xl font-semibold" htmlFor="img">
Seleccione la IRM (cerebro)
</label>
<p className="text-sm text-gray-500">
Solo se aceptan imágenes con tamaño inferior a 2MB
</p>
<input
type="file"
className="file-input file-input-bordered w-full max-w-xs my-4"
id="file"
name="file"
multiple
id="img"
name="img"
/>

<button
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/services/fileUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const baseUrl = import.meta.env.VITE_BACKEND_URL;

const uploadFiles = async (formData) => {
try {
const response = await fetch(baseUrl, {
const response = await fetch(`${baseUrl}/v1/uploadfiles`, {
method: "POST",
body: formData,
});
Expand Down