Skip to content
Snippets Groups Projects
Commit bc2ec90d authored by thomas.blanc.2@etu.univ-amu.fr's avatar thomas.blanc.2@etu.univ-amu.fr
Browse files

Fixed model edition

parent 94f78063
Branches
No related tags found
No related merge requests found
...@@ -302,5 +302,79 @@ export const api = { ...@@ -302,5 +302,79 @@ export const api = {
} catch (error) { } catch (error) {
return null return null
} }
},
async postModel (model) {
const url = this.$serverurl + 'models'
const token = await localStorage.getItem('token')
try {
const response = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token
},
body: JSON.stringify({
name: model.name,
shortDescription: model.shortDescription,
longDescription: model.longDescription,
performance: model.performance,
performanceUnit: model.performanceUnit,
parameterCount: model.parameterCount,
tags: model.tags
})
})
return await response.json()
} catch (error) {
return null
}
},
async putModel (id, model) {
const url = serverurl + 'models' + '?id=' + id
const token = await localStorage.getItem('token')
const response = await fetch(url, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token
},
body: JSON.stringify({
name: model.name,
shortDescription: model.shortDescription,
longDescription: model.longDescription,
performance: model.performance,
performanceUnit: model.performanceUnit,
parameterCount: model.parameterCount,
tags: model.tags
})
})
try {
return await response.json()
} catch (error) {
return null
}
},
async uploadModelFile (id, file) {
const data = new FormData()
const url = serverurl + 'models/upload'
const token = await localStorage.getItem('token')
data.append('file', file)
data.append('id', id)
try {
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token
},
body: data
})
if (response.status !== 200) return false
return true
} catch (error) {
return false
}
} }
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="markdownEditor container"> <div class="markdownEditor container">
<b-tabs> <b-tabs>
<b-tab-item label="Edit" class="edit"> <b-tab-item label="Edit" class="edit">
<b-input type="textarea" v-model="input"/> <b-input type="textarea" v-model="input" maxlength="5000"/>
</b-tab-item> </b-tab-item>
<b-tab-item label="Preview"> <b-tab-item label="Preview">
......
<template>
<div class="modal-card">
<b-progress :value="progress" size="is-large" show-value :type="status">
{{statusMessage}}
</b-progress>
<b-progress v-if="subProgress" size="is-large">
{{subMessage}}
</b-progress>
<b-button
v-if="progress === 100"
type="is-success"
tag="router-link"
:to="{ name: 'Model', query: { id: model.id } }"
>
Go to model page
</b-button>
</div>
</template>
<script>
import { api } from '@/api.js'
export default {
name: 'ModelUpdate',
props: {
model: {
type: Object,
default: function () {
return {}
}
}
},
data () {
return {
progress: 0,
status: 'is-primary',
statusMessage: '',
subProgress: false,
subMessage: '',
modelId: null
}
},
mounted () {
this.saveModel()
},
methods: {
preCheck () {
if (this.model.name === undefined || this.model.name === null || this.model.name === '') {
this.setError('The model name is empty')
return false
}
return true
},
setProgress (step) {
switch (step) {
case 0:
this.statusMessage = 'Sending description'
this.progress = 25
break
case 1:
this.statusMessage = 'Sending model file'
this.progress = 50
break
case 2:
this.statusMessage = 'Sending custom layers model'
this.progress = 75
break
case 3:
this.statusMessage = 'Update completed !'
this.progress = 100
this.status = 'is-success'
break
}
},
setError (message) {
this.statusMessage = message
this.status = 'is-danger'
},
setSubMessage (message) {
this.subMessage = message
},
async saveModel () {
if (!this.preCheck()) return
this.setProgress(0)
var response = await api.putModel(this.model.id, this.model)
if (response.error) {
this.setError(response.message)
return
} else {
this.modelId = response.message
}
if (this.model.file !== undefined) {
console.log('Upload model ' + this.model.file)
this.setProgress(1)
if (!await api.uploadModelFile(this.model.id, this.model.file)) {
this.setError('Model upload error')
return
}
}
if (this.model.customLayers !== undefined) {
console.log('Upload layers ' + this.model.customLayers)
this.setProgress(2)
if (!await this.uploadLayers()) {
this.setError('Custom layer upload error')
return
}
}
this.setProgress(3)
},
async uploadLayers () {
this.subProgress = true
const token = await localStorage.getItem('token')
for (var i = 0; i < this.model.customLayers.length; i++) {
const layer = this.model.customLayers[i]
const data = new FormData()
const url = this.$serverurl + 'models/uploadLayer'
this.subMessage = 'Uploading ' + layer.name
console.log('Uploading layer ' + i + ' | ' + layer.file)
if (layer.file === undefined) continue
if (layer.name === undefined) continue
data.append('file', layer.file)
data.append('name', layer.name)
data.append('id', this.modelId)
try {
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token
},
body: data
})
if (response.status !== 200) return false
} catch (error) {
return false
}
}
this.subProgress = false
return true
}
}
}
</script>
<style>
</style>
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
</template> </template>
<script> <script>
import { api } from '@/api.js'
export default { export default {
name: 'ModelUpload', name: 'ModelUpload',
props: { props: {
...@@ -42,6 +44,14 @@ export default { ...@@ -42,6 +44,14 @@ export default {
this.saveModel() this.saveModel()
}, },
methods: { methods: {
preCheck () {
if (this.model.name === undefined || this.model.name === null || this.model.name === '') {
this.setError('The model name is empty')
return false
}
return true
},
setProgress (step) { setProgress (step) {
switch (step) { switch (step) {
case 0: case 0:
...@@ -71,8 +81,9 @@ export default { ...@@ -71,8 +81,9 @@ export default {
this.subMessage = message this.subMessage = message
}, },
async saveModel () { async saveModel () {
if (!this.preCheck()) return
this.setProgress(0) this.setProgress(0)
var response = await this.uploadModel() var response = await api.postModel(this.model)
if (response.error) { if (response.error) {
this.setError(response.message) this.setError(response.message)
return return
...@@ -83,7 +94,7 @@ export default { ...@@ -83,7 +94,7 @@ export default {
if (this.model.file !== undefined) { if (this.model.file !== undefined) {
console.log('Upload model ' + this.model.file) console.log('Upload model ' + this.model.file)
this.setProgress(1) this.setProgress(1)
if (!await this.uploadModelFile()) { if (!await api.uploadModelFile(this.modelId, this.model.file)) {
this.setError('Model upload error') this.setError('Model upload error')
return return
} }
...@@ -100,54 +111,6 @@ export default { ...@@ -100,54 +111,6 @@ export default {
this.setProgress(3) this.setProgress(3)
}, },
async uploadModel () {
const url = this.$serverurl + 'models'
const token = await localStorage.getItem('token')
try {
const response = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token
},
body: JSON.stringify({
name: this.model.name,
shortDescription: this.model.shortDescription,
longDescription: this.model.longDescription,
performance: this.model.performance,
performanceUnit: this.model.performanceUnit,
parameterCount: this.model.parameterCount,
tags: this.model.tags
})
})
return await response.json()
} catch (error) {
return null
}
},
async uploadModelFile () {
const data = new FormData()
const url = this.$serverurl + 'models/upload'
const token = await localStorage.getItem('token')
data.append('file', this.model.file)
data.append('id', this.modelId)
try {
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token
},
body: data
})
if (response.status !== 200) return false
return true
} catch (error) {
return false
}
},
async uploadLayers () { async uploadLayers () {
this.subProgress = true this.subProgress = true
const token = await localStorage.getItem('token') const token = await localStorage.getItem('token')
......
<template>
<div class="modelValidator">
</div>
</template>
<script>
export default {
name: 'ModelValidator',
props: {
model: {
type: Object,
default: function () {
return {}
}
}
},
data () {
return {
errorMessage: ''
}
},
methods: {
validate () {
if (this.model.name === undefined || this.model.name === null || this.model.name === '') {
this.errorMessage = 'The model name is empty'
return false
}
return true
}
}
}
</script>
<style>
</style>
...@@ -31,9 +31,14 @@ ...@@ -31,9 +31,14 @@
<small>{{model.performanceUnit}}: </small><strong>{{model.performance}}</strong> <small>{{model.performanceUnit}}: </small><strong>{{model.performance}}</strong>
<br> <br>
<br> <br>
<div v-if="model.checksum">
<b-button v-if="model.checksum" type="is-primary" size="is-medium" icon-left="download"> <b-button v-if="model.checksum" type="is-primary" size="is-medium" icon-left="download">
Download model Download model
</b-button> </b-button>
<br>
<br>
<small>Checksum: {{model.checksum}}</small>
</div>
<h2 v-else class="title is-5">No file provided</h2> <h2 v-else class="title is-5">No file provided</h2>
<hr> <hr>
<strong>{{model.customLayers.length}} customs layers</strong> <strong>{{model.customLayers.length}} customs layers</strong>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<b-steps v-model="activeStep"> <b-steps v-model="activeStep">
<b-step-item step="1" label="Description" clickable> <b-step-item step="1" label="Description" clickable>
<b-field label="Model name"> <b-field label="Model name">
<b-input maxlength="30" size="is-large" v-model="model.name"/> <b-input minlength="3" maxlength="100" size="is-large" v-model="model.name"/>
</b-field> </b-field>
<b-field label="Short description"> <b-field label="Short description">
...@@ -16,13 +16,13 @@ ...@@ -16,13 +16,13 @@
<b-field label="Performance"> <b-field label="Performance">
<b-field> <b-field>
<b-input type="number" placeholder="98" step="0.01" v-model="model.performance"/> <b-input type="number" placeholder="98" max="10000000" step="0.01" v-model="model.performance"/>
<b-autocomplete open-on-focus placeholder="accuracy" :data="performanceTypes" v-model="model.performanceUnit"/> <b-autocomplete open-on-focus placeholder="accuracy" :data="performanceTypes" v-model="model.performanceUnit" maxlength="50"/>
</b-field> </b-field>
</b-field> </b-field>
<b-field label="Number of parameters"> <b-field label="Number of parameters">
<b-input type="number" min="0" placeholder="0" v-model="model.parameterCount"/> <b-input type="number" min="0" max="10000000" placeholder="0" v-model="model.parameterCount"/>
</b-field> </b-field>
</b-step-item> </b-step-item>
......
<template> <template>
<div class="modelEdit container"> <div class="modelEdit container">
<div class="box"> <div class="box">
<h1 class="title">Model name</h1> <b-tabs>
<b-field> <b-tab-item label="Description">
<b-input maxlength="30" size="is-large" v-model="model.name"/> <h1 class="title">Description</h1>
<b-field label="Model name">
<b-input minlength="3" maxlength="100" size="is-large" v-model="model.name"/>
</b-field> </b-field>
<hr>
<h1 class="title">Description</h1>
<b-field label="Short description"> <b-field label="Short description">
<b-input maxlength="200" type="textarea" v-model="model.shortDescription"/> <b-input maxlength="200" type="textarea" v-model="model.shortDescription"/>
</b-field> </b-field>
...@@ -18,21 +18,24 @@ ...@@ -18,21 +18,24 @@
<b-field label="Performance"> <b-field label="Performance">
<b-field> <b-field>
<b-input type="number" placeholder="98" step="0.01" v-model="model.performance"/> <b-input type="number" placeholder="98" max="10000000" step="0.01" v-model="model.performance"/>
<b-autocomplete open-on-focus placeholder="accuracy" :data="performanceTypes" v-model="model.performanceUnit"/> <b-autocomplete open-on-focus placeholder="accuracy" :data="performanceTypes" v-model="model.performanceUnit" maxlength="50"/>
</b-field> </b-field>
</b-field> </b-field>
<b-field label="Number of parameters"> <b-field label="Number of parameters">
<b-input type="number" min="0" placeholder="0" v-model="model.parameterCount"/> <b-input type="number" min="0" max="10000000" placeholder="0" v-model="model.parameterCount"/>
</b-field> </b-field>
</b-tab-item>
<hr> <b-tab-item label="Tags">
<h1 class="title">Tags</h1> <h1 class="title">Tags</h1>
<tagEditor v-bind:modelTags="model.tags" v-on:update-tags="model.tags = $event"/> <tagEditor v-bind:modelTags="model.tags" v-on:update-tags="model.tags = $event"/>
</b-tab-item>
<hr> <b-tab-item label="Files">
<h1 class="title">Files</h1> <h1 class="title">Files</h1>
<h2 class="subtitle has-text-danger">Uploading files will replace the current files</h2>
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<b-field label="Model"> <b-field label="Model">
...@@ -49,25 +52,25 @@ ...@@ -49,25 +52,25 @@
<span v-if="model.file" class="file-name">{{ model.file.name }}</span> <span v-if="model.file" class="file-name">{{ model.file.name }}</span>
</b-field> </b-field>
</div> </div>
<div class="column rightColumn"> <div class="column rightColumn">
<layersEditor v-bind:layers="model.customLayers" v-on:update-layers="model.customLayers = $event"/> <layersEditor v-bind:layers="model.customLayers" v-on:update-layers="model.customLayers = $event"/>
</div> </div>
</div> </div>
</b-tab-item>
</div> <b-tab-item label="Danger">
<div class="box">
<b-button type="is-danger" @click="removePrompt" expanded>Delete model</b-button> <b-button type="is-danger" @click="removePrompt" expanded>Delete model</b-button>
</b-tab-item>
</b-tabs>
</div> </div>
<div class="box buttons"> <div class="box buttons">
<b-button tag="router-link" :to="{ name: 'Account' }">Cancel</b-button> <b-button tag="router-link" :to="{ name: 'Account' }">Cancel</b-button>
<b-button type="is-success" @click="openUploadModal">Save</b-button> <b-button type="is-success" @click="openUpdateModal">Save</b-button>
</div> </div>
<b-modal :active.sync="isUploadModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal> <b-modal :active.sync="isUpdateModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal>
<ModelUpload v-bind:model="model"/> <ModelUpdate v-bind:model="model"/>
</b-modal> </b-modal>
</div> </div>
</template> </template>
...@@ -76,7 +79,7 @@ ...@@ -76,7 +79,7 @@
import markdownEditor from '@/components/MarkdownEditor.vue' import markdownEditor from '@/components/MarkdownEditor.vue'
import tagEditor from '@/components/TagEditor.vue' import tagEditor from '@/components/TagEditor.vue'
import layersEditor from '@/components/LayersEditor.vue' import layersEditor from '@/components/LayersEditor.vue'
import ModelUpload from '@/components/ModelUpload.vue' import ModelUpdate from '@/components/ModelUpdate.vue'
import { api } from '@/api.js' import { api } from '@/api.js'
export default { export default {
...@@ -85,7 +88,7 @@ export default { ...@@ -85,7 +88,7 @@ export default {
markdownEditor, markdownEditor,
tagEditor, tagEditor,
layersEditor, layersEditor,
ModelUpload ModelUpdate
}, },
props: { props: {
model: { model: {
...@@ -97,7 +100,12 @@ export default { ...@@ -97,7 +100,12 @@ export default {
}, },
data () { data () {
return { return {
isUploadModalActive: false isUpdateModalActive: false,
performanceTypes: [
'accuracy',
'error rate',
'MSE'
]
} }
}, },
mounted () { mounted () {
...@@ -123,6 +131,9 @@ export default { ...@@ -123,6 +131,9 @@ export default {
hasIcon: true, hasIcon: true,
onConfirm: () => api.removeModel(this.model.id) onConfirm: () => api.removeModel(this.model.id)
}) })
},
openUpdateModal () {
this.isUpdateModalActive = true
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment