<!-- Title: Text To Video Conversion by Daniel Marcu & Rory Peng -->
<!-- Description: Convert any prompt you wish into a 3 second video that is generated using the Stable Diffuse AI API -->
<!-- Date: 1/12/23 -->
<!-- API Documentation: https://stablediffusionapi.com/docs/ -->
<!-- HTML Structures and Styles -->
<!-- HTML DOM Document write(): https://www.w3schools.com/jsref/met_doc_write.asp -->
document.write(`
<head>
<style>
/* General styles for the page */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
height: 100vh;
}
/* Styles for the left container */
#leftContainer {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* Styles for the right container */
#rightContainer {
flex: 1;
background-color: #2c3e50;
color: #00ff00;
overflow-y: scroll;
max-height: 100vh;
padding: 20px;
box-sizing: border-box;
}
/* Styles for the console title */
#consoleTitle {
text-align: center;
font-size: 18px;
color: #ffffff;
margin-bottom: 10px;
}
/* Styles for the console output */
#console {
width: 100%;
padding: 10px;
font-family: monospace;
white-space: pre-wrap;
margin-bottom: 10px;
overflow: hidden;
}
/* Styles for the result container */
#result {
border: none;
padding: 0;
width: 80%; /* Adjusted width to make the video slightly smaller */
max-width: 640px;
margin-bottom: 20px;
}
/* Styles for the video element */
video {
width: 100%;
max-width: 100%; /* Ensure video doesn't exceed its container */
border-radius: 5px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
/* Styles for buttons and loaders */
#backButton,
.extraButtons {
padding: 10px 20px;
border: none;
margin-top: 10px;
border-radius: 5px;
cursor: pointer;
background-color: #007bff;
color: white;
transition: background-color 0.3s ease;
}
/* Button hover effect */
#backButton:hover,
.extraButtons:hover {
background-color: #0056b3;
}
/* Styles for the loop button in green */
#loopButton.green {
background-color: #4CAF50;
color: white;
}
/* Styles for hidden elements */
.hidden { display: none; }
/* Styles for the loader animation */
.loader {
border: 8px solid #f3f3f3;
border-top: 8px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
/* Keyframe animation for the loader spin */
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Previous styles - retained for reference */
#leftPanelTitle {
font-size: 24px;
color: #333;
margin-bottom: 20px;
}
#apiKeyInput,
#textInput {
padding: 10px;
width: 300px;
margin-bottom: 10px;
border-radius: 5px;
border: 1px solid #ddd;
}
#sendRequest,
#loopButton,
.extraButtons {
padding: 10px 20px;
border: none;
background-color: #007bff;
color: white;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
#sendRequest:hover,
#loopButton:hover,
.extraButtons:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<!-- Left Container for Prompts and Videos -->
<div id="leftContainer">
<!-- Title for the left panel -->
<div id="leftPanelTitle">API Request Interface</div>
<!-- Textbox for API key input -->
<input type="text" id="apiKeyInput" placeholder="Enter your API key...">
<!-- Textbox for input -->
<input type="text" id="textInput" placeholder="Enter prompt here..." onkeydown="if (event.key === 'Enter') sendAPIRequest()">
<!-- Button to trigger the API request -->
<button id="sendRequest" onclick="sendAPIRequest()">Send Request</button>
<br>
<!-- Loading indicator -->
<div id="loading" class="hidden">
<div class="loader"></div>
<p>Loading...</p>
</div>
<!-- Container to display the result or video -->
<div id="result" class="hidden"></div>
<!-- Back button to return to prompts -->
<button id="backButton" class="hidden" onclick="showPrompts()">Back to Prompts</button>
</div>
<!-- Right Container for Console Output -->
<div id="rightContainer">
<div id="consoleTitle">Console</div>
<!-- Console-like output -->
<div id="console"> > Welcome to the API Request Interface! Enter your API key, provide a prompt, and click "Send Request" to initiate the API request. These usually take between 2-5 minutes.
</div>
</div>
<script>
<!-- Global variable to store the API key -->
let apiKey;
<!-- Function to get the API key from the input -->
function getApiKey() {
return document.getElementById('apiKeyInput').value.trim();
}
<!-- Function to log messages to the console-like output -->
function logToConsole(message) {
const consoleOutput = document.getElementById('console');
consoleOutput.innerHTML += message + '<br>';
consoleOutput.scrollTop = consoleOutput.scrollHeight;
}
<!-- Function to show the prompts -->
function showPrompts() {
document.getElementById('result').classList.add('hidden');
document.getElementById('backButton').classList.add('hidden');
document.getElementById('console').innerHTML = '> Welcome to the API Request Interface! Enter your API key, provide a prompt, and click "Send Request" to initiate the API request. These usually take between 2-5 minutes';
document.getElementById('apiKeyInput').classList.remove('hidden');
document.getElementById('textInput').classList.remove('hidden');
document.getElementById('sendRequest').classList.remove('hidden');
}
<!-- Function to hide the prompts -->
function hidePrompts() {
document.getElementById('apiKeyInput').classList.add('hidden');
document.getElementById('textInput').classList.add('hidden');
document.getElementById('sendRequest').classList.add('hidden');
}
<!-- Function to send the API request -->
function sendAPIRequest() {
apiKey = getApiKey(); // Get the API key from the input
const textInput = document.getElementById('textInput');
const promptText = textInput.value; // Get the value from the text input
const resultContainer = document.getElementById('result');
const loadingContainer = document.getElementById('loading');
const backButton = document.getElementById('backButton');
<!-- Show loading indicator -->
loadingContainer.classList.remove('hidden');
resultContainer.innerHTML = ''; // Clear the result container
logToConsole('> API Request started...');
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
<!-- JSON stringify source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify -->
const raw = JSON.stringify({
"key": apiKey,
"prompt": promptText,
"negative_prompt": "Low Quality",
"scheduler": "UniPCMultistepScheduler",
"seconds": 3
});
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
<!-- Make the fetch request to the API -->
fetch("https://stablediffusionapi.com/api/v5/text2video", requestOptions)
.then(response => response.json())
.then(result => {
if (result.status === 'processing') {
logToConsole(\` > Please wait! If you don't see any other output in the console in the next 30 seconds, the API is probably down\`);
setTimeout(() => {
checkVideoStatus(result.fetch_result);
}, result.eta * 1000);
} else if (result.status === 'success') {
logToConsole('> API Request successful!');
displayVideo(result.output[0]);
backButton.classList.remove('hidden');
hidePrompts();
addExtraButtons();
} else {
logToConsole(' > API Request failed. See F12 console for details.');
console.error('API Request failed:', result);
}
})
.catch(error => {
logToConsole('Error: ' + error);
})
.finally(() => {
// Hide loading indicator after displaying the video or in case of an error
loadingContainer.classList.add('hidden');
});
}
<!-- Function to display the video -->
function displayVideo(videoUrl) {
const resultContainer = document.getElementById('result');
resultContainer.innerHTML = \`<video id="apiVideo" controls><source src="\${videoUrl}" type="video/mp4">Your browser does not support the video tag.</video>\`;
resultContainer.querySelector('video').load();
resultContainer.classList.remove('hidden');
}
<!-- Function to check the video status after the estimated time -->
function checkVideoStatus(fetchResultUrl) {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: JSON.stringify({ "key": apiKey })
};
fetch(fetchResultUrl, requestOptions)
.then(response => {
if (!response.ok) {
throw new Error(\`HTTP error! status: \${response.status}\`);
}
return response.json();
})
.then(result => {
if (result.status === 'success' && result.output && result.output.length > 0) {
logToConsole('Video processing complete!');
displayVideo(result.output[0]);
document.getElementById('backButton').classList.remove('hidden');
addExtraButtons();
} else if (result.status === 'processing') {
logToConsole(' > Video still processing, will check again in 10 seconds...');
setTimeout(() => {
checkVideoStatus(fetchResultUrl);
}, 10000);
} else {
logToConsole(' > Received unexpected result. See console for details.');
console.error('Received unexpected result:', result);
}
})
.catch(error => {
logToConsole('Error fetching the result: ' + error.message + '. See console for details.');
console.error('Error fetching the result:', error);
});
}
<!-- Function to add extra buttons below the video -->
function addExtraButtons() {
const resultContainer = document.getElementById('result');
<!-- Download button -->
const downloadButton = document.createElement('button');
downloadButton.className = 'extraButtons';
downloadButton.textContent = 'Download Video';
downloadButton.onclick = function () {
const video = document.getElementById('apiVideo');
const a = document.createElement('a');
a.href = video.src;
a.download = 'video.mp4';
a.click();
};
<!-- Loop button -->
<!-- Loop button source: https://stackoverflow.com/questions/3455229/control-html5-video-player-loop-with-javascript
const loopButton = document.createElement('button');
loopButton.className = 'extraButtons';
loopButton.textContent = 'Toggle Loop';
loopButton.onclick = function () {
const video = document.getElementById('apiVideo');
video.loop = !video.loop;
loopButton.classList.toggle('green', video.loop);
};
<!-- Fullscreen button -->
<!-- Fullscreen button source: https://www.w3schools.com/howto/howto_js_fullscreen.asp -->
const fullscreenButton = document.createElement('button');
fullscreenButton.className = 'extraButtons';
fullscreenButton.textContent = 'Toggle Fullscreen';
fullscreenButton.onclick = function () {
const video = document.getElementById('apiVideo');
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.mozRequestFullScreen) { /* Firefox */
video.mozRequestFullScreen();
} else if (video.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
video.webkitRequestFullscreen();
} else if (video.msRequestFullscreen) { /* IE/Edge */
video.msRequestFullscreen();
}
};
<!-- Append buttons to the result container -->
resultContainer.appendChild(downloadButton);
resultContainer.appendChild(loopButton);
resultContainer.appendChild(fullscreenButton);
}
</script>
</body>
</html>
`);