Wiki
linter / quality (push) Successful in 5m1s
tests / ci (8.4) (push) Successful in 5m8s
tests / ci (8.5) (push) Successful in 6m31s

This commit is contained in:
2026-09-15 19:44:58 +02:00
parent ca6c9fe38c
commit 6d4fdffee9
82 changed files with 29906 additions and 151 deletions
+85 -45
View File
@@ -1,6 +1,5 @@
<script setup lang="ts">
// import { Form } from '@inertiajs/vue3';
import { useForm } from '@inertiajs/vue3';
import { ref, watch } from 'vue';
import {
Form,
@@ -17,6 +16,7 @@ import type {
Dataset,
InitializationMethod,
PerceptronType,
ValidationErrors,
} from '@/types/perceptron';
import Button from './ui/button/Button.vue';
import Card from './ui/card/Card.vue';
@@ -36,6 +36,8 @@ const props = defineProps<{
defaultLearningRate: number;
sessionId: string;
defaultMaxIterations: number;
maxIterationsLimit: number;
errors: ValidationErrors;
}>();
const selectedDatasetCopy = ref(props.selectedDataset);
@@ -45,6 +47,52 @@ const hiddenLayersNeurons = ref(props.hiddenLayersNeurons);
const minError = ref(props.minError);
const learningRate = ref(props.defaultLearningRate);
const maxIterations = ref(props.defaultMaxIterations);
const maxIterationsInput = ref<{
inputElement: HTMLInputElement | null;
} | null>(null);
const form = useForm({
type: props.type,
dataset: '',
weight_init_method: selectedMethod.value,
hidden_layers: hiddenLayers.value,
hidden_layers_neurons: hiddenLayersNeurons.value,
min_error: minError.value,
learning_rate: learningRate.value,
session_id: props.sessionId,
training_id: '',
max_iterations: maxIterations.value,
});
function handleMaxIterationsInput(event: Event) {
const input = event.target as HTMLInputElement;
const numericValue = Number(input.value);
const normalizedValue = Number.isFinite(numericValue)
? Math.min(Math.max(numericValue, 1), props.maxIterationsLimit)
: 1;
console.debug('[max_iterations] native input', {
raw: input.value,
numericValue,
normalizedValue,
limit: props.maxIterationsLimit,
});
input.value = String(normalizedValue);
maxIterations.value = normalizedValue;
}
watch(maxIterations, (value) => {
const input = maxIterationsInput.value?.inputElement;
console.debug('[max_iterations] ref changed', {
value,
displayed: input?.value,
});
if (input && input.value !== String(value)) {
input.value = String(value);
}
});
watch(selectedDatasetCopy, (newvalue) => {
const selectedDatasetCopy = props.datasets.find(
@@ -85,46 +133,32 @@ function startTraining() {
return;
}
trainingId.value = `${props.sessionId}-${Date.now()}`; // Unique training ID based on session and timestamp
emit('update:trainingId', trainingId.value); // Emit the training ID to the parent component
trainingId.value = `${props.sessionId}-${Date.now()}`;
emit('update:trainingId', trainingId.value);
fetch('/api/perceptron/run', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'same-origin',
body: JSON.stringify({
type: props.type,
dataset: selectedDatasetCopy.value,
weight_init_method: selectedMethod.value,
hidden_layers: hiddenLayers.value,
hidden_layers_neurons: hiddenLayersNeurons.value,
min_error: minError.value,
learning_rate: learningRate.value,
session_id: props.sessionId,
training_id: trainingId.value,
max_iterations: maxIterations.value,
}),
})
.then((response) => {
if (!response.ok) {
if (response.status === 429) {
alert('Trop de requêtes pour mon petit serveur. Veuillez réessayer dans une minute.');
} else {
alert('Erreur lors du lancement de l\'entraînement. Veuillez réessayer.');
}
Object.assign(form, {
type: props.type,
dataset: selectedDatasetCopy.value,
weight_init_method: selectedMethod.value,
hidden_layers: hiddenLayers.value,
hidden_layers_neurons: hiddenLayersNeurons.value,
min_error: minError.value,
learning_rate: learningRate.value,
session_id: props.sessionId,
training_id: trainingId.value,
max_iterations: maxIterations.value,
});
throw new Error('Network response was not ok');
}
return response.json();
})
.then((data) => {
console.log('Perceptron training started:', data);
})
.catch((error) => {
console.error('Error starting perceptron training:', error);
});
console.debug('[max_iterations] submitting', {
displayed: maxIterationsInput.value?.inputElement?.value,
refValue: maxIterations.value,
formValue: form.max_iterations,
limit: props.maxIterationsLimit,
});
form.post('/perceptron/run', {
preserveScroll: true,
});
}
const emit = defineEmits(['update:selectedDataset', 'update:trainingId']);
@@ -161,10 +195,11 @@ watch(selectedDatasetCopy, (newValue) => {
v-bind:key="dataset.label"
:value="dataset.label"
>
{{ dataset.label }}
{{ dataset.label.replace(/_/g, ' ') }}
</NativeSelectOption>
</NativeSelect>
</FormControl>
<div v-if="props.errors?.selectedDatasetCopy">{{ props.errors?.selectedDatasetCopy }}</div>
</FormItem>
</FormField>
@@ -200,6 +235,7 @@ watch(selectedDatasetCopy, (newValue) => {
<FormControl>
<!-- TODO : MAX input -->
<Input
ref="maxIterationsInput"
type="number"
v-model="hiddenLayers"
min="1"
@@ -264,17 +300,21 @@ watch(selectedDatasetCopy, (newValue) => {
<!-- MAX ITERATIONS -->
<FormField name="max_iterations">
<FormItem>
<FormLabel>Nombre maximum d'itérations</FormLabel>
<FormLabel>Nombre maximum d'époques</FormLabel>
<FormControl>
<Input
type="number"
v-model="maxIterations"
min="0"
max="5000"
:model-value="maxIterations"
min="1"
:max="props.maxIterationsLimit"
step="1"
class="w-min"
@input="handleMaxIterationsInput"
/>
</FormControl>
<div v-if="form.errors.max_iterations || props.errors.max_iterations">
{{ form.errors.max_iterations || props.errors.max_iterations }}
</div>
</FormItem>
</FormField>
</Form>