Update Dockerfile

#446
by XciD HF Staff - opened
Files changed (3) hide show
  1. Dockerfile +2 -6
  2. app/api/ask/route.ts +114 -21
  3. hooks/useAi.ts +3 -9
Dockerfile CHANGED
@@ -1,16 +1,12 @@
1
- FROM node:20-alpine
2
- USER root
3
 
4
  USER 1000
5
  WORKDIR /usr/src/app
6
- # Copy package.json and package-lock.json to the container
7
- COPY --chown=1000 package.json package-lock.json ./
8
 
9
  # Copy the rest of the application files to the container
10
  COPY --chown=1000 . .
11
 
12
- RUN npm install
13
- RUN npm run build
14
 
15
  # Expose the application port (assuming your app runs on port 3000)
16
  EXPOSE 3000
 
1
+ FROM node:22
 
2
 
3
  USER 1000
4
  WORKDIR /usr/src/app
 
 
5
 
6
  # Copy the rest of the application files to the container
7
  COPY --chown=1000 . .
8
 
9
+ RUN npm install && npm run build
 
10
 
11
  # Expose the application port (assuming your app runs on port 3000)
12
  EXPOSE 3000
app/api/ask/route.ts CHANGED
@@ -285,11 +285,35 @@ export async function PUT(request: NextRequest) {
285
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
286
  };
287
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  const createFlexibleHtmlRegex = (searchBlock: string) => {
289
- let searchRegex = escapeRegExp(searchBlock)
290
- .replace(/\s+/g, '\\s*')
 
 
 
 
291
  .replace(/>\s*</g, '>\\s*<')
292
- .replace(/\s*>/g, '\\s*>');
 
293
 
294
  return new RegExp(searchRegex, 'g');
295
  };
@@ -450,17 +474,49 @@ export async function PUT(request: NextRequest) {
450
  updatedLines.push([1, replaceBlock.split("\n").length]);
451
  } else {
452
  const regex = createFlexibleHtmlRegex(searchBlock);
453
- const match = regex.exec(pageHtml);
 
 
 
454
 
455
  if (match) {
456
- const matchedText = match[0];
457
- const beforeText = pageHtml.substring(0, match.index);
458
- const startLineNumber = beforeText.split("\n").length;
459
- const replaceLines = replaceBlock.split("\n").length;
460
- const endLineNumber = startLineNumber + replaceLines - 1;
461
-
462
- updatedLines.push([startLineNumber, endLineNumber]);
463
- pageHtml = pageHtml.replace(matchedText, replaceBlock);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  }
465
  }
466
 
@@ -539,17 +595,54 @@ export async function PUT(request: NextRequest) {
539
  updatedLines.push([1, replaceBlock.split("\n").length]);
540
  } else {
541
  const regex = createFlexibleHtmlRegex(searchBlock);
542
- const match = regex.exec(newHtml);
 
 
 
 
 
 
 
 
 
543
 
544
  if (match) {
545
- const matchedText = match[0];
546
- const beforeText = newHtml.substring(0, match.index);
547
- const startLineNumber = beforeText.split("\n").length;
548
- const replaceLines = replaceBlock.split("\n").length;
549
- const endLineNumber = startLineNumber + replaceLines - 1;
550
-
551
- updatedLines.push([startLineNumber, endLineNumber]);
552
- newHtml = newHtml.replace(matchedText, replaceBlock);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  }
554
  }
555
 
 
285
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
286
  };
287
 
