Commit 
							
							Β·
						
						4129584
	
0
								Parent(s):
							
							
initial commit π¦
Browse files- .dockerignore +3 -0
- .gitignore +6 -0
- .nvmrc +1 -0
- Dockerfile +27 -0
- LICENSE.txt +201 -0
- README.md +43 -0
- package.json +21 -0
- public/index.html +186 -0
- public/placeholder.html +16 -0
- src/alpine.mts +220 -0
- src/daisy.mts +7 -0
- src/index.mts +155 -0
- tsconfig.json +12 -0
    	
        .dockerignore
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            node_modules
         | 
| 2 | 
            +
            npm-debug.log
         | 
| 3 | 
            +
            models
         | 
    	
        .gitignore
    ADDED
    
    | @@ -0,0 +1,6 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            node_modules
         | 
| 2 | 
            +
            *.log
         | 
| 3 | 
            +
            *.bin
         | 
| 4 | 
            +
            .DS_Store
         | 
| 5 | 
            +
            .venv
         | 
| 6 | 
            +
            models/
         | 
    	
        .nvmrc
    ADDED
    
    | @@ -0,0 +1 @@ | |
|  | 
|  | |
| 1 | 
            +
            v18.16.0
         | 
    	
        Dockerfile
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            FROM node:18
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Set up a new user named "user" with user ID 1000
         | 
| 4 | 
            +
            RUN useradd -o -u 1000 user
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Switch to the "user" user
         | 
| 7 | 
            +
            USER user
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # Set home to the user's home directory
         | 
| 10 | 
            +
            ENV HOME=/home/user \
         | 
| 11 | 
            +
            	PATH=/home/user/.local/bin:$PATH
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # Set the working directory to the user's home directory
         | 
| 14 | 
            +
            WORKDIR $HOME/app
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            # Install app dependencies
         | 
| 17 | 
            +
            # A wildcard is used to ensure both package.json AND package-lock.json are copied
         | 
| 18 | 
            +
            # where available (npm@5+)
         | 
| 19 | 
            +
            COPY --chown=user package*.json $HOME/app
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            RUN npm install
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            # Copy the current directory contents into the container at $HOME/app setting the owner to the user
         | 
| 24 | 
            +
            COPY --chown=user . $HOME/app
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            EXPOSE 7860
         | 
| 27 | 
            +
            CMD [ "npm", "run", "start" ]
         | 
    	
        LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,201 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
                                             Apache License
         | 
| 2 | 
            +
                                       Version 2.0, January 2004
         | 
| 3 | 
            +
                                    http://www.apache.org/licenses/
         | 
| 4 | 
            +
             | 
| 5 | 
            +
               TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
         | 
| 6 | 
            +
             | 
| 7 | 
            +
               1. Definitions.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  "License" shall mean the terms and conditions for use, reproduction,
         | 
| 10 | 
            +
                  and distribution as defined by Sections 1 through 9 of this document.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  "Licensor" shall mean the copyright owner or entity authorized by
         | 
| 13 | 
            +
                  the copyright owner that is granting the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  "Legal Entity" shall mean the union of the acting entity and all
         | 
| 16 | 
            +
                  other entities that control, are controlled by, or are under common
         | 
| 17 | 
            +
                  control with that entity. For the purposes of this definition,
         | 
| 18 | 
            +
                  "control" means (i) the power, direct or indirect, to cause the
         | 
| 19 | 
            +
                  direction or management of such entity, whether by contract or
         | 
| 20 | 
            +
                  otherwise, or (ii) ownership of fifty percent (50%) or more of the
         | 
| 21 | 
            +
                  outstanding shares, or (iii) beneficial ownership of such entity.
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  "You" (or "Your") shall mean an individual or Legal Entity
         | 
| 24 | 
            +
                  exercising permissions granted by this License.
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  "Source" form shall mean the preferred form for making modifications,
         | 
| 27 | 
            +
                  including but not limited to software source code, documentation
         | 
| 28 | 
            +
                  source, and configuration files.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  "Object" form shall mean any form resulting from mechanical
         | 
| 31 | 
            +
                  transformation or translation of a Source form, including but
         | 
| 32 | 
            +
                  not limited to compiled object code, generated documentation,
         | 
| 33 | 
            +
                  and conversions to other media types.
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  "Work" shall mean the work of authorship, whether in Source or
         | 
| 36 | 
            +
                  Object form, made available under the License, as indicated by a
         | 
| 37 | 
            +
                  copyright notice that is included in or attached to the work
         | 
| 38 | 
            +
                  (an example is provided in the Appendix below).
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  "Derivative Works" shall mean any work, whether in Source or Object
         | 
| 41 | 
            +
                  form, that is based on (or derived from) the Work and for which the
         | 
| 42 | 
            +
                  editorial revisions, annotations, elaborations, or other modifications
         | 
| 43 | 
            +
                  represent, as a whole, an original work of authorship. For the purposes
         | 
| 44 | 
            +
                  of this License, Derivative Works shall not include works that remain
         | 
| 45 | 
            +
                  separable from, or merely link (or bind by name) to the interfaces of,
         | 
| 46 | 
            +
                  the Work and Derivative Works thereof.
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  "Contribution" shall mean any work of authorship, including
         | 
| 49 | 
            +
                  the original version of the Work and any modifications or additions
         | 
| 50 | 
            +
                  to that Work or Derivative Works thereof, that is intentionally
         | 
| 51 | 
            +
                  submitted to Licensor for inclusion in the Work by the copyright owner
         | 
| 52 | 
            +
                  or by an individual or Legal Entity authorized to submit on behalf of
         | 
| 53 | 
            +
                  the copyright owner. For the purposes of this definition, "submitted"
         | 
| 54 | 
            +
                  means any form of electronic, verbal, or written communication sent
         | 
| 55 | 
            +
                  to the Licensor or its representatives, including but not limited to
         | 
| 56 | 
            +
                  communication on electronic mailing lists, source code control systems,
         | 
| 57 | 
            +
                  and issue tracking systems that are managed by, or on behalf of, the
         | 
| 58 | 
            +
                  Licensor for the purpose of discussing and improving the Work, but
         | 
| 59 | 
            +
                  excluding communication that is conspicuously marked or otherwise
         | 
| 60 | 
            +
                  designated in writing by the copyright owner as "Not a Contribution."
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  "Contributor" shall mean Licensor and any individual or Legal Entity
         | 
| 63 | 
            +
                  on behalf of whom a Contribution has been received by Licensor and
         | 
| 64 | 
            +
                  subsequently incorporated within the Work.
         | 
| 65 | 
            +
             | 
| 66 | 
            +
               2. Grant of Copyright License. Subject to the terms and conditions of
         | 
| 67 | 
            +
                  this License, each Contributor hereby grants to You a perpetual,
         | 
| 68 | 
            +
                  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
         | 
| 69 | 
            +
                  copyright license to reproduce, prepare Derivative Works of,
         | 
