// Global variables let currentSlideIndex = 0; let slideInterval; let speechSynthesis = window.speechSynthesis; let currentUtterance = null; let slides = []; const slideDuration = 8000; // 8 seconds per slide // Generate presentation based on topic using OpenAI async function generatePresentation(topic, slideCount) { try { // Show loading state document.querySelector('main').innerHTML = `

Generating your presentation about ${topic}...

`; // Prepare prompt for OpenAI const prompt = `Create a ${slideCount}-slide presentation about "${topic}". For each slide, provide: 1. A concise slide title (max 8 words) 2. Detailed content (3-5 bullet points or 1-2 paragraphs) Format as JSON with array of {title, content}. Include introduction and conclusion slides.`; // Call OpenAI API (you'll need to replace OPENAI_API_KEY with your actual key) // Mock response for testing since we can't use actual API key const mockResponse = { "choices": [{ "message": { "content": JSON.stringify([ { "title": "Introduction to Evaporation", "content": "Evaporation is the process where liquid turns into vapor. It occurs when molecules gain enough energy to escape the liquid's surface. This is a key part of the water cycle." }, { "title": "How Evaporation Works", "content": "Molecules in a liquid move at different speeds. The fastest molecules can break free from the surface. Heat increases the rate of evaporation." }, { "title": "Factors Affecting Evaporation", "content": "Temperature - Higher temps increase evaporation. Surface area - More area means faster evaporation. Humidity - Lower humidity speeds up evaporation. Air flow - Moving air carries away vapor." }, { "title": "Evaporation vs Boiling", "content": "Evaporation happens at any temp below boiling point. It occurs only at the surface. Boiling happens throughout the liquid at a specific temperature." }, { "title": "Applications of Evaporation", "content": "Used in cooling systems like sweating. Important in distillation processes. Used in salt production from seawater. Helps in drying clothes and foods." } ]) } }] }; // Use mock response instead of actual API call const data = mockResponse; method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }, body: JSON.stringify({ model: "gpt-3.5-turbo", messages: [ { role: "user", content: prompt } ], temperature: 0.7 }) }); const data = await response.json(); const content = data.choices[0].message.content; let slideData; try { // Try to parse JSON if returned as JSON string slideData = JSON.parse(content); } catch { // If parsing fails, assume it's text and create slides const sections = content.split('\n\n').filter(s => s.trim().length > 0); slideData = sections.map((section, i) => { const lines = section.split('\n'); const title = lines[0].replace('Title:', '').replace('Slide Title:', '').trim(); const content = lines.slice(1).join('\n').trim(); return { title, content }; }); } // Process into slides slides = []; for (let i = 0; i < slideData.length; i++) { const slide = slideData[i]; slides.push({ image: `http://static.photos/1200x630/${i+1}`, title: slide.title || (i === 0 ? `Introduction to ${topic}` : `${topic}: Key Point ${i}`), text: slide.content || slide.text || `Content for slide ${i+1} about ${topic}` }); } // Start the slideshow startSlideshowWithVoice(); // Start the slideshow without redirect startSlideshowWithVoice(); } catch (error) { console.error('Error generating presentation:', error); // Fallback with better sample content slides = []; for (let i = 0; i < slideCount; i++) { let title, text; if (i === 0) { title = `Introduction to ${topic}`; text = `${topic} is an important process in nature. Let's explore its key aspects in this presentation.`; } else if (i === slideCount - 1) { title = `Conclusion on ${topic}`; text = `We've covered the main points about ${topic}. Thank you for your attention!`; } else { title = `${topic}: Key Aspect ${i}`; text = `This slide discusses important details about ${topic}. Specific information about aspect ${i} would be presented here. For example, we might explain how this relates to the overall topic.`; }); } // Ensure we have at least one slide if (slides.length === 0) { slides.push({ image: `http://static.photos/science/1200x630/1`, title: `Presentation on ${topic}`, text: `This presentation will explore various aspects of ${topic}. Let's begin our journey of discovery!` }); }); // Start the slideshow with fallback content startSlideshowWithVoice(); } } function startSlideshowWithVoice() { // Clear any existing interval if (slideInterval) { clearInterval(slideInterval); } if (currentUtterance) { speechSynthesis.cancel(); } // Start with first slide updateSlide(0); // Set up automatic slideshow slideInterval = setInterval(() => { currentSlideIndex = (currentSlideIndex + 1) % slides.length; updateSlide(currentSlideIndex); }, slideDuration); // Speak the first slide speakCurrentSlide(); } function updateSlide(index) { const slide = slides[index]; const slideshow = document.querySelector('custom-slideshow'); if (slideshow) { slideshow.setAttribute('image', slide.image); slideshow.setAttribute('title', slide.title); slideshow.setAttribute('text', slide.text); slideshow.setAttribute('current-index', index + 1); slideshow.setAttribute('total-slides', slides.length); // Update progress bar updateProgressBar(); } // Speak the new slide content speakCurrentSlide(); } function speakCurrentSlide() { if (currentUtterance) { speechSynthesis.cancel(); } const slide = slides[currentSlideIndex]; const text = `${slide.title}. ${slide.text}`; // Speak both title and content currentUtterance = new SpeechSynthesisUtterance(text); currentUtterance.rate = 1; currentUtterance.pitch = 1; currentUtterance.volume = 1; speechSynthesis.speak(currentUtterance); } function updateProgressBar() { const progressBar = document.querySelector('.progress-fill'); if (progressBar) { progressBar.style.width = '0%'; // Reset animation void progressBar.offsetWidth; progressBar.style.width = '100%'; progressBar.style.transitionDuration = `${slideDuration/1000}s`; } } // Expose controls to the window window.toggleVoice = function() { if (speechSynthesis.speaking) { speechSynthesis.cancel(); } else { speakCurrentSlide(); } }; window.nextSlide = function() { currentSlideIndex = (currentSlideIndex + 1) % slides.length; updateSlide(currentSlideIndex); // Reset interval clearInterval(slideInterval); slideInterval = setInterval(() => { currentSlideIndex = (currentSlideIndex + 1) % slides.length; updateSlide(currentSlideIndex); }, slideDuration); }; window.prevSlide = function() { currentSlideIndex = (currentSlideIndex - 1 + slides.length) % slides.length; updateSlide(currentSlideIndex); // Reset interval clearInterval(slideInterval); slideInterval = setInterval(() => { currentSlideIndex = (currentSlideIndex + 1) % slides.length; updateSlide(currentSlideIndex); }, slideDuration); }; // Pause on hover document.querySelector('custom-slideshow')?.addEventListener('mouseenter', () => { clearInterval(slideInterval); if (currentUtterance) { speechSynthesis.pause(); } }); document.querySelector('custom-slideshow')?.addEventListener('mouseleave', () => { slideInterval = setInterval(() => { currentSlideIndex = (currentSlideIndex + 1) % slides.length; updateSlide(currentSlideIndex); }, slideDuration); if (currentUtterance) { speechSynthesis.resume(); } });