Spaces:
Running
Running
FREE STORE POS - free
#156
by
Osama261caryp
- opened
- index.html +0 -23
- package-lock.json +15 -91
- package.json +1 -3
- public/banner.png +2 -2
- server.js +50 -129
- src/assets/index.css +0 -4
- src/assets/linux.png +0 -0
- src/components/ask-ai/ask-ai.tsx +35 -63
- src/components/deploy-button/deploy-button.tsx +20 -12
- src/components/history/history.tsx +2 -2
- src/components/invite-friends/invite-friends.tsx +0 -78
- src/components/load-button/load-button.tsx +1 -1
- src/components/loading/loading.tsx +3 -16
- src/components/pro-modal/pro-modal.tsx +40 -64
- src/components/re-imagine/re-imagine.tsx +0 -136
- src/components/settings/settings.tsx +4 -5
- src/components/ui/button.tsx +2 -3
- src/components/ui/dialog.tsx +0 -144
- src/components/ui/tooltip.tsx +0 -59
- src/views/App.tsx +2 -35
- utils/providers.js +2 -9
index.html
CHANGED
@@ -11,29 +11,6 @@
|
|
11 |
helps you build websites with AI, no code required. Let's deploy your
|
12 |
website with DeepSite and enjoy the magic of AI."
|
13 |
/>
|
14 |
-
<meta name="theme-color" content="#000000" />
|
15 |
-
<meta name="apple-mobile-web-app-capable" content="yes" />
|
16 |
-
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
17 |
-
<meta name="apple-mobile-web-app-title" content="DeepSite" />
|
18 |
-
<meta name="msapplication-TileColor" content="#000000" />
|
19 |
-
<meta name="twitter:card" content="summary_large_image" />
|
20 |
-
<meta name="twitter:title" content="DeepSite | Build with AI ✨" />
|
21 |
-
<meta
|
22 |
-
name="twitter:description"
|
23 |
-
content="DeepSite is a web development tool that
|
24 |
-
helps you build websites with AI, no code required. Let's deploy your
|
25 |
-
website with DeepSite and enjoy the magic of AI."
|
26 |
-
/>
|
27 |
-
<meta name="twitter:image" content="/banner.png" />
|
28 |
-
<meta property="og:type" content="website" />
|
29 |
-
<meta property="og:title" content="DeepSite | Build with AI ✨" />
|
30 |
-
<meta
|
31 |
-
property="og:description"
|
32 |
-
content="DeepSite is a web development tool that
|
33 |
-
helps you build websites with AI, no code required. Let's deploy your
|
34 |
-
website with DeepSite and enjoy the magic of AI."
|
35 |
-
/>
|
36 |
-
<meta property="og:image" content="/banner.png" />
|
37 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
38 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
39 |
<link
|
|
|
11 |
helps you build websites with AI, no code required. Let's deploy your
|
12 |
website with DeepSite and enjoy the magic of AI."
|
13 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
15 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
16 |
<link
|
package-lock.json
CHANGED
@@ -9,10 +9,9 @@
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@huggingface/hub": "^1.1.1",
|
12 |
-
"@huggingface/inference": "^
|
13 |
"@monaco-editor/react": "^4.7.0",
|
14 |
"@radix-ui/react-avatar": "^1.1.10",
|
15 |
-
"@radix-ui/react-dialog": "^1.1.14",
|
16 |
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
17 |
"@radix-ui/react-popover": "^1.1.14",
|
18 |
"@radix-ui/react-select": "^2.2.5",
|
@@ -21,7 +20,6 @@
|
|
21 |
"@radix-ui/react-tabs": "^1.1.12",
|
22 |
"@radix-ui/react-toggle": "^1.1.9",
|
23 |
"@radix-ui/react-toggle-group": "^1.1.10",
|
24 |
-
"@radix-ui/react-tooltip": "^1.2.7",
|
25 |
"@tailwindcss/vite": "^4.0.15",
|
26 |
"@xenova/transformers": "^2.17.2",
|
27 |
"body-parser": "^1.20.3",
|
@@ -191,11 +189,10 @@
|
|
191 |
}
|
192 |
},
|
193 |
"node_modules/@babel/helper-plugin-utils": {
|
194 |
-
"version": "7.
|
195 |
-
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.
|
196 |
-
"integrity": "sha512-
|
197 |
"dev": true,
|
198 |
-
"license": "MIT",
|
199 |
"engines": {
|
200 |
"node": ">=6.9.0"
|
201 |
}
|
@@ -920,32 +917,29 @@
|
|
920 |
"integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
|
921 |
},
|
922 |
"node_modules/@huggingface/inference": {
|
923 |
-
"version": "
|
924 |
-
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-
|
925 |
-
"integrity": "sha512-
|
926 |
-
"license": "MIT",
|
927 |
"dependencies": {
|
928 |
-
"@huggingface/jinja": "^0.
|
929 |
-
"@huggingface/tasks": "^0.
|
930 |
},
|
931 |
"engines": {
|
932 |
"node": ">=18"
|
933 |
}
|
934 |
},
|
935 |
"node_modules/@huggingface/jinja": {
|
936 |
-
"version": "0.
|
937 |
-
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.
|
938 |
-
"integrity": "sha512-
|
939 |
-
"license": "MIT",
|
940 |
"engines": {
|
941 |
"node": ">=18"
|
942 |
}
|
943 |
},
|
944 |
"node_modules/@huggingface/tasks": {
|
945 |
-
"version": "0.
|
946 |
-
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.
|
947 |
-
"integrity": "sha512-
|
948 |
-
"license": "MIT"
|
949 |
},
|
950 |
"node_modules/@humanfs/core": {
|
951 |
"version": "0.19.1",
|
@@ -1283,42 +1277,6 @@
|
|
1283 |
}
|
1284 |
}
|
1285 |
},
|
1286 |
-
"node_modules/@radix-ui/react-dialog": {
|
1287 |
-
"version": "1.1.14",
|
1288 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
|
1289 |
-
"integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
|
1290 |
-
"license": "MIT",
|
1291 |
-
"dependencies": {
|
1292 |
-
"@radix-ui/primitive": "1.1.2",
|
1293 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1294 |
-
"@radix-ui/react-context": "1.1.2",
|
1295 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1296 |
-
"@radix-ui/react-focus-guards": "1.1.2",
|
1297 |
-
"@radix-ui/react-focus-scope": "1.1.7",
|
1298 |
-
"@radix-ui/react-id": "1.1.1",
|
1299 |
-
"@radix-ui/react-portal": "1.1.9",
|
1300 |
-
"@radix-ui/react-presence": "1.1.4",
|
1301 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1302 |
-
"@radix-ui/react-slot": "1.2.3",
|
1303 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1304 |
-
"aria-hidden": "^1.2.4",
|
1305 |
-
"react-remove-scroll": "^2.6.3"
|
1306 |
-
},
|
1307 |
-
"peerDependencies": {
|
1308 |
-
"@types/react": "*",
|
1309 |
-
"@types/react-dom": "*",
|
1310 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1311 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1312 |
-
},
|
1313 |
-
"peerDependenciesMeta": {
|
1314 |
-
"@types/react": {
|
1315 |
-
"optional": true
|
1316 |
-
},
|
1317 |
-
"@types/react-dom": {
|
1318 |
-
"optional": true
|
1319 |
-
}
|
1320 |
-
}
|
1321 |
-
},
|
1322 |
"node_modules/@radix-ui/react-direction": {
|
1323 |
"version": "1.1.1",
|
1324 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
@@ -1833,40 +1791,6 @@
|
|
1833 |
}
|
1834 |
}
|
1835 |
},
|
1836 |
-
"node_modules/@radix-ui/react-tooltip": {
|
1837 |
-
"version": "1.2.7",
|
1838 |
-
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
|
1839 |
-
"integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==",
|
1840 |
-
"license": "MIT",
|
1841 |
-
"dependencies": {
|
1842 |
-
"@radix-ui/primitive": "1.1.2",
|
1843 |
-
"@radix-ui/react-compose-refs": "1.1.2",
|
1844 |
-
"@radix-ui/react-context": "1.1.2",
|
1845 |
-
"@radix-ui/react-dismissable-layer": "1.1.10",
|
1846 |
-
"@radix-ui/react-id": "1.1.1",
|
1847 |
-
"@radix-ui/react-popper": "1.2.7",
|
1848 |
-
"@radix-ui/react-portal": "1.1.9",
|
1849 |
-
"@radix-ui/react-presence": "1.1.4",
|
1850 |
-
"@radix-ui/react-primitive": "2.1.3",
|
1851 |
-
"@radix-ui/react-slot": "1.2.3",
|
1852 |
-
"@radix-ui/react-use-controllable-state": "1.2.2",
|
1853 |
-
"@radix-ui/react-visually-hidden": "1.2.3"
|
1854 |
-
},
|
1855 |
-
"peerDependencies": {
|
1856 |
-
"@types/react": "*",
|
1857 |
-
"@types/react-dom": "*",
|
1858 |
-
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
1859 |
-
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
1860 |
-
},
|
1861 |
-
"peerDependenciesMeta": {
|
1862 |
-
"@types/react": {
|
1863 |
-
"optional": true
|
1864 |
-
},
|
1865 |
-
"@types/react-dom": {
|
1866 |
-
"optional": true
|
1867 |
-
}
|
1868 |
-
}
|
1869 |
-
},
|
1870 |
"node_modules/@radix-ui/react-use-callback-ref": {
|
1871 |
"version": "1.1.1",
|
1872 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@huggingface/hub": "^1.1.1",
|
12 |
+
"@huggingface/inference": "^3.6.1",
|
13 |
"@monaco-editor/react": "^4.7.0",
|
14 |
"@radix-ui/react-avatar": "^1.1.10",
|
|
|
15 |
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
16 |
"@radix-ui/react-popover": "^1.1.14",
|
17 |
"@radix-ui/react-select": "^2.2.5",
|
|
|
20 |
"@radix-ui/react-tabs": "^1.1.12",
|
21 |
"@radix-ui/react-toggle": "^1.1.9",
|
22 |
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
|
23 |
"@tailwindcss/vite": "^4.0.15",
|
24 |
"@xenova/transformers": "^2.17.2",
|
25 |
"body-parser": "^1.20.3",
|
|
|
189 |
}
|
190 |
},
|
191 |
"node_modules/@babel/helper-plugin-utils": {
|
192 |
+
"version": "7.26.5",
|
193 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
|
194 |
+
"integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
|
195 |
"dev": true,
|
|
|
196 |
"engines": {
|
197 |
"node": ">=6.9.0"
|
198 |
}
|
|
|
917 |
"integrity": "sha512-HK6JTVB/nrgjOnbe77HFSENftfAp67AI4mHMR2x64Os1hvchuTT88M8fKEiyESSvqKFKwW4lQKkHva07p05AXw=="
|
918 |
},
|
919 |
"node_modules/@huggingface/inference": {
|
920 |
+
"version": "3.6.1",
|
921 |
+
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-3.6.1.tgz",
|
922 |
+
"integrity": "sha512-EtQlbBqcZycPe+qiTEFI+wNHOMpG0gwNTaZSvYu1juN1p/1dEgqAb2GO31dxLgNev2PzH9d+9nm8GngOsIepJg==",
|
|
|
923 |
"dependencies": {
|
924 |
+
"@huggingface/jinja": "^0.3.3",
|
925 |
+
"@huggingface/tasks": "^0.17.8"
|
926 |
},
|
927 |
"engines": {
|
928 |
"node": ">=18"
|
929 |
}
|
930 |
},
|
931 |
"node_modules/@huggingface/jinja": {
|
932 |
+
"version": "0.3.3",
|
933 |
+
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
|
934 |
+
"integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
|
|
|
935 |
"engines": {
|
936 |
"node": ">=18"
|
937 |
}
|
938 |
},
|
939 |
"node_modules/@huggingface/tasks": {
|
940 |
+
"version": "0.17.9",
|
941 |
+
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.17.9.tgz",
|
942 |
+
"integrity": "sha512-lV6RgCJkqy3p93FFxP9H4SGJmFcHAwr1FO+Zk56q/JWsf7Tdsel1DEo1Xfd3An7ZPWpc2Y9ldRecGo9efDYghg=="
|
|
|
943 |
},
|
944 |
"node_modules/@humanfs/core": {
|
945 |
"version": "0.19.1",
|
|
|
1277 |
}
|
1278 |
}
|
1279 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1280 |
"node_modules/@radix-ui/react-direction": {
|
1281 |
"version": "1.1.1",
|
1282 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
|
|
1791 |
}
|
1792 |
}
|
1793 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1794 |
"node_modules/@radix-ui/react-use-callback-ref": {
|
1795 |
"version": "1.1.1",
|
1796 |
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
package.json
CHANGED
@@ -12,10 +12,9 @@
|
|
12 |
},
|
13 |
"dependencies": {
|
14 |
"@huggingface/hub": "^1.1.1",
|
15 |
-
"@huggingface/inference": "^
|
16 |
"@monaco-editor/react": "^4.7.0",
|
17 |
"@radix-ui/react-avatar": "^1.1.10",
|
18 |
-
"@radix-ui/react-dialog": "^1.1.14",
|
19 |
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
20 |
"@radix-ui/react-popover": "^1.1.14",
|
21 |
"@radix-ui/react-select": "^2.2.5",
|
@@ -24,7 +23,6 @@
|
|
24 |
"@radix-ui/react-tabs": "^1.1.12",
|
25 |
"@radix-ui/react-toggle": "^1.1.9",
|
26 |
"@radix-ui/react-toggle-group": "^1.1.10",
|
27 |
-
"@radix-ui/react-tooltip": "^1.2.7",
|
28 |
"@tailwindcss/vite": "^4.0.15",
|
29 |
"@xenova/transformers": "^2.17.2",
|
30 |
"body-parser": "^1.20.3",
|
|
|
12 |
},
|
13 |
"dependencies": {
|
14 |
"@huggingface/hub": "^1.1.1",
|
15 |
+
"@huggingface/inference": "^3.6.1",
|
16 |
"@monaco-editor/react": "^4.7.0",
|
17 |
"@radix-ui/react-avatar": "^1.1.10",
|
|
|
18 |
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
19 |
"@radix-ui/react-popover": "^1.1.14",
|
20 |
"@radix-ui/react-select": "^2.2.5",
|
|
|
23 |
"@radix-ui/react-tabs": "^1.1.12",
|
24 |
"@radix-ui/react-toggle": "^1.1.9",
|
25 |
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
|
26 |
"@tailwindcss/vite": "^4.0.15",
|
27 |
"@xenova/transformers": "^2.17.2",
|
28 |
"body-parser": "^1.20.3",
|
public/banner.png
CHANGED
![]() |
Git LFS Details
|
![]() |
Git LFS Details
|
server.js
CHANGED
@@ -204,9 +204,6 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
204 |
await uploadFiles({
|
205 |
repo,
|
206 |
files,
|
207 |
-
commitTitle: `${prompts[prompts.length - 1]} - ${
|
208 |
-
prompts.length > 1 ? "Follow Up" : "Initial"
|
209 |
-
} Deployment`,
|
210 |
accessToken: hf_token,
|
211 |
});
|
212 |
return res.status(200).send({ ok: true, path: repo.name });
|
@@ -219,14 +216,8 @@ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-
|
|
219 |
});
|
220 |
|
221 |
app.post("/api/ask-ai", async (req, res) => {
|
222 |
-
const { prompt, provider, model
|
223 |
-
if (!model) {
|
224 |
-
return res.status(400).send({
|
225 |
-
ok: false,
|
226 |
-
message: "Missing required fields",
|
227 |
-
});
|
228 |
-
}
|
229 |
-
if (!redesignMarkdown && !prompt) {
|
230 |
return res.status(400).send({
|
231 |
ok: false,
|
232 |
message: "Missing required fields",
|
@@ -254,7 +245,6 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
254 |
|
255 |
let { hf_token } = req.cookies;
|
256 |
let token = hf_token;
|
257 |
-
let billTo = null;
|
258 |
|
259 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
260 |
token = process.env.HF_TOKEN;
|
@@ -278,7 +268,6 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
278 |
}
|
279 |
|
280 |
token = process.env.DEFAULT_HF_TOKEN;
|
281 |
-
billTo = "huggingface";
|
282 |
}
|
283 |
|
284 |
// Set up response headers for streaming
|
@@ -304,27 +293,23 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
304 |
message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
|
305 |
});
|
306 |
}
|
|
|
307 |
try {
|
308 |
-
const chatCompletion = client.chatCompletionStream(
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
],
|
324 |
-
max_tokens: selectedProvider.max_tokens,
|
325 |
-
},
|
326 |
-
billTo ? { billTo } : {}
|
327 |
-
);
|
328 |
|
329 |
while (true) {
|
330 |
const { done, value } = await chatCompletion.next();
|
@@ -442,7 +427,6 @@ ${REPLACE_END}
|
|
442 |
|
443 |
let { hf_token } = req.cookies;
|
444 |
let token = hf_token;
|
445 |
-
let billTo = null;
|
446 |
|
447 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
448 |
token = process.env.HF_TOKEN;
|
@@ -466,45 +450,42 @@ ${REPLACE_END}
|
|
466 |
}
|
467 |
|
468 |
token = process.env.DEFAULT_HF_TOKEN;
|
469 |
-
billTo = "huggingface";
|
470 |
}
|
471 |
|
472 |
const client = new InferenceClient(token);
|
473 |
|
474 |
const selectedProvider = PROVIDERS[selectedModel.autoProvider];
|
|
|
475 |
try {
|
476 |
-
const response = await client.chatCompletion(
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
},
|
506 |
-
billTo ? { billTo } : {}
|
507 |
-
);
|
508 |
|
509 |
const chunk = response.choices[0]?.message?.content;
|
510 |
// TO DO: handle the case where there are multiple SEARCH/REPLACE blocks
|
@@ -517,8 +498,6 @@ ${REPLACE_END}
|
|
517 |
|
518 |
if (chunk) {
|
519 |
let newHtml = html;
|
520 |
-
// array of arrays to hold updated lines (start and end line numbers)
|
521 |
-
const updatedLines = [];
|
522 |
|
523 |
// Find all search/replace blocks in the chunk
|
524 |
let position = 0;
|
@@ -557,29 +536,9 @@ ${REPLACE_END}
|
|
557 |
if (searchBlock.trim() === "") {
|
558 |
// Inserting at the beginning
|
559 |
newHtml = `${replaceBlock}\n${newHtml}`;
|
560 |
-
|
561 |
-
// Track first line as updated
|
562 |
-
updatedLines.push([1, replaceBlock.split("\n").length]);
|
563 |
} else {
|
564 |
-
//
|
565 |
-
|
566 |
-
if (blockPosition !== -1) {
|
567 |
-
// Count lines before the search block
|
568 |
-
const beforeText = newHtml.substring(0, blockPosition);
|
569 |
-
const startLineNumber = beforeText.split("\n").length;
|
570 |
-
|
571 |
-
// Count lines in search and replace blocks
|
572 |
-
const replaceLines = replaceBlock.split("\n").length;
|
573 |
-
|
574 |
-
// Calculate end line (start + length of replaced content)
|
575 |
-
const endLineNumber = startLineNumber + replaceLines - 1;
|
576 |
-
|
577 |
-
// Track the line numbers that were updated
|
578 |
-
updatedLines.push([startLineNumber, endLineNumber]);
|
579 |
-
|
580 |
-
// Perform the replacement
|
581 |
-
newHtml = newHtml.replace(searchBlock, replaceBlock);
|
582 |
-
}
|
583 |
}
|
584 |
|
585 |
// Move position to after this block to find the next one
|
@@ -589,7 +548,6 @@ ${REPLACE_END}
|
|
589 |
return res.status(200).send({
|
590 |
ok: true,
|
591 |
html: newHtml,
|
592 |
-
updatedLines,
|
593 |
});
|
594 |
} else {
|
595 |
return res.status(400).send({
|
@@ -683,43 +641,6 @@ app.get("/api/remix/:username/:repo", async (req, res) => {
|
|
683 |
});
|
684 |
}
|
685 |
});
|
686 |
-
|
687 |
-
app.post("/api/re-design", async (req, res) => {
|
688 |
-
const { url } = req.body;
|
689 |
-
if (!url) {
|
690 |
-
return res.status(400).send({
|
691 |
-
ok: false,
|
692 |
-
message: "Missing required fields",
|
693 |
-
});
|
694 |
-
}
|
695 |
-
|
696 |
-
// call the api https://r.jina.ai/{url} and return the response
|
697 |
-
try {
|
698 |
-
const response = await fetch(
|
699 |
-
`https://r.jina.ai/${encodeURIComponent(url)}`,
|
700 |
-
{
|
701 |
-
method: "POST",
|
702 |
-
}
|
703 |
-
);
|
704 |
-
if (!response.ok) {
|
705 |
-
return res.status(500).send({
|
706 |
-
ok: false,
|
707 |
-
message: "Failed to fetch redesign",
|
708 |
-
});
|
709 |
-
}
|
710 |
-
// return the html response
|
711 |
-
const markdown = await response.text();
|
712 |
-
return res.status(200).send({
|
713 |
-
ok: true,
|
714 |
-
markdown,
|
715 |
-
});
|
716 |
-
} catch (error) {
|
717 |
-
return res.status(500).send({
|
718 |
-
ok: false,
|
719 |
-
message: error.message,
|
720 |
-
});
|
721 |
-
}
|
722 |
-
});
|
723 |
app.get("*", (_req, res) => {
|
724 |
res.sendFile(path.join(__dirname, "dist", "index.html"));
|
725 |
});
|
|
|
204 |
await uploadFiles({
|
205 |
repo,
|
206 |
files,
|
|
|
|
|
|
|
207 |
accessToken: hf_token,
|
208 |
});
|
209 |
return res.status(200).send({ ok: true, path: repo.name });
|
|
|
216 |
});
|
217 |
|
218 |
app.post("/api/ask-ai", async (req, res) => {
|
219 |
+
const { prompt, provider, model } = req.body;
|
220 |
+
if (!prompt || !model) {
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
return res.status(400).send({
|
222 |
ok: false,
|
223 |
message: "Missing required fields",
|
|
|
245 |
|
246 |
let { hf_token } = req.cookies;
|
247 |
let token = hf_token;
|
|
|
248 |
|
249 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
250 |
token = process.env.HF_TOKEN;
|
|
|
268 |
}
|
269 |
|
270 |
token = process.env.DEFAULT_HF_TOKEN;
|
|
|
271 |
}
|
272 |
|
273 |
// Set up response headers for streaming
|
|
|
293 |
message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
|
294 |
});
|
295 |
}
|
296 |
+
|
297 |
try {
|
298 |
+
const chatCompletion = client.chatCompletionStream({
|
299 |
+
model: selectedModel.value,
|
300 |
+
provider: selectedProvider.id,
|
301 |
+
messages: [
|
302 |
+
{
|
303 |
+
role: "system",
|
304 |
+
content: initialSystemPrompt,
|
305 |
+
},
|
306 |
+
{
|
307 |
+
role: "user",
|
308 |
+
content: prompt,
|
309 |
+
},
|
310 |
+
],
|
311 |
+
max_tokens: selectedProvider.max_tokens,
|
312 |
+
});
|
|
|
|
|
|
|
|
|
|
|
313 |
|
314 |
while (true) {
|
315 |
const { done, value } = await chatCompletion.next();
|
|
|
427 |
|
428 |
let { hf_token } = req.cookies;
|
429 |
let token = hf_token;
|
|
|
430 |
|
431 |
if (process.env.HF_TOKEN && process.env.HF_TOKEN !== "") {
|
432 |
token = process.env.HF_TOKEN;
|
|
|
450 |
}
|
451 |
|
452 |
token = process.env.DEFAULT_HF_TOKEN;
|
|
|
453 |
}
|
454 |
|
455 |
const client = new InferenceClient(token);
|
456 |
|
457 |
const selectedProvider = PROVIDERS[selectedModel.autoProvider];
|
458 |
+
|
459 |
try {
|
460 |
+
const response = await client.chatCompletion({
|
461 |
+
model: selectedModel.value,
|
462 |
+
provider: selectedProvider.id,
|
463 |
+
messages: [
|
464 |
+
{
|
465 |
+
role: "system",
|
466 |
+
content: followUpSystemPrompt,
|
467 |
+
},
|
468 |
+
{
|
469 |
+
role: "user",
|
470 |
+
content: previousPrompt
|
471 |
+
? previousPrompt
|
472 |
+
: "You are modifying the HTML file based on the user's request.",
|
473 |
+
},
|
474 |
+
{
|
475 |
+
role: "assistant",
|
476 |
+
content: `The current code is: \n\`\`\`html\n${html}\n\`\`\``,
|
477 |
+
},
|
478 |
+
{
|
479 |
+
role: "user",
|
480 |
+
content: prompt,
|
481 |
+
},
|
482 |
+
],
|
483 |
+
...(selectedProvider.id !== "sambanova"
|
484 |
+
? {
|
485 |
+
max_tokens: selectedProvider.max_tokens,
|
486 |
+
}
|
487 |
+
: {}),
|
488 |
+
});
|
|
|
|
|
|
|
489 |
|
490 |
const chunk = response.choices[0]?.message?.content;
|
491 |
// TO DO: handle the case where there are multiple SEARCH/REPLACE blocks
|
|
|
498 |
|
499 |
if (chunk) {
|
500 |
let newHtml = html;
|
|
|
|
|
501 |
|
502 |
// Find all search/replace blocks in the chunk
|
503 |
let position = 0;
|
|
|
536 |
if (searchBlock.trim() === "") {
|
537 |
// Inserting at the beginning
|
538 |
newHtml = `${replaceBlock}\n${newHtml}`;
|
|
|
|
|
|
|
539 |
} else {
|
540 |
+
// Replacing existing code
|
541 |
+
newHtml = newHtml.replace(searchBlock, replaceBlock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
542 |
}
|
543 |
|
544 |
// Move position to after this block to find the next one
|
|
|
548 |
return res.status(200).send({
|
549 |
ok: true,
|
550 |
html: newHtml,
|
|
|
551 |
});
|
552 |
} else {
|
553 |
return res.status(400).send({
|
|
|
641 |
});
|
642 |
}
|
643 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
644 |
app.get("*", (_req, res) => {
|
645 |
res.sendFile(path.join(__dirname, "dist", "index.html"));
|
646 |
});
|
src/assets/index.css
CHANGED
@@ -136,7 +136,3 @@
|
|
136 |
.monaco-editor .line-numbers {
|
137 |
@apply !text-neutral-500;
|
138 |
}
|
139 |
-
|
140 |
-
.matched-line {
|
141 |
-
@apply bg-sky-500/30;
|
142 |
-
}
|
|
|
136 |
.monaco-editor .line-numbers {
|
137 |
@apply !text-neutral-500;
|
138 |
}
|
|
|
|
|
|
|
|
src/assets/linux.png
DELETED
Binary file (8.63 kB)
|
|
src/components/ask-ai/ask-ai.tsx
CHANGED
@@ -1,10 +1,11 @@
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import { useState, useRef } from "react";
|
|
|
|
|
3 |
import classNames from "classnames";
|
4 |
import { toast } from "sonner";
|
5 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
6 |
-
import {
|
7 |
-
import { FaStopCircle } from "react-icons/fa";
|
8 |
|
9 |
import Login from "../login/login";
|
10 |
import { defaultHTML } from "../../../utils/consts";
|
@@ -13,11 +14,7 @@ import Settings from "../settings/settings";
|
|
13 |
import ProModal from "../pro-modal/pro-modal";
|
14 |
import { Button } from "../ui/button";
|
15 |
// @ts-expect-error not needed
|
16 |
-
import { MODELS } from "
|
17 |
-
import Loading from "../loading/loading";
|
18 |
-
import { HtmlHistory } from "../../../utils/types";
|
19 |
-
import InviteFriends from "../invite-friends/invite-friends";
|
20 |
-
import ReImagine from "../re-imagine/re-imagine";
|
21 |
|
22 |
function AskAI({
|
23 |
html,
|
@@ -33,9 +30,8 @@ function AskAI({
|
|
33 |
onScrollToBottom: () => void;
|
34 |
isAiWorking: boolean;
|
35 |
onNewPrompt: (prompt: string) => void;
|
36 |
-
htmlHistory?: HtmlHistory[];
|
37 |
setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
|
38 |
-
onSuccess: (h: string, p: string
|
39 |
}) {
|
40 |
const refThink = useRef<HTMLDivElement | null>(null);
|
41 |
|
@@ -51,14 +47,12 @@ function AskAI({
|
|
51 |
const [think, setThink] = useState<string | undefined>(undefined);
|
52 |
const [openThink, setOpenThink] = useState(false);
|
53 |
const [isThinking, setIsThinking] = useState(true);
|
54 |
-
const [controller, setController] = useState<AbortController | null>(null);
|
55 |
|
56 |
const audio = new Audio(SuccessSound);
|
57 |
audio.volume = 0.5;
|
58 |
|
59 |
-
const callAi = async (
|
60 |
-
if (isAiWorking) return;
|
61 |
-
if (!redesignMarkdown && !prompt.trim()) return;
|
62 |
setisAiWorking(true);
|
63 |
setProviderError("");
|
64 |
setThink("");
|
@@ -70,11 +64,9 @@ function AskAI({
|
|
70 |
let lastRenderTime = 0;
|
71 |
|
72 |
const isFollowUp = html !== defaultHTML;
|
73 |
-
const abortController = new AbortController();
|
74 |
-
setController(abortController);
|
75 |
try {
|
76 |
onNewPrompt(prompt);
|
77 |
-
if (isFollowUp
|
78 |
const request = await fetch("/api/ask-ai", {
|
79 |
method: "PUT",
|
80 |
body: JSON.stringify({
|
@@ -86,7 +78,6 @@ function AskAI({
|
|
86 |
headers: {
|
87 |
"Content-Type": "application/json",
|
88 |
},
|
89 |
-
signal: abortController.signal,
|
90 |
});
|
91 |
if (request && request.body) {
|
92 |
const res = await request.json();
|
@@ -109,7 +100,7 @@ function AskAI({
|
|
109 |
setPreviousPrompt(prompt);
|
110 |
setPrompt("");
|
111 |
setisAiWorking(false);
|
112 |
-
onSuccess(res.html, prompt
|
113 |
audio.play();
|
114 |
}
|
115 |
} else {
|
@@ -119,12 +110,10 @@ function AskAI({
|
|
119 |
prompt,
|
120 |
provider,
|
121 |
model,
|
122 |
-
redesignMarkdown,
|
123 |
}),
|
124 |
headers: {
|
125 |
"Content-Type": "application/json",
|
126 |
},
|
127 |
-
signal: abortController.signal,
|
128 |
});
|
129 |
if (request && request.body) {
|
130 |
if (!request.ok) {
|
@@ -234,17 +223,6 @@ function AskAI({
|
|
234 |
}
|
235 |
};
|
236 |
|
237 |
-
const stopController = () => {
|
238 |
-
if (controller) {
|
239 |
-
controller.abort();
|
240 |
-
setController(null);
|
241 |
-
setisAiWorking(false);
|
242 |
-
setThink("");
|
243 |
-
setOpenThink(false);
|
244 |
-
setIsThinking(false);
|
245 |
-
}
|
246 |
-
};
|
247 |
-
|
248 |
useUpdateEffect(() => {
|
249 |
if (refThink.current) {
|
250 |
refThink.current.scrollTop = refThink.current.scrollHeight;
|
@@ -257,8 +235,10 @@ function AskAI({
|
|
257 |
}
|
258 |
}, [isThinking]);
|
259 |
|
|
|
|
|
260 |
return (
|
261 |
-
<div className="bg-neutral-800 border border-neutral-700 rounded-
|
262 |
{think && (
|
263 |
<div className="w-full border-b border-neutral-700 relative overflow-hidden">
|
264 |
<header
|
@@ -268,7 +248,7 @@ function AskAI({
|
|
268 |
}}
|
269 |
>
|
270 |
<p className="text-sm font-medium text-neutral-300 group-hover:text-neutral-200 transition-colors duration-200">
|
271 |
-
{isThinking ? "
|
272 |
</p>
|
273 |
<ChevronDown
|
274 |
className={classNames(
|
@@ -296,46 +276,37 @@ function AskAI({
|
|
296 |
</main>
|
297 |
</div>
|
298 |
)}
|
299 |
-
<div
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
{isAiWorking && (
|
301 |
-
<div className="absolute bg-neutral-800 rounded-lg bottom-0 left-
|
302 |
-
<
|
303 |
-
|
304 |
-
|
305 |
-
AI is {isThinking ? "thinking" : "coding"}...{" "}
|
306 |
-
</p>
|
307 |
-
</div>
|
308 |
-
<div
|
309 |
-
className="text-xs text-neutral-400 px-1 py-0.5 rounded-md border border-neutral-600 flex items-center justify-center gap-1.5 bg-neutral-800 hover:brightness-110 transition-all duration-200 cursor-pointer"
|
310 |
-
onClick={stopController}
|
311 |
-
>
|
312 |
-
<FaStopCircle />
|
313 |
-
Stop generation
|
314 |
-
</div>
|
315 |
</div>
|
316 |
)}
|
|
|
317 |
<input
|
318 |
type="text"
|
319 |
disabled={isAiWorking}
|
320 |
-
className="w-full bg-transparent text-sm outline-none text-white placeholder:text-neutral-400
|
321 |
-
placeholder={
|
322 |
-
hasAsked ? "Ask DeepSite for edits" : "Ask DeepSite anything..."
|
323 |
-
}
|
324 |
value={prompt}
|
325 |
onChange={(e) => setPrompt(e.target.value)}
|
326 |
onKeyDown={(e) => {
|
327 |
-
if (e.key === "Enter"
|
328 |
callAi();
|
329 |
}
|
330 |
}}
|
331 |
/>
|
332 |
-
</div>
|
333 |
-
<div className="flex items-center justify-between gap-2 px-4 pb-3">
|
334 |
-
<div className="flex-1 flex items-center justify-start gap-1.5">
|
335 |
-
<ReImagine onRedesign={(md) => callAi(md)} />
|
336 |
-
<InviteFriends />
|
337 |
-
</div>
|
338 |
<div className="flex items-center justify-end gap-2">
|
|
|
339 |
<Settings
|
340 |
provider={provider as string}
|
341 |
model={model as string}
|
@@ -346,11 +317,12 @@ function AskAI({
|
|
346 |
onClose={setOpenProvider}
|
347 |
/>
|
348 |
<Button
|
349 |
-
|
|
|
350 |
disabled={isAiWorking || !prompt.trim()}
|
351 |
-
onClick={
|
352 |
>
|
353 |
-
<
|
354 |
</Button>
|
355 |
</div>
|
356 |
</div>
|
@@ -365,7 +337,7 @@ function AskAI({
|
|
365 |
></div>
|
366 |
<div
|
367 |
className={classNames(
|
368 |
-
"absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 border border-
|
369 |
{
|
370 |
"opacity-0 pointer-events-none": !open,
|
371 |
}
|
|
|
1 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2 |
import { useState, useRef } from "react";
|
3 |
+
import { RiSparkling2Fill } from "react-icons/ri";
|
4 |
+
import { GrSend } from "react-icons/gr";
|
5 |
import classNames from "classnames";
|
6 |
import { toast } from "sonner";
|
7 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
8 |
+
import { ChevronDown } from "lucide-react";
|
|
|
9 |
|
10 |
import Login from "../login/login";
|
11 |
import { defaultHTML } from "../../../utils/consts";
|
|
|
14 |
import ProModal from "../pro-modal/pro-modal";
|
15 |
import { Button } from "../ui/button";
|
16 |
// @ts-expect-error not needed
|
17 |
+
import { MODELS } from "./../../../utils/providers";
|
|
|
|
|
|
|
|
|
18 |
|
19 |
function AskAI({
|
20 |
html,
|
|
|
30 |
onScrollToBottom: () => void;
|
31 |
isAiWorking: boolean;
|
32 |
onNewPrompt: (prompt: string) => void;
|
|
|
33 |
setisAiWorking: React.Dispatch<React.SetStateAction<boolean>>;
|
34 |
+
onSuccess: (h: string, p: string) => void;
|
35 |
}) {
|
36 |
const refThink = useRef<HTMLDivElement | null>(null);
|
37 |
|
|
|
47 |
const [think, setThink] = useState<string | undefined>(undefined);
|
48 |
const [openThink, setOpenThink] = useState(false);
|
49 |
const [isThinking, setIsThinking] = useState(true);
|
|
|
50 |
|
51 |
const audio = new Audio(SuccessSound);
|
52 |
audio.volume = 0.5;
|
53 |
|
54 |
+
const callAi = async () => {
|
55 |
+
if (isAiWorking || !prompt.trim()) return;
|
|
|
56 |
setisAiWorking(true);
|
57 |
setProviderError("");
|
58 |
setThink("");
|
|
|
64 |
let lastRenderTime = 0;
|
65 |
|
66 |
const isFollowUp = html !== defaultHTML;
|
|
|
|
|
67 |
try {
|
68 |
onNewPrompt(prompt);
|
69 |
+
if (isFollowUp) {
|
70 |
const request = await fetch("/api/ask-ai", {
|
71 |
method: "PUT",
|
72 |
body: JSON.stringify({
|
|
|
78 |
headers: {
|
79 |
"Content-Type": "application/json",
|
80 |
},
|
|
|
81 |
});
|
82 |
if (request && request.body) {
|
83 |
const res = await request.json();
|
|
|
100 |
setPreviousPrompt(prompt);
|
101 |
setPrompt("");
|
102 |
setisAiWorking(false);
|
103 |
+
onSuccess(res.html, prompt);
|
104 |
audio.play();
|
105 |
}
|
106 |
} else {
|
|
|
110 |
prompt,
|
111 |
provider,
|
112 |
model,
|
|
|
113 |
}),
|
114 |
headers: {
|
115 |
"Content-Type": "application/json",
|
116 |
},
|
|
|
117 |
});
|
118 |
if (request && request.body) {
|
119 |
if (!request.ok) {
|
|
|
223 |
}
|
224 |
};
|
225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
useUpdateEffect(() => {
|
227 |
if (refThink.current) {
|
228 |
refThink.current.scrollTop = refThink.current.scrollHeight;
|
|
|
235 |
}
|
236 |
}, [isThinking]);
|
237 |
|
238 |
+
// TODO: auto scroll is not working properly, fix it
|
239 |
+
|
240 |
return (
|
241 |
+
<div className="bg-neutral-800 border border-neutral-700 rounded-lg ring-[5px] focus-within:ring-sky-500/50 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
|
242 |
{think && (
|
243 |
<div className="w-full border-b border-neutral-700 relative overflow-hidden">
|
244 |
<header
|
|
|
248 |
}}
|
249 |
>
|
250 |
<p className="text-sm font-medium text-neutral-300 group-hover:text-neutral-200 transition-colors duration-200">
|
251 |
+
{isThinking ? "AI is thinking..." : "AI's plan"}
|
252 |
</p>
|
253 |
<ChevronDown
|
254 |
className={classNames(
|
|
|
276 |
</main>
|
277 |
</div>
|
278 |
)}
|
279 |
+
<div
|
280 |
+
className={classNames(
|
281 |
+
"w-full relative flex items-center justify-between pl-3.5 p-2 lg:p-2 lg:pl-4",
|
282 |
+
{
|
283 |
+
"animate-pulse": isAiWorking,
|
284 |
+
}
|
285 |
+
)}
|
286 |
+
>
|
287 |
{isAiWorking && (
|
288 |
+
<div className="absolute bg-neutral-800 rounded-lg bottom-0 left-11 w-[calc(100%-92px)] h-full z-1 flex items-center justify-start max-lg:text-sm">
|
289 |
+
<p className="text-neutral-400 font-code">
|
290 |
+
AI is {isThinking ? "thinking" : "coding"}...
|
291 |
+
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
</div>
|
293 |
)}
|
294 |
+
<RiSparkling2Fill className="size-5 text-neutral-400 group-focus-within:text-sky-500" />
|
295 |
<input
|
296 |
type="text"
|
297 |
disabled={isAiWorking}
|
298 |
+
className="w-full bg-transparent max-lg:text-sm outline-none px-3 text-white placeholder:text-neutral-400 font-code"
|
299 |
+
placeholder={hasAsked ? "Ask AI for edits" : "Ask AI anything..."}
|
|
|
|
|
300 |
value={prompt}
|
301 |
onChange={(e) => setPrompt(e.target.value)}
|
302 |
onKeyDown={(e) => {
|
303 |
+
if (e.key === "Enter") {
|
304 |
callAi();
|
305 |
}
|
306 |
}}
|
307 |
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
308 |
<div className="flex items-center justify-end gap-2">
|
309 |
+
{/* <SpeechPrompt setPrompt={setPrompt} /> */}
|
310 |
<Settings
|
311 |
provider={provider as string}
|
312 |
model={model as string}
|
|
|
317 |
onClose={setOpenProvider}
|
318 |
/>
|
319 |
<Button
|
320 |
+
variant="pink"
|
321 |
+
size="icon"
|
322 |
disabled={isAiWorking || !prompt.trim()}
|
323 |
+
onClick={callAi}
|
324 |
>
|
325 |
+
<GrSend className="-translate-x-[1px]" />
|
326 |
</Button>
|
327 |
</div>
|
328 |
</div>
|
|
|
337 |
></div>
|
338 |
<div
|
339 |
className={classNames(
|
340 |
+
"absolute top-0 -translate-y-[calc(100%+8px)] right-0 z-10 w-80 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
341 |
{
|
342 |
"opacity-0 pointer-events-none": !open,
|
343 |
}
|
src/components/deploy-button/deploy-button.tsx
CHANGED
@@ -10,6 +10,20 @@ import LoadButton from "../load-button/load-button";
|
|
10 |
import { Button } from "../ui/button";
|
11 |
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
function DeployButton({
|
14 |
html,
|
15 |
auth,
|
@@ -46,17 +60,11 @@ function DeployButton({
|
|
46 |
});
|
47 |
const response = await request.json();
|
48 |
if (response.ok) {
|
49 |
-
toast.success(
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
`https://huggingface.co/spaces/${response.path ?? path}`,
|
55 |
-
"_blank"
|
56 |
-
);
|
57 |
-
},
|
58 |
-
},
|
59 |
-
});
|
60 |
setPath(response.path);
|
61 |
} else {
|
62 |
toast.error(response.message);
|
@@ -84,7 +92,7 @@ function DeployButton({
|
|
84 |
</div>
|
85 |
</PopoverTrigger>
|
86 |
<PopoverContent
|
87 |
-
className="
|
88 |
align="end"
|
89 |
>
|
90 |
{!auth ? (
|
|
|
10 |
import { Button } from "../ui/button";
|
11 |
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
12 |
|
13 |
+
const MsgToast = ({ url }: { url: string }) => (
|
14 |
+
<div className="w-full flex items-center justify-center gap-3">
|
15 |
+
Your space is live!
|
16 |
+
<button
|
17 |
+
className="bg-black text-sm block text-white rounded-md px-3 py-1.5 hover:bg-gray-900 cursor-pointer"
|
18 |
+
onClick={() => {
|
19 |
+
window.open(url, "_blank");
|
20 |
+
}}
|
21 |
+
>
|
22 |
+
See Space
|
23 |
+
</button>
|
24 |
+
</div>
|
25 |
+
);
|
26 |
+
|
27 |
function DeployButton({
|
28 |
html,
|
29 |
auth,
|
|
|
60 |
});
|
61 |
const response = await request.json();
|
62 |
if (response.ok) {
|
63 |
+
toast.success(
|
64 |
+
<MsgToast
|
65 |
+
url={`https://huggingface.co/spaces/${response.path ?? path}`}
|
66 |
+
/>
|
67 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
setPath(response.path);
|
69 |
} else {
|
70 |
toast.error(response.message);
|
|
|
92 |
</div>
|
93 |
</PopoverTrigger>
|
94 |
<PopoverContent
|
95 |
+
className="p-0 overflow-hidden !bg-neutral-900"
|
96 |
align="end"
|
97 |
>
|
98 |
{!auth ? (
|
src/components/history/history.tsx
CHANGED
@@ -13,11 +13,11 @@ export default function History({
|
|
13 |
<Popover>
|
14 |
<PopoverTrigger asChild>
|
15 |
<Button variant="ghost" size="sm" className="max-lg:hidden">
|
16 |
-
{history?.length}
|
17 |
</Button>
|
18 |
</PopoverTrigger>
|
19 |
<PopoverContent
|
20 |
-
className="!
|
21 |
align="start"
|
22 |
>
|
23 |
<header className="text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
|
|
13 |
<Popover>
|
14 |
<PopoverTrigger asChild>
|
15 |
<Button variant="ghost" size="sm" className="max-lg:hidden">
|
16 |
+
{history?.length} edits
|
17 |
</Button>
|
18 |
</PopoverTrigger>
|
19 |
<PopoverContent
|
20 |
+
className="!p-0 overflow-hidden !bg-neutral-900"
|
21 |
align="start"
|
22 |
>
|
23 |
<header className="text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
src/components/invite-friends/invite-friends.tsx
DELETED
@@ -1,78 +0,0 @@
|
|
1 |
-
import { TiUserAdd } from "react-icons/ti";
|
2 |
-
import { Link } from "lucide-react";
|
3 |
-
import { FaXTwitter } from "react-icons/fa6";
|
4 |
-
|
5 |
-
import { Button } from "../ui/button";
|
6 |
-
import { Dialog, DialogContent, DialogTrigger } from "../ui/dialog";
|
7 |
-
import { useCopyToClipboard } from "react-use";
|
8 |
-
import { toast } from "sonner";
|
9 |
-
export default function InviteFriends() {
|
10 |
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
11 |
-
const [_, copyToClipboard] = useCopyToClipboard();
|
12 |
-
|
13 |
-
return (
|
14 |
-
<Dialog>
|
15 |
-
<form>
|
16 |
-
<DialogTrigger asChild>
|
17 |
-
<Button
|
18 |
-
size="iconXs"
|
19 |
-
variant="outline"
|
20 |
-
className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
|
21 |
-
>
|
22 |
-
<TiUserAdd className="size-4" />
|
23 |
-
</Button>
|
24 |
-
</DialogTrigger>
|
25 |
-
<DialogContent className="sm:max-w-lg lg:!p-8 !rounded-3xl !bg-white !border-neutral-100">
|
26 |
-
<main>
|
27 |
-
<div className="flex items-center justify-start -space-x-4 mb-5">
|
28 |
-
<div className="size-11 rounded-full bg-pink-300 shadow-2xs flex items-center justify-center text-2xl">
|
29 |
-
😎
|
30 |
-
</div>
|
31 |
-
<div className="size-11 rounded-full bg-amber-300 shadow-2xs flex items-center justify-center text-2xl z-2">
|
32 |
-
😇
|
33 |
-
</div>
|
34 |
-
<div className="size-11 rounded-full bg-sky-300 shadow-2xs flex items-center justify-center text-2xl">
|
35 |
-
😜
|
36 |
-
</div>
|
37 |
-
</div>
|
38 |
-
<p className="text-xl font-semibold text-neutral-950 max-w-[200px]">
|
39 |
-
Invite your friends to join us!
|
40 |
-
</p>
|
41 |
-
<p className="text-sm text-neutral-500 mt-2 max-w-sm">
|
42 |
-
Support us and share the love and let them know about our awesome
|
43 |
-
platform.
|
44 |
-
</p>
|
45 |
-
<div className="mt-4 space-x-3.5">
|
46 |
-
<a
|
47 |
-
href="https://x.com/intent/post?url=https://enzostvs-deepsite.hf.space/&text=Checkout%20this%20awesome%20Ai%20Tool!%20Vibe%20coding%20has%20never%20been%20so%20easy✨"
|
48 |
-
target="_blank"
|
49 |
-
rel="noopener noreferrer"
|
50 |
-
>
|
51 |
-
<Button
|
52 |
-
variant="ghostWhite"
|
53 |
-
size="sm"
|
54 |
-
className="!text-neutral-700"
|
55 |
-
>
|
56 |
-
<FaXTwitter className="size-4" />
|
57 |
-
Share on
|
58 |
-
</Button>
|
59 |
-
</a>
|
60 |
-
<Button
|
61 |
-
variant="ghostWhite"
|
62 |
-
size="sm"
|
63 |
-
className="!text-neutral-700"
|
64 |
-
onClick={() => {
|
65 |
-
copyToClipboard("https://enzostvs-deepsite.hf.space/");
|
66 |
-
toast.success("Invite link copied to clipboard!");
|
67 |
-
}}
|
68 |
-
>
|
69 |
-
<Link className="size-4" />
|
70 |
-
Copy Invite Link
|
71 |
-
</Button>
|
72 |
-
</div>
|
73 |
-
</main>
|
74 |
-
</DialogContent>
|
75 |
-
</form>
|
76 |
-
</Dialog>
|
77 |
-
);
|
78 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/load-button/load-button.tsx
CHANGED
@@ -64,7 +64,7 @@ function LoadButton({
|
|
64 |
</p>
|
65 |
</PopoverTrigger>
|
66 |
<PopoverContent
|
67 |
-
className="
|
68 |
align="end"
|
69 |
>
|
70 |
<header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
|
|
64 |
</p>
|
65 |
</PopoverTrigger>
|
66 |
<PopoverContent
|
67 |
+
className="p-0 overflow-hidden !bg-neutral-900"
|
68 |
align="end"
|
69 |
>
|
70 |
<header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
src/components/loading/loading.tsx
CHANGED
@@ -1,21 +1,8 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
function Loading({
|
4 |
-
overlay = true,
|
5 |
-
className,
|
6 |
-
}: {
|
7 |
-
overlay?: boolean;
|
8 |
-
className?: string;
|
9 |
-
}) {
|
10 |
return (
|
11 |
-
<div
|
12 |
-
className={classNames("", {
|
13 |
-
"absolute left-0 top-0 h-full w-full flex items-center justify-center z-20 bg-black/50 rounded-full":
|
14 |
-
overlay,
|
15 |
-
})}
|
16 |
-
>
|
17 |
<svg
|
18 |
-
className=
|
19 |
xmlns="http://www.w3.org/2000/svg"
|
20 |
fill="none"
|
21 |
viewBox="0 0 24 24"
|
|
|
1 |
+
function Loading() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
return (
|
3 |
+
<div className="absolute left-0 top-0 h-full w-full flex items-center justify-center z-20 bg-black/50 rounded-full">
|
|
|
|
|
|
|
|
|
|
|
4 |
<svg
|
5 |
+
className="size-5 animate-spin text-white"
|
6 |
xmlns="http://www.w3.org/2000/svg"
|
7 |
fill="none"
|
8 |
viewBox="0 0 24 24"
|
src/components/pro-modal/pro-modal.tsx
CHANGED
@@ -1,8 +1,6 @@
|
|
|
|
1 |
import { useLocalStorage } from "react-use";
|
2 |
import { defaultHTML } from "../../../utils/consts";
|
3 |
-
import { Dialog, DialogContent } from "../ui/dialog";
|
4 |
-
import { Button } from "../ui/button";
|
5 |
-
import { CheckCheck } from "lucide-react";
|
6 |
|
7 |
function ProModal({
|
8 |
open,
|
@@ -22,73 +20,51 @@ function ProModal({
|
|
22 |
};
|
23 |
|
24 |
return (
|
25 |
-
|
26 |
-
<
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
</p>
|
42 |
-
<p className="text-
|
43 |
-
It
|
|
|
44 |
</p>
|
45 |
-
<
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
<ul className="mt-3 space-y-1 text-neutral-500">
|
50 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
51 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
52 |
-
DeepSite unlimited access to all Inference Providers
|
53 |
-
</li>
|
54 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
55 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
56 |
-
Get highest priority and 8x more quota on Spaces ZeroGPU
|
57 |
-
</li>
|
58 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
59 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
60 |
-
Activate Dataset Viewer on private datasets
|
61 |
-
</li>
|
62 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
63 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
64 |
-
Get exclusive early access to new features and updates
|
65 |
-
</li>
|
66 |
-
<li className="text-sm space-x-2 flex items-center justify-start gap-2">
|
67 |
-
<CheckCheck className="text-emerald-500 size-4" />
|
68 |
-
Get free credits across all Inference Providers
|
69 |
-
</li>
|
70 |
-
<li className="text-sm text-neutral-500 space-x-2 flex items-center justify-start gap-2 mt-3">
|
71 |
-
... and much more!
|
72 |
-
</li>
|
73 |
-
</ul>
|
74 |
-
<Button
|
75 |
-
variant="gray"
|
76 |
-
size="lg"
|
77 |
-
className="w-full !text-base !h-11 mt-8"
|
78 |
onClick={handleProClick}
|
79 |
>
|
80 |
Subscribe to PRO ($9/month)
|
81 |
-
</
|
82 |
</main>
|
83 |
-
</
|
84 |
-
|
85 |
);
|
86 |
}
|
87 |
-
|
88 |
-
<span
|
89 |
-
className={`${className} bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg rounded-md px-2.5 py-0.5`}
|
90 |
-
>
|
91 |
-
PRO
|
92 |
-
</span>
|
93 |
-
);
|
94 |
export default ProModal;
|
|
|
1 |
+
import classNames from "classnames";
|
2 |
import { useLocalStorage } from "react-use";
|
3 |
import { defaultHTML } from "../../../utils/consts";
|
|
|
|
|
|
|
4 |
|
5 |
function ProModal({
|
6 |
open,
|
|
|
20 |
};
|
21 |
|
22 |
return (
|
23 |
+
<>
|
24 |
+
<div
|
25 |
+
className={classNames(
|
26 |
+
"h-screen w-screen bg-black/20 fixed left-0 top-0 z-40",
|
27 |
+
{
|
28 |
+
"opacity-0 pointer-events-none": !open,
|
29 |
+
}
|
30 |
+
)}
|
31 |
+
onClick={() => onClose(false)}
|
32 |
+
></div>
|
33 |
+
<div
|
34 |
+
className={classNames(
|
35 |
+
"absolute top-0 -translate-y-[calc(100%+16px)] right-0 z-40 w-96 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
|
36 |
+
{
|
37 |
+
"opacity-0 pointer-events-none": !open,
|
38 |
+
}
|
39 |
+
)}
|
40 |
+
>
|
41 |
+
<header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
|
42 |
+
<span className="bg-linear-to-br shadow-green-500/10 dark:shadow-green-500/20 inline-block -skew-x-12 border border-gray-200 from-pink-300 via-green-200 to-yellow-200 text-xs font-bold text-black shadow-lg dark:from-pink-500 dark:via-green-500 dark:to-yellow-500 dark:text-black rounded-lg px-2.5 py-0.5 ">
|
43 |
+
PRO
|
44 |
+
</span>
|
45 |
+
Your free inference quota is exhausted
|
46 |
+
</header>
|
47 |
+
<main className="px-4 pt-3 pb-4">
|
48 |
+
<p className="text-gray-950 text-sm font-semibold flex items-center justify-between">
|
49 |
+
Upgrade to a PRO account to activate Inference Providers and
|
50 |
+
continue using DeepSite.
|
51 |
</p>
|
52 |
+
<p className="text-sm text-pretty text-gray-500 mt-2">
|
53 |
+
It also unlocks thousands of Space apps powered by ZeroGPU for 3d,
|
54 |
+
audio, music, video and more!
|
55 |
</p>
|
56 |
+
<a
|
57 |
+
href="https://huggingface.co/subscribe/pro"
|
58 |
+
target="_blank"
|
59 |
+
className="mt-4 bg-black text-white cursor-pointer rounded-full py-2 px-3 text-sm font-medium w-full block text-center hover:bg-gray-800 transition duration-200 ease-in-out"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
onClick={handleProClick}
|
61 |
>
|
62 |
Subscribe to PRO ($9/month)
|
63 |
+
</a>
|
64 |
</main>
|
65 |
+
</div>
|
66 |
+
</>
|
67 |
);
|
68 |
}
|
69 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
export default ProModal;
|
src/components/re-imagine/re-imagine.tsx
DELETED
@@ -1,136 +0,0 @@
|
|
1 |
-
import { useState } from "react";
|
2 |
-
import { Paintbrush } from "lucide-react";
|
3 |
-
import { toast } from "sonner";
|
4 |
-
|
5 |
-
import { Button } from "../ui/button";
|
6 |
-
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
7 |
-
import { Input } from "../ui/input";
|
8 |
-
import Loading from "../loading/loading";
|
9 |
-
|
10 |
-
export default function ReImagine({
|
11 |
-
onRedesign,
|
12 |
-
}: {
|
13 |
-
onRedesign: (md: string) => void;
|
14 |
-
}) {
|
15 |
-
const [url, setUrl] = useState<string>("");
|
16 |
-
const [open, setOpen] = useState(false);
|
17 |
-
const [isLoading, setIsLoading] = useState(false);
|
18 |
-
|
19 |
-
const checkIfUrlIsValid = (url: string) => {
|
20 |
-
const urlPattern = new RegExp(
|
21 |
-
/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/,
|
22 |
-
"i"
|
23 |
-
);
|
24 |
-
return urlPattern.test(url);
|
25 |
-
};
|
26 |
-
|
27 |
-
const handleClick = async () => {
|
28 |
-
if (!url) {
|
29 |
-
toast.error("Please enter a URL.");
|
30 |
-
return;
|
31 |
-
}
|
32 |
-
if (!checkIfUrlIsValid(url)) {
|
33 |
-
toast.error("Please enter a valid URL.");
|
34 |
-
return;
|
35 |
-
}
|
36 |
-
// Here you would typically handle the re-design logic
|
37 |
-
setIsLoading(true);
|
38 |
-
const request = await fetch("/api/re-design", {
|
39 |
-
method: "POST",
|
40 |
-
body: JSON.stringify({ url }),
|
41 |
-
headers: {
|
42 |
-
"Content-Type": "application/json",
|
43 |
-
},
|
44 |
-
});
|
45 |
-
const response = await request.json();
|
46 |
-
if (response.ok) {
|
47 |
-
setOpen(false);
|
48 |
-
setUrl("");
|
49 |
-
onRedesign(response.markdown);
|
50 |
-
toast.success("DeepSite is re-designing your site! Let him cook... 🔥");
|
51 |
-
} else {
|
52 |
-
toast.error(response.message || "Failed to re-design the site.");
|
53 |
-
}
|
54 |
-
setIsLoading(false);
|
55 |
-
};
|
56 |
-
|
57 |
-
return (
|
58 |
-
<Popover open={open} onOpenChange={setOpen}>
|
59 |
-
<form>
|
60 |
-
<PopoverTrigger asChild>
|
61 |
-
<Button
|
62 |
-
size="iconXs"
|
63 |
-
variant="outline"
|
64 |
-
className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
|
65 |
-
>
|
66 |
-
<Paintbrush className="size-4" />
|
67 |
-
</Button>
|
68 |
-
</PopoverTrigger>
|
69 |
-
<PopoverContent
|
70 |
-
align="start"
|
71 |
-
className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden"
|
72 |
-
>
|
73 |
-
<header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
|
74 |
-
<div className="flex items-center justify-center -space-x-4 mb-3">
|
75 |
-
<div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
|
76 |
-
🎨
|
77 |
-
</div>
|
78 |
-
<div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
|
79 |
-
🥳
|
80 |
-
</div>
|
81 |
-
<div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
|
82 |
-
💎
|
83 |
-
</div>
|
84 |
-
</div>
|
85 |
-
<p className="text-xl font-semibold text-neutral-950">
|
86 |
-
Redesign your Site!
|
87 |
-
</p>
|
88 |
-
<p className="text-sm text-neutral-500 mt-1.5">
|
89 |
-
Try our new Redesign feature to give your site a fresh look.
|
90 |
-
</p>
|
91 |
-
</header>
|
92 |
-
<main className="space-y-4 p-6">
|
93 |
-
<div>
|
94 |
-
<p className="text-sm text-neutral-700 mb-2">
|
95 |
-
Enter your website URL to get started:
|
96 |
-
</p>
|
97 |
-
<Input
|
98 |
-
type="text"
|
99 |
-
placeholder="https://example.com"
|
100 |
-
value={url}
|
101 |
-
onChange={(e) => setUrl(e.target.value)}
|
102 |
-
onBlur={(e) => {
|
103 |
-
const inputUrl = e.target.value.trim();
|
104 |
-
if (!inputUrl) {
|
105 |
-
setUrl("");
|
106 |
-
return;
|
107 |
-
}
|
108 |
-
if (!checkIfUrlIsValid(inputUrl)) {
|
109 |
-
toast.error("Please enter a valid URL.");
|
110 |
-
return;
|
111 |
-
}
|
112 |
-
setUrl(inputUrl);
|
113 |
-
}}
|
114 |
-
className="!bg-white !border-neutral-300 !text-neutral-800 !placeholder:text-neutral-400 selection:!bg-blue-100"
|
115 |
-
/>
|
116 |
-
</div>
|
117 |
-
<div>
|
118 |
-
<p className="text-sm text-neutral-700 mb-2">
|
119 |
-
Then, let's redesign it!
|
120 |
-
</p>
|
121 |
-
<Button
|
122 |
-
variant="gray"
|
123 |
-
onClick={handleClick}
|
124 |
-
className="relative w-full"
|
125 |
-
disabled={isLoading}
|
126 |
-
>
|
127 |
-
Redesign <Paintbrush className="size-4" />
|
128 |
-
{isLoading && <Loading className="ml-2 size-4 animate-spin" />}
|
129 |
-
</Button>
|
130 |
-
</div>
|
131 |
-
</main>
|
132 |
-
</PopoverContent>
|
133 |
-
</form>
|
134 |
-
</Popover>
|
135 |
-
);
|
136 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/settings/settings.tsx
CHANGED
@@ -56,13 +56,12 @@ function Settings({
|
|
56 |
<div className="">
|
57 |
<Popover open={open} onOpenChange={onClose}>
|
58 |
<PopoverTrigger asChild>
|
59 |
-
<Button variant="gray" size="
|
60 |
-
<PiGearSixFill className="size-
|
61 |
-
Settings
|
62 |
</Button>
|
63 |
</PopoverTrigger>
|
64 |
<PopoverContent
|
65 |
-
className="
|
66 |
align="center"
|
67 |
>
|
68 |
<header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
@@ -106,7 +105,7 @@ function Settings({
|
|
106 |
label: string;
|
107 |
isNew?: boolean;
|
108 |
}) => (
|
109 |
-
<SelectItem
|
110 |
{label}
|
111 |
{isNew && (
|
112 |
<span className="text-xs bg-gradient-to-br from-sky-400 to-sky-600 text-white rounded-full px-1.5 py-0.5">
|
|
|
56 |
<div className="">
|
57 |
<Popover open={open} onOpenChange={onClose}>
|
58 |
<PopoverTrigger asChild>
|
59 |
+
<Button variant="gray" size="icon">
|
60 |
+
<PiGearSixFill className="size-5" />
|
|
|
61 |
</Button>
|
62 |
</PopoverTrigger>
|
63 |
<PopoverContent
|
64 |
+
className="p-0 !w-96 overflow-hidden !bg-neutral-900"
|
65 |
align="center"
|
66 |
>
|
67 |
<header className="flex items-center text-sm px-4 py-3 border-b gap-2 bg-neutral-950 border-neutral-800 font-semibold text-neutral-200">
|
|
|
105 |
label: string;
|
106 |
isNew?: boolean;
|
107 |
}) => (
|
108 |
+
<SelectItem value={value} className="">
|
109 |
{label}
|
110 |
{isNew && (
|
111 |
<span className="text-xs bg-gradient-to-br from-sky-400 to-sky-600 text-white rounded-full px-1.5 py-0.5">
|
src/components/ui/button.tsx
CHANGED
@@ -11,7 +11,8 @@ const buttonVariants = cva(
|
|
11 |
variant: {
|
12 |
default:
|
13 |
"bg-neutral-900 text-neutral-50 shadow-xs hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
|
14 |
-
destructive:
|
|
|
15 |
outline:
|
16 |
"border bg-white shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:bg-neutral-200/30 dark:border-neutral-200 dark:hover:bg-neutral-200/50 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:bg-neutral-800/30 dark:dark:border-neutral-800 dark:dark:hover:bg-neutral-800/50",
|
17 |
secondary:
|
@@ -21,7 +22,6 @@ const buttonVariants = cva(
|
|
21 |
link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
|
22 |
pink: "bg-sky-500 text-white hover:brightness-110",
|
23 |
gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
|
24 |
-
ghostWhite: "bg-neutral-200/60 text-neutral-900 hover:bg-neutral-200",
|
25 |
},
|
26 |
size: {
|
27 |
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
@@ -29,7 +29,6 @@ const buttonVariants = cva(
|
|
29 |
lg: "h-10 rounded-full px-6 has-[>svg]:px-4",
|
30 |
icon: "size-9",
|
31 |
iconXs: "size-7",
|
32 |
-
iconXss: "size-6",
|
33 |
xs: "h-6 text-xs rounded-full pl-2 pr-2 gap-1",
|
34 |
},
|
35 |
},
|
|
|
11 |
variant: {
|
12 |
default:
|
13 |
"bg-neutral-900 text-neutral-50 shadow-xs hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
|
14 |
+
destructive:
|
15 |
+
"bg-red-500 text-white shadow-xs hover:bg-red-500/90 focus-visible:ring-red-500/20 dark:focus-visible:ring-red-500/40 dark:bg-red-500/60 dark:bg-red-900 dark:hover:bg-red-900/90 dark:focus-visible:ring-red-900/20 dark:dark:focus-visible:ring-red-900/40 dark:dark:bg-red-900/60",
|
16 |
outline:
|
17 |
"border bg-white shadow-xs hover:bg-neutral-100 hover:text-neutral-900 dark:bg-neutral-200/30 dark:border-neutral-200 dark:hover:bg-neutral-200/50 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50 dark:dark:bg-neutral-800/30 dark:dark:border-neutral-800 dark:dark:hover:bg-neutral-800/50",
|
18 |
secondary:
|
|
|
22 |
link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
|
23 |
pink: "bg-sky-500 text-white hover:brightness-110",
|
24 |
gray: "bg-neutral-900 text-neutral-300 hover:brightness-110",
|
|
|
25 |
},
|
26 |
size: {
|
27 |
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
|
29 |
lg: "h-10 rounded-full px-6 has-[>svg]:px-4",
|
30 |
icon: "size-9",
|
31 |
iconXs: "size-7",
|
|
|
32 |
xs: "h-6 text-xs rounded-full pl-2 pr-2 gap-1",
|
33 |
},
|
34 |
},
|
src/components/ui/dialog.tsx
DELETED
@@ -1,144 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
3 |
-
import { XIcon } from "lucide-react";
|
4 |
-
|
5 |
-
import { cn } from "./../../lib/utils";
|
6 |
-
|
7 |
-
function Dialog({
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
10 |
-
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
11 |
-
}
|
12 |
-
|
13 |
-
function DialogTrigger({
|
14 |
-
...props
|
15 |
-
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
16 |
-
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
17 |
-
}
|
18 |
-
|
19 |
-
function DialogPortal({
|
20 |
-
...props
|
21 |
-
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
22 |
-
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
23 |
-
}
|
24 |
-
|
25 |
-
function DialogClose({
|
26 |
-
...props
|
27 |
-
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
28 |
-
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
29 |
-
}
|
30 |
-
|
31 |
-
function DialogOverlay({
|
32 |
-
className,
|
33 |
-
...props
|
34 |
-
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
35 |
-
return (
|
36 |
-
<DialogPrimitive.Overlay
|
37 |
-
data-slot="dialog-overlay"
|
38 |
-
className={cn(
|
39 |
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
40 |
-
className
|
41 |
-
)}
|
42 |
-
{...props}
|
43 |
-
/>
|
44 |
-
);
|
45 |
-
}
|
46 |
-
|
47 |
-
function DialogContent({
|
48 |
-
className,
|
49 |
-
children,
|
50 |
-
showCloseButton = true,
|
51 |
-
...props
|
52 |
-
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
53 |
-
showCloseButton?: boolean;
|
54 |
-
}) {
|
55 |
-
return (
|
56 |
-
<DialogPortal data-slot="dialog-portal">
|
57 |
-
<DialogOverlay />
|
58 |
-
<DialogPrimitive.Content
|
59 |
-
data-slot="dialog-content"
|
60 |
-
className={cn(
|
61 |
-
"bg-white data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-neutral-200 p-6 shadow-lg duration-200 sm:max-w-lg dark:bg-neutral-950 dark:border-neutral-800",
|
62 |
-
className
|
63 |
-
)}
|
64 |
-
{...props}
|
65 |
-
>
|
66 |
-
{children}
|
67 |
-
{showCloseButton && (
|
68 |
-
<DialogPrimitive.Close
|
69 |
-
data-slot="dialog-close"
|
70 |
-
className="ring-offset-white focus:ring-neutral-950 data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400"
|
71 |
-
>
|
72 |
-
<XIcon />
|
73 |
-
<span className="sr-only">Close</span>
|
74 |
-
</DialogPrimitive.Close>
|
75 |
-
)}
|
76 |
-
</DialogPrimitive.Content>
|
77 |
-
</DialogPortal>
|
78 |
-
);
|
79 |
-
}
|
80 |
-
|
81 |
-
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
82 |
-
return (
|
83 |
-
<div
|
84 |
-
data-slot="dialog-header"
|
85 |
-
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
86 |
-
{...props}
|
87 |
-
/>
|
88 |
-
);
|
89 |
-
}
|
90 |
-
|
91 |
-
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
92 |
-
return (
|
93 |
-
<div
|
94 |
-
data-slot="dialog-footer"
|
95 |
-
className={cn(
|
96 |
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
97 |
-
className
|
98 |
-
)}
|
99 |
-
{...props}
|
100 |
-
/>
|
101 |
-
);
|
102 |
-
}
|
103 |
-
|
104 |
-
function DialogTitle({
|
105 |
-
className,
|
106 |
-
...props
|
107 |
-
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
108 |
-
return (
|
109 |
-
<DialogPrimitive.Title
|
110 |
-
data-slot="dialog-title"
|
111 |
-
className={cn("text-lg leading-none font-semibold", className)}
|
112 |
-
{...props}
|
113 |
-
/>
|
114 |
-
);
|
115 |
-
}
|
116 |
-
|
117 |
-
function DialogDescription({
|
118 |
-
className,
|
119 |
-
...props
|
120 |
-
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
121 |
-
return (
|
122 |
-
<DialogPrimitive.Description
|
123 |
-
data-slot="dialog-description"
|
124 |
-
className={cn(
|
125 |
-
"text-neutral-500 text-sm dark:text-neutral-400",
|
126 |
-
className
|
127 |
-
)}
|
128 |
-
{...props}
|
129 |
-
/>
|
130 |
-
);
|
131 |
-
}
|
132 |
-
|
133 |
-
export {
|
134 |
-
Dialog,
|
135 |
-
DialogClose,
|
136 |
-
DialogContent,
|
137 |
-
DialogDescription,
|
138 |
-
DialogFooter,
|
139 |
-
DialogHeader,
|
140 |
-
DialogOverlay,
|
141 |
-
DialogPortal,
|
142 |
-
DialogTitle,
|
143 |
-
DialogTrigger,
|
144 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ui/tooltip.tsx
DELETED
@@ -1,59 +0,0 @@
|
|
1 |
-
import * as React from "react";
|
2 |
-
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
3 |
-
|
4 |
-
import { cn } from "./../../lib/utils";
|
5 |
-
|
6 |
-
function TooltipProvider({
|
7 |
-
delayDuration = 0,
|
8 |
-
...props
|
9 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
10 |
-
return (
|
11 |
-
<TooltipPrimitive.Provider
|
12 |
-
data-slot="tooltip-provider"
|
13 |
-
delayDuration={delayDuration}
|
14 |
-
{...props}
|
15 |
-
/>
|
16 |
-
);
|
17 |
-
}
|
18 |
-
|
19 |
-
function Tooltip({
|
20 |
-
...props
|
21 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
22 |
-
return (
|
23 |
-
<TooltipProvider>
|
24 |
-
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
25 |
-
</TooltipProvider>
|
26 |
-
);
|
27 |
-
}
|
28 |
-
|
29 |
-
function TooltipTrigger({
|
30 |
-
...props
|
31 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
32 |
-
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
33 |
-
}
|
34 |
-
|
35 |
-
function TooltipContent({
|
36 |
-
className,
|
37 |
-
sideOffset = 0,
|
38 |
-
children,
|
39 |
-
...props
|
40 |
-
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
41 |
-
return (
|
42 |
-
<TooltipPrimitive.Portal>
|
43 |
-
<TooltipPrimitive.Content
|
44 |
-
data-slot="tooltip-content"
|
45 |
-
sideOffset={sideOffset}
|
46 |
-
className={cn(
|
47 |
-
"bg-black text-neutral-50 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
48 |
-
className
|
49 |
-
)}
|
50 |
-
{...props}
|
51 |
-
>
|
52 |
-
{children}
|
53 |
-
<TooltipPrimitive.Arrow className="bg-black fill-black z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
54 |
-
</TooltipPrimitive.Content>
|
55 |
-
</TooltipPrimitive.Portal>
|
56 |
-
);
|
57 |
-
}
|
58 |
-
|
59 |
-
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/views/App.tsx
CHANGED
@@ -34,8 +34,6 @@ export default function App() {
|
|
34 |
const resizer = useRef<HTMLDivElement>(null);
|
35 |
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
36 |
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
37 |
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
38 |
-
const monacoRef = useRef<any>(null);
|
39 |
|
40 |
const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
|
41 |
const [isAiWorking, setisAiWorking] = useState(false);
|
@@ -218,31 +216,20 @@ export default function App() {
|
|
218 |
fontLigatures: true,
|
219 |
theme: "vs-dark",
|
220 |
minimap: { enabled: false },
|
221 |
-
scrollbar: {
|
222 |
-
horizontal: "hidden",
|
223 |
-
},
|
224 |
}}
|
225 |
value={html}
|
226 |
onChange={(value) => {
|
227 |
const newValue = value ?? "";
|
228 |
setHtml(newValue);
|
229 |
}}
|
230 |
-
onMount={(editor
|
231 |
-
editorRef.current = editor;
|
232 |
-
monacoRef.current = monaco;
|
233 |
-
}}
|
234 |
/>
|
235 |
<AskAI
|
236 |
html={html}
|
237 |
setHtml={(newHtml: string) => {
|
238 |
setHtml(newHtml);
|
239 |
}}
|
240 |
-
|
241 |
-
onSuccess={(
|
242 |
-
finalHtml: string,
|
243 |
-
p: string,
|
244 |
-
updatedLines?: number[][]
|
245 |
-
) => {
|
246 |
const currentHistory = [...htmlHistory];
|
247 |
currentHistory.unshift({
|
248 |
html: finalHtml,
|
@@ -254,26 +241,6 @@ export default function App() {
|
|
254 |
if (window.innerWidth <= 1024) {
|
255 |
setCurrentTab("preview");
|
256 |
}
|
257 |
-
if (updatedLines && updatedLines?.length > 0) {
|
258 |
-
const decorations = updatedLines.map((line) => ({
|
259 |
-
range: new monacoRef.current.Range(
|
260 |
-
line[0],
|
261 |
-
1,
|
262 |
-
line[1],
|
263 |
-
1
|
264 |
-
),
|
265 |
-
options: {
|
266 |
-
inlineClassName: "matched-line",
|
267 |
-
},
|
268 |
-
}));
|
269 |
-
setTimeout(() => {
|
270 |
-
editorRef?.current
|
271 |
-
?.getModel()
|
272 |
-
?.deltaDecorations([], decorations);
|
273 |
-
|
274 |
-
editorRef.current?.revealLine(updatedLines[0][0]);
|
275 |
-
}, 100);
|
276 |
-
}
|
277 |
}}
|
278 |
isAiWorking={isAiWorking}
|
279 |
setisAiWorking={setisAiWorking}
|
|
|
34 |
const resizer = useRef<HTMLDivElement>(null);
|
35 |
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
36 |
const iframeRef = useRef<HTMLIFrameElement | null>(null);
|
|
|
|
|
37 |
|
38 |
const [html, setHtml] = useState((htmlStorage as string) ?? defaultHTML);
|
39 |
const [isAiWorking, setisAiWorking] = useState(false);
|
|
|
216 |
fontLigatures: true,
|
217 |
theme: "vs-dark",
|
218 |
minimap: { enabled: false },
|
|
|
|
|
|
|
219 |
}}
|
220 |
value={html}
|
221 |
onChange={(value) => {
|
222 |
const newValue = value ?? "";
|
223 |
setHtml(newValue);
|
224 |
}}
|
225 |
+
onMount={(editor) => (editorRef.current = editor)}
|
|
|
|
|
|
|
226 |
/>
|
227 |
<AskAI
|
228 |
html={html}
|
229 |
setHtml={(newHtml: string) => {
|
230 |
setHtml(newHtml);
|
231 |
}}
|
232 |
+
onSuccess={(finalHtml: string, p: string) => {
|
|
|
|
|
|
|
|
|
|
|
233 |
const currentHistory = [...htmlHistory];
|
234 |
currentHistory.unshift({
|
235 |
html: finalHtml,
|
|
|
241 |
if (window.innerWidth <= 1024) {
|
242 |
setCurrentTab("preview");
|
243 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
}}
|
245 |
isAiWorking={isAiWorking}
|
246 |
setisAiWorking={setisAiWorking}
|
utils/providers.js
CHANGED
@@ -36,19 +36,12 @@ export const MODELS = [
|
|
36 |
value: "deepseek-ai/DeepSeek-V3-0324",
|
37 |
label: "DeepSeek V3 O324",
|
38 |
providers: ["fireworks-ai", "nebius", "sambanova", "novita", "hyperbolic"],
|
39 |
-
autoProvider: "
|
40 |
},
|
41 |
{
|
42 |
value: "deepseek-ai/DeepSeek-R1-0528",
|
43 |
label: "DeepSeek R1 0528",
|
44 |
-
providers: [
|
45 |
-
"fireworks-ai",
|
46 |
-
"novita",
|
47 |
-
"hyperbolic",
|
48 |
-
"nebius",
|
49 |
-
"together",
|
50 |
-
"sambanova",
|
51 |
-
],
|
52 |
autoProvider: "novita",
|
53 |
isNew: true,
|
54 |
isThinker: true,
|
|
|
36 |
value: "deepseek-ai/DeepSeek-V3-0324",
|
37 |
label: "DeepSeek V3 O324",
|
38 |
providers: ["fireworks-ai", "nebius", "sambanova", "novita", "hyperbolic"],
|
39 |
+
autoProvider: "sambanova",
|
40 |
},
|
41 |
{
|
42 |
value: "deepseek-ai/DeepSeek-R1-0528",
|
43 |
label: "DeepSeek R1 0528",
|
44 |
+
providers: ["fireworks-ai", "novita", "hyperbolic", "nebius", "together"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
autoProvider: "novita",
|
46 |
isNew: true,
|
47 |
isThinker: true,
|