enzostvs HF Staff commited on
Commit
e710a1b
·
1 Parent(s): d071fc0

handle free request

Browse files
app/api/ask/route.ts CHANGED
@@ -66,7 +66,8 @@ export async function POST(request: NextRequest) {
66
  );
67
  }
68
 
69
- let token = userToken;
 
70
  let billTo: string | null = null;
71
 
72
  /**
 
66
  );
67
  }
68
 
69
+ let token: string | null = null;
70
+ if (userToken) token = userToken;
71
  let billTo: string | null = null;
72
 
73
  /**
components/contexts/login-context.tsx CHANGED
@@ -13,6 +13,7 @@ interface LoginContextType {
13
  interface LoginModalOptions {
14
  pages?: Page[];
15
  title?: string;
 
16
  description?: string;
17
  }
18
 
@@ -44,8 +45,8 @@ export function LoginProvider({ children }: { children: ReactNode }) {
44
  <LoginModal
45
  open={isOpen}
46
  onClose={setIsOpen}
47
- pages={modalOptions.pages}
48
  title={modalOptions.title}
 
49
  description={modalOptions.description}
50
  />
51
  </LoginContext.Provider>
 
13
  interface LoginModalOptions {
14
  pages?: Page[];
15
  title?: string;
16
+ prompt?: string;
17
  description?: string;
18
  }
19
 
 
45
  <LoginModal
46
  open={isOpen}
47
  onClose={setIsOpen}
 
48
  title={modalOptions.title}
49
+ prompt={modalOptions.prompt}
50
  description={modalOptions.description}
51
  />
52
  </LoginContext.Provider>
components/editor/ask-ai/index.tsx CHANGED
@@ -33,7 +33,6 @@ export const AskAi = ({
33
  }) => {
34
  const { user, projects } = useUser();
35
  const { isSameHtml, isUploading, pages, isLoadingProject } = useEditor();
36
- console.log("isSameHtml", isSameHtml);
37
  const {
38
  isAiWorking,
39
  isThinking,
@@ -57,7 +56,7 @@ export const AskAi = ({
57
 
58
  const [enhancedSettings, setEnhancedSettings, removeEnhancedSettings] =
59
  useLocalStorage<EnhancedSettings>("deepsite-enhancedSettings", {
60
- isActive: true,
61
  primaryColor: undefined,
62
  secondaryColor: undefined,
63
  theme: undefined,
@@ -65,7 +64,9 @@ export const AskAi = ({
65
  const [promptStorage, , removePromptStorage] = useLocalStorage("prompt", "");
66
 
67
  const [isFollowUp, setIsFollowUp] = useState(true);
68
- const [prompt, setPrompt] = useState("");
 
 
69
  const [think, setThink] = useState("");
70
  const [openThink, setOpenThink] = useState(false);
71
 
@@ -77,20 +78,19 @@ export const AskAi = ({
77
 
78
  useMount(() => {
79
  if (promptStorage && promptStorage.trim() !== "") {
80
- setPrompt(promptStorage);
81
  callAi();
82
  }
83
  });
84
 
85
  const callAi = async (redesignMarkdown?: string) => {
86
- if (!user) return openLoginModal();
87
  removePromptStorage();
88
- if (!user.isPro && projects.length >= MAX_FREE_PROJECTS)
89
  return openProModal([]);
90
  if (isAiWorking) return;
91
  if (!redesignMarkdown && !prompt.trim()) return;
92
 
93
  if (isFollowUp && !redesignMarkdown && !isSameHtml) {
 
94
  const result = await callAiFollowUp(prompt, enhancedSettings, isNew);
95
 
96
  if (result?.error) {
@@ -106,10 +106,7 @@ export const AskAi = ({
106
  prompt,
107
  enhancedSettings,
108
  redesignMarkdown,
109
- handleThink,
110
- () => {
111
- setIsThinking(false);
112
- }
113
  );
114
 
115
  if (result?.error) {
 
33
  }) => {
34
  const { user, projects } = useUser();
35
  const { isSameHtml, isUploading, pages, isLoadingProject } = useEditor();
 
36
  const {
37
  isAiWorking,
38
  isThinking,
 
56
 
57
  const [enhancedSettings, setEnhancedSettings, removeEnhancedSettings] =
58
  useLocalStorage<EnhancedSettings>("deepsite-enhancedSettings", {
59
+ isActive: false,
60
  primaryColor: undefined,
61
  secondaryColor: undefined,
62
  theme: undefined,
 
64
  const [promptStorage, , removePromptStorage] = useLocalStorage("prompt", "");
65
 
66
  const [isFollowUp, setIsFollowUp] = useState(true);
67
+ const [prompt, setPrompt] = useState(
68
+ promptStorage && promptStorage.trim() !== "" ? promptStorage : ""
69
+ );
70
  const [think, setThink] = useState("");
71
  const [openThink, setOpenThink] = useState(false);
72
 
 
78
 
79
  useMount(() => {
80
  if (promptStorage && promptStorage.trim() !== "") {
 
81
  callAi();
82
  }
83
  });
84
 
85
  const callAi = async (redesignMarkdown?: string) => {
 
86
  removePromptStorage();
87
+ if (user && !user.isPro && projects.length >= MAX_FREE_PROJECTS)
88
  return openProModal([]);
89
  if (isAiWorking) return;
90
  if (!redesignMarkdown && !prompt.trim()) return;
91
 
92
  if (isFollowUp && !redesignMarkdown && !isSameHtml) {
93
+ if (!user) return openLoginModal({ prompt });
94
  const result = await callAiFollowUp(prompt, enhancedSettings, isNew);
95
 
96
  if (result?.error) {
 
106
  prompt,
107
  enhancedSettings,
108
  redesignMarkdown,
109
+ !!user
 
 
 
110
  );
111
 
112
  if (result?.error) {
components/editor/ask-ai/prompt-builder/index.tsx CHANGED
@@ -11,8 +11,6 @@ import {
11
  DialogTitle,
12
  } from "@/components/ui/dialog";
13
  import { ContentModal } from "./content-modal";
14
- import { useLoginModal } from "@/components/contexts/login-context";
15
- import { useUser } from "@/hooks/useUser";
16
  import { EnhancedSettings } from "@/types";
17
 
18
  export const PromptBuilder = ({
@@ -22,8 +20,6 @@ export const PromptBuilder = ({
22
  enhancedSettings: EnhancedSettings;
23
  setEnhancedSettings: (settings: EnhancedSettings) => void;
24
  }) => {
25
- const { user } = useUser();
26
- const { openLoginModal } = useLoginModal();
27
  const { globalAiLoading } = useAi();
28
  const { globalEditorLoading } = useEditor();
29
 
@@ -36,7 +32,6 @@ export const PromptBuilder = ({
36
  className="!rounded-md !border-white/10 !bg-gradient-to-r from-sky-400/15 to-purple-400/15 light-sweep hover:brightness-110"
37
  disabled={globalAiLoading || globalEditorLoading}
38
  onClick={() => {
39
- if (!user) return openLoginModal();
40
  setOpen(true);
41
  }}
42
  >
 
11
  DialogTitle,
12
  } from "@/components/ui/dialog";
13
  import { ContentModal } from "./content-modal";
 
 
14
  import { EnhancedSettings } from "@/types";
15
 
16
  export const PromptBuilder = ({
 
20
  enhancedSettings: EnhancedSettings;
21
  setEnhancedSettings: (settings: EnhancedSettings) => void;
22
  }) => {
 
 
23
  const { globalAiLoading } = useAi();
24
  const { globalEditorLoading } = useEditor();
25
 
 
32
  className="!rounded-md !border-white/10 !bg-gradient-to-r from-sky-400/15 to-purple-400/15 light-sweep hover:brightness-110"
33
  disabled={globalAiLoading || globalEditorLoading}
34
  onClick={() => {
 
35
  setOpen(true);
36
  }}
37
  >
components/editor/ask-ai/re-imagine.tsx CHANGED
@@ -13,8 +13,6 @@ import Loading from "@/components/loading";
13
  import { api } from "@/lib/api";
14
  import { useAi } from "@/hooks/useAi";
15
  import { useEditor } from "@/hooks/useEditor";
16
- import { useUser } from "@/hooks/useUser";
17
- import { useLoginModal } from "@/components/contexts/login-context";
18
 
19
  export function ReImagine({
20
  onRedesign,
@@ -26,8 +24,6 @@ export function ReImagine({
26
  const [isLoading, setIsLoading] = useState(false);
27
  const { globalAiLoading } = useAi();
28
  const { globalEditorLoading } = useEditor();
29
- const { user } = useUser();
30
- const { openLoginModal } = useLoginModal();
31
 
32
  const checkIfUrlIsValid = (url: string) => {
33
  const urlPattern = new RegExp(
@@ -62,19 +58,6 @@ export function ReImagine({
62
  setIsLoading(false);
63
  };
64
 
65
- if (!user)
66
- return (
67
- <Button
68
- size="xs"
69
- variant="outline"
70
- className="!rounded-md"
71
- onClick={() => openLoginModal()}
72
- >
73
- <Paintbrush className="size-3.5" />
74
- Redesign
75
- </Button>
76
- );
77
-
78
  return (
79
  <Popover open={open} onOpenChange={setOpen}>
80
  <form>
 
13
  import { api } from "@/lib/api";
14
  import { useAi } from "@/hooks/useAi";
15
  import { useEditor } from "@/hooks/useEditor";
 
 
16
 
17
  export function ReImagine({
18
  onRedesign,
 
24
  const [isLoading, setIsLoading] = useState(false);
25
  const { globalAiLoading } = useAi();
26
  const { globalEditorLoading } = useEditor();
 
 
27
 
28
  const checkIfUrlIsValid = (url: string) => {
29
  const urlPattern = new RegExp(
 
58
  setIsLoading(false);
59
  };
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  return (
62
  <Popover open={open} onOpenChange={setOpen}>
63
  <form>
components/editor/index.tsx CHANGED
@@ -1,6 +1,6 @@
1
  "use client";
2
  import { useMemo, useRef, useState, useEffect } from "react";
3
- import { useCopyToClipboard, useMount } from "react-use";
4
  import { CopyIcon } from "lucide-react";
5
  import { toast } from "sonner";
6
  import classNames from "classnames";
@@ -18,6 +18,7 @@ import { Preview } from "./preview";
18
  import { SaveChangesPopup } from "./save-changes-popup";
19
  import Loading from "../loading";
20
  import { LivePreviewRef } from "./live-preview";
 
21
 
22
  export const AppEditor = ({
23
  namespace,
@@ -43,6 +44,7 @@ export const AppEditor = ({
43
  const { isAiWorking } = useAi(undefined, livePreviewRef);
44
  const [, copyToClipboard] = useCopyToClipboard();
45
  const [showSavePopup, setShowSavePopup] = useState(false);
 
46
 
47
  const monacoRef = useRef<any>(null);
48
  const editor = useRef<HTMLDivElement>(null);
@@ -50,12 +52,8 @@ export const AppEditor = ({
50
 
51
  useMount(() => {
52
  if (isNew) {
53
- setPages([
54
- {
55
- path: "index.html",
56
- html: defaultHTML,
57
- },
58
- ]);
59
  }
60
  });
61
 
 
1
  "use client";
2
  import { useMemo, useRef, useState, useEffect } from "react";
3
+ import { useCopyToClipboard, useLocalStorage, useMount } from "react-use";
4
  import { CopyIcon } from "lucide-react";
5
  import { toast } from "sonner";
6
  import classNames from "classnames";
 
18
  import { SaveChangesPopup } from "./save-changes-popup";
19
  import Loading from "../loading";
20
  import { LivePreviewRef } from "./live-preview";
21
+ import { Page } from "@/types";
22
 
23
  export const AppEditor = ({
24
  namespace,
 
44
  const { isAiWorking } = useAi(undefined, livePreviewRef);
45
  const [, copyToClipboard] = useCopyToClipboard();
46
  const [showSavePopup, setShowSavePopup] = useState(false);
47
+ const [pagesStorage, , removePagesStorage] = useLocalStorage<Page[]>("pages");
48
 
49
  const monacoRef = useRef<any>(null);
50
  const editor = useRef<HTMLDivElement>(null);
 
52
 
53
  useMount(() => {
54
  if (isNew) {
55
+ setPages(pagesStorage || []);
56
+ removePagesStorage();
 
 
 
 
57
  }
58
  });
59
 
components/login-modal/index.tsx CHANGED
@@ -4,23 +4,29 @@ import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
4
  import { useUser } from "@/hooks/useUser";
5
  import { isTheSameHtml } from "@/lib/compare-html-diff";
6
  import { Page } from "@/types";
 
7
 
8
  export const LoginModal = ({
9
  open,
10
- pages,
11
  onClose,
12
  title = "Log In to use DeepSite for free",
13
  description = "Log In through your Hugging Face account to continue using DeepSite and increase your monthly free limit.",
 
14
  }: {
15
  open: boolean;
16
- pages?: Page[];
17
  onClose: React.Dispatch<React.SetStateAction<boolean>>;
18
  title?: string;
19
  description?: string;
 
20
  }) => {
21
  const { openLoginWindow } = useUser();
 
22
  const [, setStorage] = useLocalStorage("pages");
 
23
  const handleClick = async () => {
 
 
 
24
  if (pages && !isTheSameHtml(pages[0].html)) {
25
  setStorage(pages);
26
  }
 
4
  import { useUser } from "@/hooks/useUser";
5
  import { isTheSameHtml } from "@/lib/compare-html-diff";
6
  import { Page } from "@/types";
7
+ import { useEditor } from "@/hooks/useEditor";
8
 
9
  export const LoginModal = ({
10
  open,
 
11
  onClose,
12
  title = "Log In to use DeepSite for free",
13
  description = "Log In through your Hugging Face account to continue using DeepSite and increase your monthly free limit.",
14
+ prompt,
15
  }: {
16
  open: boolean;
 
17
  onClose: React.Dispatch<React.SetStateAction<boolean>>;
18
  title?: string;
19
  description?: string;
20
+ prompt?: string;
21
  }) => {
22
  const { openLoginWindow } = useUser();
23
+ const { pages } = useEditor();
24
  const [, setStorage] = useLocalStorage("pages");
25
+ const [, setPromptStorage] = useLocalStorage("prompt", "");
26
  const handleClick = async () => {
27
+ if (prompt) {
28
+ setPromptStorage(prompt);
29
+ }
30
  if (pages && !isTheSameHtml(pages[0].html)) {
31
  setStorage(pages);
32
  }
components/my-projects/index.tsx CHANGED
@@ -93,7 +93,7 @@ export function MyProjects() {
93
  )}
94
  {projects.map((project: ProjectType) => (
95
  <ProjectCard
96
- key={project.id}
97
  project={project}
98
  onDelete={() => onDelete(project)}
99
  />
 
93
  )}
94
  {projects.map((project: ProjectType) => (
95
  <ProjectCard
96
+ key={project.name}
97
  project={project}
98
  onDelete={() => onDelete(project)}
99
  />
components/not-logged/not-logged.tsx CHANGED
@@ -1,13 +1,9 @@
1
  "use client";
2
 
3
- import { useUser } from "@/hooks/useUser";
4
- import { Button } from "@/components/ui/button";
5
  import { AnimatedBlobs } from "../animated-blobs";
6
- import { AnimatedText } from "../animated-text";
7
  import { FakeAskAi } from "../editor/ask-ai/fake-ask";
8
 
9
  export const NotLogged = () => {
10
- const { openLoginWindow } = useUser();
11
  return (
12
  <section className="relative max-w-[86rem] mx-auto">
13
  <header className="container mx-auto pt-20 px-6 relative flex flex-col items-center justify-center text-center">
 
1
  "use client";
2
 
 
 
3
  import { AnimatedBlobs } from "../animated-blobs";
 
4
  import { FakeAskAi } from "../editor/ask-ai/fake-ask";
5
 
6
  export const NotLogged = () => {
 
7
  return (
8
  <section className="relative max-w-[86rem] mx-auto">
9
  <header className="container mx-auto pt-20 px-6 relative flex flex-col items-center justify-center text-center">
hooks/useAi.ts CHANGED
@@ -111,27 +111,36 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
111
  client.setQueryData(["ai.model"], newModel);
112
  };
113
 
114
- const createNewProject = async (prompt: string, htmlPages: Page[], projectName: string | undefined) => {
115
- const response = await api.post("/me/projects", {
116
- title: projectName,
117
- pages: htmlPages,
118
- prompt,
119
- });
120
- if (response.data.ok) {
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  setIsAiWorking(false);
122
- // Reset live preview when project is created
123
  if (livePreviewRef?.current) {
124
  livePreviewRef.current.reset();
125
  }
126
- router.replace(`/projects/${response.data.space.project.space_id}`);
127
- setProject(response.data.space);
128
- setProjects([...projects, response.data.space]);
129
  toast.success("AI responded successfully");
130
  if (audio.current) audio.current.play();
131
  }
132
  }
133
 
134
- const callAiNewProject = async (prompt: string, enhancedSettings?: EnhancedSettings, redesignMarkdown?: string, handleThink?: (think: string) => void, onFinishThink?: () => void) => {
135
  if (isAiWorking) return;
136
  if (!redesignMarkdown && !prompt.trim()) return;
137
 
@@ -160,16 +169,12 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
160
  if (request && request.body) {
161
  const reader = request.body.getReader();
162
  const decoder = new TextDecoder("utf-8");
163
- const selectedModel = MODELS.find(
164
- (m: { value: string }) => m.value === model
165
- );
166
  let contentResponse = "";
167
 
168
  const read = async (): Promise<any> => {
169
  const { done, value } = await reader.read();
170
 
171
  if (done) {
172
- // Check if the response is a JSON error message
173
  const trimmedResponse = contentResponse.trim();
174
  if (trimmedResponse.startsWith("{") && trimmedResponse.endsWith("}")) {
175
  try {
@@ -196,7 +201,7 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
196
  const projectName = contentResponse.match(/<<<<<<< PROJECT_NAME_START ([\s\S]*?) >>>>>>> PROJECT_NAME_END/)?.[1]?.trim();
197
  setPages(newPages);
198
  setLastSavedPages([...newPages]); // Mark initial pages as saved
199
- createNewProject(prompt, newPages, projectName);
200
  setPrompts([...prompts, prompt]);
201
 
202
  return { success: true, pages: newPages };
@@ -226,17 +231,6 @@ export const useAi = (onScrollToBottom?: () => void, livePreviewRef?: React.RefO
226
  // Not a complete JSON yet, continue reading
227
  }
228
  }
229
-
230
- // if (selectedModel?.isThinker) {
231
- // const thinkMatch = contentResponse.match(/<think>[\s\S]*/)?.[0];
232
- // if (thinkMatch && !contentResponse?.includes("</think>")) {
233
- // handleThink?.(thinkMatch.replace("<think>", "").trim());
234
- // }
235
- // }
236
-
237
- // if (contentResponse.includes("</think>")) {
238
- // onFinishThink?.();
239
- // }
240
 