| 70 | 
            +
                  publicly display, publicly perform, sublicense, and distribute the
         | 
| 71 | 
            +
                  Work and such Derivative Works in Source or Object form.
         | 
| 72 | 
            +
             | 
| 73 | 
            +
               3. Grant of Patent License. Subject to the terms and conditions of
         | 
| 74 | 
            +
                  this License, each Contributor hereby grants to You a perpetual,
         | 
| 75 | 
            +
                  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
         | 
| 76 | 
            +
                  (except as stated in this section) patent license to make, have made,
         | 
| 77 | 
            +
                  use, offer to sell, sell, import, and otherwise transfer the Work,
         | 
| 78 | 
            +
                  where such license applies only to those patent claims licensable
         | 
| 79 | 
            +
                  by such Contributor that are necessarily infringed by their
         | 
| 80 | 
            +
                  Contribution(s) alone or by combination of their Contribution(s)
         | 
| 81 | 
            +
                  with the Work to which such Contribution(s) was submitted. If You
         | 
| 82 | 
            +
                  institute patent litigation against any entity (including a
         | 
| 83 | 
            +
                  cross-claim or counterclaim in a lawsuit) alleging that the Work
         | 
| 84 | 
            +
                  or a Contribution incorporated within the Work constitutes direct
         | 
| 85 | 
            +
                  or contributory patent infringement, then any patent licenses
         | 
| 86 | 
            +
                  granted to You under this License for that Work shall terminate
         | 
| 87 | 
            +
                  as of the date such litigation is filed.
         | 
| 88 | 
            +
             | 
| 89 | 
            +
               4. Redistribution. You may reproduce and distribute copies of the
         | 
| 90 | 
            +
                  Work or Derivative Works thereof in any medium, with or without
         | 
| 91 | 
            +
                  modifications, and in Source or Object form, provided that You
         | 
| 92 | 
            +
                  meet the following conditions:
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  (a) You must give any other recipients of the Work or
         | 
| 95 | 
            +
                      Derivative Works a copy of this License; and
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  (b) You must cause any modified files to carry prominent notices
         | 
| 98 | 
            +
                      stating that You changed the files; and
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  (c) You must retain, in the Source form of any Derivative Works
         | 
| 101 | 
            +
                      that You distribute, all copyright, patent, trademark, and
         | 
| 102 | 
            +
                      attribution notices from the Source form of the Work,
         | 
| 103 | 
            +
                      excluding those notices that do not pertain to any part of
         | 
| 104 | 
            +
                      the Derivative Works; and
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  (d) If the Work includes a "NOTICE" text file as part of its
         | 
| 107 | 
            +
                      distribution, then any Derivative Works that You distribute must
         | 
| 108 | 
            +
                      include a readable copy of the attribution notices contained
         | 
| 109 | 
            +
                      within such NOTICE file, excluding those notices that do not
         | 
| 110 | 
            +
                      pertain to any part of the Derivative Works, in at least one
         | 
| 111 | 
            +
                      of the following places: within a NOTICE text file distributed
         | 
| 112 | 
            +
                      as part of the Derivative Works; within the Source form or
         | 
| 113 | 
            +
                      documentation, if provided along with the Derivative Works; or,
         | 
| 114 | 
            +
                      within a display generated by the Derivative Works, if and
         | 
| 115 | 
            +
                      wherever such third-party notices normally appear. The contents
         | 
| 116 | 
            +
                      of the NOTICE file are for informational purposes only and
         | 
| 117 | 
            +
                      do not modify the License. You may add Your own attribution
         | 
| 118 | 
            +
                      notices within Derivative Works that You distribute, alongside
         | 
| 119 | 
            +
                      or as an addendum to the NOTICE text from the Work, provided
         | 
| 120 | 
            +
                      that such additional attribution notices cannot be construed
         | 
| 121 | 
            +
                      as modifying the License.
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  You may add Your own copyright statement to Your modifications and
         | 
| 124 | 
            +
                  may provide additional or different license terms and conditions
         | 
| 125 | 
            +
                  for use, reproduction, or distribution of Your modifications, or
         | 
| 126 | 
            +
                  for any such Derivative Works as a whole, provided Your use,
         | 
| 127 | 
            +
                  reproduction, and distribution of the Work otherwise complies with
         | 
| 128 | 
            +
                  the conditions stated in this License.
         | 
| 129 | 
            +
             | 
| 130 | 
            +
               5. Submission of Contributions. Unless You explicitly state otherwise,
         | 
| 131 | 
            +
                  any Contribution intentionally submitted for inclusion in the Work
         | 
| 132 | 
            +
                  by You to the Licensor shall be under the terms and conditions of
         | 
| 133 | 
            +
                  this License, without any additional terms or conditions.
         | 
| 134 | 
            +
                  Notwithstanding the above, nothing herein shall supersede or modify
         | 
| 135 | 
            +
                  the terms of any separate license agreement you may have executed
         | 
| 136 | 
            +
                  with Licensor regarding such Contributions.
         | 
| 137 | 
            +
             | 
| 138 | 
            +
               6. Trademarks. This License does not grant permission to use the trade
         | 
| 139 | 
            +
                  names, trademarks, service marks, or product names of the Licensor,
         | 
| 140 | 
            +
                  except as required for reasonable and customary use in describing the
         | 
| 141 | 
            +
                  origin of the Work and reproducing the content of the NOTICE file.
         | 
| 142 | 
            +
             | 
| 143 | 
            +
               7. Disclaimer of Warranty. Unless required by applicable law or
         | 
| 144 | 
            +
                  agreed to in writing, Licensor provides the Work (and each
         | 
| 145 | 
            +
                  Contributor provides its Contributions) on an "AS IS" BASIS,
         | 
| 146 | 
            +
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
         | 
| 147 | 
            +
                  implied, including, without limitation, any warranties or conditions
         | 
| 148 | 
            +
                  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
         | 
| 149 | 
            +
                  PARTICULAR PURPOSE. You are solely responsible for determining the
         | 
| 150 | 
            +
                  appropriateness of using or redistributing the Work and assume any
         | 
| 151 | 
            +
                  risks associated with Your exercise of permissions under this License.
         | 
| 152 | 
            +
             | 
| 153 | 
            +
               8. Limitation of Liability. In no event and under no legal theory,
         | 
| 154 | 
            +
                  whether in tort (including negligence), contract, or otherwise,
         | 
| 155 | 
            +
                  unless required by applicable law (such as deliberate and grossly
         | 
| 156 | 
            +
                  negligent acts) or agreed to in writing, shall any Contributor be
         | 
| 157 | 
            +
                  liable to You for damages, including any direct, indirect, special,
         | 
| 158 | 
            +
                  incidental, or consequential damages of any character arising as a
         | 
| 159 | 
            +
                  result of this License or out of the use or inability to use the
         | 
| 160 | 
            +
                  Work (including but not limited to damages for loss of goodwill,
         | 
| 161 | 
            +
                  work stoppage, computer failure or malfunction, or any and all
         | 
| 162 | 
            +
                  other commercial damages or losses), even if such Contributor
         | 
