mgbam commited on
Commit
3979311
·
verified ·
1 Parent(s): a2a4fa2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -10
app.py CHANGED
@@ -1,8 +1,9 @@
1
  import React, { useState } from 'react';
2
- import { ChevronRight, Play, Download, Users, Clock, DollarSign, CheckCircle, Loader, Zap, BookOpen, Code, Mic, AlertCircle } from 'lucide-react';
3
 
4
  const WorkshopGenerator = () => {
5
- const [currentStep, setCurrentStep] = useState('input');
 
6
  const [workshopData, setWorkshopData] = useState({
7
  topic: '',
8
  audience: '',
@@ -21,14 +22,21 @@ const WorkshopGenerator = () => {
21
  { id: 'code', name: 'Code Agent', icon: Code, description: 'Creating hands-on exercises' }
22
  ];
23
 
24
- // Real Claude API call function
25
  const callClaudeAPI = async (prompt, maxTokens = 2000) => {
26
  try {
 
 
 
 
 
 
 
 
 
27
  const response = await fetch("https://api.anthropic.com/v1/messages", {
28
  method: "POST",
29
- headers: {
30
- "Content-Type": "application/json",
31
- },
32
  body: JSON.stringify({
33
  model: "claude-sonnet-4-20250514",
34
  max_tokens: maxTokens,
@@ -39,7 +47,8 @@ const WorkshopGenerator = () => {
39
  });
40
 
41
  if (!response.ok) {
42
- throw new Error(`API request failed: ${response.status}`);
 
43
  }
44
 
45
  const data = await response.json();
@@ -210,6 +219,29 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
210
  return await callClaudeAPI(prompt, 3000);
211
  };
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  const generateWorkshop = async () => {
214
  setIsGenerating(true);
215
  setCurrentStep('generating');
@@ -227,7 +259,6 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
227
 
228
  let topicData;
229
  try {
230
- // Clean the response to extract JSON
231
  const cleanResponse = topicResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
232
  topicData = JSON.parse(cleanResponse);
233
  } catch (parseError) {
@@ -336,7 +367,8 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
336
  ...generatedContent,
337
  generated_by: "AI Workshop in a Box",
338
  export_date: new Date().toISOString(),
339
- workshop_config: workshopData
 
340
  };
341
 
342
  const dataStr = JSON.stringify(workshopPackage, null, 2);
@@ -366,7 +398,7 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
366
  </div>
367
  <div>
368
  <h1 className="text-2xl font-bold">AI Workshop in a Box</h1>
369
- <p className="text-blue-200 text-sm">Functional Multi-Agent Generator</p>
370
  </div>
371
  </div>
372
  <div className="flex items-center space-x-4">
@@ -390,6 +422,56 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
390
  </div>
391
  )}
392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  {/* Step 1: Input */}
394
  {currentStep === 'input' && (
395
  <div className="max-w-2xl mx-auto">
@@ -463,6 +545,16 @@ Focus on practical, business-relevant examples. DO NOT include any text outside
463
  <ChevronRight className="w-5 h-5" />
464
  </button>
465
  </div>
 
 
 
 
 
 
 
 
 
 
466
  </div>
467
  </div>
468
  )}
 
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: '',
 
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,
 
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();
 
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');
 
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) {
 
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);
 
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">
 
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">
 
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
  )}