jbilcke-hf HF staff commited on
Commit
5dd2af5
1 Parent(s): 58e2526

let's use two pages

Browse files
.env CHANGED
@@ -11,6 +11,8 @@ RENDERING_ENGINE="INFERENCE_API"
11
  # - OPENAI
12
  LLM_ENGINE="INFERENCE_API"
13
 
 
 
14
  # Not implemented for the Inference API yet - you can submit a PR if you have some ideas
15
  NEXT_PUBLIC_CAN_UPSCALE="false"
16
 
 
11
  # - OPENAI
12
  LLM_ENGINE="INFERENCE_API"
13
 
14
+ NEXT_PUBLIC_MAX_NB_PAGES="2"
15
+
16
  # Not implemented for the Inference API yet - you can submit a PR if you have some ideas
17
  NEXT_PUBLIC_CAN_UPSCALE="false"
18
 
package-lock.json CHANGED
@@ -60,7 +60,6 @@
60
  "tailwind-merge": "^1.13.2",
61
  "tailwindcss": "3.3.3",
62
  "tailwindcss-animate": "^1.0.6",
63
- "tesseract.js": "^4.1.2",
64
  "ts-node": "^10.9.1",
65
  "typescript": "5.1.6",
66
  "usehooks-ts": "^2.9.1",
@@ -156,9 +155,9 @@
156
  }
157
  },
158
  "node_modules/@eslint-community/regexpp": {
159
- "version": "4.9.1",
160
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz",
161
- "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==",
162
  "engines": {
163
  "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
164
  }
@@ -236,11 +235,11 @@
236
  }
237
  },
238
  "node_modules/@humanwhocodes/config-array": {
239
- "version": "0.11.11",
240
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
241
- "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
242
  "dependencies": {
243
- "@humanwhocodes/object-schema": "^1.2.1",
244
  "debug": "^4.1.1",
245
  "minimatch": "^3.0.5"
246
  },
@@ -261,9 +260,9 @@
261
  }
262
  },
263
  "node_modules/@humanwhocodes/object-schema": {
264
- "version": "1.2.1",
265
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
266
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
267
  },
268
  "node_modules/@jridgewell/gen-mapping": {
269
  "version": "0.3.3",
@@ -300,9 +299,9 @@
300
  "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
301
  },
302
  "node_modules/@jridgewell/trace-mapping": {
303
- "version": "0.3.19",
304
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
305
- "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
306
  "dependencies": {
307
  "@jridgewell/resolve-uri": "^3.1.0",
308
  "@jridgewell/sourcemap-codec": "^1.4.14"
@@ -1630,21 +1629,21 @@
1630
  }
1631
  },
1632
  "node_modules/@react-pdf/font": {
1633
- "version": "2.3.6",
1634
- "resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-2.3.6.tgz",
1635
- "integrity": "sha512-JYV+KmVyG2tPdpCK0/iFiBy1V7VHz2fETttKCgTRsLAo+w8RpM0pUGSAYROSuRl7yqbhiKGw/A24PYWhBReiOQ==",
1636
  "dependencies": {
1637
  "@babel/runtime": "^7.20.13",
1638
- "@react-pdf/types": "^2.3.3",
1639
  "cross-fetch": "^3.1.5",
1640
  "fontkit": "^2.0.2",
1641
  "is-url": "^1.2.4"
1642
  }
1643
  },
1644
  "node_modules/@react-pdf/image": {
1645
- "version": "2.2.1",
1646
- "resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-2.2.1.tgz",
1647
- "integrity": "sha512-f0+cEP6pSBmk8eS/wP2tMsJcv2c7xjzca6cr1kwcapr1nzkPrh6fMdEeFl6kR2/HlJK/JoHo+xxlzRiQ8V2lrw==",
1648
  "dependencies": {
1649
  "@babel/runtime": "^7.20.13",
1650
  "@react-pdf/png-js": "^2.2.0",
@@ -1652,18 +1651,18 @@
1652
  }
1653
  },
1654
  "node_modules/@react-pdf/layout": {
1655
- "version": "3.6.2",
1656
- "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-3.6.2.tgz",
1657
- "integrity": "sha512-YD3/tDC6p5XPCXI04zH79bgX8LytjxEYfeCtsIzEFk0A2VvIHoRnRRDZ2OhZmO5g112ykyjY8vn9//ubTt+Ktg==",
1658
  "dependencies": {
1659
  "@babel/runtime": "^7.20.13",
1660
  "@react-pdf/fns": "2.0.1",
1661
- "@react-pdf/image": "^2.2.1",
1662
  "@react-pdf/pdfkit": "^3.0.2",
1663
  "@react-pdf/primitives": "^3.0.0",
1664
- "@react-pdf/stylesheet": "^4.1.7",
1665
  "@react-pdf/textkit": "^4.2.0",
1666
- "@react-pdf/types": "^2.3.3",
1667
  "@react-pdf/yoga": "^4.1.2",
1668
  "cross-fetch": "^3.1.5",
1669
  "emoji-regex": "^10.2.1",
@@ -1697,15 +1696,15 @@
1697
  "integrity": "sha512-0HGcknrLNwyhxe+SZCBL29JY4M85mXKdvTZE9uhjNbADGgTc8wVnkc5+e4S/lDvugbVISXyuIhZnYwtK9eDnyQ=="
1698
  },
1699
  "node_modules/@react-pdf/render": {
1700
- "version": "3.2.6",
1701
- "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-3.2.6.tgz",
1702
- "integrity": "sha512-nsd1sleWMzBdrYGv5BwChPgVwoTZilfdiadE5wQiblFqG1C7EYINadalnEl1tjldKAzofSPBLKJbnSGR5r2lIQ==",
1703
  "dependencies": {
1704
  "@babel/runtime": "^7.20.13",
1705
  "@react-pdf/fns": "2.0.1",
1706
  "@react-pdf/primitives": "^3.0.0",
1707
  "@react-pdf/textkit": "^4.2.0",
1708
- "@react-pdf/types": "^2.3.3",
1709
  "abs-svg-path": "^0.1.1",
1710
  "color-string": "^1.5.3",
1711
  "normalize-svg-path": "^1.1.0",
@@ -1714,17 +1713,17 @@
1714
  }
1715
  },
1716
  "node_modules/@react-pdf/renderer": {
1717
- "version": "3.1.13",
1718
- "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-3.1.13.tgz",
1719
- "integrity": "sha512-vsQauiy63A2ORWmoYwG3qoBbs3IKlSEM6XxipesZUEohn9WH9LXiU+VN8k+W75KRwRNJnqGOVhSxAiBVUxc61Q==",
1720
  "dependencies": {
1721
  "@babel/runtime": "^7.20.13",
1722
- "@react-pdf/font": "^2.3.6",
1723
- "@react-pdf/layout": "^3.6.2",
1724
  "@react-pdf/pdfkit": "^3.0.2",
1725
  "@react-pdf/primitives": "^3.0.0",
1726
- "@react-pdf/render": "^3.2.6",
1727
- "@react-pdf/types": "^2.3.3",
1728
  "events": "^3.3.0",
1729
  "object-assign": "^4.1.1",
1730
  "prop-types": "^15.6.2",
@@ -1736,13 +1735,13 @@
1736
  }
1737
  },
1738
  "node_modules/@react-pdf/stylesheet": {
1739
- "version": "4.1.7",
1740
- "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-4.1.7.tgz",
1741
- "integrity": "sha512-3n0Vg0XFszPyo0MpH75DkLRvsS4JOE0HzBH6XqFHDiquZDrC4mNgmMhZEbsOED+8xDGoCeVh8fLU3L6Tu0HWqg==",
1742
  "dependencies": {
1743
  "@babel/runtime": "^7.20.13",
1744
  "@react-pdf/fns": "2.0.1",
1745
- "@react-pdf/types": "^2.3.3",
1746
  "color-string": "^1.5.3",
1747
  "hsl-to-hex": "^1.0.0",
1748
  "media-engine": "^1.0.3",
@@ -1761,9 +1760,9 @@
1761
  }
1762
  },
1763
  "node_modules/@react-pdf/types": {
1764
- "version": "2.3.3",
1765
- "resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.3.3.tgz",
1766
- "integrity": "sha512-I3BVu5vF0xxX6rvqZHt4gCjFAt6X+mak5bwYQyf6bm21IIMDXXBtgXqWEl1wosWizArox7fcN/XbEnysrf/8Dw=="
1767
  },
1768
  "node_modules/@react-pdf/yoga": {
1769
  "version": "4.1.2",
@@ -1823,23 +1822,23 @@
1823
  "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw=="
1824
  },
1825
  "node_modules/@types/node-fetch": {
1826
- "version": "2.6.6",
1827
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.6.tgz",
1828
- "integrity": "sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==",
1829
  "dependencies": {
1830
  "@types/node": "*",
1831
  "form-data": "^4.0.0"
1832
  }
1833
  },
1834
  "node_modules/@types/prop-types": {
1835
- "version": "15.7.8",
1836
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz",
1837
- "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ=="
1838
  },
1839
  "node_modules/@types/qs": {
1840
- "version": "6.9.8",
1841
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
1842
- "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==",
1843
  "dev": true
1844
  },
1845
  "node_modules/@types/react": {
@@ -1861,17 +1860,17 @@
1861
  }
1862
  },
1863
  "node_modules/@types/react-reconciler": {
1864
- "version": "0.28.5",
1865
- "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.5.tgz",
1866
- "integrity": "sha512-Qrwgl4NxNYH1oAJSJtlMGu95uaeMqrGiKzxwI90VvofBkJAj4GxcCAsJMZkwdR/qAxlm84YEXa8Fqu2xXk0arw==",
1867
  "dependencies": {
1868
  "@types/react": "*"
1869
  }
1870
  },
1871
  "node_modules/@types/react-virtualized": {
1872
- "version": "9.21.23",
1873
- "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.23.tgz",
1874
- "integrity": "sha512-8GX+P+nUl+c1qlyb3z0lQExQfoHPscBliZiBEUQ90PzMHY76XvkMawmKMyhvAUlCemhlEnvZdvWsyQAK5E/Jeg==",
1875
  "dev": true,
1876
  "dependencies": {
1877
  "@types/prop-types": "*",
@@ -1879,25 +1878,25 @@
1879
  }
1880
  },
1881
  "node_modules/@types/sbd": {
1882
- "version": "1.0.3",
1883
- "resolved": "https://registry.npmjs.org/@types/sbd/-/sbd-1.0.3.tgz",
1884
- "integrity": "sha512-4rOX5JsLAEFrzOB0zvV2fG0lqwyNoo/TTYuQna/rjKi+ZHsN7s3BLfx70gsqGD6DM0j6Ha0QfneU/KspzMMeUg==",
1885
  "dev": true
1886
  },
1887
  "node_modules/@types/scheduler": {
1888
- "version": "0.16.4",
1889
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz",
1890
- "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ=="
1891
  },
1892
  "node_modules/@types/stylis": {
1893
- "version": "4.2.1",
1894
- "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.1.tgz",
1895
- "integrity": "sha512-OSaMrXUKxVigGlKRrET39V2xdhzlztQ9Aqumn1WbCBKHOi9ry7jKSd7rkyj0GzmWaU960Rd+LpOFpLfx5bMQAg=="
1896
  },
1897
  "node_modules/@types/uuid": {
1898
- "version": "9.0.5",
1899
- "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.5.tgz",
1900
- "integrity": "sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ=="
1901
  },
1902
  "node_modules/@typescript-eslint/parser": {
1903
  "version": "5.62.0",
@@ -2012,9 +2011,9 @@
2012
  "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA=="
2013
  },
2014
  "node_modules/acorn": {
2015
- "version": "8.10.0",
2016
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
2017
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
2018
  "bin": {
2019
  "acorn": "bin/acorn"
2020
  },
@@ -2031,9 +2030,9 @@
2031
  }
2032
  },
2033
  "node_modules/acorn-walk": {
2034
- "version": "8.2.0",
2035
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
2036
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
2037
  "engines": {
2038
  "node": ">=0.4.0"
2039
  }
@@ -2255,9 +2254,9 @@
2255
  }
2256
  },
2257
  "node_modules/ast-types-flow": {
2258
- "version": "0.0.7",
2259
- "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
2260
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
2261
  },
2262
  "node_modules/asynciterator.prototype": {
2263
  "version": "1.0.0",
@@ -2316,9 +2315,9 @@
2316
  }
2317
  },
2318
  "node_modules/axe-core": {
2319
- "version": "4.8.2",
2320
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.2.tgz",
2321
- "integrity": "sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==",
2322
  "engines": {
2323
  "node": ">=4"
2324
  }
@@ -2391,11 +2390,6 @@
2391
  "readable-stream": "^3.4.0"
2392
  }
2393
  },
2394
- "node_modules/bmp-js": {
2395
- "version": "0.1.0",
2396
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
2397
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
2398
- },
2399
  "node_modules/brace-expansion": {
2400
  "version": "1.1.11",
2401
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2498,12 +2492,13 @@
2498
  }
2499
  },
2500
  "node_modules/call-bind": {
2501
- "version": "1.0.2",
2502
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
2503
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
2504
  "dependencies": {
2505
- "function-bind": "^1.1.1",
2506
- "get-intrinsic": "^1.0.2"
 
2507
  },
2508
  "funding": {
2509
  "url": "https://github.com/sponsors/ljharb"
@@ -2534,9 +2529,9 @@
2534
  }
2535
  },
2536
  "node_modules/caniuse-lite": {
2537
- "version": "1.0.30001549",
2538
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
2539
- "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
2540
  "funding": [
2541
  {
2542
  "type": "opencollective",
@@ -2988,9 +2983,9 @@
2988
  }
2989
  },
2990
  "node_modules/cookies-next/node_modules/@types/node": {
2991
- "version": "16.18.58",
2992
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.58.tgz",
2993
- "integrity": "sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA=="
2994
  },
2995
  "node_modules/create-require": {
2996
  "version": "1.1.1",
@@ -3027,9 +3022,9 @@
3027
  }
3028
  },
3029
  "node_modules/crypto-js": {
3030
- "version": "4.1.1",
3031
- "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
3032
- "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
3033
  },
3034
  "node_modules/css-color-keywords": {
3035
  "version": "1.0.0",
@@ -3308,14 +3303,14 @@
3308
  }
3309
  },
3310
  "node_modules/electron-to-chromium": {
3311
- "version": "1.4.554",
3312
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz",
3313
- "integrity": "sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ=="
3314
  },
3315
  "node_modules/emoji-regex": {
3316
- "version": "10.2.1",
3317
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz",
3318
- "integrity": "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA=="
3319
  },
3320
  "node_modules/encoding": {
3321
  "version": "0.1.13",
@@ -3357,25 +3352,25 @@
3357
  }
3358
  },
3359
  "node_modules/es-abstract": {
3360
- "version": "1.22.2",
3361
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz",
3362
- "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==",
3363
  "dependencies": {
3364
  "array-buffer-byte-length": "^1.0.0",
3365
  "arraybuffer.prototype.slice": "^1.0.2",
3366
  "available-typed-arrays": "^1.0.5",
3367
- "call-bind": "^1.0.2",
3368
  "es-set-tostringtag": "^2.0.1",
3369
  "es-to-primitive": "^1.2.1",
3370
  "function.prototype.name": "^1.1.6",
3371
- "get-intrinsic": "^1.2.1",
3372
  "get-symbol-description": "^1.0.0",
3373
  "globalthis": "^1.0.3",
3374
  "gopd": "^1.0.1",
3375
- "has": "^1.0.3",
3376
  "has-property-descriptors": "^1.0.0",
3377
  "has-proto": "^1.0.1",
3378
  "has-symbols": "^1.0.3",
 
3379
  "internal-slot": "^1.0.5",
3380
  "is-array-buffer": "^3.0.2",
3381
  "is-callable": "^1.2.7",
@@ -3385,7 +3380,7 @@
3385
  "is-string": "^1.0.7",
3386
  "is-typed-array": "^1.1.12",
3387
  "is-weakref": "^1.0.2",
3388
- "object-inspect": "^1.12.3",
3389
  "object-keys": "^1.1.1",
3390
  "object.assign": "^4.1.4",
3391
  "regexp.prototype.flags": "^1.5.1",
@@ -3399,7 +3394,7 @@
3399
  "typed-array-byte-offset": "^1.0.0",
3400
  "typed-array-length": "^1.0.4",
3401
  "unbox-primitive": "^1.0.2",
3402
- "which-typed-array": "^1.1.11"
3403
  },
3404
  "engines": {
3405
  "node": ">= 0.4"
@@ -3430,24 +3425,24 @@
3430
  }
3431
  },
