返回 presentation-ai
page.tsx
根目录 / src / app / presentation / create / page.tsx
1 "use client";
2 import { createEmptyPresentation } from "@/app/_actions/notebook/presentation/presentationActions";
3 import { ThemeBackground } from "@/components/notebook/presentation/components/theme/ThemeBackground";
4 import { Spinner } from "@/components/ui/spinner";
5 import { usePresentationState } from "@/states/presentation-state";
6 import { useTheme } from "next-themes";
7 import { useRouter, useSearchParams } from "next/navigation";
8 import { useEffect, useRef } from "react";
9 import { toast } from "sonner";
10
11 function getSlideCount(value: string | null): number {
12 const parsed = Number(value);
13 if (!Number.isFinite(parsed)) {
14 return 5;
15 }
16
17 return Math.max(1, Math.floor(parsed));
18 }
19
20 export default function Page() {
21 const router = useRouter();
22 const { resolvedTheme } = useTheme();
23 const params = useSearchParams();
24 const handledRequestRef = useRef<string | null>(null);
25 const themeMode = resolvedTheme === "dark" ? "dark" : "light";
26 const createTheme = resolvedTheme === "dark" ? "ebony" : "mystique";
27 const prompt = params.get("prompt")?.trim() ?? "";
28 const language = params.get("language") ?? "en-US";
29 const noOfSlides = getSlideCount(params.get("noOfSlides"));
30 const webSearchEnabled = params.get("webSearch") === "true";
31 const {
32 setPresentationInput,
33 setLanguage: setPresentationLanguage,
34 setNumSlides,
35 setCurrentPresentation,
36 setIsGeneratingOutline,
37 startOutlineGeneration,
38 setWebSearchEnabled,
39 setTheme: setPresentationTheme,
40 } = usePresentationState();
41
42 // Direct generation function
43 const handleDirectGeneration = async (promptText: string, lang: string) => {
44 try {
45 setIsGeneratingOutline(true);
46 setPresentationTheme(createTheme);
47
48 // Create empty presentation
49 const result = await createEmptyPresentation({
50 title: promptText.substring(0, 50) || "Untitled Presentation",
51 theme: createTheme,
52 language: lang,
53 });
54
55 if (result.success && result.presentation) {
56 // Set the current presentation
57 setCurrentPresentation(
58 result.presentation.id,
59 result.presentation.title,
60 );
61
62 // Navigate to the generate page
63 startOutlineGeneration();
64 router.replace(`/presentation/generate/${result.presentation.id}`);
65 } else {
66 setIsGeneratingOutline(false);
67 toast.error(result.message || "Failed to create presentation");
68 router.push("/presentation");
69 }
70 } catch (error) {
71 setIsGeneratingOutline(false);
72 console.error("Error creating presentation:", error);
73 toast.error("Failed to create presentation");
74 router.push("/presentation");
75 }
76 };
77
78 // Check for generation data and handle accordingly
79 useEffect(() => {
80 const presentationState = usePresentationState.getState();
81 const queryRequest = {
82 language,
83 modelId: presentationState.modelId,
84 modelProvider: presentationState.modelProvider,
85 numSlides: noOfSlides,
86 prompt,
87 webSearchEnabled,
88 };
89 const request =
90 queryRequest.prompt.length > 0
91 ? queryRequest
92 : presentationState.consumePendingCreateRequest();
93
94 if (!request || !request.prompt) {
95 presentationState.setPendingCreateRequest(null);
96 router.replace("/presentation");
97 return;
98 }
99
100 const requestKey = `${request.language}:${request.modelProvider}:${request.modelId}:${request.numSlides}:${request.webSearchEnabled}:${request.prompt}`;
101 if (handledRequestRef.current === requestKey) {
102 return;
103 }
104
105 handledRequestRef.current = requestKey;
106
107 setPresentationInput(request.prompt);
108 setPresentationLanguage(request.language);
109 setNumSlides(request.numSlides);
110 setWebSearchEnabled(request.webSearchEnabled);
111 presentationState.setModelProvider(request.modelProvider);
112 presentationState.setModelId(request.modelId);
113
114 void handleDirectGeneration(request.prompt, request.language);
115 }, [
116 language,
117 noOfSlides,
118 prompt,
119 setIsGeneratingOutline,
120 setNumSlides,
121 setPresentationInput,
122 setPresentationLanguage,
123 setWebSearchEnabled,
124 webSearchEnabled,
125 ]);
126
127 if (handledRequestRef.current || prompt) {
128 return (
129 <ThemeBackground
130 themeOverride={createTheme}
131 themeModeOverride={themeMode}
132 >
133 <div className="flex h-[calc(100vh-8rem)] flex-col items-center justify-center">
134 <div className="relative">
135 <Spinner className="h-10 w-10 text-primary" />
136 </div>
137 <div className="space-y-2 text-center">
138 <h2 className="text-2xl font-bold">Loading Presentation Outline</h2>
139 <p className="text-muted-foreground">Please wait a moment...</p>
140 </div>
141 </div>
142 </ThemeBackground>
143 );
144 }
145
146 return (
147 <div className="grid h-full w-full place-items-center bg-background">
148 <div className="flex flex-col items-center justify-center space-y-4">
149 <Spinner size={32} />
150 </div>
151 </div>
152 );
153 }
154
154 lines Plain Text