add button to create new class without images closes #14

This commit is contained in:
Andre Henriques 2024-04-16 10:37:18 +01:00
parent f4e70d7a73
commit 7d742e7970
6 changed files with 180 additions and 67 deletions

View File

@ -459,6 +459,45 @@ func handleDataUpload(handle *Handle) {
return c.SendJSON(model.Id) return c.SendJSON(model.Id)
}) })
// Create New class
type CreateNewEmptyClass struct {
Id string `json:"id" validate:"required"`
Name string `json:"name" validate:"required"`
}
PostAuthJson(handle, "/models/data/class/new", User_Normal, func(c *Context, obj *CreateNewEmptyClass) *Error {
model, err := GetBaseModel(c.Db, obj.Id)
if err == ModelNotFoundError {
return c.JsonBadRequest("Model not found")
}
if model.ModelType != 2 && model.Status != CONFIRM_PRE_TRAINING || model.ModelType == 2 && model.Status != CONFIRM_PRE_TRAINING && model.Status != READY {
return c.JsonBadRequest("Model not in the correct status for adding new class")
}
var baseOrder struct {
Order int `db:"class_order"`
}
err = GetDBOnce(c, &baseOrder, "model_classes where model_id=$1 order by class_order desc;", model.Id)
if err != nil {
return c.E500M("Could not create class", err)
}
id, err := model_classes.CreateClass(c.Db, model.Id, baseOrder.Order+1, obj.Name)
if err == model_classes.ClassAlreadyExists {
return c.JsonBadRequest("Class Already exists")
} else if err != nil {
return c.E500M("Could not create class", err)
}
var modelClass model_classes.ModelClass
err = GetDBOnce(c, &modelClass, "model_classes where id=$1;", id)
if err != nil {
return c.E500M("Failed to get class information but class was creted", err)
}
return c.SendJSON(modelClass)
})
// ------ // ------
// ------ CLASS DATA UPLOAD // ------ CLASS DATA UPLOAD
// ------ // ------

View File

@ -0,0 +1,11 @@
<script lang="ts">
function updateSize() {
let s = document.body.getBoundingClientRect();
document.body.style.minHeight = `${Math.max(window.innerHeight, s.height)}px`;
}
$effect(() => {
updateSize();
});
</script>
<svelte:window on:scroll={updateSize} />

View File

@ -99,3 +99,19 @@ export async function postFormData(url: string, body: FormData) {
return r.json(); return r.json();
} }
export async function showMessage(
e: any,
messages: any,
message = 'Could not complete request'
): Promise<boolean> {
if (e == null) {
return false;
} else if (e instanceof Response) {
messages.display(await e.json());
return true;
} else {
messages.display(message);
return true;
}
}

View File