| 163 | 
            +
                  has been advised of the possibility of such damages.
         | 
| 164 | 
            +
             | 
| 165 | 
            +
               9. Accepting Warranty or Additional Liability. While redistributing
         | 
| 166 | 
            +
                  the Work or Derivative Works thereof, You may choose to offer,
         | 
| 167 | 
            +
                  and charge a fee for, acceptance of support, warranty, indemnity,
         | 
| 168 | 
            +
                  or other liability obligations and/or rights consistent with this
         | 
| 169 | 
            +
                  License. However, in accepting such obligations, You may act only
         | 
| 170 | 
            +
                  on Your own behalf and on Your sole responsibility, not on behalf
         | 
| 171 | 
            +
                  of any other Contributor, and only if You agree to indemnify,
         | 
| 172 | 
            +
                  defend, and hold each Contributor harmless for any liability
         | 
| 173 | 
            +
                  incurred by, or claims asserted against, such Contributor by reason
         | 
| 174 | 
            +
                  of your accepting any such warranty or additional liability.
         | 
| 175 | 
            +
             | 
| 176 | 
            +
               END OF TERMS AND CONDITIONS
         | 
| 177 | 
            +
             | 
| 178 | 
            +
               APPENDIX: How to apply the Apache License to your work.
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  To apply the Apache License to your work, attach the following
         | 
| 181 | 
            +
                  boilerplate notice, with the fields enclosed by brackets "[]"
         | 
| 182 | 
            +
                  replaced with your own identifying information. (Don't include
         | 
| 183 | 
            +
                  the brackets!)  The text should be enclosed in the appropriate
         | 
| 184 | 
            +
                  comment syntax for the file format. We also recommend that a
         | 
| 185 | 
            +
                  file or class name and description of purpose be included on the
         | 
| 186 | 
            +
                  same "printed page" as the copyright notice for easier
         | 
| 187 | 
            +
                  identification within third-party archives.
         | 
| 188 | 
            +
             | 
| 189 | 
            +
               Copyright [yyyy] [name of copyright owner]
         | 
| 190 | 
            +
             | 
| 191 | 
            +
               Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 192 | 
            +
               you may not use this file except in compliance with the License.
         | 
| 193 | 
            +
               You may obtain a copy of the License at
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                   http://www.apache.org/licenses/LICENSE-2.0
         | 
| 196 | 
            +
             | 
| 197 | 
            +
               Unless required by applicable law or agreed to in writing, software
         | 
| 198 | 
            +
               distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 199 | 
            +
               WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 200 | 
            +
               See the License for the specific language governing permissions and
         | 
| 201 | 
            +
               limitations under the License.
         | 
    	
        README.md
    ADDED
    
    | @@ -0,0 +1,43 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            title: Webapp Factory Llama
         | 
| 3 | 
            +
            emoji: ππ¦
         | 
| 4 | 
            +
            colorFrom: yellow
         | 
| 5 | 
            +
            colorTo: red
         | 
| 6 | 
            +
            sdk: docker
         | 
| 7 | 
            +
            pinned: false
         | 
| 8 | 
            +
            app_port: 7860
         | 
| 9 | 
            +
            ---
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            A minimalist Docker project to generate web apps on demand using Llama2.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Note: this is for demonstration only: this endpoint isn't supposed to be duplicated, as it uses a private Hugging Face Inference Endpoint.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # Examples
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ## Local prompt examples
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
            http://localhost:7860/?prompt=A%20simple%20page%20to%20compute%20the%20BMI%20(use%20SI%20units)
         | 
| 21 | 
            +
            ```
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            # Installation
         | 
| 24 | 
            +
            ## Building and run without Docker
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ```bash
         | 
| 27 | 
            +
            nvm use
         | 
| 28 | 
            +
            npm i
         | 
| 29 | 
            +
            HF_API_TOKEN=******* HF_END_POINT_URL=https://*******.endpoints.huggingface.cloud npm run start
         | 
| 30 | 
            +
            ```
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ## Building and running with Docker
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            ```bash
         | 
| 35 | 
            +
            npm run docker
         | 
| 36 | 
            +
            ```
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            This script is a shortcut executing the following commands:
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ```bash
         | 
| 41 | 
            +
            docker build -t webapp-factory-llama2 .
         | 
| 42 | 
            +
            docker run -it -p 7860:7860 webapp-factory-llama2
         | 