241
  formatPages(contentResponse);
242
 
 
111
  client.setQueryData(["ai.model"], newModel);
112
  };
113
 
114
+ const createNewProject = async (prompt: string, htmlPages: Page[], projectName: string | undefined, isLoggedIn?: boolean) => {
115
+ if (isLoggedIn) {
116
+ const response = await api.post("/me/projects", {
117
+ title: projectName,
118
+ pages: htmlPages,
119
+ prompt,
120
+ });
121
+ if (response.data.ok) {
122
+ setIsAiWorking(false);
123
+ // Reset live preview when project is created
124
+ if (livePreviewRef?.current) {
125
+ livePreviewRef.current.reset();
126
+ }
127
+ router.replace(`/projects/${response.data.space.project.space_id}`);
128
+ setProject(response.data.space);
129
+ setProjects([...projects, response.data.space]);
130
+ toast.success("AI responded successfully");
131
+ if (audio.current) audio.current.play();
132
+ }
133
+ } else {
134
  setIsAiWorking(false);
 
135
  if (livePreviewRef?.current) {
136
  livePreviewRef.current.reset();
137
  }
 
 
 
138
  toast.success("AI responded successfully");
139
  if (audio.current) audio.current.play();
140
  }
141
  }
142
 
143
+ const callAiNewProject = async (prompt: string, enhancedSettings?: EnhancedSettings, redesignMarkdown?: string, isLoggedIn?: boolean) => {
144
  if (isAiWorking) return;
145
  if (!redesignMarkdown && !prompt.trim()) return;
146
 
 
169
  if (request && request.body) {
170
  const reader = request.body.getReader();
171
  const decoder = new TextDecoder("utf-8");
 
 
 
172
  let contentResponse = "";
173
 
174
  const read = async (): Promise<any> => {
175
  const { done, value } = await reader.read();
176
 
177
  if (done) {
 
178
  const trimmedResponse = contentResponse.trim();
179
  if (trimmedResponse.startsWith("{") && trimmedResponse.endsWith("}")) {
180
  try {
 
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 };
 
231
  // Not a complete JSON yet, continue reading
232
  }
233
  }
 
 
 
 
 
 
 
 
 
 
 
234
 
235
  formatPages(contentResponse);
236
 
hooks/useEditor.ts CHANGED
@@ -1,6 +1,6 @@
1
  import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
2
  import { useMemo } from "react";
3
- import { useUpdateEffect } from "react-use";
4
  import { toast } from "sonner";
5
  import { useRouter } from "next/navigation";
6
 
@@ -12,7 +12,6 @@ import { isTheSameHtml } from "@/lib/compare-html-diff";
12
  export const useEditor = (namespace?: string, repoId?: string) => {
13
  const client = useQueryClient();
14
  const router = useRouter();
15
- // const [pagesStorage,, removePagesStorage] = useLocalStorage<Page[]>("pages");
16
 
17
  const { data: project, isFetching: isLoadingProject } = useQuery({
18
  queryKey: ["editor.project"],
 
1
  import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
2
  import { useMemo } from "react";
3
+ import { useLocalStorage, useMount, useUpdateEffect } from "react-use";
4
  import { toast } from "sonner";
5
  import { useRouter } from "next/navigation";
6
 
 
12
  export const useEditor = (namespace?: string, repoId?: string) => {
13
  const client = useQueryClient();
14
  const router = useRouter();
 
15
 
16
  const { data: project, isFetching: isLoadingProject } = useQuery({
17
  queryKey: ["editor.project"],
lib/prompts.ts CHANGED
@@ -1,7 +1,7 @@
1
  export const SEARCH_START = "<<<<<<< SEARCH";
2
  export const DIVIDER = "=======";
3
  export const REPLACE_END = ">>>>>>> REPLACE";
4
- export const MAX_REQUESTS_PER_IP = 2;
5
  export const TITLE_PAGE_START = "<<<<<<< START_TITLE ";
6
  export const TITLE_PAGE_END = " >>>>>>> END_TITLE";
7
  export const NEW_PAGE_START = "<<<<<<< NEW_PAGE_START ";
 
1
  export const SEARCH_START = "<<<<<<< SEARCH";
2
  export const DIVIDER = "=======";
3
  export const REPLACE_END = ">>>>>>> REPLACE";
4
+ export const MAX_REQUESTS_PER_IP = 4;
5
  export const TITLE_PAGE_START = "<<<<<<< START_TITLE ";
6
  export const TITLE_PAGE_END = " >>>>>>> END_TITLE";
7
  export const NEW_PAGE_START = "<<<<<<< NEW_PAGE_START ";