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.

231 lines
6.1 KiB

  1. <template>
  2. <layout-text v-if="doc.id">
  3. <template v-slot:header>
  4. <toolbar-laptop
  5. :doc-id="doc.id"
  6. :enable-auto-labeling.sync="enableAutoLabeling"
  7. :guideline-text="project.guideline"
  8. :is-reviewd="doc.isApproved"
  9. :show-approve-button="project.permitApprove"
  10. :total="docs.count"
  11. class="d-none d-sm-block"
  12. @click:clear-label="clear"
  13. @click:review="approve"
  14. />
  15. <toolbar-mobile
  16. :total="docs.count"
  17. class="d-flex d-sm-none"
  18. />
  19. </template>
  20. <template v-slot:content>
  21. <v-card>
  22. <v-card-text class="title">
  23. <entity-item-box
  24. :labels="labels"
  25. :link-types="linkTypes"
  26. :text="doc.text"
  27. :entities="annotations"
  28. :delete-annotation="remove"
  29. :update-entity="update"
  30. :add-entity="add"
  31. :source-chunk="sourceChunk"
  32. :source-link-type="sourceLinkType"
  33. :select-source="selectSource"
  34. :select-target="selectTarget"
  35. :delete-link="deleteLink"
  36. :select-new-link-type="selectNewLinkType"
  37. :hide-all-link-menus="hideAllLinkMenus"
  38. />
  39. </v-card-text>
  40. </v-card>
  41. </template>
  42. <template v-slot:sidebar>
  43. <list-metadata :metadata="doc.meta" />
  44. </template>
  45. </layout-text>
  46. </template>
  47. <script>
  48. import _ from 'lodash'
  49. import {mapGetters} from 'vuex'
  50. import LayoutText from '@/components/tasks/layout/LayoutText'
  51. import ListMetadata from '@/components/tasks/metadata/ListMetadata'
  52. import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
  53. import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
  54. import EntityItemBox from '~/components/tasks/sequenceLabeling/EntityItemBox'
  55. const NONE = {
  56. id: -1,
  57. none: true
  58. };
  59. export default {
  60. layout: 'workspace',
  61. components: {
  62. EntityItemBox,
  63. LayoutText,
  64. ListMetadata,
  65. ToolbarLaptop,
  66. ToolbarMobile
  67. },
  68. async fetch() {
  69. this.docs = await this.$services.example.fetchOne(
  70. this.projectId,
  71. this.$route.query.page,
  72. this.$route.query.q,
  73. this.$route.query.isChecked,
  74. this.project.filterOption
  75. )
  76. const doc = this.docs.items[0]
  77. if (this.enableAutoLabeling) {
  78. await this.autoLabel(doc.id)
  79. }
  80. await this.list(doc.id)
  81. },
  82. data() {
  83. return {
  84. annotations: [],
  85. docs: [],
  86. labels: [],
  87. links: [],
  88. linkTypes: [],
  89. project: {},
  90. enableAutoLabeling: false,
  91. sourceChunk: NONE,
  92. sourceLink: NONE,
  93. sourceLinkType: NONE
  94. }
  95. },
  96. computed: {
  97. ...mapGetters('auth', ['isAuthenticated', 'getUsername', 'getUserId']),
  98. shortKeys() {
  99. return Object.fromEntries(this.labels.map(item => [item.id, [item.suffixKey]]))
  100. },
  101. projectId() {
  102. return this.$route.params.id
  103. },
  104. doc() {
  105. if (_.isEmpty(this.docs) || this.docs.items.length === 0) {
  106. return {}
  107. } else {
  108. return this.docs.items[0]
  109. }
  110. }
  111. },
  112. watch: {
  113. '$route.query': '$fetch',
  114. enableAutoLabeling(val) {
  115. if (val) {
  116. this.list(this.doc.id)
  117. }
  118. }
  119. },
  120. async created() {
  121. this.labels = await this.$services.label.list(this.projectId)
  122. this.linkTypes = await this.$services.linkTypes.list(this.projectId)
  123. this.project = await this.$services.project.findById(this.projectId)
  124. },
  125. methods: {
  126. async list(docId) {
  127. this.hideAllLinkMenus();
  128. const annotations = await this.$services.sequenceLabeling.list(this.projectId, docId);
  129. const links = await this.$services.sequenceLabeling.listLinks(this.projectId);
  130. annotations.forEach(function(annotation) {
  131. annotation.links = links.filter(link => link.annotation_id_1 === annotation.id);
  132. });
  133. this.annotations = annotations;
  134. this.links = links;
  135. },
  136. populateLinks() {
  137. const links = this.links;
  138. this.annotations.forEach(function(annotation) {
  139. annotation.links = links.filter(link => link.annotation_id_1 === annotation.id);
  140. });
  141. },
  142. async remove(id) {
  143. this.hideAllLinkMenus();
  144. await this.$services.sequenceLabeling.delete(this.projectId, this.doc.id, id)
  145. await this.list(this.doc.id)
  146. },
  147. async add(startOffset, endOffset, labelId) {
  148. this.hideAllLinkMenus();
  149. await this.$services.sequenceLabeling.create(this.projectId, this.doc.id, labelId, startOffset, endOffset)
  150. await this.list(this.doc.id)
  151. },
  152. async update(labelId, annotationId) {
  153. this.hideAllLinkMenus();
  154. await this.$services.sequenceLabeling.changeLabel(this.projectId, this.doc.id, annotationId, labelId)
  155. await this.list(this.doc.id)
  156. },
  157. async clear() {
  158. await this.$services.sequenceLabeling.clear(this.projectId, this.doc.id)
  159. await this.list(this.doc.id)
  160. },
  161. async autoLabel(docId) {
  162. try {
  163. await this.$services.sequenceLabeling.autoLabel(this.projectId, docId)
  164. } catch (e) {
  165. console.log(e.response.data.detail)
  166. }
  167. },
  168. async approve() {
  169. const approved = !this.doc.isApproved
  170. await this.$services.example.approve(this.projectId, this.doc.id, approved)
  171. await this.$fetch()
  172. },
  173. selectSource(chunk) {
  174. this.sourceChunk = chunk;
  175. },
  176. async selectTarget(chunk) {
  177. // to avoid duplicated links:
  178. if (!chunk.links.find(ch => ch.id === this.sourceChunk.id)) {
  179. await this.$services.sequenceLabeling.createLink(this.projectId, this.sourceChunk.id, chunk.id, this.sourceLinkType.id, this.getUserId);
  180. await this.list(this.doc.id);
  181. }
  182. this.hideAllLinkMenus();
  183. },
  184. async deleteLink(id, ndx) {
  185. await this.$services.sequenceLabeling.deleteLink(this.projectId, this.sourceChunk.links[ndx].id)
  186. await this.list(this.doc.id)
  187. this.hideAllLinkMenus();
  188. },
  189. selectNewLinkType(type) {
  190. this.sourceLinkType = type;
  191. },
  192. hideAllLinkMenus() {
  193. this.sourceChunk = NONE;
  194. this.sourceLinkType = NONE;
  195. }
  196. },
  197. validate({ params, query }) {
  198. return /^\d+$/.test(params.id) && /^\d+$/.test(query.page)
  199. }
  200. }
  201. </script>