| 43 | 
            +
            ```
         | 
    	
        package.json
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "name": "webapp-factory-llama2",
         | 
| 3 | 
            +
              "version": "1.0.0",
         | 
| 4 | 
            +
              "description": "A minimalist project to generate webapps without any 3rd party API. Designed to run in a Hugging Face space.",
         | 
| 5 | 
            +
              "main": "src/index.mts",
         | 
| 6 | 
            +
              "scripts": {
         | 
| 7 | 
            +
                "start": "node --loader ts-node/esm src/index.mts",
         | 
| 8 | 
            +
                "test": "node --loader ts-node/esm src/test.mts",
         | 
| 9 | 
            +
                "docker": "npm run docker:build && npm run docker:run",
         | 
| 10 | 
            +
                "docker:build": "docker build -t webapp-factory-llama2 .",
         | 
| 11 | 
            +
                "docker:run": "docker run -it -p 7860:7860 webapp-factory-llama2"
         | 
| 12 | 
            +
              },
         | 
| 13 | 
            +
              "author": "Julian Bilcke <[email protected]>",
         | 
| 14 | 
            +
              "license": "Apache License",
         | 
| 15 | 
            +
              "dependencies": {
         | 
| 16 | 
            +
                "@huggingface/inference": "^2.6.1",
         | 
| 17 | 
            +
                "@types/express": "^4.17.17",
         | 
| 18 | 
            +
                "express": "^4.18.2",
         | 
| 19 | 
            +
                "ts-node": "^10.9.1"
         | 
| 20 | 
            +
              }
         | 
| 21 | 
            +
            }
         | 
    	
        public/index.html
    ADDED
    
    | @@ -0,0 +1,186 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            <html>
         | 
| 2 | 
            +
              <head>
         | 
| 3 | 
            +
                <title>Webapp Factory π</title>
         | 
| 4 | 
            +
                <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
         | 
| 5 | 
            +
                <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
         | 
| 6 | 
            +
                <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
         | 
| 7 | 
            +
                <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.2/iframeResizer.contentWindow.min.js"></script>
         | 
| 8 | 
            +
              </head>
         | 
| 9 | 
            +
              <body>
         | 
| 10 | 
            +
                <div class="flex flex-col md:flex-row" x-data="app()" x-init="init()">
         | 
| 11 | 
            +
                  <div
         | 
| 12 | 
            +
                    class="hero md:h-screen bg-stone-100 transition-[width] delay-150 ease-in-out"
         | 
| 13 | 
            +
                    :class="open ? 'w-full md:w-2/6' : 'w-full md:w-6/6'"
         | 
| 14 | 
            +
                  >
         | 
| 15 | 
            +
                    <div class="hero-content text-center">
         | 
| 16 | 
            +
                      <div class="flex flex-col w-full md:max-w-xl space-y-3 md:space-y-6">
         | 
| 17 | 
            +
                        <h1
         | 
| 18 | 
            +
                          class="font-bold text-stone-600 mb-1 md:mb-3 transition-all delay-150 ease-in-out"
         | 
| 19 | 
            +
                          :class="open
         | 
| 20 | 
            +
                          ? 'text-2xl md:text-3xl lg:text-4xl'
         | 
| 21 | 
            +
                          : 'text-2xl md:text-3xl lg:text-6xl'"
         | 
| 22 | 
            +
                        >
         | 
| 23 | 
            +
                          Webapp Factory π
         | 
| 24 | 
            +
                        </h1>
         | 
| 25 | 
            +
                        <div
         | 
| 26 | 
            +
                          class="py-1 md:py-2 space-y-2 md:space-y-3 text-stone-600 transition-all delay-150 ease-in-out"
         | 
| 27 | 
            +
                          :class="open
         | 
| 28 | 
            +
                          ? 'text-lg lg:text-xl'
         | 
| 29 | 
            +
                          : 'text-lg lg:text-xl'"
         | 
| 30 | 
            +
                        >
         | 
| 31 | 
            +
                          <p>A space to generate tiny web apps.</p>
         | 
| 32 | 
            +
                          <p>In case of hallucination try generating again π²</p>
         | 
| 33 | 
            +
                        </div>
         | 
| 34 | 
            +
                        <textarea
         | 
| 35 | 
            +
                          name="promptDraft"
         | 
| 36 | 
            +
                          x-model="promptDraft"
         | 
| 37 | 
            +
                          rows="10"
         | 
| 38 | 
            +
                          placeholder="Describe your web app"
         | 
| 39 | 
            +
                          class="input w-full rounded text-stone-800 bg-stone-50 border-2 border-stone-400 font-mono text-md md:text-lg h-24 md:h-48"
         | 
| 40 | 
            +
                        ></textarea>
         | 
| 41 | 
            +
                        <p class="py-1 md:py-2 text-stone-700 text-italic">
         | 
| 42 | 
            +
                          Examples:
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                          <a href="/?prompt=a simple page to compute the BMI using metric units" class="text-bold underline">compute my BMI</a>,
         | 
| 45 | 
            +
                          <a href="/?prompt=app listing various types of savanna animals, with their photos" class="text-bold underline">photos of savanna animals</a>
         | 
| 46 | 
            +
                        </p>
         | 
| 47 | 
            +
                        <button
         | 
| 48 | 
            +
                          class="btn disabled:text-stone-400"
         | 
| 49 | 
            +
                          @click="open = true, prompt = promptDraft, state = state === 'stopped' ? 'loading' : 'stopped', state === 'streaming' ? stopGeneration() : true"
         | 
| 50 | 
            +
                          :class="promptDraft.length < minPromptSize ? 'btn-neutral' : state === 'stopped' ? 'btn-accent' : 'btn-warning'"
         | 
| 51 | 
            +
                          :disabled="promptDraft.length < minPromptSize"
         | 
| 52 | 
            +
                        >
         | 
| 53 | 
            +
                          <span x-show="promptDraft.length < minPromptSize">Prompt too short to generate</span>
         | 
| 54 | 
            +
                          <span x-show="promptDraft.length >= minPromptSize && state !== 'stopped'">Stop now</span>
         | 
| 55 | 
            +
                          <span x-show="promptDraft.length >= minPromptSize && state === 'stopped'">Generate!</span>
         | 
| 56 | 
            +
                        </button>
         | 
| 57 | 
            +
                        <div class="flex flex-col text-stone-700 space-y-1 md:space-y-2">
         | 
| 58 | 
            +
                          <p class="text-stone-700">
         | 
| 59 | 
            +
                            Model used:
         | 
| 60 | 
            +
                            <a href="https://huggingface.co/WizardLM/WizardCoder-15B-V1.0" class="underline" target="_blank">
         | 
| 61 | 
            +
                              WizardCoder-15B-1.0
         | 
| 62 | 
            +
                            </a>
         | 
| 63 | 
            +
                          </p>
         | 
| 64 | 
            +
                          <p>Powered by π€ <a href="https://huggingface.co/inference-endpoints" class="underline" target="_blank">Inference Endpoints</a></p>
         | 
| 65 | 
            +
                          <p class="text-stone-700" x-show="state === 'loading'">
         | 
| 66 | 
            +
                            Waiting for the stream to begin (might take a few minutes)..
         | 
| 67 | 
            +
                          </p>
         | 
| 68 | 
            +
                          <p class="text-stone-700" x-show="state === 'streaming'">
         | 
| 69 | 
            +
                            Content size: <span x-text="humanFileSize(size, true, 2)"></span>. This version generates up
         | 
| 70 | 
            +
                            to 1150 tokens.
         | 
| 71 | 
            +
                          </p>
         | 
| 72 | 
            +
                        </div>
         | 
| 73 | 
            +
                      </div>
         | 
| 74 | 
            +
                    </div>
         | 
| 75 | 
            +
                  </div>
         | 
| 76 | 
            +
                  <div
         | 
| 77 | 
            +
                    class="flex flex-col transition-[width] delay-150 ease-in-out md:h-screen"
         | 
| 78 | 
            +
                    :class="open ? 'w-full md:w-4/6' : 'w-full md:w-0'"
         | 
| 79 | 
            +
                  >
         | 
| 80 | 
            +
                    <iframe
         | 
| 81 | 
            +
                      id="iframe"
         | 
| 82 | 
            +
                      class="border-none w-full md:min-h-screen"
         | 
| 83 | 
            +
                      :src="!open
         | 
| 84 | 
            +
                        ? '/placeholder.html'
         | 
| 85 | 
            +
                        : `/app?prompt=${encodeURIComponent(prompt)}`
         | 
| 86 | 
            +
                      "
         | 
| 87 | 
            +
                    ></iframe>
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    <div
         | 
| 90 | 
            +
                      x-show="state !== 'stopped'"
         | 
| 91 | 
            +
                      class="flex w-full -mt-20 items-end justify-center pointer-events-none">
         | 
| 92 | 
            +
                      <div class="flex flex-row py-3 px-8 text-center bg-stone-200 text-stone-600 rounded-md shadow-md">
         | 
| 93 | 
            +
                        <div class="animate-bounce duration-150 mr-1">π€</div>
         | 
| 94 | 
            +
                        <div>Generating your app..</div>
         | 
| 95 | 
            +
                      </div>
         | 
| 96 | 
            +
                    </div>
         | 
| 97 | 
            +
                  </div>
         | 
| 98 | 
            +
                </div>
         | 
| 99 | 
            +
                <script>
         | 
| 100 | 
            +
                  /**
         | 
| 101 | 
            +
                   * Format bytes as human-readable text.
         | 
| 102 | 
            +
                   *
         | 
| 103 | 
            +
                   * @param bytes Number of bytes.
         | 
| 104 | 
            +
                   * @param si True to use metric (SI) units, aka powers of 1000. False to use
         | 
| 105 | 
            +
                   *           binary (IEC), aka powers of 1024.
         | 
| 106 | 
            +
                   * @param dp Number of decimal places to display.
         | 
| 107 | 
            +
                   *
         | 
| 108 | 
            +
                   * @return Formatted string.
         | 
| 109 | 
            +
                   */
         | 
| 110 | 
            +
                  function humanFileSize(bytes, si = false, dp = 1) {
         | 
| 111 | 
            +
                    const thresh = si ? 1000 : 1024;
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    if (Math.abs(bytes) < thresh) {
         | 
| 114 | 
            +
                      return bytes + " B";
         | 
| 115 | 
            +
                    }
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                    const units = si
         | 
| 118 | 
            +
                      ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
         | 
| 119 | 
            +
                      : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
         | 
| 120 | 
            +
                    let u = -1;
         | 
| 121 | 
            +
                    const r = 10 ** dp;
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                    do {
         | 
| 124 | 
            +
                      bytes /= thresh;
         | 
| 125 | 
            +
                      ++u;
         | 
| 126 | 
            +
                    } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                    return bytes.toFixed(dp) + " " + units[u];
         | 
| 129 | 
            +
                  }
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  function stopGeneration() {
         | 
| 132 | 
            +
                    console.log("stopping generation..");
         | 
| 133 | 
            +
                    document?.getElementById("iframe")?.contentWindow?.stop?.();
         | 
| 134 | 
            +
                  }
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  function app() {
         | 
| 137 | 
            +
                    return {
         | 
| 138 | 
            +
                      open: false,
         | 
| 139 | 
            +
                      promptDraft:
         | 
| 140 | 
            +
                        new URLSearchParams(window.location.search).get("prompt") || '',
         | 
| 141 | 
            +
                      prompt: "",
         | 
| 142 | 
            +
                      size: 0,
         | 
| 143 | 
            +
                      minPromptSize: 16, // if you change this, you will need to also change in src/index.mts
         | 
| 144 | 
            +
                      timeoutInSec: 15, // time before we determine something went wrong
         | 
| 145 | 
            +
                      state: "stopped",
         | 
| 146 | 
            +
                      lastTokenAt: +new Date(),
         | 
| 147 | 
            +
                      init() {
         | 
| 148 | 
            +
                        setInterval(() => {
         | 
| 149 | 
            +
                          if (this.state === "stopped") {
         | 
| 150 | 
            +
                            this.lastTokenAt = +new Date();
         | 
| 151 | 
            +
                            return;
         | 
| 152 | 
            +
                          }
         | 
| 153 | 
            +
                          const html = document?.getElementById("iframe")?.contentWindow?.document?.documentElement?.outerHTML;
         | 
| 154 | 
            +
                          const size = Number(html?.length); // count how many characters we have generated
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                          if (isNaN(size) || !isFinite(size)) {
         | 
| 157 | 
            +
                            this.size = 0;
         | 
| 158 | 
            +
                            this.state = "loading";
         | 
| 159 | 
            +
                            return;
         | 
| 160 | 
            +
                          }
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                          this.state = "streaming";
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                          const now = +new Date();
         | 
| 165 | 
            +
                          const newSize = new Blob([html]).size;
         | 
| 166 | 
            +
                          const hasChanged = newSize !== this.size;
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                          if (hasChanged) {
         | 
| 169 | 
            +
                            this.lastTokenAt = now;
         | 
| 170 | 
            +
                          }
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                          this.size = newSize;
         | 
| 173 | 
            +
                 
         | 
| 174 | 
            +
                          const timeSinceLastUpdate = (now - this.lastTokenAt) / 1000;
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                          if (timeSinceLastUpdate > this.timeoutInSec) {
         | 
| 177 | 
            +
                            console.log(`no changes detected for the past ${this.timeoutInSec} seconds -> considering we're done`);
         | 