288
+ const normalizeHtml = (html: string): string => {
289
+ return html
290
+ // Normalize whitespace within tags
291
+ .replace(/\s+/g, ' ')
292
+ // Remove spaces before closing >
293
+ .replace(/\s+>/g, '>')
294
+ // Remove spaces before />
295
+ .replace(/\s+\/>/g, '/>')
296
+ // Normalize spaces around = in attributes
297
+ .replace(/\s*=\s*/g, '=')
298
+ // Normalize quotes (convert single to double)
299
+ .replace(/='([^']*)'/g, '="$1"')
300
+ // Remove trailing spaces in opening/closing tags
301
+ .replace(/<([^>]*?)\s+>/g, '<$1>')
302
+ // Normalize self-closing tags
303
+ .replace(/\/\s*>/g, '/>')
304
+ .trim();
305
+ };
306
+
307
  const createFlexibleHtmlRegex = (searchBlock: string) => {
308
+ // Normalize both the search block for comparison
309
+ const normalizedSearch = normalizeHtml(searchBlock);
310
+
311
+ // Escape regex special characters
312
+ let searchRegex = escapeRegExp(normalizedSearch)
313
+ // Make whitespace flexible (but only between elements, not within tags)
314
  .replace(/>\s*</g, '>\\s*<')
315
+ // Make line breaks and spaces around content flexible
316
+ .replace(/>\s*([^<]+)\s*</g, '>\\s*$1\\s*<');
317
 
318
  return new RegExp(searchRegex, 'g');
319
  };
 
474
  updatedLines.push([1, replaceBlock.split("\n").length]);
475
  } else {
476
  const regex = createFlexibleHtmlRegex(searchBlock);
477
+
478
+ // Normalize the pageHtml for matching
479
+ const normalizedPageHtml = normalizeHtml(pageHtml);
480
+ const match = regex.exec(normalizedPageHtml);
481
 
482
  if (match) {
483
+ // Find the original match in the non-normalized HTML
484
+ const normalizedSearch = normalizeHtml(searchBlock);
485
+ const originalMatchIndex = pageHtml.indexOf(searchBlock);
486
+
487
+ if (originalMatchIndex !== -1) {
488
+ const beforeText = pageHtml.substring(0, originalMatchIndex);
489
+ const startLineNumber = beforeText.split("\n").length;
490
+ const replaceLines = replaceBlock.split("\n").length;
491
+ const endLineNumber = startLineNumber + replaceLines - 1;
492
+
493
+ updatedLines.push([startLineNumber, endLineNumber]);
494
+ pageHtml = pageHtml.replace(searchBlock, replaceBlock);
495
+ } else {
496
+ // Fallback: try to find similar pattern in the original HTML
497
+ const flexibleRegex = new RegExp(
498
+ escapeRegExp(searchBlock)
499
+ .replace(/\s+/g, '\\s+')
500
+ .replace(/\s*=\s*/g, '\\s*=\\s*')
501
+ .replace(/'\s*([^']*)\s*'/g, "'\\s*$1\\s*'")
502
+ .replace(/"\s*([^"]*)\s*"/g, '"\\s*$1\\s*"')
503
+ .replace(/\s*>/g, '\\s*>')
504
+ .replace(/\s*\/>/g, '\\s*/>'),
505
+ 'g'
506
+ );
507
+
508
+ const flexibleMatch = flexibleRegex.exec(pageHtml);
509
+ if (flexibleMatch) {
510
+ const matchedText = flexibleMatch[0];
511
+ const beforeText = pageHtml.substring(0, flexibleMatch.index);
512
+ const startLineNumber = beforeText.split("\n").length;
513
+ const replaceLines = replaceBlock.split("\n").length;
514
+ const endLineNumber = startLineNumber + replaceLines - 1;
515
+
516
+ updatedLines.push([startLineNumber, endLineNumber]);
517
+ pageHtml = pageHtml.replace(matchedText, replaceBlock);
518
+ }
519
+ }
520
  }
521
  }
522
 
 
595
  updatedLines.push([1, replaceBlock.split("\n").length]);