3432
  "node_modules/es-set-tostringtag": {
3433
- "version": "2.0.1",
3434
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
3435
- "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
3436
  "dependencies": {
3437
- "get-intrinsic": "^1.1.3",
3438
- "has": "^1.0.3",
3439
- "has-tostringtag": "^1.0.0"
3440
  },
3441
  "engines": {
3442
  "node": ">= 0.4"
3443
  }
3444
  },
3445
  "node_modules/es-shim-unscopables": {
3446
- "version": "1.0.0",
3447
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
3448
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
3449
  "dependencies": {
3450
- "has": "^1.0.3"
3451
  }
3452
  },
3453
  "node_modules/es-to-primitive": {
@@ -3630,25 +3625,25 @@
3630
  }
3631
  },
3632
  "node_modules/eslint-plugin-import": {
3633
- "version": "2.28.1",
3634
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
3635
- "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
3636
- "dependencies": {
3637
- "array-includes": "^3.1.6",
3638
- "array.prototype.findlastindex": "^1.2.2",
3639
- "array.prototype.flat": "^1.3.1",
3640
- "array.prototype.flatmap": "^1.3.1",
3641
  "debug": "^3.2.7",
3642
  "doctrine": "^2.1.0",
3643
- "eslint-import-resolver-node": "^0.3.7",
3644
  "eslint-module-utils": "^2.8.0",
3645
- "has": "^1.0.3",
3646
- "is-core-module": "^2.13.0",
3647
  "is-glob": "^4.0.3",
3648
  "minimatch": "^3.1.2",
3649
- "object.fromentries": "^2.0.6",
3650
- "object.groupby": "^1.0.0",
3651
- "object.values": "^1.1.6",
3652
  "semver": "^6.3.1",
3653
  "tsconfig-paths": "^3.14.2"
3654
  },
@@ -3687,26 +3682,26 @@
3687
  }
3688
  },
3689
  "node_modules/eslint-plugin-jsx-a11y": {
3690
- "version": "6.7.1",
3691
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz",
3692
- "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==",
3693
- "dependencies": {
3694
- "@babel/runtime": "^7.20.7",
3695
- "aria-query": "^5.1.3",
3696
- "array-includes": "^3.1.6",
3697
- "array.prototype.flatmap": "^1.3.1",
3698
- "ast-types-flow": "^0.0.7",
3699
- "axe-core": "^4.6.2",
3700
- "axobject-query": "^3.1.1",
3701
  "damerau-levenshtein": "^1.0.8",
3702
  "emoji-regex": "^9.2.2",
3703
- "has": "^1.0.3",
3704
- "jsx-ast-utils": "^3.3.3",
3705
- "language-tags": "=1.0.5",
 
3706
  "minimatch": "^3.1.2",
3707
- "object.entries": "^1.1.6",
3708
- "object.fromentries": "^2.0.6",
3709
- "semver": "^6.3.0"
3710
  },
3711
  "engines": {
3712
  "node": ">=4.0"
@@ -3720,14 +3715,6 @@
3720
  "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
3721
  "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
3722
  },
3723
- "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
3724
- "version": "6.3.1",
3725
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
3726
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
3727
- "bin": {
3728
- "semver": "bin/semver.js"
3729
- }
3730
- },
3731
  "node_modules/eslint-plugin-react": {
3732
  "version": "7.33.2",
3733
  "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz",
@@ -4070,6 +4057,14 @@
4070
  "node": ">= 12.20"
4071
  }
4072
  },
 
 
 
 
 
 
 
 
4073
  "node_modules/fraction.js": {
4074
  "version": "4.3.7",
4075
  "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@@ -4139,14 +4134,14 @@
4139
  }
4140
  },
4141
  "node_modules/get-intrinsic": {
4142
- "version": "1.2.1",
4143
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
4144
- "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
4145
  "dependencies": {
4146
- "function-bind": "^1.1.1",
4147
- "has": "^1.0.3",
4148
  "has-proto": "^1.0.1",
4149
- "has-symbols": "^1.0.3"
 
4150
  },
4151
  "funding": {
4152
  "url": "https://github.com/sponsors/ljharb"
@@ -4294,14 +4289,6 @@
4294
  "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
4295
  "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
4296
  },
4297
- "node_modules/has": {
4298
- "version": "1.0.4",
4299
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
4300
- "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
4301
- "engines": {
4302
- "node": ">= 0.4.0"
4303
- }
4304
- },
4305
  "node_modules/has-bigints": {
4306
  "version": "1.0.2",
4307
  "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -4319,11 +4306,11 @@
4319
  }
4320
  },
4321
  "node_modules/has-property-descriptors": {
4322
- "version": "1.0.0",
4323
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
4324
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
4325
  "dependencies": {
4326
- "get-intrinsic": "^1.1.1"
4327
  },
4328
  "funding": {
4329
  "url": "https://github.com/sponsors/ljharb"
@@ -4365,6 +4352,17 @@
4365
  "url": "https://github.com/sponsors/ljharb"
4366
  }
4367
  },
 
 
 
 
 
 
 
 
 
 
 
4368
  "node_modules/hsl-to-hex": {
4369
  "version": "1.0.0",
4370
  "resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz",
@@ -4417,9 +4415,9 @@
4417
  }
4418
  },
4419
  "node_modules/hyphen": {
4420
- "version": "1.7.0",
4421
- "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.7.0.tgz",
4422
- "integrity": "sha512-U5GRiJeEpXyDw1MqgZkig+TBzfWhXhwpE2aHmKuZAh/mzedvtPCXhaSDztJWhIhHUMe//D5nyGMGm5Jcb8tRdw=="
4423
  },
4424
  "node_modules/iconv-lite": {
4425
  "version": "0.6.3",
@@ -4432,11 +4430,6 @@
4432
  "node": ">=0.10.0"
4433
  }
4434
  },
4435
- "node_modules/idb-keyval": {
4436
- "version": "6.2.1",
4437
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
4438
- "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
4439
- },
4440
  "node_modules/ieee754": {
4441
  "version": "1.2.1",
4442
  "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -4507,12 +4500,12 @@
4507
  "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
4508
  },
4509
  "node_modules/internal-slot": {
4510
- "version": "1.0.5",
4511
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
4512
- "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
4513
  "dependencies": {
4514
- "get-intrinsic": "^1.2.0",
4515
- "has": "^1.0.3",
4516
  "side-channel": "^1.0.4"
4517
  },
4518
  "engines": {
@@ -4613,11 +4606,11 @@
4613
  }
4614
  },
4615
  "node_modules/is-core-module": {
4616
- "version": "2.13.0",
4617
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
4618
- "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
4619
  "dependencies": {
4620
- "has": "^1.0.3"
4621
  },
4622
  "funding": {
4623
  "url": "https://github.com/sponsors/ljharb"
@@ -4637,11 +4630,6 @@
4637
  "url": "https://github.com/sponsors/ljharb"
4638
  }
4639
  },
4640
- "node_modules/is-electron": {
4641
- "version": "2.2.2",
4642
- "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
4643
- "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="
4644
- },
4645
  "node_modules/is-extglob": {
4646
  "version": "2.1.1",
4647
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -4889,9 +4877,9 @@
4889
  }
4890
  },
4891
  "node_modules/jiti": {
4892
- "version": "1.20.0",
4893
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz",
4894
- "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==",
4895
  "bin": {
4896
  "jiti": "bin/jiti.js"
4897
  }
@@ -4961,9 +4949,9 @@
4961
  }
4962
  },
4963
  "node_modules/konva": {
4964
- "version": "9.2.2",
4965
- "resolved": "https://registry.npmjs.org/konva/-/konva-9.2.2.tgz",
4966
- "integrity": "sha512-Gyn5hQa/5+8pJvTn/IVyZWgum2otWXszuVCG/cevkAyKUFcmFv4tGbQhHFGtJPLQkGO+W6xfgRzyYIkNgKnPxA==",
4967
  "funding": [
4968
  {
4969
  "type": "patreon",
@@ -4985,11 +4973,14 @@
4985
  "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w=="
4986
  },
4987
  "node_modules/language-tags": {
4988
- "version": "1.0.5",
4989
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
4990
- "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
4991
  "dependencies": {
4992
- "language-subtag-registry": "~0.3.2"
 
 
 
4993
  }
4994
  },
4995
  "node_modules/legacy-swc-helpers": {
@@ -5293,9 +5284,9 @@
5293
  }
5294
  },
5295
  "node_modules/node-abi": {
5296
- "version": "3.50.0",
5297
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.50.0.tgz",
5298
- "integrity": "sha512-2Gxu7Eq7vnBIRfYSmqPruEllMM14FjOQFJSoqdGWthVn+tmwEXzmdPpya6cvvwf0uZA3F5N1fMFr9mijZBplFA==",
5299
  "dependencies": {
5300
  "semver": "^7.3.5"
5301
  },
@@ -5391,9 +5382,9 @@
5391
  }
5392
  },
5393
  "node_modules/object-inspect": {
5394
- "version": "1.13.0",
5395
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz",
5396
- "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==",
5397
  "funding": {
5398
  "url": "https://github.com/sponsors/ljharb"
5399
  }
@@ -5500,9 +5491,9 @@
5500
  }
5501
  },
5502
  "node_modules/openai": {
5503
- "version": "4.12.1",
5504
- "resolved": "https://registry.npmjs.org/openai/-/openai-4.12.1.tgz",
5505
- "integrity": "sha512-EAoUwm4dtiWvFwBhOCK/VfF8sj1ZU8+aAIJnfT4NyeTfrt1DM/6Gdd6fOZWTjBYryTAqu9Vpb5+9Wu6JMtm/gA==",
5506
  "dependencies": {
5507
  "@types/node": "^18.11.18",
5508
  "@types/node-fetch": "^2.6.4",
@@ -5511,23 +5502,19 @@
5511
  "digest-fetch": "^1.3.0",
5512
  "form-data-encoder": "1.7.2",
5513
  "formdata-node": "^4.3.2",
5514
- "node-fetch": "^2.6.7"
 
5515
  },
5516
  "bin": {
5517
  "openai": "bin/cli"
5518
  }
5519
  },
5520
  "node_modules/openai/node_modules/@types/node": {
5521
- "version": "18.18.5",
5522
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.5.tgz",
5523
- "integrity": "sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A=="
5524
- },
5525
- "node_modules/opencollective-postinstall": {
5526
- "version": "2.0.3",
5527
- "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
5528
- "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
5529
- "bin": {
5530
- "opencollective-postinstall": "index.js"
5531
  }
5532
  },
5533
  "node_modules/optionator": {
@@ -5880,9 +5867,9 @@
5880
  }
5881
  },
5882
  "node_modules/punycode": {
5883
- "version": "2.3.0",
5884
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
5885
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
5886
  "engines": {
5887
  "node": ">=6"
5888
  }
@@ -6393,6 +6380,20 @@
6393
  "node": ">=10"
6394
  }
6395
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6396
  "node_modules/set-function-name": {
6397
  "version": "2.0.1",
6398
  "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
@@ -6541,9 +6542,9 @@
6541
  }
6542
  },
6543
  "node_modules/streamx": {
6544
- "version": "2.15.1",
6545
- "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz",
6546
- "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==",
6547
  "dependencies": {
6548
  "fast-fifo": "^1.1.0",
6549
  "queue-tick": "^1.0.1"
@@ -6877,34 +6878,6 @@
6877
  "streamx": "^2.15.0"
6878
  }
6879
  },
6880
- "node_modules/tesseract.js": {
6881
- "version": "4.1.4",
6882
- "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-4.1.4.tgz",
6883
- "integrity": "sha512-iLjJjLWVNV4PApofEsd54Y1MbjhzpPxEzF8EjYmC2CLN4hrUqO5aTNTSbGA7/QjycKtAWHhn2YmDR+6GFwi2Zg==",
6884
- "hasInstallScript": true,
6885
- "dependencies": {
6886
- "bmp-js": "^0.1.0",
6887
- "idb-keyval": "^6.2.0",
6888
- "is-electron": "^2.2.2",
6889
- "is-url": "^1.2.4",
6890
- "node-fetch": "^2.6.9",
6891
- "opencollective-postinstall": "^2.0.3",
6892
- "regenerator-runtime": "^0.13.3",
6893
- "tesseract.js-core": "^4.0.4",
6894
- "wasm-feature-detect": "^1.2.11",
6895
- "zlibjs": "^0.3.1"
6896
- }
6897
- },
6898
- "node_modules/tesseract.js-core": {
6899
- "version": "4.0.4",
6900
- "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-4.0.4.tgz",
6901
- "integrity": "sha512-MJ+vtktjAaT0681uPl6TDUPhbRbpD/S9emko5rtorgHRZpQo7R3BG7h+3pVHgn1KjfNf1bvnx4B7KxEK8YKqpg=="
6902
- },
6903
- "node_modules/tesseract.js/node_modules/regenerator-runtime": {
6904
- "version": "0.13.11",
6905
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
6906
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
6907
- },
6908
  "node_modules/text-segmentation": {
6909
  "version": "1.0.3",
6910
  "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
@@ -7165,6 +7138,11 @@
7165
  "url": "https://github.com/sponsors/ljharb"
7166
  }
7167
  },
 
 
 
 
 
7168
  "node_modules/unicode-properties": {
7169
  "version": "1.4.1",
7170
  "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
@@ -7330,11 +7308,6 @@
7330
  "node": ">= 6"
7331
  }
7332
  },
7333
- "node_modules/wasm-feature-detect": {
7334
- "version": "1.5.1",
7335
- "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.5.1.tgz",
7336
- "integrity": "sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg=="
7337
- },
7338
  "node_modules/watchpack": {
7339
  "version": "2.4.0",
7340
  "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
@@ -7348,11 +7321,11 @@
7348
  }
7349
  },
7350
  "node_modules/web-streams-polyfill": {
7351
- "version": "4.0.0-beta.3",
7352
- "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
7353
- "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
7354
  "engines": {
7355
- "node": ">= 14"
7356
  }
7357
  },
7358
  "node_modules/webidl-conversions": {
@@ -7438,12 +7411,12 @@
7438
  }
7439
  },
7440
  "node_modules/which-typed-array": {
7441
- "version": "1.1.11",
7442
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
7443
- "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
7444
  "dependencies": {
7445
  "available-typed-arrays": "^1.0.5",
7446
- "call-bind": "^1.0.2",
7447
  "for-each": "^0.3.3",
7448
  "gopd": "^1.0.1",
7449
  "has-tostringtag": "^1.0.0"
@@ -7492,14 +7465,6 @@
7492
  "url": "https://github.com/sponsors/sindresorhus"
7493
  }
7494
  },
7495
- "node_modules/zlibjs": {
7496
- "version": "0.3.1",
7497
- "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
7498
- "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==",
7499
- "engines": {
7500
- "node": "*"
7501
- }
7502
- },
7503
  "node_modules/zod": {
7504
  "version": "3.21.4",
7505
  "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
@@ -7509,9 +7474,9 @@
7509
  }
7510
  },
7511
  "node_modules/zustand": {
7512
- "version": "4.4.3",
7513
- "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.3.tgz",
7514
- "integrity": "sha512-oRy+X3ZazZvLfmv6viIaQmtLOMeij1noakIsK/Y47PWYhT8glfXzQ4j0YcP5i0P0qI1A4rIB//SGROGyZhx91A==",
7515
  "dependencies": {
7516
  "use-sync-external-store": "1.2.0"
7517
  },
 
60
  "tailwind-merge": "^1.13.2",
61
  "tailwindcss": "3.3.3",
62
  "tailwindcss-animate": "^1.0.6",
 
63
  "ts-node": "^10.9.1",
64
  "typescript": "5.1.6",
65
  "usehooks-ts": "^2.9.1",
 
155
  }
156
  },
157
  "node_modules/@eslint-community/regexpp": {
158
+ "version": "4.10.0",
159
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
160
+ "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
161
  "engines": {
162
  "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
163
  }
 
235
  }
236
  },
237
  "node_modules/@humanwhocodes/config-array": {
238
+ "version": "0.11.13",
239
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
240
+ "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
241
  "dependencies": {
242
+ "@humanwhocodes/object-schema": "^2.0.1",
243
  "debug": "^4.1.1",
244
  "minimatch": "^3.0.5"
245
  },
 
260
  }
261
  },
262
  "node_modules/@humanwhocodes/object-schema": {
263
+ "version": "2.0.1",
264
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
265
+ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw=="
266
  },
267
  "node_modules/@jridgewell/gen-mapping": {
268
  "version": "0.3.3",
 
299
  "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
300
  },
301
  "node_modules/@jridgewell/trace-mapping": {
302
+ "version": "0.3.20",
303
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
304
+ "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
305
  "dependencies": {
306
  "@jridgewell/resolve-uri": "^3.1.0",
307
  "@jridgewell/sourcemap-codec": "^1.4.14"
 
1629
  }
1630
  },
1631
  "node_modules/@react-pdf/font": {
1632
+ "version": "2.3.7",
1633
+ "resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-2.3.7.tgz",
1634
+ "integrity": "sha512-NoCieWea6c1mCpDBoyjPbUEC1qXa+S/M7+8vYPZ71aTMgX7co3gQc2e6YKwrSQeQP+BsBq3LSVhjI2ETXfcytw==",
1635
  "dependencies": {
1636
  "@babel/runtime": "^7.20.13",
1637
+ "@react-pdf/types": "^2.3.4",
1638
  "cross-fetch": "^3.1.5",
1639
  "fontkit": "^2.0.2",
1640
  "is-url": "^1.2.4"
1641
  }
1642
  },
1643
  "node_modules/@react-pdf/image": {
1644
+ "version": "2.2.2",
1645
+ "resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-2.2.2.tgz",
1646
+ "integrity": "sha512-990JvRZuhsnHyAGd7gvmhfr+4/5PAHLH9IgDstaEDLEq2eFAIQFuNM7k3D6kjKgV1mM7Jqif3CWqrcHBF3jrJw==",
1647
  "dependencies": {
1648
  "@babel/runtime": "^7.20.13",
1649
  "@react-pdf/png-js": "^2.2.0",
 
1651
  }
1652
  },
1653
  "node_modules/@react-pdf/layout": {
1654
+ "version": "3.6.3",
1655
+ "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-3.6.3.tgz",
1656
+ "integrity": "sha512-w6ACZ9o18Q5wbzsY9a4KW2Gqn6Drt3AN/kb/I6SBz/L7PAJ9rPQBIDq/s5qZJ+/WwWy33rcC8WC1givtDhjCHQ==",
1657
  "dependencies": {
1658
  "@babel/runtime": "^7.20.13",
1659
  "@react-pdf/fns": "2.0.1",
1660
+ "@react-pdf/image": "^2.2.2",
1661
  "@react-pdf/pdfkit": "^3.0.2",
1662
  "@react-pdf/primitives": "^3.0.0",
1663
+ "@react-pdf/stylesheet": "^4.1.8",
1664
  "@react-pdf/textkit": "^4.2.0",
1665
+ "@react-pdf/types": "^2.3.4",
1666
  "@react-pdf/yoga": "^4.1.2",
1667
  "cross-fetch": "^3.1.5",
1668
  "emoji-regex": "^10.2.1",
 
1696
  "integrity": "sha512-0HGcknrLNwyhxe+SZCBL29JY4M85mXKdvTZE9uhjNbADGgTc8wVnkc5+e4S/lDvugbVISXyuIhZnYwtK9eDnyQ=="
1697
  },
1698
  "node_modules/@react-pdf/render": {
1699
+ "version": "3.2.7",
1700
+ "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-3.2.7.tgz",
1701
+ "integrity": "sha512-fAgbbAAkVL0hpcf1vUJLHxuPjPBqZuq8nors7fCwvoatBBwOWP9fza7IDPeFKN7+ZOnfmIZzes8Kc/DNHzJohw==",
1702
  "dependencies": {
1703
  "@babel/runtime": "^7.20.13",
1704
  "@react-pdf/fns": "2.0.1",
1705
  "@react-pdf/primitives": "^3.0.0",
1706
  "@react-pdf/textkit": "^4.2.0",
1707
+ "@react-pdf/types": "^2.3.4",
1708
  "abs-svg-path": "^0.1.1",
1709
  "color-string": "^1.5.3",
1710
  "normalize-svg-path": "^1.1.0",
 
1713
  }
1714
  },
1715
  "node_modules/@react-pdf/renderer": {
1716
+ "version": "3.1.14",
1717
+ "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-3.1.14.tgz",
1718
+ "integrity": "sha512-Qk29uTamH6q+drK/YmiFbuQQ+yutesfIe+wyrsXFoUJUutIiDIaibO6zByMkhWb3M6CMt6NvG3NLHio1OF8U6Q==",
1719
  "dependencies": {
1720
  "@babel/runtime": "^7.20.13",
1721
+ "@react-pdf/font": "^2.3.7",
1722
+ "@react-pdf/layout": "^3.6.3",
1723
  "@react-pdf/pdfkit": "^3.0.2",
1724
  "@react-pdf/primitives": "^3.0.0",
1725
+ "@react-pdf/render": "^3.2.7",
1726
+ "@react-pdf/types": "^2.3.4",
1727
  "events": "^3.3.0",
1728
  "object-assign": "^4.1.1",
1729
  "prop-types": "^15.6.2",
 
1735
  }
1736
  },
1737
  "node_modules/@react-pdf/stylesheet": {
1738
+ "version": "4.1.8",
1739
+ "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-4.1.8.tgz",
1740
+ "integrity": "sha512-/EuB9RBsH3YYRj8mwzImaul619MvX3rsHNF4h8LnlwDOuBehPA3L/fHrikfPqtJvHqK2ty3GXnkw0HG5SQpMzw==",
1741
  "dependencies": {
1742
  "@babel/runtime": "^7.20.13",
1743
  "@react-pdf/fns": "2.0.1",
1744
+ "@react-pdf/types": "^2.3.4",
1745
  "color-string": "^1.5.3",
1746
  "hsl-to-hex": "^1.0.0",
1747
  "media-engine": "^1.0.3",
 
1760
  }
1761
  },
1762
  "node_modules/@react-pdf/types": {
1763
+ "version": "2.3.4",
1764
+ "resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.3.4.tgz",
1765
+ "integrity": "sha512-vGGz21BTE05EktBbotbd7fjC0Yi8A/lOSIpzd7L7aF1XY+vyIHlQVb35DWCipM1p/6XN4cr9etGAmm1e4Mtmjw=="
1766
  },
1767
  "node_modules/@react-pdf/yoga": {
1768
  "version": "4.1.2",
 
1822
  "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw=="
1823
  },
1824
  "node_modules/@types/node-fetch": {
1825
+ "version": "2.6.8",
1826
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.8.tgz",
1827
+ "integrity": "sha512-nnH5lV9QCMPsbEVdTb5Y+F3GQxLSw1xQgIydrb2gSfEavRPs50FnMr+KUaa+LoPSqibm2N+ZZxH7lavZlAT4GA==",
1828
  "dependencies": {
1829
  "@types/node": "*",
1830
  "form-data": "^4.0.0"
1831
  }
1832
  },
1833
  "node_modules/@types/prop-types": {
1834
+ "version": "15.7.9",
1835
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz",
1836
+ "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g=="
1837
  },
1838
  "node_modules/@types/qs": {
1839
+ "version": "6.9.9",
1840
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz",
1841
+ "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==",
1842
  "dev": true
1843
  },
1844
  "node_modules/@types/react": {
 
1860
  }
1861
  },
1862
  "node_modules/@types/react-reconciler": {
1863
+ "version": "0.28.6",
1864
+ "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.6.tgz",
1865
+ "integrity": "sha512-NlilRDg7yjtFX568NA046OiHWbz5EKM1q5FSXi2GP7WKyU+Vem4NJQcG+ZaMiWotyPiYqkIb6NKJkFuplbchAA==",
1866
  "dependencies": {
1867
  "@types/react": "*"
1868
  }
1869
  },
1870
  "node_modules/@types/react-virtualized": {
1871
+ "version": "9.21.26",
1872
+ "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.26.tgz",
1873
+ "integrity": "sha512-fUpUyQqF8PTrFmBZzE9PcdtPwL8xgqUdXmtrYadNgFDYwbKBl3Lz0khp+tZ7dyKIHUVDO9NDlgQx8q1+LIUk+A==",
1874
  "dev": true,
1875
  "dependencies": {
1876
  "@types/prop-types": "*",
 
1878
  }
1879
  },
1880
  "node_modules/@types/sbd": {
1881
+ "version": "1.0.4",
1882
+ "resolved": "https://registry.npmjs.org/@types/sbd/-/sbd-1.0.4.tgz",
1883
+ "integrity": "sha512-j/1NO9SzpSyh2dnQjcV6VVWQvXyoNFX9nniZs3AlqQEJ7LF0Kq2Go/b6N+BrdnC7P93gtKmZZqMHOD8L6lg0fg==",
1884
  "dev": true
1885
  },
1886
  "node_modules/@types/scheduler": {
1887
+ "version": "0.16.5",
1888
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz",
1889
+ "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw=="
1890
  },
1891
  "node_modules/@types/stylis": {
1892
+ "version": "4.2.2",
1893
+ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.2.tgz",
1894
+ "integrity": "sha512-Rm17MsTpQQP5Jq4BF7CdrxJsDufoiL/q5IbJZYZmOZAJALyijgF7BzLgobXUqraNcQdqFYLYGeglDp6QzaxPpg=="
1895
  },
1896
  "node_modules/@types/uuid": {
1897
+ "version": "9.0.6",
1898
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
1899
+ "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew=="
1900
  },
1901
  "node_modules/@typescript-eslint/parser": {
1902
  "version": "5.62.0",
 
2011
  "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA=="
2012
  },
2013
  "node_modules/acorn": {
2014
+ "version": "8.11.2",
2015
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
2016
+ "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
2017
  "bin": {
2018
  "acorn": "bin/acorn"
2019
  },
 
2030
  }
2031
  },
2032
  "node_modules/acorn-walk": {
2033
+ "version": "8.3.0",
2034
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz",
2035
+ "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==",
2036
  "engines": {
2037
  "node": ">=0.4.0"
2038
  }
 
2254
  }
2255
  },
2256
  "node_modules/ast-types-flow": {
2257
+ "version": "0.0.8",
2258
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
2259
+ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="
2260
  },
2261
  "node_modules/asynciterator.prototype": {
2262
  "version": "1.0.0",
 
2315
  }
2316
  },
2317
  "node_modules/axe-core": {
2318
+ "version": "4.7.0",
2319
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
2320
+ "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
2321
  "engines": {
2322
  "node": ">=4"
2323
  }
 
2390
  "readable-stream": "^3.4.0"
2391
  }
2392
  },
 
 
 
 
 
2393
  "node_modules/brace-expansion": {
2394
  "version": "1.1.11",
2395
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
 
2492
  }
2493
  },
2494
  "node_modules/call-bind": {
2495
+ "version": "1.0.5",
2496
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
2497
+ "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
2498
  "dependencies": {
2499
+ "function-bind": "^1.1.2",
2500
+ "get-intrinsic": "^1.2.1",
2501
+ "set-function-length": "^1.1.1"
2502
  },
2503
  "funding": {
2504
  "url": "https://github.com/sponsors/ljharb"
 
2529
  }
2530
  },
2531
  "node_modules/caniuse-lite": {
2532
+ "version": "1.0.30001559",
2533
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz",
2534
+ "integrity": "sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==",
2535
  "funding": [
2536
  {
2537
  "type": "opencollective",
 
2983
  }
2984
  },
2985
  "node_modules/cookies-next/node_modules/@types/node": {
2986
+ "version": "16.18.60",
2987
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.60.tgz",
2988
+ "integrity": "sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA=="
2989
  },
2990
  "node_modules/create-require": {
2991
  "version": "1.1.1",
 
3022
  }
3023
  },
3024
  "node_modules/crypto-js": {
3025
+ "version": "4.2.0",
3026
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
3027
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
3028
  },
3029
  "node_modules/css-color-keywords": {
3030
  "version": "1.0.0",
 
3303
  }
3304
  },
3305
  "node_modules/electron-to-chromium": {
3306
+ "version": "1.4.574",
3307
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.574.tgz",
3308
+ "integrity": "sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg=="
3309
  },
3310
  "node_modules/emoji-regex": {
3311
+ "version": "10.3.0",
3312
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
3313
+ "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
3314
  },
3315
  "node_modules/encoding": {
3316
  "version": "0.1.13",
 
3352
  }
3353
  },
3354
  "node_modules/es-abstract": {
3355
+ "version": "1.22.3",
3356
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz",
3357
+ "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==",
3358
  "dependencies": {
3359
  "array-buffer-byte-length": "^1.0.0",
3360
  "arraybuffer.prototype.slice": "^1.0.2",
3361
  "available-typed-arrays": "^1.0.5",
3362
+ "call-bind": "^1.0.5",
3363
  "es-set-tostringtag": "^2.0.1",
3364
  "es-to-primitive": "^1.2.1",
3365
  "function.prototype.name": "^1.1.6",
3366
+ "get-intrinsic": "^1.2.2",
3367
  "get-symbol-description": "^1.0.0",
3368
  "globalthis": "^1.0.3",
3369
  "gopd": "^1.0.1",
 
3370
  "has-property-descriptors": "^1.0.0",
3371
  "has-proto": "^1.0.1",
3372
  "has-symbols": "^1.0.3",
3373
+ "hasown": "^2.0.0",
3374
  "internal-slot": "^1.0.5",
3375
  "is-array-buffer": "^3.0.2",
3376
  "is-callable": "^1.2.7",
 
3380
  "is-string": "^1.0.7",
3381
  "is-typed-array": "^1.1.12",
3382
  "is-weakref": "^1.0.2",
3383
+ "object-inspect": "^1.13.1",
3384
  "object-keys": "^1.1.1",
3385
  "object.assign": "^4.1.4",
3386
  "regexp.prototype.flags": "^1.5.1",
 
3394
  "typed-array-byte-offset": "^1.0.0",
3395
  "typed-array-length": "^1.0.4",
3396
  "unbox-primitive": "^1.0.2",
3397
+ "which-typed-array": "^1.1.13"
3398
  },
3399
  "engines": {
3400
  "node": ">= 0.4"
 
3425
  }
3426
  },
3427
  "node_modules/es-set-tostringtag": {
3428
+ "version": "2.0.2",
3429
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz",
3430
+ "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==",
3431
  "dependencies": {
3432
+ "get-intrinsic": "^1.2.2",
3433
+ "has-tostringtag": "^1.0.0",
3434
+ "hasown": "^2.0.0"
3435
  },
3436
  "engines": {
3437
  "node": ">= 0.4"
3438
  }
3439
  },
3440
  "node_modules/es-shim-unscopables": {
3441
+ "version": "1.0.2",
3442
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
3443
+ "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
3444
  "dependencies": {
3445
+ "hasown": "^2.0.0"
3446
  }
3447
  },
3448
  "node_modules/es-to-primitive": {
 
3625
  }
3626
  },
3627
  "node_modules/eslint-plugin-import": {
3628
+ "version": "2.29.0",
3629
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz",
3630
+ "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==",
3631
+ "dependencies": {
3632
+ "array-includes": "^3.1.7",
3633
+ "array.prototype.findlastindex": "^1.2.3",
3634
+ "array.prototype.flat": "^1.3.2",
3635
+ "array.prototype.flatmap": "^1.3.2",
3636
  "debug": "^3.2.7",
3637
  "doctrine": "^2.1.0",
3638
+ "eslint-import-resolver-node": "^0.3.9",
3639
  "eslint-module-utils": "^2.8.0",
3640
+ "hasown": "^2.0.0",
3641
+ "is-core-module": "^2.13.1",
3642
  "is-glob": "^4.0.3",
3643
  "minimatch": "^3.1.2",
3644
+ "object.fromentries": "^2.0.7",
3645
+ "object.groupby": "^1.0.1",
3646
+ "object.values": "^1.1.7",
3647
  "semver": "^6.3.1",
3648
  "tsconfig-paths": "^3.14.2"
3649
  },
 
3682
  }
3683
  },
3684
  "node_modules/eslint-plugin-jsx-a11y": {
3685
+ "version": "6.8.0",
3686
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz",
3687
+ "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==",
3688
+ "dependencies": {
3689
+ "@babel/runtime": "^7.23.2",
3690
+ "aria-query": "^5.3.0",
3691
+ "array-includes": "^3.1.7",
3692
+ "array.prototype.flatmap": "^1.3.2",
3693
+ "ast-types-flow": "^0.0.8",
3694
+ "axe-core": "=4.7.0",
3695
+ "axobject-query": "^3.2.1",
3696
  "damerau-levenshtein": "^1.0.8",
3697
  "emoji-regex": "^9.2.2",
3698
+ "es-iterator-helpers": "^1.0.15",
3699
+ "hasown": "^2.0.0",
3700
+ "jsx-ast-utils": "^3.3.5",
3701
+ "language-tags": "^1.0.9",
3702
  "minimatch": "^3.1.2",
3703
+ "object.entries": "^1.1.7",
3704
+ "object.fromentries": "^2.0.7"
 
3705
  },
3706
  "engines": {
3707
  "node": ">=4.0"
 
3715
  "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
3716
  "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
3717
  },
 
 
 
 
 
 
 
 
3718
  "node_modules/eslint-plugin-react": {
3719
  "version": "7.33.2",
3720
  "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz",
 
4057
  "node": ">= 12.20"
4058
  }
4059
  },
