Ticker

10/recent/ticker-posts

Ads

Gemini AI Video Creator

AI Video Creator

Powered by Gemini & Ginigen Flux

Your video will appear here

is in your HTML and loaded correctly. Check browser console for network errors or ad-blocker interference."); throw new Error("Gemini AI SDK not loaded. Check browser console for script loading errors (e.g., network issues, ad-blockers)."); } // Check API Key configuration (and warn about the public key) if (GEMINI_API_KEY === "YOUR_GEMINI_API_KEY" || !GEMINI_API_KEY) { throw new Error("Gemini API Key is not configured. Please set it in the script."); } else if (GEMINI_API_KEY === "AIzaSyB-AX1KFYjavqGmnb2TUV_s29sDU-lZIis") { console.warn("CRITICAL SECURITY WARNING: Using a publicly shared/compromised API key. This key should be revoked and replaced with a new, private key for any real use. This is for local testing ONLY."); } const { GoogleGenerativeAI } = genAI; // Destructure from the global 'genAI' object const ai = new GoogleGenerativeAI(GEMINI_API_KEY); // UI mentions Gemini 1.5 Flash. If you have access and intend to use it, // change "gemini-pro" to "gemini-1.5-flash-latest" or your specific model name. const model = ai.getGenerativeModel({ model: "gemini-pro" }); console.log("Sending prompt to Gemini SDK:", promptContent.substring(0, 100) + "..."); // Log snippet const result = await model.generateContent(promptContent); const response = result.response; if (!response) { // Attempt to get more details from the result if response is falsy let feedbackInfo = ""; if (result && result.promptFeedback) { feedbackInfo = ` Prompt Feedback: ${JSON.stringify(result.promptFeedback)}`; } throw new Error(`Gemini API returned an empty response structure.${feedbackInfo}`); } const rawText = response.text(); console.log("Gemini SDK extracted raw text:", rawText); if (!rawText || rawText.trim() === "") { let feedbackInfo = ""; if (response.promptFeedback) { feedbackInfo = ` Prompt Feedback: ${JSON.stringify(response.promptFeedback)}`; } else if (result && result.promptFeedback) { feedbackInfo = ` Prompt Feedback: ${JSON.stringify(result.promptFeedback)}`; } throw new Error(`Gemini API returned empty text content.${feedbackInfo}`); } // Clean and parse JSON (remove potential markdown backticks) const jsonString = rawText.replace(/```json/g, '').replace(/```/g, '').trim(); console.log("Gemini API cleaned JSON string:", jsonString); let parsedJson; try { parsedJson = JSON.parse(jsonString); } catch (jsonError) { console.error("Failed to parse JSON from Gemini. Raw text:", rawText); throw new Error(`Failed to parse JSON response from Gemini: ${jsonError.message}.`); } if (!parsedJson.prompt || !parsedJson.visual_description) { console.warn("Gemini response might be missing expected fields. Parsed:", parsedJson); throw new Error("Gemini response is missing required script details (e.g., 'prompt' or 'visual_description')."); } return parsedJson; } catch (error) { console.error("Error during Gemini script generation:", error); let errorMessage = `Error during Gemini script generation: ${error.message}`; // Check if error object has response and promptFeedback for more specific Gemini errors if (error.response && error.response.promptFeedback) { console.error("Gemini Prompt Feedback:", error.response.promptFeedback); errorMessage += ` (Safety/Feedback: ${JSON.stringify(error.response.promptFeedback)})`; } throw new Error(errorMessage); } } /** * Calls the Ginigen Flux API to generate the video based on the script. * THIS IS CURRENTLY A MOCK/PLACEHOLDER. * @param {Object} script - The detailed video script. * @param {string} style - The selected video style. * @param {number} duration - The selected video duration. * @returns {Promise} A promise that resolves with the URL of the generated video. * @throws {Error} If the Ginigen API call fails or returns no video data. */ async function generateVideoWithGinigen(script, style, duration) { updateProgress(40); // Simulate progress for demo purposes as the actual API call is mocked for (let i = 41; i <= 90; i += Math.floor(Math.random() * 5) + 1) { await new Promise(resolve => setTimeout(resolve, 200 + Math.random() * 300)); updateProgress(Math.min(i, 90)); } try { // --- THIS SECTION IS A MOCK --- console.log("Simulating Ginigen Flux video generation..."); await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate network delay const placeholderVideos = [ "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4", ]; currentVideoUrl = placeholderVideos[Math.floor(Math.random() * placeholderVideos.length)]; updateProgress(95); return currentVideoUrl; // --- END OF MOCK SECTION --- } catch (error) { console.error("Error during Ginigen video generation:", error); throw new Error(`Error during Ginigen video generation: ${error.message}`); } } /** * Displays the generated video in the UI and updates button visibility. * @param {string} videoUrl - The URL of the generated video. */ function showVideoResult(videoUrl) { elements.generatedVideo.src = videoUrl; elements.generatedVideo.classList.remove('hidden'); elements.placeholder.classList.add('hidden'); elements.downloadBtn.classList.remove('hidden'); elements.regenerateBtn.classList.remove('hidden'); elements.generatedVideo.load(); elements.generatedVideo.play().catch(e => console.warn("Video autoplay was prevented:", e)); } /** * Triggers the download of the current generated video. */ function downloadVideo() { if (!currentVideoUrl) { showError("No video to download."); return; } const a = document.createElement('a'); a.href = currentVideoUrl; const fileNameFromPrompt = elements.prompt.value.trim().toLowerCase().replace(/\s+/g, '-').substring(0, 30) || "ai-video"; a.download = `${fileNameFromPrompt}-${Date.now()}.mp4`; document.body.appendChild(a); a.click(); document.body.removeChild(a); if (currentVideoUrl.startsWith('blob:')) { // Only revoke if it's an object URL URL.revokeObjectURL(a.href); } } /** * Sets the loading state for the UI elements (buttons, inputs, spinner). * @param {boolean} isLoading - True to activate loading state, false to deactivate. */ function setLoadingState(isLoading) { elements.generateBtn.disabled = isLoading; elements.regenerateBtn.disabled = isLoading; // Disable regenerate during generation elements.btnText.textContent = isLoading ? "Generating..." : "Generate Video"; elements.loadingSpinner.classList.toggle('hidden', !isLoading); elements.prompt.disabled = isLoading; elements.style.disabled = isLoading; elements.duration.disabled = isLoading; } /** * Displays an error message in the dedicated error area. * @param {string} message - The error message text. */ function showError(message) { elements.errorMessage.textContent = message; elements.errorMessage.classList.remove('hidden'); } /** * Hides the error message from the display. */ function hideError() { elements.errorMessage.classList.add('hidden'); elements.errorMessage.textContent = ""; // Clear previous message } /** * Updates the progress bar width and percentage text. * @param {number} percent - The progress percentage (0-100). */ function updateProgress(percent) { const p = Math.max(0, Math.min(100, percent)); // Clamp between 0 and 100 elements.progressBar.style.width = `${p}%`; elements.progressPercent.textContent = `${Math.round(p)}%`; } /** * Updates the content and styling of the video placeholder. * @param {string} message - The message to display in the placeholder. * @param {boolean} isError - If true, styles the placeholder for an error message. */ function updatePlaceholder(message, isError = false) { elements.placeholder.innerHTML = `
${isError ? '' : ''}

${message}

`; }

Post a Comment

0 Comments