Skip to content

Commit fb5160b

Browse files
authored
1 parent 3b7d4a3 commit fb5160b

File tree

1 file changed

+114
-6
lines changed

1 file changed

+114
-6
lines changed

openai-audio-output.html

+114-6
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,26 @@
102102
.copy-button:hover:not(:disabled) {
103103
background: #45a049;
104104
}
105+
.gist-button {
106+
background: #2ea44f;
107+
margin-right: 10px;
108+
}
109+
.gist-button:hover:not(:disabled) {
110+
background: #2c974b;
111+
}
112+
.gist-links {
113+
margin: 10px 0;
114+
}
115+
.gist-links a {
116+
display: block;
117+
margin: 5px 0;
118+
color: #0066cc;
119+
}
120+
#authLink {
121+
color: #0066cc;
122+
cursor: pointer;
123+
text-decoration: underline;
124+
}
105125
</style>
106126
</head>
107127
<body>
@@ -136,6 +156,13 @@ <h1>Prompt GPT-4o audio</h1>
136156
</div>
137157

138158
<div id="jsonContainer" class="json-container" style="display: none;">
159+
<div id="gistContainer">
160+
<span id="authLinkContainer" style="display: none;">
161+
<a id="authLink">Authenticate with GitHub</a>
162+
</span>
163+
<button id="saveGistBtn" class="gist-button" style="display: none;">Save as Gist</button>
164+
<div id="gistLinks" class="gist-links"></div>
165+
</div>
139166
<h3>API Response:</h3>
140167
<textarea id="responseJson" readonly></textarea>
141168
<button id="copyJsonBtn" class="copy-button">Copy to clipboard</button>
@@ -154,6 +181,10 @@ <h3>API Response:</h3>
154181
const jsonContainer = document.getElementById('jsonContainer');
155182
const responseJson = document.getElementById('responseJson');
156183
const copyJsonBtn = document.getElementById('copyJsonBtn');
184+
const saveGistBtn = document.getElementById('saveGistBtn');
185+
const authLinkContainer = document.getElementById('authLinkContainer');
186+
const authLink = document.getElementById('authLink');
187+
const gistLinks = document.getElementById('gistLinks');
157188

158189
function showError(message) {
159190
errorDiv.textContent = message;
@@ -166,6 +197,84 @@ <h3>API Response:</h3>
166197
errorDiv.style.display = 'none';
167198
}
168199

200+
function checkGithubAuth() {
201+
const token = localStorage.getItem('github_token');
202+
if (token) {
203+
authLinkContainer.style.display = 'none';
204+
saveGistBtn.style.display = 'inline-block';
205+
} else {
206+
authLinkContainer.style.display = 'inline-block';
207+
saveGistBtn.style.display = 'none';
208+
}
209+
}
210+
211+
function startAuthPoll() {
212+
const pollInterval = setInterval(() => {
213+
if (localStorage.getItem('github_token')) {
214+
checkGithubAuth();
215+
clearInterval(pollInterval);
216+
}
217+
}, 1000);
218+
}
219+
220+
authLink.addEventListener('click', () => {
221+
window.open('https://tools.simonwillison.net/github-auth', 'github-auth', 'width=600,height=800');
222+
startAuthPoll();
223+
});
224+
225+
async function createGist() {
226+
const token = localStorage.getItem('github_token');
227+
if (!token) {
228+
checkGithubAuth();
229+
return;
230+
}
231+
232+
try {
233+
saveGistBtn.disabled = true;
234+
saveGistBtn.textContent = 'Saving...';
235+
236+
const response = await fetch('https://api.github.com/gists', {
237+
method: 'POST',
238+
headers: {
239+
'Authorization': `token ${token}`,
240+
'Content-Type': 'application/json',
241+
},
242+
body: JSON.stringify({
243+
description: 'GPT-4o audio response',
244+
public: true,
245+
files: {
246+
'response.json': {
247+
content: responseJson.value
248+
}
249+
}
250+
})
251+
});
252+
253+
if (!response.ok) {
254+
throw new Error('Failed to create gist');
255+
}
256+
257+
const data = await response.json();
258+
const gistId = data.id;
259+
const gistUrl = data.html_url;
260+
const playerUrl = `https://tools.simonwillison.net/gpt-4o-audio-player?gist=${gistId}`;
261+
262+
gistLinks.innerHTML = `
263+
<a href="${gistUrl}" target="_blank">View Gist</a>
264+
<a href="${playerUrl}" target="_blank">Audio player</a>
265+
`;
266+
} catch (error) {
267+
console.error('Gist creation failed:', error);
268+
localStorage.removeItem('github_token');
269+
checkGithubAuth();
270+
} finally {
271+
saveGistBtn.disabled = false;
272+
saveGistBtn.textContent = 'Save as Gist';
273+
}
274+
}
275+
276+
saveGistBtn.addEventListener('click', createGist);
277+
169278
function getAPIKey() {
170279
let apiKey = localStorage.getItem('openai_api_key');
171280
if (!apiKey) {
@@ -244,15 +353,14 @@ <h3>API Response:</h3>
244353
throw new Error(data.error?.message || 'API request failed');
245354
}
246355

247-
// Display raw JSON response
248356
responseJson.value = JSON.stringify(data, null, 2);
249357
jsonContainer.style.display = 'block';
358+
gistLinks.innerHTML = '';
359+
checkGithubAuth();
250360

251-
// Extract audio data and transcript
252361
const audioData = data.choices[0].message.audio.data;
253362
const transcript = data.choices[0].message.audio.transcript;
254363

255-
// Create audio blob and URL
256364
const binaryData = atob(audioData);
257365
const arrayBuffer = new ArrayBuffer(binaryData.length);
258366
const uint8Array = new Uint8Array(arrayBuffer);
@@ -262,13 +370,11 @@ <h3>API Response:</h3>
262370
const blob = new Blob([uint8Array], { type: 'audio/wav' });
263371
const audioUrl = URL.createObjectURL(blob);
264372

265-
// Update UI
266373
audioPlayer.src = audioUrl;
267374
transcriptDiv.textContent = transcript;
268375
playerContainer.style.display = 'block';
269376
clearError();
270377

271-
// Set up download button
272378
downloadBtn.onclick = () => {
273379
const a = document.createElement('a');
274380
a.href = audioUrl;
@@ -286,14 +392,16 @@ <h3>API Response:</h3>
286392
}
287393
}
288394

289-
// Handle form submission
290395
submitBtn.addEventListener('click', submitToAPI);
291396

292397
promptInput.addEventListener('keypress', (e) => {
293398
if (e.key === 'Enter' && e.ctrlKey) {
294399
submitToAPI();
295400
}
296401
});
402+
403+
// Initial GitHub auth check
404+
checkGithubAuth();
297405
</script>
298406
</body>
299407
</html>

0 commit comments

Comments
 (0)