596
  } else {
597
  const regex = createFlexibleHtmlRegex(searchBlock);
598
+
599
+ // Get the main page HTML (first page or index page)
600
+ const mainPage = updatedPages.find(p => p.path === '/' || p.path === '/index' || p.path === 'index') || updatedPages[0];
601
+ if (!mainPage) continue;
602
+
603
+ newHtml = mainPage.html;
604
+
605
+ // Normalize the newHtml for matching
606
+ const normalizedNewHtml = normalizeHtml(newHtml);
607
+ const match = regex.exec(normalizedNewHtml);
608
 
609
  if (match) {
610
+ // Find the original match in the non-normalized HTML
611
+ const originalMatchIndex = newHtml.indexOf(searchBlock);
612
+
613
+ if (originalMatchIndex !== -1) {
614
+ const beforeText = newHtml.substring(0, originalMatchIndex);
615
+ const startLineNumber = beforeText.split("\n").length;
616
+ const replaceLines = replaceBlock.split("\n").length;
617
+ const endLineNumber = startLineNumber + replaceLines - 1;
618
+
619
+ updatedLines.push([startLineNumber, endLineNumber]);
620
+ newHtml = newHtml.replace(searchBlock, replaceBlock);
621
+ } else {
622
+ // Fallback: try to find similar pattern in the original HTML
623
+ const flexibleRegex = new RegExp(
624
+ escapeRegExp(searchBlock)
625
+ .replace(/\s+/g, '\\s+')
626
+ .replace(/\s*=\s*/g, '\\s*=\\s*')
627
+ .replace(/'\s*([^']*)\s*'/g, "'\\s*$1\\s*'")
628
+ .replace(/"\s*([^"]*)\s*"/g, '"\\s*$1\\s*"')
629
+ .replace(/\s*>/g, '\\s*>')
630
+ .replace(/\s*\/>/g, '\\s*/>'),
631
+ 'g'
632
+ );
633
+
634
+ const flexibleMatch = flexibleRegex.exec(newHtml);
635
+ if (flexibleMatch) {
636
+ const matchedText = flexibleMatch[0];
637
+ const beforeText = newHtml.substring(0, flexibleMatch.index);
638
+ const startLineNumber = beforeText.split("\n").length;
639
+ const replaceLines = replaceBlock.split("\n").length;
640
+ const endLineNumber = startLineNumber + replaceLines - 1;
641
+
642
+ updatedLines.push([startLineNumber, endLineNumber]);
643
+ newHtml = newHtml.replace(matchedText, replaceBlock);
644
+ }
645
+ }
646
  }
647
  }
648
 
hooks/useAi.ts CHANGED
@@ -10,7 +10,6 @@ import { api } from "@/lib/api";
10
  import { useRouter } from "next/navigation";
11
  import { useUser } from "./useUser";
12
  import { LivePreviewRef } from "@/components/editor/live-preview";
13
- import { isTheSameHtml } from "@/lib/compare-html-diff";
14
 
15
  export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefObject<LivePreviewRef | null>) => {
16
  const client = useQueryClient();
@@ -199,15 +198,10 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
199
  }
200
 
201
  const newPages = formatPages(contentResponse);
202
- let projectName = contentResponse.match(/<<<<<<< PROJECT_NAME_START ([\s\S]*?) >>>>>>> PROJECT_NAME_END/)?.[1]?.trim();
203
- if (!projectName) {
204
- projectName = prompt.substring(0, 40).replace(/[^a-zA-Z0-9]/g, "-").slice(0, 40);
205
- }
206
  setPages(newPages);
207
- setLastSavedPages([...newPages]);
208
- if (newPages.length > 0 && !isTheSameHtml(newPages[0].html)) {
209
- createNewProject(prompt, newPages, projectName, isLoggedIn);
210
- }
211
  setPrompts([...prompts, prompt]);
212
 
213
  return { success: true, pages: newPages };
 
10
  import { useRouter } from "next/navigation";
11
  import { useUser } from "./useUser";
12
  import { LivePreviewRef } from "@/components/editor/live-preview";
 
13
 
14
  export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefObject<LivePreviewRef | null>) => {
15
  const client = useQueryClient();
 
198
  }
199
 
200
  const newPages = formatPages(contentResponse);
201
+ const projectName = contentResponse.match(/<<<<<<< PROJECT_NAME_START ([\s\S]*?) >>>>>>> PROJECT_NAME_END/)?.[1]?.trim();
 
 
 
202
  setPages(newPages);
203
+ setLastSavedPages([...newPages]); // Mark initial pages as saved
204
+ createNewProject(prompt, newPages, projectName, isLoggedIn);
 
 
205
  setPrompts([...prompts, prompt]);
206
 
207
  return { success: true, pages: newPages };