| 178 | 
            +
                            this.state = "stopped";
         | 
| 179 | 
            +
                          }
         | 
| 180 | 
            +
                        }, 100);
         | 
| 181 | 
            +
                      },
         | 
| 182 | 
            +
                    };
         | 
| 183 | 
            +
                  }
         | 
| 184 | 
            +
                </script>
         | 
| 185 | 
            +
              </body>
         | 
| 186 | 
            +
            </html>
         | 
    	
        public/placeholder.html
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            <html>
         | 
| 2 | 
            +
              <head>
         | 
| 3 | 
            +
                <title>Nothing to show (yet)</title>
         | 
| 4 | 
            +
                <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
         | 
| 5 | 
            +
                <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
         | 
| 6 | 
            +
              </head>
         | 
| 7 | 
            +
              <body>
         | 
| 8 | 
            +
                <div class="hero min-h-screen bg-stone-100">
         | 
| 9 | 
            +
                  <div class="hero-content text-center">
         | 
| 10 | 
            +
                    <div class="flex flex-col max-w-xl space-y-6">
         | 
| 11 | 
            +
                      <h1 class="font-bold text-stone-600 mb-4">Nothing to show here (note: minimum prompt size is 16 characters)</h1>
         | 
| 12 | 
            +
                    </div>
         | 
| 13 | 
            +
                  </div>
         | 
| 14 | 
            +
                </div>
         | 
| 15 | 
            +
              </body>
         | 
| 16 | 
            +
            </html>
         | 
    	
        src/alpine.mts
    ADDED
    
    | @@ -0,0 +1,220 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
             | 
| 2 | 
            +
            interface FeatureAPI {
         | 
| 3 | 
            +
              title: string
         | 
| 4 | 
            +
              description: string
         | 
| 5 | 
            +
              pattern: string
         | 
| 6 | 
            +
            }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            const getPromptFromFeatures = (feats: FeatureAPI[]) =>
         | 
