Spaces:
Sleeping
Sleeping
| <html> | |
| <head> | |
| <title>Beam Search Generation</title> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #4F46E5; | |
| --secondary-color: #818CF8; | |
| --background-color: #F3F4F6; | |
| --card-background: #FFFFFF; | |
| --text-primary: #111827; | |
| --text-secondary: #4B5563; | |
| --accent-color: #3730A3; | |
| --success-color: #059669; | |
| --border-radius: 12px; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; | |
| } | |
| body { | |
| background-color: var(--background-color); | |
| color: var(--text-primary); | |
| line-height: 1.5; | |
| min-height: 100vh; | |
| } | |
| .header { | |
| background: var(--card-background); | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| margin-bottom: 1rem; | |
| } | |
| h1 { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| color: var(--accent-color); | |
| text-align: center; | |
| text-shadow: 0 1px 2px rgba(0,0,0,0.1); | |
| padding: 1.5rem; | |
| margin: 0; | |
| } | |
| .input-section { | |
| background: var(--card-background); | |
| padding: 1.5rem 2rem; | |
| border-bottom: 1px solid #E5E7EB; | |
| } | |
| textarea { | |
| width: 100%; | |
| padding: 1rem; | |
| border: 2px solid #E5E7EB; | |
| border-radius: var(--border-radius); | |
| font-size: 1rem; | |
| transition: border-color 0.3s ease; | |
| resize: vertical; | |
| margin-bottom: 1rem; | |
| } | |
| textarea:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1); | |
| } | |
| .controls { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 1rem; | |
| margin-bottom: 1rem; | |
| } | |
| .input-group { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| label { | |
| font-weight: 600; | |
| margin-bottom: 0.5rem; | |
| color: var(--text-secondary); | |
| } | |
| input[type="number"] { | |
| padding: 0.75rem; | |
| border: 2px solid #E5E7EB; | |
| border-radius: var(--border-radius); | |
| font-size: 1rem; | |
| transition: all 0.3s ease; | |
| } | |
| input[type="number"]:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1); | |
| } | |
| .slider-container { | |
| margin: 1rem 0; | |
| padding: 1rem; | |
| background: var(--background-color); | |
| border-radius: var(--border-radius); | |
| } | |
| .slider-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| margin-top: 0.5rem; | |
| } | |
| input[type="range"] { | |
| flex: 1; | |
| height: 8px; | |
| -webkit-appearance: none; | |
| background: #E5E7EB; | |
| border-radius: 4px; | |
| outline: none; | |
| transition: all 0.3s ease; | |
| } | |
| input[type="range"]::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| background: var(--primary-color); | |
| border-radius: 50%; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| input[type="range"]::-webkit-slider-thumb:hover { | |
| background: var(--accent-color); | |
| transform: scale(1.1); | |
| } | |
| .slider-value { | |
| min-width: 100px; | |
| padding: 0.5rem 1rem; | |
| background: var(--primary-color); | |
| color: white; | |
| border-radius: var(--border-radius); | |
| text-align: center; | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| } | |
| #generate-btn { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 1rem 2rem; | |
| border-radius: var(--border-radius); | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| width: 100%; | |
| margin-top: 1rem; | |
| } | |
| #generate-btn:hover { | |
| background-color: var(--accent-color); | |
| transform: translateY(-1px); | |
| } | |
| #generate-btn:disabled { | |
| background-color: #D1D5DB; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| color: var(--text-secondary); | |
| font-weight: 600; | |
| padding: 0.5rem; | |
| } | |
| .container { | |
| padding: 0 2rem; | |
| } | |
| .split-container { | |
| display: flex; | |
| gap: 2rem; | |
| padding-bottom: 2rem; | |
| } | |
| .left-panel, .right-panel { | |
| flex: 1; | |
| background: var(--card-background); | |
| border-radius: var(--border-radius); | |
| padding: 1.5rem; | |
| min-height: 300px; | |
| } | |
| .panel-title { | |
| font-size: 1.25rem; | |
| color: var(--accent-color); | |
| margin-bottom: 1rem; | |
| padding-bottom: 0.5rem; | |
| border-bottom: 2px solid var(--secondary-color); | |
| } | |
| .beam-container { | |
| background: var(--background-color); | |
| margin-bottom: 1rem; | |
| padding: 1.5rem; | |
| border-radius: var(--border-radius); | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
| transition: transform 0.3s ease; | |
| } | |
| .beam-container:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .beam-container h3, .beam-container h4 { | |
| color: var(--accent-color); | |
| margin-bottom: 1rem; | |
| font-weight: 600; | |
| } | |
| .beam-text { | |
| white-space: pre-wrap; | |
| font-family: 'Cascadia Code', 'Source Code Pro', monospace; | |
| line-height: 1.6; | |
| color: var(--text-secondary); | |
| background: var(--card-background); | |
| padding: 1rem; | |
| border-radius: calc(var(--border-radius) - 4px); | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 0 1rem; | |
| } | |
| .split-container { | |
| flex-direction: column; | |
| gap: 1rem; | |
| } | |
| .controls { | |
| grid-template-columns: 1fr; | |
| } | |
| .header { | |
| margin-bottom: 1rem; | |
| } | |
| } | |
| .footer { | |
| background: var(--card-background); | |
| padding: 2rem; | |
| margin-top: 2rem; | |
| box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.05); | |
| } | |
| .footer-content { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| display: grid; | |
| grid-template-columns: 2fr 1fr; | |
| gap: 2rem; | |
| } | |
| .project-info h3 { | |
| color: var(--accent-color); | |
| margin-bottom: 1rem; | |
| font-size: 1.25rem; | |
| } | |
| .project-info p { | |
| color: var(--text-secondary); | |
| line-height: 1.6; | |
| margin-bottom: 1rem; | |
| } | |
| .credit { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-end; | |
| justify-content: center; | |
| } | |
| .credit p { | |
| color: var(--text-secondary); | |
| margin-bottom: 1rem; | |
| } | |
| .credit a { | |
| color: var(--primary-color); | |
| text-decoration: none; | |
| font-weight: 600; | |
| transition: color 0.3s ease; | |
| } | |
| .credit a:hover { | |
| color: var(--accent-color); | |
| } | |
| .social-links { | |
| display: flex; | |
| gap: 1rem; | |
| } | |
| .social-links a { | |
| color: var(--text-secondary); | |
| font-size: 1.5rem; | |
| transition: all 0.3s ease; | |
| } | |
| .social-links a:hover { | |
| color: var(--primary-color); | |
| transform: translateY(-2px); | |
| } | |
| @media (max-width: 768px) { | |
| .footer-content { | |
| grid-template-columns: 1fr; | |
| gap: 1rem; | |
| } | |
| .credit { | |
| align-items: flex-start; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h1>Beam Search Generator</h1> | |
| <div class="input-section"> | |
| <textarea id="prompt" rows="4" placeholder="Enter your prompt here..."></textarea> | |
| <div class="controls"> | |
| <div class="input-group"> | |
| <label for="num_beams">Number of beams</label> | |
| <input type="number" id="num_beams" value="5" min="2" max="10"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="max_tokens">Max tokens</label> | |
| <input type="number" id="max_tokens" value="512" min="1"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="model_select">Model</label> | |
| <select id="model_select" class="form-select"> | |
| <option value="gpt2">GPT-2</option> | |
| <option value="qwen">Qwen</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="slider-container"> | |
| <label for="sleep_time">Generation Speed</label> | |
| <div class="slider-group"> | |
| <i class="fas fa-bolt" title="Fast"></i> | |
| <input type="range" id="sleep_time" min="0" max="500" value="0" step="10"> | |
| <i class="fas fa-hourglass" title="Slow"></i> | |
| <div class="slider-value" id="sleep_value">0ms delay</div> | |
| </div> | |
| </div> | |
| <button id="generate-btn" onclick="generate()"> | |
| <i class="fas fa-wand-magic-sparkles"></i> | |
| Generate | |
| </button> | |
| <div id="loading" class="loading"> | |
| <i class="fas fa-spinner"></i> | |
| Generating amazing content... | |
| </div> | |
| </div> | |
| </div> | |
| <div class="container"> | |
| <div class="split-container"> | |
| <div class="left-panel"> | |
| <h2 class="panel-title">Active Beams</h2> | |
| <div id="beams"></div> | |
| </div> | |
| <div class="right-panel"> | |
| <h2 class="panel-title">Completed Beams</h2> | |
| <div id="completed-list"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| let socket = io({ | |
| transports: ['websocket'], | |
| reconnection: true, | |
| reconnectionAttempts: 5, | |
| reconnectionDelay: 1000, | |
| path: '/socket.io/', | |
| upgrade: false, | |
| forceNew: true, | |
| pingTimeout: 60000, | |
| pingInterval: 25000 | |
| }); | |
| let beams = {}; | |
| let completedBeams = []; | |
| let isGenerating = false; | |
| // Add slider value update | |
| const sleepSlider = document.getElementById('sleep_time'); | |
| const sleepValue = document.getElementById('sleep_value'); | |
| sleepSlider.addEventListener('input', function() { | |
| const value = parseInt(this.value); | |
| sleepValue.textContent = value === 0 ? 'No delay' : `${value}ms delay`; | |
| }); | |
| function setupSocketListeners() { | |
| socket.on('beam_update', function(data) { | |
| console.log('Received beam update:', data); // Add logging | |
| const { beam_idx, text } = data; | |
| if (!beams[beam_idx]) { | |
| createBeamContainer(beam_idx); | |
| } | |
| const beamElement = document.getElementById(`beam-${beam_idx}`); | |
| if (beamElement) { | |
| beamElement.textContent = text; | |
| } | |
| }); | |
| socket.on('beam_finished', function(data) { | |
| completedBeams.push(data.text); | |
| updateCompletedBeams(); | |
| }); | |
| socket.on('generation_started', function() { | |
| isGenerating = true; | |
| document.getElementById('generate-btn').disabled = true; | |
| document.getElementById('loading').style.display = 'block'; | |
| document.getElementById('generate-btn').innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generating...'; | |
| }); | |
| socket.on('generation_completed', function() { | |
| isGenerating = false; | |
| document.getElementById('generate-btn').disabled = false; | |
| document.getElementById('loading').style.display = 'none'; | |
| document.getElementById('generate-btn').innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate'; | |
| }); | |
| socket.on('generation_error', function(data) { | |
| alert('Error during generation: ' + data.error); | |
| isGenerating = false; | |
| document.getElementById('generate-btn').disabled = false; | |
| document.getElementById('loading').style.display = 'none'; | |
| document.getElementById('generate-btn').innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate'; | |
| }); | |
| socket.on('connect_error', function(error) { | |
| console.error('Connection error:', error); | |
| resetConnection(); | |
| }); | |
| } | |
| function createBeamContainer(beamIdx) { | |
| const container = document.createElement('div'); | |
| container.className = 'beam-container'; | |
| container.innerHTML = ` | |
| <h3>Beam ${beamIdx + 1}</h3> | |
| <div id="beam-${beamIdx}" class="beam-text"></div> | |
| `; | |
| document.getElementById('beams').appendChild(container); | |
| beams[beamIdx] = container; | |
| } | |
| function updateCompletedBeams() { | |
| const completedList = document.getElementById('completed-list'); | |
| completedList.innerHTML = completedBeams.map((text, idx) => ` | |
| <div class="beam-container"> | |
| <h4>Completed Beam ${idx + 1}</h4> | |
| <div class="beam-text">${text}</div> | |
| </div> | |
| `).join(''); | |
| } | |
| function resetConnection() { | |
| if (socket) { | |
| socket.removeAllListeners(); | |
| socket.close(); | |
| } | |
| socket = io({ | |
| transports: ['websocket'], | |
| reconnection: true, | |
| reconnectionAttempts: 5, | |
| reconnectionDelay: 1000 | |
| }); | |
| setupSocketListeners(); | |
| } | |
| function generate() { | |
| if (isGenerating) return; | |
| console.log('Starting generation...'); // Add logging | |
| // Clear previous state | |
| document.getElementById('beams').innerHTML = ''; | |
| document.getElementById('completed-list').innerHTML = ''; | |
| beams = {}; | |
| completedBeams = []; | |
| // Reset connection before each generation | |
| resetConnection(); | |
| const prompt = document.getElementById('prompt').value; | |
| const model = document.getElementById('model_select').value; | |
| const numBeams = parseInt(document.getElementById('num_beams').value); | |
| const maxTokens = parseInt(document.getElementById('max_tokens').value); | |
| const sleepTime = parseInt(document.getElementById('sleep_time').value); | |
| console.log('Emitting generate event with params:', { | |
| prompt, numBeams, maxTokens, sleepTime | |
| }); | |
| socket.emit('generate', { | |
| prompt: prompt, | |
| model: model, | |
| num_beams: numBeams, | |
| max_tokens: maxTokens, | |
| sleep_time: sleepTime | |
| }); | |
| } | |
| setupSocketListeners(); | |
| </script> | |
| <footer class="footer"> | |
| <div class="footer-content"> | |
| <div class="project-info"> | |
| <h3>About This Project</h3> | |
| <p>This website demonstrates the MultiBeamTextStreamer feature proposed in a pull request to the Hugging Face Transformers library. The MultiBeamTextStreamer enables real-time visualization of beam search generation, providing insights into how language models explore different text completion possibilities.</p> | |
| <p>The implementation showcases how beam search works by displaying multiple candidate sequences simultaneously, making it a valuable educational tool for understanding text generation algorithms.</p> | |
| </div> | |
| <div class="credit"> | |
| <p>Created by <a href="https://github.com/mosheofer1" target="_blank" rel="noopener noreferrer">Moshe Ofer</a></p> | |
| <div class="social-links"> | |
| <a href="https://github.com/mosheofer1" target="_blank" rel="noopener noreferrer" title="GitHub"> | |
| <i class="fab fa-github"></i> | |
| </a> | |
| <a href="https://www.linkedin.com/in/moshe-ofer/" target="_blank" rel="noopener noreferrer" title="linkedin"> | |
| <i class="fas fa-rocket"></i> | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </footer> | |
| </body> | |
| </html> |