video upload works
This commit is contained in:
parent
258dd43e35
commit
fe247d7eb1
62
bun.lock
62
bun.lock
|
|
@ -85,6 +85,7 @@
|
|||
"name": "@workshop/spike",
|
||||
"dependencies": {
|
||||
"@openai/agents": "^0.0.10",
|
||||
"@workshop/shared": "workspace:*",
|
||||
"discord.js": "^14.19.3",
|
||||
"luxon": "^3.6.1",
|
||||
"zod": "3.25.67",
|
||||
|
|
@ -139,10 +140,13 @@
|
|||
"dependencies": {
|
||||
"@google/genai": "^1.9.0",
|
||||
"@openai/agents": "^0.0.11",
|
||||
"@techstark/opencv-js": "^4.11.0-release.1",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@workshop/nano-remix": "workspace:*",
|
||||
"@workshop/shared": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"opencv4nodejs": "^5.6.0",
|
||||
"luxon": "^3.7.1",
|
||||
"pngjs": "^7.0.0",
|
||||
"zod": "3.25.67",
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -212,12 +216,16 @@
|
|||
|
||||
"@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
|
||||
|
||||
"@techstark/opencv-js": ["@techstark/opencv-js@4.11.0-release.1", "", {}, "sha512-d5h8cMiSbbnme5+I1ta4++EJ3mkca1zkVNh0A4+5ASJYOmO5OhVPRX3oPnNzs9I3KyGVX7QeFU8gVoI7I0w8RQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="],
|
||||
|
||||
"@types/node": ["@types/node@24.0.13", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ=="],
|
||||
|
||||
"@types/pngjs": ["@types/pngjs@6.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||
|
|
@ -250,16 +258,10 @@
|
|||
|
||||
"amqplib": ["amqplib@0.5.2", "", { "dependencies": { "bitsyntax": "~0.0.4", "bluebird": "^3.4.6", "buffer-more-ints": "0.0.2", "readable-stream": "1.x >=1.1.9", "safe-buffer": "^5.0.1" } }, "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
|
||||
"app-root-path": ["app-root-path@2.1.0", "", {}, "sha512-z5BqVjscbjmJBybKlICogJR2jCr2q/Ixu7Pvui5D4y97i7FLsJlvEG9XOR/KJRlkxxZz7UaaS2TMwQh1dRJ2dA=="],
|
||||
|
||||
"aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="],
|
||||
|
||||
"are-we-there-yet": ["are-we-there-yet@1.1.7", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g=="],
|
||||
|
||||
"array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
|
||||
|
||||
"array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
|
||||
|
|
@ -312,8 +314,6 @@
|
|||
|
||||
"chalk": ["chalk@2.4.1", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ=="],
|
||||
|
||||
"code-point-at": ["code-point-at@1.1.0", "", {}, "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA=="],
|
||||
|
||||
"color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
|
||||
"color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||
|
|
@ -326,8 +326,6 @@
|
|||
|
||||
"compression": ["compression@1.7.3", "", { "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", "compressible": "~2.0.14", "debug": "2.6.9", "on-headers": "~1.0.1", "safe-buffer": "5.1.2", "vary": "~1.1.2" } }, "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg=="],
|
||||
|
||||
"console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="],
|
||||
|
||||
"content-disposition": ["content-disposition@0.5.2", "", {}, "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA=="],
|
||||
|
||||
"content-type": ["content-type@1.0.4", "", {}, "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="],
|
||||
|
|
@ -364,8 +362,6 @@
|
|||
|
||||
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
|
||||
|
||||
"delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="],
|
||||
|
||||
"depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="],
|
||||
|
||||
"destroy": ["destroy@1.0.4", "", {}, "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg=="],
|
||||
|
|
@ -440,8 +436,6 @@
|
|||
|
||||
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
|
||||
|
||||
"gauge": ["gauge@2.7.4", "", { "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.0", "object-assign": "^4.1.0", "signal-exit": "^3.0.0", "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" } }, "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg=="],
|
||||
|
||||
"gaxios": ["gaxios@6.7.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", "uuid": "^9.0.1" } }, "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ=="],
|
||||
|
||||
"gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="],
|
||||
|
|
@ -476,8 +470,6 @@
|
|||
|
||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
||||
|
||||
"has-unicode": ["has-unicode@2.0.1", "", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="],
|
||||
|
||||
"hase": ["hase@2.0.0", "", { "dependencies": { "@babel/runtime": "7.1.2", "amqplib": "0.5.2" } }, "sha512-L83pBR/oZvQQNjv4kw9aUpTqBxERPiY7B42jsmkt1VDeUaRVhYkEIKzkCqrppjtxHe2EZqzZJzuhMXsWsxYIsw=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
|
@ -512,8 +504,6 @@
|
|||
|
||||
"is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@1.0.0", "", { "dependencies": { "number-is-nan": "^1.0.0" } }, "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw=="],
|
||||
|
||||
"is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
|
||||
|
||||
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
|
||||
|
|
@ -612,12 +602,8 @@
|
|||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nan": ["nan@2.23.0", "", {}, "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ=="],
|
||||
|
||||
"nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
|
||||
|
||||
"native-node-utils": ["native-node-utils@0.2.7", "", { "dependencies": { "nan": "^2.13.2" } }, "sha512-61v0G3uVxWlXHppSZGwZi+ZEIgGUKI8QvEkEJLb1GVePI7P8SBe+G747z+QMXSt4TxfgbVZP0DyobbRKYVIjdw=="],
|
||||
|
||||
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||
|
||||
"nocache": ["nocache@2.0.0", "", {}, "sha512-YdKcy2x0dDwOh+8BEuHvA+mnOKAhmMQDgKBOCUGaLpewdmsRYguYZSom3yA+/OrE61O/q+NMQANnun65xpI1Hw=="],
|
||||
|
|
@ -628,10 +614,6 @@
|
|||
|
||||
"node-statsd": ["node-statsd@0.1.1", "", {}, "sha512-QDf6R8VXF56QVe1boek8an/Rb3rSNaxoFWb7Elpsv2m1+Noua1yy0F1FpKpK5VluF8oymWM4w764A4KsYL4pDg=="],
|
||||
|
||||
"npmlog": ["npmlog@4.1.2", "", { "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", "gauge": "~2.7.3", "set-blocking": "~2.0.0" } }, "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg=="],
|
||||
|
||||
"number-is-nan": ["number-is-nan@1.0.1", "", {}, "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
|
@ -650,10 +632,6 @@
|
|||
|
||||
"openai": ["openai@5.9.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-cmLC0pfqLLhBGxE4aZPyRPjydgYCncppV2ClQkKmW79hNjCvmzkfhz8rN5/YVDmjVQlFV+UsF1JIuNjNgeagyQ=="],
|
||||
|
||||
"opencv-build": ["opencv-build@0.1.9", "", { "dependencies": { "npmlog": "^4.1.2" } }, "sha512-tgT/bnJAcYROen9yaPynfK98IMl62mPSgMLmTx41911m5bczlq21xtE5r+UWLB/xEo/0hKk6tl5zHyxV/JS5Rg=="],
|
||||
|
||||
"opencv4nodejs": ["opencv4nodejs@5.6.0", "", { "dependencies": { "nan": "^2.14.0", "native-node-utils": "^0.2.7", "npmlog": "^4.1.2", "opencv-build": "^0.1.9" }, "optionalDependencies": { "@types/node": ">6" } }, "sha512-JvcT1hb2JUCdntcVABgD9Gprr+gkXBe+jhHKvrr0Ug51y087K4ybm0vHBQVzI2ei1aJxEc9tNknPL9rpyx5Xuw=="],
|
||||
|
||||
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
|
||||
|
||||
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||
|
|
@ -666,9 +644,9 @@
|
|||
|
||||
"pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="],
|
||||
|
||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||
"pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
|
||||
|
||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||
|
||||
"processenv": ["processenv@1.1.0", "", { "dependencies": { "babel-runtime": "6.26.0" } }, "sha512-SymqIsn8GjEUy8nG7HiyEjgbfk1xFosRIakUX1NHLpriq3vVpKniGrr9RdMWCaGYWByIovbRt2f/WvmP/IOApQ=="],
|
||||
|
||||
|
|
@ -712,8 +690,6 @@
|
|||
|
||||
"serve-static": ["serve-static@1.13.2", "", { "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.2", "send": "0.16.2" } }, "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw=="],
|
||||
|
||||
"set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
|
||||
|
||||
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
|
||||
|
||||
"set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
|
||||
|
|
@ -736,8 +712,6 @@
|
|||
|
||||
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"split2": ["split2@3.0.0", "", { "dependencies": { "readable-stream": "^3.0.0" } }, "sha512-Cp7G+nUfKJyHCrAI8kze3Q00PFGEG1pMgrAlTFlDbn+GW24evSZHJuMl+iUJx1w/NTRDeBiTgvwnf6YOt94FMw=="],
|
||||
|
||||
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
|
||||
|
|
@ -748,8 +722,6 @@
|
|||
|
||||
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
||||
|
||||
"string-width": ["string-width@1.0.2", "", { "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw=="],
|
||||
|
||||
"string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="],
|
||||
|
||||
"string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="],
|
||||
|
|
@ -760,8 +732,6 @@
|
|||
|
||||
"stringify-object": ["stringify-object@3.3.0", "", { "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", "is-regexp": "^1.0.0" } }, "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="],
|
||||
|
||||
"style-mod": ["style-mod@4.1.2", "", {}, "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="],
|
||||
|
||||
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
|
|
@ -836,8 +806,6 @@
|
|||
|
||||
"which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="],
|
||||
|
||||
"wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"ws": ["ws@6.2.0", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-deZYUNlt2O4buFCa3t5bKLf8A7FPP/TVjwOeVNpw818Ma5nk4MLXls2eoEGS39o8119QIYxTrTDoPQ5B/gTD6w=="],
|
||||
|
|
@ -874,8 +842,6 @@
|
|||
|
||||
"amqplib/readable-stream": ["readable-stream@1.1.14", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ=="],
|
||||
|
||||
"are-we-there-yet/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"babel-runtime/regenerator-runtime": ["regenerator-runtime@0.11.1", "", {}, "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="],
|
||||
|
||||
"body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
|
@ -968,12 +934,6 @@
|
|||
|
||||
"amqplib/readable-stream/string_decoder": ["string_decoder@0.10.31", "", {}, "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="],
|
||||
|
||||
"are-we-there-yet/readable-stream/inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"are-we-there-yet/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"are-we-there-yet/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
|
|
|||
|
|
@ -59,10 +59,18 @@ export const submitAction = async (data: any, options: SubmitActionOptions = {})
|
|||
|
||||
actionFns?.setStatus("submitting")
|
||||
|
||||
const body = new FormData()
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
body.append(key, String(value))
|
||||
})
|
||||
let body
|
||||
// if data is a FormData, we can use it directly
|
||||
if (data instanceof FormData) {
|
||||
body = data
|
||||
} else {
|
||||
// Otherwise, convert to FormData
|
||||
const formData = new FormData()
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
formData.append(key, String(value))
|
||||
})
|
||||
body = formData
|
||||
}
|
||||
|
||||
const res = await fetch(url, { method, body })
|
||||
|
||||
|
|
|
|||
32
packages/whiteboard/certs/cert.pem
Normal file
32
packages/whiteboard/certs/cert.pem
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFlTCCA32gAwIBAgIUZR64clYd03SXp6rx5uy5n0xrKsgwDQYJKoZIhvcNAQEL
|
||||
BQAwWjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
|
||||
MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xFTATBgNVBAMMDGRhbGxhcy5sb2NhbDAe
|
||||
Fw0yNTA3MTcxNzQ3MzJaFw0yNjA3MTcxNzQ3MzJaMFoxCzAJBgNVBAYTAlVTMQ4w
|
||||
DAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UECgwMT3JnYW5pemF0
|
||||
aW9uMRUwEwYDVQQDDAxkYWxsYXMubG9jYWwwggIiMA0GCSqGSIb3DQEBAQUAA4IC
|
||||
DwAwggIKAoICAQDCWaYE4w2dKrFBlE3zFw0wzeiIfTYRP0OASM3tOSEDrGN7UF75
|
||||
P0sR/2y61hVjVeXP0qrD1JI7oo+0OR1xHm9eEaSdCm7VKGE4llt+qDxzpUmQEK9J
|
||||
h4TrAME+TkLptkmrR/xJSLdHorlqjDWbRrFIQwoM4MrCcMj+CQWUBFcM/dodtHEn
|
||||
md2kv8HMuw3ALl6Wu/PgVTGv8/wvXdz99eFy6r/OtlWCyQxd7sm69b5Jm1anLn9t
|
||||
WXkdas0RcmzBXNiXRC8mCjf3U6HkLCVPdAMNHCvLVy5HqXD+AbegvuDSk0zht/iU
|
||||
pL8U+5YGM8UtOjpocnoz+ey8AGV+BxT8OpFvdC5Ww+e3GRxvQsGwa/r/QTT7VAel
|
||||
b1p9szYE9Dmk22GYIm9RJmnWLeXsutS55/VsscOFKQN6/7X0STDS1bSDjdrOILFT
|
||||
GgnwaGR8Kdwa4N0ceOWAMGPspkce1+i993PFXboEcY/zP6qUOmoc+MAJqolXzBre
|
||||
unhpoQRAFkIRjqOqEZ07spLWrzgaoeUmiKoBJTA+e3F5hBBOLCF2oRz2Ueu1FlcX
|
||||
bgIEEltuiuk49sIDeVbnedzJR/yCn9Rnk2ZMYpblh12VL/6xvw3nY2XZJ05ixDIG
|
||||
oIPgn9N+8pckVRVVfOZQm8vk/RUnWaKkRWABX3IXs2qao9VjJO64RbdHCQIDAQAB
|
||||
o1MwUTAdBgNVHQ4EFgQU0v0vPP/3VBNhL0bt4G5lG1liBmQwHwYDVR0jBBgwFoAU
|
||||
0v0vPP/3VBNhL0bt4G5lG1liBmQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
|
||||
AQsFAAOCAgEAElfSsTgbV9aqZSI4KMpjCXDVopgRC39Kmmyhmqmvyjd8kgcuEoLy
|
||||
2VEGfR3d0M5/8IoCX5BZyxf0TyJneKaUzPm8pYmC/5P9tAiobde2flg0qeK1xY18
|
||||
sQhLoBvC4hjJzkTru3+Gw9k+4EBTEkaPD9FF3ezpbaygBAd6ktfnOViZ3QYEjDTj
|
||||
9IwEgT79IcukDIbDOJ/LfZ+uZ7vFAgHLUYeIjWR1IdpHKGFPjW/Mv7j5EICFOhiP
|
||||
9PlTncmzkXL1FiaBRphl7GcZiUUAUNPBzsVo2CNrEyH1Xk6JVb70FQdO2q3NGXaz
|
||||
K8lktdHHrhgBZiJVZlhbSluzCaZEe1RMmo3Fi8Xs/5Lf/pLZLmr2jxJ8hL5TctE3
|
||||
Wi+8iODw9Qxlce5fhGNQHO9f4zrLedTe6XoxXB3Q9DfclJ/NH2S03t5s57qb9AUC
|
||||
0XoR/XSX78hgloIMJ8SeH5jCsnDmXbdMBVrtjmvcWrn5aGEYa6L08j17NC3gtuZO
|
||||
TWikADahp9YFFJqZESP5UGk3Hf+pYO46cPCf3arVBpQU0PZCN4YcL4CZt+uNdfo1
|
||||
IasoFUk9TZjtRseLEEcSbTPF3yxEPxXYhwCAzrQVDojikuS0PJc6sKZBq98o5uEA
|
||||
x/q4E8nBNDiPulWjWDzI7g7vS3mnOUgXn36qD0YrZ6S+VQgHOI7gWrA=
|
||||
-----END CERTIFICATE-----
|
||||
52
packages/whiteboard/certs/key.pem
Normal file
52
packages/whiteboard/certs/key.pem
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
b0dH61UfW7O//NJWWv2YqAdm1Opuhw==
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -11,9 +11,13 @@
|
|||
"dependencies": {
|
||||
"@google/genai": "^1.9.0",
|
||||
"@openai/agents": "^0.0.11",
|
||||
"@techstark/opencv-js": "^4.11.0-release.1",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@workshop/nano-remix": "workspace:*",
|
||||
"@workshop/shared": "workspace:*",
|
||||
"hono": "catalog:",
|
||||
"luxon": "^3.7.1",
|
||||
"pngjs": "^7.0.0",
|
||||
"zod": "3.25.67"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB |
BIN
packages/whiteboard/public/whiteboard.png
Normal file
BIN
packages/whiteboard/public/whiteboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
95
packages/whiteboard/src/opencv.ts
Normal file
95
packages/whiteboard/src/opencv.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import cvReady from "@techstark/opencv-js"
|
||||
import { PNG } from "pngjs"
|
||||
|
||||
type Element = {
|
||||
ymin: number
|
||||
xmin: number
|
||||
ymax: number
|
||||
xmax: number
|
||||
label: string
|
||||
}
|
||||
type StructuredResponse = { elements: Element[] }
|
||||
|
||||
export const detectShapes = async (
|
||||
imgBuffer: ArrayBuffer,
|
||||
minAreaPercent = 0.5,
|
||||
maxAreaPercent = 15
|
||||
): Promise<StructuredResponse> => {
|
||||
const cv = await cvReady
|
||||
|
||||
// 1. Decode PNG from ArrayBuffer → raw RGBA buffer
|
||||
const buf = Buffer.from(imgBuffer)
|
||||
const { width, height, data } = PNG.sync.read(buf)
|
||||
|
||||
// 2. Create a 4-ch Mat from RGBA pixels
|
||||
const srcRGBA = cv.matFromArray(height, width, cv.CV_8UC4, new Uint8Array(data))
|
||||
|
||||
// 3. Convert → gray → blur → threshold
|
||||
const gray = new cv.Mat()
|
||||
cv.cvtColor(srcRGBA, gray, cv.COLOR_RGBA2GRAY)
|
||||
cv.GaussianBlur(gray, gray, new cv.Size(5, 5), 0)
|
||||
|
||||
const thresh = new cv.Mat()
|
||||
cv.adaptiveThreshold(gray, thresh, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 11, 2)
|
||||
|
||||
// 4. Find contours
|
||||
const contours = new cv.MatVector()
|
||||
const hierarchy = new cv.Mat()
|
||||
cv.findContours(thresh, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
|
||||
|
||||
const norm = (v: number, max: number) => Math.round((v / max) * 1000)
|
||||
const totalImageArea = width * height
|
||||
const elements: Element[] = []
|
||||
|
||||
for (let i = 0; i < contours.size(); i++) {
|
||||
const cnt = contours.get(i)
|
||||
const rect = cv.boundingRect(cnt)
|
||||
const contourArea = cv.contourArea(cnt)
|
||||
const areaPercent = (contourArea / totalImageArea) * 100
|
||||
|
||||
// Basic filtering
|
||||
if (areaPercent < minAreaPercent || areaPercent > maxAreaPercent) {
|
||||
cnt.delete()
|
||||
continue
|
||||
}
|
||||
|
||||
const margin = Math.min(width, height) * 0.05
|
||||
if (
|
||||
rect.x < margin ||
|
||||
rect.y < margin ||
|
||||
rect.x + rect.width > width - margin ||
|
||||
rect.y + rect.height > height - margin
|
||||
) {
|
||||
cnt.delete()
|
||||
continue
|
||||
}
|
||||
|
||||
// Simple shape classification
|
||||
const peri = cv.arcLength(cnt, true)
|
||||
const approx = new cv.Mat()
|
||||
cv.approxPolyDP(cnt, approx, 0.02 * peri, true)
|
||||
|
||||
let label = "polygon"
|
||||
if (approx.rows === 3) label = "triangle"
|
||||
else if (approx.rows === 4) {
|
||||
const aspectRatio = rect.width / rect.height
|
||||
label = Math.abs(aspectRatio - 1) < 0.2 ? "square" : "rectangle"
|
||||
} else if (approx.rows > 6) label = "circle"
|
||||
|
||||
elements.push({
|
||||
ymin: norm(rect.y, gray.rows),
|
||||
xmin: norm(rect.x, gray.cols),
|
||||
ymax: norm(rect.y + rect.height, gray.rows),
|
||||
xmax: norm(rect.x + rect.width, gray.cols),
|
||||
label,
|
||||
})
|
||||
|
||||
cnt.delete()
|
||||
approx.delete()
|
||||
}
|
||||
|
||||
// 5. Cleanup
|
||||
;[srcRGBA, gray, thresh, contours, hierarchy].forEach((m: any) => m.delete())
|
||||
|
||||
return { elements }
|
||||
}
|
||||
39
packages/whiteboard/src/result.json
Normal file
39
packages/whiteboard/src/result.json
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"elements": [
|
||||
{
|
||||
"ymin": 583,
|
||||
"xmin": 97,
|
||||
"ymax": 744,
|
||||
"xmax": 392,
|
||||
"label": "rectangle"
|
||||
},
|
||||
{
|
||||
"ymin": 471,
|
||||
"xmin": 455,
|
||||
"ymax": 680,
|
||||
"xmax": 664,
|
||||
"label": "circle"
|
||||
},
|
||||
{
|
||||
"ymin": 349,
|
||||
"xmin": 173,
|
||||
"ymax": 442,
|
||||
"xmax": 296,
|
||||
"label": "circle"
|
||||
},
|
||||
{
|
||||
"ymin": 303,
|
||||
"xmin": 432,
|
||||
"ymax": 466,
|
||||
"xmax": 589,
|
||||
"label": "circle"
|
||||
},
|
||||
{
|
||||
"ymin": 49,
|
||||
"xmin": 87,
|
||||
"ymax": 255,
|
||||
"xmax": 368,
|
||||
"label": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ import { ensure } from "@workshop/shared/utils"
|
|||
import { useAction, Form, type Head } from "@workshop/nano-remix"
|
||||
import { useEffect, useRef, useState } from "hono/jsx"
|
||||
import { getGeminiResponse } from "../ai"
|
||||
import result from "../result.json"
|
||||
import { detectShapes } from "../opencv"
|
||||
|
||||
const categories = ["hand drawn circle", "hand drawn square", "hand drawn arrow"]
|
||||
const prompts = {
|
||||
|
|
@ -11,12 +13,14 @@ const prompts = {
|
|||
|
||||
export const action = async (req: Request, params: {}) => {
|
||||
const url = new URL(req.url)
|
||||
const imageUrl = new URL("whiteboard.jpeg", url.origin).toString()
|
||||
const imageUrl = new URL("whiteboard.png", url.origin).toString()
|
||||
const imageResponse = await fetch(imageUrl)
|
||||
const imageBuffer = await imageResponse.arrayBuffer()
|
||||
// const response = await getGeminiResponse(imageBuffer, prompts.default)
|
||||
// return { elements: response?.elements || [] }
|
||||
|
||||
return { elements: response?.elements || [] }
|
||||
const response = await detectShapes(imageBuffer)
|
||||
return { elements: response.elements }
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
|
|
@ -34,7 +38,7 @@ export default function Index() {
|
|||
canvasRef.current.height = img.height
|
||||
}
|
||||
|
||||
img.src = "/whiteboard.jpeg"
|
||||
img.src = "/whiteboard.png"
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -51,7 +55,6 @@ export default function Index() {
|
|||
// Draw AI detected elements with box_2d format
|
||||
data?.elements.forEach((element, index) => {
|
||||
const { ymin, xmin, ymax, xmax } = element
|
||||
ensure(ymin && xmin && ymax && xmax, "Box 2D coordinates must be defined")
|
||||
|
||||
// Convert normalized coordinates (0-1000) to actual canvas coordinates
|
||||
const x = (xmin / 1000) * canvas.width
|
||||
|
|
@ -87,6 +90,10 @@ export default function Index() {
|
|||
<p class="mb-2">
|
||||
<strong>Detected Elements:</strong> {data?.elements.length}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-gray-300 inline-block">
|
||||
<canvas ref={canvasRef} class="max-w-full h-auto" />
|
||||
<ul class="list-disc list-inside mb-4">
|
||||
{data?.elements.map((element, index) => (
|
||||
<li key={index}>
|
||||
|
|
@ -95,10 +102,6 @@ export default function Index() {
|
|||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-gray-300 inline-block">
|
||||
<canvas ref={canvasRef} class="max-w-full h-auto" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
159
packages/whiteboard/src/routes/upload.tsx
Normal file
159
packages/whiteboard/src/routes/upload.tsx
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
import { ensure } from "@workshop/shared/utils"
|
||||
import { useRef, useState, useEffect } from "hono/jsx"
|
||||
import { useAction, submitAction } from "@workshop/nano-remix"
|
||||
import { join } from "path"
|
||||
|
||||
export const action = async (req: Request, params: {}) => {
|
||||
const formData = await req.formData()
|
||||
const imageData = formData.get("imageData") as string
|
||||
|
||||
if (!imageData) {
|
||||
return { success: false, error: "No image provided" }
|
||||
}
|
||||
|
||||
const filename = `whiteboard.png`
|
||||
const base64Data = imageData.split(",")[1]
|
||||
if (!base64Data) {
|
||||
return { success: false, error: "Invalid image data" }
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(base64Data, "base64")
|
||||
const publicPath = join(import.meta.dir, `../../public/${filename}`)
|
||||
|
||||
try {
|
||||
await Bun.write(publicPath, buffer)
|
||||
return { success: true, filename, path: publicPath }
|
||||
} catch (error) {
|
||||
return { success: false, error: "Failed to save image" }
|
||||
}
|
||||
}
|
||||
|
||||
export default function Camera() {
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||
const [stream, setStream] = useState<MediaStream | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [capturedImage, setCapturedImage] = useState<string | null>(null)
|
||||
const { data, error: uploadError, loading } = useAction<typeof action>()
|
||||
|
||||
const captureImage = () => {
|
||||
ensure(videoRef.current, "Video ref must be set before capturing image")
|
||||
ensure(canvasRef.current, "Canvas ref must be set before capturing image")
|
||||
|
||||
const canvas = canvasRef.current
|
||||
const video = videoRef.current
|
||||
|
||||
// Downscale to max 320x240
|
||||
const maxWidth = 320
|
||||
const maxHeight = 240
|
||||
const aspectRatio = video.videoWidth / video.videoHeight
|
||||
|
||||
let newWidth = maxWidth
|
||||
let newHeight = maxHeight
|
||||
|
||||
if (aspectRatio > 1) {
|
||||
newHeight = maxWidth / aspectRatio
|
||||
} else {
|
||||
newWidth = maxHeight * aspectRatio
|
||||
}
|
||||
|
||||
canvas.width = newWidth
|
||||
canvas.height = newHeight
|
||||
|
||||
const ctx = canvas.getContext("2d")
|
||||
if (!ctx) return
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
ctx.drawImage(video, 0, 0, newWidth, newHeight)
|
||||
const dataURL = canvas.toDataURL("image/png")
|
||||
setCapturedImage(dataURL)
|
||||
|
||||
// Upload the image
|
||||
const formData = new FormData()
|
||||
formData.append("imageData", dataURL)
|
||||
submitAction(formData)
|
||||
}
|
||||
|
||||
const startCamera = async () => {
|
||||
try {
|
||||
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: "environment" },
|
||||
})
|
||||
|
||||
if (videoRef.current) {
|
||||
videoRef.current.srcObject = mediaStream
|
||||
videoRef.current.onloadedmetadata = () => {
|
||||
setTimeout(captureImage, 100)
|
||||
}
|
||||
}
|
||||
|
||||
setStream(mediaStream)
|
||||
setError(null)
|
||||
} catch (err) {
|
||||
setError("Failed to access camera")
|
||||
}
|
||||
}
|
||||
|
||||
const stopCamera = () => {
|
||||
if (!stream) return
|
||||
|
||||
stream.getTracks().forEach((track) => track.stop())
|
||||
setStream(null)
|
||||
setCapturedImage(null)
|
||||
if (videoRef.current) {
|
||||
videoRef.current.srcObject = null
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!stream) return
|
||||
|
||||
const interval = setInterval(() => {
|
||||
captureImage()
|
||||
}, 1000)
|
||||
|
||||
return () => clearInterval(interval)
|
||||
}, [stream])
|
||||
|
||||
return (
|
||||
<div class="p-5">
|
||||
<h1 class="text-3xl font-bold mb-5">Camera Test</h1>
|
||||
|
||||
{error && (
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">{error}</div>
|
||||
)}
|
||||
|
||||
<div class="mb-4">
|
||||
{!stream ? (
|
||||
<button onClick={startCamera} class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">
|
||||
Start Camera
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={stopCamera} class="bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600">
|
||||
Stop Camera
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{uploadError && (
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">{uploadError}</div>
|
||||
)}
|
||||
|
||||
{data?.success && (
|
||||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
|
||||
Upload successful! File: {data.filename}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{capturedImage && (
|
||||
<img src={capturedImage} alt="Captured" class="w-full max-w-lg border-2 border-gray-300 rounded" />
|
||||
)}
|
||||
|
||||
<canvas ref={canvasRef} style={{ display: "none" }} />
|
||||
<video ref={videoRef} autoPlay muted playsInline class="w-full max-w-lg object-cover" />
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
|
||||
<script>eruda.init()</script>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
import { nanoRemix } from "@workshop/nano-remix"
|
||||
|
||||
Bun.serve({
|
||||
port: 3000,
|
||||
hostname: "0.0.0.0", // Accept connections from any IP
|
||||
tls: {
|
||||
key: Bun.file("certs/key.pem"),
|
||||
cert: Bun.file("certs/cert.pem"),
|
||||
},
|
||||
routes: {
|
||||
"/*": (req) => {
|
||||
return nanoRemix(req)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user