File size: 6,461 Bytes
6348944
 
 
fd74d53
 
 
 
6348944
 
fd74d53
6348944
fd74d53
5443231
 
6348944
fd74d53
6348944
fd74d53
 
 
 
5443231
 
 
6348944
fd74d53
 
 
5443231
 
64dea8b
02b4e01
6348944
6b981ec
 
 
 
109f3e6
5443231
6b981ec
6348944
 
64dea8b
 
 
6348944
64dea8b
 
 
6348944
5443231
 
 
6348944
5443231
 
 
6348944
 
 
 
fd74d53
5443231
 
6348944
 
5443231
6348944
 
64dea8b
5443231
 
6348944
 
 
 
5443231
 
 
 
 
 
 
 
 
 
 
6348944
5443231
 
 
6348944
5443231
 
 
 
 
6348944
5443231
 
 
 
6348944
5443231
 
 
 
 
9e78595
 
 
5443231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6348944
5443231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6348944
 
5443231
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<html>
  <head>
    <title>Webapp Factory 🏭</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
    <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.2/iframeResizer.contentWindow.min.js"></script>
  </head>
  <body>
    <div class="flex flex-col md:flex-row" x-data="app()" x-init="init()">
      <div
        class="hero md:h-screen bg-stone-100 transition-[width] delay-150 ease-in-out"
        :class="open ? 'w-full md:w-2/6' : 'w-full md:w-6/6'"
      >
        <div class="hero-content text-center">
          <div class="flex flex-col w-full md:max-w-xl space-y-3 md:space-y-6">
            <h1
              class="font-bold text-stone-600 mb-1 md:mb-4 transition-all delay-150 ease-in-out"
              :class="open
              ? 'text-2xl md:text-3xl lg:text-4xl'
              : 'text-2xl md:text-3xl lg:text-6xl'"
            >
              Webapp Factory 🏭
            </h1>
            <div
              class="py-1 md:py-2 space-y-2 md:space-y-4 text-stone-600 transition-all delay-150 ease-in-out"
              :class="open
              ? 'text-lg md:text-xl lg:text-2xl'
              : 'text-lg md:text-xl lg:text-2xl'"
            >
              <p>A space to generate web content using WizardCoder.</p>
              <p>Running on πŸ€— Inference Endpoints.</p>
            </div>
            <textarea
              name="promptDraft"
              x-model="promptDraft"
              rows="10"
              placeholder="A simple page to compute the BMI (use SI units)"
              class="input input-bordered w-full rounded text-stone-500 bg-stone-300 font-mono text-md md:text-lg h-24 md:h-48"
            ></textarea>
            <button
              class="btn disabled:text-stone-400"
              @click="open = true, prompt = promptDraft, state = state === 'stopped' ? 'loading' : 'stopped'"
              :class="promptDraft.length < minPromptSize ? 'btn-neutral' : state === 'stopped' ? 'btn-accent' : 'btn-warning'"
              :disabled="promptDraft.length < minPromptSize"
            >
              <span x-show="promptDraft.length < minPromptSize">Prompt too short to generate</span>
              <span x-show="promptDraft.length >= minPromptSize && state !== 'stopped'">Stop now</span>
              <span x-show="promptDraft.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 />Note: this version generates up
              to 1024 tokens.</span
            >
          </div>
        </div>
      </div>
      <div
        class="flex transition-[width] delay-150 ease-in-out md:h-screen"
        :class="open ? 'w-full md:w-4/6' : 'w-full md:w-0'"
      >
        <iframe
          id="iframe"
          class="border-none w-full md:min-h-screen p-4 md:p-8"
          :src="!open
            ? '/placeholder.html'
            : `/app?prompt=${encodeURIComponent(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,
          examples: {
            'page about dolphins': 'a page about dolphins, with text and a few pictures'
         },
          promptDraft:
            new URLSearchParams(window.location.search).get("prompt") ||
            "A simple page to compute the BMI (use SI units)",
          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 ${this.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>