Skip to content

Commit 49b34a3

Browse files
committed
Aperçu de l'image avant envoi + catégorisation IA préalable
Close #41 #46
1 parent cb8bb09 commit 49b34a3

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

changelog.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,30 @@
4444
</div>
4545
</div>
4646
</div>
47+
<div class="card">
48+
<div class="card-header">
49+
<a data-bs-toggle="collapse" href="#v27">
50+
v2.7 - Septembre 2025
51+
&nbsp;<span class="bi-caret-down-fill"></span>
52+
</a>
53+
</div>
54+
<div id="v27" class="card-collapse">
55+
<div class="card-body">
56+
<ul>
57+
<li>Ajout d'un aperçu de l'image avant l'envoi.</li>
58+
<li>Validation IA du contenu de l'image avant l'envoi.</li>
59+
</ul>
60+
</div>
61+
</div>
62+
</div>
4763
<div class="card">
4864
<div class="card-header">
4965
<a data-bs-toggle="collapse" href="#v26">
5066
v2.6 - Février 2025
5167
&nbsp;<span class="bi-caret-down-fill"></span>
5268
</a>
5369
</div>
54-
<div id="v26" class="card-collapse">
70+
<div id="v26" class="card-collapse collapse">
5571
<div class="card-body">
5672
<ul>
5773
<li>Compatibilité PHP 8.3 et 8.4.</li>

index.php

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<a href="cgu.php">Conditions Générales d'Utilisation</a> du service.
9595
</div>
9696
</div>
97+
<img src="#" id="preview" alt="preview" style="display: none; max-width: 200px; max-height: 200px;" />
9798
<h3>Options</h3>
9899
<span class="help-block"><em>Le ratio de l'image sera conservé.</em></span>
99100
<div class="mb-3">
@@ -133,8 +134,71 @@
133134
</select>
134135
</div>
135136
</div>
136-
<button class="btn btn-success" name="Submit" type="submit" <?= ($uploadDisabled ? 'disabled="disabled"' : '') ?>><span class="bi-cloud-arrow-up-fill"></span>&nbsp;Envoyer</button>
137+
<button class="btn btn-success" name="Submit" id="submit" type="submit" <?= ($uploadDisabled ? 'disabled="disabled"' : '') ?>><span class="bi-cloud-arrow-up-fill"></span>&nbsp;Envoyer</button>
137138
</form>
138139
</div>
139140
</div>
141+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js" defer></script>
142+
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js" defer></script>
143+
<script type="text/javascript">
144+
// More API functions here:
145+
// https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image
146+
let model, maxPredictions;
147+
const categorieMap = new Map([
148+
<?php foreach (_ABUSE_TYPES_ as $type => $tabInfos): ?>
149+
['<?= $type ?>', <?= $tabInfos['limite'] ?>],
150+
<?php endforeach; ?>
151+
]);
152+
153+
async function init() {
154+
// Activer l'exécution GPU avec TensorFlow.js
155+
await tf.setBackend('webgl');
156+
// load the model and metadata
157+
// Note: the pose library adds "tmImage" object to your window (window.tmImage)
158+
model = await tmImage.load('<?= _URL_HTTPS_ ?>ia_model/model.json', '<?= _URL_HTTPS_ ?>ia_model/metadata.json');
159+
maxPredictions = model.getTotalClasses();
160+
161+
// Génération d'une "miniature" d'aperçu lors de la sélection d'une image
162+
const preview = document.getElementById('preview');
163+
document.getElementById('fichier').addEventListener('change', function () {
164+
// Réactiver le bouton d'envoi
165+
document.getElementById('submit').disabled = false;
166+
167+
const file = this.files[0];
168+
if (file) {
169+
const reader = new FileReader();
170+
reader.onload = function (event) {
171+
preview.src = event.target.result;
172+
preview.style.display = 'block';
173+
}
174+
reader.readAsDataURL(file);
175+
// Prédiction type d'image
176+
predictImage(preview);
177+
}
178+
});
179+
}
180+
181+
/**
182+
* Prédire les catégories d'images
183+
* @param img contenu à analyser
184+
* @returns {Promise<void>}
185+
*/
186+
async function predictImage(img) {
187+
// Lancer la prédiction sur l'image
188+
const prediction = await model.predict(img);
189+
// Trouver la classe avec la plus grande probabilité
190+
const bestPrediction = prediction.reduce((max, p) => (p.probability > max.probability ? p : max), prediction[0]);
191+
// Cette image atteint-elle la limite pour sa catégorie la plus probable ?
192+
if (
193+
categorieMap.has(bestPrediction.className)
194+
&& (bestPrediction.probability * 100) >= categorieMap.get(bestPrediction.className)
195+
) {
196+
// Désactiver l'envoi de l'image
197+
document.getElementById('submit').disabled = true;
198+
alert(`L'image selectionnée n'est pas conforme aux CGU de la plateforme. Elle contrevient à la règle ${bestPrediction.className} (taux de précision : ${Math.round(bestPrediction.probability * 100)}%)`)
199+
}
200+
}
201+
202+
window.onload = init;
203+
</script>
140204
<?php require _TPL_BOTTOM_; ?>

template/templateV2Bottom.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<span class="text-muted">
2828
<?= _SITE_NAME_ ?>
2929
-
30-
<a href="<?= _URL_HTTPS_ ?>changelog.php">v2.6 (2025) <span class="bi-award"></span></a>
30+
<a href="<?= _URL_HTTPS_ ?>changelog.php">v2.7 (2025) <span class="bi-award"></span></a>
3131
-
3232
<a href="<?= _URL_HTTPS_ ?>stats.php">Statistiques <span class="bi-graph-up"></span></a>
3333
-

0 commit comments

Comments
 (0)