4060
+ "node_modules/formdata-node/node_modules/web-streams-polyfill": {
4061
+ "version": "4.0.0-beta.3",
4062
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
4063
+ "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
4064
+ "engines": {
4065
+ "node": ">= 14"
4066
+ }
4067
+ },
4068
  "node_modules/fraction.js": {
4069
  "version": "4.3.7",
4070
  "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
 
4134
  }
4135
  },
4136
  "node_modules/get-intrinsic": {
4137
+ "version": "1.2.2",
4138
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
4139
+ "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
4140
  "dependencies": {
4141
+ "function-bind": "^1.1.2",
 
4142
  "has-proto": "^1.0.1",
4143
+ "has-symbols": "^1.0.3",
4144
+ "hasown": "^2.0.0"
4145
  },
4146
  "funding": {
4147
  "url": "https://github.com/sponsors/ljharb"
 
4289
  "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
4290
  "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
4291
  },
 
 
 
 
 
 
 
 
4292
  "node_modules/has-bigints": {
4293
  "version": "1.0.2",
4294
  "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
 
4306
  }
4307
  },
4308
  "node_modules/has-property-descriptors": {
4309
+ "version": "1.0.1",
4310
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
4311
+ "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
4312
  "dependencies": {
4313
+ "get-intrinsic": "^1.2.2"
4314
  },
4315
  "funding": {
4316
  "url": "https://github.com/sponsors/ljharb"
 
4352
  "url": "https://github.com/sponsors/ljharb"
4353
  }
4354
  },
4355
+ "node_modules/hasown": {
4356
+ "version": "2.0.0",
4357
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
4358
+ "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
4359
+ "dependencies": {
4360
+ "function-bind": "^1.1.2"
4361
+ },
4362
+ "engines": {
4363
+ "node": ">= 0.4"
4364
+ }
4365
+ },
4366
  "node_modules/hsl-to-hex": {
4367
  "version": "1.0.0",
4368
  "resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz",
 
4415
  }
4416
  },
4417
  "node_modules/hyphen": {
4418
+ "version": "1.7.1",
4419
+ "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.7.1.tgz",
4420
+ "integrity": "sha512-fFMAldOO42EeYQnLTHB1YqXGpuMUm3CKgmU4IKuYQLGruTkVloWDVPA0E75SWwlNAXBQqtnAPk7wwzvebXYl5g=="
4421
  },
4422
  "node_modules/iconv-lite": {
4423
  "version": "0.6.3",
 
4430
  "node": ">=0.10.0"
4431
  }
4432
  },
 
 
 
 
 
4433
  "node_modules/ieee754": {
4434
  "version": "1.2.1",
4435
  "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 
4500
  "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
4501
  },
4502
  "node_modules/internal-slot": {
4503
+ "version": "1.0.6",
4504
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz",
4505
+ "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==",
4506
  "dependencies": {
4507
+ "get-intrinsic": "^1.2.2",
4508
+ "hasown": "^2.0.0",
4509
  "side-channel": "^1.0.4"
4510
  },
4511
  "engines": {
 
4606
  }
4607
  },
4608
  "node_modules/is-core-module": {
4609
+ "version": "2.13.1",
4610
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
4611
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
4612
  "dependencies": {
4613
+ "hasown": "^2.0.0"
4614
  },
4615
  "funding": {
4616
  "url": "https://github.com/sponsors/ljharb"
 
4630
  "url": "https://github.com/sponsors/ljharb"
4631
  }
4632
  },
 
 
 
 
 
4633
  "node_modules/is-extglob": {
4634
  "version": "2.1.1",
4635
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 
4877
  }
4878
  },
4879
  "node_modules/jiti": {
4880
+ "version": "1.21.0",
4881
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
4882
+ "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
4883
  "bin": {
4884
  "jiti": "bin/jiti.js"
4885
  }
 
4949
  }
4950
  },
4951
  "node_modules/konva": {
4952
+ "version": "9.2.3",
4953
+ "resolved": "https://registry.npmjs.org/konva/-/konva-9.2.3.tgz",
4954
+ "integrity": "sha512-oQ6VQ6kUL9IlhOGuEKKhxqnv6g/t8jZpVuWahQQ6hCqAsO8Ydi1zFGv7ef4EOq5GoPNq/d6Fyj/3i5Y/a5NooA==",
4955
  "funding": [
4956
  {
4957
  "type": "patreon",
 
4973
  "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w=="
4974
  },
4975
  "node_modules/language-tags": {
4976
+ "version": "1.0.9",
4977
+ "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
4978
+ "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
4979
  "dependencies": {
4980
+ "language-subtag-registry": "^0.3.20"
4981
+ },
4982
+ "engines": {
4983
+ "node": ">=0.10"
4984
  }
4985
  },
4986
  "node_modules/legacy-swc-helpers": {
 
5284
  }
5285
  },
5286
  "node_modules/node-abi": {
5287
+ "version": "3.51.0",
5288
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz",
5289
+ "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==",
5290
  "dependencies": {
5291
  "semver": "^7.3.5"
5292
  },
 
5382
  }
5383
  },
5384
  "node_modules/object-inspect": {
5385
+ "version": "1.13.1",
5386
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
5387
+ "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
5388
  "funding": {
5389
  "url": "https://github.com/sponsors/ljharb"
5390
  }
 
5491
  }
5492
  },
5493
  "node_modules/openai": {
5494
+ "version": "4.14.2",
5495
+ "resolved": "https://registry.npmjs.org/openai/-/openai-4.14.2.tgz",
5496
+ "integrity": "sha512-JGlm7mMC7J+cyQZnQMOH7daD9cBqqWqLtlBsejElEkgoehPrYfdyxSxIGICz5xk4YimbwI5FlLATSVojLtCKXQ==",
5497
  "dependencies": {
5498
  "@types/node": "^18.11.18",
5499
  "@types/node-fetch": "^2.6.4",
 
5502
  "digest-fetch": "^1.3.0",
5503
  "form-data-encoder": "1.7.2",
5504
  "formdata-node": "^4.3.2",
5505
+ "node-fetch": "^2.6.7",
5506
+ "web-streams-polyfill": "^3.2.1"
5507
  },
5508
  "bin": {
5509
  "openai": "bin/cli"
5510
  }
5511
  },
5512
  "node_modules/openai/node_modules/@types/node": {
5513
+ "version": "18.18.8",
5514
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz",
5515
+ "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==",
5516
+ "dependencies": {
5517
+ "undici-types": "~5.26.4"
 
 
 
 
 
5518
  }
5519
  },
5520
  "node_modules/optionator": {
 
5867
  }
5868
  },
5869
  "node_modules/punycode": {
5870
+ "version": "2.3.1",
5871
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
5872
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
5873
  "engines": {
5874
  "node": ">=6"
5875
  }
 
6380
  "node": ">=10"
6381
  }
6382
  },
6383
+ "node_modules/set-function-length": {
6384
+ "version": "1.1.1",
6385
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
6386
+ "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
6387
+ "dependencies": {
6388
+ "define-data-property": "^1.1.1",
6389
+ "get-intrinsic": "^1.2.1",
6390
+ "gopd": "^1.0.1",
6391
+ "has-property-descriptors": "^1.0.0"
6392
+ },
6393
+ "engines": {
6394
+ "node": ">= 0.4"
6395
+ }
6396
+ },
6397
  "node_modules/set-function-name": {
6398
  "version": "2.0.1",
6399
  "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
 
6542
  }
6543
  },
6544
  "node_modules/streamx": {
6545
+ "version": "2.15.2",
6546
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.2.tgz",
6547
+ "integrity": "sha512-b62pAV/aeMjUoRN2C/9F0n+G8AfcJjNC0zw/ZmOHeFsIe4m4GzjVW9m6VHXVjk536NbdU9JRwKMJRfkc+zUFTg==",
6548
  "dependencies": {
6549
  "fast-fifo": "^1.1.0",
6550
  "queue-tick": "^1.0.1"
 
6878
  "streamx": "^2.15.0"
6879
  }
6880
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6881
  "node_modules/text-segmentation": {
6882
  "version": "1.0.3",
6883
  "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
 
7138
  "url": "https://github.com/sponsors/ljharb"
7139
  }
7140
  },
7141
+ "node_modules/undici-types": {
7142
+ "version": "5.26.5",
7143
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
7144
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
7145
+ },
7146
  "node_modules/unicode-properties": {
7147
  "version": "1.4.1",
7148
  "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
 
7308
  "node": ">= 6"
7309
  }
7310
  },
 
 
 
 
 
7311
  "node_modules/watchpack": {
7312
  "version": "2.4.0",
7313
  "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
 
7321
  }
7322
  },
7323
  "node_modules/web-streams-polyfill": {
7324
+ "version": "3.2.1",
7325
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
7326
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
7327
  "engines": {
7328
+ "node": ">= 8"
7329
  }
7330
  },
7331
  "node_modules/webidl-conversions": {
 
7411
  }
7412
  },
7413
  "node_modules/which-typed-array": {
7414
+ "version": "1.1.13",
7415
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz",
7416
+ "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==",
7417
  "dependencies": {
7418
  "available-typed-arrays": "^1.0.5",
7419
+ "call-bind": "^1.0.4",
7420
  "for-each": "^0.3.3",
7421
  "gopd": "^1.0.1",
7422
  "has-tostringtag": "^1.0.0"
 
7465
  "url": "https://github.com/sponsors/sindresorhus"
7466
  }
7467
  },
 
 
 
 
 
 
 
 
7468
  "node_modules/zod": {
7469
  "version": "3.21.4",
7470
  "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
 
7474
  }
7475
  },
