| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>rapformer | The Generator</title> |
| <style> |
| |
| :root { |
| --primary: #fff; |
| --bg: #000000; |
| --text-main: #ffffff; |
| --text-muted: #888888; |
| } |
| |
| body { |
| background-color: var(--bg); |
| color: var(--text-main); |
| font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif; |
| margin: 0; |
| padding: 0; |
| line-height: 1.5; |
| -webkit-font-smoothing: antialiased; |
| min-height: 100vh; |
| position: relative; |
| overflow-x: hidden; |
| } |
| |
| body::before { |
| content: ""; |
| position: fixed; |
| top: -50%; |
| left: -50%; |
| right: -50%; |
| bottom: -50%; |
| width: 200vw; |
| height: 200vh; |
| background: |
| radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.3) 0%, transparent 40%), |
| radial-gradient(circle at 75% 40%, rgba(255, 255, 255, 0.05) 0%, transparent 45%), |
| radial-gradient(circle at 15% 65%, rgba(255, 255, 255, 0.1) 0%, transparent 35%), |
| radial-gradient(circle at 60% 85%, rgba(255, 255, 255, 0.06) 0%, transparent 50%), |
| radial-gradient(circle at 90% 10%, rgba(255, 255, 255, 0.5) 0%, transparent 30%); |
| animation: waveFlow 25s infinite alternate ease-in-out; |
| z-index: -1; |
| pointer-events: none; |
| } |
| @keyframes waveFlow { |
| 0% { |
| transform: translate(0, 0) rotate(0deg) scale(1); |
| } |
| 50% { |
| transform: translate(-5%, 8%) rotate(10deg) scale(1.1); |
| } |
| 100% { |
| transform: translate(4%, -5%) rotate(-5deg) scale(0.95); |
| } |
| } |
| |
| .container { |
| max-width: 800px; |
| margin: 0 auto; |
| padding: 50px 20px; |
| position: relative; |
| z-index: 1; |
| } |
| |
| |
| header { |
| margin-bottom: 40px; |
| border-bottom: 1px solid rgba(255, 255, 255, 0.2); |
| padding-bottom: 20px; |
| } |
| |
| h1 { |
| font-size: 3.5rem; |
| font-weight: 900; |
| letter-spacing: -2px; |
| margin: 0; |
| color: var(--primary); |
| text-transform: lowercase; |
| } |
| |
| .subtitle { |
| font-size: 1rem; |
| font-weight: 700; |
| color: var(--text-muted); |
| margin-top: 5px; |
| text-transform: uppercase; |
| letter-spacing: 2px; |
| } |
| |
| |
| label { |
| display: block; |
| font-weight: 800; |
| font-size: 0.85rem; |
| text-transform: uppercase; |
| color: var(--text-muted); |
| margin-bottom: 10px; |
| letter-spacing: 1px; |
| } |
| |
| .val-display { |
| color: var(--primary); |
| font-size: 1rem; |
| float: right; |
| } |
| |
| |
| textarea { |
| width: 100%; |
| background: rgba(255, 255, 255, 0.05); |
| backdrop-filter: blur(12px); |
| -webkit-backdrop-filter: blur(12px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| color: var(--text-main); |
| font-family: inherit; |
| font-size: 1.3rem; |
| padding: 20px; |
| min-height: 140px; |
| resize: vertical; |
| box-sizing: border-box; |
| border-radius: 12px; |
| box-shadow: inset 0 1px 2px rgba(255, 255, 255, 0.05), |
| 0 8px 32px 0 rgba(0, 0, 0, 0.3); |
| transition: all 0.3s ease; |
| } |
| |
| textarea:focus { |
| outline: none; |
| border-color: rgba(255, 255, 255, 0.3); |
| } |
| |
| |
| .controls-grid { |
| display: grid; |
| grid-template-columns: 1fr 1fr; |
| gap: 20px; |
| margin-top: 20px; |
| } |
| |
| .slider-box { |
| background: rgba(255, 255, 255, 0.05); |
| backdrop-filter: blur(12px); |
| -webkit-backdrop-filter: blur(12px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| padding: 20px; |
| border-radius: 12px; |
| box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); |
| } |
| |
| input[type=range] { |
| width: 100%; |
| accent-color: var(--primary); |
| cursor: pointer; |
| } |
| |
| |
| button { |
| width: 100%; |
| background-color: var(--primary); |
| color: var(--bg); |
| border: none; |
| border-radius: 12px; |
| padding: 24px; |
| font-size: 1.5rem; |
| font-weight: 900; |
| cursor: pointer; |
| margin-top: 30px; |
| text-transform: uppercase; |
| letter-spacing: 1px; |
| transition: all 0.1s ease; |
| } |
| |
| button:active { |
| transform: scale(0.98); |
| } |
| |
| button:disabled { |
| background-color: rgba(255, 255, 255, 0.1); |
| color: var(--text-muted); |
| cursor: not-allowed; |
| } |
| |
| |
| #output-section { |
| display: none; |
| background: rgba(255, 255, 255, 0.05); |
| backdrop-filter: blur(40px); |
| -webkit-backdrop-filter: blur(40px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| border-radius: 24px; |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), |
| inset 0 1px 0 rgba(255, 255, 255, 0.2); |
| padding: 40px; |
| margin-top: 40px; |
| } |
| |
| .output-label { |
| font-weight: 900; |
| text-transform: uppercase; |
| font-size: 0.9rem; |
| border-bottom: 1px solid rgba(255,255,255,0.2); |
| padding-bottom: 10px; |
| margin-bottom: 20px; |
| letter-spacing: 1px; |
| color: rgba(255, 255, 255, 0.6); |
| } |
| |
| #lyrics-display { |
| font-size: 2.2rem; |
| font-weight: 800; |
| line-height: 1.4; |
| letter-spacing: -0.02em; |
| color: rgba(255, 255, 255, 0.95); |
| text-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); |
| white-space: pre-wrap; |
| } |
| |
| @media (max-width: 600px) { |
| .controls-grid { grid-template-columns: 1fr; } |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="container"> |
| <header> |
| <h1>rapformer</h1> |
| <div class="subtitle">14M Params • 500K Words • Zero-Shot Generation</div> |
| </header> |
|
|
| <main> |
| <label for="seed">Start Phrase / Context</label> |
| <textarea id="seed" placeholder="Drop a starting verse... (e.g. 'This one's from zwix!')"></textarea> |
|
|
| <div class="controls-grid"> |
| <div class="slider-box"> |
| <label for="temp">Temperature <span id="temp-val" class="val-display">1.2</span></label> |
| <input type="range" id="temp" min="0.1" max="1.5" step="0.05" value="1.2"> |
| </div> |
| <div class="slider-box"> |
| <label for="topk">Top-K <span id="topk-val" class="val-display">50</span></label> |
| <input type="range" id="topk" min="1" max="100" step="1" value="50"> |
| </div> |
| </div> |
|
|
| <button id="generate-btn">LET ME YAP!</button> |
|
|
| <div id="output-section"> |
| <div class="output-label">Generated Output</div> |
| <div id="lyrics-display"></div> |
| </div> |
| </main> |
| </div> |
|
|
| <script> |
| const tempSlider = document.getElementById('temp'); |
| const tempValDisplay = document.getElementById('temp-val'); |
| const topkSlider = document.getElementById('topk'); |
| const topkValDisplay = document.getElementById('topk-val'); |
| const seedInput = document.getElementById('seed'); |
| const generateBtn = document.getElementById('generate-btn'); |
| const outputSection = document.getElementById('output-section'); |
| const lyricsDisplay = document.getElementById('lyrics-display'); |
| |
| |
| tempSlider.addEventListener('input', (e) => { |
| tempValDisplay.textContent = parseFloat(e.target.value).toFixed(2).replace(/\.00$/, ''); |
| }); |
| |
| topkSlider.addEventListener('input', (e) => { |
| topkValDisplay.textContent = e.target.value; |
| }); |
| |
| |
| generateBtn.addEventListener('click', async () => { |
| const seedText = seedInput.value.trim() || "Yeah"; |
| const temperature = parseFloat(tempSlider.value); |
| const top_k = parseInt(topkSlider.value); |
| |
| generateBtn.disabled = true; |
| generateBtn.textContent = "YAPPING..."; |
| outputSection.style.display = "none"; |
| |
| try { |
| const response = await fetch('/generate', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| }, |
| body: JSON.stringify({ |
| start_phrase: seedText, |
| temperature: temperature, |
| top_k: top_k |
| }) |
| }); |
| |
| if (!response.ok) { |
| throw new Error(`Server Response Failure: ${response.status}`); |
| } |
| |
| const data = await response.json(); |
| lyricsDisplay.textContent = data.lyrics; |
| outputSection.style.display = "block"; |
| |
| } catch (error) { |
| alert("Failed to track response parameters. Verify server connection state."); |
| console.error(error); |
| } finally { |
| generateBtn.disabled = false; |
| generateBtn.textContent = "LET ME YAP!"; |
| } |
| }); |
| </script> |
| </body> |
| </html> |