mmrwinston001 commited on
Commit
8031b7f
·
verified ·
1 Parent(s): 8e610fc

Delete app

Browse files
app/(public)/layout.tsx DELETED
@@ -1,15 +0,0 @@
1
- import Navigation from "@/components/public/navigation";
2
-
3
- export default async function PublicLayout({
4
- children,
5
- }: Readonly<{
6
- children: React.ReactNode;
7
- }>) {
8
- return (
9
- <div className="min-h-screen bg-black z-1 relative">
10
- <div className="background__noisy" />
11
- <Navigation />
12
- {children}
13
- </div>
14
- );
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/(public)/page.tsx DELETED
@@ -1,44 +0,0 @@
1
- import { AskAi } from "@/components/space/ask-ai";
2
- import { redirect } from "next/navigation";
3
- export default function Home() {
4
- redirect("/projects/new");
5
- return (
6
- <>
7
- <header className="container mx-auto pt-20 px-6 relative flex flex-col items-center justify-center text-center">
8
- <div className="rounded-full border border-neutral-100/10 bg-neutral-100/5 text-xs text-neutral-300 px-3 py-1 max-w-max mx-auto mb-2">
9
- ✨ DeepSite Public Beta
10
- </div>
11
- <h1 className="text-8xl font-semibold text-white font-mono max-w-4xl">
12
- Code your website with AI in seconds
13
- </h1>
14
- <p className="text-2xl text-neutral-300/80 mt-4 text-center max-w-2xl">
15
- Vibe Coding has never been so easy.
16
- </p>
17
- <div className="mt-14 max-w-2xl w-full mx-auto">
18
- <AskAi />
19
- </div>
20
- <div className="absolute inset-0 pointer-events-none -z-[1]">
21
- <div className="w-full h-full bg-gradient-to-r from-purple-500 to-pink-500 opacity-10 blur-3xl rounded-full" />
22
- <div className="w-2/3 h-3/4 bg-gradient-to-r from-blue-500 to-teal-500 opacity-24 blur-3xl absolute -top-20 right-10 transform rotate-12" />
23
- <div className="w-1/2 h-1/2 bg-gradient-to-r from-amber-500 to-rose-500 opacity-20 blur-3xl absolute bottom-0 left-10 rounded-3xl" />
24
- <div className="w-48 h-48 bg-gradient-to-r from-cyan-500 to-indigo-500 opacity-20 blur-3xl absolute top-1/3 right-1/3 rounded-lg transform -rotate-15" />
25
- </div>
26
- </header>
27
- <div id="community" className="h-screen flex items-center justify-center">
28
- <h1 className="text-7xl font-extrabold text-white font-mono">
29
- Community Driven
30
- </h1>
31
- </div>
32
- <div id="deploy" className="h-screen flex items-center justify-center">
33
- <h1 className="text-7xl font-extrabold text-white font-mono">
34
- Deploy your website in seconds
35
- </h1>
36
- </div>
37
- <div id="features" className="h-screen flex items-center justify-center">
38
- <h1 className="text-7xl font-extrabold text-white font-mono">
39
- Features that make you smile
40
- </h1>
41
- </div>
42
- </>
43
- );
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/(public)/projects/page.tsx DELETED
@@ -1,13 +0,0 @@
1
- import { redirect } from "next/navigation";
2
-
3
- import { MyProjects } from "@/components/my-projects";
4
- import { getProjects } from "@/app/actions/projects";
5
-
6
- export default async function ProjectsPage() {
7
- const { ok, projects } = await getProjects();
8
- if (!ok) {
9
- redirect("/");
10
- }
11
-
12
- return <MyProjects projects={projects} />;
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/actions/auth.ts DELETED
@@ -1,18 +0,0 @@
1
- "use server";
2
-
3
- import { headers } from "next/headers";
4
-
5
- export async function getAuth() {
6
- const authList = await headers();
7
- const host = authList.get("host") ?? "localhost:3000";
8
- const url = host.includes("/spaces/enzostvs")
9
- ? "enzostvs-deepsite.hf.space"
10
- : host;
11
- const redirect_uri =
12
- `${host.includes("localhost") ? "http://" : "https://"}` +
13
- url +
14
- "/auth/callback";
15
-
16
- const loginRedirectUrl = `https://huggingface.co/oauth/authorize?client_id=${process.env.OAUTH_CLIENT_ID}&redirect_uri=${redirect_uri}&response_type=code&scope=openid%20profile%20write-repos%20manage-repos%20inference-api&prompt=consent&state=1234567890`;
17
- return loginRedirectUrl;
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/actions/projects.ts DELETED
@@ -1,63 +0,0 @@
1
- "use server";
2
-
3
- import { isAuthenticated } from "@/lib/auth";
4
- import { NextResponse } from "next/server";
5
- import dbConnect from "@/lib/mongodb";
6
- import Project from "@/models/Project";
7
- import { Project as ProjectType } from "@/types";
8
-
9
- export async function getProjects(): Promise<{
10
- ok: boolean;
11
- projects: ProjectType[];
12
- }> {
13
- const user = await isAuthenticated();
14
-
15
- if (user instanceof NextResponse || !user) {
16
- return {
17
- ok: false,
18
- projects: [],
19
- };
20
- }
21
-
22
- await dbConnect();
23
- const projects = await Project.find({
24
- user_id: user?.id,
25
- })
26
- .sort({ _createdAt: -1 })
27
- .limit(100)
28
- .lean();
29
- if (!projects) {
30
- return {
31
- ok: false,
32
- projects: [],
33
- };
34
- }
35
- return {
36
- ok: true,
37
- projects: JSON.parse(JSON.stringify(projects)) as ProjectType[],
38
- };
39
- }
40
-
41
- export async function getProject(
42
- namespace: string,
43
- repoId: string
44
- ): Promise<ProjectType | null> {
45
- const user = await isAuthenticated();
46
-
47
- if (user instanceof NextResponse || !user) {
48
- return null;
49
- }
50
-
51
- await dbConnect();
52
- const project = await Project.findOne({
53
- user_id: user.id,
54
- namespace,
55
- repoId,
56
- }).lean();
57
-
58
- if (!project) {
59
- return null;
60
- }
61
-
62
- return JSON.parse(JSON.stringify(project)) as ProjectType;
63
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/actions/rewrite-prompt.ts DELETED
@@ -1,35 +0,0 @@
1
- import { InferenceClient } from "@huggingface/inference";
2
-
3
- const START_REWRITE_PROMPT = ">>>>>>> START PROMPT >>>>>>";
4
- const END_REWRITE_PROMPT = ">>>>>>> END PROMPT >>>>>>";
5
-
6
- export const callAiRewritePrompt = async (prompt: string, { token, billTo }: { token: string, billTo?: string | null }) => {
7
- const client = new InferenceClient(token);
8
- const response = await client.chatCompletion(
9
- {
10
- model: "deepseek-ai/DeepSeek-V3.1",
11
- provider: "novita",
12
- messages: [{
13
- role: "system",
14
- content: `You are a helpful assistant that rewrites prompts to make them better. All the prompts will be about creating a website or app.
15
- Try to make the prompt more detailed and specific to create a good UI/UX Design and good code.
16
- Format the result by following this format:
17
- ${START_REWRITE_PROMPT}
18
- new prompt here
19
- ${END_REWRITE_PROMPT}
20
- If you don't rewrite the prompt, return the original prompt.
21
- Make sure to return the prompt in the same language as the prompt you are given. Also IMPORTANT: Make sure to keep the original intent of the prompt. Improve it it needed, but don't change the original intent.
22
- `
23
- },{ role: "user", content: prompt }],
24
- },
25
- billTo ? { billTo } : {}
26
- );
27
-
28
- const responseContent = response.choices[0]?.message?.content;
29
- if (!responseContent) {
30
- return prompt;
31
- }
32
- const startIndex = responseContent.indexOf(START_REWRITE_PROMPT);
33
- const endIndex = responseContent.indexOf(END_REWRITE_PROMPT);
34
- return responseContent.substring(startIndex + START_REWRITE_PROMPT.length, endIndex);
35
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/ask-ai/route.ts DELETED
@@ -1,510 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import type { NextRequest } from "next/server";
3
- import { NextResponse } from "next/server";
4
- import { headers } from "next/headers";
5
- import { InferenceClient } from "@huggingface/inference";
6
-
7
- import { MODELS, PROVIDERS } from "@/lib/providers";
8
- import {
9
- DIVIDER,
10
- FOLLOW_UP_SYSTEM_PROMPT,
11
- INITIAL_SYSTEM_PROMPT,
12
- MAX_REQUESTS_PER_IP,
13
- NEW_PAGE_END,
14
- NEW_PAGE_START,
15
- REPLACE_END,
16
- SEARCH_START,
17
- UPDATE_PAGE_START,
18
- UPDATE_PAGE_END,
19
- } from "@/lib/prompts";
20
- import MY_TOKEN_KEY from "@/lib/get-cookie-name";
21
- import { Page } from "@/types";
22
-
23
- const ipAddresses = new Map();
24
-
25
- export async function POST(request: NextRequest) {
26
- const authHeaders = await headers();
27
- const userToken = request.cookies.get(MY_TOKEN_KEY())?.value;
28
-
29
- const body = await request.json();
30
- const { prompt, provider, model, redesignMarkdown, previousPrompts, pages } = body;
31
-
32
- if (!model || (!prompt && !redesignMarkdown)) {
33
- return NextResponse.json(
34
- { ok: false, error: "Missing required fields" },
35
- { status: 400 }
36
- );
37
- }
38
-
39
- const selectedModel = MODELS.find(
40
- (m) => m.value === model || m.label === model
41
- );
42
-
43
- if (!selectedModel) {
44
- return NextResponse.json(
45
- { ok: false, error: "Invalid model selected" },
46
- { status: 400 }
47
- );
48
- }
49
-
50
- if (!selectedModel.providers.includes(provider) && provider !== "auto") {
51
- return NextResponse.json(
52
- {
53
- ok: false,
54
- error: `The selected model does not support the ${provider} provider.`,
55
- openSelectProvider: true,
56
- },
57
- { status: 400 }
58
- );
59
- }
60
-
61
- let token = userToken;
62
- let billTo: string | null = null;
63
-
64
- /**
65
- * Handle local usage token, this bypass the need for a user token
66
- * and allows local testing without authentication.
67
- * This is useful for development and testing purposes.
68
- */
69
- if (process.env.HF_TOKEN && process.env.HF_TOKEN.length > 0) {
70
- token = process.env.HF_TOKEN;
71
- }
72
-
73
- const ip = authHeaders.get("x-forwarded-for")?.includes(",")
74
- ? authHeaders.get("x-forwarded-for")?.split(",")[1].trim()
75
- : authHeaders.get("x-forwarded-for");
76
-
77
- if (!token) {
78
- ipAddresses.set(ip, (ipAddresses.get(ip) || 0) + 1);
79
- if (ipAddresses.get(ip) > MAX_REQUESTS_PER_IP) {
80
- return NextResponse.json(
81
- {
82
- ok: false,
83
- openLogin: true,
84
- message: "Log In to continue using the service",
85
- },
86
- { status: 429 }
87
- );
88
- }
89
-
90
- token = process.env.DEFAULT_HF_TOKEN as string;
91
- billTo = "huggingface";
92
- }
93
-
94
- const DEFAULT_PROVIDER = PROVIDERS.novita;
95
- const selectedProvider =
96
- provider === "auto"
97
- ? PROVIDERS[selectedModel.autoProvider as keyof typeof PROVIDERS]
98
- : PROVIDERS[provider as keyof typeof PROVIDERS] ?? DEFAULT_PROVIDER;
99
-
100
- const rewrittenPrompt = prompt;
101
-
102
- // if (prompt?.length < 240) {
103
-
104
- //rewrittenPrompt = await callAiRewritePrompt(prompt, { token, billTo });
105
- // }
106
-
107
- try {
108
- const encoder = new TextEncoder();
109
- const stream = new TransformStream();
110
- const writer = stream.writable.getWriter();
111
-
112
- const response = new NextResponse(stream.readable, {
113
- headers: {
114
- "Content-Type": "text/plain; charset=utf-8",
115
- "Cache-Control": "no-cache",
116
- Connection: "keep-alive",
117
- },
118
- });
119
-
120
- (async () => {
121
- // let completeResponse = "";
122
- try {
123
- const client = new InferenceClient(token);
124
- const chatCompletion = client.chatCompletionStream(
125
- {
126
- model: selectedModel.value,
127
- provider: selectedProvider.id as any,
128
- messages: [
129
- {
130
- role: "system",
131
- content: INITIAL_SYSTEM_PROMPT,
132
- },
133
- ...(pages?.length > 1 ? [{
134
- role: "assistant",
135
- content: `Here are the current pages:\n\n${pages.map((p: Page) => `- ${p.path} \n${p.html}`).join("\n")}\n\nNow, please create a new page based on this code. Also here are the previous prompts:\n\n${previousPrompts.map((p: string) => `- ${p}`).join("\n")}`
136
- }] : []),
137
- {
138
- role: "user",
139
- content: redesignMarkdown
140
- ? `Here is my current design as a markdown:\n\n${redesignMarkdown}\n\nNow, please create a new design based on this markdown.`
141
- : rewrittenPrompt,
142
- },
143
- ],
144
- max_tokens: selectedProvider.max_tokens,
145
- },
146
- billTo ? { billTo } : {}
147
- );
148
-
149
- while (true) {
150
- const { done, value } = await chatCompletion.next();
151
- if (done) {
152
- break;
153
- }
154
-
155
- const chunk = value.choices[0]?.delta?.content;
156
- if (chunk) {
157
- await writer.write(encoder.encode(chunk));
158
- }
159
- }
160
- } catch (error: any) {
161
- if (error.message?.includes("exceeded your monthly included credits")) {
162
- await writer.write(
163
- encoder.encode(
164
- JSON.stringify({
165
- ok: false,
166
- openProModal: true,
167
- message: error.message,
168
- })
169
- )
170
- );
171
- } else {
172
- await writer.write(
173
- encoder.encode(
174
- JSON.stringify({
175
- ok: false,
176
- message:
177
- error.message ||
178
- "An error occurred while processing your request.",
179
- })
180
- )
181
- );
182
- }
183
- } finally {
184
- await writer?.close();
185
- }
186
- })();
187
-
188
- return response;
189
- } catch (error: any) {
190
- return NextResponse.json(
191
- {
192
- ok: false,
193
- openSelectProvider: true,
194
- message:
195
- error?.message || "An error occurred while processing your request.",
196
- },
197
- { status: 500 }
198
- );
199
- }
200
- }
201
-
202
- export async function PUT(request: NextRequest) {
203
- const authHeaders = await headers();
204
- const userToken = request.cookies.get(MY_TOKEN_KEY())?.value;
205
-
206
- const body = await request.json();
207
- const { prompt, previousPrompts, provider, selectedElementHtml, model, pages, files, } =
208
- body;
209
-
210
- if (!prompt || pages.length === 0) {
211
- return NextResponse.json(
212
- { ok: false, error: "Missing required fields" },
213
- { status: 400 }
214
- );
215
- }
216
-
217
- const selectedModel = MODELS.find(
218
- (m) => m.value === model || m.label === model
219
- );
220
- if (!selectedModel) {
221
- return NextResponse.json(
222
- { ok: false, error: "Invalid model selected" },
223
- { status: 400 }
224
- );
225
- }
226
-
227
- let token = userToken;
228
- let billTo: string | null = null;
229
-
230
- /**
231
- * Handle local usage token, this bypass the need for a user token
232
- * and allows local testing without authentication.
233
- * This is useful for development and testing purposes.
234
- */
235
- if (process.env.HF_TOKEN && process.env.HF_TOKEN.length > 0) {
236
- token = process.env.HF_TOKEN;
237
- }
238
-
239
- const ip = authHeaders.get("x-forwarded-for")?.includes(",")
240
- ? authHeaders.get("x-forwarded-for")?.split(",")[1].trim()
241
- : authHeaders.get("x-forwarded-for");
242
-
243
- if (!token) {
244
- ipAddresses.set(ip, (ipAddresses.get(ip) || 0) + 1);
245
- if (ipAddresses.get(ip) > MAX_REQUESTS_PER_IP) {
246
- return NextResponse.json(
247
- {
248
- ok: false,
249
- openLogin: true,
250
- message: "Log In to continue using the service",
251
- },
252
- { status: 429 }
253
- );
254
- }
255
-
256
- token = process.env.DEFAULT_HF_TOKEN as string;
257
- billTo = "huggingface";
258
- }
259
-
260
- const client = new InferenceClient(token);
261
-
262
- const DEFAULT_PROVIDER = PROVIDERS.novita;
263
- const selectedProvider =
264
- provider === "auto"
265
- ? PROVIDERS[selectedModel.autoProvider as keyof typeof PROVIDERS]
266
- : PROVIDERS[provider as keyof typeof PROVIDERS] ?? DEFAULT_PROVIDER;
267
-
268
- try {
269
- const response = await client.chatCompletion(
270
- {
271
- model: selectedModel.value,
272
- provider: selectedProvider.id as any,
273
- messages: [
274
- {
275
- role: "system",
276
- content: FOLLOW_UP_SYSTEM_PROMPT,
277
- },
278
- {
279
- role: "user",
280
- content: previousPrompts
281
- ? `Also here are the previous prompts:\n\n${previousPrompts.map((p: string) => `- ${p}`).join("\n")}`
282
- : "You are modifying the HTML file based on the user's request.",
283
- },
284
- {
285
- role: "assistant",
286
-
287
- content: `${
288
- selectedElementHtml
289
- ? `\n\nYou have to update ONLY the following element, NOTHING ELSE: \n\n\`\`\`html\n${selectedElementHtml}\n\`\`\``
290
- : ""
291
- }. Current pages: ${pages?.map((p: Page) => `- ${p.path} \n${p.html}`).join("\n")}. ${files?.length > 0 ? `Current images: ${files?.map((f: string) => `- ${f}`).join("\n")}.` : ""}`,
292
- },
293
- {
294
- role: "user",
295
- content: prompt,
296
- },
297
- ],
298
- ...(selectedProvider.id !== "sambanova"
299
- ? {
300
- max_tokens: selectedProvider.max_tokens,
301
- }
302
- : {}),
303
- },
304
- billTo ? { billTo } : {}
305
- );
306
-
307
- const chunk = response.choices[0]?.message?.content;
308
- if (!chunk) {
309
- return NextResponse.json(
310
- { ok: false, message: "No content returned from the model" },
311
- { status: 400 }
312
- );
313
- }
314
-
315
- if (chunk) {
316
- const updatedLines: number[][] = [];
317
- let newHtml = "";
318
- const updatedPages = [...(pages || [])];
319
-
320
- const updatePageRegex = new RegExp(`${UPDATE_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^\\s]+)\\s*${UPDATE_PAGE_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([\\s\\S]*?)(?=${UPDATE_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}|${NEW_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}|$)`, 'g');
321
- let updatePageMatch;
322
-
323
- while ((updatePageMatch = updatePageRegex.exec(chunk)) !== null) {
324
- const [, pagePath, pageContent] = updatePageMatch;
325
-
326
- const pageIndex = updatedPages.findIndex(p => p.path === pagePath);
327
- if (pageIndex !== -1) {
328
- let pageHtml = updatedPages[pageIndex].html;
329
-
330
- let processedContent = pageContent;
331
- const htmlMatch = pageContent.match(/```html\s*([\s\S]*?)\s*```/);
332
- if (htmlMatch) {
333
- processedContent = htmlMatch[1];
334
- }
335
- let position = 0;
336
- let moreBlocks = true;
337
-
338
- while (moreBlocks) {
339
- const searchStartIndex = processedContent.indexOf(SEARCH_START, position);
340
- if (searchStartIndex === -1) {
341
- moreBlocks = false;
342
- continue;
343
- }
344
-
345
- const dividerIndex = processedContent.indexOf(DIVIDER, searchStartIndex);
346
- if (dividerIndex === -1) {
347
- moreBlocks = false;
348
- continue;
349
- }
350
-
351
- const replaceEndIndex = processedContent.indexOf(REPLACE_END, dividerIndex);
352
- if (replaceEndIndex === -1) {
353
- moreBlocks = false;
354
- continue;
355
- }
356
-
357
- const searchBlock = processedContent.substring(
358
- searchStartIndex + SEARCH_START.length,
359
- dividerIndex
360
- );
361
- const replaceBlock = processedContent.substring(
362
- dividerIndex + DIVIDER.length,
363
- replaceEndIndex
364
- );
365
-
366
- if (searchBlock.trim() === "") {
367
- pageHtml = `${replaceBlock}\n${pageHtml}`;
368
- updatedLines.push([1, replaceBlock.split("\n").length]);
369
- } else {
370
- const blockPosition = pageHtml.indexOf(searchBlock);
371
- if (blockPosition !== -1) {
372
- const beforeText = pageHtml.substring(0, blockPosition);
373
- const startLineNumber = beforeText.split("\n").length;
374
- const replaceLines = replaceBlock.split("\n").length;
375
- const endLineNumber = startLineNumber + replaceLines - 1;
376
-
377
- updatedLines.push([startLineNumber, endLineNumber]);
378
- pageHtml = pageHtml.replace(searchBlock, replaceBlock);
379
- }
380
- }
381
-
382
- position = replaceEndIndex + REPLACE_END.length;
383
- }
384
-
385
- updatedPages[pageIndex].html = pageHtml;
386
-
387
- if (pagePath === '/' || pagePath === '/index' || pagePath === 'index') {
388
- newHtml = pageHtml;
389
- }
390
- }
391
- }
392
-
393
- const newPageRegex = new RegExp(`${NEW_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^\\s]+)\\s*${NEW_PAGE_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([\\s\\S]*?)(?=${UPDATE_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}|${NEW_PAGE_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}|$)`, 'g');
394
- let newPageMatch;
395
-
396
- while ((newPageMatch = newPageRegex.exec(chunk)) !== null) {
397
- const [, pagePath, pageContent] = newPageMatch;
398
-
399
- let pageHtml = pageContent;
400
- const htmlMatch = pageContent.match(/```html\s*([\s\S]*?)\s*```/);
401
- if (htmlMatch) {
402
- pageHtml = htmlMatch[1];
403
- }
404
-
405
- const existingPageIndex = updatedPages.findIndex(p => p.path === pagePath);
406
-
407
- if (existingPageIndex !== -1) {
408
- updatedPages[existingPageIndex] = {
409
- path: pagePath,
410
- html: pageHtml.trim()
411
- };
412
- } else {
413
- updatedPages.push({
414
- path: pagePath,
415
- html: pageHtml.trim()
416
- });
417
- }
418
- }
419
-
420
- if (updatedPages.length === pages?.length && !chunk.includes(UPDATE_PAGE_START)) {
421
- let position = 0;
422
- let moreBlocks = true;
423
-
424
- while (moreBlocks) {
425
- const searchStartIndex = chunk.indexOf(SEARCH_START, position);
426
- if (searchStartIndex === -1) {
427
- moreBlocks = false;
428
- continue;
429
- }
430
-
431
- const dividerIndex = chunk.indexOf(DIVIDER, searchStartIndex);
432
- if (dividerIndex === -1) {
433
- moreBlocks = false;
434
- continue;
435
- }
436
-
437
- const replaceEndIndex = chunk.indexOf(REPLACE_END, dividerIndex);
438
- if (replaceEndIndex === -1) {
439
- moreBlocks = false;
440
- continue;
441
- }
442
-
443
- const searchBlock = chunk.substring(
444
- searchStartIndex + SEARCH_START.length,
445
- dividerIndex
446
- );
447
- const replaceBlock = chunk.substring(
448
- dividerIndex + DIVIDER.length,
449
- replaceEndIndex
450
- );
451
-
452
- if (searchBlock.trim() === "") {
453
- newHtml = `${replaceBlock}\n${newHtml}`;
454
- updatedLines.push([1, replaceBlock.split("\n").length]);
455
- } else {
456
- const blockPosition = newHtml.indexOf(searchBlock);
457
- if (blockPosition !== -1) {
458
- const beforeText = newHtml.substring(0, blockPosition);
459
- const startLineNumber = beforeText.split("\n").length;
460
- const replaceLines = replaceBlock.split("\n").length;
461
- const endLineNumber = startLineNumber + replaceLines - 1;
462
-
463
- updatedLines.push([startLineNumber, endLineNumber]);
464
- newHtml = newHtml.replace(searchBlock, replaceBlock);
465
- }
466
- }
467
-
468
- position = replaceEndIndex + REPLACE_END.length;
469
- }
470
-
471
- // Update the main HTML if it's the index page
472
- const mainPageIndex = updatedPages.findIndex(p => p.path === '/' || p.path === '/index' || p.path === 'index');
473
- if (mainPageIndex !== -1) {
474
- updatedPages[mainPageIndex].html = newHtml;
475
- }
476
- }
477
-
478
- return NextResponse.json({
479
- ok: true,
480
- updatedLines,
481
- pages: updatedPages,
482
- });
483
- } else {
484
- return NextResponse.json(
485
- { ok: false, message: "No content returned from the model" },
486
- { status: 400 }
487
- );
488
- }
489
- } catch (error: any) {
490
- if (error.message?.includes("exceeded your monthly included credits")) {
491
- return NextResponse.json(
492
- {
493
- ok: false,
494
- openProModal: true,
495
- message: error.message,
496
- },
497
- { status: 402 }
498
- );
499
- }
500
- return NextResponse.json(
501
- {
502
- ok: false,
503
- openSelectProvider: true,
504
- message:
505
- error.message || "An error occurred while processing your request.",
506
- },
507
- { status: 500 }
508
- );
509
- }
510
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/auth/route.ts DELETED
@@ -1,86 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
-
3
- export async function POST(req: NextRequest) {
4
- const body = await req.json();
5
- const { code } = body;
6
-
7
- if (!code) {
8
- return NextResponse.json(
9
- { error: "Code is required" },
10
- {
11
- status: 400,
12
- headers: {
13
- "Content-Type": "application/json",
14
- },
15
- }
16
- );
17
- }
18
-
19
- const Authorization = `Basic ${Buffer.from(
20
- `${process.env.OAUTH_CLIENT_ID}:${process.env.OAUTH_CLIENT_SECRET}`
21
- ).toString("base64")}`;
22
-
23
- const host =
24
- req.headers.get("host") ?? req.headers.get("origin") ?? "localhost:3000";
25
-
26
- const url = host.includes("/spaces/enzostvs")
27
- ? "enzostvs-deepsite.hf.space"
28
- : host;
29
- const redirect_uri =
30
- `${host.includes("localhost") ? "http://" : "https://"}` +
31
- url +
32
- "/auth/callback";
33
- const request_auth = await fetch("https://huggingface.co/oauth/token", {
34
- method: "POST",
35
- headers: {
36
- "Content-Type": "application/x-www-form-urlencoded",
37
- Authorization,
38
- },
39
- body: new URLSearchParams({
40
- grant_type: "authorization_code",
41
- code,
42
- redirect_uri,
43
- }),
44
- });
45
-
46
- const response = await request_auth.json();
47
- if (!response.access_token) {
48
- return NextResponse.json(
49
- { error: "Failed to retrieve access token" },
50
- {
51
- status: 400,
52
- headers: {
53
- "Content-Type": "application/json",
54
- },
55
- }
56
- );
57
- }
58
-
59
- const userResponse = await fetch("https://huggingface.co/api/whoami-v2", {
60
- headers: {
61
- Authorization: `Bearer ${response.access_token}`,
62
- },
63
- });
64
-
65
- if (!userResponse.ok) {
66
- return NextResponse.json(
67
- { user: null, errCode: userResponse.status },
68
- { status: userResponse.status }
69
- );
70
- }
71
- const user = await userResponse.json();
72
-
73
- return NextResponse.json(
74
- {
75
- access_token: response.access_token,
76
- expires_in: response.expires_in,
77
- user,
78
- },
79
- {
80
- status: 200,
81
- headers: {
82
- "Content-Type": "application/json",
83
- },
84
- }
85
- );
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/me/projects/[namespace]/[repoId]/images/route.ts DELETED
@@ -1,111 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- import { RepoDesignation, uploadFiles } from "@huggingface/hub";
3
-
4
- import { isAuthenticated } from "@/lib/auth";
5
- import Project from "@/models/Project";
6
- import dbConnect from "@/lib/mongodb";
7
-
8
- // No longer need the ImageUpload interface since we're handling FormData with File objects
9
-
10
- export async function POST(
11
- req: NextRequest,
12
- { params }: { params: Promise<{ namespace: string; repoId: string }> }
13
- ) {
14
- try {
15
- const user = await isAuthenticated();
16
-
17
- if (user instanceof NextResponse || !user) {
18
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
19
- }
20
-
21
- await dbConnect();
22
- const param = await params;
23
- const { namespace, repoId } = param;
24
-
25
- const project = await Project.findOne({
26
- user_id: user.id,
27
- space_id: `${namespace}/${repoId}`,
28
- }).lean();
29
-
30
- if (!project) {
31
- return NextResponse.json(
32
- {
33
- ok: false,
34
- error: "Project not found",
35
- },
36
- { status: 404 }
37
- );
38
- }
39
-
40
- // Parse the FormData to get the images
41
- const formData = await req.formData();
42
- const imageFiles = formData.getAll("images") as File[];
43
-
44
- if (!imageFiles || imageFiles.length === 0) {
45
- return NextResponse.json(
46
- {
47
- ok: false,
48
- error: "At least one image file is required under the 'images' key",
49
- },
50
- { status: 400 }
51
- );
52
- }
53
-
54
- const files: File[] = [];
55
- for (const file of imageFiles) {
56
- if (!(file instanceof File)) {
57
- return NextResponse.json(
58
- {
59
- ok: false,
60
- error: "Invalid file format - all items under 'images' key must be files",
61
- },
62
- { status: 400 }
63
- );
64
- }
65
-
66
- if (!file.type.startsWith('image/')) {
67
- return NextResponse.json(
68
- {
69
- ok: false,
70
- error: `File ${file.name} is not an image`,
71
- },
72
- { status: 400 }
73
- );
74
- }
75
-
76
- // Create File object with images/ folder prefix
77
- const fileName = `images/${file.name}`;
78
- const processedFile = new File([file], fileName, { type: file.type });
79
- files.push(processedFile);
80
- }
81
-
82
- // Upload files to HuggingFace space
83
- const repo: RepoDesignation = {
84
- type: "space",
85
- name: `${namespace}/${repoId}`,
86
- };
87
-
88
- await uploadFiles({
89
- repo,
90
- files,
91
- accessToken: user.token as string,
92
- commitTitle: `Upload ${files.length} image(s)`,
93
- });
94
-
95
- return NextResponse.json({
96
- ok: true,
97
- message: `Successfully uploaded ${files.length} image(s) to ${namespace}/${repoId}/images/`,
98
- uploadedFiles: files.map((file) => `https://huggingface.co/spaces/${namespace}/${repoId}/resolve/main/${file.name}`),
99
- }, { status: 200 });
100
-
101
- } catch (error) {
102
- console.error('Error uploading images:', error);
103
- return NextResponse.json(
104
- {
105
- ok: false,
106
- error: "Failed to upload images",
107
- },
108
- { status: 500 }
109
- );
110
- }
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/me/projects/[namespace]/[repoId]/route.ts DELETED
@@ -1,276 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- import { RepoDesignation, spaceInfo, uploadFiles, listFiles } from "@huggingface/hub";
3
-
4
- import { isAuthenticated } from "@/lib/auth";
5
- import Project from "@/models/Project";
6
- import dbConnect from "@/lib/mongodb";
7
- import { Page } from "@/types";
8
-
9
- export async function GET(
10
- req: NextRequest,
11
- { params }: { params: Promise<{ namespace: string; repoId: string }> }
12
- ) {
13
- const user = await isAuthenticated();
14
-
15
- if (user instanceof NextResponse || !user) {
16
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
17
- }
18
-
19
- await dbConnect();
20
- const param = await params;
21
- const { namespace, repoId } = param;
22
-
23
- const project = await Project.findOne({
24
- user_id: user.id,
25
- space_id: `${namespace}/${repoId}`,
26
- }).lean();
27
- if (!project) {
28
- return NextResponse.json(
29
- {
30
- ok: false,
31
- error: "Project not found",
32
- },
33
- { status: 404 }
34
- );
35
- }
36
- try {
37
- const space = await spaceInfo({
38
- name: namespace + "/" + repoId,
39
- accessToken: user.token as string,
40
- additionalFields: ["author"],
41
- });
42
-
43
- if (!space || space.sdk !== "static") {
44
- return NextResponse.json(
45
- {
46
- ok: false,
47
- error: "Space is not a static space",
48
- },
49
- { status: 404 }
50
- );
51
- }
52
- if (space.author !== user.name) {
53
- return NextResponse.json(
54
- {
55
- ok: false,
56
- error: "Space does not belong to the authenticated user",
57
- },
58
- { status: 403 }
59
- );
60
- }
61
-
62
- const repo: RepoDesignation = {
63
- type: "space",
64
- name: `${namespace}/${repoId}`,
65
- };
66
-
67
- const htmlFiles: Page[] = [];
68
- const images: string[] = [];
69
-
70
- const allowedImagesExtensions = ["jpg", "jpeg", "png", "gif", "svg", "webp", "avif", "heic", "heif", "ico", "bmp", "tiff", "tif"];
71
-
72
- for await (const fileInfo of listFiles({repo, accessToken: user.token as string})) {
73
- if (fileInfo.path.endsWith(".html")) {
74
- const res = await fetch(`https://huggingface.co/spaces/${namespace}/${repoId}/raw/main/${fileInfo.path}`);
75
- if (res.ok) {
76
- const html = await res.text();
77
- if (fileInfo.path === "index.html") {
78
- htmlFiles.unshift({
79
- path: fileInfo.path,
80
- html,
81
- });
82
- } else {
83
- htmlFiles.push({
84
- path: fileInfo.path,
85
- html,
86
- });
87
- }
88
- }
89
- }
90
- if (fileInfo.type === "directory" && fileInfo.path === "images") {
91
- for await (const imageInfo of listFiles({repo, accessToken: user.token as string, path: fileInfo.path})) {
92
- if (allowedImagesExtensions.includes(imageInfo.path.split(".").pop() || "")) {
93
- images.push(`https://huggingface.co/spaces/${namespace}/${repoId}/resolve/main/${imageInfo.path}`);
94
- }
95
- }
96
- }
97
- }
98
-
99
- if (htmlFiles.length === 0) {
100
- return NextResponse.json(
101
- {
102
- ok: false,
103
- error: "No HTML files found",
104
- },
105
- { status: 404 }
106
- );
107
- }
108
-
109
- return NextResponse.json(
110
- {
111
- project: {
112
- ...project,
113
- pages: htmlFiles,
114
- images,
115
- },
116
- ok: true,
117
- },
118
- { status: 200 }
119
- );
120
-
121
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
122
- } catch (error: any) {
123
- if (error.statusCode === 404) {
124
- await Project.deleteOne({
125
- user_id: user.id,
126
- space_id: `${namespace}/${repoId}`,
127
- });
128
- return NextResponse.json(
129
- { error: "Space not found", ok: false },
130
- { status: 404 }
131
- );
132
- }
133
- return NextResponse.json(
134
- { error: error.message, ok: false },
135
- { status: 500 }
136
- );
137
- }
138
- }
139
-
140
- export async function PUT(
141
- req: NextRequest,
142
- { params }: { params: Promise<{ namespace: string; repoId: string }> }
143
- ) {
144
- const user = await isAuthenticated();
145
-
146
- if (user instanceof NextResponse || !user) {
147
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
148
- }
149
-
150
- await dbConnect();
151
- const param = await params;
152
- const { namespace, repoId } = param;
153
- const { pages, prompts } = await req.json();
154
-
155
- const project = await Project.findOne({
156
- user_id: user.id,
157
- space_id: `${namespace}/${repoId}`,
158
- }).lean();
159
- if (!project) {
160
- return NextResponse.json(
161
- {
162
- ok: false,
163
- error: "Project not found",
164
- },
165
- { status: 404 }
166
- );
167
- }
168
-
169
- const repo: RepoDesignation = {
170
- type: "space",
171
- name: `${namespace}/${repoId}`,
172
- };
173
-
174
- const files: File[] = [];
175
- const promptsFile = new File([prompts.join("\n")], "prompts.txt", {
176
- type: "text/plain",
177
- });
178
- files.push(promptsFile);
179
- pages.forEach((page: Page) => {
180
- const file = new File([page.html], page.path, { type: "text/html" });
181
- files.push(file);
182
- });
183
- await uploadFiles({
184
- repo,
185
- files,
186
- accessToken: user.token as string,
187
- commitTitle: `${prompts[prompts.length - 1]} - Follow Up Deployment`,
188
- });
189
-
190
- await Project.updateOne(
191
- { user_id: user.id, space_id: `${namespace}/${repoId}` },
192
- {
193
- $set: {
194
- prompts: [
195
- ...prompts,
196
- ],
197
- },
198
- }
199
- );
200
- return NextResponse.json({ ok: true }, { status: 200 });
201
- }
202
-
203
- export async function POST(
204
- req: NextRequest,
205
- { params }: { params: Promise<{ namespace: string; repoId: string }> }
206
- ) {
207
- const user = await isAuthenticated();
208
-
209
- if (user instanceof NextResponse || !user) {
210
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
211
- }
212
-
213
- await dbConnect();
214
- const param = await params;
215
- const { namespace, repoId } = param;
216
-
217
- const space = await spaceInfo({
218
- name: namespace + "/" + repoId,
219
- accessToken: user.token as string,
220
- additionalFields: ["author"],
221
- });
222
-
223
- if (!space || space.sdk !== "static") {
224
- return NextResponse.json(
225
- {
226
- ok: false,
227
- error: "Space is not a static space",
228
- },
229
- { status: 404 }
230
- );
231
- }
232
- if (space.author !== user.name) {
233
- return NextResponse.json(
234
- {
235
- ok: false,
236
- error: "Space does not belong to the authenticated user",
237
- },
238
- { status: 403 }
239
- );
240
- }
241
-
242
- const project = await Project.findOne({
243
- user_id: user.id,
244
- space_id: `${namespace}/${repoId}`,
245
- }).lean();
246
- if (project) {
247
- // redirect to the project page if it already exists
248
- return NextResponse.json(
249
- {
250
- ok: false,
251
- error: "Project already exists",
252
- redirect: `/projects/${namespace}/${repoId}`,
253
- },
254
- { status: 400 }
255
- );
256
- }
257
-
258
- const newProject = new Project({
259
- user_id: user.id,
260
- space_id: `${namespace}/${repoId}`,
261
- prompts: [],
262
- });
263
-
264
- await newProject.save();
265
- return NextResponse.json(
266
- {
267
- ok: true,
268
- project: {
269
- id: newProject._id,
270
- space_id: newProject.space_id,
271
- prompts: newProject.prompts,
272
- },
273
- },
274
- { status: 201 }
275
- );
276
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/me/projects/route.ts DELETED
@@ -1,127 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
- import { createRepo, RepoDesignation, uploadFiles } from "@huggingface/hub";
3
-
4
- import { isAuthenticated } from "@/lib/auth";
5
- import Project from "@/models/Project";
6
- import dbConnect from "@/lib/mongodb";
7
- import { COLORS } from "@/lib/utils";
8
- import { Page } from "@/types";
9
-
10
- export async function GET() {
11
- const user = await isAuthenticated();
12
-
13
- if (user instanceof NextResponse || !user) {
14
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
15
- }
16
-
17
- await dbConnect();
18
-
19
- const projects = await Project.find({
20
- user_id: user?.id,
21
- })
22
- .sort({ _createdAt: -1 })
23
- .limit(100)
24
- .lean();
25
- if (!projects) {
26
- return NextResponse.json(
27
- {
28
- ok: false,
29
- projects: [],
30
- },
31
- { status: 404 }
32
- );
33
- }
34
- return NextResponse.json(
35
- {
36
- ok: true,
37
- projects,
38
- },
39
- { status: 200 }
40
- );
41
- }
42
-
43
- export async function POST(request: NextRequest) {
44
- const user = await isAuthenticated();
45
-
46
- if (user instanceof NextResponse || !user) {
47
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
48
- }
49
-
50
- const { title, pages, prompts } = await request.json();
51
-
52
- if (!title || !pages || pages.length === 0) {
53
- return NextResponse.json(
54
- { message: "Title and HTML content are required.", ok: false },
55
- { status: 400 }
56
- );
57
- }
58
-
59
- await dbConnect();
60
-
61
- try {
62
- let readme = "";
63
-
64
- const newTitle = title
65
- .toLowerCase()
66
- .replace(/[^a-z0-9]+/g, "-")
67
- .split("-")
68
- .filter(Boolean)
69
- .join("-")
70
- .slice(0, 96);
71
-
72
- const repo: RepoDesignation = {
73
- type: "space",
74
- name: `${user.name}/${newTitle}`,
75
- };
76
-
77
- const { repoUrl } = await createRepo({
78
- repo,
79
- accessToken: user.token as string,
80
- });
81
- const colorFrom = COLORS[Math.floor(Math.random() * COLORS.length)];
82
- const colorTo = COLORS[Math.floor(Math.random() * COLORS.length)];
83
- readme = `---
84
- title: ${newTitle}
85
- emoji: 🐳
86
- colorFrom: ${colorFrom}
87
- colorTo: ${colorTo}
88
- sdk: static
89
- pinned: false
90
- tags:
91
- - deepsite
92
- ---
93
-
94
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference`;
95
-
96
- const readmeFile = new File([readme], "README.md", {
97
- type: "text/markdown",
98
- });
99
- const promptsFile = new File([prompts.join("\n")], "prompts.txt", {
100
- type: "text/plain",
101
- });
102
- const files = [readmeFile, promptsFile];
103
- pages.forEach((page: Page) => {
104
- const file = new File([page.html], page.path, { type: "text/html" });
105
- files.push(file);
106
- });
107
- await uploadFiles({
108
- repo,
109
- files,
110
- accessToken: user.token as string,
111
- commitTitle: `${prompts[prompts.length - 1]} - Initial Deployment`,
112
- });
113
- const path = repoUrl.split("/").slice(-2).join("/");
114
- const project = await Project.create({
115
- user_id: user.id,
116
- space_id: path,
117
- prompts,
118
- });
119
- return NextResponse.json({ project, path, ok: true }, { status: 201 });
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- } catch (err: any) {
122
- return NextResponse.json(
123
- { error: err.message, ok: false },
124
- { status: 500 }
125
- );
126
- }
127
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/me/route.ts DELETED
@@ -1,25 +0,0 @@
1
- import { headers } from "next/headers";
2
- import { NextResponse } from "next/server";
3
-
4
- export async function GET() {
5
- const authHeaders = await headers();
6
- const token = authHeaders.get("Authorization");
7
- if (!token) {
8
- return NextResponse.json({ user: null, errCode: 401 }, { status: 401 });
9
- }
10
-
11
- const userResponse = await fetch("https://huggingface.co/api/whoami-v2", {
12
- headers: {
13
- Authorization: `${token}`,
14
- },
15
- });
16
-
17
- if (!userResponse.ok) {
18
- return NextResponse.json(
19
- { user: null, errCode: userResponse.status },
20
- { status: userResponse.status }
21
- );
22
- }
23
- const user = await userResponse.json();
24
- return NextResponse.json({ user, errCode: null }, { status: 200 });
25
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/re-design/route.ts DELETED
@@ -1,39 +0,0 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
-
3
- export async function PUT(request: NextRequest) {
4
- const body = await request.json();
5
- const { url } = body;
6
-
7
- if (!url) {
8
- return NextResponse.json({ error: "URL is required" }, { status: 400 });
9
- }
10
-
11
- try {
12
- const response = await fetch(
13
- `https://r.jina.ai/${encodeURIComponent(url)}`,
14
- {
15
- method: "POST",
16
- }
17
- );
18
- if (!response.ok) {
19
- return NextResponse.json(
20
- { error: "Failed to fetch redesign" },
21
- { status: 500 }
22
- );
23
- }
24
- const markdown = await response.text();
25
- return NextResponse.json(
26
- {
27
- ok: true,
28
- markdown,
29
- },
30
- { status: 200 }
31
- );
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- } catch (error: any) {
34
- return NextResponse.json(
35
- { error: error.message || "An error occurred" },
36
- { status: 500 }
37
- );
38
- }
39
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/auth/callback/page.tsx DELETED
@@ -1,72 +0,0 @@
1
- "use client";
2
- import Link from "next/link";
3
- import { useUser } from "@/hooks/useUser";
4
- import { use, useState } from "react";
5
- import { useMount, useTimeoutFn } from "react-use";
6
-
7
- import { Button } from "@/components/ui/button";
8
- export default function AuthCallback({
9
- searchParams,
10
- }: {
11
- searchParams: Promise<{ code: string }>;
12
- }) {
13
- const [showButton, setShowButton] = useState(false);
14
- const { code } = use(searchParams);
15
- const { loginFromCode } = useUser();
16
-
17
- useMount(async () => {
18
- if (code) {
19
- await loginFromCode(code);
20
- }
21
- });
22
-
23
- useTimeoutFn(
24
- () => setShowButton(true),
25
- 7000 // Show button after 5 seconds
26
- );
27
-
28
- return (
29
- <div className="h-screen flex flex-col justify-center items-center">
30
- <div className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden ring-[8px] ring-white/20">
31
- <header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
32
- <div className="flex items-center justify-center -space-x-4 mb-3">
33
- <div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
34
- 🚀
35
- </div>
36
- <div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
37
- 👋
38
- </div>
39
- <div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
40
- 🙌
41
- </div>
42
- </div>
43
- <p className="text-xl font-semibold text-neutral-950">
44
- Login In Progress...
45
- </p>
46
- <p className="text-sm text-neutral-500 mt-1.5">
47
- Wait a moment while we log you in with your code.
48
- </p>
49
- </header>
50
- <main className="space-y-4 p-6">
51
- <div>
52
- <p className="text-sm text-neutral-700 mb-4 max-w-xs">
53
- If you are not redirected automatically in the next 5 seconds,
54
- please click the button below
55
- </p>
56
- {showButton ? (
57
- <Link href="/">
58
- <Button variant="black" className="relative">
59
- Go to Home
60
- </Button>
61
- </Link>
62
- ) : (
63
- <p className="text-xs text-neutral-500">
64
- Please wait, we are logging you in...
65
- </p>
66
- )}
67
- </div>
68
- </main>
69
- </div>
70
- </div>
71
- );
72
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/auth/page.tsx DELETED
@@ -1,28 +0,0 @@
1
- import { redirect } from "next/navigation";
2
- import { Metadata } from "next";
3
-
4
- import { getAuth } from "@/app/actions/auth";
5
-
6
- export const revalidate = 1;
7
-
8
- export const metadata: Metadata = {
9
- robots: "noindex, nofollow",
10
- };
11
-
12
- export default async function Auth() {
13
- const loginRedirectUrl = await getAuth();
14
- if (loginRedirectUrl) {
15
- redirect(loginRedirectUrl);
16
- }
17
-
18
- return (
19
- <div className="p-4">
20
- <div className="border bg-red-500/10 border-red-500/20 text-red-500 px-5 py-3 rounded-lg">
21
- <h1 className="text-xl font-bold">Error</h1>
22
- <p className="text-sm">
23
- An error occurred while trying to log in. Please try again later.
24
- </p>
25
- </div>
26
- </div>
27
- );
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/favicon.ico DELETED
Binary file (25.9 kB)
 
app/layout.tsx DELETED
@@ -1,112 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import type { Metadata, Viewport } from "next";
3
- import { Inter, PT_Sans } from "next/font/google";
4
- import { cookies } from "next/headers";
5
-
6
- import TanstackProvider from "@/components/providers/tanstack-query-provider";
7
- import "@/assets/globals.css";
8
- import { Toaster } from "@/components/ui/sonner";
9
- import MY_TOKEN_KEY from "@/lib/get-cookie-name";
10
- import { apiServer } from "@/lib/api";
11
- import AppContext from "@/components/contexts/app-context";
12
- import Script from "next/script";
13
- import IframeDetector from "@/components/iframe-detector";
14
-
15
- const inter = Inter({
16
- variable: "--font-inter-sans",
17
- subsets: ["latin"],
18
- });
19
-
20
- const ptSans = PT_Sans({
21
- variable: "--font-ptSans-mono",
22
- subsets: ["latin"],
23
- weight: ["400", "700"],
24
- });
25
-
26
- export const metadata: Metadata = {
27
- title: "DeepSite | Build with AI ✨",
28
- description:
29
- "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
30
- openGraph: {
31
- title: "DeepSite | Build with AI ✨",
32
- description:
33
- "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
34
- url: "https://deepsite.hf.co",
35
- siteName: "DeepSite",
36
- images: [
37
- {
38
- url: "https://deepsite.hf.co/banner.png",
39
- width: 1200,
40
- height: 630,
41
- alt: "DeepSite Open Graph Image",
42
- },
43
- ],
44
- },
45
- twitter: {
46
- card: "summary_large_image",
47
- title: "DeepSite | Build with AI ✨",
48
- description:
49
- "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
50
- images: ["https://deepsite.hf.co/banner.png"],
51
- },
52
- appleWebApp: {
53
- capable: true,
54
- title: "DeepSite",
55
- statusBarStyle: "black-translucent",
56
- },
57
- icons: {
58
- icon: "/logo.svg",
59
- shortcut: "/logo.svg",
60
- apple: "/logo.svg",
61
- },
62
- };
63
-
64
- export const viewport: Viewport = {
65
- initialScale: 1,
66
- maximumScale: 1,
67
- themeColor: "#000000",
68
- };
69
-
70
- async function getMe() {
71
- const cookieStore = await cookies();
72
- const token = cookieStore.get(MY_TOKEN_KEY())?.value;
73
- if (!token) return { user: null, errCode: null };
74
- try {
75
- const res = await apiServer.get("/me", {
76
- headers: {
77
- Authorization: `Bearer ${token}`,
78
- },
79
- });
80
- return { user: res.data.user, errCode: null };
81
- } catch (err: any) {
82
- return { user: null, errCode: err.status };
83
- }
84
- }
85
-
86
- // if domain isn't deepsite.hf.co or enzostvs-deepsite.hf.space redirect to deepsite.hf.co
87
-
88
- export default async function RootLayout({
89
- children,
90
- }: Readonly<{
91
- children: React.ReactNode;
92
- }>) {
93
- const data = await getMe();
94
- return (
95
- <html lang="en">
96
- <Script
97
- defer
98
- data-domain="deepsite.hf.co"
99
- src="https://plausible.io/js/script.js"
100
- ></Script>
101
- <body
102
- className={`${inter.variable} ${ptSans.variable} antialiased bg-black dark h-[100dvh] overflow-hidden`}
103
- >
104
- <IframeDetector />
105
- <Toaster richColors position="bottom-center" />
106
- <TanstackProvider>
107
- <AppContext me={data}>{children}</AppContext>
108
- </TanstackProvider>
109
- </body>
110
- </html>
111
- );
112
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/projects/[namespace]/[repoId]/page.tsx DELETED
@@ -1,42 +0,0 @@
1
- import { cookies } from "next/headers";
2
- import { redirect } from "next/navigation";
3
-
4
- import { apiServer } from "@/lib/api";
5
- import MY_TOKEN_KEY from "@/lib/get-cookie-name";
6
- import { AppEditor } from "@/components/editor";
7
-
8
- async function getProject(namespace: string, repoId: string) {
9
- // TODO replace with a server action
10
- const cookieStore = await cookies();
11
- const token = cookieStore.get(MY_TOKEN_KEY())?.value;
12
- if (!token) return {};
13
- try {
14
- const { data } = await apiServer.get(
15
- `/me/projects/${namespace}/${repoId}`,
16
- {
17
- headers: {
18
- Authorization: `Bearer ${token}`,
19
- },
20
- }
21
- );
22
-
23
- return data.project;
24
- } catch {
25
- return {};
26
- }
27
- }
28
-
29
- export default async function ProjectNamespacePage({
30
- params,
31
- }: {
32
- params: Promise<{ namespace: string; repoId: string }>;
33
- }) {
34
- const { namespace, repoId } = await params;
35
- const data = await getProject(namespace, repoId);
36
- if (!data?.pages) {
37
- redirect("/projects");
38
- }
39
- return (
40
- <AppEditor project={data} pages={data.pages} images={data.images ?? []} />
41
- );
42
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/projects/new/page.tsx DELETED
@@ -1,5 +0,0 @@
1
- import { AppEditor } from "@/components/editor";
2
-
3
- export default function ProjectsNewPage() {
4
- return <AppEditor isNew />;
5
- }