| 9 | 
            +
              feats.map(({ title, description, pattern }) => `## "${title}": ${description}.\nExample: \`${pattern}\``).join("\n")
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            export const attributes: FeatureAPI[] = [
         | 
| 13 | 
            +
              {
         | 
| 14 | 
            +
                title: "x-data",
         | 
| 15 | 
            +
                description: "Declare a new Alpine component and its data for a block of HTML",
         | 
| 16 | 
            +
                pattern:
         | 
| 17 | 
            +
            `<div x-data="{ open: false }">
         | 
| 18 | 
            +
            ...
         | 
| 19 | 
            +
            </div>`
         | 
| 20 | 
            +
              },
         | 
| 21 | 
            +
              {
         | 
| 22 | 
            +
                title: "x-bind",
         | 
| 23 | 
            +
                description: "Dynamically set HTML attributes on an element",
         | 
| 24 | 
            +
                pattern:
         | 
| 25 | 
            +
            `<div x-bind:class="! open ? 'hidden' : ''">
         | 
| 26 | 
            +
            ...
         | 
| 27 | 
            +
            </div>`
         | 
| 28 | 
            +
              },
         | 
| 29 | 
            +
              {
         | 
| 30 | 
            +
                title: "x-on",
         | 
| 31 | 
            +
                description: "Listen for browser events on an element",
         | 
| 32 | 
            +
                pattern:
         | 
| 33 | 
            +
            `<button x-on:click="open = ! open">
         | 
| 34 | 
            +
            Toggle
         | 
| 35 | 
            +
            </button>`
         | 
| 36 | 
            +
              },
         | 
| 37 | 
            +
              {
         | 
| 38 | 
            +
                title: "x-text",
         | 
| 39 | 
            +
                description: "Set the text content of an element",
         | 
| 40 | 
            +
                pattern:
         | 
| 41 | 
            +
            `<div>
         | 
| 42 | 
            +
            Copyright Β©
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            <span x-text="new Date().getFullYear()"></span>
         | 
| 45 | 
            +
            </div>`
         | 
| 46 | 
            +
              },
         | 
| 47 | 
            +
              {
         | 
| 48 | 
            +
                title: "x-html",
         | 
| 49 | 
            +
                description: "Set the inner HTML of an element",
         | 
| 50 | 
            +
                pattern:
         | 
| 51 | 
            +
            `<div x-html="(await axios.get('/some/html/partial')).data">
         | 
| 52 | 
            +
            ...
         | 
| 53 | 
            +
            </div>`
         | 
| 54 | 
            +
              },
         | 
| 55 | 
            +
              {
         | 
| 56 | 
            +
                title: "x-model",
         | 
| 57 | 
            +
                description: "Synchronize a piece of data with an input element",
         | 
| 58 | 
            +
                pattern:
         | 
| 59 | 
            +
            `<div x-data="{ search: '' }">
         | 
| 60 | 
            +
            <input type="text" x-model="search">
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            Searching for: <span x-text="search"></span>
         | 
| 63 | 
            +
            </div>`
         | 
| 64 | 
            +
              },
         | 
| 65 | 
            +
              {
         | 
| 66 | 
            +
                title: "x-show",
         | 
| 67 | 
            +
                description: "Toggle the visibility of an element",
         | 
| 68 | 
            +
                pattern:
         | 
| 69 | 
            +
            `<div x-show="open">
         | 
| 70 | 
            +
            ...
         | 
| 71 | 
            +
            </div>`
         | 
| 72 | 
            +
              },
         | 
| 73 | 
            +
              {
         | 
| 74 | 
            +
                title: "x-transition",
         | 
| 75 | 
            +
                description: "Transition an element in and out using CSS transitions",
         | 
| 76 | 
            +
                pattern:
         | 
| 77 | 
            +
            `<div x-show="open" x-transition>
         | 
| 78 | 
            +
            ...
         | 
| 79 | 
            +
            </div>`
         | 
| 80 | 
            +
              },
         | 
| 81 | 
            +
              {
         | 
| 82 | 
            +
                title: "x-for",
         | 
| 83 | 
            +
                description: "Repeat a block of HTML based on a data set",
         | 
| 84 | 
            +
                pattern:
         | 
| 85 | 
            +
            `<template x-for="post in posts">
         | 
| 86 | 
            +
            <h2 x-text="post.title"></h2>
         | 
| 87 | 
            +
            </template>`
         | 
| 88 | 
            +
              },
         | 
| 89 | 
            +
              {
         | 
| 90 | 
            +
                title: "x-if",
         | 
| 91 | 
            +
                description: "Conditionally add/remove a block of HTML from the page entirely",
         | 
| 92 | 
            +
                pattern:
         | 
| 93 | 
            +
            `<template x-if="open">
         | 
| 94 | 
            +
            <div>...</div>
         | 
| 95 | 
            +
            </template>`
         | 
| 96 | 
            +
              },
         | 
| 97 | 
            +
              {
         | 
| 98 | 
            +
                title: "x-init",
         | 
| 99 | 
            +
                description: "Run code when an element is initialized by Alpine",
         | 
| 100 | 
            +
                pattern:
         | 
| 101 | 
            +
            `<div x-init="date = new Date()"></div>`
         | 
| 102 | 
            +
              },
         | 
| 103 | 
            +
              {
         | 
| 104 | 
            +
                title: "x-effect",
         | 
| 105 | 
            +
                description: "Execute a script each time one of its dependencies change",
         | 
| 106 | 
            +
                pattern:
         | 
| 107 | 
            +
            `<div x-effect="console.log('Count is '+count)"></div>`
         | 
| 108 | 
            +
              },
         | 
| 109 | 
            +
              {
         | 
| 110 | 
            +
                title: "x-ref",
         | 
| 111 | 
            +
                description: "Reference elements directly by their specified keys using the $refs magic property",
         | 
| 112 | 
            +
                pattern:
         | 
| 113 | 
            +
            `<input type="text" x-ref="content">
         | 
| 114 | 
            +
             
         | 
| 115 | 
            +
            <button x-on:click="navigator.clipboard.writeText($refs.content.value)">
         | 
| 116 | 
            +
              Copy
         | 
| 117 | 
            +
            </button>`
         | 
| 118 | 
            +
              },
         | 
| 119 | 
            +
              {
         | 
| 120 | 
            +
                title: "x-cloak",
         | 
| 121 | 
            +
                description: "Hide a block of HTML until after Alpine is finished initializing its contents",
         | 
| 122 | 
            +
                pattern:
         | 
| 123 | 
            +
            `<div x-cloak>
         | 
| 124 | 
            +
            ...
         | 
| 125 | 
            +
            </div>`
         | 
| 126 | 
            +
              },
         | 
| 127 | 
            +
              {
         | 
| 128 | 
            +
                title: "x-ignore",
         | 
| 129 | 
            +
                description: "Prevent a block of HTML from being initialized by Alpine",
         | 
| 130 | 
            +
                pattern:
         | 
| 131 | 
            +
            `<div x-ignore>
         | 
| 132 | 
            +
            ...
         | 
| 133 | 
            +
            </div>`
         | 
| 134 | 
            +
              },
         | 
| 135 | 
            +
            ]
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            export const attributesPrompt = getPromptFromFeatures(attributes)
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            export const properties: FeatureAPI[] = [
         | 
| 140 | 
            +
              {
         | 
| 141 | 
            +
                title: "$store",
         | 
| 142 | 
            +
                description: "Access a global store registered using Alpine.store(...)",
         | 
| 143 | 
            +
                pattern: `<h1 x-text="$store.site.title"></h1>`
         | 
| 144 | 
            +
              },
         | 
| 145 | 
            +
              {
         | 
| 146 | 
            +
                title: "$el",
         | 
| 147 | 
            +
                description: "Reference the current DOM element",
         | 
| 148 | 
            +
                pattern:`<div x-init="new Pikaday($el)"></div>`
         | 
| 149 | 
            +
              },
         | 
| 150 | 
            +
              {
         | 
| 151 | 
            +
                title: "$dispatch",
         | 
| 152 | 
            +
                description: "Dispatch a custom browser event from the current element",
         | 
| 153 | 
            +
                pattern:
         | 
| 154 | 
            +
            `<div x-on:notify="...">
         | 
| 155 | 
            +
              <button x-on:click="$dispatch('notify')">...</button>
         | 
| 156 | 
            +
            </div>`
         | 
| 157 | 
            +
              },
         | 
| 158 | 
            +
              {
         | 
| 159 | 
            +
                title: "$watch",
         | 
| 160 | 
            +
                description: "Watch a piece of data and run the provided callback anytime it changes",
         | 
| 161 | 
            +
                pattern:
         | 
| 162 | 
            +
            `<div x-init="$watch('count', value => {
         | 
| 163 | 
            +
              console.log('count is ' + value)
         | 
| 164 | 
            +
            })">...</div>`
         | 
| 165 | 
            +
              },
         | 
| 166 | 
            +
              {
         | 
| 167 | 
            +
                title: "$refs",
         | 
| 168 | 
            +
                description: "Reference an element by key (specified using x-ref)",
         | 
| 169 | 
            +
                pattern:
         | 
| 170 | 
            +
            `<div x-init="$refs.button.remove()">
         | 
| 171 | 
            +
            <button x-ref="button">Remove Me</button>
         | 
| 172 | 
            +
            </div>`
         | 
| 173 | 
            +
              },
         | 
| 174 | 
            +
              {
         | 
| 175 | 
            +
                title: "$nextTick",
         | 
| 176 | 
            +
                description: "Wait until the next \"tick\" (browser paint) to run a bit of code",
         | 
| 177 | 
            +
                pattern:
         | 
| 178 | 
            +
            `<div
         | 
| 179 | 
            +
            x-text="count"
         | 
| 180 | 
            +
            x-text="$nextTick(() => {"
         | 
| 181 | 
            +
              console.log('count is ' + $el.textContent)
         | 
| 182 | 
            +
            })
         | 
| 183 | 
            +
            >...</div>`
         | 
| 184 | 
            +
              },
         | 
| 185 | 
            +
            ]
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            export const propertiesPrompt = getPromptFromFeatures(properties)
         | 
