mirror of https://github.com/doccano/doccano.git
pythonannotation-tooldatasetsactive-learningtext-annotationdatasetnatural-language-processingdata-labelingmachine-learning
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
6.9 KiB
272 lines
6.9 KiB
<template>
|
|
<v-card>
|
|
<v-card-title>
|
|
{{ $t('dataset.importDataTitle') }}
|
|
</v-card-title>
|
|
<v-card-text>
|
|
<v-overlay :value="isImporting">
|
|
<v-progress-circular
|
|
indeterminate
|
|
size="64"
|
|
/>
|
|
</v-overlay>
|
|
<v-select
|
|
v-model="selected"
|
|
:items="catalog"
|
|
item-text="name"
|
|
label="File format"
|
|
outlined
|
|
/>
|
|
<v-form v-model="valid">
|
|
<v-text-field
|
|
v-for="(item, key) in textFields"
|
|
:key="key"
|
|
v-model="option[key]"
|
|
:label="item.title"
|
|
:rules="requiredRules"
|
|
outlined
|
|
/>
|
|
<v-select
|
|
v-for="(val, key) in selectFields"
|
|
:key="key"
|
|
v-model="option[key]"
|
|
:items="val.enum"
|
|
:label="val.title"
|
|
outlined
|
|
>
|
|
<template #selection="{ item }">
|
|
{{ toVisualize(item) }}
|
|
</template>
|
|
<template #item="{ item }">
|
|
{{ toVisualize(item) }}
|
|
</template>
|
|
</v-select>
|
|
</v-form>
|
|
<v-sheet
|
|
v-if="selected"
|
|
:dark="!$vuetify.theme.dark"
|
|
:light="$vuetify.theme.dark"
|
|
class="mb-5 pa-5"
|
|
>
|
|
<pre>{{ example }}</pre>
|
|
</v-sheet>
|
|
<file-pond
|
|
v-if="selected && acceptedFileTypes !== '*'"
|
|
ref="pond"
|
|
chunk-uploads="true"
|
|
label-idle="Drop files here..."
|
|
:allow-multiple="true"
|
|
:accepted-file-types="acceptedFileTypes"
|
|
:server="server"
|
|
:files="myFiles"
|
|
@processfile="handleFilePondProcessfile"
|
|
@removefile="handleFilePondRemovefile"
|
|
/>
|
|
<file-pond
|
|
v-if="selected && acceptedFileTypes === '*'"
|
|
ref="pond"
|
|
chunk-uploads="true"
|
|
label-idle="Drop files here..."
|
|
:allow-multiple="true"
|
|
:server="server"
|
|
:files="myFiles"
|
|
@processfile="handleFilePondProcessfile"
|
|
@removefile="handleFilePondRemovefile"
|
|
/>
|
|
<v-data-table
|
|
v-if="errors.length > 0"
|
|
:headers="headers"
|
|
:items="errors"
|
|
class="elevation-1"
|
|
></v-data-table>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn
|
|
class='text-capitalize me-2 primary'
|
|
:disabled="isDisabled"
|
|
@click="importDataset"
|
|
>
|
|
Import
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script>
|
|
import Cookies from 'js-cookie'
|
|
import vueFilePond from "vue-filepond"
|
|
import "filepond/dist/filepond.min.css"
|
|
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type"
|
|
const FilePond = vueFilePond(
|
|
FilePondPluginFileValidateType,
|
|
)
|
|
|
|
export default {
|
|
|
|
components: {
|
|
FilePond,
|
|
},
|
|
layout: 'project',
|
|
|
|
data() {
|
|
return {
|
|
catalog: [],
|
|
selected: null,
|
|
myFiles: [],
|
|
option: {'column_data': '', 'column_label': '', 'delimiter': ''},
|
|
taskId: null,
|
|
polling: null,
|
|
errors: [],
|
|
headers: [
|
|
{ text: 'Filename', value: 'filename' },
|
|
{ text: 'Line', value: 'line' },
|
|
{ text: 'Message', value: 'message' }
|
|
],
|
|
requiredRules: [
|
|
v => !!v || 'Field value is required'
|
|
],
|
|
server: {
|
|
url: '/v1/fp',
|
|
headers: {
|
|
'X-CSRFToken': Cookies.get('csrftoken'),
|
|
},
|
|
process: {
|
|
url: '/process/',
|
|
method: 'POST',
|
|
},
|
|
patch: '/patch/',
|
|
revert: '/revert/',
|
|
restore: '/restore/',
|
|
load: '/load/',
|
|
fetch: '/fetch/'
|
|
},
|
|
uploadedFiles: [],
|
|
valid: false,
|
|
isImporting: false,
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
isDisabled() {
|
|
return this.uploadedFiles.length === 0 || this.taskId !== null || !this.valid
|
|
},
|
|
properties() {
|
|
const item = this.catalog.find(item => item.name === this.selected)
|
|
if (item) {
|
|
return item.properties
|
|
} else {
|
|
return {}
|
|
}
|
|
},
|
|
textFields() {
|
|
const asArray = Object.entries(this.properties)
|
|
const textFields = asArray.filter(([key, value]) => !('enum' in value))
|
|
return Object.fromEntries(textFields)
|
|
},
|
|
selectFields() {
|
|
const asArray = Object.entries(this.properties)
|
|
const textFields = asArray.filter(([key, value]) => 'enum' in value)
|
|
return Object.fromEntries(textFields)
|
|
},
|
|
acceptedFileTypes() {
|
|
const item = this.catalog.find(item => item.name === this.selected)
|
|
if (item) {
|
|
return item.acceptTypes
|
|
} else {
|
|
return ''
|
|
}
|
|
},
|
|
example() {
|
|
const item = this.catalog.find(item => item.name === this.selected)
|
|
if (item) {
|
|
const column_data = 'column_data'
|
|
const column_label = 'column_label'
|
|
if (column_data in this.option && column_label in this.option) {
|
|
return item.example.replaceAll(column_data, this.option[column_data])
|
|
.replaceAll(column_label, this.option[column_label])
|
|
.trim()
|
|
} else {
|
|
return item.example.trim()
|
|
}
|
|
} else {
|
|
return ''
|
|
}
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
selected() {
|
|
const item = this.catalog.find(item => item.name === this.selected)
|
|
for (const [key, value] of Object.entries(item.properties)) {
|
|
this.option[key] = value.default
|
|
}
|
|
this.myFiles = []
|
|
for (const file of this.uploadedFiles) {
|
|
this.$services.parse.revert(file.serverId)
|
|
}
|
|
this.uploadedFiles = []
|
|
this.errors = []
|
|
}
|
|
},
|
|
|
|
async created() {
|
|
this.catalog = await this.$services.catalog.list(this.$route.params.id)
|
|
this.pollData()
|
|
},
|
|
|
|
beforeDestroy() {
|
|
clearInterval(this.polling)
|
|
},
|
|
|
|
methods: {
|
|
handleFilePondProcessfile(error, file) {
|
|
console.log(error)
|
|
this.uploadedFiles.push(file)
|
|
this.$nextTick()
|
|
},
|
|
handleFilePondRemovefile(error, file) {
|
|
console.log(error)
|
|
const index = this.uploadedFiles.findIndex(item => item.id === file.id)
|
|
if (index > -1) {
|
|
this.uploadedFiles.splice(index, 1)
|
|
this.$nextTick()
|
|
}
|
|
},
|
|
async importDataset() {
|
|
this.isImporting = true
|
|
this.taskId = await this.$services.parse.analyze(
|
|
this.$route.params.id,
|
|
this.selected,
|
|
this.uploadedFiles.map(item => item.serverId),
|
|
this.option
|
|
)
|
|
},
|
|
pollData() {
|
|
this.polling = setInterval(async() => {
|
|
if (this.taskId) {
|
|
const res = await this.$services.taskStatus.get(this.taskId)
|
|
if (res.ready) {
|
|
this.taskId = null
|
|
this.errors = res.result.error
|
|
this.myFiles = []
|
|
this.uploadedFiles = []
|
|
this.isImporting = false
|
|
}
|
|
}
|
|
}, 3000)
|
|
},
|
|
toVisualize(text) {
|
|
if (text === '\t') {
|
|
return 'Tab'
|
|
} else if (text === ' ') {
|
|
return 'Space'
|
|
} else if (text === '') {
|
|
return 'None'
|
|
} else {
|
|
return text
|
|
}
|
|
}
|
|
},
|
|
};
|
|
</script>
|