Skip to content

Commit

Permalink
Visual Telephone Game by Claude 3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
ToonTalk committed Jun 21, 2024
1 parent 7d20341 commit 93235a4
Showing 1 changed file with 339 additions and 0 deletions.
339 changes: 339 additions & 0 deletions apps/visual telephone game/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenAI Image Analyzer and Generator</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f0f0f0;
color: #333;
}
h1, h2 {
color: #2c3e50;
}
#imageDisplay {
max-width: 100%;
height: auto;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
textarea {
width: 100%;
height: 150px;
padding: 12px;
border: 2px solid #3498db;
border-radius: 8px;
font-size: 16px;
resize: vertical;
transition: border-color 0.3s ease;
}
textarea:focus {
outline: none;
border-color: #2980b9;
}
.button {
display: inline-block;
padding: 10px 20px;
margin: 10px 5px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.1s ease;
}
.button:hover {
background-color: #2980b9;
}
.button:active {
transform: scale(0.98);
}
.button:disabled {
background-color: #bdc3c7;
cursor: not-allowed;
}
.hidden {
display: none;
}
.history-item {
background-color: white;
border-radius: 8px;
padding: 15px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.history-item img {
max-width: 200px;
height: auto;
border-radius: 4px;
}
#loading {
display: none;
text-align: center;
padding: 20px;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.markdown-content {
background-color: #f9f9f9;
padding: 15px;
border-radius: 5px;
margin-top: 10px;
}
.markdown-content p {
margin: 0 0 10px 0;
}
.markdown-content ul, .markdown-content ol {
margin: 0 0 10px 20px;
}
#error {
color: #e74c3c;
background-color: #fadbd8;
border: 1px solid #e74c3c;
padding: 10px;
border-radius: 5px;
margin-top: 10px;
}
.input-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #2c3e50;
}
input[type="password"], input[type="file"] {
width: 100%;
padding: 10px;
border: 2px solid #3498db;
border-radius: 5px;
font-size: 16px;
}
input[type="file"] {
padding: 10px 0;
}
</style>
</head>
<body>
<h1>OpenAI Image Analyzer and Generator</h1>

<div class="input-group">
<label for="apiKey">Enter OpenAI API Key:</label>
<input type="password" id="apiKey">
</div>

<h2>Current Image</h2>
<div class="input-group">
<input type="file" id="imageUpload" accept="image/*">
</div>
<img id="imageDisplay" alt="Current image" class="hidden">

<h2>Image Description</h2>
<textarea id="imageDescription" readonly></textarea>

<button id="analyzeBtn" class="button" disabled>Analyze Image</button>
<button id="generateBtn" class="button">Generate New Image</button>

<div id="loading">
<div class="spinner"></div>
<p>Processing... Please wait.</p>
</div>

<div id="error" class="hidden"></div>

<h2>History</h2>
<div id="history"></div>

<script>
document.addEventListener('DOMContentLoaded', function() {
let apiKey = '';

document.getElementById('apiKey').addEventListener('input', (e) => {
apiKey = e.target.value.trim();
console.log("API Key updated. Length:", apiKey.length);
});

document.getElementById('imageUpload').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
document.getElementById('imageDisplay').src = event.target.result;
document.getElementById('imageDisplay').classList.remove('hidden');
document.getElementById('analyzeBtn').disabled = false;
}
reader.readAsDataURL(file);
}
});

async function analyzeImage() {
const img = document.getElementById('imageDisplay');
const imgData = img.src;

if (!apiKey) {
showError("Please enter an API key.");
return;
}

showLoading();
hideError();

try {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: "gpt-4o",
messages: [
{
role: "user",
content: [
{
type: "text",
text: "Please describe the image in detail"
},
{
type: "image_url",
image_url: {
url: imgData
}
}
]
}
],
max_tokens: 500
})
});

if (!response.ok) {
const errorBody = await response.text();
console.error('API Response:', response.status, errorBody);
throw new Error(`HTTP error! status: ${response.status}, body: ${errorBody}`);
}

const result = await response.json();
if (result.choices && result.choices[0] && result.choices[0].message) {
const description = result.choices[0].message.content;
document.getElementById('imageDescription').value = description;
addToHistory(imgData, description, 'Analyzed');
} else {
throw new Error('Unexpected response structure');
}
} catch (error) {
console.error('Error:', error);
showError(`Error analyzing image: ${error.message}`);
} finally {
hideLoading();
}
}

async function generateImage() {
const description = document.getElementById('imageDescription').value;

if (!apiKey) {
showError("Please enter an API key.");
return;
}

showLoading();
hideError();

try {
const response = await fetch('https://api.openai.com/v1/images/generations', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: "dall-e-3",
prompt: `Create this: ${description}`,
n: 1,
size: "1024x1024"
})
});

if (!response.ok) {
const errorBody = await response.text();
console.error('API Response:', response.status, errorBody);
throw new Error(`HTTP error! status: ${response.status}, body: ${errorBody}`);
}

const result = await response.json();
if (result.data && result.data[0] && result.data[0].url) {
const imageUrl = result.data[0].url;
document.getElementById('imageDisplay').src = imageUrl;
document.getElementById('imageDisplay').classList.remove('hidden');
addToHistory(imageUrl, description, 'Generated');
} else {
throw new Error('Unexpected response structure');
}
} catch (error) {
console.error('Error:', error);
showError(`Error generating image: ${error.message}`);
} finally {
hideLoading();
}
}

function addToHistory(imageUrl, description, action) {
const historyDiv = document.getElementById('history');
const historyItem = document.createElement('div');
historyItem.className = 'history-item';
historyItem.innerHTML = `
<h3>${action} Image</h3>
<img src="${imageUrl}" alt="${action} image">
<div class="markdown-content">
<strong>Description:</strong>
${marked.parse(description)}
</div>
`;
historyDiv.appendChild(historyItem);
}

function showLoading() {
document.getElementById('loading').style.display = 'block';
}

function hideLoading() {
document.getElementById('loading').style.display = 'none';
}

function showError(message) {
const errorDiv = document.getElementById('error');
errorDiv.textContent = message;
errorDiv.classList.remove('hidden');
}

function hideError() {
const errorDiv = document.getElementById('error');
errorDiv.classList.add('hidden');
}

document.getElementById('analyzeBtn').addEventListener('click', analyzeImage);
document.getElementById('generateBtn').addEventListener('click', generateImage);
});
</script>
</body>
</html>

0 comments on commit 93235a4

Please sign in to comment.