Skip to content

Commit 0f89a8f

Browse files
authored
Update gpt-4o-audio-player.html
Handle long truncated gists Claude prompt was: > This breaks if the JSON is too long and is truncated by the gist API
1 parent 668115e commit 0f89a8f

File tree

1 file changed

+70
-28
lines changed

1 file changed

+70
-28
lines changed

gpt-4o-audio-player.html

+70-28
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@
6767
color: #666;
6868
font-style: italic;
6969
}
70+
.progress {
71+
margin: 10px 0;
72+
padding: 10px;
73+
background: #f0f0f0;
74+
border-radius: 4px;
75+
}
7076
</style>
7177
</head>
7278
<body>
@@ -80,6 +86,7 @@
8086
<button id="fetchBtn">Fetch</button>
8187
</div>
8288
<div id="error" class="error" style="display: none;"></div>
89+
<div id="progress" class="progress" style="display: none;"></div>
8390
<div id="playerContainer" class="player-container" style="display: none;">
8491
<audio id="audioPlayer" controls></audio>
8592
<button id="downloadBtn">Download Audio</button>
@@ -90,6 +97,7 @@
9097
const gistInput = document.getElementById('gistUrl');
9198
const fetchBtn = document.getElementById('fetchBtn');
9299
const errorDiv = document.getElementById('error');
100+
const progressDiv = document.getElementById('progress');
93101
const playerContainer = document.getElementById('playerContainer');
94102
const audioPlayer = document.getElementById('audioPlayer');
95103
const downloadBtn = document.getElementById('downloadBtn');
@@ -101,6 +109,15 @@
101109
playerContainer.style.display = 'none';
102110
}
103111

112+
function showProgress(message) {
113+
progressDiv.textContent = message;
114+
progressDiv.style.display = 'block';
115+
}
116+
117+
function hideProgress() {
118+
progressDiv.style.display = 'none';
119+
}
120+
104121
function clearError() {
105122
errorDiv.style.display = 'none';
106123
}
@@ -118,44 +135,75 @@
118135
history.pushState({}, '', newUrl);
119136
}
120137

138+
async function fetchWithRetry(url, options = {}, retries = 3) {
139+
for (let i = 0; i < retries; i++) {
140+
try {
141+
const response = await fetch(url, options);
142+
if (!response.ok) {
143+
throw new Error(`HTTP error! status: ${response.status}`);
144+
}
145+
return response;
146+
} catch (error) {
147+
if (i === retries - 1) throw error;
148+
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
149+
}
150+
}
151+
}
152+
153+
async function fetchGistContent(gistId) {
154+
showProgress('Fetching Gist metadata...');
155+
const gistResponse = await fetchWithRetry(`https://api.github.com/gists/${gistId}`);
156+
const gistData = await gistResponse.json();
157+
158+
const files = gistData.files;
159+
if (!files || Object.keys(files).length === 0) {
160+
throw new Error('No files found in Gist');
161+
}
162+
163+
const firstFile = Object.values(files)[0];
164+
165+
// Check if content is truncated
166+
if (firstFile.truncated) {
167+
showProgress('Content is truncated, fetching raw content...');
168+
const rawResponse = await fetchWithRetry(firstFile.raw_url);
169+
return await rawResponse.text();
170+
}
171+
172+
return firstFile.content;
173+
}
174+
121175
async function processGistUrl(url) {
122176
try {
123177
fetchBtn.disabled = true;
178+
clearError();
179+
hideProgress();
180+
124181
const gistId = extractGistId(url);
125182
if (!gistId) throw new Error('Invalid Gist URL');
126183

127-
// Update URL with gist ID
128184
updateURL(gistId);
129-
130-
// Update input field if it doesn't match
131185
if (gistInput.value !== url) {
132186
gistInput.value = url;
133187
}
134188

135-
// Fetch gist data
136-
const gistResponse = await fetch(`https://api.github.com/gists/${gistId}`);
137-
if (!gistResponse.ok) throw new Error('Failed to fetch Gist');
189+
const content = await fetchGistContent(gistId);
138190

139-
const gistData = await gistResponse.json();
140-
const files = gistData.files;
141-
if (!files || Object.keys(files).length === 0) {
142-
throw new Error('No files found in Gist');
191+
showProgress('Parsing JSON content...');
192+
let jsonContent;
193+
try {
194+
jsonContent = JSON.parse(content);
195+
} catch (e) {
196+
throw new Error('Failed to parse JSON content. The content might be corrupted or incomplete.');
143197
}
144198

145-
// Get content from first file
146-
const firstFile = Object.values(files)[0];
147-
const content = JSON.parse(firstFile.content);
148-
149-
// Verify this is an audio response
150-
if (!content?.choices?.[0]?.message?.audio?.data) {
199+
if (!jsonContent?.choices?.[0]?.message?.audio?.data) {
151200
throw new Error('This Gist does not contain a valid GPT-4 audio response');
152201
}
153202

154-
// Extract audio data and transcript
155-
const audioData = content.choices[0].message.audio.data;
156-
const transcript = content.choices[0].message.audio.transcript;
203+
showProgress('Processing audio data...');
204+
const audioData = jsonContent.choices[0].message.audio.data;
205+
const transcript = jsonContent.choices[0].message.audio.transcript;
157206

158-
// Create audio blob and URL
159207
const binaryData = atob(audioData);
160208
const arrayBuffer = new ArrayBuffer(binaryData.length);
161209
const uint8Array = new Uint8Array(arrayBuffer);
@@ -165,13 +213,11 @@
165213
const blob = new Blob([uint8Array], { type: 'audio/wav' });
166214
const audioUrl = URL.createObjectURL(blob);
167215

168-
// Update UI
169216
audioPlayer.src = audioUrl;
170217
transcriptDiv.textContent = transcript;
171218
playerContainer.style.display = 'block';
172-
clearError();
219+
hideProgress();
173220

174-
// Set up download button
175221
downloadBtn.onclick = () => {
176222
const a = document.createElement('a');
177223
a.href = audioUrl;
@@ -184,10 +230,10 @@
184230
showError(error.message || 'An error occurred');
185231
} finally {
186232
fetchBtn.disabled = false;
233+
hideProgress();
187234
}
188235
}
189236

190-
// Handle form submission
191237
fetchBtn.addEventListener('click', () => {
192238
const url = gistInput.value.trim();
193239
if (!url) {
@@ -203,27 +249,23 @@
203249
}
204250
});
205251

206-
// Check for gist ID in URL on page load
207252
window.addEventListener('load', () => {
208253
const params = new URLSearchParams(window.location.search);
209254
const gistId = params.get('gist');
210255
if (gistId) {
211-
// If it's just an ID, construct the full URL
212256
const fullUrl = `https://gist.github.com/${gistId}`;
213257
gistInput.value = fullUrl;
214258
processGistUrl(fullUrl);
215259
}
216260
});
217261

218-
// Handle browser back/forward
219262
window.addEventListener('popstate', () => {
220263
const params = new URLSearchParams(window.location.search);
221264
const gistId = params.get('gist');
222265
if (gistId) {
223266
const fullUrl = `https://gist.github.com/${gistId}`;
224267
processGistUrl(fullUrl);
225268
} else {
226-
// Clear everything if there's no gist ID
227269
gistInput.value = '';
228270
playerContainer.style.display = 'none';
229271
clearError();

0 commit comments

Comments
 (0)