Spaces:
Build error
Build error
| import React, { useState, useEffect } from 'react'; | |
| import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; | |
| import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; | |
| import { Avatar } from 'lucide-react'; | |
| // AI Tutor Avatar Component | |
| const TutorAvatar = ({ state = 'neutral', speaking = false }) => { | |
| const [isBlinking, setIsBlinking] = useState(false); | |
| useEffect(() => { | |
| const blinkInterval = setInterval(() => { | |
| setIsBlinking(true); | |
| setTimeout(() => setIsBlinking(false), 200); | |
| }, Math.random() * 4000 + 2000); | |
| return () => clearInterval(blinkInterval); | |
| }, []); | |
| return ( | |
| <div className="flex justify-center items-center p-4"> | |
| <svg | |
| viewBox="0 0 100 100" | |
| className="w-32 h-32 transition-transform duration-300 hover:scale-110" | |
| > | |
| {/* Avatar face */} | |
| <circle cx="50" cy="50" r="45" className="fill-blue-500" /> | |
| {/* Eyes */} | |
| {isBlinking ? ( | |
| <g> | |
| <line x1="30" y1="40" x2="40" y2="40" stroke="white" strokeWidth="3" /> | |
| <line x1="60" y1="40" x2="70" y2="40" stroke="white" strokeWidth="3" /> | |
| </g> | |
| ) : ( | |
| <g> | |
| <circle cx="35" cy="40" r="5" fill="white" /> | |
| <circle cx="65" cy="40" r="5" fill="white" /> | |
| </g> | |
| )} | |
| {/* Mouth based on state */} | |
| <path | |
| d={ | |
| state === 'happy' | |
| ? 'M 30 60 Q 50 80 70 60' | |
| : state === 'thinking' | |
| ? 'M 30 65 Q 50 65 70 65' | |
| : 'M 30 60 Q 50 70 70 60' | |
| } | |
| stroke="white" | |
| fill="none" | |
| strokeWidth="3" | |
| className={speaking ? 'animate-bounce' : ''} | |
| /> | |
| </svg> | |
| </div> | |
| ); | |
| }; | |
| // Chat Message Component | |
| const ChatMessage = ({ message, role }) => ( | |
| <div className={`flex ${role === 'user' ? 'justify-end' : 'justify-start'} mb-4`}> | |
| <div className={`max-w-[80%] rounded-lg p-3 ${ | |
| role === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-100' | |
| }`}> | |
| {message} | |
| </div> | |
| </div> | |
| ); | |
| // Learning Module Component | |
| const LearningModule = ({ module, onComplete }) => ( | |
| <Card className="mb-4"> | |
| <CardHeader> | |
| <CardTitle>{module.name}</CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <div className="prose dark:prose-invert"> | |
| <div className="mb-4"> | |
| <h4 className="font-semibold">Introduction</h4> | |
| <p>{module.content.introduction}</p> | |
| </div> | |
| <div className="mb-4"> | |
| <h4 className="font-semibold">Key Points</h4> | |
| <ul> | |
| {module.content.key_points.map((point, idx) => ( | |
| <li key={idx}>{point}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| <div className="mb-4"> | |
| <h4 className="font-semibold">Examples</h4> | |
| <ul> | |
| {module.content.examples.map((example, idx) => ( | |
| <li key={idx}>{example}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| <div className="mb-4"> | |
| <h4 className="font-semibold">Practice Problems</h4> | |
| <ol> | |
| {module.content.practice_problems.map((problem, idx) => ( | |
| <li key={idx}>{problem}</li> | |
| ))} | |
| </ol> | |
| </div> | |
| <button | |
| onClick={onComplete} | |
| className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition" | |
| > | |
| Mark as Complete | |
| </button> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| ); | |
| // Main App Component | |
| const App = () => { | |
| const [activeTab, setActiveTab] = useState('learning'); | |
| const [messages, setMessages] = useState([]); | |
| const [userInput, setUserInput] = useState(''); | |
| const [tutorState, setTutorState] = useState('neutral'); | |
| const [selectedPath, setSelectedPath] = useState(null); | |
| // Simulated learning paths data (would come from API) | |
| const learningPaths = { | |
| 'physics_mechanics': { | |
| name: 'Classical Mechanics', | |
| // ... rest of the data structure | |
| }, | |
| 'ai_fundamentals': { | |
| name: 'AI Fundamentals', | |
| // ... rest of the data structure | |
| } | |
| }; | |
| const handleSendMessage = async () => { | |
| if (!userInput.trim()) return; | |
| // Add user message | |
| setMessages(prev => [...prev, { role: 'user', content: userInput }]); | |
| setTutorState('thinking'); | |
| try { | |
| // API call to get AI response | |
| const response = await fetch('/api/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ message: userInput }) | |
| }); | |
| const data = await response.json(); | |
| // Add AI response | |
| setMessages(prev => [...prev, { role: 'assistant', content: data.response }]); | |
| setTutorState('happy'); | |
| } catch (error) { | |
| console.error('Error:', error); | |
| setTutorState('neutral'); | |
| } | |
| setUserInput(''); | |
| }; | |
| return ( | |
| <div className="min-h-screen bg-gray-50"> | |
| <header className="bg-white shadow-sm"> | |
| <div className="max-w-7xl mx-auto px-4 py-4"> | |
| <h1 className="text-2xl font-bold text-gray-900">🎓 EduAI Platform</h1> | |
| </div> | |
| </header> | |
| <main className="max-w-7xl mx-auto px-4 py-6"> | |
| <Tabs value={activeTab} onValueChange={setActiveTab}> | |
| <TabsList> | |
| <TabsTrigger value="learning">📚 Learning Paths</TabsTrigger> | |
| <TabsTrigger value="tutor">🤖 AI Tutor</TabsTrigger> | |
| <TabsTrigger value="playground">💻 Code Playground</TabsTrigger> | |
| </TabsList> | |
| <TabsContent value="learning"> | |
| {/* Learning Paths Content */} | |
| <div className="grid grid-cols-1 gap-6"> | |
| {Object.entries(learningPaths).map(([id, path]) => ( | |
| <Card key={id}> | |
| <CardHeader> | |
| <CardTitle>{path.name}</CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| {/* Add learning path content */} | |
| </CardContent> | |
| </Card> | |
| ))} | |
| </div> | |
| </TabsContent> | |
| <TabsContent value="tutor"> | |
| {/* AI Tutor Content */} | |
| <div className="flex flex-col h-[600px]"> | |
| <TutorAvatar state={tutorState} /> | |
| <div className="flex-1 overflow-y-auto mb-4 space-y-4"> | |
| {messages.map((msg, idx) => ( | |
| <ChatMessage key={idx} {...msg} /> | |
| ))} | |
| </div> | |
| <div className="flex gap-2"> | |
| <input | |
| type="text" | |
| value={userInput} | |
| onChange={(e) => setUserInput(e.target.value)} | |
| onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()} | |
| placeholder="Ask your question..." | |
| className="flex-1 p-2 border rounded" | |
| /> | |
| <button | |
| onClick={handleSendMessage} | |
| className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" | |
| > | |
| Send | |
| </button> | |
| </div> | |
| </div> | |
| </TabsContent> | |
| <TabsContent value="playground"> | |
| {/* Code Playground Content */} | |
| <Card> | |
| <CardContent> | |
| <textarea | |
| className="w-full h-64 font-mono p-4 border rounded" | |
| placeholder="Write your Python code here..." | |
| /> | |
| <button className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"> | |
| Run Code | |
| </button> | |
| </CardContent> | |
| </Card> | |
| </TabsContent> | |
| </Tabs> | |
| </main> | |
| </div> | |
| ); | |
| }; | |
| export default App; |