Custom endpoints (#72)
Browse filesCo-authored-by: Victor Muštar (aider) <[email protected]>
- package.json +2 -1
- pnpm-lock.yaml +312 -31
- src/app.css +14 -0
- src/lib/actions/click-outside.ts +4 -0
- src/lib/components/avatar.svelte +26 -12
- src/lib/components/debug-menu.svelte +12 -0
- src/lib/components/icon-provider.svelte +19 -1
- src/lib/components/inference-playground/code-snippets.svelte +109 -80
- src/lib/components/inference-playground/conversation-header.svelte +17 -14
- src/lib/components/inference-playground/conversation.svelte +1 -1
- src/lib/components/inference-playground/custom-model-config.svelte +251 -0
- src/lib/components/inference-playground/custom-provider-select.svelte +100 -0
- src/lib/components/inference-playground/generation-config.svelte +1 -3
- src/lib/components/inference-playground/hf-token-modal.svelte +3 -3
- src/lib/components/inference-playground/message.svelte +3 -1
- src/lib/components/inference-playground/model-selector-modal.svelte +121 -88
- src/lib/components/inference-playground/model-selector.svelte +13 -10
- src/lib/components/inference-playground/playground.svelte +14 -14
- src/lib/components/inference-playground/provider-select.svelte +2 -2
- src/lib/components/inference-playground/utils.ts +131 -27
- src/lib/components/local-toasts.svelte +13 -6
- src/lib/state/models.svelte.ts +72 -4
- src/lib/state/session.svelte.ts +3 -3
- src/lib/types.ts +23 -1
- src/lib/utils/sleep.ts +3 -0
- src/routes/+layout.svelte +2 -0
package.json
CHANGED
@@ -37,7 +37,8 @@
|
|
37 |
"globals": "^16.0.0",
|
38 |
"highlight.js": "^11.10.0",
|
39 |
"jiti": "^2.4.2",
|
40 |
-
"melt": "^0.
|
|
|
41 |
"postcss": "^8.4.38",
|
42 |
"prettier": "^3.1.1",
|
43 |
"prettier-plugin-svelte": "^3.2.6",
|
|
|
37 |
"globals": "^16.0.0",
|
38 |
"highlight.js": "^11.10.0",
|
39 |
"jiti": "^2.4.2",
|
40 |
+
"melt": "^0.28.0",
|
41 |
+
"openai": "^4.90.0",
|
42 |
"postcss": "^8.4.38",
|
43 |
"prettier": "^3.1.1",
|
44 |
"prettier-plugin-svelte": "^3.2.6",
|
pnpm-lock.yaml
CHANGED
@@ -41,22 +41,22 @@ importers:
|
|
41 |
version: 1.2.15
|
42 |
'@ryoppippi/unplugin-typia':
|
43 |
specifier: ^1.0.0
|
44 |
-
version: 1.2.0(@samchon/[email protected])([email protected])([email protected])([email protected])([email protected])
|
45 |
'@samchon/openapi':
|
46 |
specifier: ^3.0.0
|
47 |
version: 3.0.0
|
48 |
'@sveltejs/adapter-auto':
|
49 |
specifier: ^3.2.2
|
50 |
-
version: 3.3.1(@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected])))
|
51 |
'@sveltejs/adapter-node':
|
52 |
specifier: ^5.2.0
|
53 |
-
version: 5.2.12(@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected])))
|
54 |
'@sveltejs/kit':
|
55 |
specifier: ^2.5.27
|
56 |
-
version: 2.18.0(@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))
|
57 |
'@sveltejs/vite-plugin-svelte':
|
58 |
specifier: ^4.0.0
|
59 |
-
version: 4.0.4([email protected])([email protected]([email protected]))
|
60 |
'@tailwindcss/container-queries':
|
61 |
specifier: ^0.1.1
|
62 |
version: 0.1.1([email protected])
|
@@ -85,8 +85,11 @@ importers:
|
|
85 |
specifier: ^2.4.2
|
86 |
version: 2.4.2
|
87 |
melt:
|
88 |
-
specifier: ^0.
|
89 |
-
version: 0.
|
|
|
|
|
|
|
90 |
postcss:
|
91 |
specifier: ^8.4.38
|
92 |
version: 8.5.3
|
@@ -131,7 +134,7 @@ importers:
|
|
131 |
version: 22.1.0([email protected])
|
132 |
vite:
|
133 |
specifier: ^5.4.4
|
134 |
-
version: 5.4.14([email protected])
|
135 |
|
136 |
packages:
|
137 |
|
@@ -840,6 +843,12 @@ packages:
|
|
840 |
'@types/[email protected]':
|
841 |
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
842 |
|
|
|
|
|
|
|
|
|
|
|
|
|
843 |
'@types/[email protected]':
|
844 |
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
845 |
|
@@ -890,6 +899,10 @@ packages:
|
|
890 |
resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
|
891 |
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
892 |
|
|
|
|
|
|
|
|
|
893 | |
894 |
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
895 |
peerDependencies:
|
@@ -900,6 +913,10 @@ packages:
|
|
900 |
engines: {node: '>=0.4.0'}
|
901 |
hasBin: true
|
902 |
|
|
|
|
|
|
|
|
|
903 | |
904 |
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
905 |
|
@@ -929,6 +946,9 @@ packages:
|
|
929 | |
930 |
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
|
931 |
|
|
|
|
|
|
|
932 | |
933 |
resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==}
|
934 |
engines: {node: '>=4'}
|
@@ -959,6 +979,10 @@ packages:
|
|
959 | |
960 |
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
961 |
|
|
|
|
|
|
|
|
|
962 | |
963 |
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
964 |
engines: {node: '>=6'}
|
@@ -1001,6 +1025,10 @@ packages:
|
|
1001 | |
1002 |
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
1003 |
|
|
|
|
|
|
|
|
|
1004 | |
1005 |
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
|
1006 |
engines: {node: '>=14'}
|
@@ -1066,6 +1094,10 @@ packages:
|
|
1066 | |
1067 |
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
1068 |
|
|
|
|
|
|
|
|
|
1069 | |
1070 |
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
1071 |
engines: {node: '>=0.10'}
|
@@ -1085,6 +1117,10 @@ packages:
|
|
1085 |
resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==}
|
1086 |
engines: {node: '>=4'}
|
1087 |
|
|
|
|
|
|
|
|
|
1088 | |
1089 |
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
1090 |
|
@@ -1092,6 +1128,22 @@ packages:
|
|
1092 |
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
1093 |
engines: {node: '>=10.13.0'}
|
1094 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1095 | |
1096 |
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
|
1097 |
engines: {node: '>=12'}
|
@@ -1202,6 +1254,10 @@ packages:
|
|
1202 |
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
1203 |
engines: {node: '>=0.10.0'}
|
1204 |
|
|
|
|
|
|
|
|
|
1205 | |
1206 |
resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==}
|
1207 |
|
@@ -1267,6 +1323,17 @@ packages:
|
|
1267 | |
1268 |
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
|
1269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 | |
1271 |
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
1272 |
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
@@ -1275,6 +1342,14 @@ packages:
|
|
1275 | |
1276 |
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
1277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1278 | |
1279 |
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
1280 |
engines: {node: '>= 6'}
|
@@ -1299,6 +1374,10 @@ packages:
|
|
1299 |
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
|
1300 |
engines: {node: '>=18'}
|
1301 |
|
|
|
|
|
|
|
|
|
1302 | |
1303 |
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
1304 |
|
@@ -1313,6 +1392,14 @@ packages:
|
|
1313 |
resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==}
|
1314 |
engines: {node: '>=8'}
|
1315 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1316 | |
1317 |
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
1318 |
engines: {node: '>= 0.4'}
|
@@ -1321,6 +1408,9 @@ packages:
|
|
1321 |
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
1322 |
engines: {node: '>=12.0.0'}
|
1323 |
|
|
|
|
|
|
|
1324 | |
1325 |
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
1326 |
engines: {node: '>=0.10.0'}
|
@@ -1548,8 +1638,12 @@ packages:
|
|
1548 | |
1549 |
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
1550 |
|
1551 |
-
|
1552 |
-
resolution: {integrity: sha512
|
|
|
|
|
|
|
|
|
1553 |
peerDependencies:
|
1554 |
'@floating-ui/dom': ^1.6.0
|
1555 |
svelte: ^5.0.0
|
@@ -1562,6 +1656,14 @@ packages:
|
|
1562 |
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
1563 |
engines: {node: '>=8.6'}
|
1564 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1565 | |
1566 |
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
1567 |
engines: {node: '>=6'}
|
@@ -1606,10 +1708,35 @@ packages:
|
|
1606 | |
1607 |
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
1608 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1609 | |
1610 |
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
1611 |
engines: {node: '>=6'}
|
1612 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1613 | |
1614 |
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
1615 |
engines: {node: '>= 0.8.0'}
|
@@ -1985,6 +2112,9 @@ packages:
|
|
1985 |
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
1986 |
engines: {node: '>=6'}
|
1987 |
|
|
|
|
|
|
|
1988 | |
1989 |
resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
|
1990 |
engines: {node: '>=18.12'}
|
@@ -2044,6 +2174,9 @@ packages:
|
|
2044 | |
2045 |
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
|
2046 |
|
|
|
|
|
|
|
2047 | |
2048 |
resolution: {integrity: sha512-ect2ZNtk1Zgwb0NVHd0C1IDW/MV+Jk/xaq4t8o6rYdVS3+L660ZdD5kTSQZvsgdwCvquRw+/wYn75hsweRjoIA==}
|
2049 |
peerDependencies:
|
@@ -2163,9 +2296,19 @@ packages:
|
|
2163 | |
2164 |
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
2165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2166 | |
2167 |
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
2168 |
|
|
|
|
|
|
|
2169 | |
2170 |
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
2171 |
engines: {node: '>= 8'}
|
@@ -2597,7 +2740,7 @@ snapshots:
|
|
2597 |
'@rollup/[email protected]':
|
2598 |
optional: true
|
2599 |
|
2600 |
-
'@ryoppippi/[email protected](@samchon/[email protected])([email protected])([email protected])([email protected])([email protected])':
|
2601 |
dependencies:
|
2602 |
'@rollup/pluginutils': 5.1.4([email protected])
|
2603 |
consola: 3.4.0
|
@@ -2611,7 +2754,7 @@ snapshots:
|
|
2611 |
typescript: 5.6.3
|
2612 |
typia: 7.6.4(@samchon/[email protected])([email protected])
|
2613 |
unplugin: 1.16.1
|
2614 |
-
vite: 6.2.1([email protected])([email protected])([email protected])
|
2615 |
transitivePeerDependencies:
|
2616 |
- '@samchon/openapi'
|
2617 |
- '@types/node'
|
@@ -2635,22 +2778,22 @@ snapshots:
|
|
2635 |
dependencies:
|
2636 |
acorn: 8.14.0
|
2637 |
|
2638 |
-
'@sveltejs/[email protected](@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected])))':
|
2639 |
dependencies:
|
2640 |
-
'@sveltejs/kit': 2.18.0(@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))
|
2641 |
import-meta-resolve: 4.1.0
|
2642 |
|
2643 |
-
'@sveltejs/[email protected](@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected])))':
|
2644 |
dependencies:
|
2645 |
'@rollup/plugin-commonjs': 28.0.2([email protected])
|
2646 |
'@rollup/plugin-json': 6.1.0([email protected])
|
2647 |
'@rollup/plugin-node-resolve': 16.0.0([email protected])
|
2648 |
-
'@sveltejs/kit': 2.18.0(@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))
|
2649 |
rollup: 4.34.9
|
2650 |
|
2651 |
-
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))':
|
2652 |
dependencies:
|
2653 |
-
'@sveltejs/vite-plugin-svelte': 4.0.4([email protected])([email protected]([email protected]))
|
2654 |
'@types/cookie': 0.6.0
|
2655 |
cookie: 0.6.0
|
2656 |
devalue: 5.1.1
|
@@ -2663,27 +2806,27 @@ snapshots:
|
|
2663 |
set-cookie-parser: 2.7.1
|
2664 |
sirv: 3.0.1
|
2665 |
svelte: 5.23.0
|
2666 |
-
vite: 5.4.14([email protected])
|
2667 |
|
2668 |
-
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))':
|
2669 |
dependencies:
|
2670 |
-
'@sveltejs/vite-plugin-svelte': 4.0.4([email protected])([email protected]([email protected]))
|
2671 |
debug: 4.4.0
|
2672 |
svelte: 5.23.0
|
2673 |
-
vite: 5.4.14([email protected])
|
2674 |
transitivePeerDependencies:
|
2675 |
- supports-color
|
2676 |
|
2677 |
-
'@sveltejs/[email protected]([email protected])([email protected]([email protected]))':
|
2678 |
dependencies:
|
2679 |
-
'@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/[email protected]([email protected])([email protected]([email protected])))([email protected])([email protected]([email protected]))
|
2680 |
debug: 4.4.0
|
2681 |
deepmerge: 4.3.1
|
2682 |
kleur: 4.1.5
|
2683 |
magic-string: 0.30.17
|
2684 |
svelte: 5.23.0
|
2685 |
-
vite: 5.4.14([email protected])
|
2686 |
-
vitefu: 1.0.6([email protected]([email protected]))
|
2687 |
transitivePeerDependencies:
|
2688 |
- supports-color
|
2689 |
|
@@ -2759,6 +2902,15 @@ snapshots:
|
|
2759 |
|
2760 |
'@types/[email protected]': {}
|
2761 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2762 |
'@types/[email protected]': {}
|
2763 |
|
2764 |
'@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected])':
|
@@ -2838,12 +2990,20 @@ snapshots:
|
|
2838 |
'@typescript-eslint/types': 8.26.1
|
2839 |
eslint-visitor-keys: 4.2.0
|
2840 |
|
|
|
|
|
|
|
|
|
2841 | |
2842 |
dependencies:
|
2843 |
acorn: 8.14.0
|
2844 |
|
2845 | |
2846 |
|
|
|
|
|
|
|
|
|
2847 | |
2848 |
dependencies:
|
2849 |
fast-deep-equal: 3.1.3
|
@@ -2869,6 +3029,8 @@ snapshots:
|
|
2869 |
|
2870 | |
2871 |
|
|
|
|
|
2872 | |
2873 |
|
2874 | |
@@ -2901,6 +3063,11 @@ snapshots:
|
|
2901 |
base64-js: 1.5.1
|
2902 |
ieee754: 1.2.1
|
2903 |
|
|
|
|
|
|
|
|
|
|
|
2904 | |
2905 |
|
2906 | |
@@ -2932,6 +3099,10 @@ snapshots:
|
|
2932 |
|
2933 | |
2934 |
|
|
|
|
|
|
|
|
|
2935 | |
2936 |
|
2937 | |
@@ -2980,6 +3151,8 @@ snapshots:
|
|
2980 |
|
2981 | |
2982 |
|
|
|
|
|
2983 | |
2984 |
|
2985 | |
@@ -2990,6 +3163,12 @@ snapshots:
|
|
2990 |
|
2991 | |
2992 |
|
|
|
|
|
|
|
|
|
|
|
|
|
2993 | |
2994 |
|
2995 | |
@@ -2997,6 +3176,21 @@ snapshots:
|
|
2997 |
graceful-fs: 4.2.11
|
2998 |
tapable: 2.2.1
|
2999 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3000 | |
3001 |
optionalDependencies:
|
3002 |
'@esbuild/aix-ppc64': 0.21.5
|
@@ -3170,6 +3364,8 @@ snapshots:
|
|
3170 |
|
3171 | |
3172 |
|
|
|
|
|
3173 | |
3174 |
|
3175 | |
@@ -3236,11 +3432,43 @@ snapshots:
|
|
3236 |
|
3237 | |
3238 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3239 | |
3240 |
optional: true
|
3241 |
|
3242 | |
3243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3244 | |
3245 |
dependencies:
|
3246 |
is-glob: 4.0.3
|
@@ -3261,6 +3489,8 @@ snapshots:
|
|
3261 |
|
3262 | |
3263 |
|
|
|
|
|
3264 | |
3265 |
|
3266 | |
@@ -3269,12 +3499,22 @@ snapshots:
|
|
3269 |
|
3270 | |
3271 |
|
|
|
|
|
|
|
|
|
|
|
|
|
3272 | |
3273 |
dependencies:
|
3274 |
function-bind: 1.1.2
|
3275 |
|
3276 | |
3277 |
|
|
|
|
|
|
|
|
|
3278 | |
3279 |
dependencies:
|
3280 |
safer-buffer: 2.1.2
|
@@ -3474,7 +3714,9 @@ snapshots:
|
|
3474 |
dependencies:
|
3475 |
'@jridgewell/sourcemap-codec': 1.5.0
|
3476 |
|
3477 |
-
|
|
|
|
|
3478 |
dependencies:
|
3479 |
'@floating-ui/dom': 1.6.13
|
3480 |
jest-axe: 9.0.0
|
@@ -3489,6 +3731,12 @@ snapshots:
|
|
3489 |
braces: 3.0.3
|
3490 |
picomatch: 2.3.1
|
3491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
3492 | |
3493 |
|
3494 | |
@@ -3522,10 +3770,28 @@ snapshots:
|
|
3522 |
|
3523 | |
3524 |
|
|
|
|
|
|
|
|
|
|
|
|
|
3525 | |
3526 |
dependencies:
|
3527 |
mimic-fn: 2.1.0
|
3528 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3529 | |
3530 |
dependencies:
|
3531 |
deep-is: 0.1.4
|
@@ -3858,6 +4124,8 @@ snapshots:
|
|
3858 |
|
3859 | |
3860 |
|
|
|
|
|
3861 | |
3862 |
dependencies:
|
3863 |
typescript: 5.8.2
|
@@ -3917,6 +4185,8 @@ snapshots:
|
|
3917 |
|
3918 | |
3919 |
|
|
|
|
|
3920 | |
3921 |
dependencies:
|
3922 |
'@antfu/install-pkg': 1.0.0
|
@@ -3945,36 +4215,47 @@ snapshots:
|
|
3945 |
|
3946 | |
3947 |
|
3948 | |
3949 |
dependencies:
|
3950 |
esbuild: 0.21.5
|
3951 |
postcss: 8.5.3
|
3952 |
rollup: 4.34.9
|
3953 |
optionalDependencies:
|
|
|
3954 |
fsevents: 2.3.3
|
3955 |
lightningcss: 1.29.1
|
3956 |
|
3957 | |
3958 |
dependencies:
|
3959 |
esbuild: 0.25.1
|
3960 |
postcss: 8.5.3
|
3961 |
rollup: 4.34.9
|
3962 |
optionalDependencies:
|
|
|
3963 |
fsevents: 2.3.3
|
3964 |
jiti: 2.4.2
|
3965 |
lightningcss: 1.29.1
|
3966 |
yaml: 2.7.0
|
3967 |
|
3968 | |
3969 |
optionalDependencies:
|
3970 |
-
vite: 5.4.14([email protected])
|
3971 |
|
3972 | |
3973 |
dependencies:
|
3974 |
defaults: 1.0.4
|
3975 |
|
|
|
|
|
|
|
|
|
3976 | |
3977 |
|
|
|
|
|
|
|
|
|
|
|
3978 | |
3979 |
dependencies:
|
3980 |
isexe: 2.0.0
|
|
|
41 |
version: 1.2.15
|
42 |
'@ryoppippi/unplugin-typia':
|
43 |
specifier: ^1.0.0
|
44 |
+
version: 1.2.0(@samchon/[email protected])(@types/[email protected])([email protected])([email protected])([email protected])([email protected])
|
45 |
'@samchon/openapi':
|
46 |
specifier: ^3.0.0
|
47 |
version: 3.0.0
|
48 |
'@sveltejs/adapter-auto':
|
49 |
specifier: ^3.2.2
|
50 |
+
version: 3.3.1(@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected])))
|
51 |
'@sveltejs/adapter-node':
|
52 |
specifier: ^5.2.0
|
53 |
+
version: 5.2.12(@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected])))
|
54 |
'@sveltejs/kit':
|
55 |
specifier: ^2.5.27
|
56 |
+
version: 2.18.0(@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))
|
57 |
'@sveltejs/vite-plugin-svelte':
|
58 |
specifier: ^4.0.0
|
59 |
+
version: 4.0.4([email protected])([email protected](@types/[email protected])([email protected]))
|
60 |
'@tailwindcss/container-queries':
|
61 |
specifier: ^0.1.1
|
62 |
version: 0.1.1([email protected])
|
|
|
85 |
specifier: ^2.4.2
|
86 |
version: 2.4.2
|
87 |
melt:
|
88 |
+
specifier: ^0.28.0
|
89 |
+
version: 0.28.0(@floating-ui/[email protected])([email protected])
|
90 |
+
openai:
|
91 |
+
specifier: ^4.90.0
|
92 |
+
version: 4.90.0
|
93 |
postcss:
|
94 |
specifier: ^8.4.38
|
95 |
version: 8.5.3
|
|
|
134 |
version: 22.1.0([email protected])
|
135 |
vite:
|
136 |
specifier: ^5.4.4
|
137 |
+
version: 5.4.14(@types/[email protected])([email protected])
|
138 |
|
139 |
packages:
|
140 |
|
|
|
843 |
'@types/[email protected]':
|
844 |
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
845 |
|
846 |
+
'@types/[email protected]':
|
847 |
+
resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
|
848 |
+
|
849 |
+
'@types/[email protected]':
|
850 |
+
resolution: {integrity: sha512-ACYy2HGcZPHxEeWTqowTF7dhXN+JU1o7Gr4b41klnn6pj2LD6rsiGqSZojMdk1Jh2ys3m76ap+ae1vvE4+5+vg==}
|
851 |
+
|
852 |
'@types/[email protected]':
|
853 |
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
854 |
|
|
|
899 |
resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
|
900 |
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
901 |
|
902 | |
903 |
+
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
904 |
+
engines: {node: '>=6.5'}
|
905 |
+
|
906 | |
907 |
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
908 |
peerDependencies:
|
|
|
913 |
engines: {node: '>=0.4.0'}
|
914 |
hasBin: true
|
915 |
|
916 | |
917 |
+
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
918 |
+
engines: {node: '>= 8.0.0'}
|
919 |
+
|
920 | |
921 |
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
922 |
|
|
|
946 | |
947 |
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
|
948 |
|
949 | |
950 |
+
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
951 |
+
|
952 | |
953 |
resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==}
|
954 |
engines: {node: '>=4'}
|
|
|
979 | |
980 |
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
981 |
|
982 | |
983 |
+
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
984 |
+
engines: {node: '>= 0.4'}
|
985 |
+
|
986 | |
987 |
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
988 |
engines: {node: '>=6'}
|
|
|
1025 | |
1026 |
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
1027 |
|
1028 | |
1029 |
+
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
1030 |
+
engines: {node: '>= 0.8'}
|
1031 |
+
|
1032 | |
1033 |
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
|
1034 |
engines: {node: '>=14'}
|
|
|
1094 | |
1095 |
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
1096 |
|
1097 | |
1098 |
+
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
1099 |
+
engines: {node: '>=0.4.0'}
|
1100 |
+
|
1101 | |
1102 |
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
1103 |
engines: {node: '>=0.10'}
|
|
|
1117 |
resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==}
|
1118 |
engines: {node: '>=4'}
|
1119 |
|
1120 | |
1121 |
+
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
1122 |
+
engines: {node: '>= 0.4'}
|
1123 |
+
|
1124 | |
1125 |
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
1126 |
|
|
|
1128 |
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
1129 |
engines: {node: '>=10.13.0'}
|
1130 |
|
1131 | |
1132 |
+
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
1133 |
+
engines: {node: '>= 0.4'}
|
1134 |
+
|
1135 | |
1136 |
+
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
1137 |
+
engines: {node: '>= 0.4'}
|
1138 |
+
|
1139 | |
1140 |
+
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
1141 |
+
engines: {node: '>= 0.4'}
|
1142 |
+
|
1143 | |
1144 |
+
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
1145 |
+
engines: {node: '>= 0.4'}
|
1146 |
+
|
1147 | |
1148 |
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
|
1149 |
engines: {node: '>=12'}
|
|
|
1254 |
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
1255 |
engines: {node: '>=0.10.0'}
|
1256 |
|
1257 | |
1258 |
+
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
1259 |
+
engines: {node: '>=6'}
|
1260 |
+
|
1261 | |
1262 |
resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==}
|
1263 |
|
|
|
1323 | |
1324 |
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
|
1325 |
|
1326 | |
1327 |
+
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
1328 |
+
|
1329 | |
1330 |
+
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
|
1331 |
+
engines: {node: '>= 6'}
|
1332 |
+
|
1333 | |
1334 |
+
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
1335 |
+
engines: {node: '>= 12.20'}
|
1336 |
+
|
1337 | |
1338 |
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
1339 |
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
|
|
1342 | |
1343 |
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
1344 |
|
1345 | |
1346 |
+
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
1347 |
+
engines: {node: '>= 0.4'}
|
1348 |
+
|
1349 | |
1350 |
+
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
1351 |
+
engines: {node: '>= 0.4'}
|
1352 |
+
|
1353 | |
1354 |
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
1355 |
engines: {node: '>= 6'}
|
|
|
1374 |
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
|
1375 |
engines: {node: '>=18'}
|
1376 |
|
1377 | |
1378 |
+
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
1379 |
+
engines: {node: '>= 0.4'}
|
1380 |
+
|
1381 | |
1382 |
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
1383 |
|
|
|
1392 |
resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==}
|
1393 |
engines: {node: '>=8'}
|
1394 |
|
1395 | |
1396 |
+
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
1397 |
+
engines: {node: '>= 0.4'}
|
1398 |
+
|
1399 | |
1400 |
+
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
|
1401 |
+
engines: {node: '>= 0.4'}
|
1402 |
+
|
1403 | |
1404 |
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
1405 |
engines: {node: '>= 0.4'}
|
|
|
1408 |
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
1409 |
engines: {node: '>=12.0.0'}
|
1410 |
|
1411 | |
1412 |
+
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
1413 |
+
|
1414 | |
1415 |
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
1416 |
engines: {node: '>=0.10.0'}
|
|
|
1638 | |
1639 |
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
1640 |
|
1641 |
+
math-intrinsics@1.1.0:
|
1642 |
+
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
1643 |
+
engines: {node: '>= 0.4'}
|
1644 |
+
|
1645 | |
1646 |
+
resolution: {integrity: sha512-kiqaTgNB/IkADmUfJZKROqQ3z+isal8LjLhckQANqjfjggIosHM8M7RO3Og7IQ12zK06nLnwanL80SuTPhblrw==}
|
1647 |
peerDependencies:
|
1648 |
'@floating-ui/dom': ^1.6.0
|
1649 |
svelte: ^5.0.0
|
|
|
1656 |
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
1657 |
engines: {node: '>=8.6'}
|
1658 |
|
1659 | |
1660 |
+
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
1661 |
+
engines: {node: '>= 0.6'}
|
1662 |
+
|
1663 | |
1664 |
+
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
1665 |
+
engines: {node: '>= 0.6'}
|
1666 |
+
|
1667 | |
1668 |
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
1669 |
engines: {node: '>=6'}
|
|
|
1708 | |
1709 |
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
1710 |
|
1711 | |
1712 |
+
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
1713 |
+
engines: {node: '>=10.5.0'}
|
1714 |
+
|
1715 | |
1716 |
+
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
1717 |
+
engines: {node: 4.x || >=6.0.0}
|
1718 |
+
peerDependencies:
|
1719 |
+
encoding: ^0.1.0
|
1720 |
+
peerDependenciesMeta:
|
1721 |
+
encoding:
|
1722 |
+
optional: true
|
1723 |
+
|
1724 | |
1725 |
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
1726 |
engines: {node: '>=6'}
|
1727 |
|
1728 | |
1729 |
+
resolution: {integrity: sha512-YCuHMMycqtCg1B8G9ezkOF0j8UnBWD3Al/zYaelpuXwU1yhCEv+Y4n9G20MnyGy6cH4GsFwOMrgstQ+bgG1PtA==}
|
1730 |
+
hasBin: true
|
1731 |
+
peerDependencies:
|
1732 |
+
ws: ^8.18.0
|
1733 |
+
zod: ^3.23.8
|
1734 |
+
peerDependenciesMeta:
|
1735 |
+
ws:
|
1736 |
+
optional: true
|
1737 |
+
zod:
|
1738 |
+
optional: true
|
1739 |
+
|
1740 | |
1741 |
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
1742 |
engines: {node: '>= 0.8.0'}
|
|
|
2112 |
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
2113 |
engines: {node: '>=6'}
|
2114 |
|
2115 | |
2116 |
+
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
2117 |
+
|
2118 | |
2119 |
resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
|
2120 |
engines: {node: '>=18.12'}
|
|
|
2174 | |
2175 |
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
|
2176 |
|
2177 | |
2178 |
+
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
2179 |
+
|
2180 | |
2181 |
resolution: {integrity: sha512-ect2ZNtk1Zgwb0NVHd0C1IDW/MV+Jk/xaq4t8o6rYdVS3+L660ZdD5kTSQZvsgdwCvquRw+/wYn75hsweRjoIA==}
|
2182 |
peerDependencies:
|
|
|
2296 | |
2297 |
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
2298 |
|
2299 | |
2300 |
+
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
2301 |
+
engines: {node: '>= 14'}
|
2302 |
+
|
2303 | |
2304 |
+
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
2305 |
+
|
2306 | |
2307 |
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
2308 |
|
2309 | |
2310 |
+
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
2311 |
+
|
2312 | |
2313 |
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
2314 |
engines: {node: '>= 8'}
|
|
|
2740 |
'@rollup/[email protected]':
|
2741 |
optional: true
|
2742 |
|
2743 |
+
'@ryoppippi/[email protected](@samchon/[email protected])(@types/[email protected])([email protected])([email protected])([email protected])([email protected])':
|
2744 |
dependencies:
|
2745 |
'@rollup/pluginutils': 5.1.4([email protected])
|
2746 |
consola: 3.4.0
|
|
|
2754 |
typescript: 5.6.3
|
2755 |
typia: 7.6.4(@samchon/[email protected])([email protected])
|
2756 |
unplugin: 1.16.1
|
2757 |
+
vite: 6.2.1(@types/[email protected])([email protected])([email protected])([email protected])
|
2758 |
transitivePeerDependencies:
|
2759 |
- '@samchon/openapi'
|
2760 |
- '@types/node'
|
|
|
2778 |
dependencies:
|
2779 |
acorn: 8.14.0
|
2780 |
|
2781 |
+
'@sveltejs/[email protected](@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected])))':
|
2782 |
dependencies:
|
2783 |
+
'@sveltejs/kit': 2.18.0(@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))
|
2784 |
import-meta-resolve: 4.1.0
|
2785 |
|
2786 |
+
'@sveltejs/[email protected](@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected])))':
|
2787 |
dependencies:
|
2788 |
'@rollup/plugin-commonjs': 28.0.2([email protected])
|
2789 |
'@rollup/plugin-json': 6.1.0([email protected])
|
2790 |
'@rollup/plugin-node-resolve': 16.0.0([email protected])
|
2791 |
+
'@sveltejs/kit': 2.18.0(@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))
|
2792 |
rollup: 4.34.9
|
2793 |
|
2794 |
+
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))':
|
2795 |
dependencies:
|
2796 |
+
'@sveltejs/vite-plugin-svelte': 4.0.4([email protected])([email protected](@types/[email protected])([email protected]))
|
2797 |
'@types/cookie': 0.6.0
|
2798 |
cookie: 0.6.0
|
2799 |
devalue: 5.1.1
|
|
|
2806 |
set-cookie-parser: 2.7.1
|
2807 |
sirv: 3.0.1
|
2808 |
svelte: 5.23.0
|
2809 |
+
vite: 5.4.14(@types/[email protected])([email protected])
|
2810 |
|
2811 |
+
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))':
|
2812 |
dependencies:
|
2813 |
+
'@sveltejs/vite-plugin-svelte': 4.0.4([email protected])([email protected](@types/[email protected])([email protected]))
|
2814 |
debug: 4.4.0
|
2815 |
svelte: 5.23.0
|
2816 |
+
vite: 5.4.14(@types/[email protected])([email protected])
|
2817 |
transitivePeerDependencies:
|
2818 |
- supports-color
|
2819 |
|
2820 |
+
'@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected]))':
|
2821 |
dependencies:
|
2822 |
+
'@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/[email protected]([email protected])([email protected](@types/[email protected])([email protected])))([email protected])([email protected](@types/[email protected])([email protected]))
|
2823 |
debug: 4.4.0
|
2824 |
deepmerge: 4.3.1
|
2825 |
kleur: 4.1.5
|
2826 |
magic-string: 0.30.17
|
2827 |
svelte: 5.23.0
|
2828 |
+
vite: 5.4.14(@types/[email protected])([email protected])
|
2829 |
+
vitefu: 1.0.6([email protected](@types/[email protected])([email protected]))
|
2830 |
transitivePeerDependencies:
|
2831 |
- supports-color
|
2832 |
|
|
|
2902 |
|
2903 |
'@types/[email protected]': {}
|
2904 |
|
2905 |
+
'@types/[email protected]':
|
2906 |
+
dependencies:
|
2907 |
+
'@types/node': 18.19.84
|
2908 |
+
form-data: 4.0.2
|
2909 |
+
|
2910 |
+
'@types/[email protected]':
|
2911 |
+
dependencies:
|
2912 |
+
undici-types: 5.26.5
|
2913 |
+
|
2914 |
'@types/[email protected]': {}
|
2915 |
|
2916 |
'@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected]))([email protected]([email protected]))([email protected])':
|
|
|
2990 |
'@typescript-eslint/types': 8.26.1
|
2991 |
eslint-visitor-keys: 4.2.0
|
2992 |
|
2993 | |
2994 |
+
dependencies:
|
2995 |
+
event-target-shim: 5.0.1
|
2996 |
+
|
2997 | |
2998 |
dependencies:
|
2999 |
acorn: 8.14.0
|
3000 |
|
3001 | |
3002 |
|
3003 | |
3004 |
+
dependencies:
|
3005 |
+
humanize-ms: 1.2.1
|
3006 |
+
|
3007 | |
3008 |
dependencies:
|
3009 |
fast-deep-equal: 3.1.3
|
|
|
3029 |
|
3030 | |
3031 |
|
3032 |
+
[email protected]: {}
|
3033 |
+
|
3034 | |
3035 |
|
3036 | |
|
|
3063 |
base64-js: 1.5.1
|
3064 |
ieee754: 1.2.1
|
3065 |
|
3066 | |
3067 |
+
dependencies:
|
3068 |
+
es-errors: 1.3.0
|
3069 |
+
function-bind: 1.1.2
|
3070 |
+
|
3071 | |
3072 |
|
3073 | |
|
|
3099 |
|
3100 | |
3101 |
|
3102 | |
3103 |
+
dependencies:
|
3104 |
+
delayed-stream: 1.0.0
|
3105 |
+
|
3106 | |
3107 |
|
3108 | |
|
|
3151 |
|
3152 | |
3153 |
|
3154 |
+
[email protected]: {}
|
3155 |
+
|
3156 | |
3157 |
|
3158 | |
|
|
3163 |
|
3164 | |
3165 |
|
3166 | |
3167 |
+
dependencies:
|
3168 |
+
call-bind-apply-helpers: 1.0.2
|
3169 |
+
es-errors: 1.3.0
|
3170 |
+
gopd: 1.2.0
|
3171 |
+
|
3172 | |
3173 |
|
3174 | |
|
|
3176 |
graceful-fs: 4.2.11
|
3177 |
tapable: 2.2.1
|
3178 |
|
3179 |
+
[email protected]: {}
|
3180 |
+
|
3181 |
+
[email protected]: {}
|
3182 |
+
|
3183 | |
3184 |
+
dependencies:
|
3185 |
+
es-errors: 1.3.0
|
3186 |
+
|
3187 | |
3188 |
+
dependencies:
|
3189 |
+
es-errors: 1.3.0
|
3190 |
+
get-intrinsic: 1.3.0
|
3191 |
+
has-tostringtag: 1.0.2
|
3192 |
+
hasown: 2.0.2
|
3193 |
+
|
3194 | |
3195 |
optionalDependencies:
|
3196 |
'@esbuild/aix-ppc64': 0.21.5
|
|
|
3364 |
|
3365 | |
3366 |
|
3367 |
+
[email protected]: {}
|
3368 |
+
|
3369 | |
3370 |
|
3371 | |
|
|
3432 |
|
3433 | |
3434 |
|
3435 |
+
[email protected]: {}
|
3436 |
+
|
3437 | |
3438 |
+
dependencies:
|
3439 |
+
asynckit: 0.4.0
|
3440 |
+
combined-stream: 1.0.8
|
3441 |
+
es-set-tostringtag: 2.1.0
|
3442 |
+
mime-types: 2.1.35
|
3443 |
+
|
3444 | |
3445 |
+
dependencies:
|
3446 |
+
node-domexception: 1.0.0
|
3447 |
+
web-streams-polyfill: 4.0.0-beta.3
|
3448 |
+
|
3449 | |
3450 |
optional: true
|
3451 |
|
3452 | |
3453 |
|
3454 | |
3455 |
+
dependencies:
|
3456 |
+
call-bind-apply-helpers: 1.0.2
|
3457 |
+
es-define-property: 1.0.1
|
3458 |
+
es-errors: 1.3.0
|
3459 |
+
es-object-atoms: 1.1.1
|
3460 |
+
function-bind: 1.1.2
|
3461 |
+
get-proto: 1.0.1
|
3462 |
+
gopd: 1.2.0
|
3463 |
+
has-symbols: 1.1.0
|
3464 |
+
hasown: 2.0.2
|
3465 |
+
math-intrinsics: 1.1.0
|
3466 |
+
|
3467 | |
3468 |
+
dependencies:
|
3469 |
+
dunder-proto: 1.0.1
|
3470 |
+
es-object-atoms: 1.1.1
|
3471 |
+
|
3472 | |
3473 |
dependencies:
|
3474 |
is-glob: 4.0.3
|
|
|
3489 |
|
3490 | |
3491 |
|
3492 |
+
[email protected]: {}
|
3493 |
+
|
3494 | |
3495 |
|
3496 | |
|
|
3499 |
|
3500 | |
3501 |
|
3502 |
+
[email protected]: {}
|
3503 |
+
|
3504 | |
3505 |
+
dependencies:
|
3506 |
+
has-symbols: 1.1.0
|
3507 |
+
|
3508 | |
3509 |
dependencies:
|
3510 |
function-bind: 1.1.2
|
3511 |
|
3512 | |
3513 |
|
3514 | |
3515 |
+
dependencies:
|
3516 |
+
ms: 2.1.3
|
3517 |
+
|
3518 | |
3519 |
dependencies:
|
3520 |
safer-buffer: 2.1.2
|
|
|
3714 |
dependencies:
|
3715 |
'@jridgewell/sourcemap-codec': 1.5.0
|
3716 |
|
3717 |
+
math-intrinsics@1.1.0: {}
|
3718 |
+
|
3719 |
+
[email protected](@floating-ui/[email protected])([email protected]):
|
3720 |
dependencies:
|
3721 |
'@floating-ui/dom': 1.6.13
|
3722 |
jest-axe: 9.0.0
|
|
|
3731 |
braces: 3.0.3
|
3732 |
picomatch: 2.3.1
|
3733 |
|
3734 |
+
[email protected]: {}
|
3735 |
+
|
3736 | |
3737 |
+
dependencies:
|
3738 |
+
mime-db: 1.52.0
|
3739 |
+
|
3740 | |
3741 |
|
3742 | |
|
|
3770 |
|
3771 | |
3772 |
|
3773 |
+
[email protected]: {}
|
3774 |
+
|
3775 | |
3776 |
+
dependencies:
|
3777 |
+
whatwg-url: 5.0.0
|
3778 |
+
|
3779 | |
3780 |
dependencies:
|
3781 |
mimic-fn: 2.1.0
|
3782 |
|
3783 | |
3784 |
+
dependencies:
|
3785 |
+
'@types/node': 18.19.84
|
3786 |
+
'@types/node-fetch': 2.6.12
|
3787 |
+
abort-controller: 3.0.0
|
3788 |
+
agentkeepalive: 4.6.0
|
3789 |
+
form-data-encoder: 1.7.2
|
3790 |
+
formdata-node: 4.4.1
|
3791 |
+
node-fetch: 2.7.0
|
3792 |
+
transitivePeerDependencies:
|
3793 |
+
- encoding
|
3794 |
+
|
3795 | |
3796 |
dependencies:
|
3797 |
deep-is: 0.1.4
|
|
|
4124 |
|
4125 | |
4126 |
|
4127 |
+
[email protected]: {}
|
4128 |
+
|
4129 | |
4130 |
dependencies:
|
4131 |
typescript: 5.8.2
|
|
|
4185 |
|
4186 | |
4187 |
|
4188 |
+
[email protected]: {}
|
4189 |
+
|
4190 | |
4191 |
dependencies:
|
4192 |
'@antfu/install-pkg': 1.0.0
|
|
|
4215 |
|
4216 | |
4217 |
|
4218 |
+
[email protected](@types/[email protected])([email protected]):
|
4219 |
dependencies:
|
4220 |
esbuild: 0.21.5
|
4221 |
postcss: 8.5.3
|
4222 |
rollup: 4.34.9
|
4223 |
optionalDependencies:
|
4224 |
+
'@types/node': 18.19.84
|
4225 |
fsevents: 2.3.3
|
4226 |
lightningcss: 1.29.1
|
4227 |
|
4228 | |
4229 |
dependencies:
|
4230 |
esbuild: 0.25.1
|
4231 |
postcss: 8.5.3
|
4232 |
rollup: 4.34.9
|
4233 |
optionalDependencies:
|
4234 |
+
'@types/node': 18.19.84
|
4235 |
fsevents: 2.3.3
|
4236 |
jiti: 2.4.2
|
4237 |
lightningcss: 1.29.1
|
4238 |
yaml: 2.7.0
|
4239 |
|
4240 | |
4241 |
optionalDependencies:
|
4242 |
+
vite: 5.4.14(@types/[email protected])([email protected])
|
4243 |
|
4244 | |
4245 |
dependencies:
|
4246 |
defaults: 1.0.4
|
4247 |
|
4248 |
+
[email protected]: {}
|
4249 |
+
|
4250 |
+
[email protected]: {}
|
4251 |
+
|
4252 | |
4253 |
|
4254 | |
4255 |
+
dependencies:
|
4256 |
+
tr46: 0.0.3
|
4257 |
+
webidl-conversions: 3.0.1
|
4258 |
+
|
4259 | |
4260 |
dependencies:
|
4261 |
isexe: 2.0.0
|
src/app.css
CHANGED
@@ -60,6 +60,20 @@
|
|
60 |
@apply flex h-[39px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700;
|
61 |
}
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
/* Elements & Classes */
|
64 |
html {
|
65 |
font-size: 15px;
|
|
|
60 |
@apply flex h-[39px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700;
|
61 |
}
|
62 |
|
63 |
+
@utility custom-outline {
|
64 |
+
@apply outline-hidden;
|
65 |
+
@apply border-blue-500 ring ring-blue-500;
|
66 |
+
}
|
67 |
+
|
68 |
+
@utility focus-outline {
|
69 |
+
@apply focus-visible:custom-outline;
|
70 |
+
}
|
71 |
+
|
72 |
+
@utility input {
|
73 |
+
@apply rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400;
|
74 |
+
@apply focus-outline;
|
75 |
+
}
|
76 |
+
|
77 |
/* Elements & Classes */
|
78 |
html {
|
79 |
font-size: 15px;
|
src/lib/actions/click-outside.ts
CHANGED
@@ -8,6 +8,10 @@ export const clickOutside: Action<HTMLElement, () => void> = (node, callback) =>
|
|
8 |
}
|
9 |
|
10 |
function handleClick(event: MouseEvent) {
|
|
|
|
|
|
|
|
|
11 |
if (node && !node.contains(event.target as Node) && !event.defaultPrevented) {
|
12 |
_callback();
|
13 |
}
|
|
|
8 |
}
|
9 |
|
10 |
function handleClick(event: MouseEvent) {
|
11 |
+
if (window.getSelection()?.toString()) {
|
12 |
+
// Don't close if text is selected
|
13 |
+
return;
|
14 |
+
}
|
15 |
if (node && !node.contains(event.target as Node) && !event.defaultPrevented) {
|
16 |
_callback();
|
17 |
}
|
src/lib/components/avatar.svelte
CHANGED
@@ -1,12 +1,18 @@
|
|
1 |
<script lang="ts">
|
|
|
|
|
|
|
2 |
interface Props {
|
3 |
-
|
|
|
4 |
size?: "sm" | "md";
|
5 |
}
|
6 |
|
7 |
-
let { orgName, size = "md" }: Props = $props();
|
8 |
|
9 |
let sizeClass = $derived(size === "sm" ? "size-3" : "size-4");
|
|
|
|
|
10 |
|
11 |
async function getAvatarUrl(orgName?: string) {
|
12 |
if (!orgName) return;
|
@@ -22,14 +28,22 @@
|
|
22 |
}
|
23 |
</script>
|
24 |
|
25 |
-
{#
|
26 |
-
<div
|
27 |
-
{:
|
28 |
-
|
29 |
-
<
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
<div class="{sizeClass} flex-none rounded-sm bg-gray-200"></div>
|
32 |
-
{/
|
33 |
-
{
|
34 |
-
<div class="{sizeClass} flex-none rounded-sm bg-gray-200"></div>
|
35 |
-
{/await}
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { isCustomModel, type CustomModel, type Model } from "$lib/types.js";
|
3 |
+
import IconCube from "~icons/carbon/cube";
|
4 |
+
|
5 |
interface Props {
|
6 |
+
model: Model | CustomModel;
|
7 |
+
orgName?: string | undefined;
|
8 |
size?: "sm" | "md";
|
9 |
}
|
10 |
|
11 |
+
let { model, orgName = undefined, size = "md" }: Props = $props();
|
12 |
|
13 |
let sizeClass = $derived(size === "sm" ? "size-3" : "size-4");
|
14 |
+
let isCustom = $derived(isCustomModel(model));
|
15 |
+
let _orgName = $derived(orgName ?? (!isCustom ? model.id.split("/")[0] : undefined));
|
16 |
|
17 |
async function getAvatarUrl(orgName?: string) {
|
18 |
if (!orgName) return;
|
|
|
28 |
}
|
29 |
</script>
|
30 |
|
31 |
+
{#if isCustom}
|
32 |
+
<div
|
33 |
+
class="{sizeClass} grid place-items-center rounded-sm bg-gray-500/10 text-gray-500 dark:bg-gray-500/20 dark:text-gray-300"
|
34 |
+
>
|
35 |
+
<IconCube class="size-full p-0.5" />
|
36 |
+
</div>
|
37 |
+
{:else}
|
38 |
+
{#await getAvatarUrl(_orgName)}
|
39 |
+
<div class="{sizeClass} flex-none rounded-sm bg-gray-200"></div>
|
40 |
+
{:then avatarUrl}
|
41 |
+
{#if avatarUrl}
|
42 |
+
<img class="{sizeClass} flex-none rounded-sm bg-gray-200 object-cover" src={avatarUrl} alt="{_orgName} avatar" />
|
43 |
+
{:else}
|
44 |
+
<div class="{sizeClass} flex-none rounded-sm bg-gray-200"></div>
|
45 |
+
{/if}
|
46 |
+
{:catch}
|
47 |
<div class="{sizeClass} flex-none rounded-sm bg-gray-200"></div>
|
48 |
+
{/await}
|
49 |
+
{/if}
|
|
|
|
src/lib/components/debug-menu.svelte
CHANGED
@@ -10,6 +10,7 @@
|
|
10 |
import { addToast } from "./toaster.svelte.js";
|
11 |
import { models } from "$lib/state/models.svelte";
|
12 |
import { last } from "$lib/utils/array.js";
|
|
|
13 |
|
14 |
let innerWidth = $state<number>();
|
15 |
let innerHeight = $state<number>();
|
@@ -95,6 +96,17 @@
|
|
95 |
addToast(toastData[Math.floor(Math.random() * toastData.length)]!);
|
96 |
},
|
97 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
].toSorted((a, b) => compareStr(a.label, b.label));
|
99 |
</script>
|
100 |
|
|
|
10 |
import { addToast } from "./toaster.svelte.js";
|
11 |
import { models } from "$lib/state/models.svelte";
|
12 |
import { last } from "$lib/utils/array.js";
|
13 |
+
import { openCustomModelConfig } from "./inference-playground/custom-model-config.svelte";
|
14 |
|
15 |
let innerWidth = $state<number>();
|
16 |
let innerHeight = $state<number>();
|
|
|
96 |
addToast(toastData[Math.floor(Math.random() * toastData.length)]!);
|
97 |
},
|
98 |
},
|
99 |
+
{
|
100 |
+
label: "Pre-filled custom model config",
|
101 |
+
cb: () => {
|
102 |
+
openCustomModelConfig({
|
103 |
+
model: {
|
104 |
+
id: "google/gemini-2.0-flash-001",
|
105 |
+
endpointUrl: "https://openrouter.ai/api",
|
106 |
+
},
|
107 |
+
});
|
108 |
+
},
|
109 |
+
},
|
110 |
].toSorted((a, b) => compareStr(a.label, b.label));
|
111 |
</script>
|
112 |
|
src/lib/components/icon-provider.svelte
CHANGED
@@ -30,7 +30,7 @@
|
|
30 |
fill="#EE7624"
|
31 |
></path></svg
|
32 |
>
|
33 |
-
{:else if provider === "fal"}
|
34 |
<svg
|
35 |
class="text-lg"
|
36 |
xmlns="http://www.w3.org/2000/svg"
|
@@ -298,6 +298,24 @@
|
|
298 |
fill="#814D00"
|
299 |
></path></svg
|
300 |
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
{:else if children}{@render children()}{:else}
|
302 |
<div class="size-4 flex-none rounded-sm bg-gray-200"></div>
|
303 |
{/if}
|
|
|
30 |
fill="#EE7624"
|
31 |
></path></svg
|
32 |
>
|
33 |
+
{:else if provider === "fal" || provider === "fal-ai"}
|
34 |
<svg
|
35 |
class="text-lg"
|
36 |
xmlns="http://www.w3.org/2000/svg"
|
|
|
298 |
fill="#814D00"
|
299 |
></path></svg
|
300 |
>
|
301 |
+
{:else if provider === "openai"}
|
302 |
+
<svg
|
303 |
+
class="text-lg"
|
304 |
+
aria-hidden="true"
|
305 |
+
focusable="false"
|
306 |
+
width="1em"
|
307 |
+
height="1em"
|
308 |
+
viewBox="0 0 24 24"
|
309 |
+
role="img"
|
310 |
+
xmlns="http://www.w3.org/2000/svg"
|
311 |
+
preserveAspectRatio="xMidYMid meet"
|
312 |
+
fill="currentColor"
|
313 |
+
>
|
314 |
+
<title>OpenAI icon</title>
|
315 |
+
<path
|
316 |
+
d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"
|
317 |
+
/>
|
318 |
+
</svg>
|
319 |
{:else if children}{@render children()}{:else}
|
320 |
<div class="size-4 flex-none rounded-sm bg-gray-200"></div>
|
321 |
{/if}
|
src/lib/components/inference-playground/code-snippets.svelte
CHANGED
@@ -1,17 +1,18 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import
|
3 |
-
|
|
|
|
|
|
|
|
|
4 |
import hljs from "highlight.js/lib/core";
|
5 |
import http from "highlight.js/lib/languages/http";
|
6 |
import javascript from "highlight.js/lib/languages/javascript";
|
7 |
import python from "highlight.js/lib/languages/python";
|
8 |
import { createEventDispatcher } from "svelte";
|
9 |
-
|
10 |
-
import { token } from "$lib/state/token.svelte.js";
|
11 |
-
import { entries, fromEntries, keys } from "$lib/utils/object.js";
|
12 |
-
import type { InferenceProvider } from "@huggingface/inference";
|
13 |
import IconExternal from "~icons/carbon/arrow-up-right";
|
14 |
-
import
|
|
|
15 |
import { getInferenceSnippet, type GetInferenceSnippetReturn, type InferenceSnippetLanguage } from "./utils.js";
|
16 |
|
17 |
hljs.registerLanguage("javascript", javascript);
|
@@ -42,7 +43,40 @@
|
|
42 |
lang: InferenceSnippetLanguage;
|
43 |
};
|
44 |
function getSnippet({ tokenStr, conversation, lang }: GetSnippetArgs) {
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
messages: conversation.messages,
|
47 |
streaming: conversation.streaming,
|
48 |
max_tokens: conversation.config.max_tokens,
|
@@ -66,78 +100,55 @@
|
|
66 |
docs: string;
|
67 |
};
|
68 |
|
69 |
-
function getTokenStr(showToken: boolean) {
|
70 |
-
if (token.value && showToken) {
|
71 |
-
return token.value;
|
72 |
-
}
|
73 |
-
return "YOUR_HF_TOKEN";
|
74 |
-
}
|
75 |
-
|
76 |
function highlight(code?: string, language?: InferenceSnippetLanguage) {
|
|
|
77 |
if (!code || !language) return "";
|
78 |
return hljs.highlight(code, { language: language === "curl" ? "http" : language }).value;
|
79 |
}
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
|
85 |
-
|
86 |
-
content = _content ?? "";
|
87 |
}
|
88 |
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
timeout = setTimeout(() => {
|
94 |
-
el.classList.remove("text-green-500");
|
95 |
-
}, 400);
|
96 |
-
}
|
97 |
-
el.addEventListener("click", onClick);
|
98 |
-
|
99 |
-
return {
|
100 |
-
update,
|
101 |
-
destroy() {
|
102 |
-
clearTimeout(timeout);
|
103 |
-
el.removeEventListener("click", onClick);
|
104 |
-
},
|
105 |
-
};
|
106 |
-
}
|
107 |
-
let tokenStr = $derived(getTokenStr(showToken));
|
108 |
-
let snippetsByLang = $derived({
|
109 |
javascript: getSnippet({ lang: "js", tokenStr, conversation }),
|
110 |
python: getSnippet({ lang: "python", tokenStr, conversation }),
|
111 |
http: getSnippet({ lang: "curl", tokenStr, conversation }),
|
112 |
} as Record<Language, GetInferenceSnippetReturn>);
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
}
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
}
|
139 |
-
}
|
140 |
-
);
|
141 |
</script>
|
142 |
|
143 |
<div class="px-2 pt-2">
|
@@ -198,12 +209,21 @@
|
|
198 |
</a>
|
199 |
</h2>
|
200 |
<div class="flex items-center gap-x-4">
|
201 |
-
<
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
</div>
|
208 |
</div>
|
209 |
<pre
|
@@ -224,12 +244,21 @@
|
|
224 |
<input type="checkbox" bind:checked={showToken} />
|
225 |
<p class="leading-none">With token</p>
|
226 |
</label>
|
227 |
-
<
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
</div>
|
234 |
</div>
|
235 |
<pre
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { emptyModel } from "$lib/state/session.svelte.js";
|
3 |
+
import { token } from "$lib/state/token.svelte.js";
|
4 |
+
import { isConversationWithCustomModel, isCustomModel, PipelineTag, type Conversation } from "$lib/types.js";
|
5 |
+
import { copyToClipboard } from "$lib/utils/copy.js";
|
6 |
+
import { entries, fromEntries, keys } from "$lib/utils/object.js";
|
7 |
+
import type { InferenceProvider } from "@huggingface/inference";
|
8 |
import hljs from "highlight.js/lib/core";
|
9 |
import http from "highlight.js/lib/languages/http";
|
10 |
import javascript from "highlight.js/lib/languages/javascript";
|
11 |
import python from "highlight.js/lib/languages/python";
|
12 |
import { createEventDispatcher } from "svelte";
|
|
|
|
|
|
|
|
|
13 |
import IconExternal from "~icons/carbon/arrow-up-right";
|
14 |
+
import IconCopy from "~icons/carbon/copy";
|
15 |
+
import LocalToasts from "../local-toasts.svelte";
|
16 |
import { getInferenceSnippet, type GetInferenceSnippetReturn, type InferenceSnippetLanguage } from "./utils.js";
|
17 |
|
18 |
hljs.registerLanguage("javascript", javascript);
|
|
|
43 |
lang: InferenceSnippetLanguage;
|
44 |
};
|
45 |
function getSnippet({ tokenStr, conversation, lang }: GetSnippetArgs) {
|
46 |
+
const model = conversation.model;
|
47 |
+
if (isCustomModel(model)) {
|
48 |
+
const snippets = getInferenceSnippet(
|
49 |
+
{
|
50 |
+
...emptyModel,
|
51 |
+
_id: model._id,
|
52 |
+
id: model.id,
|
53 |
+
pipeline_tag: PipelineTag.TextGeneration,
|
54 |
+
tags: ["conversational"],
|
55 |
+
},
|
56 |
+
"hf-inference",
|
57 |
+
lang,
|
58 |
+
tokenStr,
|
59 |
+
{
|
60 |
+
messages: conversation.messages,
|
61 |
+
streaming: conversation.streaming,
|
62 |
+
max_tokens: conversation.config.max_tokens,
|
63 |
+
temperature: conversation.config.temperature,
|
64 |
+
top_p: conversation.config.top_p,
|
65 |
+
}
|
66 |
+
);
|
67 |
+
return snippets
|
68 |
+
.filter(s => s.client.startsWith("open") || lang === "curl")
|
69 |
+
.map(s => {
|
70 |
+
return {
|
71 |
+
...s,
|
72 |
+
content: s.content
|
73 |
+
.replaceAll("https://router.huggingface.co/hf-inference/v1", model.endpointUrl)
|
74 |
+
.replaceAll(`https://router.huggingface.co/hf-inference/models/${model.id}/v1`, model.endpointUrl),
|
75 |
+
};
|
76 |
+
});
|
77 |
+
}
|
78 |
+
|
79 |
+
return getInferenceSnippet(model, conversation.provider as InferenceProvider, lang, tokenStr, {
|
80 |
messages: conversation.messages,
|
81 |
streaming: conversation.streaming,
|
82 |
max_tokens: conversation.config.max_tokens,
|
|
|
100 |
docs: string;
|
101 |
};
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
function highlight(code?: string, language?: InferenceSnippetLanguage) {
|
104 |
+
console.log({ code, language });
|
105 |
if (!code || !language) return "";
|
106 |
return hljs.highlight(code, { language: language === "curl" ? "http" : language }).value;
|
107 |
}
|
108 |
|
109 |
+
const tokenStr = $derived.by(() => {
|
110 |
+
if (isConversationWithCustomModel(conversation)) {
|
111 |
+
const t = conversation.model.accessToken;
|
112 |
|
113 |
+
return t && showToken ? t : "YOUR_ACCESS_TOKEN";
|
|
|
114 |
}
|
115 |
|
116 |
+
return token.value && showToken ? token.value : "YOUR_HF_TOKEN";
|
117 |
+
});
|
118 |
+
|
119 |
+
const snippetsByLang = $derived({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
javascript: getSnippet({ lang: "js", tokenStr, conversation }),
|
121 |
python: getSnippet({ lang: "python", tokenStr, conversation }),
|
122 |
http: getSnippet({ lang: "curl", tokenStr, conversation }),
|
123 |
} as Record<Language, GetInferenceSnippetReturn>);
|
124 |
+
|
125 |
+
const selectedSnippet = $derived(snippetsByLang[lang][selectedSnippetIdxByLang[lang]]);
|
126 |
+
|
127 |
+
const installInstructions = $derived.by(function getInstallInstructions(): InstallInstructions | undefined {
|
128 |
+
if (lang === "javascript") {
|
129 |
+
const isHugging = selectedSnippet?.client.includes("hugging");
|
130 |
+
const toInstall = isHugging ? "@huggingface/inference" : "openai";
|
131 |
+
const docs = isHugging
|
132 |
+
? "https://huggingface.co/docs/huggingface.js/inference/README"
|
133 |
+
: "https://platform.openai.com/docs/libraries";
|
134 |
+
return {
|
135 |
+
title: `Install ${toInstall}`,
|
136 |
+
content: `npm install --save ${toInstall}`,
|
137 |
+
docs,
|
138 |
+
};
|
139 |
+
} else if (lang === "python") {
|
140 |
+
const isHugging = selectedSnippet?.client.includes("hugging");
|
141 |
+
const toInstall = isHugging ? "huggingface_hub" : "openai";
|
142 |
+
const docs = isHugging
|
143 |
+
? "https://huggingface.co/docs/huggingface_hub/guides/inference"
|
144 |
+
: "https://platform.openai.com/docs/libraries";
|
145 |
+
return {
|
146 |
+
title: `Install the latest`,
|
147 |
+
content: `pip install --upgrade ${toInstall}`,
|
148 |
+
docs,
|
149 |
+
};
|
150 |
+
}
|
151 |
+
});
|
152 |
</script>
|
153 |
|
154 |
<div class="px-2 pt-2">
|
|
|
209 |
</a>
|
210 |
</h2>
|
211 |
<div class="flex items-center gap-x-4">
|
212 |
+
<LocalToasts>
|
213 |
+
{#snippet children({ addToast, trigger })}
|
214 |
+
<button
|
215 |
+
{...trigger}
|
216 |
+
class="btn flex h-auto items-center gap-2 px-2 py-1.5 text-xs"
|
217 |
+
onclick={() => {
|
218 |
+
copyToClipboard(installInstructions.content);
|
219 |
+
addToast({ data: { content: "Copied to clipboard", variant: "info" } });
|
220 |
+
}}
|
221 |
+
>
|
222 |
+
<IconCopy />
|
223 |
+
Copy code
|
224 |
+
</button>
|
225 |
+
{/snippet}
|
226 |
+
</LocalToasts>
|
227 |
</div>
|
228 |
</div>
|
229 |
<pre
|
|
|
244 |
<input type="checkbox" bind:checked={showToken} />
|
245 |
<p class="leading-none">With token</p>
|
246 |
</label>
|
247 |
+
<LocalToasts>
|
248 |
+
{#snippet children({ addToast, trigger })}
|
249 |
+
<button
|
250 |
+
{...trigger}
|
251 |
+
class="btn flex h-auto items-center gap-2 px-2 py-1.5 text-xs"
|
252 |
+
onclick={() => {
|
253 |
+
copyToClipboard(selectedSnippet?.content ?? "");
|
254 |
+
addToast({ data: { content: "Copied to clipboard", variant: "info" } });
|
255 |
+
}}
|
256 |
+
>
|
257 |
+
<IconCopy />
|
258 |
+
Copy code
|
259 |
+
</button>
|
260 |
+
{/snippet}
|
261 |
+
</LocalToasts>
|
262 |
</div>
|
263 |
</div>
|
264 |
<pre
|
src/lib/components/inference-playground/conversation-header.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type
|
3 |
|
4 |
import { createEventDispatcher } from "svelte";
|
5 |
|
@@ -42,9 +42,10 @@
|
|
42 |
? 'mr-4 max-sm:ml-4'
|
43 |
: 'mx-4'} flex h-11 flex-none items-center gap-2 rounded-lg border border-gray-200/80 bg-white pr-2 pl-3 text-sm leading-none whitespace-nowrap shadow-xs *:flex-none max-sm:mt-4 dark:border-white/5 dark:bg-gray-800/70 dark:hover:bg-gray-800"
|
44 |
>
|
45 |
-
<Avatar orgName={nameSpace} size="md" />
|
46 |
-
<button
|
47 |
-
|
|
|
48 |
>
|
49 |
<button
|
50 |
class="borderdark:border-white/5 flex size-6 items-center justify-center rounded-sm bg-gray-50 text-xs hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600"
|
@@ -63,13 +64,15 @@
|
|
63 |
</button>
|
64 |
</div>
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { isConversationWithHFModel, type Conversation, type ModelWithTokenizer } from "$lib/types.js";
|
3 |
|
4 |
import { createEventDispatcher } from "svelte";
|
5 |
|
|
|
42 |
? 'mr-4 max-sm:ml-4'
|
43 |
: 'mx-4'} flex h-11 flex-none items-center gap-2 rounded-lg border border-gray-200/80 bg-white pr-2 pl-3 text-sm leading-none whitespace-nowrap shadow-xs *:flex-none max-sm:mt-4 dark:border-white/5 dark:bg-gray-800/70 dark:hover:bg-gray-800"
|
44 |
>
|
45 |
+
<Avatar model={conversation.model} orgName={nameSpace} size="md" />
|
46 |
+
<button
|
47 |
+
class="focus-outline flex-1! self-stretch text-left hover:underline"
|
48 |
+
onclick={() => (modelSelectorOpen = true)}>{conversation.model.id}</button
|
49 |
>
|
50 |
<button
|
51 |
class="borderdark:border-white/5 flex size-6 items-center justify-center rounded-sm bg-gray-50 text-xs hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600"
|
|
|
64 |
</button>
|
65 |
</div>
|
66 |
|
67 |
+
{#if isConversationWithHFModel(conversation)}
|
68 |
+
<div
|
69 |
+
class="{conversationIdx === 0
|
70 |
+
? 'mr-4 max-sm:ml-4'
|
71 |
+
: 'mx-4'} mt-2 h-11 text-sm leading-none whitespace-nowrap max-sm:mt-4"
|
72 |
+
>
|
73 |
+
<ProviderSelect
|
74 |
+
bind:conversation
|
75 |
+
class="rounded-lg border border-gray-200/80 bg-white dark:border-white/5 dark:bg-gray-800/70 dark:hover:bg-gray-800"
|
76 |
+
/>
|
77 |
+
</div>
|
78 |
+
{/if}
|
src/lib/components/inference-playground/conversation.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type
|
3 |
|
4 |
import { ScrollState } from "$lib/spells/scroll-state.svelte";
|
5 |
import { watch } from "runed";
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { type Conversation } from "$lib/types.js";
|
3 |
|
4 |
import { ScrollState } from "$lib/spells/scroll-state.svelte";
|
5 |
import { watch } from "runed";
|
src/lib/components/inference-playground/custom-model-config.svelte
ADDED
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts" module>
|
2 |
+
let model = $state<Partial<CustomModel> | undefined>(undefined);
|
3 |
+
let onSubmit = $state<OpenCustomModelConfigArgs["onSubmit"]>();
|
4 |
+
|
5 |
+
type OpenCustomModelConfigArgs = {
|
6 |
+
model?: typeof model;
|
7 |
+
onSubmit?: (model: CustomModel) => void;
|
8 |
+
onDelete?: () => void;
|
9 |
+
};
|
10 |
+
|
11 |
+
export function openCustomModelConfig(args?: OpenCustomModelConfigArgs) {
|
12 |
+
model = $state.snapshot(args?.model ?? {});
|
13 |
+
onSubmit = args?.onSubmit;
|
14 |
+
}
|
15 |
+
|
16 |
+
function close() {
|
17 |
+
model = undefined;
|
18 |
+
onSubmit = undefined;
|
19 |
+
}
|
20 |
+
</script>
|
21 |
+
|
22 |
+
<script lang="ts">
|
23 |
+
import { autofocus } from "$lib/actions/autofocus.js";
|
24 |
+
|
25 |
+
import { clickOutside } from "$lib/actions/click-outside.js";
|
26 |
+
import { models } from "$lib/state/models.svelte";
|
27 |
+
import { type Conversation, type CustomModel } from "$lib/types.js";
|
28 |
+
import type { HTMLFormAttributes } from "svelte/elements";
|
29 |
+
import { fade, scale } from "svelte/transition";
|
30 |
+
import IconCross from "~icons/carbon/close";
|
31 |
+
import typia from "typia";
|
32 |
+
import { handleNonStreamingResponse } from "./utils.js";
|
33 |
+
|
34 |
+
let dialog: HTMLDialogElement | undefined = $state();
|
35 |
+
const exists = $derived(!!models.custom.find(m => m._id === model?._id));
|
36 |
+
|
37 |
+
$effect(() => {
|
38 |
+
if (model !== undefined) {
|
39 |
+
dialog?.showModal();
|
40 |
+
} else {
|
41 |
+
setTimeout(() => {
|
42 |
+
dialog?.close();
|
43 |
+
clear();
|
44 |
+
}, 250);
|
45 |
+
}
|
46 |
+
});
|
47 |
+
|
48 |
+
type Message = {
|
49 |
+
type: "error" | "success";
|
50 |
+
content: string;
|
51 |
+
};
|
52 |
+
let message = $state<Message | null>(null);
|
53 |
+
|
54 |
+
const error = (content: string) => (message = { type: "error", content }) satisfies Message;
|
55 |
+
const success = (content: string) => (message = { type: "success", content }) satisfies Message;
|
56 |
+
const clear = () => (message = null);
|
57 |
+
|
58 |
+
const onsubmit: HTMLFormAttributes["onsubmit"] = async e => {
|
59 |
+
e.preventDefault();
|
60 |
+
clear();
|
61 |
+
const isTest = e.submitter?.dataset.form === "test";
|
62 |
+
if (isTest) {
|
63 |
+
testing = true;
|
64 |
+
|
65 |
+
const conv: Conversation = {
|
66 |
+
model: {
|
67 |
+
...model,
|
68 |
+
_id: "",
|
69 |
+
/** These will never be empty, because of our form validation */
|
70 |
+
id: model?.id ?? "",
|
71 |
+
endpointUrl: model?.endpointUrl ?? "",
|
72 |
+
},
|
73 |
+
messages: [
|
74 |
+
{
|
75 |
+
role: "user",
|
76 |
+
content: "test",
|
77 |
+
},
|
78 |
+
],
|
79 |
+
config: {},
|
80 |
+
systemMessage: { role: "system", content: "" },
|
81 |
+
streaming: false,
|
82 |
+
};
|
83 |
+
try {
|
84 |
+
await handleNonStreamingResponse(conv);
|
85 |
+
success("Test successful!");
|
86 |
+
} catch (err) {
|
87 |
+
if (err instanceof Error) {
|
88 |
+
error(`Test failed: ${err.message}`);
|
89 |
+
} else {
|
90 |
+
error(`An unknown error occurred during testing.`);
|
91 |
+
}
|
92 |
+
} finally {
|
93 |
+
testing = false;
|
94 |
+
}
|
95 |
+
} else {
|
96 |
+
const withUUID = { _id: crypto.randomUUID(), ...model };
|
97 |
+
if (!typia.is<CustomModel>(withUUID)) return;
|
98 |
+
models.upsertCustom(withUUID);
|
99 |
+
onSubmit?.(withUUID);
|
100 |
+
model = undefined;
|
101 |
+
}
|
102 |
+
};
|
103 |
+
|
104 |
+
let testing = $state(false);
|
105 |
+
</script>
|
106 |
+
|
107 |
+
<dialog class="backdrop:bg-transparent" bind:this={dialog} onclose={() => close()}>
|
108 |
+
{#if model !== undefined}
|
109 |
+
<!-- Backdrop -->
|
110 |
+
<div
|
111 |
+
class="fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-black/50 backdrop-blur-sm"
|
112 |
+
transition:fade={{ duration: 150 }}
|
113 |
+
>
|
114 |
+
<!-- Content -->
|
115 |
+
<form
|
116 |
+
class="relative w-xl rounded-xl bg-white shadow-sm dark:bg-gray-900"
|
117 |
+
use:clickOutside={() => close()}
|
118 |
+
transition:scale={{ start: 0.975, duration: 250 }}
|
119 |
+
{onsubmit}
|
120 |
+
>
|
121 |
+
<div class="flex items-center justify-between rounded-t border-b p-4 md:px-5 md:py-4 dark:border-gray-800">
|
122 |
+
<h2 class="flex items-center gap-2.5 text-lg font-semibold text-gray-900 dark:text-white">
|
123 |
+
Configure custom endpoint
|
124 |
+
</h2>
|
125 |
+
<button
|
126 |
+
type="button"
|
127 |
+
class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white"
|
128 |
+
onclick={close}
|
129 |
+
>
|
130 |
+
<div class="text-xl">
|
131 |
+
<IconCross />
|
132 |
+
</div>
|
133 |
+
<span class="sr-only">Close modal</span>
|
134 |
+
</button>
|
135 |
+
</div>
|
136 |
+
<!-- Modal body -->
|
137 |
+
<div class="flex flex-col gap-3 p-4 md:p-5">
|
138 |
+
<label class="flex flex-col gap-2">
|
139 |
+
<p class="block text-sm font-medium text-gray-900 dark:text-white">
|
140 |
+
Model ID <span class="text-red-800 dark:text-red-300">*</span>
|
141 |
+
</p>
|
142 |
+
<input
|
143 |
+
use:autofocus
|
144 |
+
bind:value={model.id}
|
145 |
+
required
|
146 |
+
placeholder="e.g. mistralai/mistral-large-2407"
|
147 |
+
type="text"
|
148 |
+
class="input block w-full"
|
149 |
+
/>
|
150 |
+
</label>
|
151 |
+
<label class="flex flex-col gap-2">
|
152 |
+
<p class="block text-sm font-medium text-gray-900 dark:text-white">
|
153 |
+
Endpoint URL <span class="text-red-800 dark:text-red-300">*</span>
|
154 |
+
</p>
|
155 |
+
<input
|
156 |
+
bind:value={model.endpointUrl}
|
157 |
+
placeholder="e.g. https://your-provider.com/api/v1"
|
158 |
+
required
|
159 |
+
type="text"
|
160 |
+
class="input block w-full"
|
161 |
+
/>
|
162 |
+
</label>
|
163 |
+
<label class="flex flex-col gap-2">
|
164 |
+
<p class="block text-sm font-medium text-gray-900 dark:text-white">Access Token</p>
|
165 |
+
<input
|
166 |
+
bind:value={model.accessToken}
|
167 |
+
placeholder="XXXXXXXXXXXXXXXXXXXX"
|
168 |
+
type="text"
|
169 |
+
class="input block w-full"
|
170 |
+
/>
|
171 |
+
<p class="text-sm text-gray-500">Stored locally - not sent to our server</p>
|
172 |
+
</label>
|
173 |
+
|
174 |
+
{#if message}
|
175 |
+
<div
|
176 |
+
class={[
|
177 |
+
"mt-2 rounded-lg border p-3 text-sm",
|
178 |
+
message.type === "error" &&
|
179 |
+
"border-red-400 bg-red-100 text-red-700 dark:border-red-600 dark:bg-red-900/30 dark:text-red-300",
|
180 |
+
message.type === "success" &&
|
181 |
+
"border-green-400 bg-green-100 text-green-700 dark:border-green-600 dark:bg-green-900/30 dark:text-green-300",
|
182 |
+
]}
|
183 |
+
role="alert"
|
184 |
+
>
|
185 |
+
{message.content}
|
186 |
+
</div>
|
187 |
+
{/if}
|
188 |
+
</div>
|
189 |
+
|
190 |
+
<!-- Modal footer -->
|
191 |
+
<div class="flex gap-2 rounded-b border-t border-gray-200 p-4 md:p-5 dark:border-gray-800">
|
192 |
+
{#if exists}
|
193 |
+
<button
|
194 |
+
type="button"
|
195 |
+
class="rounded-lg bg-red-100 px-5 py-2.5 text-sm font-medium text-red-700 hover:bg-red-200 focus:ring-4 focus:ring-red-300 focus:outline-none dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/40 dark:focus:ring-red-900"
|
196 |
+
onclick={() => {
|
197 |
+
if (model?._id) models.removeCustom(model._id);
|
198 |
+
close();
|
199 |
+
}}
|
200 |
+
disabled={testing}
|
201 |
+
>
|
202 |
+
Delete
|
203 |
+
</button>
|
204 |
+
{/if}
|
205 |
+
<!-- Reverse flex so that submit is the button called on enter -->
|
206 |
+
<div class="ml-auto flex flex-row-reverse items-center gap-2">
|
207 |
+
<button
|
208 |
+
data-form="submit"
|
209 |
+
type="submit"
|
210 |
+
class="rounded-lg bg-black px-5 py-2.5 text-sm font-medium text-white
|
211 |
+
hover:bg-gray-900 focus:ring-4 focus:ring-gray-300 focus:outline-none
|
212 |
+
disabled:!bg-black dark:border-gray-700
|
213 |
+
dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:disabled:!bg-gray-800"
|
214 |
+
disabled={testing}
|
215 |
+
>
|
216 |
+
Submit
|
217 |
+
</button>
|
218 |
+
<button
|
219 |
+
data-form="test"
|
220 |
+
type="submit"
|
221 |
+
class="flex items-center rounded-lg bg-black px-5 py-2.5 text-sm font-medium text-white
|
222 |
+
hover:bg-gray-900 focus:ring-4 focus:ring-gray-300 focus:outline-none
|
223 |
+
disabled:!bg-black dark:border-gray-700
|
224 |
+
dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:disabled:!bg-gray-800"
|
225 |
+
disabled={testing}
|
226 |
+
>
|
227 |
+
{#if testing}
|
228 |
+
<svg
|
229 |
+
class="mr-2 h-4 w-4 animate-spin text-white"
|
230 |
+
xmlns="http://www.w3.org/2000/svg"
|
231 |
+
fill="none"
|
232 |
+
viewBox="0 0 24 24"
|
233 |
+
>
|
234 |
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
235 |
+
<path
|
236 |
+
class="opacity-75"
|
237 |
+
fill="currentColor"
|
238 |
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
239 |
+
></path>
|
240 |
+
</svg>
|
241 |
+
Testing...
|
242 |
+
{:else}
|
243 |
+
Test
|
244 |
+
{/if}
|
245 |
+
</button>
|
246 |
+
</div>
|
247 |
+
</div>
|
248 |
+
</form>
|
249 |
+
</div>
|
250 |
+
{/if}
|
251 |
+
</dialog>
|
src/lib/components/inference-playground/custom-provider-select.svelte
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { randomPick } from "$lib/utils/array.js";
|
3 |
+
import { cn } from "$lib/utils/cn.js";
|
4 |
+
import { INFERENCE_PROVIDERS, type InferenceProvider } from "@huggingface/inference";
|
5 |
+
import { Select } from "melt/builders";
|
6 |
+
import { onMount } from "svelte";
|
7 |
+
import IconCaret from "~icons/carbon/chevron-down";
|
8 |
+
import IconProvider from "../icon-provider.svelte";
|
9 |
+
|
10 |
+
const providers = [...INFERENCE_PROVIDERS];
|
11 |
+
|
12 |
+
interface Props {
|
13 |
+
provider?: InferenceProvider;
|
14 |
+
class?: string;
|
15 |
+
}
|
16 |
+
|
17 |
+
let { provider = $bindable(), class: classes = undefined }: Props = $props();
|
18 |
+
|
19 |
+
function reset() {
|
20 |
+
if (provider !== undefined) return;
|
21 |
+
provider = randomPick(providers);
|
22 |
+
}
|
23 |
+
|
24 |
+
onMount(reset);
|
25 |
+
|
26 |
+
const select = new Select<InferenceProvider, false>({
|
27 |
+
value: () => provider,
|
28 |
+
onValueChange(v) {
|
29 |
+
provider = v;
|
30 |
+
},
|
31 |
+
});
|
32 |
+
|
33 |
+
const nameMap: Record<InferenceProvider, string> = {
|
34 |
+
"sambanova": "SambaNova",
|
35 |
+
"fal-ai": "fal",
|
36 |
+
"cerebras": "Cerebras",
|
37 |
+
"replicate": "Replicate",
|
38 |
+
"black-forest-labs": "Black Forest Labs",
|
39 |
+
"fireworks-ai": "Fireworks",
|
40 |
+
"together": "Together AI",
|
41 |
+
"nebius": "Nebius AI Studio",
|
42 |
+
"hyperbolic": "Hyperbolic",
|
43 |
+
"novita": "Novita",
|
44 |
+
"cohere": "Nohere",
|
45 |
+
"hf-inference": "HF Inference API",
|
46 |
+
"openai": "OpenAI Compatible",
|
47 |
+
};
|
48 |
+
const UPPERCASE_WORDS = ["hf", "ai"];
|
49 |
+
|
50 |
+
function formatName(provider: InferenceProvider) {
|
51 |
+
if (provider in nameMap) return nameMap[provider];
|
52 |
+
|
53 |
+
const words = provider
|
54 |
+
.toLowerCase()
|
55 |
+
.split("-")
|
56 |
+
.map(word => {
|
57 |
+
if (UPPERCASE_WORDS.includes(word)) {
|
58 |
+
return word.toUpperCase();
|
59 |
+
} else {
|
60 |
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
61 |
+
}
|
62 |
+
});
|
63 |
+
|
64 |
+
return words.join(" ");
|
65 |
+
}
|
66 |
+
</script>
|
67 |
+
|
68 |
+
<button
|
69 |
+
{...select.trigger}
|
70 |
+
class={cn(
|
71 |
+
"focus-outline relative flex items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm",
|
72 |
+
"hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110",
|
73 |
+
select.open && "!custom-outline",
|
74 |
+
classes
|
75 |
+
)}
|
76 |
+
type="button"
|
77 |
+
>
|
78 |
+
<div class="flex items-center gap-1 text-sm">
|
79 |
+
<IconProvider {provider} />
|
80 |
+
{provider && formatName(provider)}
|
81 |
+
</div>
|
82 |
+
<div
|
83 |
+
class="absolute right-2 grid size-4 flex-none place-items-center rounded-sm bg-gray-100 text-xs dark:bg-gray-600"
|
84 |
+
>
|
85 |
+
<IconCaret />
|
86 |
+
</div>
|
87 |
+
</button>
|
88 |
+
|
89 |
+
<div {...select.content} class="rounded-lg border bg-gray-100 outline-hidden dark:border-gray-700 dark:bg-gray-800">
|
90 |
+
{#each providers as p}
|
91 |
+
<button {...select.getOption(p)} class="group block w-full p-1 text-sm dark:text-white" type="button">
|
92 |
+
<div
|
93 |
+
class="flex items-center gap-2 rounded-md px-2 py-1.5 group-data-[highlighted]:bg-gray-200 dark:group-data-[highlighted]:bg-gray-700"
|
94 |
+
>
|
95 |
+
<IconProvider provider={p} />
|
96 |
+
{formatName(p)}
|
97 |
+
</div>
|
98 |
+
</button>
|
99 |
+
{/each}
|
100 |
+
</div>
|
src/lib/components/inference-playground/generation-config.svelte
CHANGED
@@ -11,9 +11,7 @@
|
|
11 |
|
12 |
let { conversation = $bindable(), classNames = "" }: Props = $props();
|
13 |
|
14 |
-
let modelMaxLength = $derived(
|
15 |
-
customMaxTokens[conversation.model.id] ?? conversation.model.tokenizerConfig.model_max_length
|
16 |
-
);
|
17 |
let maxTokens = $derived(Math.min(modelMaxLength ?? GENERATION_CONFIG_SETTINGS["max_tokens"].max, 64_000));
|
18 |
</script>
|
19 |
|
|
|
11 |
|
12 |
let { conversation = $bindable(), classNames = "" }: Props = $props();
|
13 |
|
14 |
+
let modelMaxLength = $derived(customMaxTokens[conversation.model.id] ?? 100000);
|
|
|
|
|
15 |
let maxTokens = $derived(Math.min(modelMaxLength ?? GENERATION_CONFIG_SETTINGS["max_tokens"].max, 64_000));
|
16 |
</script>
|
17 |
|
src/lib/components/inference-playground/hf-token-modal.svelte
CHANGED
@@ -81,9 +81,9 @@
|
|
81 |
><br /> Your token is kept safe by only being used from your browser.
|
82 |
</p>
|
83 |
<div>
|
84 |
-
<label for="hf-token" class="
|
85 |
-
|
86 |
-
>
|
87 |
<input
|
88 |
use:autofocus
|
89 |
required
|
|
|
81 |
><br /> Your token is kept safe by only being used from your browser.
|
82 |
</p>
|
83 |
<div>
|
84 |
+
<label for="hf-token" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white">
|
85 |
+
Hugging Face Token
|
86 |
+
</label>
|
87 |
<input
|
88 |
use:autofocus
|
89 |
required
|
src/lib/components/inference-playground/message.svelte
CHANGED
@@ -26,7 +26,9 @@
|
|
26 |
});
|
27 |
|
28 |
const canUploadImgs = $derived(
|
29 |
-
message.role === "user" &&
|
|
|
|
|
30 |
);
|
31 |
const fileUpload = new FileUpload({
|
32 |
accept: "image/*",
|
|
|
26 |
});
|
27 |
|
28 |
const canUploadImgs = $derived(
|
29 |
+
message.role === "user" &&
|
30 |
+
"pipeline_tag" in conversation.model &&
|
31 |
+
conversation.model.pipeline_tag === PipelineTag.ImageTextToText
|
32 |
);
|
33 |
const fileUpload = new FileUpload({
|
34 |
accept: "image/*",
|
src/lib/components/inference-playground/model-selector-modal.svelte
CHANGED
@@ -1,15 +1,21 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type { Conversation, ModelWithTokenizer } from "$lib/types.js";
|
3 |
-
|
4 |
-
import { tick } from "svelte";
|
5 |
-
|
6 |
import { autofocus } from "$lib/actions/autofocus.js";
|
7 |
import { models } from "$lib/state/models.svelte.js";
|
|
|
|
|
8 |
import fuzzysearch from "$lib/utils/search.js";
|
9 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
import IconSearch from "~icons/carbon/search";
|
11 |
import IconStar from "~icons/carbon/star";
|
12 |
import IconEye from "~icons/carbon/view";
|
|
|
|
|
13 |
|
14 |
interface Props {
|
15 |
onModelSelect?: (model: string) => void;
|
@@ -19,71 +25,35 @@
|
|
19 |
|
20 |
let { onModelSelect, onClose, conversation }: Props = $props();
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
let backdropEl = $state<HTMLDivElement>();
|
23 |
-
let highlightIdx = $state(-1);
|
24 |
-
let ignoreCursorHighlight = $state(false);
|
25 |
-
let containerEl = $state<HTMLDivElement>();
|
26 |
let query = $state("");
|
27 |
|
28 |
const trending = $derived(fuzzysearch({ needle: query, haystack: models.trending, property: "id" }));
|
29 |
const other = $derived(fuzzysearch({ needle: query, haystack: models.nonTrending, property: "id" }));
|
30 |
-
const
|
31 |
-
function getModelIdx(model: ModelWithTokenizer) {
|
32 |
-
return queried.findIndex(m => m.id === model.id);
|
33 |
-
}
|
34 |
-
const highlighted = $derived(queried[highlightIdx]);
|
35 |
-
|
36 |
-
watch(
|
37 |
-
() => queried,
|
38 |
-
(curr, prev) => {
|
39 |
-
const prevModel = prev?.[highlightIdx];
|
40 |
-
if (prevModel) {
|
41 |
-
// maintain model selection
|
42 |
-
highlightIdx = Math.max(
|
43 |
-
0,
|
44 |
-
curr.findIndex(model => model.id === prevModel?.id)
|
45 |
-
);
|
46 |
-
} else {
|
47 |
-
highlightIdx = curr.findIndex(model => model.id === conversation.model.id);
|
48 |
-
}
|
49 |
-
scrollToResult();
|
50 |
-
}
|
51 |
-
);
|
52 |
-
|
53 |
-
function selectModel(model: ModelWithTokenizer) {
|
54 |
-
onModelSelect?.(model.id);
|
55 |
-
onClose?.();
|
56 |
-
}
|
57 |
-
|
58 |
-
function handleKeydown(e: KeyboardEvent) {
|
59 |
-
if (e.key === "Escape") {
|
60 |
-
onClose?.();
|
61 |
-
} else if (e.key === "Enter") {
|
62 |
-
if (highlighted) selectModel(highlighted);
|
63 |
-
} else if (e.key === "ArrowUp") {
|
64 |
-
if (highlightIdx > 0) highlightIdx--;
|
65 |
-
ignoreCursorHighlight = true;
|
66 |
-
} else if (e.key === "ArrowDown") {
|
67 |
-
if (highlightIdx < queried.length - 1) highlightIdx++;
|
68 |
-
ignoreCursorHighlight = true;
|
69 |
-
} else {
|
70 |
-
return;
|
71 |
-
}
|
72 |
-
e.preventDefault();
|
73 |
-
|
74 |
-
scrollToResult();
|
75 |
-
}
|
76 |
-
|
77 |
-
async function scrollToResult() {
|
78 |
-
await tick();
|
79 |
-
const highlightedEl = document.querySelector("[data-model][data-highlighted]");
|
80 |
-
highlightedEl?.scrollIntoView({ block: "nearest" });
|
81 |
-
}
|
82 |
-
|
83 |
-
function highlightRow(idx: number) {
|
84 |
-
if (ignoreCursorHighlight) return;
|
85 |
-
highlightIdx = idx;
|
86 |
-
}
|
87 |
|
88 |
function handleBackdropClick(event: MouseEvent) {
|
89 |
event.stopPropagation();
|
@@ -94,9 +64,9 @@
|
|
94 |
onClose?.();
|
95 |
}
|
96 |
}
|
97 |
-
</script>
|
98 |
|
99 |
-
|
|
|
100 |
|
101 |
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
102 |
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
@@ -108,50 +78,93 @@
|
|
108 |
<div class="flex w-full max-w-[600px] items-start justify-center overflow-hidden p-10 text-left whitespace-nowrap">
|
109 |
<div
|
110 |
class="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"
|
111 |
-
bind:this={containerEl}
|
112 |
>
|
113 |
<div class="flex items-center border-b px-3 dark:border-gray-800">
|
114 |
<div class="mr-2 text-sm">
|
115 |
<IconSearch />
|
116 |
</div>
|
117 |
<input
|
|
|
118 |
use:autofocus
|
119 |
class="flex h-10 w-full rounded-md bg-transparent py-3 text-sm placeholder-gray-400 outline-hidden"
|
120 |
placeholder="Search models ..."
|
121 |
bind:value={query}
|
122 |
/>
|
123 |
</div>
|
124 |
-
<div class="max-h-[300px] overflow-x-hidden overflow-y-auto">
|
125 |
-
{#snippet modelEntry(model: ModelWithTokenizer, trending?: boolean)}
|
126 |
-
{@const idx = getModelIdx(model)}
|
127 |
{@const [nameSpace, modelName] = model.id.split("/")}
|
128 |
<button
|
129 |
class="flex w-full cursor-pointer items-center px-2 py-1.5 text-sm
|
130 |
data-[highlighted]:bg-gray-100 data-[highlighted]:dark:bg-gray-800"
|
131 |
-
data-highlighted={highlightIdx === idx ? true : undefined}
|
132 |
data-model
|
133 |
-
|
134 |
-
onclick={() => {
|
135 |
-
onModelSelect?.(model.id);
|
136 |
-
onClose?.();
|
137 |
-
}}
|
138 |
>
|
139 |
{#if trending}
|
140 |
<div class=" mr-1.5 size-4 text-yellow-400">
|
141 |
<IconStar />
|
142 |
</div>
|
143 |
{/if}
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
>
|
153 |
-
|
154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
{/if}
|
156 |
</button>
|
157 |
{/snippet}
|
@@ -161,6 +174,26 @@
|
|
161 |
{@render modelEntry(model, true)}
|
162 |
{/each}
|
163 |
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
{#if other.length > 0}
|
165 |
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Other models</div>
|
166 |
{#each other as model}
|
|
|
1 |
<script lang="ts">
|
|
|
|
|
|
|
|
|
2 |
import { autofocus } from "$lib/actions/autofocus.js";
|
3 |
import { models } from "$lib/state/models.svelte.js";
|
4 |
+
import type { Conversation, CustomModel, ModelWithTokenizer } from "$lib/types.js";
|
5 |
+
import { noop } from "$lib/utils/noop.js";
|
6 |
import fuzzysearch from "$lib/utils/search.js";
|
7 |
+
import { sleep } from "$lib/utils/sleep.js";
|
8 |
+
import { Combobox } from "melt/builders";
|
9 |
+
import { untrack } from "svelte";
|
10 |
+
import typia from "typia";
|
11 |
+
import IconAdd from "~icons/carbon/add";
|
12 |
+
import IconCube from "~icons/carbon/cube";
|
13 |
+
import IconEdit from "~icons/carbon/edit";
|
14 |
import IconSearch from "~icons/carbon/search";
|
15 |
import IconStar from "~icons/carbon/star";
|
16 |
import IconEye from "~icons/carbon/view";
|
17 |
+
import Tooltip from "../tooltip.svelte";
|
18 |
+
import { openCustomModelConfig } from "./custom-model-config.svelte";
|
19 |
|
20 |
interface Props {
|
21 |
onModelSelect?: (model: string) => void;
|
|
|
25 |
|
26 |
let { onModelSelect, onClose, conversation }: Props = $props();
|
27 |
|
28 |
+
const combobox = new Combobox({
|
29 |
+
onOpenChange(o) {
|
30 |
+
if (!o) onClose?.();
|
31 |
+
},
|
32 |
+
floatingConfig: {
|
33 |
+
onCompute: noop,
|
34 |
+
},
|
35 |
+
sameWidth: false,
|
36 |
+
value: () => undefined,
|
37 |
+
onValueChange(modelId) {
|
38 |
+
if (!modelId) return;
|
39 |
+
onModelSelect?.(modelId);
|
40 |
+
onClose?.();
|
41 |
+
},
|
42 |
+
});
|
43 |
+
$effect(() => {
|
44 |
+
untrack(() => combobox.highlight(conversation.model.id));
|
45 |
+
// Workaround while this component does not use a <dialog />
|
46 |
+
sleep(10).then(() => {
|
47 |
+
combobox.open = true;
|
48 |
+
});
|
49 |
+
});
|
50 |
+
|
51 |
let backdropEl = $state<HTMLDivElement>();
|
|
|
|
|
|
|
52 |
let query = $state("");
|
53 |
|
54 |
const trending = $derived(fuzzysearch({ needle: query, haystack: models.trending, property: "id" }));
|
55 |
const other = $derived(fuzzysearch({ needle: query, haystack: models.nonTrending, property: "id" }));
|
56 |
+
const custom = $derived(fuzzysearch({ needle: query, haystack: models.custom, property: "id" }));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
function handleBackdropClick(event: MouseEvent) {
|
59 |
event.stopPropagation();
|
|
|
64 |
onClose?.();
|
65 |
}
|
66 |
}
|
|
|
67 |
|
68 |
+
const isCustom = typia.createIs<CustomModel>();
|
69 |
+
</script>
|
70 |
|
71 |
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
72 |
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
|
78 |
<div class="flex w-full max-w-[600px] items-start justify-center overflow-hidden p-10 text-left whitespace-nowrap">
|
79 |
<div
|
80 |
class="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"
|
|
|
81 |
>
|
82 |
<div class="flex items-center border-b px-3 dark:border-gray-800">
|
83 |
<div class="mr-2 text-sm">
|
84 |
<IconSearch />
|
85 |
</div>
|
86 |
<input
|
87 |
+
{...combobox.input}
|
88 |
use:autofocus
|
89 |
class="flex h-10 w-full rounded-md bg-transparent py-3 text-sm placeholder-gray-400 outline-hidden"
|
90 |
placeholder="Search models ..."
|
91 |
bind:value={query}
|
92 |
/>
|
93 |
</div>
|
94 |
+
<div class="max-h-[300px] overflow-x-hidden overflow-y-auto" {...combobox.content} popover={undefined}>
|
95 |
+
{#snippet modelEntry(model: ModelWithTokenizer | CustomModel, trending?: boolean)}
|
|
|
96 |
{@const [nameSpace, modelName] = model.id.split("/")}
|
97 |
<button
|
98 |
class="flex w-full cursor-pointer items-center px-2 py-1.5 text-sm
|
99 |
data-[highlighted]:bg-gray-100 data-[highlighted]:dark:bg-gray-800"
|
|
|
100 |
data-model
|
101 |
+
{...combobox.getOption(model.id)}
|
|
|
|
|
|
|
|
|
102 |
>
|
103 |
{#if trending}
|
104 |
<div class=" mr-1.5 size-4 text-yellow-400">
|
105 |
<IconStar />
|
106 |
</div>
|
107 |
{/if}
|
108 |
+
|
109 |
+
{#if modelName}
|
110 |
+
<span class="inline-flex items-center">
|
111 |
+
<span class="text-gray-500 dark:text-gray-400">{nameSpace}</span>
|
112 |
+
<span class="mx-1 text-gray-300 dark:text-gray-700">/</span>
|
113 |
+
<span class="text-black dark:text-white">{modelName}</span>
|
114 |
+
</span>
|
115 |
+
{:else}
|
116 |
+
<span class="text-black dark:text-white">{nameSpace}</span>
|
117 |
+
{/if}
|
118 |
+
|
119 |
+
{#if "pipeline_tag" in model && model.pipeline_tag === "image-text-to-text"}
|
120 |
+
<Tooltip openDelay={100}>
|
121 |
+
{#snippet trigger(tooltip)}
|
122 |
+
<div
|
123 |
+
class="ml-2 grid size-5 place-items-center rounded bg-gray-500/10 text-gray-500 dark:bg-gray-500/20 dark:text-gray-300"
|
124 |
+
{...tooltip.trigger}
|
125 |
+
>
|
126 |
+
<IconEye class="size-3.5" />
|
127 |
+
</div>
|
128 |
+
{/snippet}
|
129 |
+
Image text-to-text
|
130 |
+
</Tooltip>
|
131 |
+
{/if}
|
132 |
+
|
133 |
+
{#if isCustom(model)}
|
134 |
+
<Tooltip openDelay={100}>
|
135 |
+
{#snippet trigger(tooltip)}
|
136 |
+
<div
|
137 |
+
class="ml-2 grid size-5 place-items-center rounded bg-gray-500/10 text-gray-500 dark:bg-gray-500/20 dark:text-gray-300"
|
138 |
+
{...tooltip.trigger}
|
139 |
+
>
|
140 |
+
<IconCube class="size-3.5" />
|
141 |
+
</div>
|
142 |
+
{/snippet}
|
143 |
+
Custom Model
|
144 |
+
</Tooltip>
|
145 |
+
<Tooltip>
|
146 |
+
{#snippet trigger(tooltip)}
|
147 |
+
<button
|
148 |
+
class="mr-1 ml-auto grid size-4.5 place-items-center rounded-sm bg-gray-100 text-xs
|
149 |
+
hover:bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-500"
|
150 |
+
aria-label="Add custom model"
|
151 |
+
{...tooltip.trigger}
|
152 |
+
onclick={e => {
|
153 |
+
e.stopPropagation();
|
154 |
+
onClose?.();
|
155 |
+
openCustomModelConfig({
|
156 |
+
model,
|
157 |
+
onSubmit: model => {
|
158 |
+
onModelSelect?.(model.id);
|
159 |
+
},
|
160 |
+
});
|
161 |
+
}}
|
162 |
+
>
|
163 |
+
<IconEdit class="size-3" />
|
164 |
+
</button>
|
165 |
+
{/snippet}
|
166 |
+
<span class="text-sm">Edit</span>
|
167 |
+
</Tooltip>
|
168 |
{/if}
|
169 |
</button>
|
170 |
{/snippet}
|
|
|
174 |
{@render modelEntry(model, true)}
|
175 |
{/each}
|
176 |
{/if}
|
177 |
+
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Custom endpoints</div>
|
178 |
+
{#if custom.length > 0}
|
179 |
+
{#each custom as model}
|
180 |
+
{@render modelEntry(model, false)}
|
181 |
+
{/each}
|
182 |
+
{/if}
|
183 |
+
<button
|
184 |
+
class="flex w-full cursor-pointer items-center gap-2 px-2 py-1.5 text-sm text-gray-500 data-[highlighted]:bg-blue-500/15 data-[highlighted]:text-blue-600 dark:text-gray-400 dark:data-[highlighted]:text-blue-300"
|
185 |
+
{...combobox.getOption("__custom__", () => {
|
186 |
+
onClose?.();
|
187 |
+
openCustomModelConfig({
|
188 |
+
onSubmit: model => {
|
189 |
+
onModelSelect?.(model.id);
|
190 |
+
},
|
191 |
+
});
|
192 |
+
})}
|
193 |
+
>
|
194 |
+
<IconAdd class="rounded bg-blue-500/10 text-blue-600" />
|
195 |
+
Add a custom endpoint
|
196 |
+
</button>
|
197 |
{#if other.length > 0}
|
198 |
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Other models</div>
|
199 |
{#each other as model}
|
src/lib/components/inference-playground/model-selector.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type
|
3 |
|
4 |
import { models } from "$lib/state/models.svelte.js";
|
5 |
import IconCaret from "~icons/carbon/chevron-down";
|
@@ -27,27 +27,28 @@
|
|
27 |
conversation.provider = undefined;
|
28 |
}
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
const
|
|
|
|
|
33 |
</script>
|
34 |
|
35 |
<div class="flex flex-col gap-2">
|
36 |
<label for={id} class="flex items-baseline gap-2 text-sm font-medium text-gray-900 dark:text-white">
|
37 |
Models<span class="text-xs font-normal text-gray-400">{models.all.length}</span>
|
38 |
</label>
|
39 |
-
|
40 |
<button
|
41 |
{id}
|
42 |
-
class="relative flex items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110"
|
43 |
onclick={() => (showModelPickerModal = true)}
|
44 |
>
|
45 |
-
<div class="
|
46 |
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
|
47 |
-
<Avatar orgName={nameSpace} size="sm" />
|
48 |
{nameSpace}
|
49 |
</div>
|
50 |
-
<div>{modelName}</div>
|
51 |
</div>
|
52 |
<div
|
53 |
class="absolute right-2 grid size-4 flex-none place-items-center rounded-sm bg-gray-100 text-xs dark:bg-gray-600"
|
@@ -61,4 +62,6 @@
|
|
61 |
<ModelSelectorModal {conversation} onModelSelect={changeModel} onClose={() => (showModelPickerModal = false)} />
|
62 |
{/if}
|
63 |
|
64 |
-
|
|
|
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { isConversationWithHFModel, isCustomModel, type Conversation, type ModelWithTokenizer } from "$lib/types.js";
|
3 |
|
4 |
import { models } from "$lib/state/models.svelte.js";
|
5 |
import IconCaret from "~icons/carbon/chevron-down";
|
|
|
27 |
conversation.provider = undefined;
|
28 |
}
|
29 |
|
30 |
+
const model = $derived(conversation.model);
|
31 |
+
const isCustom = $derived(isCustomModel(model));
|
32 |
+
const nameSpace = $derived(isCustom ? "Custom endpoint" : (model.id.split("/")[0] ?? ""));
|
33 |
+
const modelName = $derived(isCustom ? model.id : (model.id.split("/")[1] ?? ""));
|
34 |
+
const id = $props.id();
|
35 |
</script>
|
36 |
|
37 |
<div class="flex flex-col gap-2">
|
38 |
<label for={id} class="flex items-baseline gap-2 text-sm font-medium text-gray-900 dark:text-white">
|
39 |
Models<span class="text-xs font-normal text-gray-400">{models.all.length}</span>
|
40 |
</label>
|
|
|
41 |
<button
|
42 |
{id}
|
43 |
+
class="focus-outline relative flex items-center justify-between gap-6 overflow-hidden rounded-lg border bg-gray-100/80 px-3 py-1.5 leading-tight whitespace-nowrap shadow-sm hover:brightness-95 dark:border-gray-700 dark:bg-gray-800 dark:hover:brightness-110"
|
44 |
onclick={() => (showModelPickerModal = true)}
|
45 |
>
|
46 |
+
<div class="overflow-hidden text-start">
|
47 |
<div class="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-300">
|
48 |
+
<Avatar model={conversation.model} orgName={nameSpace} size="sm" />
|
49 |
{nameSpace}
|
50 |
</div>
|
51 |
+
<div class="truncate">{modelName}</div>
|
52 |
</div>
|
53 |
<div
|
54 |
class="absolute right-2 grid size-4 flex-none place-items-center rounded-sm bg-gray-100 text-xs dark:bg-gray-600"
|
|
|
62 |
<ModelSelectorModal {conversation} onModelSelect={changeModel} onClose={() => (showModelPickerModal = false)} />
|
63 |
{/if}
|
64 |
|
65 |
+
{#if isConversationWithHFModel(conversation)}
|
66 |
+
<ProviderSelect bind:conversation />
|
67 |
+
{/if}
|
src/lib/components/inference-playground/playground.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type
|
3 |
|
4 |
import { handleNonStreamingResponse, handleStreamingResponse, isSystemPromptSupported } from "./utils.js";
|
5 |
|
@@ -8,7 +8,6 @@
|
|
8 |
import { session } from "$lib/state/session.svelte.js";
|
9 |
import { token } from "$lib/state/token.svelte.js";
|
10 |
import { isMac } from "$lib/utils/platform.js";
|
11 |
-
import { HfInference } from "@huggingface/inference";
|
12 |
import typia from "typia";
|
13 |
import IconExternal from "~icons/carbon/arrow-up-right";
|
14 |
import IconCode from "~icons/carbon/code";
|
@@ -21,6 +20,7 @@
|
|
21 |
import { showShareModal } from "../share-modal.svelte";
|
22 |
import Toaster from "../toaster.svelte";
|
23 |
import { addToast } from "../toaster.svelte.js";
|
|
|
24 |
import PlaygroundConversationHeader from "./conversation-header.svelte";
|
25 |
import PlaygroundConversation from "./conversation.svelte";
|
26 |
import GenerationConfig from "./generation-config.svelte";
|
@@ -69,14 +69,12 @@
|
|
69 |
if (!conversation) return;
|
70 |
|
71 |
const startTime = performance.now();
|
72 |
-
const hf = new HfInference(token.value);
|
73 |
|
74 |
if (conversation.streaming) {
|
75 |
let addedMessage = false;
|
76 |
let streamingMessage = $state({ role: "assistant", content: "" });
|
77 |
|
78 |
await handleStreamingResponse(
|
79 |
-
hf,
|
80 |
conversation,
|
81 |
content => {
|
82 |
if (!streamingMessage) return;
|
@@ -92,10 +90,7 @@
|
|
92 |
abortManager.createController()
|
93 |
);
|
94 |
} else {
|
95 |
-
const { message: newMessage, completion_tokens: newTokensCount } = await handleNonStreamingResponse(
|
96 |
-
hf,
|
97 |
-
conversation
|
98 |
-
);
|
99 |
conversation.messages = [...conversation.messages, newMessage];
|
100 |
const c = generationStats[conversationIdx];
|
101 |
if (c) c.generatedTokensCount += newTokensCount;
|
@@ -286,9 +281,14 @@
|
|
286 |
{!viewSettings ? "Settings" : "Hide Settings"}
|
287 |
</button>
|
288 |
{/if}
|
289 |
-
<
|
290 |
-
|
291 |
-
|
|
|
|
|
|
|
|
|
|
|
292 |
</div>
|
293 |
<div class="flex flex-1 shrink-0 items-center justify-center gap-x-8 text-center text-sm text-gray-500">
|
294 |
{#each generationStats as { latency, generatedTokensCount }}
|
@@ -298,8 +298,8 @@
|
|
298 |
<div class="flex flex-1 justify-end gap-x-2">
|
299 |
<button type="button" onclick={() => (viewCode = !viewCode)} class="btn">
|
300 |
<IconCode />
|
301 |
-
{!viewCode ? "View Code" : "Hide Code"}
|
302 |
-
>
|
303 |
<button
|
304 |
onclick={() => {
|
305 |
viewCode = false;
|
@@ -417,7 +417,7 @@
|
|
417 |
<div class="absolute bottom-6 left-4 flex items-center gap-2 max-md:hidden">
|
418 |
<a
|
419 |
target="_blank"
|
420 |
-
href="https://huggingface.co/docs/
|
421 |
class="flex items-center gap-1 text-sm text-gray-500 underline decoration-gray-300 hover:text-gray-800 dark:text-gray-400 dark:decoration-gray-600 dark:hover:text-gray-200"
|
422 |
>
|
423 |
<div class="text-xs">
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { type ConversationMessage, type ModelWithTokenizer, type Project } from "$lib/types.js";
|
3 |
|
4 |
import { handleNonStreamingResponse, handleStreamingResponse, isSystemPromptSupported } from "./utils.js";
|
5 |
|
|
|
8 |
import { session } from "$lib/state/session.svelte.js";
|
9 |
import { token } from "$lib/state/token.svelte.js";
|
10 |
import { isMac } from "$lib/utils/platform.js";
|
|
|
11 |
import typia from "typia";
|
12 |
import IconExternal from "~icons/carbon/arrow-up-right";
|
13 |
import IconCode from "~icons/carbon/code";
|
|
|
20 |
import { showShareModal } from "../share-modal.svelte";
|
21 |
import Toaster from "../toaster.svelte";
|
22 |
import { addToast } from "../toaster.svelte.js";
|
23 |
+
import Tooltip from "../tooltip.svelte";
|
24 |
import PlaygroundConversationHeader from "./conversation-header.svelte";
|
25 |
import PlaygroundConversation from "./conversation.svelte";
|
26 |
import GenerationConfig from "./generation-config.svelte";
|
|
|
69 |
if (!conversation) return;
|
70 |
|
71 |
const startTime = performance.now();
|
|
|
72 |
|
73 |
if (conversation.streaming) {
|
74 |
let addedMessage = false;
|
75 |
let streamingMessage = $state({ role: "assistant", content: "" });
|
76 |
|
77 |
await handleStreamingResponse(
|
|
|
78 |
conversation,
|
79 |
content => {
|
80 |
if (!streamingMessage) return;
|
|
|
90 |
abortManager.createController()
|
91 |
);
|
92 |
} else {
|
93 |
+
const { message: newMessage, completion_tokens: newTokensCount } = await handleNonStreamingResponse(conversation);
|
|
|
|
|
|
|
94 |
conversation.messages = [...conversation.messages, newMessage];
|
95 |
const c = generationStats[conversationIdx];
|
96 |
if (c) c.generatedTokensCount += newTokensCount;
|
|
|
281 |
{!viewSettings ? "Settings" : "Hide Settings"}
|
282 |
</button>
|
283 |
{/if}
|
284 |
+
<Tooltip>
|
285 |
+
{#snippet trigger(tooltip)}
|
286 |
+
<button type="button" onclick={reset} class="btn size-[39px]" {...tooltip.trigger}>
|
287 |
+
<IconDelete />
|
288 |
+
</button>
|
289 |
+
{/snippet}
|
290 |
+
Clear conversation
|
291 |
+
</Tooltip>
|
292 |
</div>
|
293 |
<div class="flex flex-1 shrink-0 items-center justify-center gap-x-8 text-center text-sm text-gray-500">
|
294 |
{#each generationStats as { latency, generatedTokensCount }}
|
|
|
298 |
<div class="flex flex-1 justify-end gap-x-2">
|
299 |
<button type="button" onclick={() => (viewCode = !viewCode)} class="btn">
|
300 |
<IconCode />
|
301 |
+
{!viewCode ? "View Code" : "Hide Code"}
|
302 |
+
</button>
|
303 |
<button
|
304 |
onclick={() => {
|
305 |
viewCode = false;
|
|
|
417 |
<div class="absolute bottom-6 left-4 flex items-center gap-2 max-md:hidden">
|
418 |
<a
|
419 |
target="_blank"
|
420 |
+
href="https://huggingface.co/docs/inference-providers/tasks/chat-completion"
|
421 |
class="flex items-center gap-1 text-sm text-gray-500 underline decoration-gray-300 hover:text-gray-800 dark:text-gray-400 dark:decoration-gray-600 dark:hover:text-gray-200"
|
422 |
>
|
423 |
<div class="text-xs">
|
src/lib/components/inference-playground/provider-select.svelte
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<script lang="ts">
|
2 |
import { run } from "svelte/legacy";
|
3 |
|
4 |
-
import type {
|
5 |
|
6 |
import { randomPick } from "$lib/utils/array.js";
|
7 |
import { cn } from "$lib/utils/cn.js";
|
@@ -10,7 +10,7 @@
|
|
10 |
import IconProvider from "../icon-provider.svelte";
|
11 |
|
12 |
interface Props {
|
13 |
-
conversation:
|
14 |
class?: string | undefined;
|
15 |
}
|
16 |
|
|
|
1 |
<script lang="ts">
|
2 |
import { run } from "svelte/legacy";
|
3 |
|
4 |
+
import type { ConversationWithHFModel } from "$lib/types.js";
|
5 |
|
6 |
import { randomPick } from "$lib/utils/array.js";
|
7 |
import { cn } from "$lib/utils/cn.js";
|
|
|
10 |
import IconProvider from "../icon-provider.svelte";
|
11 |
|
12 |
interface Props {
|
13 |
+
conversation: ConversationWithHFModel;
|
14 |
class?: string | undefined;
|
15 |
}
|
16 |
|
src/lib/components/inference-playground/utils.ts
CHANGED
@@ -1,8 +1,16 @@
|
|
1 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import type { ChatCompletionInputMessage, InferenceSnippet } from "@huggingface/tasks";
|
3 |
import { type ChatCompletionOutputMessage } from "@huggingface/tasks";
|
4 |
-
|
5 |
import { HfInference, snippets, type InferenceProvider } from "@huggingface/inference";
|
|
|
|
|
6 |
type ChatCompletionInputMessageChunk =
|
7 |
NonNullable<ChatCompletionInputMessage["content"]> extends string | (infer U)[] ? U : never;
|
8 |
|
@@ -25,27 +33,107 @@ function parseMessage(message: ConversationMessage): ChatCompletionInputMessage
|
|
25 |
};
|
26 |
}
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
const { model, systemMessage } = conversation;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
const messages = [
|
36 |
...(isSystemPromptSupported(model) && systemMessage.content?.length ? [systemMessage] : []),
|
37 |
...conversation.messages,
|
38 |
];
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
42 |
model: model.id,
|
43 |
messages: messages.map(parseMessage),
|
44 |
provider: conversation.provider,
|
45 |
...conversation.config,
|
46 |
},
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
if (chunk.choices && chunk.choices.length > 0 && chunk.choices[0]?.delta?.content) {
|
50 |
out += chunk.choices[0].delta.content;
|
51 |
onChunk(out);
|
@@ -54,22 +142,30 @@ export async function handleStreamingResponse(
|
|
54 |
}
|
55 |
|
56 |
export async function handleNonStreamingResponse(
|
57 |
-
hf: HfInference,
|
58 |
conversation: Conversation
|
59 |
): Promise<{ message: ChatCompletionOutputMessage; completion_tokens: number }> {
|
60 |
-
const
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
72 |
|
|
|
|
|
73 |
if (response.choices && response.choices.length > 0) {
|
74 |
const { message } = response.choices[0]!;
|
75 |
const { completion_tokens } = response.usage;
|
@@ -78,8 +174,10 @@ export async function handleNonStreamingResponse(
|
|
78 |
throw new Error("No response from the model");
|
79 |
}
|
80 |
|
81 |
-
export function isSystemPromptSupported(model: ModelWithTokenizer) {
|
82 |
-
|
|
|
|
|
83 |
}
|
84 |
|
85 |
export const defaultSystemMessage: { [key: string]: string } = {
|
@@ -159,6 +257,11 @@ export function getInferenceSnippet(
|
|
159 |
accessToken: string,
|
160 |
opts?: Record<string, unknown>
|
161 |
): GetInferenceSnippetReturn {
|
|
|
|
|
|
|
|
|
|
|
162 |
const providerId = model.inferenceProviderMapping.find(p => p.provider === provider)?.providerId;
|
163 |
const snippetsByClient = GET_SNIPPET_FN[language](
|
164 |
{ ...model, inference: "" },
|
@@ -178,5 +281,6 @@ export function hasInferenceSnippet(
|
|
178 |
provider: InferenceProvider,
|
179 |
language: InferenceSnippetLanguage
|
180 |
): boolean {
|
|
|
181 |
return getInferenceSnippet(model, provider, language, "").length > 0;
|
182 |
}
|
|
|
1 |
+
import {
|
2 |
+
isCustomModel,
|
3 |
+
type Conversation,
|
4 |
+
type ConversationMessage,
|
5 |
+
type CustomModel,
|
6 |
+
type ModelWithTokenizer,
|
7 |
+
} from "$lib/types.js";
|
8 |
import type { ChatCompletionInputMessage, InferenceSnippet } from "@huggingface/tasks";
|
9 |
import { type ChatCompletionOutputMessage } from "@huggingface/tasks";
|
10 |
+
import { token } from "$lib/state/token.svelte";
|
11 |
import { HfInference, snippets, type InferenceProvider } from "@huggingface/inference";
|
12 |
+
import OpenAI from "openai";
|
13 |
+
|
14 |
type ChatCompletionInputMessageChunk =
|
15 |
NonNullable<ChatCompletionInputMessage["content"]> extends string | (infer U)[] ? U : never;
|
16 |
|
|
|
33 |
};
|
34 |
}
|
35 |
|
36 |
+
type HFCompletionMetadata = {
|
37 |
+
type: "huggingface";
|
38 |
+
client: HfInference;
|
39 |
+
args: Parameters<HfInference["chatCompletion"]>[0];
|
40 |
+
};
|
41 |
+
|
42 |
+
type OpenAICompletionMetadata = {
|
43 |
+
type: "openai";
|
44 |
+
client: OpenAI;
|
45 |
+
args: OpenAI.ChatCompletionCreateParams;
|
46 |
+
};
|
47 |
+
|
48 |
+
type CompletionMetadata = HFCompletionMetadata | OpenAICompletionMetadata;
|
49 |
+
|
50 |
+
function parseOpenAIMessages(
|
51 |
+
messages: ConversationMessage[],
|
52 |
+
systemMessage?: ConversationMessage
|
53 |
+
): OpenAI.ChatCompletionMessageParam[] {
|
54 |
+
const parsedMessages: OpenAI.ChatCompletionMessageParam[] = [];
|
55 |
+
|
56 |
+
if (systemMessage?.content) {
|
57 |
+
parsedMessages.push({
|
58 |
+
role: "system",
|
59 |
+
content: systemMessage.content,
|
60 |
+
});
|
61 |
+
}
|
62 |
+
|
63 |
+
return [
|
64 |
+
...parsedMessages,
|
65 |
+
...messages.map(msg => ({
|
66 |
+
role: msg.role === "assistant" ? ("assistant" as const) : ("user" as const),
|
67 |
+
content: msg.content || "",
|
68 |
+
})),
|
69 |
+
];
|
70 |
+
}
|
71 |
+
|
72 |
+
function getCompletionMetadata(conversation: Conversation): CompletionMetadata {
|
73 |
const { model, systemMessage } = conversation;
|
74 |
+
|
75 |
+
// Handle OpenAI-compatible models
|
76 |
+
if (isCustomModel(model)) {
|
77 |
+
const openai = new OpenAI({
|
78 |
+
apiKey: model.accessToken,
|
79 |
+
baseURL: model.endpointUrl,
|
80 |
+
dangerouslyAllowBrowser: true,
|
81 |
+
});
|
82 |
+
|
83 |
+
return {
|
84 |
+
type: "openai",
|
85 |
+
client: openai,
|
86 |
+
args: {
|
87 |
+
messages: parseOpenAIMessages(conversation.messages, systemMessage),
|
88 |
+
model: model.id,
|
89 |
+
},
|
90 |
+
};
|
91 |
+
}
|
92 |
+
|
93 |
+
// Handle HuggingFace models
|
94 |
const messages = [
|
95 |
...(isSystemPromptSupported(model) && systemMessage.content?.length ? [systemMessage] : []),
|
96 |
...conversation.messages,
|
97 |
];
|
98 |
+
|
99 |
+
return {
|
100 |
+
type: "huggingface",
|
101 |
+
client: new HfInference(token.value),
|
102 |
+
args: {
|
103 |
model: model.id,
|
104 |
messages: messages.map(parseMessage),
|
105 |
provider: conversation.provider,
|
106 |
...conversation.config,
|
107 |
},
|
108 |
+
};
|
109 |
+
}
|
110 |
+
|
111 |
+
export async function handleStreamingResponse(
|
112 |
+
conversation: Conversation,
|
113 |
+
onChunk: (content: string) => void,
|
114 |
+
abortController: AbortController
|
115 |
+
): Promise<void> {
|
116 |
+
const metadata = getCompletionMetadata(conversation);
|
117 |
+
|
118 |
+
if (metadata.type === "openai") {
|
119 |
+
const stream = await metadata.client.chat.completions.create({
|
120 |
+
...metadata.args,
|
121 |
+
stream: true,
|
122 |
+
} as OpenAI.ChatCompletionCreateParamsStreaming);
|
123 |
+
|
124 |
+
let out = "";
|
125 |
+
for await (const chunk of stream) {
|
126 |
+
if (chunk.choices[0]?.delta?.content) {
|
127 |
+
out += chunk.choices[0].delta.content;
|
128 |
+
onChunk(out);
|
129 |
+
}
|
130 |
+
}
|
131 |
+
return;
|
132 |
+
}
|
133 |
+
|
134 |
+
// HuggingFace streaming
|
135 |
+
let out = "";
|
136 |
+
for await (const chunk of metadata.client.chatCompletionStream(metadata.args, { signal: abortController.signal })) {
|
137 |
if (chunk.choices && chunk.choices.length > 0 && chunk.choices[0]?.delta?.content) {
|
138 |
out += chunk.choices[0].delta.content;
|
139 |
onChunk(out);
|
|
|
142 |
}
|
143 |
|
144 |
export async function handleNonStreamingResponse(
|
|
|
145 |
conversation: Conversation
|
146 |
): Promise<{ message: ChatCompletionOutputMessage; completion_tokens: number }> {
|
147 |
+
const metadata = getCompletionMetadata(conversation);
|
148 |
+
|
149 |
+
if (metadata.type === "openai") {
|
150 |
+
const response = await metadata.client.chat.completions.create({
|
151 |
+
...metadata.args,
|
152 |
+
stream: false,
|
153 |
+
} as OpenAI.ChatCompletionCreateParamsNonStreaming);
|
154 |
|
155 |
+
if (response.choices && response.choices.length > 0 && response.choices[0]?.message) {
|
156 |
+
return {
|
157 |
+
message: {
|
158 |
+
role: "assistant",
|
159 |
+
content: response.choices[0].message.content || "",
|
160 |
+
},
|
161 |
+
completion_tokens: response.usage?.completion_tokens || 0,
|
162 |
+
};
|
163 |
+
}
|
164 |
+
throw new Error("No response from the model");
|
165 |
+
}
|
166 |
|
167 |
+
// HuggingFace non-streaming
|
168 |
+
const response = await metadata.client.chatCompletion(metadata.args);
|
169 |
if (response.choices && response.choices.length > 0) {
|
170 |
const { message } = response.choices[0]!;
|
171 |
const { completion_tokens } = response.usage;
|
|
|
174 |
throw new Error("No response from the model");
|
175 |
}
|
176 |
|
177 |
+
export function isSystemPromptSupported(model: ModelWithTokenizer | CustomModel) {
|
178 |
+
if (isCustomModel(model)) return true; // OpenAI-compatible models support system messages
|
179 |
+
if ("tokenizerConfig" in model) return model?.tokenizerConfig?.chat_template?.includes("system");
|
180 |
+
return false;
|
181 |
}
|
182 |
|
183 |
export const defaultSystemMessage: { [key: string]: string } = {
|
|
|
257 |
accessToken: string,
|
258 |
opts?: Record<string, unknown>
|
259 |
): GetInferenceSnippetReturn {
|
260 |
+
// If it's a custom model, we don't generate inference snippets
|
261 |
+
if (isCustomModel(model)) {
|
262 |
+
return [];
|
263 |
+
}
|
264 |
+
|
265 |
const providerId = model.inferenceProviderMapping.find(p => p.provider === provider)?.providerId;
|
266 |
const snippetsByClient = GET_SNIPPET_FN[language](
|
267 |
{ ...model, inference: "" },
|
|
|
281 |
provider: InferenceProvider,
|
282 |
language: InferenceSnippetLanguage
|
283 |
): boolean {
|
284 |
+
if (isCustomModel(model)) return false;
|
285 |
return getInferenceSnippet(model, provider, language, "").length > 0;
|
286 |
}
|
src/lib/components/local-toasts.svelte
CHANGED
@@ -6,13 +6,14 @@
|
|
6 |
|
7 |
interface Props {
|
8 |
children: Snippet<[{ addToast: typeof toaster.addToast; trigger: typeof trigger }]>;
|
|
|
9 |
closeDelay?: number;
|
10 |
}
|
11 |
-
const { children, closeDelay = 2000 }: Props = $props();
|
12 |
|
13 |
const id = $props.id();
|
14 |
|
15 |
-
const trigger = {
|
16 |
id,
|
17 |
} as const;
|
18 |
|
@@ -21,11 +22,13 @@
|
|
21 |
variant: "info" | "danger";
|
22 |
};
|
23 |
|
24 |
-
const toaster = new Toaster<ToastData>({
|
25 |
hover: null,
|
26 |
closeDelay: () => closeDelay,
|
27 |
});
|
28 |
|
|
|
|
|
29 |
function float(node: HTMLElement) {
|
30 |
const triggerEl = document.getElementById(trigger.id);
|
31 |
if (!triggerEl) return;
|
@@ -55,16 +58,20 @@
|
|
55 |
|
56 |
{@render children({ trigger, addToast: toaster.addToast })}
|
57 |
|
58 |
-
{#each toaster.toasts as toast (toast.id)}
|
59 |
<div
|
60 |
data-local-toast
|
61 |
data-variant={toast.data.variant}
|
62 |
-
class=
|
63 |
in:fly={{ y: 10 }}
|
64 |
out:fly={{ y: -4 }}
|
65 |
use:float
|
66 |
>
|
67 |
-
{
|
|
|
|
|
|
|
|
|
68 |
</div>
|
69 |
{/each}
|
70 |
|
|
|
6 |
|
7 |
interface Props {
|
8 |
children: Snippet<[{ addToast: typeof toaster.addToast; trigger: typeof trigger }]>;
|
9 |
+
toast?: Snippet<[{ toast: (typeof toaster.toasts)[0]; float: typeof float }]>;
|
10 |
closeDelay?: number;
|
11 |
}
|
12 |
+
const { children, closeDelay = 2000, toast: toastSnippet }: Props = $props();
|
13 |
|
14 |
const id = $props.id();
|
15 |
|
16 |
+
export const trigger = {
|
17 |
id,
|
18 |
} as const;
|
19 |
|
|
|
22 |
variant: "info" | "danger";
|
23 |
};
|
24 |
|
25 |
+
export const toaster = new Toaster<ToastData>({
|
26 |
hover: null,
|
27 |
closeDelay: () => closeDelay,
|
28 |
});
|
29 |
|
30 |
+
export const addToast = toaster.addToast;
|
31 |
+
|
32 |
function float(node: HTMLElement) {
|
33 |
const triggerEl = document.getElementById(trigger.id);
|
34 |
if (!triggerEl) return;
|
|
|
58 |
|
59 |
{@render children({ trigger, addToast: toaster.addToast })}
|
60 |
|
61 |
+
{#each toaster.toasts.slice(toaster.toasts.length - 1) as toast (toast.id)}
|
62 |
<div
|
63 |
data-local-toast
|
64 |
data-variant={toast.data.variant}
|
65 |
+
class={[!toastSnippet && `${classMap[toast.data.variant]} rounded-full px-2 py-1 text-xs`]}
|
66 |
in:fly={{ y: 10 }}
|
67 |
out:fly={{ y: -4 }}
|
68 |
use:float
|
69 |
>
|
70 |
+
{#if toastSnippet}
|
71 |
+
{@render toastSnippet({ toast, float })}
|
72 |
+
{:else}
|
73 |
+
{toast.data.content}
|
74 |
+
{/if}
|
75 |
</div>
|
76 |
{/each}
|
77 |
|
src/lib/state/models.svelte.ts
CHANGED
@@ -1,10 +1,78 @@
|
|
1 |
import { page } from "$app/state";
|
2 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
class Models {
|
5 |
-
|
6 |
-
trending = $derived(this.
|
7 |
-
nonTrending = $derived(this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
}
|
9 |
|
10 |
export const models = new Models();
|
|
|
1 |
import { page } from "$app/state";
|
2 |
+
import { createInit } from "$lib/spells/create-init.svelte";
|
3 |
+
import type { CustomModel, ModelWithTokenizer } from "$lib/types.js";
|
4 |
+
import { safeParse } from "$lib/utils/json.js";
|
5 |
+
import typia from "typia";
|
6 |
+
import { session } from "./session.svelte";
|
7 |
+
import { randomPick } from "$lib/utils/array.js";
|
8 |
+
|
9 |
+
const LOCAL_STORAGE_KEY = "hf_inference_playground_custom_models";
|
10 |
|
11 |
class Models {
|
12 |
+
remote = $derived(page.data.models as ModelWithTokenizer[]);
|
13 |
+
trending = $derived(this.remote.toSorted((a, b) => b.trendingScore - a.trendingScore).slice(0, 5));
|
14 |
+
nonTrending = $derived(this.remote.filter(m => !this.trending.includes(m)));
|
15 |
+
|
16 |
+
#custom = $state<CustomModel[]>([]);
|
17 |
+
#initCustom = createInit(() => {
|
18 |
+
const savedData = localStorage.getItem(LOCAL_STORAGE_KEY);
|
19 |
+
if (!savedData) return;
|
20 |
+
const parsed = safeParse(savedData);
|
21 |
+
const res = typia.validate<CustomModel[]>(parsed);
|
22 |
+
if (res.success) {
|
23 |
+
this.#custom = parsed;
|
24 |
+
} else {
|
25 |
+
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify([]));
|
26 |
+
}
|
27 |
+
});
|
28 |
+
|
29 |
+
all = $derived([...this.remote, ...this.custom]);
|
30 |
+
|
31 |
+
constructor() {
|
32 |
+
$effect.root(() => {
|
33 |
+
$effect(() => {
|
34 |
+
if (!this.#initCustom.called) return;
|
35 |
+
const v = $state.snapshot(this.#custom);
|
36 |
+
try {
|
37 |
+
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(v));
|
38 |
+
} catch (e) {
|
39 |
+
console.error("Failed to save session to localStorage:", e);
|
40 |
+
}
|
41 |
+
});
|
42 |
+
});
|
43 |
+
}
|
44 |
+
|
45 |
+
get custom() {
|
46 |
+
this.#initCustom.fn();
|
47 |
+
return this.#custom;
|
48 |
+
}
|
49 |
+
|
50 |
+
// set local(v: CustomModel[]) {
|
51 |
+
// this.local = v;
|
52 |
+
// }
|
53 |
+
|
54 |
+
addCustom(model: CustomModel) {
|
55 |
+
if (this.#custom.find(m => m.id === model.id)) return null;
|
56 |
+
this.#custom = [...this.#custom, model];
|
57 |
+
return model;
|
58 |
+
}
|
59 |
+
|
60 |
+
upsertCustom(model: CustomModel) {
|
61 |
+
const index = this.#custom.findIndex(m => m._id === model._id);
|
62 |
+
if (index === -1) {
|
63 |
+
this.addCustom(model);
|
64 |
+
} else {
|
65 |
+
this.#custom[index] = model;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
removeCustom(uuid: CustomModel["_id"]) {
|
70 |
+
this.#custom = this.#custom.filter(m => m._id !== uuid);
|
71 |
+
session.project.conversations.forEach((c, i) => {
|
72 |
+
if (c.model._id !== uuid) return;
|
73 |
+
session.project.conversations[i]!.model = randomPick(models.trending)!;
|
74 |
+
});
|
75 |
+
}
|
76 |
}
|
77 |
|
78 |
export const models = new Models();
|
src/lib/state/session.svelte.ts
CHANGED
@@ -21,7 +21,7 @@ const systemMessage: ConversationMessage = {
|
|
21 |
content: "",
|
22 |
};
|
23 |
|
24 |
-
const emptyModel: ModelWithTokenizer = {
|
25 |
_id: "",
|
26 |
inferenceProviderMapping: [],
|
27 |
pipeline_tag: PipelineTag.TextGeneration,
|
@@ -37,7 +37,7 @@ const emptyModel: ModelWithTokenizer = {
|
|
37 |
};
|
38 |
|
39 |
function getDefaults() {
|
40 |
-
const defaultModel = models.trending[0] ?? models.
|
41 |
|
42 |
const defaultConversation: Conversation = {
|
43 |
model: defaultModel,
|
@@ -90,7 +90,7 @@ class SessionState {
|
|
90 |
const searchParams = new URLSearchParams(window.location.search);
|
91 |
const searchProviders = searchParams.getAll("provider");
|
92 |
const searchModelIds = searchParams.getAll("modelId");
|
93 |
-
const modelsFromSearch = searchModelIds.map(id => models.
|
94 |
if (modelsFromSearch.length > 0) savedSession.activeProjectId = "default";
|
95 |
|
96 |
let min = Math.min(dp.conversations.length, modelsFromSearch.length, searchProviders.length);
|
|
|
21 |
content: "",
|
22 |
};
|
23 |
|
24 |
+
export const emptyModel: ModelWithTokenizer = {
|
25 |
_id: "",
|
26 |
inferenceProviderMapping: [],
|
27 |
pipeline_tag: PipelineTag.TextGeneration,
|
|
|
37 |
};
|
38 |
|
39 |
function getDefaults() {
|
40 |
+
const defaultModel = models.trending[0] ?? models.remote[0] ?? emptyModel;
|
41 |
|
42 |
const defaultConversation: Conversation = {
|
43 |
model: defaultModel,
|
|
|
90 |
const searchParams = new URLSearchParams(window.location.search);
|
91 |
const searchProviders = searchParams.getAll("provider");
|
92 |
const searchModelIds = searchParams.getAll("modelId");
|
93 |
+
const modelsFromSearch = searchModelIds.map(id => models.remote.find(model => model.id === id)).filter(Boolean);
|
94 |
if (modelsFromSearch.length > 0) savedSession.activeProjectId = "default";
|
95 |
|
96 |
let min = Math.min(dp.conversations.length, modelsFromSearch.length, searchProviders.length);
|
src/lib/types.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import type { GenerationConfig } from "$lib/components/inference-playground/generation-config-settings.js";
|
2 |
import type { ChatCompletionInputMessage } from "@huggingface/tasks";
|
|
|
3 |
|
4 |
export type ConversationMessage = Pick<ChatCompletionInputMessage, "name" | "role" | "tool_calls"> & {
|
5 |
content?: string;
|
@@ -7,7 +8,7 @@ export type ConversationMessage = Pick<ChatCompletionInputMessage, "name" | "rol
|
|
7 |
};
|
8 |
|
9 |
export type Conversation = {
|
10 |
-
model: ModelWithTokenizer;
|
11 |
config: GenerationConfig;
|
12 |
messages: ConversationMessage[];
|
13 |
systemMessage: ConversationMessage;
|
@@ -15,6 +16,19 @@ export type Conversation = {
|
|
15 |
provider?: string;
|
16 |
};
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
export type Project = {
|
19 |
conversations: [Conversation] | [Conversation, Conversation];
|
20 |
id: string;
|
@@ -51,6 +65,14 @@ export type Model = {
|
|
51 |
library_name?: LibraryName;
|
52 |
};
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
export type Config = {
|
55 |
architectures: string[];
|
56 |
model_type: string;
|
|
|
1 |
import type { GenerationConfig } from "$lib/components/inference-playground/generation-config-settings.js";
|
2 |
import type { ChatCompletionInputMessage } from "@huggingface/tasks";
|
3 |
+
import typia from "typia";
|
4 |
|
5 |
export type ConversationMessage = Pick<ChatCompletionInputMessage, "name" | "role" | "tool_calls"> & {
|
6 |
content?: string;
|
|
|
8 |
};
|
9 |
|
10 |
export type Conversation = {
|
11 |
+
model: ModelWithTokenizer | CustomModel;
|
12 |
config: GenerationConfig;
|
13 |
messages: ConversationMessage[];
|
14 |
systemMessage: ConversationMessage;
|
|
|
16 |
provider?: string;
|
17 |
};
|
18 |
|
19 |
+
export type ConversationWithCustomModel = Conversation & {
|
20 |
+
model: CustomModel;
|
21 |
+
};
|
22 |
+
|
23 |
+
export type ConversationWithHFModel = Conversation & {
|
24 |
+
model: ModelWithTokenizer;
|
25 |
+
};
|
26 |
+
|
27 |
+
export const isConversationWithHFModel = typia.createIs<ConversationWithHFModel>();
|
28 |
+
export const isConversationWithCustomModel = typia.createIs<ConversationWithCustomModel>();
|
29 |
+
|
30 |
+
export const isCustomModel = typia.createIs<CustomModel>();
|
31 |
+
|
32 |
export type Project = {
|
33 |
conversations: [Conversation] | [Conversation, Conversation];
|
34 |
id: string;
|
|
|
65 |
library_name?: LibraryName;
|
66 |
};
|
67 |
|
68 |
+
export type CustomModel = {
|
69 |
+
id: string;
|
70 |
+
/** UUID */
|
71 |
+
_id: string;
|
72 |
+
endpointUrl: string;
|
73 |
+
accessToken?: string;
|
74 |
+
};
|
75 |
+
|
76 |
export type Config = {
|
77 |
architectures: string[];
|
78 |
model_type: string;
|
src/lib/utils/sleep.ts
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
export async function sleep(ms: number) {
|
2 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
3 |
+
}
|
src/routes/+layout.svelte
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
<script lang="ts">
|
|
|
2 |
import DebugMenu from "$lib/components/debug-menu.svelte";
|
3 |
import Prompts from "$lib/components/prompts.svelte";
|
4 |
import QuotaModal from "$lib/components/quota-modal.svelte";
|
@@ -18,3 +19,4 @@
|
|
18 |
<Prompts />
|
19 |
<QuotaModal />
|
20 |
<ShareModal />
|
|
|
|
1 |
<script lang="ts">
|
2 |
+
import CustomModelConfig from "$lib/components/inference-playground/custom-model-config.svelte";
|
3 |
import DebugMenu from "$lib/components/debug-menu.svelte";
|
4 |
import Prompts from "$lib/components/prompts.svelte";
|
5 |
import QuotaModal from "$lib/components/quota-modal.svelte";
|
|
|
19 |
<Prompts />
|
20 |
<QuotaModal />
|
21 |
<ShareModal />
|
22 |
+
<CustomModelConfig />
|