188 lines
6.1 KiB
Svelte
188 lines
6.1 KiB
Svelte
<script lang="ts" context="module">
|
|
export type Class = {
|
|
name: string;
|
|
id: string;
|
|
}
|
|
</script>
|
|
<script lang="ts">
|
|
import FileUpload from "src/lib/FileUpload.svelte";
|
|
import Tabs from "src/lib/Tabs.svelte";
|
|
import type { Model } from "./+page.svelte";
|
|
import { postFormData, get } from "src/lib/requests.svelte";
|
|
import MessageSimple from "src/lib/MessageSimple.svelte";
|
|
import { createEventDispatcher } from "svelte";
|
|
import ModelTable from "./ModelTable.svelte";
|
|
|
|
let { model } = $props<{model: Model}>();
|
|
|
|
let classes: Class[] = $state([]);
|
|
|
|
let file: File | undefined = $state();
|
|
|
|
const dispatch = createEventDispatcher<{
|
|
reload: void
|
|
}>();
|
|
|
|
let uploading: Promise<void> = $state(Promise.resolve())
|
|
let numberOfInvalidImages = $state(0);
|
|
|
|
let uploadImage: MessageSimple;
|
|
|
|
async function uploadZip() {
|
|
if (!file) return;
|
|
|
|
uploading = new Promise(() => {});
|
|
|
|
let form = new FormData();
|
|
form.append('id', model.id);
|
|
form.append('file', file, 'upload.zip');
|
|
|
|
try {
|
|
await postFormData('models/data/upload', form);
|
|
dispatch('reload');
|
|
} catch (e) {
|
|
if (e instanceof Response) {
|
|
uploadImage.display(await e.json());
|
|
} else {
|
|
uploadImage.display('');
|
|
}
|
|
}
|
|
|
|
uploading = Promise.resolve();
|
|
}
|
|
|
|
$effect(() => {
|
|
getData();
|
|
});
|
|
|
|
async function getData() {
|
|
if (!model) return;
|
|
try {
|
|
let data = await get(`models/edit/classes?id=${model.id}`);
|
|
classes = data.classes
|
|
numberOfInvalidImages = data.number_of_invalid_images;
|
|
} catch {
|
|
return;
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<div class="card">
|
|
<h3>
|
|
Training data
|
|
</h3>
|
|
{#if classes.length == 0}
|
|
<p>
|
|
You need to upload data so the model can train.
|
|
</p>
|
|
<Tabs active="upload" let:isActive>
|
|
<div slot="buttons" let:setActive let:isActive>
|
|
<button class="tab" class:selected={isActive("upload")} on:click={setActive("upload")}>
|
|
Upload
|
|
</button>
|
|
<button class="tab" class:selected={isActive("create-class")} on:click={setActive("create-class")}>
|
|
Create Class
|
|
</button>
|
|
<button class="tab" class:selected={isActive("api")} on:click={setActive("api")}>
|
|
Api
|
|
</button>
|
|
</div>
|
|
<div class="content" class:selected={isActive("upload")}>
|
|
<form on:submit|preventDefault={uploadZip}>
|
|
<fieldset class="file-upload" >
|
|
<label for="file">Data file</label>
|
|
<div class="form-msg">
|
|
Please provide a file that has the training and testing data<br/>
|
|
The file must have 2 folders one with testing images and one with training images. <br/>
|
|
Each of the folders will contain the classes of the model. The folders must be the same in testing and training.
|
|
The class folders must have the images for the classes.
|
|
<pre>
|
|
training\
|
|
class1\
|
|
img1.png
|
|
img2.png
|
|
img2.png
|
|
...
|
|
class2\
|
|
img1.png
|
|
img2.png
|
|
img2.png
|
|
...
|
|
...
|
|
testing\
|
|
class1\
|
|
img1.png
|
|
img2.png
|
|
img2.png
|
|
...
|
|
class2\
|
|
img1.png
|
|
img2.png
|
|
img2.png
|
|
...
|
|
...
|
|
</pre>
|
|
</div>
|
|
<FileUpload replace_slot bind:file={file} accept="application/zip" >
|
|
<img src="/imgs/upload-icon.png" alt="" />
|
|
<span>
|
|
Upload Zip File
|
|
</span>
|
|
<div slot="replaced">
|
|
<img src="/imgs/upload-icon.png" alt="" />
|
|
<span>
|
|
File selected
|
|
</span>
|
|
</div>
|
|
</FileUpload>
|
|
</fieldset>
|
|
<MessageSimple bind:this={uploadImage} />
|
|
{#await uploading}
|
|
<button disabled>
|
|
Uploading
|
|
</button>
|
|
{:then}
|
|
<button>
|
|
Add
|
|
</button>
|
|
{/await}
|
|
</form>
|
|
</div>
|
|
<div class="content" class:selected={isActive("create-class")}>
|
|
<ModelTable classes={classes} />
|
|
</div>
|
|
<div class="content" class:selected={isActive("api")}>
|
|
TODO
|
|
</div>
|
|
</Tabs>
|
|
<div class="tabs">
|
|
</div>
|
|
{:else}
|
|
<p>
|
|
You need to upload data so the model can train.
|
|
</p>
|
|
{#if numberOfInvalidImages > 0}
|
|
<p class="danger">
|
|
There are images {numberOfInvalidImages} that were loaded that do not have the correct format. These images will be delete when the model trains.
|
|
</p>
|
|
{/if}
|
|
<Tabs active="create-class" let:isActive>
|
|
<div slot="buttons" let:setActive let:isActive>
|
|
<button class="tab" class:selected={isActive("create-class")} on:click={setActive("create-class")}>
|
|
Create Class
|
|
</button>
|
|
<button class="tab" class:selected={isActive("api")} on:click={setActive("api")}>
|
|
Api
|
|
</button>
|
|
</div>
|
|
<div class="content" class:selected={isActive("create-class")}>
|
|
<ModelTable classes={classes} />
|
|
</div>
|
|
<div class="content" class:selected={isActive("api")}>
|
|
TODO
|
|
</div>
|
|
</Tabs>
|
|
{/if}
|
|
</div>
|