| 188 | 
            +
             | 
| 189 | 
            +
            export const methods: FeatureAPI[] = [
         | 
| 190 | 
            +
              {
         | 
| 191 | 
            +
                title: "Alpine.data",
         | 
| 192 | 
            +
                description: "Reuse a data object and reference it using x-data",
         | 
| 193 | 
            +
                pattern:
         | 
| 194 | 
            +
            `<div x-data="dropdown">
         | 
| 195 | 
            +
            ...
         | 
| 196 | 
            +
            </div>`
         | 
| 197 | 
            +
              },
         | 
| 198 | 
            +
              {
         | 
| 199 | 
            +
                title: "Alpine.store",
         | 
| 200 | 
            +
                description: "Declare a piece of global, reactive, data that can be accessed from anywhere using $store",
         | 
| 201 | 
            +
                pattern:
         | 
| 202 | 
            +
            `<button @click="$store.notifications.notify('...')">
         | 
| 203 | 
            +
            Notify
         | 
| 204 | 
            +
            </button>
         | 
| 205 | 
            +
             | 
| 206 | 
            +
            ...
         | 
| 207 | 
            +
             | 
| 208 | 
            +
            Alpine.store('notifications', {
         | 
| 209 | 
            +
            items: [],
         | 
| 210 | 
            +
             | 
| 211 | 
            +
            notify(message) { 
         | 
| 212 | 
            +
              this.items.push(message)
         | 
| 213 | 
            +
            }
         | 
| 214 | 
            +
            })`
         | 
| 215 | 
            +
              },
         | 
| 216 | 
            +
            ]
         | 
| 217 | 
            +
             | 
| 218 | 
            +
            export const methodsPrompt = getPromptFromFeatures(methods)
         | 
| 219 | 
            +
             | 
| 220 | 
            +
            export const alpine = "# Alpine.js docs\n"+ attributesPrompt // + propertiesPrompt + methodsPrompt
         | 
    	
        src/daisy.mts
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            export const daisy = `# DaisyUI docs
         | 
| 2 | 
            +
            ## To create a nice layout, wrap each article in:
         | 
| 3 | 
            +
            <article class="prose"></article>
         | 
| 4 | 
            +
            ## Use appropriate CSS classes
         | 
| 5 | 
            +
            <button class="btn ..">
         | 
| 6 | 
            +
            <table class="table ..">
         | 
| 7 | 
            +
            <footer class="footer ..">`
         | 
    	
        src/index.mts
    ADDED
    
    | @@ -0,0 +1,155 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import express from 'express'
         | 
| 2 | 
            +
            import { HfInference } from '@huggingface/inference'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            import { daisy } from './daisy.mts'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            const hfi = new HfInference(process.env.HF_API_TOKEN)
         | 
| 7 | 
            +
            const hf = hfi.endpoint(process.env.HF_ENDPOINT_URL)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            const app = express()
         | 
| 10 | 
            +
            const port = 7860
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            const minPromptSize = 16 // if you change this, you will need to also change in public/index.html
         | 
| 13 | 
            +
            const timeoutInSec = 15 * 60
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            console.log('timeout set to 30 minutes')
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            app.use(express.static('public'))
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            const pending: {
         | 
| 20 | 
            +
              total: number;
         | 
| 21 | 
            +
              queue: string[];
         | 
| 22 | 
            +
            } = {
         | 
| 23 | 
            +
              total: 0,
         | 
| 24 | 
            +
              queue: [],
         | 
| 25 | 
            +
            }
         | 
| 26 | 
            +
             
         | 
