Reubencf commited on
Commit
d3eb6cb
·
1 Parent(s): 011fc8d

first commit

Browse files
.claude/settings.local.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm install:*)",
5
+ "Bash(npm run build:*)"
6
+ ],
7
+ "deny": [],
8
+ "ask": []
9
+ }
10
+ }
README.md CHANGED
Binary files a/README.md and b/README.md differ
 
app/api/auth/callback/route.ts ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ export async function GET(request: NextRequest) {
4
+ const searchParams = request.nextUrl.searchParams;
5
+ const code = searchParams.get('code');
6
+ const error = searchParams.get('error');
7
+
8
+ if (error) {
9
+ // Redirect to home with error
10
+ return NextResponse.redirect(new URL('/?error=auth_failed', request.url));
11
+ }
12
+
13
+ if (!code) {
14
+ return NextResponse.redirect(new URL('/?error=no_code', request.url));
15
+ }
16
+
17
+ try {
18
+ // Exchange code for access token
19
+ const tokenResponse = await fetch('https://huggingface.co/oauth/token', {
20
+ method: 'POST',
21
+ headers: {
22
+ 'Content-Type': 'application/x-www-form-urlencoded',
23
+ },
24
+ body: new URLSearchParams({
25
+ client_id: process.env.HUGGINGFACE_CLIENT_ID!,
26
+ client_secret: process.env.HUGGINGFACE_CLIENT_SECRET!,
27
+ code,
28
+ grant_type: 'authorization_code',
29
+ redirect_uri: `${new URL(request.url).origin}/api/auth/callback`,
30
+ }),
31
+ });
32
+
33
+ if (!tokenResponse.ok) {
34
+ throw new Error('Failed to exchange code for token');
35
+ }
36
+
37
+ const tokenData = await tokenResponse.json();
38
+ const accessToken = tokenData.access_token;
39
+
40
+ // In a real app, you'd store this token securely (session, JWT, etc.)
41
+ // For this demo, we'll redirect with the token in a query parameter
42
+ // Note: This is not secure for production use
43
+ return NextResponse.redirect(
44
+ new URL(`/?token=${accessToken}&auth=success`, request.url)
45
+ );
46
+
47
+ } catch (error) {
48
+ console.error('OAuth callback error:', error);
49
+ return NextResponse.redirect(new URL('/?error=token_exchange_failed', request.url));
50
+ }
51
+ }
app/api/export-pptx/route.ts ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import pptxgen from 'pptxgenjs';
3
+
4
+ interface Slide {
5
+ id: string;
6
+ title: string;
7
+ content: string[];
8
+ notes?: string;
9
+ }
10
+
11
+ export async function POST(request: NextRequest) {
12
+ try {
13
+ const { slides }: { slides: Slide[] } = await request.json();
14
+
15
+ if (!slides || !Array.isArray(slides) || slides.length === 0) {
16
+ return NextResponse.json(
17
+ { error: 'Slides array is required' },
18
+ { status: 400 }
19
+ );
20
+ }
21
+
22
+ // Create new presentation
23
+ const pres = new pptxgen();
24
+
25
+ // Set presentation properties
26
+ pres.author = 'AI PowerPoint Generator';
27
+ pres.company = 'AI Generated';
28
+ pres.subject = 'AI Generated Presentation';
29
+ pres.title = slides[0]?.title || 'Presentation';
30
+
31
+ // Define slide layout and styling
32
+ pres.defineLayout({ name: 'LAYOUT_16x9', width: 10, height: 5.625 });
33
+ pres.layout = 'LAYOUT_16x9';
34
+
35
+ // Process each slide
36
+ slides.forEach((slideData, index) => {
37
+ const slide = pres.addSlide();
38
+
39
+ // Add title
40
+ slide.addText(slideData.title, {
41
+ x: 0.5,
42
+ y: 0.5,
43
+ w: 9,
44
+ h: 1,
45
+ fontSize: 32,
46
+ bold: true,
47
+ color: '363636',
48
+ align: 'center',
49
+ });
50
+
51
+ // Add content points
52
+ if (slideData.content && slideData.content.length > 0) {
53
+ const contentText = slideData.content
54
+ .map(point => `• ${point}`)
55
+ .join('\n');
56
+
57
+ slide.addText(contentText, {
58
+ x: 1,
59
+ y: 2,
60
+ w: 8,
61
+ h: 3,
62
+ fontSize: 18,
63
+ color: '363636',
64
+ lineSpacing: 32,
65
+ valign: 'top',
66
+ });
67
+ }
68
+
69
+ // Add slide number
70
+ slide.addText(`${index + 1}`, {
71
+ x: 9.2,
72
+ y: 5,
73
+ w: 0.5,
74
+ h: 0.3,
75
+ fontSize: 12,
76
+ color: '999999',
77
+ align: 'center',
78
+ });
79
+
80
+ // Add speaker notes if available
81
+ if (slideData.notes) {
82
+ slide.addNotes(slideData.notes);
83
+ }
84
+ });
85
+
86
+ // Generate the presentation
87
+ const pptxBuffer = await pres.write({ outputType: 'nodebuffer' });
88
+
89
+ // Convert to Buffer and then to ArrayBuffer for NextResponse
90
+ const buffer = Buffer.from(pptxBuffer as Uint8Array);
91
+ const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
92
+
93
+ // Return the file as a response
94
+ return new NextResponse(arrayBuffer, {
95
+ status: 200,
96
+ headers: {
97
+ 'Content-Type': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
98
+ 'Content-Disposition': 'attachment; filename="presentation.pptx"',
99
+ },
100
+ });
101
+
102
+ } catch (error) {
103
+ console.error('Export error:', error);
104
+ return NextResponse.json(
105
+ { error: 'Failed to export presentation' },
106
+ { status: 500 }
107
+ );
108
+ }
109
+ }
app/api/generate-slides/route.ts ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HfInference } from '@huggingface/inference';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+
4
+ interface Slide {
5
+ id: string;
6
+ title: string;
7
+ content: string[];
8
+ notes?: string;
9
+ }
10
+
11
+ export async function POST(request: NextRequest) {
12
+ try {
13
+ const { prompt, model, authMethod } = await request.json();
14
+
15
+ if (!prompt || !model) {
16
+ return NextResponse.json(
17
+ { error: 'Prompt and model are required' },
18
+ { status: 400 }
19
+ );
20
+ }
21
+
22
+ // Get API token based on auth method
23
+ let apiToken: string | undefined;
24
+
25
+ if (authMethod === 'api-key') {
26
+ const authHeader = request.headers.get('authorization');
27
+ if (authHeader?.startsWith('Bearer ')) {
28
+ apiToken = authHeader.slice(7);
29
+ } else {
30
+ return NextResponse.json(
31
+ { error: 'API token required for API key authentication' },
32
+ { status: 401 }
33
+ );
34
+ }
35
+ } else {
36
+ // For OAuth, we'd normally get the token from session
37
+ // For demo purposes, we'll require API key
38
+ return NextResponse.json(
39
+ { error: 'Please use API key authentication for this demo' },
40
+ { status: 401 }
41
+ );
42
+ }
43
+
44
+ // Initialize Hugging Face client
45
+ const hf = new HfInference(apiToken);
46
+
47
+ // Create a structured prompt for slide generation
48
+ const slideGenerationPrompt = `Create a professional PowerPoint presentation based on the following topic: "${prompt}"
49
+
50
+ Please format your response as a JSON array where each object represents a slide with this structure:
51
+ {
52
+ "title": "Slide title",
53
+ "content": ["bullet point 1", "bullet point 2", "bullet point 3"],
54
+ "notes": "Optional speaker notes"
55
+ }
56
+
57
+ Guidelines:
58
+ - Create 5-8 slides
59
+ - First slide should be a title slide
60
+ - Each content slide should have 3-5 bullet points
61
+ - Keep bullet points concise and informative
62
+ - Include a conclusion slide
63
+ - Add relevant speaker notes where helpful
64
+
65
+ Topic: ${prompt}
66
+
67
+ JSON Response:`;
68
+
69
+ try {
70
+ // Try text generation with the specified model
71
+ console.log(`Attempting to use model: ${model}`);
72
+ const response = await hf.textGeneration({
73
+ model,
74
+ inputs: slideGenerationPrompt,
75
+ parameters: {
76
+ max_new_tokens: 2000,
77
+ temperature: 0.7,
78
+ do_sample: true,
79
+ },
80
+ });
81
+
82
+ const generatedText = response.generated_text;
83
+
84
+ // Try to extract JSON from the response
85
+ let slides: Slide[] = [];
86
+
87
+ try {
88
+ // Find JSON array in the response
89
+ const jsonMatch = generatedText.match(/\[[\s\S]*\]/);
90
+ if (jsonMatch) {
91
+ const parsedSlides = JSON.parse(jsonMatch[0]);
92
+ slides = parsedSlides.map((slide: { title?: string; content?: string | string[]; notes?: string }, index: number) => ({
93
+ id: `slide-${index + 1}`,
94
+ title: slide.title || `Slide ${index + 1}`,
95
+ content: Array.isArray(slide.content) ? slide.content : [slide.content || 'Content'],
96
+ notes: slide.notes || '',
97
+ }));
98
+ } else {
99
+ throw new Error('No JSON found in response');
100
+ }
101
+ } catch {
102
+ // Fallback: Parse the text manually and create slides
103
+ slides = parseTextToSlides(generatedText, prompt);
104
+ }
105
+
106
+ if (slides.length === 0) {
107
+ slides = createFallbackSlides(prompt);
108
+ }
109
+
110
+ return NextResponse.json({ slides });
111
+
112
+ } catch (modelError) {
113
+ console.error('Model error:', modelError);
114
+
115
+ // Fallback to default slides if model fails
116
+ const slides = createFallbackSlides(prompt);
117
+ return NextResponse.json({
118
+ slides,
119
+ warning: 'Used fallback content generation due to model limitations'
120
+ });
121
+ }
122
+
123
+ } catch (error) {
124
+ console.error('API error:', error);
125
+ return NextResponse.json(
126
+ { error: 'Failed to generate slides' },
127
+ { status: 500 }
128
+ );
129
+ }
130
+ }
131
+
132
+ function parseTextToSlides(text: string, prompt: string): Slide[] {
133
+ const lines = text.split('\n').filter(line => line.trim());
134
+ const slides: Slide[] = [];
135
+
136
+ let currentSlide: Partial<Slide> = {};
137
+ let slideIndex = 1;
138
+
139
+ for (const line of lines) {
140
+ const trimmedLine = line.trim();
141
+
142
+ if (trimmedLine.startsWith('#') || trimmedLine.includes('Slide') || trimmedLine.includes('SLIDE')) {
143
+ // New slide detected
144
+ if (currentSlide.title) {
145
+ slides.push({
146
+ id: `slide-${slideIndex}`,
147
+ title: currentSlide.title,
148
+ content: currentSlide.content || ['Content'],
149
+ notes: currentSlide.notes || '',
150
+ });
151
+ slideIndex++;
152
+ }
153
+
154
+ currentSlide = {
155
+ title: trimmedLine.replace(/^#+\s*/, '').replace(/slide\s*\d*:?\s*/i, ''),
156
+ content: [],
157
+ };
158
+ } else if (trimmedLine.startsWith('-') || trimmedLine.startsWith('•') || trimmedLine.startsWith('*')) {
159
+ // Bullet point
160
+ if (!currentSlide.content) currentSlide.content = [];
161
+ currentSlide.content.push(trimmedLine.replace(/^[-•*]\s*/, ''));
162
+ }
163
+ }
164
+
165
+ // Add the last slide
166
+ if (currentSlide.title) {
167
+ slides.push({
168
+ id: `slide-${slideIndex}`,
169
+ title: currentSlide.title,
170
+ content: currentSlide.content || ['Content'],
171
+ notes: currentSlide.notes || '',
172
+ });
173
+ }
174
+
175
+ if (slides.length === 0) {
176
+ return createFallbackSlides(prompt);
177
+ }
178
+
179
+ return slides;
180
+ }
181
+
182
+ function createFallbackSlides(prompt: string): Slide[] {
183
+ return [
184
+ {
185
+ id: 'slide-1',
186
+ title: prompt,
187
+ content: ['Welcome to this presentation', 'Overview of key topics', 'Let\'s get started'],
188
+ notes: 'Introduction slide to set the context',
189
+ },
190
+ {
191
+ id: 'slide-2',
192
+ title: 'Main Points',
193
+ content: [
194
+ 'Key concept 1 related to the topic',
195
+ 'Important aspect 2 to consider',
196
+ 'Critical factor 3 for understanding',
197
+ 'Additional insight 4',
198
+ ],
199
+ notes: 'Elaborate on each main point with examples',
200
+ },
201
+ {
202
+ id: 'slide-3',
203
+ title: 'Benefits & Advantages',
204
+ content: [
205
+ 'Primary benefit of this approach',
206
+ 'Secondary advantage to consider',
207
+ 'Long-term positive impacts',
208
+ ],
209
+ notes: 'Highlight the positive aspects and value proposition',
210
+ },
211
+ {
212
+ id: 'slide-4',
213
+ title: 'Implementation',
214
+ content: [
215
+ 'Step 1: Initial setup and planning',
216
+ 'Step 2: Core implementation phase',
217
+ 'Step 3: Testing and validation',
218
+ 'Step 4: Deployment and monitoring',
219
+ ],
220
+ notes: 'Provide actionable steps for implementation',
221
+ },
222
+ {
223
+ id: 'slide-5',
224
+ title: 'Conclusion',
225
+ content: [
226
+ 'Summary of key takeaways',
227
+ 'Next steps and recommendations',
228
+ 'Thank you for your attention',
229
+ ],
230
+ notes: 'Wrap up with clear action items and call to action',
231
+ },
232
+ ];
233
+ }
app/globals.css CHANGED
@@ -24,3 +24,18 @@ body {
24
  color: var(--foreground);
25
  font-family: Arial, Helvetica, sans-serif;
26
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  color: var(--foreground);
25
  font-family: Arial, Helvetica, sans-serif;
26
  }
27
+
28
+ /* Utility classes for text truncation */
29
+ .line-clamp-2 {
30
+ display: -webkit-box;
31
+ -webkit-line-clamp: 2;
32
+ -webkit-box-orient: vertical;
33
+ overflow: hidden;
34
+ }
35
+
36
+ .line-clamp-3 {
37
+ display: -webkit-box;
38
+ -webkit-line-clamp: 3;
39
+ -webkit-box-orient: vertical;
40
+ overflow: hidden;
41
+ }
app/layout.tsx CHANGED
@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
13
  });