7476
  "node_modules/zustand": {
7477
+ "version": "4.4.5",
7478
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.5.tgz",
7479
+ "integrity": "sha512-jgIrBBLKncQW74PA2Lclct3gwD4aPughwGE4FqlXrv3rDqQox7JCn8rwUiFK6ygJcbBAvfTf8fF+ICg7HLD2FQ==",
7480
  "dependencies": {
7481
  "use-sync-external-store": "1.2.0"
7482
  },
package.json CHANGED
@@ -61,7 +61,6 @@
61
  "tailwind-merge": "^1.13.2",
62
  "tailwindcss": "3.3.3",
63
  "tailwindcss-animate": "^1.0.6",
64
- "tesseract.js": "^4.1.2",
65
  "ts-node": "^10.9.1",
66
  "typescript": "5.1.6",
67
  "usehooks-ts": "^2.9.1",
 
61
  "tailwind-merge": "^1.13.2",
62
  "tailwindcss": "3.3.3",
63
  "tailwindcss-animate": "^1.0.6",
 
64
  "ts-node": "^10.9.1",
65
  "typescript": "5.1.6",
66
  "usehooks-ts": "^2.9.1",
src/app/engine/presets.ts CHANGED
@@ -243,10 +243,10 @@ export const presets: Record<string, Preset> = {
243
  font: "actionman",
244
  llmPrompt: "new pulp science fiction",
245
  imagePrompt: (prompt: string) => [
246
- `vintage color pulp comic panel`,
247
- "40s",
 
248
  "1940",
249
- "vintage science fiction",
250
  `${prompt}`,
251
  // "single panel",
252
  // "comic album"
 
243
  font: "actionman",
244
  llmPrompt: "new pulp science fiction",
245
  imagePrompt: (prompt: string) => [
246
+ `vintage science fiction`,
247
+ // "40s",
248
+ "color pulp comic panel",
249
  "1940",
 
250
  `${prompt}`,
251
  // "single panel",
252
  // "comic album"
src/app/globals.css CHANGED
@@ -30,8 +30,9 @@ body {
30
  /* this is the trick to bypass the style={{}} attribute when printing */
31
  @media print {
32
  .comic-page[style] { width: 100vw !important; }
33
- }
34
 
 
 
35
 
36
  .render-to-image .comic-panel {
37
  height: auto !important;
 
30
  /* this is the trick to bypass the style={{}} attribute when printing */
31
  @media print {
32
  .comic-page[style] { width: 100vw !important; }
 
33
 
34
+ @page { size: landscape }
35
+ }
36
 
37
  .render-to-image .comic-panel {
38
  height: auto !important;
src/app/interface/bottom-bar/index.tsx CHANGED
@@ -81,10 +81,10 @@ export function BottomBar() {
81
  #### Comic:
82
  ${uploadUrl
83
  ? (`![${prompt}](${uploadUrl})`)
84
- : (`(please drag & drop your JPG image here)`)}
85
  `;
86
 
87
- console.log("descriptionMd:", descriptionMd)
88
 
89
  const params = new URLSearchParams({
90
  title: `[Comic] ${prompt}`,
@@ -140,6 +140,7 @@ ${uploadUrl
140
  // : null
141
  }
142
  </div>
 
143
  <div>
144
  <Button
145
  onClick={handlePrint}
@@ -160,6 +161,20 @@ ${uploadUrl
160
  remainingImages ? `${allStatus.length - remainingImages}/${allStatus.length} ⌛` : `Save`
161
  }</span>
162
  </Button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  </div>
164
  <div>
165
  {
 
81
  #### Comic:
82
  ${uploadUrl
83
  ? (`![${prompt}](${uploadUrl})`)
84
+ : (`(please drag & drop a capture of your comic here - we recommend you to print the PDF and convert it to JPG for best quality!)`)}
85
  `;
86
 
87
+ // console.log("descriptionMd:", descriptionMd)
88
 
89
  const params = new URLSearchParams({
90
  title: `[Comic] ${prompt}`,
 
140
  // : null
141
  }
142
  </div>
143
+ {/*
144
  <div>
145
  <Button
146
  onClick={handlePrint}
 
161
  remainingImages ? `${allStatus.length - remainingImages}/${allStatus.length} ⌛` : `Save`
162
  }</span>
163
  </Button>
164
+ </div>
165
+ */}
166
+ <div>
167
+ <Button
168
+ onClick={handlePrint}
169
+ disabled={!prompt?.length}
170
+ >
171
+ <span className="hidden md:inline">{
172
+ remainingImages ? `${allStatus.length - remainingImages}/${allStatus.length} panels ⌛` : `Save PDF`
173
+ }</span>
174
+ <span className="inline md:hidden">{
175
+ remainingImages ? `${allStatus.length - remainingImages}/${allStatus.length} ⌛` : `Save PDF`
176
+ }</span>
177
+ </Button>
178
  </div>
179
  <div>
180
  {
src/app/interface/page/index.tsx CHANGED
@@ -1,15 +1,20 @@
1
- import { allLayoutAspectRatios, allLayouts } from "@/app/layouts"
2
  import { useStore } from "@/app/store"
3
  import { cn } from "@/lib/utils"
4
  import { useEffect, useRef } from "react"
5
 
6
- export function Page({ page }: { page: number }) {
7
  const zoomLevel = useStore(state => state.zoomLevel)
8
  const layouts = useStore(state => state.layouts)
9
  // const prompt = useStore(state => state.prompt)
10
 
11
- const LayoutElement = (allLayouts as any)[layouts[page]]
12
- const aspectRatio = ((allLayoutAspectRatios as any)[layouts[page]] as string) || "aspect-[250/297]"
 
 
 
 
 
13
  /*
14
  const [canLoad, setCanLoad] = useState(false)
15
  useEffect(() => {
@@ -42,14 +47,15 @@ export function Page({ page }: { page: number }) {
42
  `shadow-2xl`,
43
  `print:shadow-none`,
44
  `print:border-0`,
45
- `print:width-screen`
 
46
  )}
47
  style={{
48
  padding: `${Math.round((zoomLevel / 100) * 16)}px`
49
  // marginLeft: `${zoomLevel > 100 ? `100`}`
50
  }}
51
  >
52
- <LayoutElement />
53
  </div>
54
  )
55
  }
 
1
+ import { allLayoutAspectRatios, allLayouts, allLayoutsNbPanels } from "@/app/layouts"
2
  import { useStore } from "@/app/store"
3
  import { cn } from "@/lib/utils"
4
  import { useEffect, useRef } from "react"
5
 
6
+ export function Page({ page }: { page: number}) {
7
  const zoomLevel = useStore(state => state.zoomLevel)
8
  const layouts = useStore(state => state.layouts)
9
  // const prompt = useStore(state => state.prompt)
10
 
11
+ const layout = layouts[page]
12
+
13
+ const LayoutElement = (allLayouts as any)[layout]
14
+ const aspectRatio = ((allLayoutAspectRatios as any)[layout] as string) || "aspect-[250/297]"
15
+
16
+ const nbPanels = ((allLayoutsNbPanels as any)[layout] as number) || 4
17
+
18
  /*
19
  const [canLoad, setCanLoad] = useState(false)
20
  useEffect(() => {
 
47
  `shadow-2xl`,
48
  `print:shadow-none`,
49
  `print:border-0`,
50
+ `print:width-screen`,
51
+ `print:break-after-all`
52
  )}
53
  style={{
54
  padding: `${Math.round((zoomLevel / 100) * 16)}px`
55
  // marginLeft: `${zoomLevel > 100 ? `100`}`
56
  }}
57
  >
58
+ <LayoutElement page={page} nbPanels={nbPanels} />
59
  </div>
60
  )
61
  }
src/app/interface/panel/index.tsx CHANGED
@@ -13,17 +13,36 @@ import { getInitialRenderedScene } from "@/lib/getInitialRenderedScene"
13
  import { Progress } from "@/app/interface/progress"
14
 
15
  export function Panel({
 
 
16
  panel,
17
  className = "",
18
  width = 1,
19
  height = 1,
20
  }: {
 
 
 
 
 
 
 
21
  panel: number
 
 
22
  className?: string
23
  width?: number
24
  height?: number
25
  }) {
26
- const panelId = `${panel}`
 
 
 
 
 
 
 
 
27
 
28
  const [mouseOver, setMouseOver] = useState(false)
29
  const ref = useRef<HTMLImageElement>(null)
@@ -33,10 +52,10 @@ export function Panel({
33
  const setGeneratingImages = useStore(state => state.setGeneratingImages)
34
 
35
  const panels = useStore(state => state.panels)
36
- const prompt = panels[panel] || ""
37
 
38
  const captions = useStore(state => state.captions)
39
- const caption = captions[panel] || ""
40
 
41
  const zoomLevel = useStore(state => state.zoomLevel)
42
  const showCaptions = useStore(state => state.showCaptions)
@@ -47,7 +66,7 @@ export function Panel({
47
  const renderedScenes = useStore(state => state.renderedScenes)
48
  const setRendered = useStore(state => state.setRendered)
49
 
50
- const rendered = renderedScenes[panel] || getInitialRenderedScene()
51
 
52
  const [revision, setRevision] = useState(0)
53
 
@@ -59,9 +78,9 @@ export function Panel({
59
  const timeoutRef = useRef<any>(null)
60
 
61
  const enableRateLimiter = `${process.env.NEXT_PUBLIC_ENABLE_RATE_LIMITER}` === "true"
 
62
 
63
- const delay = enableRateLimiter ? (1000 + (500 * panel)) : 1000
64
-
65
 
66
  const startImageGeneration = ({ prompt, width, height, revision }: {
67
  prompt: string
@@ -85,7 +104,7 @@ export function Panel({
85
  // atrocious and very, very, very, very, very, very, very ugly hack for the Inference API
86
  // as apparently "use_cache: false" doesn't work, or doesn't do what we want it to do
87
  let cacheInvalidationHack = ""
88
- const nbMaxRevisions = 6
89
  for (let i = 0; i < revision && revision < nbMaxRevisions; i++) {
90
  const j = Math.random()
91
  cacheInvalidationHack += j < 0.3 ? "_" : j < 0.6 ? "," : "-"
 
13
  import { Progress } from "@/app/interface/progress"
14
 
15
  export function Panel({
16
+ page,
17
+ nbPanels,
18
  panel,
19
  className = "",
20
  width = 1,
21
  height = 1,
22
  }: {
23
+ // page number of which the panel is
24
+ page: number
25
+
26
+ // the number of panels should be unique to each layout
27
+ nbPanels: number
28
+
29
+ // panel id, between 0 and (nbPanels - 1)
30
  panel: number
31
+
32
+
33
  className?: string
34
  width?: number
35
  height?: number
36
  }) {
37
+
38
+ // index of the panel in the whole app
39
+ const panelIndex = page * nbPanels + panel
40
+
41
+ // console.log("debug:", { page, nbPanels, panel })
42
+ // the panel Id must be unique across all pages
43
+ const panelId = `${panelIndex}`
44
+
45
+ // console.log("panelId: " + panelId)
46
 
47
  const [mouseOver, setMouseOver] = useState(false)
48
  const ref = useRef<HTMLImageElement>(null)
 
52
  const setGeneratingImages = useStore(state => state.setGeneratingImages)
53
 
54
  const panels = useStore(state => state.panels)
55
+ const prompt = panels[panelIndex] || ""
56
 
57
  const captions = useStore(state => state.captions)
58
+ const caption = captions[panelIndex] || ""
59
 
60
  const zoomLevel = useStore(state => state.zoomLevel)
61
  const showCaptions = useStore(state => state.showCaptions)
 
66
  const renderedScenes = useStore(state => state.renderedScenes)
67
  const setRendered = useStore(state => state.setRendered)
68
 
69
+ const rendered = renderedScenes[panelIndex] || getInitialRenderedScene()
70
 
71
  const [revision, setRevision] = useState(0)
72
 
 
78
  const timeoutRef = useRef<any>(null)
79
 
80
  const enableRateLimiter = `${process.env.NEXT_PUBLIC_ENABLE_RATE_LIMITER}` === "true"
81
+
82
 
83
+ const delay = enableRateLimiter ? (1000 + (500 * panelIndex)) : 1000
 
84
 
85
  const startImageGeneration = ({ prompt, width, height, revision }: {
86
  prompt: string
 
104
  // atrocious and very, very, very, very, very, very, very ugly hack for the Inference API
105
  // as apparently "use_cache: false" doesn't work, or doesn't do what we want it to do
106
  let cacheInvalidationHack = ""
107
+ const nbMaxRevisions = 10
108
  for (let i = 0; i < revision && revision < nbMaxRevisions; i++) {
109
  const j = Math.random()
110
  cacheInvalidationHack += j < 0.3 ? "_" : j < 0.6 ? "," : "-"
src/app/interface/top-menu/index.tsx CHANGED
@@ -54,10 +54,10 @@ export function TopMenu() {
54
 
55
  const searchParams = useSearchParams()
56
 
57
- const requestedPreset = (searchParams.get('preset') as PresetName) || defaultPreset
58
- const requestedFont = (searchParams.get('font') as FontName) || defaultFont
59
- const requestedPrompt = (searchParams.get('prompt') as string) || ""
60
- const requestedLayout = (searchParams.get('layout') as LayoutName) || defaultLayout
61
 
62
  const [draftPrompt, setDraftPrompt] = useState(requestedPrompt)
63
  const [draftPreset, setDraftPreset] = useState<PresetName>(requestedPreset)
 
54
 
55
  const searchParams = useSearchParams()
56
 
57
+ const requestedPreset = (searchParams?.get('preset') as PresetName) || defaultPreset
58
+ const requestedFont = (searchParams?.get('font') as FontName) || defaultFont
59
+ const requestedPrompt = (searchParams?.get('prompt') as string) || ""
60
+ const requestedLayout = (searchParams?.get('layout') as LayoutName) || defaultLayout
61
 
62
  const [draftPrompt, setDraftPrompt] = useState(requestedPrompt)
63
  const [draftPreset, setDraftPreset] = useState<PresetName>(requestedPreset)
src/app/layouts/index.tsx CHANGED
@@ -3,12 +3,16 @@
3
  import { Panel } from "@/app/interface/panel"
4
  import { pick } from "@/lib/pick"
5
  import { Grid } from "@/app/interface/grid"
 
 
6
 
7
- export function Layout0() {
8
  return (
9
  <Grid className="grid-cols-2 grid-rows-2">
10
  <div className="bg-stone-100 col-span-1 row-span-1">
11
  <Panel
 
 
12
  panel={0}
13
  width={1024}
14
  height={1024}
@@ -16,6 +20,8 @@ export function Layout0() {
16
  </div>
17
  <div className="bg-zinc-100 col-span-1 row-span-1">
18
  <Panel
 
 
19
  panel={1}
20
  width={1024}
21
  height={1024}
@@ -23,6 +29,8 @@ export function Layout0() {
23
  </div>
24
  <div className="bg-gray-100 col-span-1 row-span-1">
25
  <Panel
 
 
26
  panel={2}
27
  width={1024}
28
  height={1024}
@@ -30,6 +38,8 @@ export function Layout0() {
30
  </div>
31
  <div className="bg-slate-100 col-span-1 row-span-1">
32
  <Panel
 
 
33
  panel={3}
34
  width={1024}
35
  height={1024}
@@ -39,11 +49,13 @@ export function Layout0() {
39
  )
40
  }
41
 
42
- export function Layout1() {
43
  return (
44
  <Grid className="grid-cols-2 grid-rows-3">
45
  <div className="bg-stone-100">
46
  <Panel
 
 
47
  panel={0}
48
  width={1024}
49
  height={768}
@@ -51,6 +63,8 @@ export function Layout1() {
51
  </div>
52
  <div className="bg-zinc-100 row-span-2">
53
  <Panel
 
 
54
  panel={1}
55
  width={768}
56
  height={1024}
@@ -58,6 +72,8 @@ export function Layout1() {
58
  </div>
59
  <div className="bg-gray-100 row-span-2 col-span-1">
60
  <Panel
 
 
61
  panel={2}
62
  width={768}
63
  height={1024}
@@ -65,6 +81,8 @@ export function Layout1() {
65
  </div>
66
  <div className="bg-slate-100">
67
  <Panel
 
 
68
  panel={3}
69
  width={1024}
70
  height={768}
@@ -74,11 +92,13 @@ export function Layout1() {
74
  )
75
  }
76
 
77
- export function Layout2_todo() {
78
  return (
79
  <Grid className="grid-cols-2 grid-rows-3">
80
  <div className="bg-gray-100 row-span-3 col-span-1">
81
  <Panel
 
 
82
  panel={0}
83
  width={768}
84
  height={1024}
@@ -86,6 +106,8 @@ export function Layout2_todo() {
86
  </div>
87
  <div className="bg-slate-100">
88
  <Panel
 
 
89
  panel={1}
90
  width={1024}
91
  height={768}
@@ -93,6 +115,8 @@ export function Layout2_todo() {
93
  </div>
94
  <div className="bg-stone-100">
95
  <Panel
 
 
96
  panel={2}
97
  width={1024}
98
  height={768}
@@ -100,6 +124,8 @@ export function Layout2_todo() {
100
  </div>
101
  <div className="bg-zinc-100 row-span-1 col-span-1">
102
  <Panel
 
 
103
  panel={3}
104
  width={1024}
105
  height={768}
@@ -109,11 +135,13 @@ export function Layout2_todo() {
109
  )
110
  }
111
 
112
- export function Layout3_todo() {
113
  return (
114
  <Grid className="grid-cols-5 grid-rows-2">
115
  <div className="bg-zinc-100 col-span-3">
116
  <Panel
 
 
117
  panel={0}
118
  width={1024}
119
  height={768}
@@ -121,6 +149,8 @@ export function Layout3_todo() {
121
  </div>
122
  <div className="bg-zinc-100 col-span-2 row-span-2">
123
  <Panel
 
 
124
  panel={1}
125
  width={768}
126
  height={1024}
@@ -129,6 +159,8 @@ export function Layout3_todo() {
129
  <div className="col-span-3 grid grid-cols-2 gap-2">
130
  <div className="bg-stone-100">
131
  <Panel
 
 
132
  panel={2}
133
  width={768}
134
  height={758}
@@ -136,6 +168,8 @@ export function Layout3_todo() {
136
  </div>
137
  <div className="bg-slate-100">
138
  <Panel
 
 
139
  panel={3}
140
  width={768}
141
  height={758}
@@ -146,11 +180,13 @@ export function Layout3_todo() {
146
  )
147
  }
148
 
149
- export function Layout4_todo() {
150
  return (
151
  <Grid className="grid-cols-2 grid-rows-3">
152
  <div className="bg-slate-100 row-span-2">
153
  <Panel
 
 
154
  panel={0}
155
  width={768}
156
  height={1024}
@@ -158,6 +194,8 @@ export function Layout4_todo() {
158
  </div>
159
  <div className="bg-gray-100 row-span-1 col-span-1">
160
  <Panel
 
 
161
  panel={1}
162
  width={1024}
163
  height={768}
@@ -165,6 +203,8 @@ export function Layout4_todo() {
165
  </div>
166
  <div className="bg-zinc-100 row-span-2">
167
  <Panel
 
 
168
  panel={2}
169
  width={1024}
170
  height={768}
@@ -172,6 +212,8 @@ export function Layout4_todo() {
172
  </div>
173
  <div className="bg-stone-100">
174
  <Panel
 
 
175
  panel={3}
176
  width={768}
177
  height={1024}
@@ -182,11 +224,13 @@ export function Layout4_todo() {
182
  }
183
 
184
 
185
- export function Layout2() {
186
  return (
187
  <Grid className="grid-cols-3 grid-rows-2">
188
  <div className="bg-zinc-100 col-span-1 row-span-1">
189
  <Panel
 
 
190
  panel={0}
191
  width={768}
192
  height={1024}
@@ -194,6 +238,8 @@ export function Layout2() {
194
  </div>
195
  <div className="bg-zinc-100 col-span-1 row-span-1">
196
  <Panel
 
 
197
  panel={1}
198
  width={768}
199
  height={1024}
@@ -201,6 +247,8 @@ export function Layout2() {
201
  </div>
202
  <div className="bg-stone-100 row-span-2 col-span-1">
203
  <Panel
 
 
204
  panel={2}
205
  width={512}
206
  height={1024}
@@ -208,6 +256,8 @@ export function Layout2() {
208
  </div>
209
  <div className="bg-slate-100 row-span-1 col-span-2">
210
  <Panel
 
 
211
  panel={3}
212
  width={1024}
213
  height={768}
@@ -217,11 +267,13 @@ export function Layout2() {
217
  )
218
  }
219
 
220
- export function Layout3() {
221
  return (
222
  <Grid className="grid-cols-3 grid-rows-2">
223
  <div className="bg-zinc-100 col-span-2 row-span-1">
224
  <Panel
 
 
225
  panel={0}
226
  width={1024}
227
  height={768}
@@ -229,6 +281,8 @@ export function Layout3() {
229
  </div>
230
  <div className="bg-zinc-100 col-span-1 row-span-1">
231
  <Panel
 
 
232
  panel={1}
233
  width={768}
234
  height={1024}
@@ -236,6 +290,8 @@ export function Layout3() {
236
  </div>
237
  <div className="bg-stone-100 row-span-1 col-span-1">
238
  <Panel
 
 
239
  panel={2}
240
  width={768}
241
  height={1024}
@@ -243,6 +299,8 @@ export function Layout3() {
243
  </div>
244
  <div className="bg-slate-100 row-span-1 col-span-2">
245
  <Panel
 
 
246
  panel={3}
247
  width={1024}
248
  height={768}
@@ -253,11 +311,13 @@ export function Layout3() {
253
  }
254
 
255
  // squares + vertical
256
- export function Layout4() {
257
  return (
258
  <Grid className="grid-cols-8 grid-rows-8">
259
  <div className="bg-zinc-100 col-start-1 col-end-7 row-start-1 row-end-3">
260
  <Panel
 
 
261
  panel={0}
262
  width={512}
263
  height={1024}
@@ -265,6 +325,8 @@ export function Layout4() {
265
  </div>
266
  <div className="bg-zinc-100 col-start-3 col-end-9 row-start-3 row-end-4">
267
  <Panel
 
 
268
  panel={1}
269
  width={1024}
270
  height={768}
@@ -272,6 +334,8 @@ export function Layout4() {
272
  </div>
273
  <div className="bg-stone-100 col-start-2 col-end-8 row-start-4 row-end-6">
274
  <Panel
 
 
275
  panel={2}
276
  width={768}
277
  height={1024}
@@ -279,6 +343,8 @@ export function Layout4() {
279
  </div>
280
  <div className="bg-slate-100 col-start-1 col-end-9 row-start-6 row-end-8">
281
  <Panel
 
 
282
  panel={3}
283
  width={1024}
284
  height={512}
@@ -289,11 +355,13 @@ export function Layout4() {
289
  }
290
 
291
  // squares + horizontal
292
- export function Layout5() {
293
  return (
294
  <Grid className="grid-cols-4 grid-rows-4">
295
  <div className="bg-zinc-100">
296
  <Panel
 
 
297
  panel={0}
298
  width={1024}
299
  height={1024}
@@ -301,6 +369,8 @@ export function Layout5() {
301
  </div>
302
  <div className="bg-zinc-100">
303
  <Panel
 
 
304
  panel={1}
305
  width={1024}
306
  height={1024}
@@ -308,6 +378,8 @@ export function Layout5() {
308
  </div>
309
  <div className="bg-stone-100">
310
  <Panel
 
 
311
  panel={2}
312
  width={1024}
313
  height={1024}
@@ -315,6 +387,8 @@ export function Layout5() {
315
  </div>
316
  <div className="bg-slate-100">
317
  <Panel
 
 
318
  panel={3}
319
  width={1024}
320
  height={1024}
@@ -352,6 +426,15 @@ export const allLayoutAspectRatios = {
352
  // Layout4: "aspect-[1/3]",
353
  }
354
 
 
 
 
 
 
 
 
 
 
355
  export type LayoutName = keyof typeof allLayouts
356
 
357
  export const defaultLayout: LayoutName = "Layout1"
@@ -367,4 +450,3 @@ export const getRandomLayoutName = (): LayoutName => {
367
  export function getRandomLayoutNames(): LayoutName[] {
368
  return nonRandomLayouts.sort(() => Math.random() - 0.5) as LayoutName[]
369
  }
370
-
 
3
  import { Panel } from "@/app/interface/panel"
4
  import { pick } from "@/lib/pick"
5
  import { Grid } from "@/app/interface/grid"
6
+ import { LayoutProps } from "@/types"
7
+ import { NB_PANELS_PER_PAGE } from "@/config"
8
 
9
+ export function Layout0({ page, nbPanels }: LayoutProps) {
10
  return (
11
  <Grid className="grid-cols-2 grid-rows-2">
12
  <div className="bg-stone-100 col-span-1 row-span-1">
13
  <Panel
14
+ page={page}
15
+ nbPanels={nbPanels}
16
  panel={0}
17
  width={1024}
18
  height={1024}
 
20
  </div>
21
  <div className="bg-zinc-100 col-span-1 row-span-1">
22
  <Panel
23
+ page={page}
24
+ nbPanels={nbPanels}
25
  panel={1}
26
  width={1024}
27
  height={1024}
 
29
  </div>
30
  <div className="bg-gray-100 col-span-1 row-span-1">
31
  <Panel
32
+ page={page}
33
+ nbPanels={nbPanels}
34
  panel={2}
35
  width={1024}
36
  height={1024}
 
38
  </div>
39
  <div className="bg-slate-100 col-span-1 row-span-1">
40
  <Panel
41
+ page={page}
42
+ nbPanels={nbPanels}
43
  panel={3}
44
  width={1024}
45
  height={1024}
 
49
  )
50
  }
51
 
52
+ export function Layout1({ page, nbPanels }: LayoutProps) {
53
  return (
54
  <Grid className="grid-cols-2 grid-rows-3">
55
  <div className="bg-stone-100">
56
  <Panel
57
+ page={page}
58
+ nbPanels={nbPanels}
59
  panel={0}
60
  width={1024}
61
  height={768}
 
63
  </div>
64
  <div className="bg-zinc-100 row-span-2">
65
  <Panel
66
+ page={page}
67
+ nbPanels={nbPanels}
68
  panel={1}
69
  width={768}
70
  height={1024}
 
72
  </div>
73
  <div className="bg-gray-100 row-span-2 col-span-1">
74
  <Panel
75
+ page={page}
76
+ nbPanels={nbPanels}
77
  panel={2}
78
  width={768}
79
  height={1024}
 
81
  </div>
82
  <div className="bg-slate-100">
83
  <Panel
84
+ page={page}
85
+ nbPanels={nbPanels}
86
  panel={3}
87
  width={1024}
88
  height={768}
 
92
  )
93
  }
94
 
95
+ export function Layout2_todo({ page, nbPanels }: LayoutProps) {
96
  return (
97
  <Grid className="grid-cols-2 grid-rows-3">
98
  <div className="bg-gray-100 row-span-3 col-span-1">
99
  <Panel
100
+ page={page}
101
+ nbPanels={nbPanels}
102
  panel={0}
103
  width={768}
104
  height={1024}
 
106
  </div>
107
  <div className="bg-slate-100">
108
  <Panel
109
+ page={page}
110
+ nbPanels={nbPanels}
111
  panel={1}
112
  width={1024}
113
  height={768}
 
115
  </div>
116
  <div className="bg-stone-100">
117
  <Panel
118
+ page={page}
119
+ nbPanels={nbPanels}
120
  panel={2}
121
  width={1024}
122
  height={768}
 
124
  </div>
125
  <div className="bg-zinc-100 row-span-1 col-span-1">
126
  <Panel
127
+ page={page}
128
+ nbPanels={nbPanels}
129
  panel={3}
130
  width={1024}
131
  height={768}
 
135
  )
136
  }
137
 
138
+ export function Layout3_todo({ page, nbPanels }: LayoutProps) {
139
  return (
140
  <Grid className="grid-cols-5 grid-rows-2">
141
  <div className="bg-zinc-100 col-span-3">
142
  <Panel
143
+ page={page}
144
+ nbPanels={nbPanels}
145
  panel={0}
146
  width={1024}
147
  height={768}
 
149
  </div>
150
  <div className="bg-zinc-100 col-span-2 row-span-2">
151
  <Panel
152
+ page={page}
153
+ nbPanels={nbPanels}
154
  panel={1}
155
  width={768}
156
  height={1024}
 
159
  <div className="col-span-3 grid grid-cols-2 gap-2">
160
  <div className="bg-stone-100">
161
  <Panel
162
+ page={page}
163
+ nbPanels={nbPanels}
164
  panel={2}
165
  width={768}
166
  height={758}
 
168
  </div>
169
  <div className="bg-slate-100">
170
  <Panel
171
+ page={page}
172
+ nbPanels={nbPanels}
173
  panel={3}
174
  width={768}
175
  height={758}
 
180
  )
181
  }
182
 
183
+ export function Layout4_todo({ page, nbPanels }: LayoutProps) {
184
  return (
185
  <Grid className="grid-cols-2 grid-rows-3">
186
  <div className="bg-slate-100 row-span-2">
187
  <Panel
188
+ page={page}
189
+ nbPanels={nbPanels}
190
  panel={0}
191
  width={768}
192
  height={1024}
 
194
  </div>
195
  <div className="bg-gray-100 row-span-1 col-span-1">
196
  <Panel
197
+ page={page}
198
+ nbPanels={nbPanels}
199
  panel={1}
200
  width={1024}
201
  height={768}
 
203
  </div>
204
  <div className="bg-zinc-100 row-span-2">
205
  <Panel
206
+ page={page}
207
+ nbPanels={nbPanels}
208
  panel={2}
209
  width={1024}
210
  height={768}
 
212
  </div>
213
  <div className="bg-stone-100">
214
  <Panel
215
+ page={page}
216
+ nbPanels={nbPanels}
217
  panel={3}
218
  width={768}
219
  height={1024}
 
224
  }
225
 
226
 
227
+ export function Layout2({ page, nbPanels }: LayoutProps) {
228
  return (
229
  <Grid className="grid-cols-3 grid-rows-2">
230
  <div className="bg-zinc-100 col-span-1 row-span-1">
231
  <Panel
232
+ page={page}
233
+ nbPanels={nbPanels}
234
  panel={0}
235
  width={768}
236
  height={1024}
 
238
  </div>
239
  <div className="bg-zinc-100 col-span-1 row-span-1">
240
  <Panel
241
+ page={page}
242
+ nbPanels={nbPanels}
243
  panel={1}
244
  width={768}
245
  height={1024}
 
247
  </div>
248
  <div className="bg-stone-100 row-span-2 col-span-1">
249
  <Panel
250
+ page={page}
251
+ nbPanels={nbPanels}
252
  panel={2}
253
  width={512}
254
  height={1024}
 
256
  </div>
257
  <div className="bg-slate-100 row-span-1 col-span-2">
258
  <Panel
259
+ page={page}
260
+ nbPanels={nbPanels}
261
  panel={3}
262
  width={1024}
263
  height={768}
 
267
  )
268
  }
269
 
270
+ export function Layout3({ page, nbPanels }: LayoutProps) {
271
  return (
272
  <Grid className="grid-cols-3 grid-rows-2">
273
  <div className="bg-zinc-100 col-span-2 row-span-1">
274
  <Panel
275
+ page={page}
276
+ nbPanels={nbPanels}
277
  panel={0}
278
  width={1024}
279
  height={768}
 
281
  </div>
282
  <div className="bg-zinc-100 col-span-1 row-span-1">
283
  <Panel
284
+ page={page}
285
+ nbPanels={nbPanels}
286
  panel={1}
287
  width={768}
288
  height={1024}
 
290
  </div>
291
  <div className="bg-stone-100 row-span-1 col-span-1">
292
  <Panel
293
+ page={page}
294
+ nbPanels={nbPanels}
295
  panel={2}
296
  width={768}
297
  height={1024}
 
299
  </div>
300
  <div className="bg-slate-100 row-span-1 col-span-2">
301
  <Panel
302
+ page={page}
303
+ nbPanels={nbPanels}
304
  panel={3}
305
  width={1024}
306
  height={768}
 
311
  }
312
 
313
  // squares + vertical
314
+ export function Layout4({ page, nbPanels }: LayoutProps) {
315
  return (
316
  <Grid className="grid-cols-8 grid-rows-8">
317
  <div className="bg-zinc-100 col-start-1 col-end-7 row-start-1 row-end-3">
318
  <Panel
319
+ page={page}
320
+ nbPanels={nbPanels}
321
  panel={0}
322
  width={512}
323
  height={1024}
 
325
  </div>
326
  <div className="bg-zinc-100 col-start-3 col-end-9 row-start-3 row-end-4">
327
  <Panel
328
+ page={page}
329
+ nbPanels={nbPanels}
330
  panel={1}
331
  width={1024}
332
  height={768}
 
334
  </div>
335
  <div className="bg-stone-100 col-start-2 col-end-8 row-start-4 row-end-6">
336
  <Panel
337
+ page={page}
338
+ nbPanels={nbPanels}
339
  panel={2}
340
  width={768}
341
  height={1024}
 
343
  </div>
344
  <div className="bg-slate-100 col-start-1 col-end-9 row-start-6 row-end-8">
345
  <Panel
346
+ page={page}
347
+ nbPanels={nbPanels}
348
  panel={3}
349
  width={1024}
350
  height={512}
 
355
  }
356
 
357
  // squares + horizontal
358
+ export function Layout5({ page, nbPanels }: LayoutProps) {
359
  return (
360
  <Grid className="grid-cols-4 grid-rows-4">
361
  <div className="bg-zinc-100">
362
  <Panel
363
+ page={page}
364
+ nbPanels={nbPanels}
365
  panel={0}
366
  width={1024}
367
  height={1024}
 
369
  </div>
370
  <div className="bg-zinc-100">
371
  <Panel
372
+ page={page}
373
+ nbPanels={nbPanels}
374
  panel={1}
375
  width={1024}
376
  height={1024}
 
378
  </div>
379
  <div className="bg-stone-100">
380
  <Panel
381
+ page={page}
382
+ nbPanels={nbPanels}
383
  panel={2}
384
  width={1024}
385
  height={1024}
 
387
  </div>
388
  <div className="bg-slate-100">
389
  <Panel
390
+ page={page}
391
+ nbPanels={nbPanels}
392
  panel={3}
393
  width={1024}
394
  height={1024}
 
426
  // Layout4: "aspect-[1/3]",
427
  }
428
 
429
+ export const allLayoutsNbPanels = {
430
+ // TODO: this is gonna be tricky to implement, but this should be unique / dynamic
431
+ Layout0: NB_PANELS_PER_PAGE,
432
+ Layout1: NB_PANELS_PER_PAGE,
433
+ Layout2: NB_PANELS_PER_PAGE,
434
+ Layout3: NB_PANELS_PER_PAGE,
435
+ // Layout4: NB_PANELS_PER_PAGE
436
+ }
437
+
438
  export type LayoutName = keyof typeof allLayouts
439
 
440
  export const defaultLayout: LayoutName = "Layout1"
 
450
  export function getRandomLayoutNames(): LayoutName[] {
451
  return nonRandomLayouts.sort(() => Math.random() - 0.5) as LayoutName[]
452
  }
 
src/app/layouts/new_layouts.tsx DELETED
@@ -1,273 +0,0 @@
1
- "use client"
2
-
3
- import { Panel } from "@/app/interface/panel"
4
- import { pick } from "@/lib/pick"
5
- import { Grid } from "@/app/interface/grid"
6
-
7
- export function Layout1() {
8
- return (
9
- <Grid className="grid-cols-2 grid-rows-4">
10
- <div className="bg-stone-100">
11
- <Panel
12
- panel={0}
13
- width={1024}
14
- height={768}
15
- />
16
- </div>
17
- <div className="bg-zinc-100 row-span-2">
18
- <Panel
19
- panel={1}
20
- width={512}
21
- height={1024}
22
- />
23
- </div>
24
- <div className="bg-gray-100 row-span-2 col-span-1">
25
- <Panel
26
- panel={2}
27
- width={512}
28
- height={1024}
29
- />
30
- </div>
31
- <div className="bg-slate-100">
32
- <Panel
33
- panel={3}
34
- width={1024}
35
- height={768}
36
- />
37
- </div>
38
- <div className="bg-slate-100 row-span-1 col-span-2">
39
- <Panel
40
- panel={4}
41
- width={1024}
42
- height={768}
43
- />
44
- </div>
45
- </Grid>
46
- )
47
- }
48
-
49
- export function Layout2() {
50
- return (
51
- <Grid className="grid-cols-2 grid-rows-3">
52
- <div className="bg-gray-100 row-span-2 col-span-1">
53
- <Panel
54
- panel={0}
55
- width={768}
56
- height={1024}
57
- />
58
- </div>
59
- <div className="bg-gray-100 row-span-1 col-span-1">
60
- <Panel
61
- panel={1}
62
- width={1024}
63
- height={1024}
64
- />
65
- </div>
66
- <div className="bg-slate-100">
67
- <Panel
68
- panel={2}
69
- width={1024}
70
- height={768}
71
- />
72
- </div>
73
- <div className="bg-stone-100">
74
- <Panel
75
- panel={3}
76
- width={1024}
77
- height={768}
78
- />
79
- </div>
80
- <div className="bg-zinc-100 row-span-1 col-span-1">
81
- <Panel
82
- panel={4}
83
- width={1024}
84
- height={768}
85
- />
86
- </div>
87
- </Grid>
88
- )
89
- }
90
-
91
- export function Layout3() {
92
- return (
93
- <Grid className="grid-cols-5 grid-rows-2">
94
- <div className="bg-zinc-100 col-span-3">
95
- <Panel
96
- panel={0}
97
- width={1024}
98
- height={1024}
99
- />
100
- </div>
101
- <div className="bg-gray-100 col-span-2 row-span-1">
102
- <Panel
103
- panel={1}
104
- width={512}
105
- height={1024}
106
- />
107
- </div>
108
- <div className="bg-gray-100 col-span-2 row-span-1">
109
- <Panel
110
- panel={2}
111
- width={512}
112
- height={1024}
113
- />
114
- </div>
115
- <div className="col-span-3 grid grid-cols-2 gap-2">
116
- <div className="bg-stone-100">
117
- <Panel
118
- panel={3}
119
- width={512}
120
- height={1024}
121
- />
122
- </div>
123
- <div className="bg-slate-100">
124
- <Panel
125
- panel={4}
126
- width={512}
127
- height={1024}
128
- />
129
- </div>
130
- </div>
131
- </Grid>
132
- )
133
- }
134
-
135
- export function Layout4() {
136
- return (
137
- <Grid className="grid-cols-2 grid-rows-3">
138
- <div className="bg-slate-100 row-span-2">
139
- <Panel
140
- panel={0}
141
- width={768}
142
- height={1024}
143
- />
144
- </div>
145
- <div className="bg-gray-100 row-span-1 col-span-1">
146
- <Panel
147
- panel={1}
148
- width={1024}
149
- height={768}
150
- />
151
- </div>
152
- <div className="bg-zinc-100 row-span-2">
153
- <Panel
154
- panel={2}
155
- width={1024}
156
- height={768}
157
- />
158
- </div>
159
- <div className="bg-stone-100">
160
- <Panel
161
- panel={3}
162
- width={768}
163
- height={1024}
164
- />
165
- </div>
166
- </Grid>
167
- )
168
- }
169
-
170
-
171
- export function Layout5() {
172
- return (
173
- <Grid className="grid-cols-3 grid-rows-3">
174
- <div className="bg-zinc-100 col-span-2 row-span-1">
175
- <Panel
176
- panel={0}
177
- width={1024}
178
- height={512}
179
- />
180
- </div>
181
- <div className="bg-zinc-100 col-span-1 row-span-1">
182
- <Panel
183
- panel={1}
184
- width={1024}
185
- height={768}
186
- />
187
- </div>
188
- <div className="bg-stone-100 row-span-1 col-span-1">
189
- <Panel
190
- panel={2}
191
- width={768}
192
- height={1024}
193
- />
194
- </div>
195
- <div className="bg-slate-100 row-span-1 col-span-2">
196
- <Panel
197
- panel={3}
198
- width={1024}
199
- height={768}
200
- />
201
- </div>
202
- <div className="bg-slate-100 row-span-1 col-span-3">
203
- <Panel
204
- panel={4}
205
- width={1024}
206
- height={1024}
207
- />
208
- </div>
209
- </Grid>
210
- )
211
- }
212
-
213
- export function Layout6() {
214
- return (
215
- <Grid className="grid-cols-3 grid-rows-3">
216
- <div className="bg-zinc-100 col-span-2 row-span-1">
217
- <Panel
218
- panel={0}
219
- width={1024}
220
- height={512}
221
- />
222
- </div>
223
- <div className="bg-zinc-100 col-span-1 row-span-1">
224
- <Panel
225
- panel={1}
226
- width={768}
227
- height={1024}
228
- />
229
- </div>
230
- <div className="bg-stone-100 row-span-1 col-span-1">
231
- <Panel
232
- panel={2}
233
- width={768}
234
- height={1024}
235
- />
236
- </div>
237
- <div className="bg-slate-100 row-span-2 col-span-2">
238
- <Panel
239
- panel={3}
240
- width={1024}
241
- height={1024}
242
- />
243
- </div>
244
- <div className="bg-slate-100 row-span-1 col-span-1">
245
- <Panel
246
- panel={3}
247
- width={768}
248
- height={1024}
249
- />
250
- </div>
251
- </Grid>
252
- )
253
- }
254
-
255
- // export const layouts = { Layout1, Layout2, Layout3, Layout4, Layout5, Layout6 }
256
- export const allLayouts = {
257
- // Layout1,
258
- // Layout2,
259
- // Layout3,
260
- // Layout4,
261
- Layout5,
262
- // Layout6
263
- }
264
-
265
- export type LayoutName = keyof typeof allLayouts
266
-
267
- export function getRandomLayoutName(): LayoutName {
268
- return pick(Object.keys(allLayouts) as LayoutName[]) as LayoutName
269
- }
270
-
271
- export function getRandomLayoutNames(): LayoutName[] {
272
- return Object.keys(allLayouts).sort(() => Math.random() - 0.5) as LayoutName[]
273
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app/main.tsx CHANGED
@@ -22,7 +22,8 @@ export default function Main() {
22
  const preset = useStore(state => state.preset)
23
  const prompt = useStore(state => state.prompt)
24
 
25
- const setLayouts = useStore(state => state.setLayouts)
 
26
 
27
  const setPanels = useStore(state => state.setPanels)
28
  const setCaptions = useStore(state => state.setCaptions)
@@ -42,12 +43,10 @@ export default function Main() {
42
  // I don't think we are going to need a rate limiter on the LLM part anymore
43
  const enableRateLimiter = false // `${process.env.NEXT_PUBLIC_ENABLE_RATE_LIMITER}` === "true"
44
 
45
- const nbPanels = 4
46
-
47
  let llmResponse: LLMResponse = []
48
 
49
  try {
50
- llmResponse = await getStory({ preset, prompt })
51
  console.log("LLM responded:", llmResponse)
52
 
53
  } catch (err) {
@@ -55,7 +54,7 @@ export default function Main() {
55
  console.log("we are now switching to a degraded mode, using 4 similar panels")
56
 
57
  llmResponse = []
58
- for (let p = 0; p < nbPanels; p++) {
59
  llmResponse.push({
60
  panel: p,
61
  instructions: `${prompt} ${".".repeat(p)}`,
@@ -78,7 +77,7 @@ export default function Main() {
78
  const newCaptions: string[] = []
79
  setWaitABitMore(true)
80
  console.log("Panel prompts for SDXL:")
81
- for (let p = 0; p < nbPanels; p++) {
82
  newCaptions.push(llmResponse[p]?.caption || "...")
83
  const newPanel = [panelPromptPrefix, llmResponse[p]?.instructions || ""].map(chunk => chunk).join(", ")
84
  newPanels.push(newPanel)
@@ -94,7 +93,7 @@ export default function Main() {
94
  }, enableRateLimiter ? 12000 : 0)
95
 
96
  })
97
- }, [prompt, preset?.label]) // important: we need to react to preset changes too
98
 
99
  return (
100
  <div>
@@ -114,18 +113,14 @@ export default function Main() {
114
  <div
115
  className={cn(
116
  `comic-page`,
117
- `flex flex-col md:flex-row md:space-x-16 md:items-center md:justify-start`,
118
  )}
119
  style={{
120
  width: `${zoomLevel}%`
121
  }}>
122
  <Page page={0} />
123
 
124
- {/*
125
- // we could support multiple pages here,
126
- // but let's disable it for now
127
  <Page page={1} />
128
- */}
129
  </div>
130
  </div>
131
  </div>
 
22
  const preset = useStore(state => state.preset)
23
  const prompt = useStore(state => state.prompt)
24
 
25
+ const nbPages = useStore(state => state.nbPages)
26
+ const nbTotalPanels = useStore(state => state.nbTotalPanels)
27
 
28
  const setPanels = useStore(state => state.setPanels)
29
  const setCaptions = useStore(state => state.setCaptions)
 
43
  // I don't think we are going to need a rate limiter on the LLM part anymore
44
  const enableRateLimiter = false // `${process.env.NEXT_PUBLIC_ENABLE_RATE_LIMITER}` === "true"
45
 
 
 
46
  let llmResponse: LLMResponse = []
47
 
48
  try {
49
+ llmResponse = await getStory({ preset, prompt, nbTotalPanels })
50
  console.log("LLM responded:", llmResponse)
51
 
52
  } catch (err) {
 
54
  console.log("we are now switching to a degraded mode, using 4 similar panels")
55
 
56
  llmResponse = []
57
+ for (let p = 0; p < nbTotalPanels; p++) {
58
  llmResponse.push({
59
  panel: p,
60
  instructions: `${prompt} ${".".repeat(p)}`,
 
77
  const newCaptions: string[] = []
78
  setWaitABitMore(true)
79
  console.log("Panel prompts for SDXL:")
80
+ for (let p = 0; p < nbTotalPanels; p++) {
81
  newCaptions.push(llmResponse[p]?.caption || "...")
82
  const newPanel = [panelPromptPrefix, llmResponse[p]?.instructions || ""].map(chunk => chunk).join(", ")
83
  newPanels.push(newPanel)
 
93
  }, enableRateLimiter ? 12000 : 0)
94
 
95
  })
96
+ }, [prompt, preset?.label, nbTotalPanels]) // important: we need to react to preset changes too
97
 
98
  return (
99
  <div>
 
113
  <div
114
  className={cn(
115
  `comic-page`,
116
+ `flex flex-col md:flex-row md:space-x-8 lg:space-x-12 xl:space-x-16 md:items-center md:justify-start print:space-x-4`,
117
  )}
118
  style={{
119
  width: `${zoomLevel}%`
120
  }}>
121
  <Page page={0} />
122
 
 
 
 
123
  <Page page={1} />
 
124
  </div>
125
  </div>
126
  </div>
src/app/ocr.tsx DELETED
@@ -1,3 +0,0 @@
1
- "use client"
2
-
3
- import { createWorker } from "tesseract.js"
 
 
 
 
src/app/queries/getStory.ts CHANGED
@@ -11,9 +11,11 @@ import { cleanJson } from "@/lib/cleanJson"
11
  export const getStory = async ({
12
  preset,
13
  prompt = "",
 
14
  }: {
15
  preset: Preset;
16
  prompt: string;
 
17
  }): Promise<LLMResponse> => {
18
  // throw new Error("Planned maintenance")
19
 
@@ -25,10 +27,10 @@ export const getStory = async ({
25
  role: "system",
26
  content: [
27
  `You are a comic book author specialized in ${preset.llmPrompt}`,
28
- `Please write detailed drawing instructions and a one-sentence short caption for the 4 panels of a new silent comic book page.`,
29
  `Give your response as a VALID JSON array like this: \`Array<{ panel: number; instructions: string; caption: string}>\`.`,
30
  // `Give your response as Markdown bullet points.`,
31
- `Be brief in your 4 instructions and captions, don't add your own comments. Be straight to the point, and never reply things like "Sure, I can.." etc. Reply using valid JSON.`
32
  ].filter(item => item).join("\n")
33
  },
34
  {
@@ -41,14 +43,14 @@ export const getStory = async ({
41
  let result = ""
42
 
43
  try {
44
- result = `${await predict(query) || ""}`.trim()
45
  if (!result.length) {
46
  throw new Error("empty result!")
47
  }
48
  } catch (err) {
49
  console.log(`prediction of the story failed, trying again..`)
50
  try {
51
- result = `${await predict(query+".") || ""}`.trim()
52
  if (!result.length) {
53
  throw new Error("empty result!")
54
  }
 
11
  export const getStory = async ({
12
  preset,
13
  prompt = "",
14
+ nbTotalPanels = 4,
15
  }: {
16
  preset: Preset;
17
  prompt: string;
18
+ nbTotalPanels: number;
19
  }): Promise<LLMResponse> => {
20
  // throw new Error("Planned maintenance")
21
 
 
27
  role: "system",
28
  content: [
29
  `You are a comic book author specialized in ${preset.llmPrompt}`,
30
+ `Please write detailed drawing instructions and a one-sentence short caption for the ${nbTotalPanels} panels of a new silent comic book page.`,
31
  `Give your response as a VALID JSON array like this: \`Array<{ panel: number; instructions: string; caption: string}>\`.`,
32
  // `Give your response as Markdown bullet points.`,
33
+ `Be brief in your ${nbTotalPanels} instructions and captions, don't add your own comments. Be straight to the point, and never reply things like "Sure, I can.." etc. Reply using valid JSON.`
34
  ].filter(item => item).join("\n")
35
  },
36
  {
 
43
  let result = ""
44
 
45
  try {
46
+ result = `${await predict(query, nbTotalPanels) || ""}`.trim()
47
  if (!result.length) {
48
  throw new Error("empty result!")
49
  }
50
  } catch (err) {
51
  console.log(`prediction of the story failed, trying again..`)
52
  try {
53
+ result = `${await predict(query+".", nbTotalPanels) || ""}`.trim()
54
  if (!result.length) {
55
  throw new Error("empty result!")
56
  }
src/app/queries/getStyle.ts DELETED
@@ -1,52 +0,0 @@
1
- import { createLlamaPrompt } from "@/lib/createLlamaPrompt"
2
-
3
- import { predict } from "./predict"
4
- import { Preset } from "../engine/presets"
5
-
6
- export const getStory = async ({
7
- preset,
8
- prompt = "",
9
- }: {
10
- preset: Preset;
11
- prompt: string;
12
- }) => {
13
-
14
- const query = createLlamaPrompt([
15
- {
16
- role: "system",
17
- content: [
18
- `You are a comic book author specialized in ${preset.llmPrompt}`,
19
- `You are going to be asked to write a comic book page, your mission is to answer a JSON array containing 4 items, to describe the page (one item per panel).`,
20
- `Each array item should be a comic book panel caption the describe the environment, era, characters, objects, textures, lighting.`,
21
- `Be brief in your caption don't add your own comments. Be straight to the point, and never reply things like "Sure, I can.." etc.`
22
- ].filter(item => item).join("\n")
23
- },
24
- {
25
- role: "user",
26
- content: `The story is: ${prompt}`,
27
- }
28
- ])
29
-
30
-
31
- let result = ""
32
- try {
33
- result = `${await predict(query) || ""}`.trim()
34
- if (!result.length) {
35
- throw new Error("empty result!")
36
- }
37
- } catch (err) {
38
- console.log(`prediction of the story failed, trying again..`)
39
- try {
40
- result = `${await predict(query+".") || ""}`.trim()
41
- if (!result.length) {
42
- throw new Error("empty result!")
43
- }
44
- } catch (err) {
45
- console.error(`prediction of the story failed again!`)
46
- throw new Error(`failed to generate the story ${err}`)
47
- }
48
- }
49
-
50
- const tmp = result // result.split("Caption:").pop() || result
51
- return tmp.replaceAll("\n", ", ")
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app/queries/mockLLMResponse.ts CHANGED
@@ -1,24 +1,43 @@
1
  import { LLMResponse } from "@/types"
2
 
3
- export const mockLLMResponse: LLMResponse = [
4
- {
5
- "panel": 1,
6
- "instructions": "Close-up of cat's face, looking straight at reader with a smirk on its face",
7
- "caption": "Feline mischief"
8
- },
9
- {
10
- "panel": 2,
11
- "instructions": "Medium shot of cat sniffing a glass of milk, with a surprised expression",
12
- "caption": "Uh oh, what's this?"
13
- },
14
- {
15
- "panel": 3,
16
- "instructions": "Wide shot of cat knocking over the glass of milk, with a crazed look in its eyes",
17
- "caption": "Cat-astrophe!"
18
- },
19
- {
20
- "panel": 4,
21
- "instructions": "Close-up of cat's face, looking satisfied with a milk moustache",
22
- "caption": "Mission accomplished"
23
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  ]
 
1
  import { LLMResponse } from "@/types"
2
 
3
+ export const mockLLMResponse: LLMResponse = [{
4
+ "panel": 1,
5
+ "instructions": "wide shot of detective walking towards a UFO crash site",
6
+ "caption": "Detective Jameson investigates a UFO crash in the desert"
7
+ },
8
+ {
9
+ "panel": 2,
10
+ "instructions": "close-up of detective's face, determined expression",
11
+ "caption": "He's been tracking this case for weeks"
12
+ },
13
+ {
14
+ "panel": 3,
15
+ "instructions": "medium shot of detective examining UFO debris",
16
+ "caption": "The evidence is scattered all over the desert"
17
+ },
18
+ {
19
+ "panel": 4,
20
+ "instructions": "close-up of strange symbol on UFO debris",
21
+ "caption": "But what does this symbol mean?"
22
+ },
23
+ {
24
+ "panel": 5,
25
+ "instructions": "wide shot of detective walking towards a strange rock formation",
26
+ "caption": "Jameson follows a trail that leads him deeper into the desert"
27
+ },
28
+ {
29
+ "panel": 6,
30
+ "instructions": "medium shot of detective discovering an alien body",
31
+ "caption": "He's not alone in the desert"
32
+ },
33
+ {
34
+ "panel": 7,
35
+ "instructions": "close-up of alien's face, eyes closed, peaceful expression",
36
+ "caption": "An alien life form, deceased"
37
+ },
38
+ {
39
+ "panel": 8,
40
+ "instructions": "wide shot of detective standing over the alien body, looking up at the sky",
41
+ "caption": "Jameson wonders, what other secrets lie beyond the stars?"
42
+ }
43
  ]
src/app/queries/predictWithHuggingFace.ts CHANGED
@@ -3,7 +3,7 @@
3
  import { HfInference, HfInferenceEndpoint } from "@huggingface/inference"
4
  import { LLMEngine } from "@/types"
5
 
6
- export async function predict(inputs: string): Promise<string> {
7
  const hf = new HfInference(process.env.AUTH_HF_API_TOKEN)
8
 
9
  const llmEngine = `${process.env.LLM_ENGINE || ""}` as LLMEngine
@@ -12,6 +12,10 @@ export async function predict(inputs: string): Promise<string> {
12
 
13
  let hfie: HfInferenceEndpoint = hf
14
 
 
 
 
 
15
  switch (llmEngine) {
16
  case "INFERENCE_ENDPOINT":
17
  if (inferenceEndpoint) {
@@ -49,9 +53,7 @@ export async function predict(inputs: string): Promise<string> {
49
  inputs,
50
  parameters: {
51
  do_sample: true,
52
- // we don't require a lot of token for our task
53
- // but to be safe, let's count ~110 tokens per panel
54
- max_new_tokens: 450, // 1150,
55
  return_full_text: false,
56
  }
57
  })) {
 
3
  import { HfInference, HfInferenceEndpoint } from "@huggingface/inference"
4
  import { LLMEngine } from "@/types"
5
 
6
+ export async function predict(inputs: string, nbPanels: number): Promise<string> {
7
  const hf = new HfInference(process.env.AUTH_HF_API_TOKEN)
8
 
9
  const llmEngine = `${process.env.LLM_ENGINE || ""}` as LLMEngine
 
12
 
13
  let hfie: HfInferenceEndpoint = hf
14
 
15
+ // we don't require a lot of token for our task
16
+ // but to be safe, let's count ~110 tokens per panel
17
+ const nbMaxNewTokens = nbPanels * 110
18
+
19
  switch (llmEngine) {
20
  case "INFERENCE_ENDPOINT":
21
  if (inferenceEndpoint) {
 
53
  inputs,
54
  parameters: {
55
  do_sample: true,
56
+ max_new_tokens: nbMaxNewTokens,
 
 
57
  return_full_text: false,
58
  }
59
  })) {
src/app/queries/predictWithOpenAI.ts CHANGED
@@ -3,7 +3,7 @@
3
  import type { ChatCompletionMessage } from "openai/resources/chat"
4
  import OpenAI from "openai"
5
 
6
- export async function predict(inputs: string): Promise<string> {
7
  const openaiApiKey = `${process.env.AUTH_OPENAI_API_KEY || ""}`
8
  const openaiApiBaseUrl = `${process.env.LLM_OPENAI_API_BASE_URL || "https://api.openai.com/v1"}`
9
  const openaiApiModel = `${process.env.LLM_OPENAI_API_MODEL || "gpt-3.5-turbo"}`
@@ -22,7 +22,8 @@ export async function predict(inputs: string): Promise<string> {
22
  messages: messages,
23
  stream: false,
24
  model: openaiApiModel,
25
- temperature: 0.8
 
26
  })
27
 
28
  return res.choices[0].message.content || ""
 
3
  import type { ChatCompletionMessage } from "openai/resources/chat"
4
  import OpenAI from "openai"
5
 
6
+ export async function predict(inputs: string, nbPanels: number): Promise<string> {
7
  const openaiApiKey = `${process.env.AUTH_OPENAI_API_KEY || ""}`
8
  const openaiApiBaseUrl = `${process.env.LLM_OPENAI_API_BASE_URL || "https://api.openai.com/v1"}`
9
  const openaiApiModel = `${process.env.LLM_OPENAI_API_MODEL || "gpt-3.5-turbo"}`
 
22
  messages: messages,
23
  stream: false,
24
  model: openaiApiModel,
25
+ temperature: 0.8,
26
+ // TODO: use the nbPanels to define a max token limit
27
  })
28
 
29
  return res.choices[0].message.content || ""
src/app/store/index.ts CHANGED
@@ -1,18 +1,20 @@
1
  "use client"
2
 
3
  import { create } from "zustand"
 
4
 
5
  import { FontName } from "@/lib/fonts"
6
  import { Preset, PresetName, defaultPreset, getPreset, getRandomPreset } from "@/app/engine/presets"
7
- import { LayoutName, defaultLayout, getRandomLayoutName, getRandomLayoutNames } from "../layouts"
8
- import html2canvas from "html2canvas"
9
  import { RenderedScene } from "@/types"
 
 
10
 
11
  export const useStore = create<{
12
  prompt: string
13
  font: FontName
14
  preset: Preset
15
- nbFrames: number
 
16
  panels: string[]
17
  captions: string[]
18
  upscaleQueue: Record<string, RenderedScene>
@@ -49,7 +51,11 @@ export const useStore = create<{
49
  prompt: "",
50
  font: "actionman",
51
  preset: getPreset(defaultPreset),
52
- nbFrames: 1,
 
 
 
 
53
  panels: [],
54
  captions: [],
55
  upscaleQueue: {} as Record<string, RenderedScene>,
@@ -109,13 +115,6 @@ export const useStore = create<{
109
  preset,
110
  })
111
  },
112
- setNbFrames: (nbFrames: number) => {
113
- const existingNbFrames = get().nbFrames
114
- if (nbFrames === existingNbFrames) { return }
115
- set({
116
- nbFrames,
117
- })
118
- },
119
  setPanels: (panels: string[]) => set({ panels }),
120
  setCaptions: (captions: string[]) => {
121
  set({
@@ -128,13 +127,27 @@ export const useStore = create<{
128
  })
129
  },
130
  setLayout: (layoutName: LayoutName) => {
 
 
 
131
  const layout = layoutName === "random"
132
- ? getRandomLayoutName()
133
- : layoutName
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  set({
136
  layout,
137
- layouts: [layout, layout]
138
  })
139
  },
140
  setLayouts: (layouts: LayoutName[]) => set({ layouts }),
@@ -186,9 +199,24 @@ export const useStore = create<{
186
  }
187
  },
188
  generate: (prompt: string, presetName: PresetName, layoutName: LayoutName) => {
 
 
 
189
  const layout = layoutName === "random"
190
- ? getRandomLayoutName()
191
- : layoutName
 
 
 
 
 
 
 
 
 
 
 
 
192
  set({
193
  prompt,
194
  panels: [],
@@ -197,7 +225,7 @@ export const useStore = create<{
197
  ? getRandomPreset()
198
  : getPreset(presetName),
199
  layout,
200
- layouts: [layout, layout],
201
  })
202
  }
203
  }))
 
1
  "use client"
2
 
3
  import { create } from "zustand"
4
+ import html2canvas from "html2canvas"
5
 
6
  import { FontName } from "@/lib/fonts"
7
  import { Preset, PresetName, defaultPreset, getPreset, getRandomPreset } from "@/app/engine/presets"
 
 
8
  import { RenderedScene } from "@/types"
9
+ import { LayoutName, defaultLayout, getRandomLayoutName } from "../layouts"
10
+ import { MAX_NB_PAGES, NB_PANELS_PER_PAGE } from "@/config"
11
 
12
  export const useStore = create<{
13
  prompt: string
14
  font: FontName
15
  preset: Preset
16
+ nbPages: number
17
+ nbTotalPanels: number
18
  panels: string[]
19
  captions: string[]
20
  upscaleQueue: Record<string, RenderedScene>
 
51
  prompt: "",
52
  font: "actionman",
53
  preset: getPreset(defaultPreset),
54
+ nbPages: MAX_NB_PAGES,
55
+
56
+ // TODO: make this dynamic!
57
+ nbTotalPanels: NB_PANELS_PER_PAGE * MAX_NB_PAGES,
58
+
59
  panels: [],
60
  captions: [],
61
  upscaleQueue: {} as Record<string, RenderedScene>,
 
115
  preset,
116
  })
117
  },
 
 
 
 
 
 
 
118
  setPanels: (panels: string[]) => set({ panels }),
119
  setCaptions: (captions: string[]) => {
120
  set({
 
127
  })
128
  },
129
  setLayout: (layoutName: LayoutName) => {
130
+
131
+ const { nbPages } = get()
132
+
133
  const layout = layoutName === "random"
134
+ ? getRandomLayoutName()
135
+ : layoutName
136
+
137
+ const layouts: LayoutName[] = []
138
+ for (let i = 0; i < nbPages; i++) {
139
+ layouts.push(
140
+ layoutName === "random"
141
+ ? getRandomLayoutName()
142
+ : layoutName
143
+ )
144
+
145
+ // TODO: update the number of total panels here!
146
+ }
147
 
148
  set({
149
  layout,
150
+ layouts,
151
  })
152
  },
153
  setLayouts: (layouts: LayoutName[]) => set({ layouts }),
 
199
  }
200
  },
201
  generate: (prompt: string, presetName: PresetName, layoutName: LayoutName) => {
202
+
203
+ const { nbPages } = get()
204
+
205
  const layout = layoutName === "random"
206
+ ? getRandomLayoutName()
207
+ : layoutName
208
+
209
+ const layouts: LayoutName[] = []
210
+ for (let i = 0; i < nbPages; i++) {
211
+ layouts.push(
212
+ layoutName === "random"
213
+ ? getRandomLayoutName()
214
+ : layoutName
215
+ )
216
+
217
+ // TODO: update the number of total panels here!
218
+ }
219
+
220
  set({
221
  prompt,
222
  panels: [],
 
225
  ? getRandomPreset()
226
  : getPreset(presetName),
227
  layout,
228
+ layouts,
229
  })
230
  }
231
  }))
src/config.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { getValidNumber } from "./lib/getValidNumber"
2
+
3
+ export const MAX_NB_PAGES = getValidNumber(process.env.NEXT_PUBLIC_MAX_NB_PAGES, 1, 2, 1)
4
+
5
+ // TODO: this one should be dynamic and depend upon the page layout type
6
+ export const NB_PANELS_PER_PAGE = 4
src/lib/dirtyLLMJsonParser.ts CHANGED
@@ -1,5 +1,6 @@
1
  import { LLMResponse } from "@/types"
2
  import { cleanJson } from "./cleanJson"
 
3
 
4
  export function dirtyLLMJsonParser(input: string): LLMResponse {
5
 
@@ -9,7 +10,7 @@ export function dirtyLLMJsonParser(input: string): LLMResponse {
9
  // we only keep what's after the first [
10
  let jsonOrNot = cleanJson(input)
11
 
12
- const jsonData = JSON.parse(jsonOrNot) as LLMResponse
13
 
14
  const results = jsonData.map((item, i) => {
15
  let panel = i
 
1
  import { LLMResponse } from "@/types"
2
  import { cleanJson } from "./cleanJson"
3
+ import { parseBadJSON } from "./parseBadJSON"
4
 
5
  export function dirtyLLMJsonParser(input: string): LLMResponse {
6
 
 
10
  // we only keep what's after the first [
11
  let jsonOrNot = cleanJson(input)
12
 
13
+ const jsonData = parseBadJSON(jsonOrNot) as LLMResponse
14
 
15
  const results = jsonData.map((item, i) => {
16
  let panel = i
src/lib/dirtyLLMResponseCleaner.ts CHANGED
@@ -18,11 +18,19 @@ export function dirtyLLMResponseCleaner(input: string) {
18
  .replaceAll("[2]", "")
19
  .replaceAll("[3]", "")
20
  .replaceAll("[4]", "")
 
 
 
 
21
  .replaceAll("[panel 0]", "")
22
  .replaceAll("[panel 1]", "")
23
  .replaceAll("[panel 2]", "")
24
  .replaceAll("[panel 3]", "")
25
  .replaceAll("[panel 4]", "")
 
 
 
 
26
  )
27
 
28
  // repair missing end of JSON array
 
18
  .replaceAll("[2]", "")
19
  .replaceAll("[3]", "")
20
  .replaceAll("[4]", "")
21
+ .replaceAll("[5]", "")
22
+ .replaceAll("[6]", "")
23
+ .replaceAll("[7]", "")
24
+ .replaceAll("[8]", "")
25
  .replaceAll("[panel 0]", "")
26
  .replaceAll("[panel 1]", "")
27
  .replaceAll("[panel 2]", "")
28
  .replaceAll("[panel 3]", "")
29
  .replaceAll("[panel 4]", "")
30
+ .replaceAll("[panel 5]", "")
31
+ .replaceAll("[panel 6]", "")
32
+ .replaceAll("[panel 7]", "")
33
+ .replaceAll("[panel 8]", "")
34
  )
35
 
36
  // repair missing end of JSON array
src/lib/getValidNumber.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ export const getValidNumber = (something: any, minValue: number, maxValue: number, defaultValue: number) => {
2
+ const strValue = `${something || defaultValue}`
3
+ const numValue = Number(strValue)
4
+ const isValid = !isNaN(numValue) && isFinite(numValue)
5
+ if (!isValid) {
6
+ return defaultValue
7
+ }
8
+ return Math.max(minValue, Math.min(maxValue, numValue))
9
+
10
+ }
src/lib/parseBadJSON.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { LLMResponse } from "@/types"
2
+
3
+ export function parseBadJSON(jsonLikeString: string): LLMResponse {
4
+
5
+ try {
6
+ return JSON.parse(jsonLikeString) as LLMResponse
7
+ } catch (err) {
8
+ var regex = /\{\s*"panel":\s*(\d+),\s*"instructions"\s*:\s*"([^"]+)",\s*"caption":\s*"([^"]*)"\s*\}/gs;
9
+
10
+ let results = [];
11
+ let match;
12
+
13
+ while ((match = regex.exec(jsonLikeString)) !== null) {
14
+ let json = {
15
+ panel: Number(match[1]),
16
+ instructions: match[2],
17
+ caption: match[3]
18
+ };
19
+ results.push(json);
20
+ }
21
+
22
+ return results as LLMResponse
23
+ }
24
+ }
src/lib/replaceTextInSpeechBubbles.ts DELETED
@@ -1,98 +0,0 @@
1
- "use client"
2
-
3
- import { createWorker } from "tesseract.js"
4
- import { loadImageToCanvas } from "./loadImageToCanvas";
5
-
6
- export async function replaceTextInSpeechBubbles(image: string, customText: string) {
7
- console.log('creating OCR worker to find bubbles inside', image);
8
-
9
- const worker = await createWorker({
10
- logger: (info) => {
11
- console.log(info)
12
- },
13
- });
14
-
15
- const canvas = await loadImageToCanvas(image)
16
-
17
- const ctx = canvas.getContext('2d')!;
18
-
19
- try {
20
- await worker.load();
21
- await worker.loadLanguage('eng');
22
- await worker.initialize('eng');
23
-
24
- const { data } = await worker.recognize(canvas);
25
- const lines = data.lines || [];
26
-
27
- // Draw the lines on the image
28
- ctx.fillStyle = "white";
29
-
30
- lines.forEach((line) => {
31
- ctx.fillRect(line.bbox.x0, line.bbox.y0, line.bbox.x1 - line.bbox.x0, line.bbox.y1 - line.bbox.y0);
32
-
33
- const bubbleWidth = line.bbox.x1 - line.bbox.x0;
34
- const bubbleHeight = line.bbox.y1 - line.bbox.y0;
35
- let fontSize = 18;
36
- ctx.font = `${fontSize}px Arial`;
37
-
38
- /*
39
- while (
40
- ctx.measureText(customText).width > bubbleWidth || fontSize * 1.2 // line height
41
- > bubbleHeight) {
42
- fontSize -= 1;
43
- ctx.font = `${fontSize}px Arial`;
44
- }
45
-
46
- const lines = wrapText(ctx, customText, line.bbox.x0, line.bbox.y0, bubbleWidth, fontSize);
47
-
48
- ctx.fillStyle = "black";
49
- lines.forEach((text, i) => {
50
- ctx.fillText(text, line.bbox.x0, line.bbox.y0 + (i * fontSize * 1.2));
51
- });
52
- */
53
- })
54
-
55
- await worker.terminate();
56
-
57
- // Convert the Canvas to image data
58
- const imgAsDataURL = canvas.toDataURL('image/png');
59
-
60
- if (typeof window !== "undefined") {
61
- const foo = (window as any)
62
- if (!foo.debugJujul) {
63
- foo.debugJujul = []
64
- }
65
- foo.debugJujul.push({
66
- lines
67
- })
68
- }
69
- console.log("lines:", lines)
70
-
71
- return imgAsDataURL;
72
-
73
- } catch (err) {
74
- console.error(err);
75
- }
76
- return "";
77
- }
78
-
79
- function wrapText(context: CanvasRenderingContext2D, text: string, x: number, y: number, maxWidth: number, lineHeight: number) {
80
- const words = text.split(' ');
81
- let line = '';
82
- const lines = [];
83
-
84
- for(let n = 0; n < words.length; n++) {
85
- let testLine = line + words[n] + ' ';
86
- let metrics = context.measureText(testLine);
87
- let testWidth = metrics.width;
88
- if (testWidth > maxWidth && n > 0) {
89
- lines.push(line);
90
- line = words[n] + ' ';
91
- }
92
- else {
93
- line = testLine;
94
- }
95
- }
96
- lines.push(line);
97
- return lines;
98
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/types.ts CHANGED
@@ -127,4 +127,9 @@ export type GetAppPostResponse = {
127
  success?: boolean
128
  error?: string
129
  post: Post
130
- }
 
 
 
 
 
 
127
  success?: boolean
128
  error?: string
129
  post: Post
130
+ }
131
+
132
+ export type LayoutProps = {
133
+ page: number
134
+ nbPanels: number
135
+ }