@ -42,6 +42,7 @@
import ModelDataPage from './ModelDataPage.svelte'; import ModelDataPage from './ModelDataPage.svelte';
import 'src/styles/forms.css'; import 'src/styles/forms.css';
import KeepPageSize from 'src/lib/KeepPageSize.svelte';
let model: Promise<Model> = $state(new Promise(() => {})); let model: Promise<Model> = $state(new Promise(() => {}));
let _model: Model | undefined = $state(undefined); let _model: Model | undefined = $state(undefined);
@ -87,7 +88,6 @@
}); });
let resetMessages: MessageSimple; let resetMessages: MessageSimple;
async function resetModel() { async function resetModel() {
resetMessages.display(''); resetMessages.display('');
@ -125,11 +125,7 @@
{/await} {/await}
</svelte:head> </svelte:head>
<!-- <KeepPageSize />
{{ define "run-model-card" }}
{{ end }}
-->
<main> <main>
<Tabs active="model" let:isActive nobox> <Tabs active="model" let:isActive nobox>

View File

@ -10,17 +10,22 @@
<script lang="ts"> <script lang="ts">
import Tabs from 'src/lib/Tabs.svelte'; import Tabs from 'src/lib/Tabs.svelte';
import type { Class } from './ModelData.svelte'; import type { Class } from './ModelData.svelte';
import { post, postFormData, rdelete } from 'src/lib/requests.svelte'; import { post, postFormData, rdelete, showMessage } from 'src/lib/requests.svelte';
import type { Model } from './+page.svelte'; import type { Model } from './+page.svelte';
import FileUpload from 'src/lib/FileUpload.svelte'; import FileUpload from 'src/lib/FileUpload.svelte';
import MessageSimple from 'src/lib/MessageSimple.svelte'; import MessageSimple from 'src/lib/MessageSimple.svelte';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import ZipStructure from './ZipStructure.svelte';
const dispatch = createEventDispatcher<{ reload: void }>(); const dispatch = createEventDispatcher<{ reload: void }>();
let selected_class: Class | undefined = $state(); let selected_class: Class | undefined = $state();
let { classes, model } = $props<{ classes: Class[]; model: Model }>(); let { classes, model }: { classes: Class[]; model: Model } = $props();
let createClass: { className: string } = $state({
className: ''
});
let page = $state(0); let page = $state(0);
let showNext = $state(false); let showNext = $state(false);
@ -51,11 +56,6 @@
$effect(() => { $effect(() => {
if (selected_class) { if (selected_class) {
page = 0; page = 0;
}
});
$effect(() => {
if (selected_class) {
getList(); getList();
} }
}); });
@ -88,6 +88,22 @@
uploading = Promise.resolve(); uploading = Promise.resolve();
} }
let createNewClassMessages: MessageSimple;
async function createNewClass() {
try {
const r = await post('models/data/class/new', {
id: model.id,
name: createClass.className
});
selected_class = r;
classes.push(r);
classes = classes;
getList();
} catch (e) {
showMessage(e, createNewClassMessages);
}
}
function deleteDataPoint(id: string) { function deleteDataPoint(id: string) {
try { try {
rdelete('models/data/point', { id }); rdelete('models/data/point', { id });
@ -104,9 +120,10 @@
<Tabs active={classes[0]?.name} let:isActive> <Tabs active={classes[0]?.name} let:isActive>
<div class="buttons" slot="buttons" let:setActive let:isActive> <div class="buttons" slot="buttons" let:setActive let:isActive>
<!-- TODO Auto Load 1st --> <!-- TODO Auto Load 1st -->
<div> <div style="display: flex; overflow-x: scroll;">
{#each classes as item} {#each classes as item}
<button <button
style="width: auto; white-space: nowrap;"
on:click={() => setActiveClass(item, setActive)} on:click={() => setActiveClass(item, setActive)}
class="tab" class="tab"
class:selected={isActive(item.name)} class:selected={isActive(item.name)}
@ -136,6 +153,24 @@
{#if selected_class == undefined && isActive('-----New Class-----')} {#if selected_class == undefined && isActive('-----New Class-----')}
<div class="content selected"> <div class="content selected">
<h2>Add New Class</h2> <h2>Add New Class</h2>
<Tabs active="zip" let:isActive nobox>
<div slot="buttons" let:setActive let:isActive>
<button
class="tab"
on:click|preventDefault={setActive('zip')}
class:selected={isActive('zip')}
>
Zip
</button>
<button
class="tab"
on:click|preventDefault={setActive('empty')}
class:selected={isActive('empty')}
>
Empty Class
</button>
</div>
<div class="content" class:selected={isActive('zip')}>
<form on:submit|preventDefault={uploadZip}> <form on:submit|preventDefault={uploadZip}>
<fieldset class="file-upload"> <fieldset class="file-upload">
<label for="file">Data file</label> <label for="file">Data file</label>
@ -143,34 +178,9 @@
Please provide a file that has the training and testing data<br /> 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. The file must have 2 folders one with testing images and one with training images.
<br /> <br />
Each of the folders will contain the classes of the model. The folders must be the same Each of the folders will contain the classes of the model. The folders must be the
in testing and training. The class folders must have the images for the classes. same in testing and training. The class folders must have the images for the classes.
<pre> <ZipStructure />
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> </div>
<FileUpload replace_slot bind:file accept="application/zip" notExpand> <FileUpload replace_slot bind:file accept="application/zip" notExpand>
<img src="/imgs/upload-icon.png" alt="" /> <img src="/imgs/upload-icon.png" alt="" />
@ -191,6 +201,21 @@
{/if} {/if}
</form> </form>
</div> </div>
<div class="content" class:selected={isActive('empty')}>
<form on:submit|preventDefault={createNewClass}>
<div class="form-msg">
This Creates an empty class that allows images to be added after
</div>
<fieldset>
<label for="className">Class Name</label>
<input required name="className" bind:value={createClass.className} />
</fieldset>
<MessageSimple bind:this={createNewClassMessages} />
<button> Create New Class </button>
</form>
</div>
</Tabs>
</div>
{/if} {/if}
{#if selected_class} {#if selected_class}
<div class="content selected"> <div class="content selected">

View File

@ -0,0 +1,26 @@
<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>