14
 
15
  export const metadata: Metadata = {
16
- title: "Create Next App",
17
- description: "Generated by create next app",
18
  };
19
 
20
  export default function RootLayout({
 
13
  });
14
 
15
  export const metadata: Metadata = {
16
+ title: "AI PowerPoint Generator",
17
+ description: "Generate PowerPoint presentations using AI with Hugging Face models",
18
  };
19
 
20
  export default function RootLayout({
app/page.tsx CHANGED
@@ -1,103 +1,34 @@
1
- import Image from "next/image";
 
 
 
 
2
 
3
  export default function Home() {
 
 
 
4
  return (
5
- <div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
6
- <main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
7
- <Image
8
- className="dark:invert"
9
- src="/next.svg"
10
- alt="Next.js logo"
11
- width={180}
12
- height={38}
13
- priority
14
- />
15
- <ol className="font-mono list-inside list-decimal text-sm/6 text-center sm:text-left">
16
- <li className="mb-2 tracking-[-.01em]">
17
- Get started by editing{" "}
18
- <code className="bg-black/[.05] dark:bg-white/[.06] font-mono font-semibold px-1 py-0.5 rounded">
19
- app/page.tsx
20
- </code>
21
- .
22
- </li>
23
- <li className="tracking-[-.01em]">
24
- Save and see your changes instantly.
25
- </li>
26
- </ol>
27
 
28
- <div className="flex gap-4 items-center flex-col sm:flex-row">
29
- <a
30
- className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
31
- href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
32
- target="_blank"
33
- rel="noopener noreferrer"
34
- >
35
- <Image
36
- className="dark:invert"
37
- src="/vercel.svg"
38
- alt="Vercel logomark"
39
- width={20}
40
- height={20}
41
- />
42
- Deploy now
43
- </a>
44
- <a
45
- className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
46
- href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
47
- target="_blank"
48
- rel="noopener noreferrer"
49
- >
50
- Read our docs
51
- </a>
52
- </div>
53
- </main>
54
- <footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
55
- <a
56
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
57
- href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
58
- target="_blank"
59
- rel="noopener noreferrer"
60
- >
61
- <Image
62
- aria-hidden
63
- src="/file.svg"
64
- alt="File icon"
65
- width={16}
66
- height={16}
67
- />
68
- Learn
69
- </a>
70
- <a
71
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
72
- href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
73
- target="_blank"
74
- rel="noopener noreferrer"
75
- >
76
- <Image
77
- aria-hidden
78
- src="/window.svg"
79
- alt="Window icon"
80
- width={16}
81
- height={16}
82
- />
83
- Examples
84
- </a>
85
- <a
86
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
87
- href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
88
- target="_blank"
89
- rel="noopener noreferrer"
90
- >
91
- <Image
92
- aria-hidden
93
- src="/globe.svg"
94
- alt="Globe icon"
95
- width={16}
96
- height={16}
97
  />
98
- Go to nextjs.org →
99
- </a>
100
- </footer>
 
101
  </div>
102
  );
103
- }
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { PresentationGenerator } from '@/components/PresentationGenerator';
5
+ import { AuthProvider } from '@/components/AuthProvider';
6
 
7
  export default function Home() {
8
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
9
+ const [authMethod, setAuthMethod] = useState<'huggingface' | 'api-key' | null>(null);
10
+
11
  return (
12
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-4">
13
+ <div className="max-w-6xl mx-auto">
14
+ <header className="text-center py-8">
15
+ <h1 className="text-4xl font-bold text-gray-800 mb-2">
16
+ AI PowerPoint Generator
17
+ </h1>
18
+ <p className="text-lg text-gray-600">
19
+ Create stunning presentations with AI-powered content generation
20
+ </p>
21
+ </header>
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ {!isAuthenticated ? (
24
+ <AuthProvider
25
+ onAuthSuccess={() => setIsAuthenticated(true)}
26
+ onAuthMethodSelect={setAuthMethod}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  />
28
+ ) : (
29
+ <PresentationGenerator authMethod={authMethod} />
30
+ )}
31
+ </div>
32
  </div>
33
  );
34
+ }
components/AuthProvider.tsx ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Key, ExternalLink } from 'lucide-react';
5
+
6
+ interface AuthProviderProps {
7
+ onAuthSuccess: () => void;
8
+ onAuthMethodSelect: (method: 'huggingface' | 'api-key') => void;
9
+ }
10
+
11
+ export function AuthProvider({ onAuthSuccess, onAuthMethodSelect }: AuthProviderProps) {
12
+ // const [selectedMethod, setSelectedMethod] = useState<'huggingface' | 'api-key' | null>(null);
13
+ const [apiKey, setApiKey] = useState('');
14
+ const [isLoading, setIsLoading] = useState(false);
15
+
16
+ const handleHuggingFaceAuth = async () => {
17
+ setIsLoading(true);
18
+ try {
19
+ // Redirect to Hugging Face OAuth
20
+ const clientId = process.env.NEXT_PUBLIC_HUGGINGFACE_CLIENT_ID;
21
+ const redirectUri = encodeURIComponent(window.location.origin + '/auth/callback');
22
+ const scope = encodeURIComponent('read-repos inference');
23
+
24
+ if (!clientId) {
25
+ alert('Hugging Face client ID not configured. Please use API key method.');
26
+ setIsLoading(false);
27
+ return;
28
+ }
29
+
30
+ const authUrl = `https://huggingface.co/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code`;
31
+ window.location.href = authUrl;
32
+ } catch (error) {
33
+ console.error('HF Auth error:', error);
34
+ setIsLoading(false);
35
+ }
36
+ };
37
+
38
+ const handleApiKeyAuth = () => {
39
+ if (!apiKey.trim()) {
40
+ alert('Please enter a valid API key');
41
+ return;
42
+ }
43
+
44
+ // Store API key in localStorage for demo purposes
45
+ localStorage.setItem('hf_api_key', apiKey);
46
+ onAuthMethodSelect('api-key');
47
+ onAuthSuccess();
48
+ };
49
+
50
+ return (
51
+ <div className="max-w-md mx-auto bg-white rounded-lg shadow-lg p-6">
52
+ <h2 className="text-2xl font-bold text-center mb-6 text-gray-800">
53
+ Choose Authentication Method
54
+ </h2>
55
+
56
+ <div className="space-y-4">
57
+ {/* Hugging Face OAuth Option */}
58
+ <div className="border-2 border-orange-200 rounded-lg p-4 hover:border-orange-300 transition-colors">
59
+ <div className="flex items-center justify-between mb-3">
60
+ <h3 className="font-semibold text-lg text-gray-800">Hugging Face Login</h3>
61
+ <ExternalLink className="w-5 h-5 text-orange-500" />
62
+ </div>
63
+ <p className="text-gray-600 text-sm mb-4">
64
+ Sign in with your Hugging Face account to access all available models
65
+ </p>
66
+ <button
67
+ onClick={handleHuggingFaceAuth}
68
+ disabled={isLoading}
69
+ className="w-full bg-orange-500 hover:bg-orange-600 text-white font-medium py-2 px-4 rounded-md transition-colors disabled:opacity-50"
70
+ >
71
+ {isLoading ? 'Redirecting...' : 'Sign in with Hugging Face'}
72
+ </button>
73
+ </div>
74
+
75
+ {/* API Key Option */}
76
+ <div className="border-2 border-blue-200 rounded-lg p-4 hover:border-blue-300 transition-colors">
77
+ <div className="flex items-center justify-between mb-3">
78
+ <h3 className="font-semibold text-lg text-gray-800">API Key</h3>
79
+ <Key className="w-5 h-5 text-blue-500" />
80
+ </div>
81
+ <p className="text-gray-600 text-sm mb-4">
82
+ Use your personal Hugging Face API token for access
83
+ </p>
84
+ <div className="space-y-3">
85
+ <input
86
+ type="password"
87
+ placeholder="Enter your Hugging Face API token..."
88
+ value={apiKey}
89
+ onChange={(e) => setApiKey(e.target.value)}
90
+ className="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
91
+ />
92
+ <button
93
+ onClick={handleApiKeyAuth}
94
+ className="w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded-md transition-colors"
95
+ >
96
+ Continue with API Key
97
+ </button>
98
+ </div>
99
+ </div>
100
+ </div>
101
+
102
+ <div className="mt-6 text-center">
103
+ <p className="text-xs text-gray-500">
104
+ Need an API key?{' '}
105
+ <a
106
+ href="https://huggingface.co/settings/tokens"
107
+ target="_blank"
108
+ rel="noopener noreferrer"
109
+ className="text-blue-500 hover:underline"
110
+ >
111
+ Get one here
112
+ </a>
113
+ </p>
114
+ </div>
115
+ </div>
116
+ );
117
+ }
components/ModelSelector.tsx ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { ChevronDown, Plus } from 'lucide-react';
5
+
6
+ interface ModelSelectorProps {
7
+ selectedModel: string;
8
+ customModel: string;
9
+ onModelSelect: (model: string) => void;
10
+ onCustomModelChange: (model: string) => void;
11
+ }
12
+
13
+ const POPULAR_MODELS = [
14
+ {
15
+ id: 'microsoft/DialoGPT-large',
16
+ name: 'DialoGPT Large',
17
+ description: 'Conversational AI model for generating natural dialogue',
18
+ },
19
+ {
20
+ id: 'google/flan-t5-large',
21
+ name: 'FLAN-T5 Large',
22
+ description: 'Instruction-tuned model good for structured content',
23
+ },
24
+ {
25
+ id: 'meta-llama/Llama-2-7b-chat-hf',
26
+ name: 'Llama 2 7B Chat',
27
+ description: 'Meta\'s conversational AI model',
28
+ },
29
+ {
30
+ id: 'mistralai/Mistral-7B-Instruct-v0.1',
31
+ name: 'Mistral 7B Instruct',
32
+ description: 'Efficient instruction-following model',
33
+ },
34
+ {
35
+ id: 'HuggingFaceH4/zephyr-7b-beta',
36
+ name: 'Zephyr 7B Beta',
37
+ description: 'Fine-tuned assistant model',
38
+ },
39
+ ];
40
+
41
+ export function ModelSelector({
42
+ selectedModel,
43
+ customModel,
44
+ onModelSelect,
45
+ onCustomModelChange,
46
+ }: ModelSelectorProps) {
47
+ const [showCustomInput, setShowCustomInput] = useState(false);
48
+ const [isOpen, setIsOpen] = useState(false);
49
+
50
+ const handleModelSelect = (modelId: string) => {
51
+ onModelSelect(modelId);
52
+ onCustomModelChange('');
53
+ setShowCustomInput(false);
54
+ setIsOpen(false);
55
+ };
56
+
57
+ const handleCustomModelSubmit = () => {
58
+ if (customModel.trim()) {
59
+ setShowCustomInput(false);
60
+ setIsOpen(false);
61
+ }
62
+ };
63
+
64
+ const displayValue = customModel ||
65
+ POPULAR_MODELS.find(m => m.id === selectedModel)?.name ||
66
+ selectedModel;
67
+
68
+ return (
69
+ <div className="relative">
70
+ <label className="block text-sm font-medium text-gray-700 mb-2">
71
+ AI Model
72
+ </label>
73
+
74
+ <div className="relative">
75
+ <button
76
+ onClick={() => setIsOpen(!isOpen)}
77
+ className="w-full bg-white border border-gray-300 rounded-md px-3 py-2 text-left focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center justify-between"
78
+ >
79
+ <span className="truncate">{displayValue}</span>
80
+ <ChevronDown className={`w-4 h-4 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
81
+ </button>
82
+
83
+ {isOpen && (
84
+ <div className="absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg max-h-64 overflow-y-auto">
85
+ {POPULAR_MODELS.map((model) => (
86
+ <button
87
+ key={model.id}
88
+ onClick={() => handleModelSelect(model.id)}
89
+ className={`w-full text-left px-3 py-2 hover:bg-gray-50 border-b border-gray-100 last:border-b-0 ${
90
+ selectedModel === model.id && !customModel ? 'bg-blue-50' : ''
91
+ }`}
92
+ >
93
+ <div className="font-medium text-sm">{model.name}</div>
94
+ <div className="text-xs text-gray-500 truncate">{model.description}</div>
95
+ <div className="text-xs text-gray-400 font-mono">{model.id}</div>
96
+ </button>
97
+ ))}
98
+
99
+ <button
100
+ onClick={() => {
101
+ setShowCustomInput(true);
102
+ setIsOpen(false);
103
+ }}
104
+ className="w-full text-left px-3 py-2 hover:bg-gray-50 border-t border-gray-200 flex items-center gap-2"
105
+ >
106
+ <Plus className="w-4 h-4" />
107
+ <span className="font-medium text-sm">Use Custom Model</span>
108
+ </button>
109
+ </div>
110
+ )}
111
+ </div>
112
+
113
+ {showCustomInput && (
114
+ <div className="mt-2 p-3 border border-blue-200 rounded-md bg-blue-50">
115
+ <label className="block text-sm font-medium text-gray-700 mb-2">
116
+ Custom Model ID
117
+ </label>
118
+ <div className="flex gap-2">
119
+ <input
120
+ type="text"
121
+ value={customModel}
122
+ onChange={(e) => onCustomModelChange(e.target.value)}
123
+ placeholder="e.g., your-username/your-model-name"
124
+ className="flex-1 border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
125
+ />
126
+ <button
127
+ onClick={handleCustomModelSubmit}
128
+ className="bg-blue-500 hover:bg-blue-600 text-white px-3 py-2 rounded-md text-sm"
129
+ >
130
+ Use
131
+ </button>
132
+ <button
133
+ onClick={() => setShowCustomInput(false)}
134
+ className="bg-gray-500 hover:bg-gray-600 text-white px-3 py-2 rounded-md text-sm"
135
+ >
136
+ Cancel
137
+ </button>
138
+ </div>
139
+ <p className="text-xs text-gray-600 mt-1">
140
+ Enter any Hugging Face model ID that supports text generation
141
+ </p>
142
+ </div>
143
+ )}
144
+ </div>
145
+ );
146
+ }
components/PresentationGenerator.tsx ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Wand2, Download, Edit, Eye } from 'lucide-react';
5
+ import { ModelSelector } from './ModelSelector';
6
+ import { SlideEditor } from './SlideEditor';
7
+ import { SlidePreview } from './SlidePreview';
8
+
9
+ interface PresentationGeneratorProps {
10
+ authMethod: 'huggingface' | 'api-key' | null;
11
+ }
12
+
13
+ export interface Slide {
14
+ id: string;
15
+ title: string;
16
+ content: string[];
17
+ notes?: string;
18
+ }
19
+
20
+ export function PresentationGenerator({ authMethod }: PresentationGeneratorProps) {
21
+ const [prompt, setPrompt] = useState('');
22
+ const [selectedModel, setSelectedModel] = useState('microsoft/DialoGPT-large');
23
+ const [customModel, setCustomModel] = useState('');
24
+ const [slides, setSlides] = useState<Slide[]>([]);
25
+ const [isGenerating, setIsGenerating] = useState(false);
26
+ const [currentView, setCurrentView] = useState<'generate' | 'edit' | 'preview'>('generate');
27
+
28
+ const generatePresentation = async () => {
29
+ if (!prompt.trim()) {
30
+ alert('Please enter a prompt for your presentation');
31
+ return;
32
+ }
33
+
34
+ setIsGenerating(true);
35
+ try {
36
+ // Get API token from localStorage if using API key method
37
+ let headers: Record<string, string> = {
38
+ 'Content-Type': 'application/json',
39
+ };
40
+
41
+ if (authMethod === 'api-key') {
42
+ const apiKey = localStorage.getItem('hf_api_key');
43
+ if (!apiKey) {
44
+ alert('API key not found. Please authenticate again.');
45
+ return;
46
+ }
47
+ headers = {
48
+ ...headers,
49
+ 'Authorization': `Bearer ${apiKey}`,
50
+ };
51
+ }
52
+
53
+ const response = await fetch('/api/generate-slides', {
54
+ method: 'POST',
55
+ headers,
56
+ body: JSON.stringify({
57
+ prompt,
58
+ model: customModel || selectedModel,
59
+ authMethod,
60
+ }),
61
+ });
62
+
63
+ if (!response.ok) {
64
+ const errorData = await response.json();
65
+ throw new Error(errorData.error || 'Failed to generate presentation');
66
+ }
67
+
68
+ const data = await response.json();
69
+ setSlides(data.slides);
70
+ setCurrentView('edit');
71
+
72
+ if (data.warning) {
73
+ alert(`Note: ${data.warning}`);
74
+ }
75
+ } catch (error) {
76
+ console.error('Generation error:', error);
77
+ alert(`Failed to generate presentation: ${error instanceof Error ? error.message : 'Unknown error'}`);
78
+ } finally {
79
+ setIsGenerating(false);
80
+ }
81
+ };
82
+
83
+ const exportToPowerPoint = async () => {
84
+ try {
85
+ const response = await fetch('/api/export-pptx', {
86
+ method: 'POST',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ },
90
+ body: JSON.stringify({ slides }),
91
+ });
92
+
93
+ if (!response.ok) {
94
+ throw new Error('Failed to export presentation');
95
+ }
96
+
97
+ const blob = await response.blob();
98
+ const url = window.URL.createObjectURL(blob);
99
+ const a = document.createElement('a');
100
+ a.style.display = 'none';
101
+ a.href = url;
102
+ a.download = 'presentation.pptx';
103
+ document.body.appendChild(a);
104
+ a.click();
105
+ window.URL.revokeObjectURL(url);
106
+ } catch (error) {
107
+ console.error('Export error:', error);
108
+ alert('Failed to export presentation. Please try again.');
109
+ }
110
+ };
111
+
112
+ if (currentView === 'edit' && slides.length > 0) {
113
+ return (
114
+ <SlideEditor
115
+ slides={slides}
116
+ onSlidesUpdate={setSlides}
117
+ onBack={() => setCurrentView('generate')}
118
+ onPreview={() => setCurrentView('preview')}
119
+ onExport={exportToPowerPoint}
120
+ />
121
+ );
122
+ }
123
+
124
+ if (currentView === 'preview' && slides.length > 0) {
125
+ return (
126
+ <SlidePreview
127
+ slides={slides}
128
+ onBack={() => setCurrentView('edit')}
129
+ onExport={exportToPowerPoint}
130
+ />
131
+ );
132
+ }
133
+
134
+ return (
135
+ <div className="max-w-4xl mx-auto bg-white rounded-lg shadow-lg p-6">
136
+ <div className="mb-6">
137
+ <h2 className="text-2xl font-bold text-gray-800 mb-4">Generate Your Presentation</h2>
138
+
139
+ <div className="space-y-4">
140
+ <div>
141
+ <label className="block text-sm font-medium text-gray-700 mb-2">
142
+ Presentation Topic
143
+ </label>
144
+ <textarea
145
+ value={prompt}
146
+ onChange={(e) => setPrompt(e.target.value)}
147
+ placeholder="Describe what you want your presentation to be about... (e.g., 'Create a 5-slide presentation about renewable energy sources including solar, wind, and hydroelectric power with benefits and challenges')"
148
+ className="w-full h-32 border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
149
+ />
150
+ </div>
151
+
152
+ <ModelSelector
153
+ selectedModel={selectedModel}
154
+ customModel={customModel}
155
+ onModelSelect={setSelectedModel}
156
+ onCustomModelChange={setCustomModel}
157
+ />
158
+
159
+ <button
160
+ onClick={generatePresentation}
161
+ disabled={isGenerating}
162
+ className="w-full bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white font-medium py-3 px-6 rounded-md transition-all duration-200 disabled:opacity-50 flex items-center justify-center gap-2"
163
+ >
164
+ <Wand2 className="w-5 h-5" />
165
+ {isGenerating ? 'Generating Presentation...' : 'Generate Presentation'}
166
+ </button>
167
+ </div>
168
+ </div>
169
+
170
+ {slides.length > 0 && (
171
+ <div className="border-t pt-6">
172
+ <div className="flex justify-between items-center mb-4">
173
+ <h3 className="text-lg font-semibold text-gray-800">
174
+ Generated Presentation ({slides.length} slides)
175
+ </h3>
176
+ <div className="flex gap-2">
177
+ <button
178
+ onClick={() => setCurrentView('edit')}
179
+ className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
180
+ >
181
+ <Edit className="w-4 h-4" />
182
+ Edit
183
+ </button>
184
+ <button
185
+ onClick={() => setCurrentView('preview')}
186
+ className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
187
+ >
188
+ <Eye className="w-4 h-4" />
189
+ Preview
190
+ </button>
191
+ <button
192
+ onClick={exportToPowerPoint}
193
+ className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
194
+ >
195
+ <Download className="w-4 h-4" />
196
+ Export
197
+ </button>
198
+ </div>
199
+ </div>
200
+
201
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
202
+ {slides.map((slide, index) => (
203
+ <div
204
+ key={slide.id}
205
+ className="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow"
206
+ >
207
+ <h4 className="font-semibold text-sm text-gray-600 mb-2">
208
+ Slide {index + 1}
209
+ </h4>
210
+ <h5 className="font-bold text-lg mb-2 line-clamp-2">{slide.title}</h5>
211
+ <div className="text-sm text-gray-600 line-clamp-3">
212
+ {slide.content.map((point, i) => (
213
+ <div key={i}>• {point}</div>
214
+ ))}
215
+ </div>
216
+ </div>
217
+ ))}
218
+ </div>
219
+ </div>
220
+ )}
221
+ </div>
222
+ );
223
+ }
components/SlideEditor.tsx ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { ArrowLeft, Eye, Download, Plus, Trash2, Type, Palette } from 'lucide-react';
5
+ import { Slide } from './PresentationGenerator';
6
+
7
+ interface SlideEditorProps {
8
+ slides: Slide[];
9
+ onSlidesUpdate: (slides: Slide[]) => void;
10
+ onBack: () => void;
11
+ onPreview: () => void;
12
+ onExport: () => void;
13
+ }
14
+
15
+ export function SlideEditor({ slides, onSlidesUpdate, onBack, onPreview, onExport }: SlideEditorProps) {
16
+ const [selectedSlideIndex, setSelectedSlideIndex] = useState(0);
17
+ const [fontSize, setFontSize] = useState('16');
18
+ const [fontFamily, setFontFamily] = useState('Arial');
19
+ const [textColor, setTextColor] = useState('#000000');
20
+
21
+ const currentSlide = slides[selectedSlideIndex];
22
+
23
+ const updateSlide = (updates: Partial<Slide>) => {
24
+ const updatedSlides = slides.map((slide, index) =>
25
+ index === selectedSlideIndex ? { ...slide, ...updates } : slide
26
+ );
27
+ onSlidesUpdate(updatedSlides);
28
+ };
29
+
30
+ const addSlide = () => {
31
+ const newSlide: Slide = {
32
+ id: `slide-${Date.now()}`,
33
+ title: 'New Slide',
34
+ content: ['Add your content here'],
35
+ notes: '',
36
+ };
37
+ const updatedSlides = [...slides, newSlide];
38
+ onSlidesUpdate(updatedSlides);
39
+ setSelectedSlideIndex(updatedSlides.length - 1);
40
+ };
41
+
42
+ const deleteSlide = (index: number) => {
43
+ if (slides.length <= 1) {
44
+ alert('Cannot delete the last slide');
45
+ return;
46
+ }
47
+
48
+ const updatedSlides = slides.filter((_, i) => i !== index);
49
+ onSlidesUpdate(updatedSlides);
50
+
51
+ if (selectedSlideIndex >= updatedSlides.length) {
52
+ setSelectedSlideIndex(updatedSlides.length - 1);
53
+ }
54
+ };
55
+
56
+ const addContentPoint = () => {
57
+ const updatedContent = [...currentSlide.content, 'New bullet point'];
58
+ updateSlide({ content: updatedContent });
59
+ };
60
+
61
+ const updateContentPoint = (index: number, value: string) => {
62
+ const updatedContent = currentSlide.content.map((point, i) =>
63
+ i === index ? value : point
64
+ );
65
+ updateSlide({ content: updatedContent });
66
+ };
67
+
68
+ const deleteContentPoint = (index: number) => {
69
+ if (currentSlide.content.length <= 1) return;
70
+
71
+ const updatedContent = currentSlide.content.filter((_, i) => i !== index);
72
+ updateSlide({ content: updatedContent });
73
+ };
74
+
75
+ return (
76
+ <div className="max-w-7xl mx-auto bg-white rounded-lg shadow-lg overflow-hidden">
77
+ {/* Header */}
78
+ <div className="bg-gray-50 px-6 py-4 border-b flex items-center justify-between">
79
+ <div className="flex items-center gap-4">
80
+ <button
81
+ onClick={onBack}
82
+ className="flex items-center gap-2 text-gray-600 hover:text-gray-800"
83
+ >
84
+ <ArrowLeft className="w-4 h-4" />
85
+ Back to Generator
86
+ </button>
87
+ <h2 className="text-xl font-bold text-gray-800">Edit Presentation</h2>
88
+ </div>
89
+
90
+ <div className="flex gap-2">
91
+ <button
92
+ onClick={onPreview}
93
+ className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
94
+ >
95
+ <Eye className="w-4 h-4" />
96
+ Preview
97
+ </button>
98
+ <button
99
+ onClick={onExport}
100
+ className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
101
+ >
102
+ <Download className="w-4 h-4" />
103
+ Export
104
+ </button>
105
+ </div>
106
+ </div>
107
+
108
+ <div className="flex h-screen">
109
+ {/* Slide Thumbnails */}
110
+ <div className="w-64 bg-gray-50 border-r overflow-y-auto">
111
+ <div className="p-4">
112
+ <div className="flex items-center justify-between mb-4">
113
+ <h3 className="font-semibold text-gray-800">Slides</h3>
114
+ <button
115
+ onClick={addSlide}
116
+ className="bg-blue-500 hover:bg-blue-600 text-white p-2 rounded-md"
117
+ >
118
+ <Plus className="w-4 h-4" />
119
+ </button>
120
+ </div>
121
+
122
+ <div className="space-y-2">
123
+ {slides.map((slide, index) => (
124
+ <div
125
+ key={slide.id}
126
+ className={`border rounded-lg p-3 cursor-pointer transition-colors ${
127
+ selectedSlideIndex === index
128
+ ? 'border-blue-500 bg-blue-50'
129
+ : 'border-gray-200 hover:border-gray-300'
130
+ }`}
131
+ onClick={() => setSelectedSlideIndex(index)}
132
+ >
133
+ <div className="flex items-center justify-between mb-2">
134
+ <span className="text-sm font-medium text-gray-600">
135
+ Slide {index + 1}
136
+ </span>
137
+ {slides.length > 1 && (
138
+ <button
139
+ onClick={(e) => {
140
+ e.stopPropagation();
141
+ deleteSlide(index);
142
+ }}
143
+ className="text-red-500 hover:text-red-700"
144
+ >
145
+ <Trash2 className="w-3 h-3" />
146
+ </button>
147
+ )}
148
+ </div>
149
+ <h4 className="text-sm font-bold line-clamp-2 mb-1">{slide.title}</h4>
150
+ <div className="text-xs text-gray-500 line-clamp-2">
151
+ {slide.content.slice(0, 2).map((point, i) => (
152
+ <div key={i}>• {point}</div>
153
+ ))}
154
+ </div>
155
+ </div>
156
+ ))}
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ {/* Main Editor */}
162
+ <div className="flex-1 flex">
163
+ {/* Content Editor */}
164
+ <div className="flex-1 p-6">
165
+ <div className="mb-6">
166
+ <label className="block text-sm font-medium text-gray-700 mb-2">
167
+ Slide Title
168
+ </label>
169
+ <input
170
+ type="text"
171
+ value={currentSlide.title}
172
+ onChange={(e) => updateSlide({ title: e.target.value })}
173
+ className="w-full border border-gray-300 rounded-md px-3 py-2 text-lg font-bold focus:outline-none focus:ring-2 focus:ring-blue-500"
174
+ />
175
+ </div>
176
+
177
+ <div className="mb-6">
178
+ <div className="flex items-center justify-between mb-2">
179
+ <label className="block text-sm font-medium text-gray-700">
180
+ Content Points
181
+ </label>
182
+ <button
183
+ onClick={addContentPoint}
184
+ className="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded-md text-sm flex items-center gap-1"
185
+ >
186
+ <Plus className="w-3 h-3" />
187
+ Add Point
188
+ </button>
189
+ </div>
190
+
191
+ <div className="space-y-3">
192
+ {currentSlide.content.map((point, index) => (
193
+ <div key={index} className="flex items-center gap-2">
194
+ <span className="text-gray-400">•</span>
195
+ <input
196
+ type="text"
197
+ value={point}
198
+ onChange={(e) => updateContentPoint(index, e.target.value)}
199
+ className="flex-1 border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
200
+ style={{
201
+ fontSize: `${fontSize}px`,
202
+ fontFamily,
203
+ color: textColor,
204
+ }}
205
+ />
206
+ {currentSlide.content.length > 1 && (
207
+ <button
208
+ onClick={() => deleteContentPoint(index)}
209
+ className="text-red-500 hover:text-red-700"
210
+ >
211
+ <Trash2 className="w-4 h-4" />
212
+ </button>
213
+ )}
214
+ </div>
215
+ ))}
216
+ </div>
217
+ </div>
218
+
219
+ <div>
220
+ <label className="block text-sm font-medium text-gray-700 mb-2">
221
+ Speaker Notes (Optional)
222
+ </label>
223
+ <textarea
224
+ value={currentSlide.notes || ''}
225
+ onChange={(e) => updateSlide({ notes: e.target.value })}
226
+ placeholder="Add speaker notes for this slide..."
227
+ className="w-full h-24 border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
228
+ />
229
+ </div>
230
+ </div>
231
+
232
+ {/* Formatting Panel */}
233
+ <div className="w-64 bg-gray-50 border-l p-4">
234
+ <h3 className="font-semibold text-gray-800 mb-4 flex items-center gap-2">
235
+ <Type className="w-4 h-4" />
236
+ Formatting
237
+ </h3>
238
+
239
+ <div className="space-y-4">
240
+ <div>
241
+ <label className="block text-sm font-medium text-gray-700 mb-2">
242
+ Font Family
243
+ </label>
244
+ <select
245
+ value={fontFamily}
246
+ onChange={(e) => setFontFamily(e.target.value)}
247
+ className="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
248
+ >
249
+ <option value="Arial">Arial</option>
250
+ <option value="Helvetica">Helvetica</option>
251
+ <option value="Times New Roman">Times New Roman</option>
252
+ <option value="Georgia">Georgia</option>
253
+ <option value="Courier New">Courier New</option>
254
+ <option value="Verdana">Verdana</option>
255
+ </select>
256
+ </div>
257
+
258
+ <div>
259
+ <label className="block text-sm font-medium text-gray-700 mb-2">
260
+ Font Size
261
+ </label>
262
+ <input
263
+ type="range"
264
+ min="12"
265
+ max="24"
266
+ value={fontSize}
267
+ onChange={(e) => setFontSize(e.target.value)}
268
+ className="w-full"
269
+ />
270
+ <div className="text-sm text-gray-600 text-center">{fontSize}px</div>
271
+ </div>
272
+
273
+ <div>
274
+ <label className="block text-sm font-medium text-gray-700 mb-2 flex items-center gap-2">
275
+ <Palette className="w-4 h-4" />
276
+ Text Color
277
+ </label>
278
+ <input
279
+ type="color"
280
+ value={textColor}
281
+ onChange={(e) => setTextColor(e.target.value)}
282
+ className="w-full h-10 border border-gray-300 rounded-md cursor-pointer"
283
+ />
284
+ </div>
285
+ </div>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ );
291
+ }
components/SlidePreview.tsx ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { ArrowLeft, ArrowRight, Download } from 'lucide-react';
5
+ import { Slide } from './PresentationGenerator';
6
+
7
+ interface SlidePreviewProps {
8
+ slides: Slide[];
9
+ onBack: () => void;
10
+ onExport: () => void;
11
+ }
12
+
13
+ export function SlidePreview({ slides, onBack, onExport }: SlidePreviewProps) {
14
+ const [currentSlideIndex, setCurrentSlideIndex] = useState(0);
15
+
16
+ const currentSlide = slides[currentSlideIndex];
17
+
18
+ const nextSlide = () => {
19
+ if (currentSlideIndex < slides.length - 1) {
20
+ setCurrentSlideIndex(currentSlideIndex + 1);
21
+ }
22
+ };
23
+
24
+ const prevSlide = () => {
25
+ if (currentSlideIndex > 0) {
26
+ setCurrentSlideIndex(currentSlideIndex - 1);
27
+ }
28
+ };
29
+
30
+ const goToSlide = (index: number) => {
31
+ setCurrentSlideIndex(index);
32
+ };
33
+
34
+ return (
35
+ <div className="max-w-7xl mx-auto bg-white rounded-lg shadow-lg overflow-hidden">
36
+ {/* Header */}
37
+ <div className="bg-gray-50 px-6 py-4 border-b flex items-center justify-between">
38
+ <div className="flex items-center gap-4">
39
+ <button
40
+ onClick={onBack}
41
+ className="flex items-center gap-2 text-gray-600 hover:text-gray-800"
42
+ >
43
+ <ArrowLeft className="w-4 h-4" />
44
+ Back to Editor
45
+ </button>
46
+ <h2 className="text-xl font-bold text-gray-800">
47
+ Preview Mode - Slide {currentSlideIndex + 1} of {slides.length}
48
+ </h2>
49
+ </div>
50
+
51
+ <div className="flex gap-2">
52
+ <button
53
+ onClick={onExport}
54
+ className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-md flex items-center gap-2"
55
+ >
56
+ <Download className="w-4 h-4" />
57
+ Export PowerPoint
58
+ </button>
59
+ </div>
60
+ </div>
61
+
62
+ <div className="flex h-screen">
63
+ {/* Slide Navigation */}
64
+ <div className="w-64 bg-gray-50 border-r overflow-y-auto">
65
+ <div className="p-4">
66
+ <h3 className="font-semibold text-gray-800 mb-4">Slides</h3>
67
+ <div className="space-y-2">
68
+ {slides.map((slide, index) => (
69
+ <button
70
+ key={slide.id}
71
+ onClick={() => goToSlide(index)}
72
+ className={`w-full text-left border rounded-lg p-3 transition-colors ${
73
+ currentSlideIndex === index
74
+ ? 'border-blue-500 bg-blue-50'
75
+ : 'border-gray-200 hover:border-gray-300'
76
+ }`}
77
+ >
78
+ <div className="text-sm font-medium text-gray-600 mb-1">
79
+ Slide {index + 1}
80
+ </div>
81
+ <h4 className="text-sm font-bold line-clamp-2">{slide.title}</h4>
82
+ </button>
83
+ ))}
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ {/* Main Slide Preview */}
89
+ <div className="flex-1 flex flex-col">
90
+ {/* Slide Content */}
91
+ <div className="flex-1 p-8 flex items-center justify-center bg-gray-100">
92
+ <div className="w-full max-w-4xl aspect-[16/9] bg-white rounded-lg shadow-lg p-12 flex flex-col">
93
+ {/* Slide Title */}
94
+ <h1 className="text-4xl font-bold text-gray-800 mb-8 text-center">
95
+ {currentSlide.title}
96
+ </h1>
97
+
98
+ {/* Slide Content */}
99
+ <div className="flex-1 flex flex-col justify-center">
100
+ <ul className="space-y-4">
101
+ {currentSlide.content.map((point, index) => (
102
+ <li
103
+ key={index}
104
+ className="text-xl text-gray-700 flex items-start gap-3"
105
+ >
106
+ <span className="text-blue-500 font-bold mt-1">•</span>
107
+ <span>{point}</span>
108
+ </li>
109
+ ))}
110
+ </ul>
111
+ </div>
112
+
113
+ {/* Slide Number */}
114
+ <div className="text-right text-sm text-gray-400 mt-4">
115
+ {currentSlideIndex + 1} / {slides.length}
116
+ </div>
117
+ </div>
118
+ </div>
119
+
120
+ {/* Navigation Controls */}
121
+ <div className="bg-white border-t px-6 py-4 flex items-center justify-between">
122
+ <button
123
+ onClick={prevSlide}
124
+ disabled={currentSlideIndex === 0}
125
+ className="flex items-center gap-2 px-4 py-2 bg-gray-500 hover:bg-gray-600 disabled:bg-gray-300 text-white rounded-md transition-colors"
126
+ >
127
+ <ArrowLeft className="w-4 h-4" />
128
+ Previous
129
+ </button>
130
+
131
+ <div className="flex items-center gap-2">
132
+ {slides.map((_, index) => (
133
+ <button
134
+ key={index}
135
+ onClick={() => goToSlide(index)}
136
+ className={`w-3 h-3 rounded-full transition-colors ${
137
+ currentSlideIndex === index ? 'bg-blue-500' : 'bg-gray-300'
138
+ }`}
139
+ />
140
+ ))}
141
+ </div>
142
+
143
+ <button
144
+ onClick={nextSlide}
145
+ disabled={currentSlideIndex === slides.length - 1}
146
+ className="flex items-center gap-2 px-4 py-2 bg-gray-500 hover:bg-gray-600 disabled:bg-gray-300 text-white rounded-md transition-colors"
147
+ >
148
+ Next
149
+ <ArrowRight className="w-4 h-4" />
150
+ </button>
151
+ </div>
152
+
153
+ {/* Speaker Notes */}
154
+ {currentSlide.notes && (
155
+ <div className="bg-yellow-50 border-t border-yellow-200 px-6 py-4">
156
+ <h4 className="font-semibold text-gray-800 mb-2">Speaker Notes:</h4>
157
+ <p className="text-gray-700">{currentSlide.notes}</p>
158
+ </div>
159
+ )}
160
+ </div>
161
+ </div>
162
+ </div>
163
+ );
164
+ }
package-lock.json CHANGED
@@ -8,7 +8,15 @@
8
  "name": "powerpoint",
9
  "version": "0.1.0",
10
  "dependencies": {
 
 
 
 
 
 
11
  "next": "15.5.3",
 
 
12
  "react": "19.1.0",
13
  "react-dom": "19.1.0"
14
  },
@@ -37,6 +45,46 @@
37
  "url": "https://github.com/sponsors/sindresorhus"
38
  }
39
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  "node_modules/@emnapi/core": {
41
  "version": "1.5.0",
42
  "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
@@ -211,6 +259,34 @@
211
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
212
  }
213
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  "node_modules/@humanfs/core": {
215
  "version": "0.19.1",
216
  "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -949,6 +1025,15 @@
949
  "node": ">=12.4.0"
950
  }
951
  },
 
 
 
 
 
 
 
 
 
952
  "node_modules/@rtsao/scc": {
953
  "version": "1.1.0",
954
  "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1259,6 +1344,12 @@
1259
  "tslib": "^2.4.0"
1260
  }
1261
  },
 
 
 
 
 
 
1262
  "node_modules/@types/estree": {
1263
  "version": "1.0.8",
1264
  "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -1290,6 +1381,19 @@
1290
  "undici-types": "~6.21.0"
1291
  }
1292
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
1293
  "node_modules/@types/react": {
1294
  "version": "19.1.13",
1295
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
@@ -1310,6 +1414,13 @@
1310
  "@types/react": "^19.0.0"
1311
  }
1312
  },
 
 
 
 
 
 
 
1313
  "node_modules/@typescript-eslint/eslint-plugin": {
1314
  "version": "8.44.0",
1315
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz",
@@ -2117,6 +2228,12 @@
2117
  "node": ">= 0.4"
2118
  }
2119
  },
 
 
 
 
 
 
2120
  "node_modules/available-typed-arrays": {
2121
  "version": "1.0.7",
2122
  "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -2143,6 +2260,17 @@
2143
  "node": ">=4"
2144
  }
2145
  },
 
 
 
 
 
 
 
 
 
 
 
2146
  "node_modules/axobject-query": {
2147
  "version": "4.1.0",
2148
  "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -2160,6 +2288,15 @@
2160
  "dev": true,
2161
  "license": "MIT"
2162
  },
 
 
 
 
 
 
 
 
 
2163
  "node_modules/brace-expansion": {
2164
  "version": "1.1.12",
2165
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -2207,7 +2344,6 @@
2207
  "version": "1.0.2",
2208
  "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
2209
  "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
2210
- "dev": true,
2211
  "license": "MIT",
2212
  "dependencies": {
2213
  "es-errors": "^1.3.0",
@@ -2264,6 +2400,26 @@
2264
  ],
2265
  "license": "CC-BY-4.0"
2266
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2267
  "node_modules/chalk": {
2268
  "version": "4.1.2",
2269
  "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2342,6 +2498,18 @@
2342
  "simple-swizzle": "^0.2.2"
2343
  }
2344
  },
 
 
 
 
 
 
 
 
 
 
 
 
2345
  "node_modules/concat-map": {
2346
  "version": "0.0.1",
2347
  "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2349,6 +2517,33 @@
2349
  "dev": true,
2350
  "license": "MIT"
2351
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2352
  "node_modules/cross-spawn": {
2353
  "version": "7.0.6",
2354
  "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2364,6 +2559,15 @@
2364
  "node": ">= 8"
2365
  }
2366
  },
 
 
 
 
 
 
 
 
 
2367
  "node_modules/csstype": {
2368
  "version": "3.1.3",
2369
  "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -2493,6 +2697,15 @@
2493
  "url": "https://github.com/sponsors/ljharb"
2494
  }
2495
  },
 
 
 
 
 
 
 
 
 
2496
  "node_modules/detect-libc": {
2497
  "version": "2.1.0",
2498
  "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
@@ -2516,11 +2729,20 @@
2516
  "node": ">=0.10.0"
2517
  }
2518
  },
 
 
 
 
 
 
 
 
 
 
2519
  "node_modules/dunder-proto": {
2520
  "version": "1.0.1",
2521
  "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
2522
  "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
2523
- "dev": true,
2524
  "license": "MIT",
2525
  "dependencies": {
2526
  "call-bind-apply-helpers": "^1.0.1",
@@ -2625,7 +2847,6 @@
2625
  "version": "1.0.1",
2626
  "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
2627
  "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
2628
- "dev": true,
2629
  "license": "MIT",
2630
  "engines": {
2631
  "node": ">= 0.4"
@@ -2635,7 +2856,6 @@
2635
  "version": "1.3.0",
2636
  "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
2637
  "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
2638
- "dev": true,
2639
  "license": "MIT",
2640
  "engines": {
2641
  "node": ">= 0.4"
@@ -2673,7 +2893,6 @@
2673
  "version": "1.1.1",
2674
  "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
2675
  "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
2676
- "dev": true,
2677
  "license": "MIT",
2678
  "dependencies": {
2679
  "es-errors": "^1.3.0"
@@ -2686,7 +2905,6 @@
2686
  "version": "2.1.0",
2687
  "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
2688
  "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
2689
- "dev": true,
2690
  "license": "MIT",
2691
  "dependencies": {
2692
  "es-errors": "^1.3.0",
@@ -3219,6 +3437,17 @@
3219
  "dev": true,
3220
  "license": "MIT"
3221
  },
 
 
 
 
 
 
 
 
 
 
 
3222
  "node_modules/fastq": {
3223
  "version": "1.19.1",
3224
  "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@@ -3229,6 +3458,12 @@
3229
  "reusify": "^1.0.4"
3230
  }
3231
  },
 
 
 
 
 
 
3232
  "node_modules/file-entry-cache": {
3233
  "version": "8.0.0",
3234
  "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3293,6 +3528,26 @@
3293
  "dev": true,
3294
  "license": "ISC"
3295
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3296
  "node_modules/for-each": {
3297
  "version": "0.3.5",
3298
  "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -3309,11 +3564,26 @@
3309
  "url": "https://github.com/sponsors/ljharb"
3310
  }
3311
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3312
  "node_modules/function-bind": {
3313
  "version": "1.1.2",
3314
  "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
3315
  "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
3316
- "dev": true,
3317
  "license": "MIT",
3318
  "funding": {
3319
  "url": "https://github.com/sponsors/ljharb"
@@ -3354,7 +3624,6 @@
3354
  "version": "1.3.0",
3355
  "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
3356
  "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
3357
- "dev": true,
3358
  "license": "MIT",
3359
  "dependencies": {
3360
  "call-bind-apply-helpers": "^1.0.2",
@@ -3379,7 +3648,6 @@
3379
  "version": "1.0.1",
3380
  "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
3381
  "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
3382
- "dev": true,
3383
  "license": "MIT",
3384
  "dependencies": {
3385
  "dunder-proto": "^1.0.1",
@@ -3467,7 +3735,6 @@
3467
  "version": "1.2.0",
3468
  "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
3469
  "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
3470
- "dev": true,
3471
  "license": "MIT",
3472
  "engines": {
3473
  "node": ">= 0.4"
@@ -3546,7 +3813,6 @@
3546
  "version": "1.1.0",
3547
  "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
3548
  "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
3549
- "dev": true,
3550
  "license": "MIT",
3551
  "engines": {
3552
  "node": ">= 0.4"
@@ -3559,7 +3825,6 @@
3559
  "version": "1.0.2",
3560
  "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
3561
  "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
3562
- "dev": true,
3563
  "license": "MIT",
3564
  "dependencies": {
3565
  "has-symbols": "^1.0.3"
@@ -3575,7 +3840,6 @@
3575
  "version": "2.0.2",
3576
  "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
3577
  "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
3578
- "dev": true,
3579
  "license": "MIT",
3580
  "dependencies": {
3581
  "function-bind": "^1.1.2"
@@ -3584,6 +3848,25 @@
3584
  "node": ">= 0.4"
3585
  }
3586
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3587
  "node_modules/ignore": {
3588
  "version": "5.3.2",
3589
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3594,6 +3877,27 @@
3594
  "node": ">= 4"
3595
  }
3596
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3597
  "node_modules/import-fresh": {
3598
  "version": "3.3.1",
3599
  "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -3621,6 +3925,12 @@
3621
  "node": ">=0.8.19"
3622
  }
3623
  },
 
 
 
 
 
 
3624
  "node_modules/internal-slot": {
3625
  "version": "1.1.0",
3626
  "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -3636,6 +3946,12 @@
3636
  "node": ">= 0.4"
3637
  }
3638
  },
 
 
 
 
 
 
3639
  "node_modules/is-array-buffer": {
3640
  "version": "3.0.5",
3641
  "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4086,6 +4402,15 @@
4086
  "jiti": "lib/jiti-cli.mjs"
4087
  }
4088
  },
 
 
 
 
 
 
 
 
 
4089
  "node_modules/js-tokens": {
4090
  "version": "4.0.0",
4091
  "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -4140,6 +4465,23 @@
4140
  "json5": "lib/cli.js"
4141
  }
4142
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4143
  "node_modules/jsx-ast-utils": {
4144
  "version": "3.3.5",
4145
  "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -4156,6 +4498,24 @@
4156
  "node": ">=4.0"
4157
  }
4158
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4159
  "node_modules/keyv": {
4160
  "version": "4.5.4",
4161
  "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -4200,6 +4560,15 @@
4200
  "node": ">= 0.8.0"
4201
  }
4202
  },
 
 
 
 
 
 
 
 
 
4203
  "node_modules/lightningcss": {
4204
  "version": "1.30.1",
4205
  "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
@@ -4475,6 +4844,33 @@
4475
  "loose-envify": "cli.js"
4476
  }
4477
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4478
  "node_modules/magic-string": {
4479
  "version": "0.30.19",
4480
  "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
@@ -4489,7 +4885,6 @@
4489
  "version": "1.1.0",
4490
  "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
4491
  "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
4492
- "dev": true,
4493
  "license": "MIT",
4494
  "engines": {
4495
  "node": ">= 0.4"
@@ -4519,6 +4914,27 @@
4519
  "node": ">=8.6"
4520
  }
4521
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4522
  "node_modules/minimatch": {
4523
  "version": "3.1.2",
4524
  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -4681,6 +5097,56 @@
4681
  }
4682
  }
4683
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4684
  "node_modules/next/node_modules/postcss": {
4685
  "version": "8.4.31",
4686
  "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -4709,6 +5175,21 @@
4709
  "node": "^10 || ^12 || >=14"
4710
  }
4711
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4712
  "node_modules/object-assign": {
4713
  "version": "4.1.1",
4714
  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4719,6 +5200,15 @@
4719
  "node": ">=0.10.0"
4720
  }
4721
  },
 
 
 
 
 
 
 
 
 
4722
  "node_modules/object-inspect": {
4723
  "version": "1.13.4",
4724
  "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@@ -4832,6 +5322,39 @@
4832
  "url": "https://github.com/sponsors/ljharb"
4833
  }
4834
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4835
  "node_modules/optionator": {
4836
  "version": "0.9.4",
4837
  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -4900,6 +5423,12 @@
4900
  "url": "https://github.com/sponsors/sindresorhus"
4901
  }
4902
  },
 
 
 
 
 
 
4903
  "node_modules/parent-module": {
4904
  "version": "1.0.1",
4905
  "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -4940,6 +5469,13 @@
4940
  "dev": true,
4941
  "license": "MIT"
4942
  },
 
 
 
 
 
 
 
4943
  "node_modules/picocolors": {
4944
  "version": "1.1.1",
4945
  "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -4998,6 +5534,49 @@
4998
  "node": "^10 || ^12 || >=14"
4999
  }
5000
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5001
  "node_modules/prelude-ls": {
5002
  "version": "1.2.1",
5003
  "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -5008,6 +5587,18 @@
5008
  "node": ">= 0.8.0"
5009
  }
5010
  },
 
 
 
 
 
 
 
 
 
 
 
 
5011
  "node_modules/prop-types": {
5012
  "version": "15.8.1",
5013
  "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5020,6 +5611,12 @@
5020
  "react-is": "^16.13.1"
5021
  }
5022
  },
 
 
 
 
 
 
5023
  "node_modules/punycode": {
5024
  "version": "2.3.1",
5025
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5030,6 +5627,15 @@
5030
  "node": ">=6"
5031
  }
5032
  },
 
 
 
 
 
 
 
 
 
5033
  "node_modules/queue-microtask": {
5034
  "version": "1.2.3",
5035
  "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5051,6 +5657,16 @@
5051
  ],
5052
  "license": "MIT"
5053
  },
 
 
 
 
 
 
 
 
 
 
5054
  "node_modules/react": {
5055
  "version": "19.1.0",
5056
  "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
@@ -5079,6 +5695,27 @@
5079
  "dev": true,
5080
  "license": "MIT"
5081
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5082
  "node_modules/reflect.getprototypeof": {
5083
  "version": "1.0.10",
5084
  "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -5102,6 +5739,13 @@
5102
  "url": "https://github.com/sponsors/ljharb"
5103
  }
5104
  },
 
 
 
 
 
 
 
5105
  "node_modules/regexp.prototype.flags": {
5106
  "version": "1.5.4",
5107
  "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@@ -5175,6 +5819,16 @@
5175
  "node": ">=0.10.0"
5176
  }
5177
  },
 
 
 
 
 
 
 
 
 
 
5178
  "node_modules/run-parallel": {
5179
  "version": "1.2.0",
5180
  "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5219,6 +5873,12 @@
5219
  "url": "https://github.com/sponsors/ljharb"
5220
  }
5221
  },
 
 
 
 
 
 
5222
  "node_modules/safe-push-apply": {
5223
  "version": "1.0.0",
5224
  "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@@ -5322,6 +5982,12 @@
5322
  "node": ">= 0.4"
5323
  }
5324
  },
 
 
 
 
 
 
5325
  "node_modules/sharp": {
5326
  "version": "0.34.3",
5327
  "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
@@ -5490,6 +6156,16 @@
5490
  "dev": true,
5491
  "license": "MIT"
5492
  },
 
 
 
 
 
 
 
 
 
 
5493
  "node_modules/stop-iteration-iterator": {
5494
  "version": "1.1.0",
5495
  "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -5504,6 +6180,15 @@
5504
  "node": ">= 0.4"
5505
  }
5506
  },
 
 
 
 
 
 
 
 
 
5507
  "node_modules/string.prototype.includes": {
5508
  "version": "2.0.1",
5509
  "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
@@ -5689,6 +6374,16 @@
5689
  "url": "https://github.com/sponsors/ljharb"
5690
  }
5691
  },
 
 
 
 
 
 
 
 
 
 
5692
  "node_modules/tailwindcss": {
5693
  "version": "4.1.13",
5694
  "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
@@ -5728,6 +6423,15 @@
5728
  "node": ">=18"
5729
  }
5730
  },
 
 
 
 
 
 
 
 
 
5731
  "node_modules/tinyglobby": {
5732
  "version": "0.2.15",
5733
  "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -5949,7 +6653,6 @@
5949
  "version": "6.21.0",
5950
  "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
5951
  "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
5952
- "dev": true,
5953
  "license": "MIT"
5954
  },
5955
  "node_modules/unrs-resolver": {
@@ -5997,6 +6700,30 @@
5997
  "punycode": "^2.1.0"
5998
  }
5999
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6000
  "node_modules/which": {
6001
  "version": "2.0.2",
6002
  "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 
8
  "name": "powerpoint",
9
  "version": "0.1.0",
10
  "dependencies": {
11
+ "@auth/core": "^0.34.2",
12
+ "@huggingface/inference": "^4.8.0",
13
+ "axios": "^1.12.2",
14
+ "html2canvas": "^1.4.1",
15
+ "jspdf": "^3.0.2",
16
+ "lucide-react": "^0.544.0",
17
  "next": "15.5.3",
18
+ "next-auth": "^4.24.11",
19
+ "pptxgenjs": "^4.0.1",
20
  "react": "19.1.0",
21
  "react-dom": "19.1.0"
22
  },
 
45
  "url": "https://github.com/sponsors/sindresorhus"
46
  }
47
  },
48
+ "node_modules/@auth/core": {
49
+ "version": "0.34.2",
50
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.34.2.tgz",
51
+ "integrity": "sha512-KywHKRgLiF3l7PLyL73fjLSIBe1YNcA6sMeew4yMP6cfCWGXZrkkXd32AjRi1hlJ9nvovUBGZHvbn+LijO6ZeQ==",
52
+ "license": "ISC",
53
+ "dependencies": {
54
+ "@panva/hkdf": "^1.1.1",
55
+ "@types/cookie": "0.6.0",
56
+ "cookie": "0.6.0",
57
+ "jose": "^5.1.3",
58
+ "oauth4webapi": "^2.10.4",
59
+ "preact": "10.11.3",
60
+ "preact-render-to-string": "5.2.3"
61
+ },
62
+ "peerDependencies": {
63
+ "@simplewebauthn/browser": "^9.0.1",
64
+ "@simplewebauthn/server": "^9.0.2",
65
+ "nodemailer": "^6.8.0"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "@simplewebauthn/browser": {
69
+ "optional": true
70
+ },
71
+ "@simplewebauthn/server": {
72
+ "optional": true
73
+ },
74
+ "nodemailer": {
75
+ "optional": true
76
+ }
77
+ }
78
+ },
79
+ "node_modules/@babel/runtime": {
80
+ "version": "7.28.4",
81
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
82
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
83
+ "license": "MIT",
84
+ "engines": {
85
+ "node": ">=6.9.0"
86
+ }
87
+ },
88
  "node_modules/@emnapi/core": {
89
  "version": "1.5.0",
90
  "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
 
259
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
260
  }
261
  },
262
+ "node_modules/@huggingface/inference": {
263
+ "version": "4.8.0",
264
+ "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-4.8.0.tgz",
265
+ "integrity": "sha512-Eq98EAXqYn4rKMfrbEXuhc3IjKfaeIO6eXNOZk9xk6v5akrIWRtd6d1h0fjAWyX4zRbdUpXRh6MvsqXnzGvXCA==",
266
+ "license": "MIT",
267
+ "dependencies": {
268
+ "@huggingface/jinja": "^0.5.1",
269
+ "@huggingface/tasks": "^0.19.45"
270
+ },
271
+ "engines": {
272
+ "node": ">=18"
273
+ }
274
+ },
275
+ "node_modules/@huggingface/jinja": {
276
+ "version": "0.5.1",
277
+ "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.1.tgz",
278
+ "integrity": "sha512-yUZLld4lrM9iFxHCwFQ7D1HW2MWMwSbeB7WzWqFYDWK+rEb+WldkLdAJxUPOmgICMHZLzZGVcVjFh3w/YGubng==",
279
+ "license": "MIT",
280
+ "engines": {
281
+ "node": ">=18"
282
+ }
283
+ },
284
+ "node_modules/@huggingface/tasks": {
285
+ "version": "0.19.45",
286
+ "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.45.tgz",
287
+ "integrity": "sha512-lM3QOgbfkGZ5gAZOYWOmzMM6BbKcXOIHjgnUAoymTdZEcEcGSr0vy/LWGEiK+vBXC4vU+sCT+WNoA/JZ8TEWdA==",
288
+ "license": "MIT"
289
+ },
290
  "node_modules/@humanfs/core": {
291
  "version": "0.19.1",
292
  "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
 
1025
  "node": ">=12.4.0"
1026
  }
1027
  },
1028
+ "node_modules/@panva/hkdf": {
1029
+ "version": "1.2.1",
1030
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
1031
+ "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
1032
+ "license": "MIT",
1033
+ "funding": {
1034
+ "url": "https://github.com/sponsors/panva"
1035
+ }
1036
+ },
1037
  "node_modules/@rtsao/scc": {
1038
  "version": "1.1.0",
1039
  "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
 
1344
  "tslib": "^2.4.0"
1345
  }
1346
  },
1347
+ "node_modules/@types/cookie": {
1348
+ "version": "0.6.0",
1349
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
1350
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
1351
+ "license": "MIT"
1352
+ },
1353
  "node_modules/@types/estree": {
1354
  "version": "1.0.8",
1355
  "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
 
1381
  "undici-types": "~6.21.0"
1382
  }
1383
  },
1384
+ "node_modules/@types/pako": {
1385
+ "version": "2.0.4",
1386
+ "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
1387
+ "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
1388
+ "license": "MIT"
1389
+ },
1390
+ "node_modules/@types/raf": {
1391
+ "version": "3.4.3",
1392
+ "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
1393
+ "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
1394
+ "license": "MIT",
1395
+ "optional": true
1396
+ },
1397
  "node_modules/@types/react": {
1398
  "version": "19.1.13",
1399
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
 
1414
  "@types/react": "^19.0.0"
1415
  }
1416
  },
1417
+ "node_modules/@types/trusted-types": {
1418
+ "version": "2.0.7",
1419
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
1420
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
1421
+ "license": "MIT",
1422
+ "optional": true
1423
+ },
1424
  "node_modules/@typescript-eslint/eslint-plugin": {
1425
  "version": "8.44.0",
1426
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz",
 
2228
  "node": ">= 0.4"
2229
  }
2230
  },
2231
+ "node_modules/asynckit": {
2232
+ "version": "0.4.0",
2233
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
2234
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
2235
+ "license": "MIT"
2236
+ },
2237
  "node_modules/available-typed-arrays": {
2238
  "version": "1.0.7",
2239
  "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
 
2260
  "node": ">=4"
2261
  }
2262
  },
2263
+ "node_modules/axios": {
2264
+ "version": "1.12.2",
2265
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
2266
+ "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
2267
+ "license": "MIT",
2268
+ "dependencies": {
2269
+ "follow-redirects": "^1.15.6",
2270
+ "form-data": "^4.0.4",
2271
+ "proxy-from-env": "^1.1.0"
2272
+ }
2273
+ },
2274
  "node_modules/axobject-query": {
2275
  "version": "4.1.0",
2276
  "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
 
2288
  "dev": true,
2289
  "license": "MIT"
2290
  },
2291
+ "node_modules/base64-arraybuffer": {
2292
+ "version": "1.0.2",
2293
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
2294
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
2295
+ "license": "MIT",
2296
+ "engines": {
2297
+ "node": ">= 0.6.0"
2298
+ }
2299
+ },
2300
  "node_modules/brace-expansion": {
2301
  "version": "1.1.12",
2302
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
 
2344
  "version": "1.0.2",
2345
  "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
2346
  "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
 
2347
  "license": "MIT",
2348
  "dependencies": {
2349
  "es-errors": "^1.3.0",
 
2400
  ],
2401
  "license": "CC-BY-4.0"
2402
  },
2403
+ "node_modules/canvg": {
2404
+ "version": "3.0.11",
2405
+ "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
2406
+ "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
2407
+ "license": "MIT",
2408
+ "optional": true,
2409
+ "dependencies": {
2410
+ "@babel/runtime": "^7.12.5",
2411
+ "@types/raf": "^3.4.0",
2412
+ "core-js": "^3.8.3",
2413
+ "raf": "^3.4.1",
2414
+ "regenerator-runtime": "^0.13.7",
2415
+ "rgbcolor": "^1.0.1",
2416
+ "stackblur-canvas": "^2.0.0",
2417
+ "svg-pathdata": "^6.0.3"
2418
+ },
2419
+ "engines": {
2420
+ "node": ">=10.0.0"
2421
+ }
2422
+ },
2423
  "node_modules/chalk": {
2424
  "version": "4.1.2",
2425
  "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 
2498
  "simple-swizzle": "^0.2.2"
2499
  }
2500
  },
2501
+ "node_modules/combined-stream": {
2502
+ "version": "1.0.8",
2503
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
2504
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
2505
+ "license": "MIT",
2506
+ "dependencies": {
2507
+ "delayed-stream": "~1.0.0"
2508
+ },
2509
+ "engines": {
2510
+ "node": ">= 0.8"
2511
+ }
2512
+ },
2513
  "node_modules/concat-map": {
2514
  "version": "0.0.1",
2515
  "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 
2517
  "dev": true,
2518
  "license": "MIT"
2519
  },
2520
+ "node_modules/cookie": {
2521
+ "version": "0.6.0",
2522
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
2523
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
2524
+ "license": "MIT",
2525
+ "engines": {
2526
+ "node": ">= 0.6"
2527
+ }
2528
+ },
2529
+ "node_modules/core-js": {
2530
+ "version": "3.45.1",
2531
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz",
2532
+ "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==",
2533
+ "hasInstallScript": true,
2534
+ "license": "MIT",
2535
+ "optional": true,
2536
+ "funding": {
2537
+ "type": "opencollective",
2538
+ "url": "https://opencollective.com/core-js"
2539
+ }
2540
+ },
2541
+ "node_modules/core-util-is": {
2542
+ "version": "1.0.3",
2543
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
2544
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
2545
+ "license": "MIT"
2546
+ },
2547
  "node_modules/cross-spawn": {
2548
  "version": "7.0.6",
2549
  "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
 
2559
  "node": ">= 8"
2560
  }
2561
  },
2562
+ "node_modules/css-line-break": {
2563
+ "version": "2.1.0",
2564
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
2565
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
2566
+ "license": "MIT",
2567
+ "dependencies": {
2568
+ "utrie": "^1.0.2"
2569
+ }
2570
+ },
2571
  "node_modules/csstype": {
2572
  "version": "3.1.3",
2573
  "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
 
2697
  "url": "https://github.com/sponsors/ljharb"
2698
  }
2699
  },
2700
+ "node_modules/delayed-stream": {
2701
+ "version": "1.0.0",
2702
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
2703
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
2704
+ "license": "MIT",
2705
+ "engines": {
2706
+ "node": ">=0.4.0"
2707
+ }
2708
+ },
2709
  "node_modules/detect-libc": {
2710
  "version": "2.1.0",
2711
  "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
 
2729
  "node": ">=0.10.0"
2730
  }
2731
  },
2732
+ "node_modules/dompurify": {
2733
+ "version": "3.2.6",
2734
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz",
2735
+ "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==",
2736
+ "license": "(MPL-2.0 OR Apache-2.0)",
2737
+ "optional": true,
2738
+ "optionalDependencies": {
2739
+ "@types/trusted-types": "^2.0.7"
2740
+ }
2741
+ },
2742
  "node_modules/dunder-proto": {
2743
  "version": "1.0.1",
2744
  "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
2745
  "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
 
2746
  "license": "MIT",
2747
  "dependencies": {
2748
  "call-bind-apply-helpers": "^1.0.1",
 
2847
  "version": "1.0.1",
2848
  "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
2849
  "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
 
2850
  "license": "MIT",
2851
  "engines": {
2852
  "node": ">= 0.4"
 
2856
  "version": "1.3.0",
2857
  "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
2858
  "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
 
2859
  "license": "MIT",
2860
  "engines": {
2861
  "node": ">= 0.4"
 
2893
  "version": "1.1.1",
2894
  "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
2895
  "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
 
2896
  "license": "MIT",
2897
  "dependencies": {
2898
  "es-errors": "^1.3.0"
 
2905
  "version": "2.1.0",
2906
  "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
2907
  "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
 
2908
  "license": "MIT",
2909
  "dependencies": {
2910
  "es-errors": "^1.3.0",
 
3437
  "dev": true,
3438
  "license": "MIT"
3439
  },
3440
+ "node_modules/fast-png": {
3441
+ "version": "6.4.0",
3442
+ "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
3443
+ "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
3444
+ "license": "MIT",
3445
+ "dependencies": {
3446
+ "@types/pako": "^2.0.3",
3447
+ "iobuffer": "^5.3.2",
3448
+ "pako": "^2.1.0"
3449
+ }
3450
+ },
3451
  "node_modules/fastq": {
3452
  "version": "1.19.1",
3453
  "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
 
3458
  "reusify": "^1.0.4"
3459
  }
3460
  },
3461
+ "node_modules/fflate": {
3462
+ "version": "0.8.2",
3463
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
3464
+ "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
3465
+ "license": "MIT"
3466
+ },
3467
  "node_modules/file-entry-cache": {
3468
  "version": "8.0.0",
3469
  "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
 
3528
  "dev": true,
3529
  "license": "ISC"
3530
  },
3531
+ "node_modules/follow-redirects": {
3532
+ "version": "1.15.11",
3533
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
3534
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
3535
+ "funding": [
3536
+ {
3537
+ "type": "individual",
3538
+ "url": "https://github.com/sponsors/RubenVerborgh"
3539
+ }
3540
+ ],
3541
+ "license": "MIT",
3542
+ "engines": {
3543
+ "node": ">=4.0"
3544
+ },
3545
+ "peerDependenciesMeta": {
3546
+ "debug": {
3547
+ "optional": true
3548
+ }
3549
+ }
3550
+ },
3551
  "node_modules/for-each": {
3552
  "version": "0.3.5",
3553
  "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
 
3564
  "url": "https://github.com/sponsors/ljharb"
3565
  }
3566
  },
3567
+ "node_modules/form-data": {
3568
+ "version": "4.0.4",
3569
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
3570
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
3571
+ "license": "MIT",
3572
+ "dependencies": {
3573
+ "asynckit": "^0.4.0",
3574
+ "combined-stream": "^1.0.8",
3575
+ "es-set-tostringtag": "^2.1.0",
3576
+ "hasown": "^2.0.2",
3577
+ "mime-types": "^2.1.12"
3578
+ },
3579
+ "engines": {
3580
+ "node": ">= 6"
3581
+ }
3582
+ },
3583
  "node_modules/function-bind": {
3584
  "version": "1.1.2",
3585
  "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
3586
  "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
 
3587
  "license": "MIT",
3588
  "funding": {
3589
  "url": "https://github.com/sponsors/ljharb"
 
3624
  "version": "1.3.0",
3625
  "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
3626
  "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
 
3627
  "license": "MIT",
3628
  "dependencies": {
3629
  "call-bind-apply-helpers": "^1.0.2",
 
3648
  "version": "1.0.1",
3649
  "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
3650
  "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
 
3651
  "license": "MIT",
3652
  "dependencies": {
3653
  "dunder-proto": "^1.0.1",
 
3735
  "version": "1.2.0",
3736
  "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
3737
  "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
 
3738
  "license": "MIT",
3739
  "engines": {
3740
  "node": ">= 0.4"
 
3813
  "version": "1.1.0",
3814
  "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
3815
  "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
 
3816
  "license": "MIT",
3817
  "engines": {
3818
  "node": ">= 0.4"
 
3825
  "version": "1.0.2",
3826
  "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
3827
  "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
 
3828
  "license": "MIT",
3829
  "dependencies": {
3830
  "has-symbols": "^1.0.3"
 
3840
  "version": "2.0.2",
3841
  "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
3842
  "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
 
3843
  "license": "MIT",
3844
  "dependencies": {
3845
  "function-bind": "^1.1.2"
 
3848
  "node": ">= 0.4"
3849
  }
3850
  },
3851
+ "node_modules/html2canvas": {
3852
+ "version": "1.4.1",
3853
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
3854
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
3855
+ "license": "MIT",
3856
+ "dependencies": {
3857
+ "css-line-break": "^2.1.0",
3858
+ "text-segmentation": "^1.0.3"
3859
+ },
3860
+ "engines": {
3861
+ "node": ">=8.0.0"
3862
+ }
3863
+ },
3864
+ "node_modules/https": {
3865
+ "version": "1.0.0",
3866
+ "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
3867
+ "integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==",
3868
+ "license": "ISC"
3869
+ },
3870
  "node_modules/ignore": {
3871
  "version": "5.3.2",
3872
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
 
3877
  "node": ">= 4"
3878
  }
3879
  },
3880
+ "node_modules/image-size": {
3881
+ "version": "1.2.1",
3882
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
3883
+ "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
3884
+ "license": "MIT",
3885
+ "dependencies": {
3886
+ "queue": "6.0.2"
3887
+ },
3888
+ "bin": {
3889
+ "image-size": "bin/image-size.js"
3890
+ },
3891
+ "engines": {
3892
+ "node": ">=16.x"
3893
+ }
3894
+ },
3895
+ "node_modules/immediate": {
3896
+ "version": "3.0.6",
3897
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
3898
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
3899
+ "license": "MIT"
3900
+ },
3901
  "node_modules/import-fresh": {
3902
  "version": "3.3.1",
3903
  "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
 
3925
  "node": ">=0.8.19"
3926
  }
3927
  },
3928
+ "node_modules/inherits": {
3929
+ "version": "2.0.4",
3930
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
3931
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
3932
+ "license": "ISC"
3933
+ },
3934
  "node_modules/internal-slot": {
3935
  "version": "1.1.0",
3936
  "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
 
3946
  "node": ">= 0.4"
3947
  }
3948
  },
3949
+ "node_modules/iobuffer": {
3950
+ "version": "5.4.0",
3951
+ "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
3952
+ "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
3953
+ "license": "MIT"
3954
+ },
3955
  "node_modules/is-array-buffer": {
3956
  "version": "3.0.5",
3957
  "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
 
4402
  "jiti": "lib/jiti-cli.mjs"
4403
  }
4404
  },
4405
+ "node_modules/jose": {
4406
+ "version": "5.10.0",
4407
+ "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
4408
+ "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
4409
+ "license": "MIT",
4410
+ "funding": {
4411
+ "url": "https://github.com/sponsors/panva"
4412
+ }
4413
+ },
4414
  "node_modules/js-tokens": {
4415
  "version": "4.0.0",
4416
  "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
 
4465
  "json5": "lib/cli.js"
4466
  }
4467
  },
4468
+ "node_modules/jspdf": {
4469
+ "version": "3.0.2",
4470
+ "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.2.tgz",
4471
+ "integrity": "sha512-G0fQDJ5fAm6UW78HG6lNXyq09l0PrA1rpNY5i+ly17Zb1fMMFSmS+3lw4cnrAPGyouv2Y0ylujbY2Ieq3DSlKA==",
4472
+ "license": "MIT",
4473
+ "dependencies": {
4474
+ "@babel/runtime": "^7.26.9",
4475
+ "fast-png": "^6.2.0",
4476
+ "fflate": "^0.8.1"
4477
+ },
4478
+ "optionalDependencies": {
4479
+ "canvg": "^3.0.11",
4480
+ "core-js": "^3.6.0",
4481
+ "dompurify": "^3.2.4",
4482
+ "html2canvas": "^1.0.0-rc.5"
4483
+ }
4484
+ },
4485
  "node_modules/jsx-ast-utils": {
4486
  "version": "3.3.5",
4487
  "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
 
4498
  "node": ">=4.0"
4499
  }
4500
  },
4501
+ "node_modules/jszip": {
4502
+ "version": "3.10.1",
4503
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
4504
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
4505
+ "license": "(MIT OR GPL-3.0-or-later)",
4506
+ "dependencies": {
4507
+ "lie": "~3.3.0",
4508
+ "pako": "~1.0.2",
4509
+ "readable-stream": "~2.3.6",
4510
+ "setimmediate": "^1.0.5"
4511
+ }
4512
+ },
4513
+ "node_modules/jszip/node_modules/pako": {
4514
+ "version": "1.0.11",
4515
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
4516
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
4517
+ "license": "(MIT AND Zlib)"
4518
+ },
4519
  "node_modules/keyv": {
4520
  "version": "4.5.4",
4521
  "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
 
4560
  "node": ">= 0.8.0"
4561
  }
4562
  },
4563
+ "node_modules/lie": {
4564
+ "version": "3.3.0",
4565
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
4566
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
4567
+ "license": "MIT",
4568
+ "dependencies": {
4569
+ "immediate": "~3.0.5"
4570
+ }
4571
+ },
4572
  "node_modules/lightningcss": {
4573
  "version": "1.30.1",
4574
  "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
 
4844
  "loose-envify": "cli.js"
4845
  }
4846
  },
4847
+ "node_modules/lru-cache": {
4848
+ "version": "6.0.0",
4849
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
4850
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
4851
+ "license": "ISC",
4852
+ "dependencies": {
4853
+ "yallist": "^4.0.0"
4854
+ },
4855
+ "engines": {
4856
+ "node": ">=10"
4857
+ }
4858
+ },
4859
+ "node_modules/lru-cache/node_modules/yallist": {
4860
+ "version": "4.0.0",
4861
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
4862
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
4863
+ "license": "ISC"
4864
+ },
4865
+ "node_modules/lucide-react": {
4866
+ "version": "0.544.0",
4867
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz",
4868
+ "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==",
4869
+ "license": "ISC",
4870
+ "peerDependencies": {
4871
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
4872
+ }
4873
+ },
4874
  "node_modules/magic-string": {
4875
  "version": "0.30.19",
4876
  "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
 
4885
  "version": "1.1.0",
4886
  "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
4887
  "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
 
4888
  "license": "MIT",
4889
  "engines": {
4890
  "node": ">= 0.4"
 
4914
  "node": ">=8.6"
4915
  }
4916
  },
4917
+ "node_modules/mime-db": {
4918
+ "version": "1.52.0",
4919
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
4920
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
4921
+ "license": "MIT",
4922
+ "engines": {
4923
+ "node": ">= 0.6"
4924
+ }
4925
+ },
4926
+ "node_modules/mime-types": {
4927
+ "version": "2.1.35",
4928
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
4929
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
4930
+ "license": "MIT",
4931
+ "dependencies": {
4932
+ "mime-db": "1.52.0"
4933
+ },
4934
+ "engines": {
4935
+ "node": ">= 0.6"
4936
+ }
4937
+ },
4938
  "node_modules/minimatch": {
4939
  "version": "3.1.2",
4940
  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
 
5097
  }
5098
  }
5099
  },
5100
+ "node_modules/next-auth": {
5101
+ "version": "4.24.11",
5102
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz",
5103
+ "integrity": "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==",
5104
+ "license": "ISC",
5105
+ "dependencies": {
5106
+ "@babel/runtime": "^7.20.13",
5107
+ "@panva/hkdf": "^1.0.2",
5108
+ "cookie": "^0.7.0",
5109
+ "jose": "^4.15.5",
5110
+ "oauth": "^0.9.15",
5111
+ "openid-client": "^5.4.0",
5112
+ "preact": "^10.6.3",
5113
+ "preact-render-to-string": "^5.1.19",
5114
+ "uuid": "^8.3.2"
5115
+ },
5116
+ "peerDependencies": {
5117
+ "@auth/core": "0.34.2",
5118
+ "next": "^12.2.5 || ^13 || ^14 || ^15",
5119
+ "nodemailer": "^6.6.5",
5120
+ "react": "^17.0.2 || ^18 || ^19",
5121
+ "react-dom": "^17.0.2 || ^18 || ^19"
5122
+ },
5123
+ "peerDependenciesMeta": {
5124
+ "@auth/core": {
5125
+ "optional": true
5126
+ },
5127
+ "nodemailer": {
5128
+ "optional": true
5129
+ }
5130
+ }
5131
+ },
5132
+ "node_modules/next-auth/node_modules/cookie": {
5133
+ "version": "0.7.2",
5134
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
5135
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
5136
+ "license": "MIT",
5137
+ "engines": {
5138
+ "node": ">= 0.6"
5139
+ }
5140
+ },
5141
+ "node_modules/next-auth/node_modules/jose": {
5142
+ "version": "4.15.9",
5143
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
5144
+ "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
5145
+ "license": "MIT",
5146
+ "funding": {
5147
+ "url": "https://github.com/sponsors/panva"
5148
+ }
5149
+ },
5150
  "node_modules/next/node_modules/postcss": {
5151
  "version": "8.4.31",
5152
  "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
 
5175
  "node": "^10 || ^12 || >=14"
5176
  }
5177
  },
5178
+ "node_modules/oauth": {
5179
+ "version": "0.9.15",
5180
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
5181
+ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==",
5182
+ "license": "MIT"
5183
+ },
5184
+ "node_modules/oauth4webapi": {
5185
+ "version": "2.17.0",
5186
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.17.0.tgz",
5187
+ "integrity": "sha512-lbC0Z7uzAFNFyzEYRIC+pkSVvDHJTbEW+dYlSBAlCYDe6RxUkJ26bClhk8ocBZip1wfI9uKTe0fm4Ib4RHn6uQ==",
5188
+ "license": "MIT",
5189
+ "funding": {
5190
+ "url": "https://github.com/sponsors/panva"
5191
+ }
5192
+ },
5193
  "node_modules/object-assign": {
5194
  "version": "4.1.1",
5195
  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
 
5200
  "node": ">=0.10.0"
5201
  }
5202
  },
5203
+ "node_modules/object-hash": {
5204
+ "version": "2.2.0",
5205
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
5206
+ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
5207
+ "license": "MIT",
5208
+ "engines": {
5209
+ "node": ">= 6"
5210
+ }
5211
+ },
5212
  "node_modules/object-inspect": {
5213
  "version": "1.13.4",
5214
  "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
 
5322
  "url": "https://github.com/sponsors/ljharb"
5323
  }
5324
  },
5325
+ "node_modules/oidc-token-hash": {
5326
+ "version": "5.1.1",
5327
+ "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.1.tgz",
5328
+ "integrity": "sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g==",
5329
+ "license": "MIT",
5330
+ "engines": {
5331
+ "node": "^10.13.0 || >=12.0.0"
5332
+ }
5333
+ },
5334
+ "node_modules/openid-client": {
5335
+ "version": "5.7.1",
5336
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
5337
+ "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
5338
+ "license": "MIT",
5339
+ "dependencies": {
5340
+ "jose": "^4.15.9",
5341
+ "lru-cache": "^6.0.0",
5342
+ "object-hash": "^2.2.0",
5343
+ "oidc-token-hash": "^5.0.3"
5344
+ },
5345
+ "funding": {
5346
+ "url": "https://github.com/sponsors/panva"
5347
+ }
5348
+ },
5349
+ "node_modules/openid-client/node_modules/jose": {
5350
+ "version": "4.15.9",
5351
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
5352
+ "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
5353
+ "license": "MIT",
5354
+ "funding": {
5355
+ "url": "https://github.com/sponsors/panva"
5356
+ }
5357
+ },
5358
  "node_modules/optionator": {
5359
  "version": "0.9.4",
5360
  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
 
5423
  "url": "https://github.com/sponsors/sindresorhus"
5424
  }
5425
  },
5426
+ "node_modules/pako": {
5427
+ "version": "2.1.0",
5428
+ "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
5429
+ "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
5430
+ "license": "(MIT AND Zlib)"
5431
+ },
5432
  "node_modules/parent-module": {
5433
  "version": "1.0.1",
5434
  "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
 
5469
  "dev": true,
5470
  "license": "MIT"
5471
  },
5472
+ "node_modules/performance-now": {
5473
+ "version": "2.1.0",
5474
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
5475
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
5476
+ "license": "MIT",
5477
+ "optional": true
5478
+ },
5479
  "node_modules/picocolors": {
5480
  "version": "1.1.1",
5481
  "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
 
5534
  "node": "^10 || ^12 || >=14"
5535
  }
5536
  },
5537
+ "node_modules/pptxgenjs": {
5538
+ "version": "4.0.1",
5539
+ "resolved": "https://registry.npmjs.org/pptxgenjs/-/pptxgenjs-4.0.1.tgz",
5540
+ "integrity": "sha512-TeJISr8wouAuXw4C1F/mC33xbZs/FuEG6nH9FG1Zj+nuPcGMP5YRHl6X+j3HSUnS1f3at6k75ZZXPMZlA5Lj9A==",
5541
+ "license": "MIT",
5542
+ "dependencies": {
5543
+ "@types/node": "^22.8.1",
5544
+ "https": "^1.0.0",
5545
+ "image-size": "^1.2.1",
5546
+ "jszip": "^3.10.1"
5547
+ }
5548
+ },
5549
+ "node_modules/pptxgenjs/node_modules/@types/node": {
5550
+ "version": "22.18.4",
5551
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.4.tgz",
5552
+ "integrity": "sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==",
5553
+ "license": "MIT",
5554
+ "dependencies": {
5555
+ "undici-types": "~6.21.0"
5556
+ }
5557
+ },
5558
+ "node_modules/preact": {
5559
+ "version": "10.11.3",
5560
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
5561
+ "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==",
5562
+ "license": "MIT",
5563
+ "funding": {
5564
+ "type": "opencollective",
5565
+ "url": "https://opencollective.com/preact"
5566
+ }
5567
+ },
5568
+ "node_modules/preact-render-to-string": {
5569
+ "version": "5.2.3",
5570
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz",
5571
+ "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==",
5572
+ "license": "MIT",
5573
+ "dependencies": {
5574
+ "pretty-format": "^3.8.0"
5575
+ },
5576
+ "peerDependencies": {
5577
+ "preact": ">=10"
5578
+ }
5579
+ },
5580
  "node_modules/prelude-ls": {
5581
  "version": "1.2.1",
5582
  "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 
5587
  "node": ">= 0.8.0"
5588
  }
5589
  },
5590
+ "node_modules/pretty-format": {
5591
+ "version": "3.8.0",
5592
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
5593
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==",
5594
+ "license": "MIT"
5595
+ },
5596
+ "node_modules/process-nextick-args": {
5597
+ "version": "2.0.1",
5598
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
5599
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
5600
+ "license": "MIT"
5601
+ },
5602
  "node_modules/prop-types": {
5603
  "version": "15.8.1",
5604
  "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
 
5611
  "react-is": "^16.13.1"
5612
  }
5613
  },
5614
+ "node_modules/proxy-from-env": {
5615
+ "version": "1.1.0",
5616
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
5617
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
5618
+ "license": "MIT"
5619
+ },
5620
  "node_modules/punycode": {
5621
  "version": "2.3.1",
5622
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
 
5627
  "node": ">=6"
5628
  }
5629
  },
5630
+ "node_modules/queue": {
5631
+ "version": "6.0.2",
5632
+ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
5633
+ "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
5634
+ "license": "MIT",
5635
+ "dependencies": {
5636
+ "inherits": "~2.0.3"
5637
+ }
5638
+ },
5639
  "node_modules/queue-microtask": {
5640
  "version": "1.2.3",
5641
  "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 
5657
  ],
5658
  "license": "MIT"
5659
  },
5660
+ "node_modules/raf": {
5661
+ "version": "3.4.1",
5662
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
5663
+ "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
5664
+ "license": "MIT",
5665
+ "optional": true,
5666
+ "dependencies": {
5667
+ "performance-now": "^2.1.0"
5668
+ }
5669
+ },
5670
  "node_modules/react": {
5671
  "version": "19.1.0",
5672
  "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
 
5695
  "dev": true,
5696
  "license": "MIT"
5697
  },
5698
+ "node_modules/readable-stream": {
5699
+ "version": "2.3.8",
5700
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
5701
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
5702
+ "license": "MIT",
5703
+ "dependencies": {
5704
+ "core-util-is": "~1.0.0",
5705
+ "inherits": "~2.0.3",
5706
+ "isarray": "~1.0.0",
5707
+ "process-nextick-args": "~2.0.0",
5708
+ "safe-buffer": "~5.1.1",
5709
+ "string_decoder": "~1.1.1",
5710
+ "util-deprecate": "~1.0.1"
5711
+ }
5712
+ },
5713
+ "node_modules/readable-stream/node_modules/isarray": {
5714
+ "version": "1.0.0",
5715
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
5716
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
5717
+ "license": "MIT"
5718
+ },
5719
  "node_modules/reflect.getprototypeof": {
5720
  "version": "1.0.10",
5721
  "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
 
5739
  "url": "https://github.com/sponsors/ljharb"
5740
  }
5741
  },
5742
+ "node_modules/regenerator-runtime": {
5743
+ "version": "0.13.11",
5744
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
5745
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
5746
+ "license": "MIT",
5747
+ "optional": true
5748
+ },
5749
  "node_modules/regexp.prototype.flags": {
5750
  "version": "1.5.4",
5751
  "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
 
5819
  "node": ">=0.10.0"
5820
  }
5821
  },
5822
+ "node_modules/rgbcolor": {
5823
+ "version": "1.0.1",
5824
+ "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
5825
+ "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
5826
+ "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
5827
+ "optional": true,
5828
+ "engines": {
5829
+ "node": ">= 0.8.15"
5830
+ }
5831
+ },
5832
  "node_modules/run-parallel": {
5833
  "version": "1.2.0",
5834
  "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 
5873
  "url": "https://github.com/sponsors/ljharb"
5874
  }
5875
  },
5876
+ "node_modules/safe-buffer": {
5877
+ "version": "5.1.2",
5878
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
5879
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
5880
+ "license": "MIT"
5881
+ },
5882
  "node_modules/safe-push-apply": {
5883
  "version": "1.0.0",
5884
  "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
 
5982
  "node": ">= 0.4"
5983
  }
5984
  },
5985
+ "node_modules/setimmediate": {
5986
+ "version": "1.0.5",
5987
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
5988
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
5989
+ "license": "MIT"
5990
+ },
5991
  "node_modules/sharp": {
5992
  "version": "0.34.3",
5993
  "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
 
6156
  "dev": true,
6157
  "license": "MIT"
6158
  },
6159
+ "node_modules/stackblur-canvas": {
6160
+ "version": "2.7.0",
6161
+ "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
6162
+ "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
6163
+ "license": "MIT",
6164
+ "optional": true,
6165
+ "engines": {
6166
+ "node": ">=0.1.14"
6167
+ }
6168
+ },
6169
  "node_modules/stop-iteration-iterator": {
6170
  "version": "1.1.0",
6171
  "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
 
6180
  "node": ">= 0.4"
6181
  }
6182
  },
6183
+ "node_modules/string_decoder": {
6184
+ "version": "1.1.1",
6185
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
6186
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
6187
+ "license": "MIT",
6188
+ "dependencies": {
6189
+ "safe-buffer": "~5.1.0"
6190
+ }
6191
+ },
6192
  "node_modules/string.prototype.includes": {
6193
  "version": "2.0.1",
6194
  "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
 
6374
  "url": "https://github.com/sponsors/ljharb"
6375
  }
6376
  },
6377
+ "node_modules/svg-pathdata": {
6378
+ "version": "6.0.3",
6379
+ "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
6380
+ "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
6381
+ "license": "MIT",
6382
+ "optional": true,
6383
+ "engines": {
6384
+ "node": ">=12.0.0"
6385
+ }
6386
+ },
6387
  "node_modules/tailwindcss": {
6388
  "version": "4.1.13",
6389
  "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
 
6423
  "node": ">=18"
6424
  }
6425
  },
6426
+ "node_modules/text-segmentation": {
6427
+ "version": "1.0.3",
6428
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
6429
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
6430
+ "license": "MIT",
6431
+ "dependencies": {
6432
+ "utrie": "^1.0.2"
6433
+ }
6434
+ },
6435
  "node_modules/tinyglobby": {
6436
  "version": "0.2.15",
6437
  "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
 
6653
  "version": "6.21.0",
6654
  "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
6655
  "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
 
6656
  "license": "MIT"
6657
  },
6658
  "node_modules/unrs-resolver": {
 
6700
  "punycode": "^2.1.0"
6701
  }
6702
  },
6703
+ "node_modules/util-deprecate": {
6704
+ "version": "1.0.2",
6705
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
6706
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
6707
+ "license": "MIT"
6708
+ },
6709
+ "node_modules/utrie": {
6710
+ "version": "1.0.2",
6711
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
6712
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
6713
+ "license": "MIT",
6714
+ "dependencies": {
6715
+ "base64-arraybuffer": "^1.0.2"
6716
+ }
6717
+ },
6718
+ "node_modules/uuid": {
6719
+ "version": "8.3.2",
6720
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
6721
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
6722
+ "license": "MIT",
6723
+ "bin": {
6724
+ "uuid": "dist/bin/uuid"
6725
+ }
6726
+ },
6727
  "node_modules/which": {
6728
  "version": "2.0.2",
6729
  "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
package.json CHANGED
@@ -9,19 +9,27 @@
9
  "lint": "eslint"
10
  },
11
  "dependencies": {
 
 
 
 
 
 
 
 
 
12
  "react": "19.1.0",
13
- "react-dom": "19.1.0",
14
- "next": "15.5.3"
15
  },
16
  "devDependencies": {
17
- "typescript": "^5",
 
18
  "@types/node": "^20",
19
  "@types/react": "^19",
20
  "@types/react-dom": "^19",
21
- "@tailwindcss/postcss": "^4",
22
- "tailwindcss": "^4",
23
  "eslint": "^9",
24
  "eslint-config-next": "15.5.3",
25
- "@eslint/eslintrc": "^3"
 
26
  }
27
- }
 
9
  "lint": "eslint"
10
  },
11
  "dependencies": {
12
+ "@auth/core": "^0.34.2",
13
+ "@huggingface/inference": "^4.8.0",
14
+ "axios": "^1.12.2",
15
+ "html2canvas": "^1.4.1",
16
+ "jspdf": "^3.0.2",
17
+ "lucide-react": "^0.544.0",
18
+ "next": "15.5.3",
19
+ "next-auth": "^4.24.11",
20
+ "pptxgenjs": "^4.0.1",
21
  "react": "19.1.0",
22
+ "react-dom": "19.1.0"
 
23
  },
24
  "devDependencies": {
25
+ "@eslint/eslintrc": "^3",
26
+ "@tailwindcss/postcss": "^4",
27
  "@types/node": "^20",
28
  "@types/react": "^19",
29
  "@types/react-dom": "^19",
 
 
30
  "eslint": "^9",
31
  "eslint-config-next": "15.5.3",
32
+ "tailwindcss": "^4",
33
+ "typescript": "^5"
34
  }
35
+ }