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.

227 lines
5.5 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, useContext } 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 { app } = useContext()
  95. const { state, getLabelList, shortKeys } = useLabelList(app.$services.categoryType)
  96. return {
  97. ...toRefs(state),
  98. getLabelList,
  99. shortKeys,
  100. }
  101. },
  102. data() {
  103. return {
  104. annotations: [],
  105. images: [],
  106. project: {},
  107. enableAutoLabeling: false,
  108. labelOption: 0,
  109. imageSize: {
  110. height: 0,
  111. width: 0
  112. },
  113. mdiText,
  114. mdiFormatListBulleted
  115. }
  116. },
  117. async fetch() {
  118. this.images = await this.$services.example.fetchOne(
  119. this.projectId,
  120. this.$route.query.page,
  121. this.$route.query.q,
  122. this.$route.query.isChecked
  123. )
  124. const image = this.images.items[0]
  125. this.setImageSize(image)
  126. if (this.enableAutoLabeling) {
  127. await this.autoLabel(image.id)
  128. }
  129. await this.list(image.id)
  130. },
  131. computed: {
  132. projectId() {
  133. return this.$route.params.id
  134. },
  135. image() {
  136. if (_.isEmpty(this.images) || this.images.items.length === 0) {
  137. return {}
  138. } else {
  139. return this.images.items[0]
  140. }
  141. }
  142. },
  143. watch: {
  144. '$route.query': '$fetch',
  145. enableAutoLabeling(val) {
  146. if (val) {
  147. this.list(this.image.id)
  148. }
  149. }
  150. },
  151. async created() {
  152. this.getLabelList(this.projectId)
  153. this.project = await this.$services.project.findById(this.projectId)
  154. },
  155. methods: {
  156. async list(imageId) {
  157. this.annotations = await this.$services.textClassification.list(this.projectId, imageId)
  158. },
  159. async remove(id) {
  160. await this.$services.textClassification.delete(this.projectId, this.image.id, id)
  161. await this.list(this.image.id)
  162. },
  163. async add(labelId) {
  164. await this.$services.textClassification.create(this.projectId, this.image.id, labelId)
  165. await this.list(this.image.id)
  166. },
  167. async addOrRemove(event) {
  168. const labelId = parseInt(event.srcKey, 10)
  169. const annotation = this.annotations.find(item => item.label === labelId)
  170. if (annotation) {
  171. await this.remove(annotation.id)
  172. } else {
  173. await this.add(labelId)
  174. }
  175. },
  176. async clear() {
  177. await this.$services.textClassification.clear(this.projectId, this.image.id)
  178. await this.list(this.image.id)
  179. },
  180. async autoLabel(imageId) {
  181. try {
  182. await this.$services.textClassification.autoLabel(this.projectId, imageId)
  183. } catch (e) {
  184. console.log(e.response.data.detail)
  185. }
  186. },
  187. async confirm() {
  188. await this.$services.example.confirm(this.projectId, this.image.id)
  189. await this.$fetch()
  190. },
  191. setImageSize(val) {
  192. const img = new Image()
  193. const self = this
  194. img.onload = function() {
  195. self.imageSize.height = this.height
  196. self.imageSize.width = this.width
  197. }
  198. img.src = val.url
  199. }
  200. }
  201. }
  202. </script>
  203. <style scoped>
  204. .text-pre-wrap {
  205. white-space: pre-wrap !important;
  206. }
  207. </style>