Spaces:
Runtime error
Runtime error
<html> | |
<head> | |
<title>Webapp Factory π</title> | |
<link href="/css/[email protected]" rel="stylesheet" type="text/css"> | |
<script src="/js/[email protected]" defer></script> | |
<script src="/js/[email protected]"></script> | |
</head> | |
<body> | |
<div class="flex flex-row" x-data="app()" x-init="init()"> | |
<div | |
class="hero min-h-screen bg-stone-100 transition-[width] delay-150 ease-in-out" | |
:class="open ? 'w-2/6' : 'w-6/6'"> | |
<div class="hero-content text-center"> | |
<div class="flex flex-col max-w-xl space-y-6"> | |
<h1 | |
class="font-bold text-stone-600 mb-4 transition-all delay-150 ease-in-out" | |
:class="open ? 'md:text-3xl lg:text-4xl' : 'text-6xl'" | |
>Webapp Factory π</h1> | |
<div | |
class="py-2 space-y-4 text-stone-600 transition-all delay-150 ease-in-out" | |
:class="open ? 'md:text-lg lg:text-xl' : 'text-2xl'"> | |
<p>A space to generate web content with WizardCoder, using an Inference Endpoint.</p> | |
<p>Feel free to duplicate and create interesting forks π§</p> | |
</div> | |
<textarea | |
name="draft" | |
x-model="draft" | |
rows="10" | |
placeholder="a pong clone made using the canvas.." | |
class="input input-bordered w-full rounded text-lg text-stone-500 bg-stone-300 font-mono h-48" | |
></textarea> | |
<button | |
class="btn disabled:text-stone-400" | |
@click="open = true, prompt = draft, state = state === 'stopped' ? 'loading' : 'stopped'" | |
:class="draft.length < minPromptSize ? 'btn-neutral' : state === 'stopped' ? 'btn-accent' : 'btn-warning'" | |
:disabled="draft.length < minPromptSize" | |
> | |
<span x-show="draft.length < minPromptSize">Prompt too short to generate</span> | |
<span x-show="draft.length >= minPromptSize && state !== 'stopped'">Stop now</span> | |
<span x-show="draft.length >= minPromptSize && state === 'stopped'">Generate!</span> | |
</button> | |
<span class="py-3" x-show="state === 'loading'">Waiting for the stream to begin (might take a few minutes)..</span> | |
<span class="py-3" x-show="state === 'streaming'"> | |
Streamed <span x-text="humanFileSize(size, true, 2)"></span> so far<br/> (hang on, this may take a while β)</span> | |
</div> | |
</div> | |
</div> | |
<div | |
class="flex transition-[width] delay-150 ease-in-out" | |
:class="open ? 'w-4/6' : 'w-0'"> | |
<iframe | |
id="iframe" | |
class="border-none w-full h-screen" | |
:src="!open | |
? '/placeholder.html' | |
: `/app?prompt=${prompt}` | |
"></iframe> | |
</div> | |
</div> | |
<script> | |
/** | |
* Format bytes as human-readable text. | |
* | |
* @param bytes Number of bytes. | |
* @param si True to use metric (SI) units, aka powers of 1000. False to use | |
* binary (IEC), aka powers of 1024. | |
* @param dp Number of decimal places to display. | |
* | |
* @return Formatted string. | |
*/ | |
function humanFileSize(bytes, si=false, dp=1) { | |
const thresh = si ? 1000 : 1024; | |
if (Math.abs(bytes) < thresh) { | |
return bytes + ' B'; | |
} | |
const units = si | |
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] | |
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; | |
let u = -1; | |
const r = 10**dp; | |
do { | |
bytes /= thresh; | |
++u; | |
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1); | |
return bytes.toFixed(dp) + ' ' + units[u]; | |
} | |
function app() { | |
return { | |
open: false, | |
draft: new URLSearchParams(window.location.search).get('prompt') || '', | |
prompt: '', | |
size: 0, | |
minPromptSize: 16, // if you change this, you will need to also change in src/index.mts | |
timeoutInSec: 10, // time before we determine something went wrong | |
state: 'stopped', | |
lastTokenAt: + new Date(), | |
init() { | |
setInterval(() => { | |
if (this.state === 'stopped') { | |
this.lastTokenAt = +new Date() | |
return | |
} | |
const html = document?.getElementById('iframe')?.contentWindow?.document?.documentElement?.outerHTML | |
const size = Number(html?.length) // count how many characters we have generated | |
if (isNaN(size) || !isFinite(size)) { | |
this.size = 0 | |
this.state = 'loading' | |
return | |
} | |
this.size = new Blob([html]).size | |
this.state = 'streaming' | |
const lastTokenAt = + new Date() | |
const elapsed = (lastTokenAt - this.lastTokenAt) / 1000 | |
this.lastTokenAt = lastTokenAt | |
if (elapsed > this.timeoutInSec) { | |
console.log(`Something went wrong, it too more than ${timeoutInSec} seconds to generate a token.`) | |
this.state = 'stopped' | |
return | |
} | |
if (html.includes('</html>')) { | |
// console.log('We reached the natural end of the stream, it seems.') | |
// this.state === 'stopped' | |
return | |
} | |
}, 100) | |
}, | |
} | |
} | |
</script> | |
</body> | |
</html> |