mgbam commited on
Commit
0e14b98
·
verified ·
1 Parent(s): 414512a

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -726
app.py DELETED
@@ -1,726 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { ChevronRight, Play, Download, Users, Clock, DollarSign, CheckCircle, Loader, Zap, BookOpen, Code, Mic, AlertCircle, Settings } from 'lucide-react';
3
-
4
- const WorkshopGenerator = () => {
5
- const [currentStep, setCurrentStep] = useState('setup');
6
- const [apiKey, setApiKey] = useState('');
7
- const [workshopData, setWorkshopData] = useState({
8
- topic: '',
9
- audience: '',
10
- duration: '90',
11
- difficulty: 'intermediate'
12
- });
13
- const [generatedContent, setGeneratedContent] = useState(null);
14
- const [isGenerating, setIsGenerating] = useState(false);
15
- const [activeAgent, setActiveAgent] = useState('');
16
- const [error, setError] = useState('');
17
-
18
- const agents = [
19
- { id: 'topic', name: 'Topic Agent', icon: BookOpen, description: 'Analyzing topic and creating learning path' },
20
- { id: 'content', name: 'Content Agent', icon: Users, description: 'Writing module scripts and speaker notes' },
21
- { id: 'slide', name: 'Slide Agent', icon: Play, description: 'Generating presentation slides' },
22
- { id: 'code', name: 'Code Agent', icon: Code, description: 'Creating hands-on exercises' }
23
- ];
24
-
25
- // Real Claude API call function with proper authentication
26
- const callClaudeAPI = async (prompt, maxTokens = 2000) => {
27
- try {
28
- const headers = {
29
- "Content-Type": "application/json",
30
- };
31
-
32
- // Add API key for external deployment, or use built-in access for Claude.ai
33
- if (apiKey && apiKey.startsWith('sk-ant-')) {
34
- headers["x-api-key"] = apiKey;
35
- }
36
-
37
- const response = await fetch("https://api.anthropic.com/v1/messages", {
38
- method: "POST",
39
- headers: headers,
40
- body: JSON.stringify({
41
- model: "claude-sonnet-4-20250514",
42
- max_tokens: maxTokens,
43
- messages: [
44
- { role: "user", content: prompt }
45
- ]
46
- })
47
- });
48
-
49
- if (!response.ok) {
50
- const errorText = await response.text();
51
- throw new Error(`API request failed: ${response.status} - ${errorText}`);
52
- }
53
-
54
- const data = await response.json();
55
- return data.content[0].text;
56
- } catch (error) {
57
- console.error("Claude API Error:", error);
58
- throw error;
59
- }
60
- };
61
-
62
- // Topic Agent - Creates learning outline
63
- const topicAgent = async (topic, audience, duration, difficulty) => {
64
- const prompt = `You are an expert corporate trainer creating a workshop outline.
65
-
66
- Topic: ${topic}
67
- Audience: ${audience}
68
- Duration: ${duration} minutes
69
- Difficulty: ${difficulty}
70
-
71
- Create a comprehensive workshop structure. Respond ONLY with valid JSON in this exact format:
72
-
73
- {
74
- "title": "Workshop title",
75
- "objective": "Main learning objective",
76
- "modules": [
77
- {
78
- "name": "Module 1 name",
79
- "duration": 20,
80
- "objectives": ["objective 1", "objective 2"],
81
- "key_points": ["point 1", "point 2", "point 3"]
82
- }
83
- ],
84
- "target_outcomes": ["outcome 1", "outcome 2"],
85
- "prerequisites": ["prereq 1", "prereq 2"],
86
- "difficulty_level": "${difficulty}"
87
- }
88
-
89
- DO NOT include any text outside the JSON structure.`;
90
-
91
- return await callClaudeAPI(prompt, 1500);
92
- };
93
-
94
- // Content Agent - Creates detailed content
95
- const contentAgent = async (topicStructure, topic, audience) => {
96
- const prompt = `You are a corporate training content writer. Create detailed workshop content based on this structure:
97
-
98
- ${topicStructure}
99
-
100
- Topic: ${topic}
101
- Audience: ${audience}
102
-
103
- Generate comprehensive content. Respond ONLY with valid JSON:
104
-
105
- {
106
- "speaker_notes": {
107
- "introduction": "Detailed intro script with talking points",
108
- "modules": [
109
- {
110
- "module_name": "Name",
111
- "opening": "Module opening script",
112
- "main_content": "Detailed teaching content with examples",
113
- "activities": "Instructions for hands-on activities",
114
- "closing": "Module wrap-up and transition"
115
- }
116
- ],
117
- "conclusion": "Workshop conclusion script"
118
- },
119
- "participant_materials": {
120
- "worksheets": ["Worksheet 1 description", "Worksheet 2 description"],
121
- "reference_guides": ["Guide 1 content outline", "Guide 2 content outline"]
122
- },
123
- "assessment": {
124
- "quiz_questions": [
125
- {
126
- "question": "Question text",
127
- "type": "multiple_choice",
128
- "options": ["A", "B", "C", "D"],
129
- "correct_answer": "A",
130
- "explanation": "Why this is correct"
131
- }
132
- ]
133
- }
134
- }
135
-
136
- DO NOT include any text outside the JSON structure.`;
137
-
138
- return await callClaudeAPI(prompt, 3000);
139
- };
140
-
141
- // Slide Agent - Creates presentation structure
142
- const slideAgent = async (contentData, topic) => {
143
- const prompt = `You are a presentation designer. Create a professional slide deck structure based on this workshop content:
144
-
145
- ${contentData}
146
-
147
- Topic: ${topic}
148
-
149
- Generate slide-by-slide content. Respond ONLY with valid JSON:
150
-
151
- {
152
- "slides": [
153
- {
154
- "slide_number": 1,
155
- "title": "Slide title",
156
- "type": "title_slide",
157
- "content": {
158
- "main_text": "Primary text content",
159
- "bullet_points": ["Point 1", "Point 2"],
160
- "notes": "Speaker notes for this slide"
161
- },
162
- "design_hints": {
163
- "layout": "title_and_content",
164
- "visual_elements": ["chart", "diagram", "icon"],
165
- "color_scheme": "professional_blue"
166
- }
167
- }
168
- ],
169
- "slide_count": 24,
170
- "estimated_presentation_time": "75 minutes"
171
- }
172
-
173
- Create exactly enough slides for the workshop duration. DO NOT include any text outside the JSON structure.`;
174
-
175
- return await callClaudeAPI(prompt, 4000);
176
- };
177
-
178
- // Code Agent - Creates practical exercises
179
- const codeAgent = async (topicStructure, topic, audience, difficulty) => {
180
- const prompt = `You are a technical training specialist. Create hands-on coding exercises based on:
181
-
182
- ${topicStructure}
183
-
184
- Topic: ${topic}
185
- Audience: ${audience}
186
- Difficulty: ${difficulty}
187
-
188
- Generate practical coding exercises. Respond ONLY with valid JSON:
189
-
190
- {
191
- "exercises": [
192
- {
193
- "title": "Exercise title",
194
- "duration": 15,
195
- "difficulty": "beginner",
196
- "description": "What participants will build",
197
- "setup_instructions": "Step-by-step setup",
198
- "starter_code": "// Starter code template",
199
- "solution_code": "// Complete solution",
200
- "learning_objectives": ["objective 1", "objective 2"],
201
- "common_mistakes": ["mistake 1", "mistake 2"]
202
- }
203
- ],
204
- "code_demos": [
205
- {
206
- "title": "Demo title",
207
- "code": "# Complete demo code",
208
- "explanation": "Step-by-step explanation"
209
- }
210
- ],
211
- "resources": {
212
- "documentation_links": ["https://example.com/docs"],
213
- "additional_tools": ["Tool 1", "Tool 2"]
214
- }
215
- }
216
-
217
- Focus on practical, business-relevant examples. DO NOT include any text outside the JSON structure.`;
218
-
219
- return await callClaudeAPI(prompt, 3000);
220
- };
221
-
222
- const testAPIConnection = async () => {
223
- try {
224
- const testPrompt = "Respond with exactly: API_TEST_SUCCESS";
225
- const response = await callClaudeAPI(testPrompt, 50);
226
- return response.includes("API_TEST_SUCCESS");
227
- } catch (error) {
228
- console.error("API test failed:", error);
229
- return false;
230
- }
231
- };
232
-
233
- const handleAPISetup = async () => {
234
- setError('');
235
-
236
- // Test API connection
237
- const isConnected = await testAPIConnection();
238
- if (isConnected) {
239
- setCurrentStep('input');
240
- } else {
241
- setError('API connection failed. Please check your API key or try again.');
242
- }
243
- };
244
-
245
- const generateWorkshop = async () => {
246
- setIsGenerating(true);
247
- setCurrentStep('generating');
248
- setError('');
249
-
250
- try {
251
- // Step 1: Topic Agent
252
- setActiveAgent('topic');
253
- const topicResponse = await topicAgent(
254
- workshopData.topic,
255
- workshopData.audience,
256
- workshopData.duration,
257
- workshopData.difficulty
258
- );
259
-
260
- let topicData;
261
- try {
262
- const cleanResponse = topicResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
263
- topicData = JSON.parse(cleanResponse);
264
- } catch (parseError) {
265
- console.error("Topic parsing error:", parseError);
266
- throw new Error("Failed to parse topic structure");
267
- }
268
-
269
- // Step 2: Content Agent
270
- setActiveAgent('content');
271
- const contentResponse = await contentAgent(
272
- JSON.stringify(topicData),
273
- workshopData.topic,
274
- workshopData.audience
275
- );
276
-
277
- let contentData;
278
- try {
279
- const cleanResponse = contentResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
280
- contentData = JSON.parse(cleanResponse);
281
- } catch (parseError) {
282
- console.error("Content parsing error:", parseError);
283
- throw new Error("Failed to parse content structure");
284
- }
285
-
286
- // Step 3: Slide Agent
287
- setActiveAgent('slide');
288
- const slideResponse = await slideAgent(
289
- JSON.stringify(contentData),
290
- workshopData.topic
291
- );
292
-
293
- let slideData;
294
- try {
295
- const cleanResponse = slideResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
296
- slideData = JSON.parse(cleanResponse);
297
- } catch (parseError) {
298
- console.error("Slide parsing error:", parseError);
299
- throw new Error("Failed to parse slide structure");
300
- }
301
-
302
- // Step 4: Code Agent
303
- setActiveAgent('code');
304
- const codeResponse = await codeAgent(
305
- JSON.stringify(topicData),
306
- workshopData.topic,
307
- workshopData.audience,
308
- workshopData.difficulty
309
- );
310
-
311
- let codeData;
312
- try {
313
- const cleanResponse = codeResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
314
- codeData = JSON.parse(cleanResponse);
315
- } catch (parseError) {
316
- console.error("Code parsing error:", parseError);
317
- throw new Error("Failed to parse code structure");
318
- }
319
-
320
- // Combine all generated content
321
- setGeneratedContent({
322
- topic: topicData,
323
- content: contentData,
324
- slides: slideData,
325
- code: codeData,
326
- metadata: {
327
- title: topicData.title,
328
- modules: topicData.modules?.length || 4,
329
- slideCount: slideData.slide_count || slideData.slides?.length || 0,
330
- exercises: codeData.exercises?.length || 0,
331
- estimatedValue: calculateWorkshopValue(workshopData.duration, workshopData.audience),
332
- generatedAt: new Date().toISOString()
333
- }
334
- });
335
-
336
- setCurrentStep('preview');
337
- } catch (error) {
338
- console.error("Workshop generation error:", error);
339
- setError(`Generation failed: ${error.message}`);
340
- setCurrentStep('input');
341
- } finally {
342
- setIsGenerating(false);
343
- setActiveAgent('');
344
- }
345
- };
346
-
347
- const calculateWorkshopValue = (duration, audience) => {
348
- const basePrices = {
349
- 'executives': 200,
350
- 'managers': 150,
351
- 'developers': 120,
352
- 'analysts': 100,
353
- 'mixed': 140
354
- };
355
-
356
- const basePrice = basePrices[audience] || 120;
357
- const durationMultiplier = parseInt(duration) / 60;
358
- const estimatedValue = Math.round(basePrice * durationMultiplier) * 100;
359
-
360
- return `$${estimatedValue.toLocaleString()}`;
361
- };
362
-
363
- const downloadWorkshop = () => {
364
- if (!generatedContent) return;
365
-
366
- const workshopPackage = {
367
- ...generatedContent,
368
- generated_by: "AI Workshop in a Box",
369
- export_date: new Date().toISOString(),
370
- workshop_config: workshopData,
371
- api_version: "claude-sonnet-4-20250514"
372
- };
373
-
374
- const dataStr = JSON.stringify(workshopPackage, null, 2);
375
- const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
376
-
377
- const exportFileDefaultName = `workshop-${workshopData.topic.replace(/\s+/g, '-').toLowerCase()}.json`;
378
-
379
- const linkElement = document.createElement('a');
380
- linkElement.setAttribute('href', dataUri);
381
- linkElement.setAttribute('download', exportFileDefaultName);
382
- linkElement.click();
383
- };
384
-
385
- const handleInputChange = (field, value) => {
386
- setWorkshopData(prev => ({ ...prev, [field]: value }));
387
- };
388
-
389
- return (
390
- <div className="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 text-white">
391
- {/* Header */}
392
- <div className="bg-black/20 backdrop-blur-lg border-b border-white/10">
393
- <div className="max-w-7xl mx-auto px-6 py-4">
394
- <div className="flex items-center justify-between">
395
- <div className="flex items-center space-x-3">
396
- <div className="w-10 h-10 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-lg flex items-center justify-center">
397
- <Zap className="w-6 h-6 text-white" />
398
- </div>
399
- <div>
400
- <h1 className="text-2xl font-bold">AI Workshop in a Box</h1>
401
- <p className="text-blue-200 text-sm">Production Multi-Agent Generator</p>
402
- </div>
403
- </div>
404
- <div className="flex items-center space-x-4">
405
- <div className="text-right">
406
- <div className="text-2xl font-bold text-green-400">$10K+</div>
407
- <div className="text-sm text-gray-300">per workshop</div>
408
- </div>
409
- </div>
410
- </div>
411
- </div>
412
- </div>
413
-
414
- <div className="max-w-7xl mx-auto px-6 py-8">
415
- {/* Error Display */}
416
- {error && (
417
- <div className="max-w-2xl mx-auto mb-6">
418
- <div className="bg-red-500/20 border border-red-400 rounded-lg p-4 flex items-center space-x-3">
419
- <AlertCircle className="w-5 h-5 text-red-400" />
420
- <span className="text-red-200">{error}</span>
421
- </div>
422
- </div>
423
- )}
424
-
425
- {/* Step 0: API Setup */}
426
- {currentStep === 'setup' && (
427
- <div className="max-w-2xl mx-auto">
428
- <div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20">
429
- <div className="text-center mb-6">
430
- <Settings className="w-16 h-16 text-cyan-400 mx-auto mb-4" />
431
- <h2 className="text-3xl font-bold mb-2">API Configuration</h2>
432
- <p className="text-blue-200">Set up your Claude API access to start generating workshops</p>
433
- </div>
434
-
435
- <div className="space-y-6">
436
- <div>
437
- <label className="block text-sm font-medium mb-2">
438
- Claude API Key (Optional for Claude.ai)
439
- </label>
440
- <input
441
- type="password"
442
- placeholder="sk-ant-api03-... (leave blank if running in Claude.ai)"
443
- className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-cyan-400 focus:border-transparent text-white placeholder-gray-300"
444
- value={apiKey}
445
- onChange={(e) => setApiKey(e.target.value)}
446
- />
447
- <p className="text-xs text-gray-400 mt-2">
448
- • Leave blank when running in Claude.ai (uses built-in access)<br/>
449
- • Required when deploying to your own domain<br/>
450
- • Get your API key from: <span className="text-cyan-400">console.anthropic.com</span>
451
- </p>
452
- </div>
453
-
454
- <div className="bg-blue-500/20 border border-blue-400/30 rounded-lg p-4">
455
- <h4 className="font-semibold text-blue-200 mb-2">Deployment Options:</h4>
456
- <div className="text-sm text-blue-100 space-y-1">
457
- <div>• <strong>Claude.ai:</strong> No API key needed (current environment)</div>
458
- <div>• <strong>Your Domain:</strong> Add API key to environment variables</div>
459
- <div>• <strong>GitHub:</strong> Store API key in repository secrets</div>
460
- </div>
461
- </div>
462
-
463
- <button
464
- onClick={handleAPISetup}
465
- className="w-full py-4 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-lg font-semibold text-lg hover:from-cyan-600 hover:to-blue-700 transition-all duration-200 flex items-center justify-center space-x-2"
466
- >
467
- <CheckCircle className="w-5 h-5" />
468
- <span>Test Connection & Continue</span>
469
- </button>
470
- </div>
471
- </div>
472
- </div>
473
- )}
474
-
475
- {/* Step 1: Input */}
476
- {currentStep === 'input' && (
477
- <div className="max-w-2xl mx-auto">
478
- <div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20">
479
- <h2 className="text-3xl font-bold mb-6 text-center">Create Your Workshop</h2>
480
-
481
- <div className="space-y-6">
482
- <div>
483
- <label className="block text-sm font-medium mb-2">Workshop Topic</label>
484
- <input
485
- type="text"
486
- placeholder="e.g., Advanced Prompt Engineering, AI Agents for Business"
487
- className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-cyan-400 focus:border-transparent text-white placeholder-gray-300"
488
- value={workshopData.topic}
489
- onChange={(e) => handleInputChange('topic', e.target.value)}
490
- />
491
- </div>
492
-
493
- <div>
494
- <label className="block text-sm font-medium mb-2">Target Audience</label>
495
- <select
496
- className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-cyan-400 text-white"
497
- value={workshopData.audience}
498
- onChange={(e) => handleInputChange('audience', e.target.value)}
499
- >
500
- <option value="">Select audience</option>
501
- <option value="executives">C-Suite Executives</option>
502
- <option value="managers">Product Managers</option>
503
- <option value="developers">Developers & Engineers</option>
504
- <option value="analysts">Data Analysts</option>
505
- <option value="mixed">Mixed Technical Team</option>
506
- </select>
507
- </div>
508
-
509
- <div className="grid grid-cols-2 gap-4">
510
- <div>
511
- <label className="block text-sm font-medium mb-2">Duration (minutes)</label>
512
- <select
513
- className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-cyan-400 text-white"
514
- value={workshopData.duration}
515
- onChange={(e) => handleInputChange('duration', e.target.value)}
516
- >
517
- <option value="60">60 minutes</option>
518
- <option value="90">90 minutes</option>
519
- <option value="120">2 hours</option>
520
- <option value="240">Half day</option>
521
- </select>
522
- </div>
523
-
524
- <div>
525
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
526
- <select
527
- className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg focus:ring-2 focus:ring-cyan-400 text-white"
528
- value={workshopData.difficulty}
529
- onChange={(e) => handleInputChange('difficulty', e.target.value)}
530
- >
531
- <option value="beginner">Beginner</option>
532
- <option value="intermediate">Intermediate</option>
533
- <option value="advanced">Advanced</option>
534
- </select>
535
- </div>
536
- </div>
537
-
538
- <button
539
- onClick={generateWorkshop}
540
- disabled={!workshopData.topic || !workshopData.audience || isGenerating}
541
- className="w-full py-4 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-lg font-semibold text-lg hover:from-cyan-600 hover:to-blue-700 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center space-x-2"
542
- >
543
- <Zap className="w-5 h-5" />
544
- <span>Generate Workshop</span>
545
- <ChevronRight className="w-5 h-5" />
546
- </button>
547
- </div>
548
-
549
- <div className="mt-6 pt-6 border-t border-white/10">
550
- <button
551
- onClick={() => setCurrentStep('setup')}
552
- className="text-gray-300 hover:text-white text-sm flex items-center space-x-2"
553
- >
554
- <Settings className="w-4 h-4" />
555
- <span>Change API Settings</span>
556
- </button>
557
- </div>
558
- </div>
559
- </div>
560
- )}
561
-
562
- {/* Step 2: Generation Process */}
563
- {currentStep === 'generating' && (
564
- <div className="max-w-4xl mx-auto">
565
- <div className="text-center mb-8">
566
- <h2 className="text-3xl font-bold mb-4">Generating Your Workshop</h2>
567
- <p className="text-blue-200">Multi-agent system creating your complete training package...</p>
568
- </div>
569
-
570
- <div className="grid gap-6">
571
- {agents.map((agent, index) => {
572
- const isActive = activeAgent === agent.id;
573
- const isComplete = agents.findIndex(a => a.id === activeAgent) > index;
574
- const Icon = agent.icon;
575
-
576
- return (
577
- <div
578
- key={agent.id}
579
- className={`p-6 rounded-xl border transition-all duration-500 ${
580
- isActive
581
- ? 'bg-cyan-500/20 border-cyan-400 shadow-lg shadow-cyan-500/25'
582
- : isComplete
583
- ? 'bg-green-500/20 border-green-400'
584
- : 'bg-white/5 border-white/10'
585
- }`}
586
- >
587
- <div className="flex items-center space-x-4">
588
- <div className={`p-3 rounded-lg ${
589
- isActive ? 'bg-cyan-500' : isComplete ? 'bg-green-500' : 'bg-white/10'
590
- }`}>
591
- {isActive ? (
592
- <Loader className="w-6 h-6 animate-spin" />
593
- ) : isComplete ? (
594
- <CheckCircle className="w-6 h-6" />
595
- ) : (
596
- <Icon className="w-6 h-6" />
597
- )}
598
- </div>
599
- <div className="flex-1">
600
- <h3 className="font-semibold text-lg">{agent.name}</h3>
601
- <p className="text-gray-300">{agent.description}</p>
602
- </div>
603
- {isActive && (
604
- <div className="flex space-x-1">
605
- <div className="w-2 h-2 bg-cyan-400 rounded-full animate-bounce"></div>
606
- <div className="w-2 h-2 bg-cyan-400 rounded-full animate-bounce" style={{animationDelay: '0.1s'}}></div>
607
- <div className="w-2 h-2 bg-cyan-400 rounded-full animate-bounce" style={{animationDelay: '0.2s'}}></div>
608
- </div>
609
- )}
610
- </div>
611
- </div>
612
- );
613
- })}
614
- </div>
615
- </div>
616
- )}
617
-
618
- {/* Step 3: Preview & Download */}
619
- {currentStep === 'preview' && generatedContent && (
620
- <div className="max-w-6xl mx-auto">
621
- <div className="text-center mb-8">
622
- <h2 className="text-3xl font-bold mb-4">Workshop Generated Successfully! 🎉</h2>
623
- <p className="text-blue-200 text-lg">Your complete training package is ready for delivery</p>
624
- </div>
625
-
626
- <div className="grid lg:grid-cols-3 gap-8">
627
- {/* Workshop Overview */}
628
- <div className="lg:col-span-2">
629
- <div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border border-white/20">
630
- <h3 className="text-2xl font-bold mb-6">{generatedContent.metadata.title}</h3>
631
-
632
- <div className="grid md:grid-cols-3 gap-6 mb-8">
633
- <div className="text-center">
634
- <div className="text-3xl font-bold text-cyan-400">{generatedContent.metadata.slideCount}</div>
635
- <div className="text-sm text-gray-300">Slides</div>
636
- </div>
637
- <div className="text-center">
638
- <div className="text-3xl font-bold text-green-400">{generatedContent.metadata.exercises}</div>
639
- <div className="text-sm text-gray-300">Exercises</div>
640
- </div>
641
- <div className="text-center">
642
- <div className="text-3xl font-bold text-purple-400">{workshopData.duration}m</div>
643
- <div className="text-sm text-gray-300">Duration</div>
644
- </div>
645
- </div>
646
-
647
- <div className="space-y-3">
648
- <h4 className="font-semibold text-lg mb-3">Workshop Modules:</h4>
649
- {generatedContent.topic.modules?.map((module, index) => (
650
- <div key={index} className="flex items-center space-x-3 p-3 bg-white/5 rounded-lg">
651
- <div className="w-8 h-8 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full flex items-center justify-center text-sm font-bold">
652
- {index + 1}
653
- </div>
654
- <div>
655
- <div className="font-medium">{module.name}</div>
656
- <div className="text-sm text-gray-300">{module.duration} minutes</div>
657
- </div>
658
- </div>
659
- )) || <div className="text-gray-400">Modules loaded successfully</div>}
660
- </div>
661
- </div>
662
- </div>
663
-
664
- {/* Actions & Pricing */}
665
- <div className="space-y-6">
666
- <div className="bg-gradient-to-r from-green-500/20 to-emerald-500/20 border border-green-400/30 rounded-2xl p-6 text-center">
667
- <DollarSign className="w-12 h-12 text-green-400 mx-auto mb-4" />
668
- <div className="text-3xl font-bold text-green-400 mb-2">{generatedContent.metadata.estimatedValue}</div>
669
- <div className="text-sm text-green-200">Estimated Workshop Value</div>
670
- </div>
671
-
672
- <div className="space-y-4">
673
- <button
674
- onClick={downloadWorkshop}
675
- className="w-full py-3 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-lg font-semibold hover:from-cyan-600 hover:to-blue-700 transition-all duration-200 flex items-center justify-center space-x-2"
676
- >
677
- <Download className="w-5 h-5" />
678
- <span>Download Package</span>
679
- </button>
680
-
681
- <button className="w-full py-3 bg-white/10 border border-white/20 rounded-lg font-semibold hover:bg-white/20 transition-all duration-200 flex items-center justify-center space-x-2">
682
- <Play className="w-5 h-5" />
683
- <span>Preview Content</span>
684
- </button>
685
-
686
- <button className="w-full py-3 bg-purple-600/20 border border-purple-400/30 rounded-lg font-semibold hover:bg-purple-600/30 transition-all duration-200 flex items-center justify-center space-x-2">
687
- <Users className="w-5 h-5" />
688
- <span>Book Client Demo</span>
689
- </button>
690
- </div>
691
-
692
- <div className="bg-white/5 rounded-xl p-4">
693
- <h4 className="font-semibold mb-2">Package Includes:</h4>
694
- <ul className="text-sm space-y-1 text-gray-300">
695
- <li>• Complete slide deck</li>
696
- <li>• Speaker notes & scripts</li>
697
- <li>• Hands-on exercises</li>
698
- <li>• Code examples</li>
699
- <li>• Assessment materials</li>
700
- <li>• JSON export for customization</li>
701
- </ul>
702
- </div>
703
- </div>
704
- </div>
705
-
706
- <div className="mt-8 text-center">
707
- <button
708
- onClick={() => {
709
- setCurrentStep('input');
710
- setGeneratedContent(null);
711
- setWorkshopData({ topic: '', audience: '', duration: '90', difficulty: 'intermediate' });
712
- setError('');
713
- }}
714
- className="px-6 py-3 bg-white/10 border border-white/20 rounded-lg hover:bg-white/20 transition-all duration-200"
715
- >
716
- Generate Another Workshop
717
- </button>
718
- </div>
719
- </div>
720
- )}
721
- </div>
722
- </div>
723
- );
724
- };
725
-
726
- export default WorkshopGenerator;