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.

237 lines
5.9 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. <annotation-progress :progress="progress" />
  66. <list-metadata :metadata="image.meta" class="mt-4" />
  67. </template>
  68. </layout-text>
  69. </template>
  70. <script>
  71. import _ from 'lodash'
  72. import { mdiText, mdiFormatListBulleted } from '@mdi/js'
  73. import { toRefs, useContext } from '@nuxtjs/composition-api'
  74. import LabelGroup from '@/components/tasks/textClassification/LabelGroup'
  75. import LabelSelect from '@/components/tasks/textClassification/LabelSelect'
  76. import LayoutText from '@/components/tasks/layout/LayoutText'
  77. import ListMetadata from '@/components/tasks/metadata/ListMetadata'
  78. import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
  79. import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
  80. import { useLabelList } from '@/composables/useLabelList'
  81. import AnnotationProgress from '@/components/tasks/sidebar/AnnotationProgress.vue'
  82. export default {
  83. components: {
  84. AnnotationProgress,
  85. LabelGroup,
  86. LabelSelect,
  87. LayoutText,
  88. ListMetadata,
  89. ToolbarLaptop,
  90. ToolbarMobile
  91. },
  92. layout: 'workspace',
  93. validate({ params, query }) {
  94. return /^\d+$/.test(params.id) && /^\d+$/.test(query.page)
  95. },
  96. setup() {
  97. const { app } = useContext()
  98. const { state, getLabelList, shortKeys } = useLabelList(app.$services.categoryType)
  99. return {
  100. ...toRefs(state),
  101. getLabelList,
  102. shortKeys,
  103. }
  104. },
  105. data() {
  106. return {
  107. annotations: [],
  108. images: [],
  109. project: {},
  110. enableAutoLabeling: false,
  111. labelOption: 0,
  112. imageSize: {
  113. height: 0,
  114. width: 0
  115. },
  116. mdiText,
  117. mdiFormatListBulleted,
  118. progress: {}
  119. }
  120. },
  121. async fetch() {
  122. this.images = await this.$services.example.fetchOne(
  123. this.projectId,
  124. this.$route.query.page,
  125. this.$route.query.q,
  126. this.$route.query.isChecked
  127. )
  128. const image = this.images.items[0]
  129. this.setImageSize(image)
  130. if (this.enableAutoLabeling) {
  131. await this.autoLabel(image.id)
  132. }
  133. await this.list(image.id)
  134. },
  135. computed: {
  136. projectId() {
  137. return this.$route.params.id
  138. },
  139. image() {
  140. if (_.isEmpty(this.images) || this.images.items.length === 0) {
  141. return {}
  142. } else {
  143. return this.images.items[0]
  144. }
  145. }
  146. },
  147. watch: {
  148. '$route.query': '$fetch',
  149. enableAutoLabeling(val) {
  150. if (val) {
  151. this.list(this.image.id)
  152. }
  153. }
  154. },
  155. async created() {
  156. this.getLabelList(this.projectId)
  157. this.project = await this.$services.project.findById(this.projectId)
  158. this.progress = await this.$services.metrics.fetchMyProgress(this.projectId)
  159. },
  160. methods: {
  161. async list(imageId) {
  162. this.annotations = await this.$services.textClassification.list(this.projectId, imageId)
  163. },
  164. async remove(id) {
  165. await this.$services.textClassification.delete(this.projectId, this.image.id, id)
  166. await this.list(this.image.id)
  167. },
  168. async add(labelId) {
  169. await this.$services.textClassification.create(this.projectId, this.image.id, labelId)
  170. await this.list(this.image.id)
  171. },
  172. async addOrRemove(event) {
  173. const labelId = parseInt(event.srcKey, 10)
  174. const annotation = this.annotations.find(item => item.label === labelId)
  175. if (annotation) {
  176. await this.remove(annotation.id)
  177. } else {
  178. await this.add(labelId)
  179. }
  180. },
  181. async clear() {
  182. await this.$services.textClassification.clear(this.projectId, this.image.id)
  183. await this.list(this.image.id)
  184. },
  185. async autoLabel(imageId) {
  186. try {
  187. await this.$services.textClassification.autoLabel(this.projectId, imageId)
  188. } catch (e) {
  189. console.log(e.response.data.detail)
  190. }
  191. },
  192. async updateProgress() {
  193. this.progress = await this.$services.metrics.fetchMyProgress(this.projectId)
  194. },
  195. async confirm() {
  196. await this.$services.example.confirm(this.projectId, this.image.id)
  197. await this.$fetch()
  198. this.updateProgress()
  199. },
  200. setImageSize(val) {
  201. const img = new Image()
  202. const self = this
  203. img.onload = function() {
  204. self.imageSize.height = this.height
  205. self.imageSize.width = this.width
  206. }
  207. img.src = val.url
  208. }
  209. }
  210. }
  211. </script>
  212. <style scoped>
  213. .text-pre-wrap {
  214. white-space: pre-wrap !important;
  215. }
  216. </style>