// Cloned by Toma on 3 Dec 2023 from World "Chat with GPT model (clone by Toma)" by Toma
// Please leave this clone trail here.
// Cloned by Toma on 1 Dec 2023 from World "Chat with GPT model" by Starter user
// Please leave this clone trail here.
// default body is margin 0 and padding 0
// give it more whitespace:
let currentPlayer = 'X';
let gameBoard = ['', '', '', '', '', '', '', '', ''];
let gameActive = true;
let apiKey;
let mediaRecorder;
let audioChunks = [];
$('body').css( "margin", "20px" );
$('body').css( "padding", "20px" );
document.write ( `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tic Tac Toe</title>
</head>
<body>
<body>
<h2 style="text-align: center">Tic Tac Toe</h2>
<div
id="gameBoard"
style="
/* color: white; */
position: relative;
margin: 0 auto;
width: 304px;
height: 304px;
border: 3px solid #000;
"
>
<div
style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgb(255, 255, 255);
z-index: 1;
"
>
<img
id="myImage"
src=""
alt="No image"
srcset=""
style="
opacity: 0.4;
width: 300px;
height: 300px;
border: 2px solid black;
"
/>
</div>
<div
id="cell0"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 0;
left: 0;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell1"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 0;
left: 100px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell2"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 0;
left: 200px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell3"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 100px;
left: 0;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell4"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell5"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 100px;
left: 200px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell6"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 200px;
left: 0;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell7"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 200px;
left: 100px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
<div
id="cell8"
style="
font-weight: bolder;
position: absolute;
z-index: 2;
top: 200px;
left: 200px;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid #000;
"
></div>
</div>
<div style="clear: both; text-align: center; margin-top: 20px;">
<p
id="gameStatus"
style="text-align: center; font-size: 20px; font-weight: bolder"
></p>
<button onclick="startGame()" style="padding: 10px 20px;">
Start New Game
</button>
<button id="startRecording" style="padding: 10px 20px;">
Change Image
</button>
<button id="stopRecording" disabled style="padding: 10px 20px;">
Stop Recording
</button>
<button id="supriseMeButton" style="padding: 10px 20px;">Random Background</button>
<!-- <br> -->
<div
style="
display: flex;
flex-direction: row;
place-items: center;
width: 100vw;
justify-content: center;
margin-top: 20px;
"
>
<audio id="audioPlayback" controls style="margin-right: 20px"></audio>
<button id="useAudioButton">Use Audio</button>
</div>
<p id="errorMessage" style="color: red; font-weight: bolder"></p>
<h2 id="isLoading" style="margin-top: 20px"></h2>
</div>
<p id="transcribedText" style="text-align: center; font-size: 15px"></p>
<input type="text" name="" id="apiKey" placeholder="API KEY">
<button id="submitApiKey">Submit</button>
</body>
</body>
</html>
` );
const myImage = document.getElementById("myImage");
const useAudioButton = document.getElementById("useAudioButton");
const startRecordingButton = document.getElementById("startRecording");
const stopRecordingButton = document.getElementById("stopRecording");
const isLoading = document.getElementById("isLoading");
const transcribedText = document.getElementById("transcribedText");
const errorMessage = document.getElementById("errorMessage");
useAudioButton.disabled = true;
startRecordingButton.addEventListener("click", startRecording);
stopRecordingButton.addEventListener("click", stopRecording);
document.getElementById("submitApiKey").addEventListener("click", function () {
apiKey = document.getElementById("apiKey").value;
if (apiKey) {
errorMessage.innerHTML = "API KEY SET";
errorMessage.style.color = 'green';
alert("API KEY SET");
} else {
alert("Please enter an API key.");
errorMessage.innerHTML = "API KEY NOT SET";
errorMessage.style.color = 'red';
}
});
useAudioButton.addEventListener("click", function () {
isLoading.innerHTML = "Loading Image........";
const audioBlob = new Blob(audioChunks, { type: "audio/mpeg" });
transcribeAudio(audioBlob);
});
supriseMeButton.addEventListener("click", function () {
isLoading.innerHTML = "Loading........";
generateRandomPromptAndImage();
})
function handleCellPlayed(clickedCell, clickedCellIndex) {
gameBoard[clickedCellIndex] = currentPlayer;
clickedCell.innerHTML = currentPlayer;
}
function handlePlayerChange() {
currentPlayer = currentPlayer === "X" ? "O" : "X";
}
function checkWin() {
const winConditions = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8], // rows
[0, 3, 6],
[1, 4, 7],
[2, 5, 8], // columns
[0, 4, 8],
[2, 4, 6], // diagonals
];
let roundWon = false;
for (let i = 0; i < winConditions.length; i++) {
const winCondition = winConditions[i];
let a = gameBoard[winCondition[0]];
let b = gameBoard[winCondition[1]];
let c = gameBoard[winCondition[2]];
if (a === "" || b === "" || c === "") {
continue;
}
if (a === b && b === c) {
roundWon = true;
break;
}
}
if (roundWon) {
document.getElementById("gameStatus").innerHTML;
document.getElementById(
"gameStatus"
).innerHTML = `Player ${currentPlayer} has won!`;
gameActive = false;
return;
}
let roundDraw = !gameBoard.includes("");
if (roundDraw) {
document.getElementById("gameStatus").innerHTML = "Game ended in a draw!";
gameActive = false;
return;
}
handlePlayerChange();
}
function handleCellClick(clickedCellEvent) {
const clickedCell = clickedCellEvent.target;
const clickedCellIndex = parseInt(
clickedCell.getAttribute("id").replace("cell", "")
);
if (gameBoard[clickedCellIndex] !== "" || !gameActive) {
return;
}
handleCellPlayed(clickedCell, clickedCellIndex);
checkWin();
}
function startGame() {
gameActive = true;
currentPlayer = "X";
gameBoard = ["", "", "", "", "", "", "", "", ""];
for (let i = 0; i < 9; i++) {
document.getElementById(`cell${i}`).innerHTML = "";
}
document.getElementById("gameStatus").innerHTML = "";
}
document
.querySelectorAll("#gameBoard div")
.forEach((cell) => cell.addEventListener("click", handleCellClick));
startGame();
function startRecording() {
navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = (event) => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: "audio/mpeg" });
const audioUrl = URL.createObjectURL(audioBlob);
document.getElementById("audioPlayback").src = audioUrl;
};
audioChunks = [];
mediaRecorder.start();
startRecordingButton.disabled = true;
useAudioButton.disabled = true;
stopRecordingButton.disabled = false;
})
.catch((e) => console.error(e));
}
function stopRecording() {
mediaRecorder.stop();
startRecordingButton.disabled = false;
stopRecordingButton.disabled = true;
useAudioButton.disabled = false;
}
function transcribeAudio(audioBlob) {
const formData = new FormData();
formData.append("file", audioBlob, "recording.mp3");
formData.append("model", "whisper-1");
formData.append("language", "en");
fetch("https://api.openai.com/v1/audio/transcriptions", {
method: "POST",
body: formData,
headers: {
Authorization: `Bearer ${apiKey}`,
},
})
.then((response) => response.json())
.then((data) => {
console.log("Transcription:", data);
generateImage(data.text);
})
.catch((error) => {
console.error("Error:", error);
isLoading.innerHTML = "";
});
}
function generateImage(text) {
if (!apiKey) {
isLoading.innerHTML = "";
alert("API key is not set.");
errorMessage.innerHTML = "API KEY NOT SET";
errorMessage.style.color = 'red';
return;
}
fetch("https://api.openai.com/v1/images/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: text,
}),
})
.then((response) => response.json())
.then((data) => {
isLoading.innerHTML = "";
errorMessage.innerHTML = "";
transcribedText.innerHTML = "Transcribed Text - ".concat(text);
var imageUrl = data.data[0].url;
myImage.src = imageUrl;
})
.catch((error) => {
console.error("Error calling DALLĀ·E API", error);
isLoading.innerHTML = "";
errorMessage.innerHTML = error.message || error;
errorMessage.style.color = 'red';
});
}
function generateRandomPromptAndImage() {
if (!apiKey) {
isLoading.innerHTML = "";
alert("API key is not set.");
errorMessage.innerHTML = "API KEY NOT SET";
errorMessage.style.color = 'red';
return;
}
const body = {
model: "gpt-3.5-turbo",
messages: [
{
role: "user",
content:
"Generate a prompt for dalle image generation no more than 20 words based on a game",
},
],
};
fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
})
.then((response) => response.json())
.then((data) => {
generateImage(data.choices[0].message.content);
})
.catch((error) => {
console.error("Error:", error.message);
isLoading.innerHTML = "";
});
}