-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |