smart-tools.history.test.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. Feature("Smart tools history");
  2. function paramsToAttrs(params) {
  3. return (
  4. params &&
  5. Object.entries(params)
  6. .map(([name, value]) => {
  7. return `${name}="${value}"`;
  8. })
  9. .join(" ")
  10. );
  11. }
  12. function createRectangleConfig(params = {}) {
  13. return `
  14. <View>
  15. <Image name="img" value="$image"/>
  16. <Rectangle name="rectangle" toName="img" ${paramsToAttrs(params)} />
  17. <Labels name="tag" toName="img">
  18. <Label value="Header" background="red"/>
  19. <Label value="Pargagraph" background="orange"/>
  20. <Label value="List Item" background="blue"/>
  21. </Labels>
  22. <TextArea name="ocr" toName="img" perRegion="true" editable="true" displayMode="region-list"/>
  23. </View>`;
  24. }
  25. const IMAGE = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Html_headers.png/640px-Html_headers.png";
  26. function getRectangleSuggestions(reg, group) {
  27. const allSuggestions = [
  28. {
  29. original_width: 640,
  30. original_height: 507,
  31. image_rotation: 0,
  32. value: {
  33. x: 0.9562500000000016,
  34. y: 0.7415920969816383,
  35. width: 35.05624999999999,
  36. height: 6.711376902658406,
  37. rotation: 0,
  38. },
  39. id: "Dx_aB91ISN",
  40. from_name: "label1",
  41. to_name: "img",
  42. type: "labels",
  43. origin: "prediction",
  44. },
  45. {
  46. original_width: 640,
  47. original_height: 507,
  48. image_rotation: 0,
  49. value: {
  50. x: 0.9562500000000016,
  51. y: 0.7415920969816383,
  52. width: 35.05624999999999,
  53. height: 6.711376902658406,
  54. rotation: 0,
  55. text: ['The "H1" Header'],
  56. },
  57. id: "Dx_aB91ISN",
  58. from_name: "ocr",
  59. to_name: "img",
  60. type: "textarea",
  61. origin: "prediction",
  62. },
  63. {
  64. original_width: 640,
  65. original_height: 507,
  66. image_rotation: 0,
  67. value: { x: 0.78125, y: 10.650887573964498, width: 98.28125, height: 10.453648915187378, rotation: 0 },
  68. id: "61LzdjSgA7",
  69. from_name: "rectangle",
  70. to_name: "img",
  71. type: "rectangle",
  72. origin: "prediction",
  73. },
  74. {
  75. original_width: 640,
  76. original_height: 507,
  77. image_rotation: 0,
  78. value: { x: 0.78125, y: 10.650887573964498, width: 98.28125, height: 10.453648915187378, rotation: 0 },
  79. id: "61LzdjSgA7",
  80. from_name: "label1",
  81. to_name: "img",
  82. type: "labels",
  83. origin: "prediction",
  84. },
  85. {
  86. original_width: 640,
  87. original_height: 507,
  88. image_rotation: 0,
  89. value: {
  90. x: 0.78125,
  91. y: 10.650887573964498,
  92. width: 98.28125,
  93. height: 10.453648915187378,
  94. rotation: 0,
  95. text: [
  96. 'This is a paragraph contained within the "p" tag. This content repeats itself for demonstration purposes. This content repeats itsel for demonstration purposes. This content repeats itself for demonstration purposes. This content repeats itself for demonstration purposes.',
  97. ],
  98. },
  99. id: "61LzdjSgA7",
  100. from_name: "ocr",
  101. to_name: "img",
  102. type: "textarea",
  103. origin: "prediction",
  104. },
  105. {
  106. original_width: 640,
  107. original_height: 507,
  108. image_rotation: 0,
  109. value: {
  110. x: 0.78125,
  111. y: 24.06311637080868,
  112. width: 25.937500000000007,
  113. height: 5.128205128205128,
  114. rotation: 0,
  115. },
  116. id: "PqkSyiIR2U",
  117. from_name: "rectangle",
  118. to_name: "img",
  119. type: "rectangle",
  120. origin: "prediction",
  121. },
  122. {
  123. original_width: 640,
  124. original_height: 507,
  125. image_rotation: 0,
  126. value: {
  127. x: 0.78125,
  128. y: 24.06311637080868,
  129. width: 25.937500000000007,
  130. height: 5.128205128205128,
  131. rotation: 0,
  132. },
  133. id: "PqkSyiIR2U",
  134. from_name: "label1",
  135. to_name: "img",
  136. type: "labels",
  137. origin: "prediction",
  138. },
  139. {
  140. original_width: 640,
  141. original_height: 507,
  142. image_rotation: 0,
  143. value: {
  144. x: 0.78125,
  145. y: 24.06311637080868,
  146. width: 25.937500000000007,
  147. height: 5.128205128205128,
  148. rotation: 0,
  149. text: ['The "H2" Header'],
  150. },
  151. id: "PqkSyiIR2U",
  152. from_name: "ocr",
  153. to_name: "img",
  154. type: "textarea",
  155. origin: "prediction",
  156. },
  157. {
  158. original_width: 640,
  159. original_height: 507,
  160. image_rotation: 0,
  161. value: { x: 0.78125, y: 31.163708086785004, width: 60.9375, height: 4.930966469428008, rotation: 0 },
  162. id: "2Goh8lkpid",
  163. from_name: "rectangle",
  164. to_name: "img",
  165. type: "rectangle",
  166. origin: "prediction",
  167. },
  168. {
  169. original_width: 640,
  170. original_height: 507,
  171. image_rotation: 0,
  172. value: {
  173. x: 0.78125,
  174. y: 31.163708086785004,
  175. width: 60.9375,
  176. height: 4.930966469428008,
  177. rotation: 0,
  178. text: ['This paragraph, also contained within "p"tag, contains an unordered list:'],
  179. },
  180. id: "2Goh8lkpid",
  181. from_name: "ocr",
  182. to_name: "img",
  183. type: "textarea",
  184. origin: "prediction",
  185. },
  186. {
  187. original_width: 640,
  188. original_height: 507,
  189. image_rotation: 0,
  190. value: {
  191. x: 3.750000000000001,
  192. y: 38.85601577909269,
  193. width: 32.96874999999999,
  194. height: 2.5641025641025608,
  195. rotation: 0,
  196. },
  197. id: "otJ6aU8x9B",
  198. from_name: "rectangle",
  199. to_name: "img",
  200. type: "rectangle",
  201. origin: "prediction-changed",
  202. },
  203. {
  204. original_width: 640,
  205. original_height: 507,
  206. image_rotation: 0,
  207. value: {
  208. x: 3.750000000000001,
  209. y: 38.85601577909269,
  210. width: 32.96874999999999,
  211. height: 2.5641025641025608,
  212. rotation: 0,
  213. text: ["This is a list item in an unordered list"],
  214. },
  215. id: "otJ6aU8x9B",
  216. from_name: "ocr",
  217. to_name: "img",
  218. type: "textarea",
  219. origin: "prediction-changed",
  220. },
  221. {
  222. original_width: 640,
  223. original_height: 507,
  224. image_rotation: 0,
  225. value: {
  226. x: 3.7499999999999987,
  227. y: 42.01183431952662,
  228. width: 37.18749999999998,
  229. height: 2.761341222879683,
  230. rotation: 0,
  231. },
  232. id: "TnWXaMtEP0",
  233. from_name: "rectangle",
  234. to_name: "img",
  235. type: "rectangle",
  236. origin: "prediction-changed",
  237. },
  238. {
  239. original_width: 640,
  240. original_height: 507,
  241. image_rotation: 0,
  242. value: {
  243. x: 3.7499999999999987,
  244. y: 42.01183431952662,
  245. width: 37.18749999999998,
  246. height: 2.761341222879683,
  247. rotation: 0,
  248. text: ["This is another list item in an unordered list"],
  249. },
  250. id: "TnWXaMtEP0",
  251. from_name: "ocr",
  252. to_name: "img",
  253. type: "textarea",
  254. origin: "prediction-changed",
  255. },
  256. {
  257. original_width: 640,
  258. original_height: 507,
  259. image_rotation: 0,
  260. value: {
  261. x: 3.7500000000000058,
  262. y: 45.364891518737686,
  263. width: 39.843749999999986,
  264. height: 3.155818540433913,
  265. rotation: 0,
  266. },
  267. id: "8DhVECLljf",
  268. from_name: "rectangle",
  269. to_name: "img",
  270. type: "rectangle",
  271. origin: "manual",
  272. },
  273. {
  274. original_width: 640,
  275. original_height: 507,
  276. image_rotation: 0,
  277. value: {
  278. x: 3.7500000000000058,
  279. y: 45.364891518737686,
  280. width: 39.843749999999986,
  281. height: 3.155818540433913,
  282. rotation: 0,
  283. text: ["This is yet another list item in an unordered list"],
  284. },
  285. id: "8DhVECLljf",
  286. from_name: "ocr",
  287. to_name: "img",
  288. type: "textarea",
  289. origin: "manual",
  290. },
  291. {
  292. original_width: 640,
  293. original_height: 507,
  294. image_rotation: 0,
  295. value: {
  296. x: 0.78125,
  297. y: 51.67652859960554,
  298. width: 21.093749999999993,
  299. height: 3.747534516765286,
  300. rotation: 0,
  301. },
  302. id: "Dr2-ppHmQU",
  303. from_name: "rectangle",
  304. to_name: "img",
  305. type: "rectangle",
  306. origin: "manual",
  307. },
  308. {
  309. original_width: 640,
  310. original_height: 507,
  311. image_rotation: 0,
  312. value: {
  313. x: 0.78125,
  314. y: 51.67652859960554,
  315. width: 21.093749999999993,
  316. height: 3.747534516765286,
  317. rotation: 0,
  318. text: ['The "H3" Header'],
  319. },
  320. id: "Dr2-ppHmQU",
  321. from_name: "ocr",
  322. to_name: "img",
  323. type: "textarea",
  324. origin: "manual",
  325. },
  326. {
  327. original_width: 640,
  328. original_height: 507,
  329. image_rotation: 0,
  330. value: {
  331. x: 0.7812499999999998,
  332. y: 58.777120315581854,
  333. width: 99.06249999999997,
  334. height: 9.664694280078905,
  335. rotation: 0,
  336. },
  337. id: "3QeY6ZaJfC",
  338. from_name: "rectangle",
  339. to_name: "img",
  340. type: "rectangle",
  341. origin: "manual",
  342. },
  343. {
  344. original_width: 640,
  345. original_height: 507,
  346. image_rotation: 0,
  347. value: {
  348. x: 0.7812499999999998,
  349. y: 58.777120315581854,
  350. width: 99.06249999999997,
  351. height: 9.664694280078905,
  352. rotation: 0,
  353. text: [
  354. 'Another paragraph contained whithin the "p" tag. This content repeats itself for demonstration purposes. This content repeats itself for demonstration purposes.This content repeats itself for demonstration purposes.This content repeats itself for demonstration purposes.',
  355. ],
  356. },
  357. id: "3QeY6ZaJfC",
  358. from_name: "ocr",
  359. to_name: "img",
  360. type: "textarea",
  361. origin: "manual",
  362. },
  363. {
  364. original_width: 640,
  365. original_height: 507,
  366. image_rotation: 0,
  367. value: { x: 0.625, y: 71.59763313609467, width: 17.65625, height: 4.142011834319527, rotation: 0 },
  368. id: "b_an6nG-s1",
  369. from_name: "rectangle",
  370. to_name: "img",
  371. type: "rectangle",
  372. origin: "manual",
  373. },
  374. {
  375. original_width: 640,
  376. original_height: 507,
  377. image_rotation: 0,
  378. value: {
  379. x: 0.625,
  380. y: 71.59763313609467,
  381. width: 17.65625,
  382. height: 4.142011834319527,
  383. rotation: 0,
  384. text: ['The "H4" Header'],
  385. },
  386. id: "b_an6nG-s1",
  387. from_name: "ocr",
  388. to_name: "img",
  389. type: "textarea",
  390. origin: "manual",
  391. },
  392. {
  393. original_width: 640,
  394. original_height: 507,
  395. image_rotation: 0,
  396. value: { x: 0.625, y: 78.30374753451676, width: 64.375, height: 4.536489151873767, rotation: 0 },
  397. id: "H58PCLk6in",
  398. from_name: "rectangle",
  399. to_name: "img",
  400. type: "rectangle",
  401. origin: "manual",
  402. },
  403. {
  404. original_width: 640,
  405. original_height: 507,
  406. image_rotation: 0,
  407. value: {
  408. x: 0.625,
  409. y: 78.30374753451676,
  410. width: 64.375,
  411. height: 4.536489151873767,
  412. rotation: 0,
  413. text: ['Another paragraf contained within the "p" tag. This one\'s shorter than the rest.'],
  414. },
  415. id: "H58PCLk6in",
  416. from_name: "ocr",
  417. to_name: "img",
  418. type: "textarea",
  419. origin: "manual",
  420. },
  421. {
  422. original_width: 640,
  423. original_height: 507,
  424. image_rotation: 0,
  425. value: {
  426. x: 0.9375,
  427. y: 85.00986193293886,
  428. width: 14.531250000000004,
  429. height: 4.142011834319527,
  430. rotation: 0,
  431. },
  432. id: "LW3Hd45XGa",
  433. from_name: "rectangle",
  434. to_name: "img",
  435. type: "rectangle",
  436. origin: "manual",
  437. },
  438. {
  439. original_width: 640,
  440. original_height: 507,
  441. image_rotation: 0,
  442. value: {
  443. x: 0.9375,
  444. y: 85.00986193293886,
  445. width: 14.531250000000004,
  446. height: 4.142011834319527,
  447. rotation: 0,
  448. text: ['The "H5" header'],
  449. },
  450. id: "LW3Hd45XGa",
  451. from_name: "ocr",
  452. to_name: "img",
  453. type: "textarea",
  454. origin: "manual",
  455. },
  456. {
  457. original_width: 640,
  458. original_height: 507,
  459. image_rotation: 0,
  460. value: { x: 0.9375, y: 91.91321499013807, width: 40.46875, height: 4.339250493096647, rotation: 0 },
  461. id: "ZxltsrsvQl",
  462. from_name: "rectangle",
  463. to_name: "img",
  464. type: "rectangle",
  465. origin: "manual",
  466. },
  467. {
  468. original_width: 640,
  469. original_height: 507,
  470. image_rotation: 0,
  471. value: {
  472. x: 0.9375,
  473. y: 91.91321499013807,
  474. width: 40.46875,
  475. height: 4.339250493096647,
  476. rotation: 0,
  477. text: ["A final paragraph. There's not much content here."],
  478. },
  479. id: "ZxltsrsvQl",
  480. from_name: "ocr",
  481. to_name: "img",
  482. type: "textarea",
  483. origin: "manual",
  484. },
  485. ];
  486. const annotation = window.labelStudio.store.annotationStore.selected;
  487. const ids = group.map((r) => r.cleanId);
  488. const results = annotation.serializeAnnotation().filter((res) => ids.includes(res.id));
  489. const suggestions = allSuggestions.filter((predictionResult) => {
  490. const targetCenterX = predictionResult.value.x + predictionResult.value.width / 2;
  491. const targetCenterY = predictionResult.value.y + predictionResult.value.height / 2;
  492. const targetWidth = predictionResult.value.width;
  493. const targetHeight = predictionResult.value.height;
  494. return results.some((result) => {
  495. const resultCenterX = result.value.x + result.value.width / 2;
  496. const resultCenterY = result.value.y + result.value.height / 2;
  497. const resultWidth = result.value.width;
  498. const resultHeight = result.value.height;
  499. return (
  500. Math.abs(resultCenterX - targetCenterX) * 2 < resultWidth + targetWidth &&
  501. Math.abs(resultCenterY - targetCenterY) * 2 < resultHeight + targetHeight
  502. );
  503. });
  504. });
  505. window.labelStudio.store.loadSuggestions(new Promise((resolve) => resolve(suggestions)), (x) => x);
  506. }
  507. Scenario("Undo regions auto-annotated from predictions", async ({ I, LabelStudio, AtImageView, AtOutliner }) => {
  508. I.amOnPage("/");
  509. LabelStudio.init({
  510. config: createRectangleConfig({
  511. smartonly: true,
  512. }),
  513. data: {
  514. image: IMAGE,
  515. },
  516. additionalInterfaces: ["auto-annotation"],
  517. events: {
  518. regionFinishedDrawing: getRectangleSuggestions,
  519. },
  520. params: {
  521. forceAutoAnnotation: true,
  522. forceAutoAcceptSuggestions: true,
  523. },
  524. });
  525. LabelStudio.setFeatureFlags({
  526. fflag_fix_front_dev_1284_auto_detect_undo_281022_short: true,
  527. });
  528. LabelStudio.waitForObjectsReady();
  529. AtOutliner.seeRegions(0);
  530. await AtImageView.lookForStage();
  531. I.say("Select magic tool");
  532. I.pressKey("M");
  533. I.seeElement('[disabled][aria-label="Undo"]');
  534. I.say("Draw region over 5 potential suggestion area");
  535. AtImageView.drawByDrag(19, 192, 140, 150);
  536. I.say("Get that suggestions as result instead of drawn region");
  537. AtOutliner.seeRegions(5);
  538. I.seeElement(':not([disabled])[aria-label="Undo"]');
  539. I.seeElement('[disabled][aria-label="Redo"]');
  540. I.say("Go back through history");
  541. I.pressKey(["CommandOrControl", "z"]);
  542. I.say("Should see nothing");
  543. AtOutliner.seeRegions(0);
  544. I.seeElement('[disabled][aria-label="Undo"]');
  545. I.seeElement(':not([disabled])[aria-label="Redo"]');
  546. I.say("Go forward through history");
  547. I.pressKey(["CommandOrControl", "shift", "z"]);
  548. I.say("Regions must be restored");
  549. AtOutliner.seeRegions(5);
  550. I.seeElement(':not([disabled])[aria-label="Undo"]');
  551. I.seeElement('[disabled][aria-label="Redo"]');
  552. });
  553. Scenario(
  554. "Undo if there are no regions auto-annotated from predictions",
  555. async ({ I, LabelStudio, AtImageView, AtOutliner, AtPanels }) => {
  556. const AtDetailsPanel = AtPanels.usePanel(AtPanels.PANEL.DETAILS);
  557. I.amOnPage("/");
  558. LabelStudio.init({
  559. config: createRectangleConfig({
  560. smartonly: true,
  561. }),
  562. data: {
  563. image: IMAGE,
  564. },
  565. additionalInterfaces: ["auto-annotation"],
  566. events: {
  567. regionFinishedDrawing: getRectangleSuggestions,
  568. },
  569. params: {
  570. forceAutoAnnotation: true,
  571. forceAutoAcceptSuggestions: true,
  572. },
  573. });
  574. LabelStudio.setFeatureFlags({
  575. fflag_fix_front_dev_1284_auto_detect_undo_281022_short: true,
  576. });
  577. AtDetailsPanel.collapsePanel();
  578. LabelStudio.waitForObjectsReady();
  579. AtOutliner.seeRegions(0);
  580. await AtImageView.lookForStage();
  581. I.say("Select magic tool");
  582. I.pressKey("M");
  583. I.seeElement('[disabled][aria-label="Undo"]');
  584. I.say("Draw region over area without potential suggestions");
  585. AtImageView.drawByDrag(600, 200, 7, 7);
  586. I.say("Get an empty list of regions as the result instead of drawn region");
  587. AtOutliner.seeRegions(0);
  588. I.seeElement(':not([disabled])[aria-label="Undo"]');
  589. I.seeElement('[disabled][aria-label="Redo"]');
  590. I.say("Go back through history");
  591. I.pressKey(["CommandOrControl", "z"]);
  592. I.say("Should see nothing");
  593. AtOutliner.seeRegions(0);
  594. I.seeElement('[disabled][aria-label="Undo"]');
  595. I.seeElement(':not([disabled])[aria-label="Redo"]');
  596. I.say("Go forward through history");
  597. I.pressKey(["CommandOrControl", "shift", "z"]);
  598. I.say("And see nothing again");
  599. AtOutliner.seeRegions(0);
  600. I.seeElement(':not([disabled])[aria-label="Undo"]');
  601. I.seeElement('[disabled][aria-label="Redo"]');
  602. I.say("Go back through history");
  603. I.pressKey(["CommandOrControl", "z"]);
  604. I.say("Should see nothing");
  605. AtOutliner.seeRegions(0);
  606. I.seeElement('[disabled][aria-label="Undo"]');
  607. I.seeElement(':not([disabled])[aria-label="Redo"]');
  608. I.say("Draw region over area without potential suggestions");
  609. AtImageView.drawByDrag(600, 200, 7, 7);
  610. I.say("Get an empty list of regions as the result instead of drawn region");
  611. AtOutliner.seeRegions(0);
  612. I.say("There should be one history step");
  613. I.seeElement(':not([disabled])[aria-label="Undo"]');
  614. I.seeElement('[disabled][aria-label="Redo"]');
  615. },
  616. );