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.

226 lines
5.4 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. <template>
  2. <layout-text v-if="image.id">
  3. <template #header>
  4. <toolbar-laptop
  5. :doc-id="image.id"
  6. :enable-auto-labeling.sync="enableAutoLabeling"
  7. :guideline-text="project.guideline"
  8. :is-reviewd="image.isConfirmed"
  9. :total="images.count"
  10. class="d-none d-sm-block"
  11. @click:clear-label="clear"
  12. @click:review="confirm"
  13. >
  14. <v-btn-toggle
  15. v-model="labelOption"
  16. mandatory
  17. class="ms-2"
  18. >
  19. <v-btn icon>
  20. <v-icon>{{ mdiFormatListBulleted }}</v-icon>
  21. </v-btn>
  22. <v-btn icon>
  23. <v-icon>{{ mdiText }}</v-icon>
  24. </v-btn>
  25. </v-btn-toggle>
  26. </toolbar-laptop>
  27. <toolbar-mobile
  28. :total="images.count"
  29. class="d-flex d-sm-none"
  30. />
  31. </template>
  32. <template #content>
  33. <v-card
  34. v-shortkey="shortKeys"
  35. @shortkey="addOrRemove"
  36. >
  37. <v-card-title>
  38. <label-group
  39. v-if="labelOption === 0"
  40. :labels="labels"
  41. :annotations="annotations"
  42. :single-label="project.singleClassClassification"
  43. @add="add"
  44. @remove="remove"
  45. />
  46. <label-select
  47. v-else
  48. :labels="labels"
  49. :annotations="annotations"
  50. :single-label="project.singleClassClassification"
  51. @add="add"
  52. @remove="remove"
  53. />
  54. </v-card-title>
  55. <v-divider />
  56. <v-img
  57. contain
  58. :src="image.url"
  59. :max-height="imageSize.height"
  60. class="grey lighten-2"
  61. />
  62. </v-card>
  63. </template>
  64. <template #sidebar>
  65. <list-metadata :metadata="image.meta" />
  66. </template>
  67. </layout-text>
  68. </template>
  69. <script>
  70. import _ from 'lodash'
  71. import { mdiText, mdiFormatListBulleted } from '@mdi/js'
  72. import { toRefs } from '@nuxtjs/composition-api'
  73. import LabelGroup from '@/components/tasks/textClassification/LabelGroup'
  74. import LabelSelect from '@/components/tasks/textClassification/LabelSelect'
  75. import LayoutText from '@/components/tasks/layout/LayoutText'
  76. import ListMetadata from '@/components/tasks/metadata/ListMetadata'
  77. import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
  78. import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
  79. import { useLabelList } from '@/composables/useLabelList'
  80. export default {
  81. components: {
  82. LabelGroup,
  83. LabelSelect,
  84. LayoutText,
  85. ListMetadata,
  86. ToolbarLaptop,
  87. ToolbarMobile
  88. },
  89. layout: 'workspace',
  90. validate({ params, query }) {
  91. return /^\d+$/.test(params.id) && /^\d+$/.test(query.page)
  92. },
  93. setup() {
  94. const { state, getLabelList, shortKeys } = useLabelList()
  95. return {
  96. ...toRefs(state),
  97. getLabelList,
  98. shortKeys,
  99. }
  100. },
  101. data() {
  102. return {
  103. annotations: [],
  104. images: [],
  105. project: {},
  106. enableAutoLabeling: false,
  107. labelOption: 0,
  108. imageSize: {
  109. height: 0,
  110. width: 0
  111. },
  112. mdiText,
  113. mdiFormatListBulleted
  114. }
  115. },
  116. async fetch() {
  117. this.images = await this.$services.example.fetchOne(
  118. this.projectId,
  119. this.$route.query.page,
  120. this.$route.query.q,
  121. this.$route.query.isChecked
  122. )
  123. const image = this.images.items[0]
  124. this.setImageSize(image)
  125. if (this.enableAutoLabeling) {
  126. await this.autoLabel(image.id)
  127. }
  128. await this.list(image.id)
  129. },
  130. computed: {
  131. projectId() {
  132. return this.$route.params.id
  133. },
  134. image() {
  135. if (_.isEmpty(this.images) || this.images.items.length === 0) {
  136. return {}
  137. } else {
  138. return this.images.items[0]
  139. }
  140. }
  141. },
  142. watch: {
  143. '$route.query': '$fetch',
  144. enableAutoLabeling(val) {
  145. if (val) {
  146. this.list(this.image.id)
  147. }
  148. }
  149. },
  150. async created() {
  151. this.getLabelList(this.projectId)
  152. this.project = await this.$services.project.findById(this.projectId)
  153. },
  154. methods: {
  155. async list(imageId) {
  156. this.annotations = await this.$services.textClassification.list(this.projectId, imageId)
  157. },
  158. async remove(id) {
  159. await this.$services.textClassification.delete(this.projectId, this.image.id, id)
  160. await this.list(this.image.id)
  161. },
  162. async add(labelId) {
  163. await this.$services.textClassification.create(this.projectId, this.image.id, labelId)
  164. await this.list(this.image.id)
  165. },
  166. async addOrRemove(event) {
  167. const labelId = parseInt(event.srcKey, 10)
  168. const annotation = this.annotations.find(item => item.label === labelId)
  169. if (annotation) {
  170. await this.remove(annotation.id)
  171. } else {
  172. await this.add(labelId)
  173. }
  174. },
  175. async clear() {
  176. await this.$services.textClassification.clear(this.projectId, this.image.id)
  177. await this.list(this.image.id)
  178. },
  179. async autoLabel(imageId) {
  180. try {
  181. await this.$services.textClassification.autoLabel(this.projectId, imageId)
  182. } catch (e) {
  183. console.log(e.response.data.detail)
  184. }
  185. },
  186. async confirm() {
  187. await this.$services.example.confirm(this.projectId, this.image.id)
  188. await this.$fetch()
  189. },
  190. setImageSize(val) {
  191. const img = new Image()
  192. const self = this
  193. img.onload = function() {
  194. self.imageSize.height = this.height
  195. self.imageSize.width = this.width
  196. }
  197. img.src = val.url
  198. }
  199. }
  200. }
  201. </script>
  202. <style scoped>
  203. .text-pre-wrap {
  204. white-space: pre-wrap !important;
  205. }
  206. </style>