import { useMemo, useState } from "react"; import classNames from "classnames"; import { ArrowUp, CircleStop, Pause, Plus, Square, StopCircle, } from "lucide-react"; import { useLocalStorage } from "react-use"; import { toast } from "sonner"; import { useAi } from "@/hooks/useAi"; import { useEditor } from "@/hooks/useEditor"; import { isTheSameHtml } from "@/lib/compare-html-diff"; import { EnhancedSettings, Project } from "@/types"; import { SelectedFiles } from "@/components/editor/ask-ai/selected-files"; import { SelectedHtmlElement } from "@/components/editor/ask-ai/selected-html-element"; import { AiLoading } from "@/components/editor/ask-ai/loading"; import { Button } from "@/components/ui/button"; import { Uploader } from "@/components/editor/ask-ai/uploader"; import { ReImagine } from "@/components/editor/ask-ai/re-imagine"; import { Selector } from "@/components/editor/ask-ai/selector"; import { PromptBuilder } from "@/components/editor/ask-ai/prompt-builder"; import { useUser } from "@/hooks/useUser"; import { useLoginModal } from "@/components/contexts/login-context"; import { Settings } from "./settings"; import { useProModal } from "@/components/contexts/pro-context"; import { MODELS } from "@/lib/providers"; import { MAX_FREE_PROJECTS } from "@/lib/utils"; export const AskAi = ({ project, isNew, onScrollToBottom, }: { project?: Project; files?: string[]; isNew?: boolean; onScrollToBottom?: () => void; }) => { const { user, projects } = useUser(); const { currentPageData, isUploading, pages, isLoadingProject } = useEditor(); const { isAiWorking, isThinking, selectedFiles, setSelectedFiles, selectedElement, setSelectedElement, setIsThinking, callAiNewProject, callAiFollowUp, setModel, selectedModel, audio: hookAudio, cancelRequest, } = useAi(onScrollToBottom); const { openLoginModal } = useLoginModal(); const { openProModal } = useProModal(); const [openProvider, setOpenProvider] = useState(false); const [providerError, setProviderError] = useState(""); const [enhancedSettings, setEnhancedSettings, removeEnhancedSettings] = useLocalStorage("deepsite-enhancedSettings", { isActive: true, primaryColor: undefined, secondaryColor: undefined, theme: undefined, }); const [isFollowUp, setIsFollowUp] = useState(true); const [prompt, setPrompt] = useState(""); const [think, setThink] = useState(""); const [openThink, setOpenThink] = useState(false); const isSameHtml = useMemo(() => { return isTheSameHtml(currentPageData.html); }, [currentPageData.html]); const handleThink = (think: string) => { setThink(think); setIsThinking(true); setOpenThink(true); }; const callAi = async (redesignMarkdown?: string) => { if (!user) return openLoginModal(); if (!user.isPro && projects.length >= MAX_FREE_PROJECTS) return openProModal([]); if (isAiWorking) return; if (!redesignMarkdown && !prompt.trim()) return; if (isFollowUp && !redesignMarkdown && !isSameHtml) { const result = await callAiFollowUp(prompt, enhancedSettings); if (result?.error) { handleError(result.error, result.message); return; } if (result?.success) { setPrompt(""); } } else { const result = await callAiNewProject( prompt, enhancedSettings, redesignMarkdown, handleThink, () => { setIsThinking(false); } ); if (result?.error) { handleError(result.error, result.message); return; } if (result?.success) { setPrompt(""); if (selectedModel?.isThinker) { setModel(MODELS[0].value); } } } }; const handleError = (error: string, message?: string) => { switch (error) { case "login_required": openLoginModal(); break; case "provider_required": setOpenProvider(true); setProviderError(message || ""); break; case "pro_required": openProModal([]); break; case "api_error": toast.error(message || "An error occurred"); break; case "network_error": toast.error(message || "Network error occurred"); break; default: toast.error("An unexpected error occurred"); } }; return (
setSelectedFiles(selectedFiles.filter((f) => f !== file)) } /> {selectedElement && (
setSelectedElement(null)} />
)}
{(isAiWorking || isUploading || isThinking) && (
{isAiWorking && ( )}
)}