|
3 | 3 | <head> |
4 | 4 | <meta charset="UTF-8"> |
5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
6 | | - <title>OpenAI Text-to-Speech</title> |
| 6 | + <title>Prompt GPT-4o audio</title> |
7 | 7 | <style> |
8 | 8 | body { |
9 | 9 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
|
27 | 27 | } |
28 | 28 | textarea { |
29 | 29 | width: 100%; |
30 | | - min-height: 150px; |
31 | 30 | padding: 12px; |
32 | 31 | font-size: 16px; |
33 | 32 | border: 1px solid #ccc; |
34 | 33 | border-radius: 4px; |
35 | 34 | resize: vertical; |
| 35 | + font-family: inherit; |
| 36 | + } |
| 37 | + #systemPrompt { |
| 38 | + min-height: 60px; |
| 39 | + } |
| 40 | + #promptInput { |
| 41 | + min-height: 150px; |
| 42 | + } |
| 43 | + #responseJson { |
| 44 | + min-height: 200px; |
| 45 | + font-family: monospace; |
| 46 | + background: #f5f5f5; |
36 | 47 | } |
37 | 48 | select { |
38 | 49 | padding: 8px 12px; |
|
78 | 89 | color: #666; |
79 | 90 | font-style: italic; |
80 | 91 | } |
| 92 | + .json-container { |
| 93 | + margin-top: 20px; |
| 94 | + } |
| 95 | + .copy-button { |
| 96 | + margin-top: 8px; |
| 97 | + background: #4CAF50; |
| 98 | + } |
| 99 | + .copy-button:hover:not(:disabled) { |
| 100 | + background: #45a049; |
| 101 | + } |
81 | 102 | </style> |
82 | 103 | </head> |
83 | | -<body><h1>Prompt gpt-4o-audio-preview</h1> |
| 104 | +<body> |
| 105 | + <h1>Prompt GPT-4o audio</h1> |
84 | 106 | <div class="info"> |
85 | 107 | Enter a prompt below and execute against <code>gpt-4o-audio-preview</code> to hear the results. |
86 | 108 | </div> |
87 | 109 |
|
88 | 110 | <div class="input-group"> |
| 111 | + <label for="systemPrompt">System Prompt (optional):</label> |
| 112 | + <textarea id="systemPrompt" placeholder="Enter system prompt here..." aria-label="System prompt"></textarea> |
| 113 | + |
| 114 | + <label for="promptInput">User Prompt:</label> |
89 | 115 | <textarea id="promptInput" placeholder="Enter your text here..." aria-label="Input text"></textarea> |
| 116 | + |
90 | 117 | <select id="voiceSelect" aria-label="Voice selection"> |
91 | 118 | <option value="alloy">Alloy</option> |
92 | 119 | <option value="echo">Echo</option> |
|
105 | 132 | <div id="transcript" class="transcript"></div> |
106 | 133 | </div> |
107 | 134 |
|
| 135 | + <div id="jsonContainer" class="json-container" style="display: none;"> |
| 136 | + <h3>API Response:</h3> |
| 137 | + <textarea id="responseJson" readonly></textarea> |
| 138 | + <button id="copyJsonBtn" class="copy-button">Copy to clipboard</button> |
| 139 | + </div> |
| 140 | + |
108 | 141 | <script> |
109 | 142 | const promptInput = document.getElementById('promptInput'); |
| 143 | + const systemPrompt = document.getElementById('systemPrompt'); |
110 | 144 | const voiceSelect = document.getElementById('voiceSelect'); |
111 | 145 | const submitBtn = document.getElementById('submitBtn'); |
112 | 146 | const errorDiv = document.getElementById('error'); |
113 | 147 | const playerContainer = document.getElementById('playerContainer'); |
114 | 148 | const audioPlayer = document.getElementById('audioPlayer'); |
115 | 149 | const downloadBtn = document.getElementById('downloadBtn'); |
116 | 150 | const transcriptDiv = document.getElementById('transcript'); |
| 151 | + const jsonContainer = document.getElementById('jsonContainer'); |
| 152 | + const responseJson = document.getElementById('responseJson'); |
| 153 | + const copyJsonBtn = document.getElementById('copyJsonBtn'); |
117 | 154 |
|
118 | 155 | function showError(message) { |
119 | 156 | errorDiv.textContent = message; |
120 | 157 | errorDiv.style.display = 'block'; |
121 | 158 | playerContainer.style.display = 'none'; |
| 159 | + jsonContainer.style.display = 'none'; |
122 | 160 | } |
123 | 161 |
|
124 | 162 | function clearError() { |
|
136 | 174 | return apiKey; |
137 | 175 | } |
138 | 176 |
|
| 177 | + copyJsonBtn.addEventListener('click', async () => { |
| 178 | + try { |
| 179 | + await navigator.clipboard.writeText(responseJson.value); |
| 180 | + const originalText = copyJsonBtn.textContent; |
| 181 | + copyJsonBtn.textContent = 'Copied!'; |
| 182 | + copyJsonBtn.disabled = true; |
| 183 | + setTimeout(() => { |
| 184 | + copyJsonBtn.textContent = originalText; |
| 185 | + copyJsonBtn.disabled = false; |
| 186 | + }, 1500); |
| 187 | + } catch (err) { |
| 188 | + console.error('Failed to copy text:', err); |
| 189 | + } |
| 190 | + }); |
| 191 | + |
139 | 192 | async function submitToAPI() { |
140 | 193 | const apiKey = getAPIKey(); |
141 | 194 | if (!apiKey) { |
|
146 | 199 | const voice = voiceSelect.value; |
147 | 200 | submitBtn.textContent = 'Processing...'; |
148 | 201 | submitBtn.disabled = true; |
149 | | - const prompt = promptInput.value; |
| 202 | + |
| 203 | + const messages = []; |
| 204 | + if (systemPrompt.value.trim()) { |
| 205 | + messages.push({ |
| 206 | + "role": "system", |
| 207 | + "content": systemPrompt.value |
| 208 | + }); |
| 209 | + } |
| 210 | + messages.push({ |
| 211 | + "role": "user", |
| 212 | + "content": promptInput.value |
| 213 | + }); |
150 | 214 |
|
151 | 215 | const payload = { |
152 | 216 | "model": "gpt-4o-audio-preview", |
|
158 | 222 | "voice": voice, |
159 | 223 | "format": "wav" |
160 | 224 | }, |
161 | | - "messages": [ |
162 | | - { |
163 | | - "role": "user", |
164 | | - "content": prompt |
165 | | - } |
166 | | - ] |
| 225 | + "messages": messages |
167 | 226 | }; |
168 | 227 |
|
169 | 228 | try { |
|
182 | 241 | throw new Error(data.error?.message || 'API request failed'); |
183 | 242 | } |
184 | 243 |
|
| 244 | + // Display raw JSON response |
| 245 | + responseJson.value = JSON.stringify(data, null, 2); |
| 246 | + jsonContainer.style.display = 'block'; |
| 247 | + |
185 | 248 | // Extract audio data and transcript |
186 | 249 | const audioData = data.choices[0].message.audio.data; |
187 | 250 | const transcript = data.choices[0].message.audio.transcript; |
|
0 commit comments