Skip to content

Commit

Permalink
feat: ✨ implementation ocr module for blank guns
Browse files Browse the repository at this point in the history
  • Loading branch information
nutfdt committed Oct 31, 2024
1 parent a268ca7 commit 9e833a4
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 206 deletions.
28 changes: 28 additions & 0 deletions backend/src/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,34 @@ async def imageupload(
logging.exception(e, extra=extras_logging)
raise HTTPException(status_code=500, detail=str(e))

@router.post("/identification-blank-gun")
async def imageblankgun(
image: UploadFile = File(...),
):
try:
img_bytes = image.file.read()
# Process image with ML models
alarm_model = is_alarm_weapon(img_bytes)
return {
"alarm_model": alarm_model,
"missing_text": False,
"low_quality": False,
}

except LowQuality:
return {
"alarm_model": None,
"low_quality": True,
"missing_text": False,
}
except MissingText:
return {
"alarm_model": None,
"low_quality": False,
"missing_text": True,
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

@router.post("/identification-feedback")
async def log_feedback(request: Request, user_id: Union[str, None] = Cookie(None)):
Expand Down
Binary file added frontend/src/assets/missing_marking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion frontend/src/components/ResultPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SnackbarAlert from "@/components/SnackbarAlert.vue";
import {
TYPOLOGIES,
MEASURED_GUNS_TYPOLOGIES,
isAlarmGun,
} from "@/utils/firearms-utils/index";
import { isUserUsingCrosscall } from "@/utils/isUserUsingCrosscall";
import { useSnackbarStore } from "@/stores/snackbar";
Expand Down Expand Up @@ -131,7 +132,7 @@ function sendFeedback(isCorrect: boolean) {
<h2 v-if="isDummy" class="fr-alert__title">
Arme factice de type {{ label }}
</h2>
<h2 v-else-if="store.selectedAlarmGun" class="fr-alert__title">
<h2 v-else-if="isAlarmGun()" class="fr-alert__title">
Arme d'alarme de type {{ label }}
</h2>
<h2 v-else class="fr-alert__title">
Expand Down
12 changes: 5 additions & 7 deletions frontend/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { clearLocalStorage } from "@/utils/storage-utils.js";
import { mgr } from "@/utils/authentication";

import MissingCardPage from "@/views/MissingCardPage.vue";
import IdentificationQualityImage from "@/views/GuideIdentificationFirearm/IdentificationQualityImage.vue";
import ExpertiseForm from "@/views/GuideAskingExpertise/ExpertiseForm.vue";

const HomePage = () => import("@/views/HomePage.vue");
Expand Down Expand Up @@ -41,8 +42,6 @@ const IdentificationFurtherInformations = () =>
);
const IdentificationSelectAmmo = () =>
import("@/views/GuideIdentificationFirearm/IdentificationSelectAmmo.vue");
const IdentificationBlankGun = () =>
import("@/views/GuideIdentificationFirearm/IdentificationBlankGun.vue");
const ExpertSituation = () =>
import("@/views/GuideContactExpert/ExpertSituation.vue");

Expand Down Expand Up @@ -137,10 +136,9 @@ const routes: RouteRecordRaw[] = [
component: IdentificationSelectAmmo,
},
{
path: "armes-alarme",
name: "IdentificationBlankGun",
component: IdentificationBlankGun,
meta: { title: "Identification" },
path: "qualite-image",
name: "IdentificationQualityImage",
component: IdentificationQualityImage,
},
{
path: "resultat-final",
Expand Down Expand Up @@ -265,7 +263,7 @@ const routes: RouteRecordRaw[] = [
}
} catch (error) {
console.error("Erreur signin callback:", error);
next({ name: "AuthRedirect" });
next({ name: "ErrorPage" });
}
},
},
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/stores/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ export const useStore = defineStore("result", {
const gunBarrelLength = ref(null);
const img = ref(null);
const imgUrl = ref(null);
const unresizeImage = ref(null);
const securingTutorial = ref(false);

const selectedOptions = ref([]);
const selectedAmmo = ref(undefined);
const selectedAlarmGun = ref(undefined);
const alarmModel = ref(null);
const isAlarmGunMissingText = ref(null);
const isAlarmGunLowQuality = ref(null);
const isDummy = computed(() => !!(selectedAmmo.value === "billes"));
const isModalTransparentAmmoOpened = ref(null);

Expand All @@ -26,11 +30,15 @@ export const useStore = defineStore("result", {
gunBarrelLength.value = null;
img.value = null;
imgUrl.value = null;
unresizeImage.value = null;
securingTutorial.value = false;

selectedOptions.value = [];
selectedAmmo.value = undefined;
selectedAlarmGun.value = undefined;
alarmModel.value = null;
isAlarmGunMissingText.value = null;
isAlarmGunLowQuality.value = null;
isModalTransparentAmmoOpened.value = null;
}

Expand All @@ -42,10 +50,14 @@ export const useStore = defineStore("result", {
gunBarrelLength,
img,
imgUrl,
unresizeImage,
securingTutorial,
selectedOptions,
selectedAmmo,
selectedAlarmGun,
alarmModel,
isAlarmGunMissingText,
isAlarmGunLowQuality,
isDummy,
isModalTransparentAmmoOpened,
$reset,
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/utils/firearms-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const TYPOLOGIES = {
const IdentificationTypologyResult = "IdentificationTypologyResult";
const IdentificationFurtherInformations = "IdentificationFurtherInformations";
const IdentificationSelectAmmo = "IdentificationSelectAmmo";
const IdentificationBlankGun = "IdentificationBlankGun";
const IdentificationQualityImage = "IdentificationQualityImage";
const IdentificationFinalResult = "IdentificationFinalResult";

export const identificationGuideSteps = [
Expand All @@ -48,7 +48,7 @@ export const identificationGuideStepsWithArmeAlarme = [
IdentificationTypologyResult,
IdentificationFurtherInformations,
IdentificationSelectAmmo,
IdentificationBlankGun,
IdentificationQualityImage,
IdentificationFinalResult,
] as const;

Expand All @@ -69,7 +69,7 @@ export const identificationRoutePathsWithArmeAlarme = [
"resultat-typologie",
"informations-complementaires",
"munition-type",
"armes-alarme",
"qualite-image",
"resultat-final",
] as const;

Expand All @@ -81,7 +81,7 @@ export function isAlarmGun() {
) {
return false;
}
return store.selectedAlarmGun ? true : undefined;
return store.alarmModel === "Alarm_model" ? true : undefined;
}

export const MEASURED_GUNS_TYPOLOGIES = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import {
isAlarmGun,
} from "@/utils/firearms-utils/index";
import { useStore } from "@/stores/result";
import { uploadPhotoForBlankGunDetection } from "@/api/api-client";
const store = useStore();
const router = useRouter();
const route = useRoute();
const confidenceLevel = computed(() => store.confidenceLevel);
const typology = computed(() => store.typology);
const alarmModel = computed(() => store.alarmModel);
const isAlarmGunLowQuality = computed(() => store.isAlarmGunLowQuality);
const isAlarmGunMissingText = computed(() => store.isAlarmGunMissingText);
const currentStep = ref(1);
const isLowConfidence = confidenceLevel.value === "low";
Expand Down Expand Up @@ -56,10 +60,6 @@ const goToNewRouteWithArmeAlarme = () =>
name: identificationGuideStepsWithArmeAlarme[currentStep.value - 1],
});
const isArmeAlarme = computed(
() => route.path === "/guide-identification/armes-alarme",
);
const goOnAndFollow = computed(() =>
currentStep.value === 1
? "Continuer"
Expand All @@ -74,26 +74,7 @@ const arrowOrCircleIcon = () =>
const calculateRoute = (store) => {
return store.selectedAmmo === "billes"
? { name: "IdentificationFinalResult" }
: { name: "IdentificationBlankGun" };
};
// showDiv is used to create a mini steper for alarm guns. Need to be reworked.
const backStepButtonAction = () => {
if (showDiv.value === false) {
currentStep.value--;
goToNewRouteWithArmeAlarme();
} else {
showDiv.value = false;
}
};
const nextStepButtonAction = () => {
if (showDiv.value === false) {
showDiv.value = true;
} else {
currentStep.value++;
goToNewRouteWithArmeAlarme();
}
: { name: "IdentificationQualityImage" };
};
function handlePreviousButtonClick() {
Expand All @@ -105,7 +86,64 @@ function handlePreviousButtonClick() {
}
}
const showDiv = ref(false);
async function onFileSelected(event) {
const uploadedFile = event.target.files[0];
if (!uploadedFile) {
console.error("Aucun fichier sélectionné.");
return;
}
console.log("Fichier sélectionné :", uploadedFile);
try {
const result = await uploadPhotoForBlankGunDetection(uploadedFile);
console.log("Résultat de l'envoi :", result);
if (result) {
const { alarm_model, missing_text, low_quality } = result;
if (alarm_model === "Alarm_model") {
store.$patch({ alarmModel: alarm_model });
console.log("Modèle d'arme d'alarme détecté :", alarm_model);
currentStep.value++;
router.push({ name: "IdentificationFinalResult" });
} else if (low_quality === true) {
store.$patch({ isAlarmGunLowQuality: true });
} else if (missing_text === true) {
store.$patch({ isAlarmGunMissingText: true });
}
} else {
console.error("La réponse est indéfinie ou mal formée :", result);
}
} catch (error) {
console.error("Erreur lors de l'envoi de l'image :", error);
}
}
const handledImageTypes = "image/jpeg, image/png, image/jpg";
const footerValue = computed(() => {
if (isAlarmGunLowQuality) {
return {
next: "Pas de marquages, passer à l'étape suivante",
picture: "Reprendre la photo",
};
} else {
return {
next: "Non, passer à l'étape suivante",
picture: "Oui, en prendre une photo rapprochée",
};
}
});
watch(alarmModel, (newVal) => {
if (newVal === "Alarm_model" || newVal === "Not_alarm") {
setTimeout(() => {
currentStep.value++;
}, 5000);
}
});
</script>

<template>
Expand All @@ -120,7 +158,7 @@ const showDiv = ref(false);
:steps="steps"
:current-step="currentStep"
/>
<RouterView :show-div="showDiv" />
<RouterView />
</div>
</div>
<div
Expand Down Expand Up @@ -183,28 +221,6 @@ const showDiv = ref(false);
/>
</div>
</div>

<div v-else-if="isArmeAlarme" class="footer z-1">
<div class="fr-col-11 fr-col-lg-6 footer-actions mx-auto">
<DsfrButton
v-if="currentStep > 0"
class="m-1 flex justify-center w-100"
icon="ri-arrow-left-line"
:secondary="true"
label="Précédent"
@click="backStepButtonAction"
/>
<DsfrButton
class="m-1 flex justify-center w-100"
icon="ri-arrow-right-line"
:label="goOnAndFollow"
:icon-right="true"
data-testid="next-step"
@click="nextStepButtonAction"
/>
</div>
</div>

<div v-else class="footer z-1">
<div v-if="confidenceLevel === 'low'" class="fr-col-11 fr-col-lg-6 mx-auto">
<DsfrButton
Expand Down Expand Up @@ -250,6 +266,49 @@ const showDiv = ref(false);
/>
</div>
</div>

<div
v-if="$route.path === '/guide-identification/qualite-image'"
class="footer z-1"
>
<div v-if="isAlarmGunLowQuality === true || isAlarmGunMissingText === true">
<div class="fr-col-12 fr-col-lg-6 mx-auto">
<input
ref="fileInput"
data-testid="select-file"
type="file"
style="width: 0; height: 1px"
:accept="handledImageTypes"
@change="onFileSelected($event)"
/>
<DsfrButton
class="flex justify-center !w-full fr-mb-1w"
data-testid="take-a-picture"
:label="footerValue.picture"
icon="ri-camera-fill"
:icon-right="true"
@click="$refs.fileInput.click()"
/>

<DsfrButton
class="flex justify-center !w-full"
:label="footerValue.next"
:icon-right="true"
icon="ri-checkbox-circle-line"
secondary
@click="
currentStep++;
goToNewRouteWithArmeAlarme();
"
/>
</div>
</div>
<div v-else>
<div class="fr-col-11 fr-col-lg-6 footer-actions mx-auto">
<p>Redirection vers la page de résultat dans 5 secondes</p>
</div>
</div>
</div>
</template>

<style scoped>
Expand Down
Loading

0 comments on commit 9e833a4

Please sign in to comment.