| 27 | 
            +
            const endRequest = (id: string, reason: string) => {
         | 
| 28 | 
            +
              if (!id || !pending.queue.includes(id)) {
         | 
| 29 | 
            +
                return
         | 
| 30 | 
            +
              }
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              pending.queue = pending.queue.filter(i => i !== id)
         | 
| 33 | 
            +
              console.log(`request ${id} ended (${reason})`)
         | 
| 34 | 
            +
            }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            app.get('/debug', (req, res) => {
         | 
| 37 | 
            +
              res.write(JSON.stringify({
         | 
| 38 | 
            +
                nbTotal: pending.total,
         | 
| 39 | 
            +
                nbPending: pending.queue.length,
         | 
| 40 | 
            +
                queue: pending.queue,
         | 
| 41 | 
            +
              }))
         | 
| 42 | 
            +
              res.end()
         | 
| 43 | 
            +
            })
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            app.get('/app', async (req, res) => {
         | 
| 46 | 
            +
              if (`${req.query.prompt}`.length < minPromptSize) {
         | 
| 47 | 
            +
                res.write(`prompt too short, please enter at least ${minPromptSize} characters`)
         | 
| 48 | 
            +
                res.end()
         | 
| 49 | 
            +
                return
         | 
| 50 | 
            +
              }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              const id = `${pending.total++}`
         | 
| 53 | 
            +
              console.log(`new request ${id}`)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              pending.queue.push(id)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              const prefix = `<html><head><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"></script><title>Generated content</title><body class="p-4 md:p-8">`
         | 
| 58 | 
            +
              res.write(prefix)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              req.on('close', function() {
         | 
| 61 | 
            +
                endRequest(id, 'browser asked to end the connection')
         | 
| 62 | 
            +
              })
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              setTimeout(() => {
         | 
| 65 | 
            +
                endRequest(id, `timed out after ${timeoutInSec}s`)
         | 
| 66 | 
            +
              }, timeoutInSec * 1000)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
             | 
| 69 | 
            +
              const finalPrompt = `# Task
         | 
| 70 | 
            +
            Generate ${req.query.prompt}
         | 
| 71 | 
            +
            ${daisy}
         | 
| 72 | 
            +
            # Orders
         | 
| 73 | 
            +
            Never repeat those instructions, instead write the final code!
         | 
| 74 | 
            +
            To generate images from captions call the /image API: <img src="/image?caption=photo of something in some place" />!
         | 
| 75 | 
            +
            Only generate a few images and use descriptive photo captions with at least 10 words!
         | 
| 76 | 
            +
            You must use TailwindCSS utility classes (Tailwind is already injected in the page)!
         | 
| 77 | 
            +
            Write application logic inside a JS <script></script> tag!
         | 
| 78 | 
            +
            This is not a demo app, so you MUST use English, no Latin! Write in English! 
         | 
| 79 | 
            +
            Use a central layout to wrap everything in a <div class='flex flex-col items-center'>
         | 
| 80 | 
            +
            # Out
         | 
| 81 | 
            +
            <html>
         | 
| 82 | 
            +
            <head>
         | 
| 83 | 
            +
            <title>App</title>
         | 
| 84 | 
            +
            </head>
         | 
| 85 | 
            +
            <body class="p-4 md:p-8">`
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              try {
         | 
| 88 | 
            +
                let result = ''
         | 
| 89 | 
            +
                for await (const output of hf.textGenerationStream({
         | 
| 90 | 
            +
                  inputs: finalPrompt,
         | 
| 91 | 
            +
                  parameters: {
         | 
| 92 | 
            +
                    do_sample: true,
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    // hard limit for max_new_tokens is 1512
         | 
| 95 | 
            +
                    max_new_tokens: 1150,
         | 
| 96 | 
            +
                    return_full_text: false,
         | 
| 97 | 
            +
                  }
         | 
| 98 | 
            +
                })) {
         | 
| 99 | 
            +
                  if (!pending.queue.includes(id)) {
         | 
| 100 | 
            +
                    break
         | 
| 101 | 
            +
                  }
         | 
| 102 | 
            +
                  result += output.token.text
         | 
| 103 | 
            +
                  process.stdout.write(output.token.text)
         | 
| 104 | 
            +
                  res.write(output.token.text)
         | 
| 105 | 
            +
                  if (result.includes('</html>')) {
         | 
| 106 | 
            +
                    break
         | 
| 107 | 
            +
                  }
         | 
| 108 | 
            +
                  if (result.includes('<|end|>') || result.includes('<|assistant|>')) {
         | 
| 109 | 
            +
                    break
         | 
| 110 | 
            +
                  }
         | 
| 111 | 
            +
                }
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                endRequest(id, `normal end of the LLM stream for request ${id}`)
         | 
| 114 | 
            +
              } catch (e) {
         | 
| 115 | 
            +
                console.log(e)
         | 
| 116 | 
            +
                endRequest(id, `premature end of the LLM stream for request ${id} (${e})`)
         | 
| 117 | 
            +
              } 
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              try {
         | 
| 120 | 
            +
                res.end()
         | 
| 121 | 
            +
              } catch (err) {
         | 
| 122 | 
            +
                console.log(`couldn't end the HTTP stream for request ${id} (${err})`)
         | 
| 123 | 
            +
              }
         | 
| 124 | 
            +
              
         | 
| 125 | 
            +
            })
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            app.get('/image', async (req, res) => {
         | 
| 128 | 
            +
              try {
         | 
| 129 | 
            +
                const blob = await hfi.textToImage({
         | 
| 130 | 
            +
                  inputs: [
         | 
| 131 | 
            +
                    `${req.query.caption || 'generic placeholder'}`,
         | 
| 132 | 
            +
                    'award winning',
         | 
| 133 | 
            +
                    'high resolution',
         | 
| 134 | 
            +
                    'photo realistic',
         | 
| 135 | 
            +
                    'intricate details',
         | 
| 136 | 
            +
                    'beautiful',
         | 
| 137 | 
            +
                    '[trending on artstation]'
         | 
| 138 | 
            +
                  ].join(', '),
         | 
| 139 | 
            +
                  model: 'stabilityai/stable-diffusion-2-1',
         | 
| 140 | 
            +
                  parameters: {
         | 
| 141 | 
            +
                    negative_prompt: 'blurry, artificial, cropped, low quality, ugly',
         | 
| 142 | 
            +
                  }
         | 
| 143 | 
            +
                })
         | 
| 144 | 
            +
                const buffer = Buffer.from(await blob.arrayBuffer())
         | 
| 145 | 
            +
                res.setHeader('Content-Type', blob.type)
         | 
| 146 | 
            +
                res.setHeader('Content-Length', buffer.length)
         | 
| 147 | 
            +
                res.end(buffer)
         | 
| 148 | 
            +
              } catch (err) {
         | 
| 149 | 
            +
                console.error(`Error when generating the image: ${err.message}`);
         | 
| 150 | 
            +
                res.status(500).json({ error: 'An error occurred when trying to generate the image' });
         | 
| 151 | 
            +
              }
         | 
| 152 | 
            +
            })
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            app.listen(port, () => { console.log(`Open http://localhost:${port}`) })
         | 
| 155 | 
            +
             | 
    	
        tsconfig.json
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
               "compilerOptions": {
         | 
| 3 | 
            +
                "allowJs": true,
         | 
| 4 | 
            +
                "esModuleInterop": true,
         | 
| 5 | 
            +
                "allowSyntheticDefaultImports": true,
         | 
| 6 | 
            +
                "module": "nodenext",
         | 
| 7 | 
            +
                "noEmit": true,
         | 
| 8 | 
            +
                "allowImportingTsExtensions": true,
         | 
| 9 | 
            +
                "target": "es2017"
         | 
| 10 | 
            +
              },
         | 
| 11 | 
            +
              "include": ["**/*.ts", "**/*.mts"],
         | 
| 12 | 
            +
            }
         | 
