let open_ai_response;
// Apply some modern styles to the body
document.body.style.fontFamily = "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
document.body.style.margin = "0";
document.body.style.padding = "20px";
document.body.style.backgroundColor = "#22092C !important";
// Create a futuristic-looking title for the page
const pageTitle = document.createElement("h1");
pageTitle.textContent = "AI TaleForge: ChatGPT & DALL-E Craft 4 Images, 1 Line, Endless Stories";
pageTitle.style.textAlign = "center";
pageTitle.style.color = "#4caf50"; // Green color
pageTitle.style.fontFamily = "'Orbitron', sans-serif"; // Futuristic font
pageTitle.style.fontSize = "36px";
pageTitle.style.marginBottom = "20px";
pageTitle.style.transition = "transform 0.3s ease-in-out"; // Add transition effect
pageTitle.style.borderBox = "border-box"; // Add box-sizing property
// Add a mouseover event to create a 3D effect on hover
pageTitle.addEventListener("mouseover", () => {
pageTitle.style.transform = "rotateX(10deg)"; // Adjust the rotation angle as needed
});
// Add a mouseout event to reset the transform on mouse leave
pageTitle.addEventListener("mouseout", () => {
pageTitle.style.transform = "rotateX(0)";
});
// Apply additional styles
pageTitle.style.backgroundColor = "#22092C"; // Background color
pageTitle.style.padding = "20px"; // Padding
pageTitle.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.1)"; // Box shadow
// Typing effect
const titleText = pageTitle.textContent;
pageTitle.textContent = ""; // Clear the initial text
// Function to simulate typing effect
function typeText(index) {
if (index <= titleText.length) {
pageTitle.textContent = titleText.slice(0, index);
setTimeout(() => {
typeText(index + 1);
}, 100); // Adjust the typing speed (milliseconds)
}
}
// Trigger the typing effect after a delay (e.g., 500 milliseconds)
setTimeout(() => {
typeText(0);
}, 500);
// Append the title to the document
document.body.appendChild(pageTitle);
// Updated styles for the dropdown
const dropdownStyles = `
.dropdown-container {
position: relative;
margin: 0 auto;
width: 500px; /* Adjust the width as needed */
text-align: center;
margin-top: 20px;
}
.model-dropdown {
width: 100%;
padding: 8px;
font-size: 24px; /* Adjust font size for better readability */
border: 1px solid #4caf50; /* Green border */
border-radius: 10px;
background: #D5BDAF; /* Dark background color */
color: #000000; /* Green text color */
appearance: none; /* Remove default dropdown arrow */
cursor: pointer;
outline: none; /* Remove focus outline */
transition: background 0.3s, border 0.3s;
animation: fadeIn 0.5s ease-out; /* Add fadeIn animation */
text-align: center;
font-family: 'Roboto', sans-serif; /* Change the font to Roboto */
font-weight: 500; /* Increase font weight for a bolder look */
position: relative; /* Added position relative */
overflow: hidden; /* Hide overflow for animation */
}
.model-dropdown option {
background-color: #D5BDAF; /* Dark background color */
color: #000000; /* Green text color */
padding: 8px;
font-size: 24px; /* Adjust font size for better readability */
text-align: center;
font-family: 'Roboto', sans-serif; /* Change the font to Roboto */
font-weight: 500; /* Increase font weight for a bolder look */
white-space: nowrap; /* Prevent text from wrapping */
overflow: hidden; /* Hide overflow for animation */
animation: typeWriter 2s steps(30, end); /* Reverse typing animation */
}
.model-dropdown:hover {
background: #4caf50; /* Green background color on hover */
border: 1px solid #fff; /* White border on hover */
}
.model-dropdown:focus {
background: #4caf50; /* Green background color on focus */
border: 1px solid #fff; /* White border on focus */
}
.model-dropdown::after {
content: '';
border-style: solid;
border-width: 8px 8px 0;
border-color: #000000 transparent transparent transparent;
position: absolute;
top: calc(50% - 4px);
right: 15px;
transition: transform 0.3s ease-in-out; /* Added transition for animation */
transform: scaleY(1); /* Initial transform state */
}
.model-dropdown:hover::after {
transform: scaleY(0); /* Final transform state on hover */
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes typeWriter {
from {
width: 0;
}
to {
width: auto;
}
}
`;
// Create a style element and append it to the head
const dropdownStyleElement = document.createElement("style");
dropdownStyleElement.textContent = dropdownStyles;
document.head.appendChild(dropdownStyleElement);
// Create a container for the dropdown
const dropdownContainer = document.createElement("div");
dropdownContainer.classList.add("dropdown-container");
// Create a dropdown for selecting the model
const modelDropdown = document.createElement("select");
modelDropdown.classList.add("model-dropdown");
// Add options for DALL-E 2 and DALL-E 3
const dalle2Option = document.createElement("option");
dalle2Option.value = "dall-e-2";
dalle2Option.textContent = "DALL-E 2";
modelDropdown.appendChild(dalle2Option);
const dalle3Option = document.createElement("option");
dalle3Option.value = "dall-e-3";
dalle3Option.textContent = "DALL-E 3";
modelDropdown.appendChild(dalle3Option);
// Append the dropdown to the container
dropdownContainer.appendChild(modelDropdown);
// Append the container to the body
document.body.appendChild(dropdownContainer);
// Append the title to the body
document.body.appendChild(pageTitle);
// Create an input field for the user to enter the one-line story
const userInput = document.createElement("input");
userInput.type = "text";
userInput.placeholder = "Enter one-line story";
userInput.style.width = "100%";
userInput.style.padding = "10px";
userInput.style.margin = "20px auto";
userInput.style.fontSize = "16px";
userInput.style.border = "1px solid #ccc";
userInput.style.borderRadius = "5px";
document.body.appendChild(userInput);
const userAPIkey = document.createElement("input");
userAPIkey.type = "text";
userAPIkey.placeholder = "Enter OPEN AI API Key";
userAPIkey.style.width = "100%";
userAPIkey.style.padding = "10px";
userAPIkey.style.margin = "20px auto";
userAPIkey.style.fontSize = "16px";
userAPIkey.style.border = "1px solid #ccc";
userAPIkey.style.borderRadius = "5px";
document.body.appendChild(userAPIkey);
// Create a button to trigger the generation based on the user's input
const generateButton = document.createElement("button");
generateButton.textContent = "Generate Image";
generateButton.style.width = "100%";
generateButton.style.padding = "10px";
generateButton.style.margin = "10px auto";
generateButton.style.fontSize = "16px";
generateButton.style.cursor = "pointer";
generateButton.style.background = "#872341";
generateButton.style.color = "white";
generateButton.style.border = "none";
generateButton.style.borderRadius = "5px"; // Add margin to separate from the input
generateButton.addEventListener("click", (event) => {
event.preventDefault(); // Prevent default form submission behavior
const openAPIKey = userAPIkey.value;
const oneLineStory = userInput.value;
const model=modelDropdown.value;
generatePrompts(oneLineStory,model,openAPIKey);
});
// Container to display generated prompts
const promptContainer = document.createElement("div");
promptContainer.style.width = "80%";
promptContainer.style.margin = "20px auto";
promptContainer.style.padding = "20px";
promptContainer.style.background = "#f8f8f8";
promptContainer.style.borderRadius = "5px";
promptContainer.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.1)";
document.body.appendChild(userInput);
document.body.appendChild(modelDropdown);
document.body.appendChild(generateButton);
document.body.appendChild(promptContainer);
// Function to get ChatGPT response
// Create a loading spinner
const loadingSpinner = document.createElement("div");
loadingSpinner.classList.add("loader");
document.body.appendChild(loadingSpinner);
async function getChatGPTResponse(prompt,openAPIKey) {
const chatGPTApiKey = openAPIKey;
const chatGPTUrl = "https://api.openai.com/v1/chat/completions";
loadingSpinner.style.display = "block";
const chatGPTData = JSON.stringify({
model: "gpt-3.5-turbo",
messages: [
{ role: "system", content: "You are story teller who follows below template and provide dalle 2 prompts, Make sure that you strictly follow below the template" },
{ role: "user", content: prompt },
],
});
const chatGPTResponse = await fetch(chatGPTUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${chatGPTApiKey}`,
},
body: chatGPTData,
});
const chatGPTResult = await chatGPTResponse.json();
loadingSpinner.style.display = "none";
const generatedPrompt = chatGPTResult.choices[0].message.content;
// Display generated prompt in UI
const promptElement = document.createElement("p");
promptElement.textContent = `Using ChatGPT API Generated Dalle 2 Prompt: ${generatedPrompt}`;
promptContainer.appendChild(promptElement);
return generatedPrompt;
}
// Function to generate prompts for DALL-E 2
async function generatePrompts(oneLineStory,model,openAPIKey) {
// Call ChatGPT to get a response
const title = oneLineStory; // Use user's input as the title
const promptTemplate = `
Title: ${title}
Prompt:
[Line 1: Introduce the setting or context of Story Title . Describe the visual elements you want in the image (e.g., colors, shapes, objects, scenes) (max 250 characters)]
[Line 2: Introduce the main character and their goal or challenge .Specify any particular style or mood (e.g., surreal, vibrant, calm)(max 250 characters)]
[Line 3: Add a twist or complication to the story . Additional details to refine the visual concept (max 250 characters)]
[Line 4: Describe a critical moment or turning point . Any specific constraints or requirements for the image(max 250 characters)]
Description:
Create an image that captures the essence of [Title of the Visual Concept]. Emphasize [visual elements], ensuring a [specified style or mood]. Pay attention to [additional details] while adhering to [constraints or requirements]
`;
// Call ChatGPT to get a response
const chatGPTResponse = await getChatGPTResponse(promptTemplate,openAPIKey);
// Limit the length of the generated prompt
const truncatedPrompt = chatGPTResponse;
// Use regex to split the prompt into four lines
const lineRegex = /\[Line (\d+): (.+?)\]/g;
let match;
const lines = [];
while ((match = lineRegex.exec(truncatedPrompt)) !== null) {
lines.push(match[2]);
}
// Check if the lines array is empty
if (lines.length === 0) {
// Recall generatePrompts with the same parameters
await generatePrompts(oneLineStory, model, openAPIKey);
return; // Exit the current invocation
}
console.log(lines)
// Display the formatted prompts in the UI
for (let i = 0; i < 4; i++) {
const formattedPrompt = lines[i];
// Display the formatted prompt in the UI
const promptElement = document.createElement("p");
loadingSpinner.style.display = "block";
promptElement.textContent = `Generated Prompt ${i + 1}:\n${formattedPrompt}`;
//promptContainer.appendChild(promptElement);
// Call DALL-E 2 with the formatted prompt
//try{
await generateImageWithPrompt(formattedPrompt,model,openAPIKey);}
//catch(error){console.log("Maximum retries reached. Unable to generate image.");}
loadingSpinner.style.display = "none";
//}
}
const maxRetries = 50;
let currentRetry = 0;
async function generateImageWithPrompt(prompt, model,openAPIKey) {
// Show loading spinner while waiting for the response
loadingSpinner.style.display = "block";
console.log(model)
const DALLE2ApiKey = openAPIKey;
const DALLE2Url = "https://api.openai.com/v1/images/generations";
const DALLE2Data = JSON.stringify({
model: model,
prompt: prompt,
});
try {
const response = await fetch(DALLE2Url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${DALLE2ApiKey}`,
},
body: DALLE2Data,
});
// Check if the response indicates a rate limit error
if (response.status === 429) {
// Implement exponential backoff
const delay = Math.pow(2, currentRetry) * 1000; // Backoff in milliseconds
currentRetry++;
// Wait for the specified delay
await new Promise(resolve => setTimeout(resolve, delay));
// Retry the request
return generateImageWithPrompt(prompt, model,openAPIKey);
}
// Handle the response as needed
const DALLE2Result = await response.json();
// Log DALL-E 2 result for debugging
console.log("DALL-E 2 Result:", DALLE2Result);
// Display the generated image with a border
const imageURL = DALLE2Result.data[0].url;
const img = document.createElement("img");
img.src = imageURL;
img.style.border = "1px solid #ccc"; // Add a border to the image
img.style.marginTop = "10px"; // Add margin to separate images
document.body.appendChild(img);
} catch (error) {
// Handle other errors if needed
if (currentRetry >= maxRetries) {
console.log("Maximum retries reached. Unable to generate image.");
// You can handle this situation as needed, e.g., display a message to the user.
} else {
console.log("Error generating image with prompt:", error.message);
// Log the warning, but don't propagate the error
}
} finally {
// Hide loading spinner once the response is received
loadingSpinner.style.display = "none";
}
}
// Add styles for the loading spinner
const spinnerStyles = `
.loader {
display: none;
border: 8px solid #f3f3f3;
border-top: 8px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 1s linear infinite;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000; /* Ensure the spinner is on top of other elements */
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`;
const spinnerStyleElement = document.createElement("style");
spinnerStyleElement.textContent = spinnerStyles;
document.head.appendChild(spinnerStyleElement);
// Apply some modern styles to the body
document.body.style.fontFamily = "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
document.body.style.margin = "0";
document.body.style.padding = "20px";
document.body.style.backgroundColor = "#22092C !important";