├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── LICENSE ├── README.md ├── components ├── ChatBox.tsx ├── Icons.tsx ├── InitModal.tsx ├── SideBar.tsx └── markdown.tsx ├── docs ├── README_CN.md ├── README_JA.md └── images │ ├── cover.png │ ├── home.png │ ├── icon.jpg │ └── mobile.png ├── hooks ├── useStore.ts └── web-llm.ts ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.tsx ├── _document.tsx └── index.tsx ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── assets │ └── icons │ │ ├── icon-128x128.png │ │ ├── icon-144x144.png │ │ ├── icon-152x152.png │ │ ├── icon-192x192.png │ │ ├── icon-384x384.png │ │ ├── icon-48x48.png │ │ ├── icon-512x512.png │ │ ├── icon-72x72.png │ │ └── icon-96x96.png ├── favicon.ico ├── github-mark-white.svg ├── lib │ └── WebLLM │ │ ├── config.json │ │ ├── sentencepiece.js │ │ ├── tvmjs.bundle.js │ │ ├── tvmjs_runtime.wasi.js │ │ └── vicuna-7b │ │ ├── ndarray-cache.json │ │ ├── tokenizer.model │ │ └── vicuna-7b-v1_webgpu.wasm ├── loading.svg ├── manifest.json ├── user.jpg └── vicuna.jpeg ├── store └── chat.ts ├── styles └── globals.css ├── tailwind.config.js ├── tsconfig.json ├── types ├── chat.ts └── web-llm.ts ├── utils ├── codeblock.ts └── opts.ts └── web-worker └── web-llm.worker.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | public/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { "react/no-unescaped-entities": 0 } 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | # next-pwa 38 | /public/precache.*.*.js 39 | /public/sw.js 40 | /public/workbox-*.js 41 | /public/worker-*.js 42 | /public/fallback-*.js 43 | /public/precache.*.*.js.map 44 | /public/sw.js.map 45 | /public/workbox-*.js.map 46 | /public/worker-*.js.map 47 | /public/fallback-*.js -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | public 3 | out 4 | node_modules -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | singleQuote: true, 4 | plugins: [ 5 | 'prettier-plugin-tailwindcss', 6 | '@trivago/prettier-plugin-sort-imports', 7 | ], 8 | importOrder: [ 9 | 'react', // React 10 | '^react-.*$', // React-related imports 11 | '^next', // Next-related imports 12 | '^next-.*$', // Next-related imports 13 | '^next/.*$', // Next-related imports 14 | '^.*/hooks/.*$', // Hooks 15 | '^.*/services/.*$', // Services 16 | '^.*/utils/.*$', // Utils 17 | '^.*/types/.*$', // Types 18 | '^.*/pages/.*$', // Components 19 | '^.*/components/.*$', // Components 20 | '^[./]', // Other imports 21 | '.*', // Any uncaught imports 22 | ], 23 | importOrderSeparation: true, 24 | importOrderSortSpecifiers: true, 25 | }; 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ryan-yang125 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | icon 3 | 4 |

ChatLLM Web

5 |

🚀 Check the AI search engine https://discovai.io, discover top ai tools that best match your need

6 | 7 | English / [简体中文](./docs/README_CN.md) / [日本語](./docs/README_JA.md) 8 | 9 | 🗣️ Chat with LLM like Vicuna totally in your browser with WebGPU, safely, privately, and with no server. Powered By [web-llm](https://github.com/mlc-ai/web-llm). 10 | 11 | [Try it now](https://chat-llm-web.vercel.app) 12 | 13 | ![cover](./docs/images/cover.png) 14 | 15 |
16 | 17 | ## Features 18 | 19 | - 🤖 Everything runs inside the browser with **no server support** and is **accelerated with WebGPU**. 20 | 21 | - ⚙️ Model runs in a web worker, ensuring that it doesn't block the user interface and providing a seamless experience. 22 | 23 | - 🚀 Easy to deploy for free with one-click on Vercel in under 1 minute, then you get your own ChatLLM Web. 24 | 25 | - 💾 Model caching is supported, so you only need to download the model once. 26 | 27 | - 💬 Multi-conversation chat, with all data stored locally in the browser for privacy. 28 | 29 | - 📝 Markdown and streaming response support: math, code highlighting, etc. 30 | 31 | - 🎨 responsive and well-designed UI, including dark mode. 32 | 33 | - 💻 PWA supported, download it and run totally offline. 34 | 35 | ## Instructions 36 | 37 | - 🌐 To use this app, you need a browser that supports WebGPU, such as Chrome 113 or Chrome Canary. Chrome versions ≤ 112 are not supported. 38 | 39 | - 💻 You will need a GPU with about 6.4GB of memory. If your GPU has less memory, the app will still run, but the response time will be slower. 40 | 41 | - 📥 The first time you use the app, you will need to download the model. For the Vicuna-7b model that we are currently using, the download size is about 4GB. After the initial download, the model will be loaded from the browser cache for faster usage. 42 | 43 | - ℹ️ For more details, please visit [mlc.ai/web-llm](https://mlc.ai/web-llm/) 44 | 45 | ## Roadmap 46 | 47 | - [✅] LLM: using web worker to create an LLM instance and generate answers. 48 | 49 | - [✅] Conversations: Multi-conversation support is available. 50 | 51 | - [✅] PWA 52 | 53 | - [] Settings: 54 | - ui: dark/light theme 55 | - device: 56 | - gpu device choose 57 | - cache usage and manage 58 | - model: 59 | - support multi models: vicuna-7b✅ RedPajama-INCITE-Chat-3B [] 60 | - params config: temperature, max-length, etc. 61 | - export & import model 62 | 63 | ## Deploy to Vercel 64 | 65 | 1. Click 66 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FRyan-yang125%2FChatLLM-Web&project-name=chat-llm-web&repository-name=ChatLLM-Web), follow the instructions, and finish in just 1 minute. 67 | 2. Enjoy it 😊 68 | 69 | ## Development 70 | 71 | ```shell 72 | git clone https://github.com/Ryan-yang125/ChatLLM-Web.git 73 | cd ChatLLM-Web 74 | npm i 75 | npm run dev 76 | ``` 77 | 78 | ## Screenshots 79 | 80 | ![Home](./docs/images/home.png) 81 | 82 | ![More](./docs/images/mobile.png) 83 | 84 | ## 🌟 History 85 | [![Star History Chart](https://api.star-history.com/svg?repos=Ryan-yang125/ChatLLM-Web&type=Date)](https://star-history.com/#Ryan-yang125/ChatLLM-Web&Date) 86 | 87 | ## LICENSE 88 | 89 | [MIT](./LICENSE) 90 | -------------------------------------------------------------------------------- /components/ChatBox.tsx: -------------------------------------------------------------------------------- 1 | import React, { useLayoutEffect, useRef, useState } from 'react'; 2 | 3 | import dynamic from 'next/dynamic'; 4 | import Image from 'next/image'; 5 | 6 | import { IconDelete, IconRename, IconSend } from './Icons'; 7 | 8 | import { Loading } from '@/pages'; 9 | import { useChatStore } from '@/store/chat'; 10 | 11 | const Markdown = dynamic(async () => (await import('./markdown')).Markdown, { 12 | loading: () => , 13 | }); 14 | 15 | function useScrollToBottom() { 16 | // for auto-scroll 17 | const scrollRef = useRef(null); 18 | const [autoScroll, setAutoScroll] = useState(true); 19 | const scrollToBottom = () => { 20 | const dom = scrollRef.current; 21 | if (dom) { 22 | setTimeout(() => (dom.scrollTop = dom.scrollHeight), 1); 23 | } 24 | }; 25 | 26 | // auto scroll 27 | useLayoutEffect(() => { 28 | autoScroll && scrollToBottom(); 29 | }); 30 | 31 | return { 32 | scrollRef, 33 | autoScroll, 34 | setAutoScroll, 35 | scrollToBottom, 36 | }; 37 | } 38 | 39 | const shouldSubmit = (e: React.KeyboardEvent) => { 40 | if (e.key !== 'Enter') return false; 41 | if (e.key === 'Enter' && e.nativeEvent.isComposing) return false; 42 | return e.ctrlKey; 43 | }; 44 | export function ChatBox() { 45 | const [userInput, setUserInput] = useState(''); 46 | 47 | const [curConversationIndex] = useChatStore((state) => [ 48 | state.curConversationIndex, 49 | ]); 50 | const chatStore = useChatStore(); 51 | const onInput = (text: string) => { 52 | setUserInput(text); 53 | }; 54 | const { scrollRef, setAutoScroll, scrollToBottom } = useScrollToBottom(); 55 | 56 | const submitUserInput = async () => { 57 | if (userInput.length <= 0) return; 58 | chatStore.onUserInputContent(userInput); 59 | setUserInput(''); 60 | scrollToBottom(); 61 | setAutoScroll(true); 62 | }; 63 | 64 | const onInputKeyDown = (e: React.KeyboardEvent) => { 65 | if (shouldSubmit(e)) { 66 | submitUserInput(); 67 | } 68 | }; 69 | 70 | return ( 71 | <> 72 |
73 |
74 |
75 |
76 | {chatStore.curConversation()?.title ?? ''} 77 |
78 |
79 | {chatStore.curConversation()?.messages?.length ?? 0} messages with 80 | Vicuna 81 |
82 |
83 | 84 |
85 | 99 | 105 |
106 |
107 |
111 | {chatStore.curConversation()?.messages.map((item, i) => ( 112 |
118 |
119 |
120 | 128 |
129 |
130 |
131 | 134 |
135 |
136 | {item.isLoading ? ( 137 | 138 | ) : item.type === 'assistant' ? ( 139 | 140 | ) : ( 141 |
{item.content}
142 | )} 143 |
144 |
{item.statsText}
145 |
146 | ))} 147 |
148 |
149 |
150 | 159 | 165 |
166 |
167 |
168 | 169 | ); 170 | } 171 | -------------------------------------------------------------------------------- /components/Icons.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function IconRename() { 4 | return ( 5 | 13 | 18 | 19 | ); 20 | } 21 | 22 | export function IconDelete() { 23 | return ( 24 | 32 | 37 | 38 | ); 39 | } 40 | 41 | export function IconSend() { 42 | return ( 43 | 51 | 56 | 57 | ); 58 | } 59 | 60 | export function IconDone() { 61 | return ( 62 | 70 | 75 | 76 | ); 77 | } 78 | 79 | export function IconCopy() { 80 | return ( 81 | 89 | 94 | 95 | ); 96 | } 97 | 98 | export function IconDownload() { 99 | return ( 100 | 108 | 113 | 114 | ); 115 | } 116 | 117 | export function IconInfo() { 118 | return ( 119 | 127 | 132 | 133 | ); 134 | } 135 | 136 | export function IconSetting() { 137 | return ( 138 | 146 | 151 | 156 | 157 | ); 158 | } 159 | 160 | export function IconAdd() { 161 | return ( 162 | 170 | 175 | 176 | ); 177 | } 178 | -------------------------------------------------------------------------------- /components/InitModal.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Link from 'next/link'; 4 | 5 | import { useChatStore } from '@/store/chat'; 6 | 7 | function InitItem(props: { content: string; isError: boolean }) { 8 | return ( 9 | <> 10 |
  • 11 | {props.content} 12 |
  • 13 | 14 | ); 15 | } 16 | export function InitModal() { 17 | const [initInfoTmp] = useChatStore((state) => [state.initInfoTmp]); 18 | 19 | const chatStore = useChatStore(); 20 | return ( 21 | <> 22 |
    23 |
    24 | {initInfoTmp.initMsg.findIndex((msg) => msg.isError) !== -1 && ( 25 | 32 | )} 33 |

    Loading Model...

    34 |
      35 | {initInfoTmp.initMsg.map((msg) => ( 36 | 41 | ))} 42 |
    43 |
    44 |
    45 | 46 | ); 47 | } 48 | 49 | export function InstructionModal() { 50 | const [instructionModalStatus] = useChatStore((state) => [ 51 | state.instructionModalStatus, 52 | ]); 53 | 54 | const chatStore = useChatStore(); 55 | return ( 56 | <> 57 |
    58 |
    59 |

    Instructions

    60 |

    61 | 62 | WebLLM 63 | 64 | brings language model chats directly onto web browsers. Everything 65 | runs inside the browser with no server support and accelerated with 66 | WebGPU. For more details, check in{' '} 67 | 68 | WebLLM 69 | 70 |

    71 |

    Here are some instructions about this app:

    72 |
      73 |
    • 1. We use model Vicuna-7b.
    • 74 |
    • 75 | 2. Using browser supports WebGPU, you can try out Chrome 113 or 76 | Chrome Canary. Chrome version ≤ 112 is not supported. 77 |
    • 78 |
    • 79 | 3. First init requires download model, for vicuna-7b-v1.1, it 80 | abouts 4GB. After downloading once, we can load modol from browser 81 | cache for next time usage, it's faster. 82 |
    • 83 |
    • 84 | 4. You will need a gpu with about 6.4G memory. If lower than that, 85 | it's ok to run, but slow to wait for response. 86 |
    • 87 |
    88 |
    89 | 96 |
    97 |
    98 |
    99 | 100 | ); 101 | } 102 | -------------------------------------------------------------------------------- /components/SideBar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Image from 'next/image'; 4 | import Link from 'next/link'; 5 | 6 | import { IconAdd, IconInfo, IconSetting } from './Icons'; 7 | 8 | import { useChatStore } from '@/store/chat'; 9 | 10 | function BottomSettings() { 11 | const chatStore = useChatStore(); 12 | return ( 13 |
    14 |
    15 | 21 |
    22 | 25 |
    26 | 31 | 32 | 33 |
    34 | 40 |
    41 | ); 42 | } 43 | 44 | export const ChatItem = (props: { 45 | onClick?: () => void; 46 | title: string; 47 | timeText: string; 48 | index: number; 49 | messageCount: number; 50 | isActive: boolean; 51 | }) => { 52 | return ( 53 |
  • 54 | 55 |
    56 |
    {props.title}
    57 |
    58 |
    Messages: {props.messageCount}
    59 |
    {props.timeText}
    60 |
    61 |
    62 |
    63 |
  • 64 | ); 65 | }; 66 | 67 | export const Sidebar = () => { 68 | const [conversations, curConversationIndex] = useChatStore((state) => [ 69 | state.conversations, 70 | state.curConversationIndex, 71 | ]); 72 | const chatStore = useChatStore(); 73 | return ( 74 |
    75 |
    76 | 81 |
    82 |
    ChatLLM-Web
    83 |
    84 | 85 |
    86 | AI assitant running in browser. 87 |
    88 |
    89 |
    90 |
      91 | {conversations.map((item, i) => ( 92 | chatStore.chooseConversation(i)} 100 | /> 101 | ))} 102 |
    103 |
    104 |
    105 | 106 |
    107 | ); 108 | }; 109 | -------------------------------------------------------------------------------- /components/markdown.tsx: -------------------------------------------------------------------------------- 1 | import { FC, RefObject, memo, useState } from 'react'; 2 | import ReactMarkdown, { Options } from 'react-markdown'; 3 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 4 | import { dracula } from 'react-syntax-highlighter/dist/cjs/styles/prism'; 5 | 6 | import { generateRandomString, programmingLanguages } from '@/utils/codeblock'; 7 | 8 | import { Message } from '@/types/chat'; 9 | 10 | import { IconCopy, IconDone, IconDownload } from './Icons'; 11 | 12 | import rehypeMathjax from 'rehype-mathjax'; 13 | import remarkGfm from 'remark-gfm'; 14 | import remarkMath from 'remark-math'; 15 | 16 | const MemoizedReactMarkdown: FC = memo( 17 | ReactMarkdown, 18 | (prevProps, nextProps) => prevProps.children === nextProps.children, 19 | ); 20 | 21 | interface Props { 22 | language: string; 23 | value: string; 24 | } 25 | 26 | const CodeBlock: FC = memo(({ language, value }) => { 27 | const [isCopied, setIsCopied] = useState(false); 28 | 29 | const copyToClipboard = () => { 30 | if (!navigator.clipboard || !navigator.clipboard.writeText) { 31 | return; 32 | } 33 | 34 | navigator.clipboard.writeText(value).then(() => { 35 | setIsCopied(true); 36 | 37 | setTimeout(() => { 38 | setIsCopied(false); 39 | }, 2000); 40 | }); 41 | }; 42 | const downloadAsFile = () => { 43 | const fileExtension = programmingLanguages[language] || '.file'; 44 | const suggestedFileName = `file-${generateRandomString( 45 | 3, 46 | true, 47 | )}${fileExtension}`; 48 | const fileName = window.prompt('Enter file name', suggestedFileName); 49 | 50 | if (!fileName) { 51 | // user pressed cancel on prompt 52 | return; 53 | } 54 | 55 | const blob = new Blob([value], { type: 'text/plain' }); 56 | const url = URL.createObjectURL(blob); 57 | const link = document.createElement('a'); 58 | link.download = fileName; 59 | link.href = url; 60 | link.style.display = 'none'; 61 | document.body.appendChild(link); 62 | link.click(); 63 | document.body.removeChild(link); 64 | URL.revokeObjectURL(url); 65 | }; 66 | return ( 67 |
    68 |
    69 | {language} 70 | 71 |
    72 | 75 | 78 |
    79 |
    80 | 81 | 86 | {value} 87 | 88 |
    89 | ); 90 | }); 91 | 92 | export function Markdown( 93 | props: { 94 | message: Message; 95 | loading?: boolean; 96 | fontSize?: number; 97 | parentRef?: RefObject; 98 | defaultShow?: boolean; 99 | } & React.DOMAttributes, 100 | ) { 101 | return ( 102 | ▍ 112 | ); 113 | } 114 | 115 | children[0] = (children[0] as string).replace('`▍`', '▍'); 116 | } 117 | 118 | const match = /language-(\w+)/.exec(className || ''); 119 | 120 | return !inline ? ( 121 | 127 | ) : ( 128 | 129 | {children} 130 | 131 | ); 132 | }, 133 | table({ children }) { 134 | return ( 135 | 136 | {children} 137 |
    138 | ); 139 | }, 140 | th({ children }) { 141 | return ( 142 | 143 | {children} 144 | 145 | ); 146 | }, 147 | td({ children }) { 148 | return ( 149 | 150 | {children} 151 | 152 | ); 153 | }, 154 | }} 155 | > 156 | {props.message.content} 157 |
    158 | ); 159 | } 160 | CodeBlock.displayName = 'CodeBlock'; 161 | -------------------------------------------------------------------------------- /docs/README_CN.md: -------------------------------------------------------------------------------- 1 |
    2 | icon 3 | 4 |

    ChatLLM Web

    5 | 6 | [English](../README.md) / 简体中文 / [日本語](./README_JA.md) 7 | 8 | 🗣️ 使用 WebGPU 在浏览器中与 LLM(语言模型)进行聊天,完全安全、私密,无需服务器。 由 [web-llm](https://github.com/mlc-ai/web-llm) 提供支持。 9 | 10 | [Try it now](https://chat-llm-web.vercel.app) 11 | 12 | ![cover](./images/cover.png) 13 | 14 |
    15 | 16 | ## Features 17 | 18 | - 🤖 一切都在浏览器内运行,无需服务器支持,并且使用 WebGPU 进行加速。 19 | 20 | - ⚙️ 模型在 Web Worker 中运行,确保不会阻塞用户界面,提供无缝体验 21 | 22 | - 🚀 通过在 Vercel 上单击一次即可轻松免费部署,不到 1 分钟,即可获得自己的 ChatLLM Web。 23 | 24 | - 💾 支持模型缓存,因此您只需要下载模型一次。 25 | 26 | - 💬 多对话聊天,所有数据都存储在浏览器中,以保护隐私。 27 | 28 | - 📝 支持 Markdown 和流式响应:数学、代码高亮等。 29 | 30 | - 🎨 响应式和设计良好的 UI,包括暗黑模式。 31 | 32 | - 💻 支持 PWA,在下载后可完全离线运行。 33 | 34 | ## Instructions 35 | 36 | - 🌐 要使用此应用程序,您需要使用支持 WebGPU 的浏览器,例如 Chrome 113 或 Chrome Canary。不支持 Chrome 版本 ≤ 112。 37 | 38 | - 💻 您需要具有约 6.4GB 的内存的 GPU。如果您的 GPU 内存较少,则应用程序仍将运行,但响应时间会较慢。 39 | 40 | - 📥 第一次使用应用程序时,您需要下载模型。对于我们当前使用的 Vicuna-7b 模型,下载大小约为 4GB。初始下载后,模型将从浏览器缓存中加载,以加快使用速度。 41 | 42 | - ℹ️ 有关更多详细信息,请访问 [mlc.ai/web-llm](https://mlc.ai/web-llm/) 43 | 44 | ## Roadmap 45 | 46 | - [✅] LLM:使用 Web Worker 创建 LLM 实例并生成答案。 47 | 48 | - [✅] 对话:支持多对话。 49 | 50 | - [] 桌面版:使用 Tauri 构建桌面版,它将使用系统缓存(而不仅仅是浏览器缓存)并在本地和离线运行。 51 | 52 | - [] UI:暗黑和明亮主题。 53 | 54 | ## Deploy to Vercel 55 | 56 | 1. 单击 57 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FRyan-yang125%2FChatLLM-Web&project-name=chat-llm-web&repository-name=ChatLLM-Web),按照说明操作,只需 1 分钟即可完成。 58 | 2. 尽情享受吧 😊 59 | 60 | ## Development 61 | 62 | ```shell 63 | git clone https://github.com/Ryan-yang125/ChatLLM-Web.git 64 | npm i 65 | npm run dev 66 | ``` 67 | 68 | ## Screenshots 69 | 70 | ![Home](./images/home.png) 71 | 72 | ![More](./images/mobile.png) 73 | 74 | ## LICENSE 75 | 76 | [MIT](./LICENSE) 77 | -------------------------------------------------------------------------------- /docs/README_JA.md: -------------------------------------------------------------------------------- 1 |
    2 | icon 3 | 4 |

    ChatLLM Web

    5 | 6 | [English](../README.md) / [简体中文](./README_CN.md) / 日本語 7 | 8 | 🗣️ Vicuna のような LLM と、WebGPU を使ってブラウザ上で安全に変えるかつプライベートに、そしてサーバを介さずに完全にチャットすることができます。[web-llm](https://github.com/mlc-ai/web-llm) を搭載。 9 | 10 | [Try it now](https://chat-llm-web.vercel.app) 11 | 12 | ![cover](./images/cover.png) 13 | 14 |
    15 | 16 | ## 特徴 17 | 18 | - 🤖 **サーバーサポートなし** ですべてがブラウザ内で実行され、**WebGPU で加速されます**。 19 | 20 | - ⚙️ モデルはウェブワーカーで実行されるため、ユーザーインターフェイスをブロックすることなく、シームレスなエクスペリエンスを提供します。 21 | 22 | - 🚀 Vercel のワンクリックで1分以内に無料で簡単にデプロイでき、その後、あなた自身の ChatLLM Web を手に入れることができます。 23 | 24 | - 💾 モデルのキャッシュがサポートされているので、モデルのダウンロードは一度のみでよい。 25 | 26 | - 💬 マルチ会話チャットは、全てのデータがブラウザにローカルに保存され、プライバシーが守られます。 27 | 28 | - 📝 Markdown とストリーミングレスポンスのサポート: 数学、コードハイライトなど。 29 | 30 | - 🎨 ダークモードを含む、レスポンシブでデザイン性の高い UI。 31 | 32 | - 💻 PWA に対応し、ダウンロードして完全にオフラインで実行できます。 33 | 34 | ## 使用方法 35 | 36 | - 🌐 このアプリを使用するには、Chrome 113 や Chrome Canary など、WebGPU をサポートするブラウザが必要です。Chrome のバージョン ≦ 112 はサポートされていません。 37 | 38 | - 💻 約 6.4GB のメモリを搭載した GPU が必要です。GPU のメモリが少ない場合でも、アプリは実行されますが、応答時間は遅くなります。 39 | 40 | - 📥 初めてアプリを使用する際は、モデルのダウンロードが必要です。現在使用している Vicuna-7b モデルの場合、ダウンロードサイズは約 4GB です。初回ダウンロード後は、ブラウザのキャッシュからモデルを読み込むことで、より高速に使用することができます。 41 | 42 | - ℹ️ 詳細は [mlc.ai/web-llm](https://mlc.ai/web-llm/) をご参照ください 43 | 44 | ## ロードマップ 45 | 46 | - [✅] LLM: Web Workerを使用してLLMインスタンスを作成し、回答を生成する。 47 | 48 | - [✅] 会話: Multi-conversation に対応しています 49 | 50 | - [✅] PWA 51 | 52 | - [] Settings: 53 | - ui: ダーク/ライトテーマ 54 | - デバイス: 55 | - gpu デバイスの選択 56 | - キャッシュの使用量と管理 57 | - モデル: 58 | - マルチモデル対応: vicuna-7b✅ RedPajama-INCITE-Chat-3B [] 59 | - パラメータ設定: temperature, max-length など。 60 | - モデルのエクスポートとインポート 61 | 62 | ## Vercel へのデプロイ 63 | 64 | 1. クリック 65 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FRyan-yang125%2FChatLLM-Web&project-name=chat-llm-web&repository-name=ChatLLM-Web)の指示に従うことで、わずか1分で終了します。 66 | 2. 楽しんでください 😊 67 | 68 | ## デプロイ 69 | 70 | ```shell 71 | git clone https://github.com/Ryan-yang125/ChatLLM-Web.git 72 | cd ChatLLM-Web 73 | npm i 74 | npm run dev 75 | ``` 76 | 77 | ## スクリーンショット 78 | 79 | ![Home](./images/home.png) 80 | 81 | ![More](./images/mobile.png) 82 | 83 | ## ライセンス 84 | 85 | [MIT](./LICENSE) 86 | -------------------------------------------------------------------------------- /docs/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/docs/images/cover.png -------------------------------------------------------------------------------- /docs/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/docs/images/home.png -------------------------------------------------------------------------------- /docs/images/icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/docs/images/icon.jpg -------------------------------------------------------------------------------- /docs/images/mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/docs/images/mobile.png -------------------------------------------------------------------------------- /hooks/useStore.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export const useStore = ( 4 | store: (callback: (state: T) => unknown) => unknown, 5 | callback: (state: T) => F, 6 | ) => { 7 | const result = store(callback) as F; 8 | const [data, setData] = useState(); 9 | 10 | useEffect(() => { 11 | setData(result); 12 | }, [result]); 13 | 14 | return data; 15 | }; 16 | -------------------------------------------------------------------------------- /hooks/web-llm.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LLMEngine, 3 | ResFromWorkerMessageEventData, 4 | SendToWorkerMessageEventData, 5 | } from '@/types/web-llm'; 6 | 7 | class WebLLM { 8 | private worker?: Worker = undefined; 9 | 10 | public destroy(): void { 11 | globalThis.tvmjsGlobalEnv?.asyncOnReset(); 12 | this.worker?.terminate(); 13 | } 14 | 15 | public setConversationHistroy(data: SendToWorkerMessageEventData): void { 16 | if (!this.worker) { 17 | this.worker = new Worker( 18 | new URL('web-worker/web-llm.worker.ts', import.meta.url), 19 | { name: 'WebLLM' }, 20 | ); 21 | } 22 | this.worker?.postMessage(data); 23 | } 24 | 25 | public async chat( 26 | data: SendToWorkerMessageEventData, 27 | workerMessageCb: (data: ResFromWorkerMessageEventData) => void, 28 | ): Promise { 29 | if (!this.worker) { 30 | this.worker = new Worker( 31 | new URL('web-worker/web-llm.worker.ts', import.meta.url), 32 | { name: 'WebLLM' }, 33 | ); 34 | } 35 | this.worker?.postMessage(data); 36 | 37 | this.worker?.addEventListener( 38 | 'message', 39 | ({ data }: { data: ResFromWorkerMessageEventData }) => { 40 | workerMessageCb(data); 41 | }, 42 | ); 43 | 44 | // requestAnimationFrame(() => this.worker?.postMessage(message)); 45 | 46 | // return new Promise((resolve) => { 47 | // this.worker?.addEventListener('message', ({ data }: { data: string }) => 48 | // resolve(data), 49 | // ); 50 | // }); 51 | } 52 | } 53 | 54 | const WebLLMInstance = new WebLLM(); 55 | export { WebLLMInstance }; 56 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | // /** @type {import('next').NextConfig} */ 2 | const withPWA = require('next-pwa')({ 3 | dest: 'public', 4 | }); 5 | module.exports = withPWA({ 6 | webpack(config, { isServer, dev }) { 7 | config.experiments = { 8 | asyncWebAssembly: true, 9 | layers: true, 10 | ...config.experiments, 11 | topLevelAwait: true, 12 | }; 13 | 14 | return config; 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat-llm-web", 3 | "version": "1.0.0", 4 | "private": false, 5 | "description": "Chat with LLM totally in your browser with WebGPU, safely, privately, and with no server.", 6 | "author": { 7 | "name": "Ryan-yang125", 8 | "email": "ruiyang0012@gmail.com", 9 | "url": "https://github.com/Ryan-yang125" 10 | }, 11 | "license": "MIT", 12 | "scripts": { 13 | "dev": "next dev", 14 | "build": "next build", 15 | "start": "next start", 16 | "lint": "next lint", 17 | "dev:local": "npm run dev && /Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary --enable-dawn-features=disable_robustness", 18 | "format": "prettier --write .", 19 | "export": "next export" 20 | }, 21 | "dependencies": { 22 | "@types/node": "18.16.0", 23 | "@types/react": "18.0.38", 24 | "@types/react-dom": "18.0.11", 25 | "@vercel/analytics": "^1.0.1", 26 | "autoprefixer": "10.4.14", 27 | "daisyui": "^2.51.5", 28 | "eslint": "8.39.0", 29 | "eslint-config-next": "13.3.1", 30 | "file-saver": "^2.0.5", 31 | "jszip": "^3.10.1", 32 | "next": "13.3.1", 33 | "next-pwa": "^5.6.0", 34 | "postcss": "8.4.23", 35 | "react": "18.2.0", 36 | "react-dom": "18.2.0", 37 | "react-markdown": "^8.0.7", 38 | "react-syntax-highlighter": "^15.5.0", 39 | "rehype-mathjax": "^4.0.2", 40 | "remark-gfm": "^3.0.1", 41 | "remark-math": "^5.1.1", 42 | "tailwindcss": "3.3.1", 43 | "typescript": "5.0.4", 44 | "zustand": "^4.3.7" 45 | }, 46 | "engines": { 47 | "node": ">=18" 48 | }, 49 | "devDependencies": { 50 | "@tailwindcss/typography": "^0.5.9", 51 | "@trivago/prettier-plugin-sort-imports": "^4.1.1", 52 | "@types/file-saver": "^2.0.5", 53 | "@types/react-syntax-highlighter": "^15.5.6", 54 | "eslint-config-prettier": "^8.8.0", 55 | "eslint-plugin-prettier": "^4.2.1", 56 | "prettier": "^2.8.7", 57 | "prettier-plugin-tailwindcss": "^0.2.7" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { Analytics } from '@vercel/analytics/react'; 2 | 3 | import type { AppProps } from 'next/app'; 4 | 5 | import '@/styles/globals.css'; 6 | 7 | export default function App({ Component, pageProps }: AppProps) { 8 | return ( 9 | <> 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Head, Html, Main, NextScript } from 'next/document'; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 | ChatLLM Web - Chat with LLM like Vicuna in Your Browser | Powered By 9 | web-llm 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
    22 | 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | 3 | import dynamic from 'next/dynamic'; 4 | import Image from 'next/image'; 5 | 6 | import { InitModal, InstructionModal } from '@/components/InitModal'; 7 | 8 | import { useChatStore } from '@/store/chat'; 9 | 10 | export function Loading() { 11 | return ( 12 |
    13 | 20 |
    21 | ); 22 | } 23 | const Sidebar = dynamic( 24 | async () => (await import('../components/SideBar')).Sidebar, 25 | { 26 | loading: () => , 27 | }, 28 | ); 29 | 30 | const ChatBox = dynamic( 31 | async () => (await import('../components/ChatBox')).ChatBox, 32 | { 33 | loading: () => , 34 | }, 35 | ); 36 | 37 | const useHasHydrated = () => { 38 | const [hasHydrated, setHasHydrated] = useState(false); 39 | 40 | useEffect(() => { 41 | setHasHydrated(true); 42 | }, []); 43 | 44 | return hasHydrated; 45 | }; 46 | 47 | function Home() { 48 | const [setWorkerConversationHistroy] = useChatStore((state) => [ 49 | state.setWorkerConversationHistroy, 50 | ]); 51 | useEffect(() => { 52 | setWorkerConversationHistroy(); 53 | }, []); 54 | const loading = !useHasHydrated(); 55 | if (loading) { 56 | return ; 57 | } 58 | 59 | return ( 60 | <> 61 |
    62 | 63 |
    64 | {/* */} 65 | 66 |
    67 |
    68 | 69 | 72 |
    73 |
    74 | 75 | 76 | 77 | ); 78 | } 79 | 80 | export default Home; 81 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/assets/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-128x128.png -------------------------------------------------------------------------------- /public/assets/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-144x144.png -------------------------------------------------------------------------------- /public/assets/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-152x152.png -------------------------------------------------------------------------------- /public/assets/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-192x192.png -------------------------------------------------------------------------------- /public/assets/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-384x384.png -------------------------------------------------------------------------------- /public/assets/icons/icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-48x48.png -------------------------------------------------------------------------------- /public/assets/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-512x512.png -------------------------------------------------------------------------------- /public/assets/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-72x72.png -------------------------------------------------------------------------------- /public/assets/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/assets/icons/icon-96x96.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/favicon.ico -------------------------------------------------------------------------------- /public/github-mark-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/lib/WebLLM/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "kvConfig": { 3 | "numLayers": 64, 4 | "shape": [32, 32, 128], 5 | "dtype": "float32" 6 | }, 7 | "wasmUrl": "/lib/WebLLM/vicuna-7b/vicuna-7b-v1_webgpu.wasm", 8 | "cacheUrl": "https://huggingface.co/mlc-ai/web-lm/resolve/main/vicuna-7b-v1/", 9 | "tokenizer": "/lib/WebLLM/vicuna-7b/tokenizer.model", 10 | "maxGenLength": 1024, 11 | "meanGenLength": 256, 12 | "maxWindowLength": 2048 13 | } 14 | -------------------------------------------------------------------------------- /public/lib/WebLLM/tvmjs_runtime.wasi.js: -------------------------------------------------------------------------------- 1 | 2 | function EmccWASI() { 3 | var Module=typeof Module!="undefined"?Module:{};var __wasmLib={};function __wasmLibInstantiateWasm(imports,successCallback){__wasmLib.imports=imports;__wasmLib.successCallback=successCallback}function __wasmLibStart(wasmInstance){__wasmLib.successCallback(wasmInstance)}__wasmLib.start=__wasmLibStart;var Module={"instantiateWasm":__wasmLibInstantiateWasm,"wasmLibraryProvider":__wasmLib};var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;function logExceptionOnExit(e){if(e instanceof ExitStatus)return;let toLog=e;if(e&&typeof e=="object"&&e.stack){toLog=[e,e.stack]}err("exiting due to exception: "+toLog)}if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,function(err,data){if(err)onerror(err);else onload(data.buffer)})};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);if(typeof module!="undefined"){module["exports"]=Module}process.on("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});var nodeMajor=process.versions.node.split(".")[0];if(nodeMajor<15){process.on("unhandledRejection",function(reason){throw reason})}quit_=(status,toThrow)=>{if(keepRuntimeAlive()){process.exitCode=status;throw toThrow}logExceptionOnExit(toThrow);process.exit(status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAP64,HEAPU64,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);Module["HEAP64"]=HEAP64=new BigInt64Array(b);Module["HEAPU64"]=HEAPU64=new BigUint64Array(b)}var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function keepRuntimeAlive(){return noExitRuntime}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="tvmjs_runtime.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}catch(err){abort(err)}}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(binaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(binaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(binaryFile)})}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(function(binary){return WebAssembly.instantiate(binary,imports)}).then(function(instance){return instance}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}else{return instantiateArrayBuffer(binaryFile,imports,callback)}}function createWasm(){var info={"env":wasmImports,"wasi_snapshot_preview1":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["memory"];updateMemoryViews();wasmTable=Module["asm"]["__indirect_function_table"];removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}function callRuntimeCallbacks(callbacks){while(callbacks.length>0){callbacks.shift()(Module)}}function _TVMWasmPackedCFunc(){err("missing function: TVMWasmPackedCFunc");abort(-1)}function _TVMWasmPackedCFuncFinalizer(){err("missing function: TVMWasmPackedCFuncFinalizer");abort(-1)}function __ZN3tvm7runtime9threading10NumThreadsEv(){err("missing function: _ZN3tvm7runtime9threading10NumThreadsEv");abort(-1)}function __ZN3tvm7runtime9threading15ResetThreadPoolEv(){err("missing function: _ZN3tvm7runtime9threading15ResetThreadPoolEv");abort(-1)}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){_emscripten_get_now=()=>{var t=process.hrtime();return t[0]*1e3+t[1]/1e6}}else _emscripten_get_now=()=>performance.now();var nowIsMonotonic=true;function checkWasiClock(clock_id){return clock_id==0||clock_id==1||clock_id==2||clock_id==3}var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>{return PATH.normalize(l+"/"+r)}};function getRandomDevice(){if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){var randomBuffer=new Uint8Array(1);return()=>{crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");return()=>crypto_module["randomBytes"](1)[0]}catch(e){}}return()=>abort("randomDevice")}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.fsync(stream.tty)},fsync:function(stream){stream.tty.ops.fsync(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};function mmapAlloc(size){abort()}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr:function(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup:function(parent,name){throw FS.genericErrors[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir:function(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink:function(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read:function(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)}var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagModes:{"r":0,"r+":2,"w":577,"w+":578,"a":1089,"a+":1090},modeStringToFlags:str=>{var flags=FS.flagModes[str];if(typeof flags=="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:(fd_start=0,fd_end=FS.MAX_OPEN_FDS)=>{for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd_start,fd_end)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}},flags:{get:function(){return this.shared.flags},set:function(val){this.shared.flags=val}},position:{get:function(){return this.shared.position},set:function(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS.modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error('Invalid encoding type "'+opts.encoding+'"')}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var random_device=getRandomDevice();FS.createDevice("/dev","random",random_device);FS.createDevice("/dev","urandom",random_device);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode},findObject:(path,dontResolveLastLink)=>{var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS.getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i{for(var i=0;i{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node},createPreloadedFile:(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency("cp "+fullname);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(Browser.handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}},indexedDB:()=>{return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB},DB_NAME:()=>{return"EM_FS_"+window.location.pathname},DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:(paths,onload=(()=>{}),onerror=(()=>{}))=>{var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=()=>{out("creating db");var db=openRequest.result;db.createObjectStore(FS.DB_STORE_NAME)};openRequest.onsuccess=()=>{var db=openRequest.result;var transaction=db.transaction([FS.DB_STORE_NAME],"readwrite");var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var putRequest=files.put(FS.analyzePath(path).object.contents,path);putRequest.onsuccess=()=>{ok++;if(ok+fail==total)finish()};putRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror},loadFilesFromDB:(paths,onload=(()=>{}),onerror=(()=>{}))=>{var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=onerror;openRequest.onsuccess=()=>{var db=openRequest.result;try{var transaction=db.transaction([FS.DB_STORE_NAME],"readonly")}catch(e){onerror(e);return}var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var getRequest=files.get(path);getRequest.onsuccess=()=>{if(FS.analyzePath(path).exists){FS.unlink(path)}FS.createDataFile(PATH.dirname(path),PATH.basename(path),getRequest.result,true,true,true);ok++;if(ok+fail==total)finish()};getRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAPU32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];HEAPU32[buf+96>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+104>>2]=tempI64[0],HEAP32[buf+108>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream}};function _clock_time_get(clk_id,ignored_precision,ptime){if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=Date.now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP32[ptime>>2]=nsec>>>0;HEAP32[ptime+4>>2]=nsec/Math.pow(2,32)>>>0;return 0}function _emscripten_notify_memory_growth(memoryIndex){updateMemoryViews()}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAPU32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doReadv(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var MAX_INT53=9007199254740992;var MIN_INT53=-9007199254740992;function bigintToI53Checked(num){return numMAX_INT53?NaN:Number(num)}function _fd_seek(fd,offset,whence,newOffset){try{offset=bigintToI53Checked(offset);if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doWritev(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _proc_exit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}function exitJS(status,implicit){EXITSTATUS=status;_proc_exit(status)}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();var wasmImports={"TVMWasmPackedCFunc":_TVMWasmPackedCFunc,"TVMWasmPackedCFuncFinalizer":_TVMWasmPackedCFuncFinalizer,"_ZN3tvm7runtime9threading10NumThreadsEv":__ZN3tvm7runtime9threading10NumThreadsEv,"_ZN3tvm7runtime9threading15ResetThreadPoolEv":__ZN3tvm7runtime9threading15ResetThreadPoolEv,"clock_time_get":_clock_time_get,"emscripten_notify_memory_growth":_emscripten_notify_memory_growth,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"fd_close":_fd_close,"fd_read":_fd_read,"fd_seek":_fd_seek,"fd_write":_fd_write,"proc_exit":_proc_exit};var asm=createWasm();var __ZN3tvm7runtime17GetCustomTypeNameEh=Module["__ZN3tvm7runtime17GetCustomTypeNameEh"]=function(){return(__ZN3tvm7runtime17GetCustomTypeNameEh=Module["__ZN3tvm7runtime17GetCustomTypeNameEh"]=Module["asm"]["_ZN3tvm7runtime17GetCustomTypeNameEh"]).apply(null,arguments)};var __ZN3tvm7runtime8Registry3GetERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE=Module["__ZN3tvm7runtime8Registry3GetERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]=function(){return(__ZN3tvm7runtime8Registry3GetERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE=Module["__ZN3tvm7runtime8Registry3GetERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]=Module["asm"]["_ZN3tvm7runtime8Registry3GetERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]).apply(null,arguments)};var __ZN3tvm7runtime23GetCustomTypeRegisteredEh=Module["__ZN3tvm7runtime23GetCustomTypeRegisteredEh"]=function(){return(__ZN3tvm7runtime23GetCustomTypeRegisteredEh=Module["__ZN3tvm7runtime23GetCustomTypeRegisteredEh"]=Module["asm"]["_ZN3tvm7runtime23GetCustomTypeRegisteredEh"]).apply(null,arguments)};var __ZN3tvm7runtime19ParseCustomDatatypeERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPPKc=Module["__ZN3tvm7runtime19ParseCustomDatatypeERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPPKc"]=function(){return(__ZN3tvm7runtime19ParseCustomDatatypeERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPPKc=Module["__ZN3tvm7runtime19ParseCustomDatatypeERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPPKc"]=Module["asm"]["_ZN3tvm7runtime19ParseCustomDatatypeERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPPKc"]).apply(null,arguments)};var _TVMGetLastError=Module["_TVMGetLastError"]=function(){return(_TVMGetLastError=Module["_TVMGetLastError"]=Module["asm"]["TVMGetLastError"]).apply(null,arguments)};var _TVMAPISetLastError=Module["_TVMAPISetLastError"]=function(){return(_TVMAPISetLastError=Module["_TVMAPISetLastError"]=Module["asm"]["TVMAPISetLastError"]).apply(null,arguments)};var _TVMModLoadFromFile=Module["_TVMModLoadFromFile"]=function(){return(_TVMModLoadFromFile=Module["_TVMModLoadFromFile"]=Module["asm"]["TVMModLoadFromFile"]).apply(null,arguments)};var __ZN3tvm7runtime6Module12LoadFromFileERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_=Module["__ZN3tvm7runtime6Module12LoadFromFileERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_"]=function(){return(__ZN3tvm7runtime6Module12LoadFromFileERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_=Module["__ZN3tvm7runtime6Module12LoadFromFileERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_"]=Module["asm"]["_ZN3tvm7runtime6Module12LoadFromFileERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_"]).apply(null,arguments)};var _TVMModImport=Module["_TVMModImport"]=function(){return(_TVMModImport=Module["_TVMModImport"]=Module["asm"]["TVMModImport"]).apply(null,arguments)};var _TVMModGetFunction=Module["_TVMModGetFunction"]=function(){return(_TVMModGetFunction=Module["_TVMModGetFunction"]=Module["asm"]["TVMModGetFunction"]).apply(null,arguments)};var _TVMModFree=Module["_TVMModFree"]=function(){return(_TVMModFree=Module["_TVMModFree"]=Module["asm"]["TVMModFree"]).apply(null,arguments)};var _TVMObjectFree=Module["_TVMObjectFree"]=function(){return(_TVMObjectFree=Module["_TVMObjectFree"]=Module["asm"]["TVMObjectFree"]).apply(null,arguments)};var _TVMBackendGetFuncFromEnv=Module["_TVMBackendGetFuncFromEnv"]=function(){return(_TVMBackendGetFuncFromEnv=Module["_TVMBackendGetFuncFromEnv"]=Module["asm"]["TVMBackendGetFuncFromEnv"]).apply(null,arguments)};var _TVMBackendAllocWorkspace=Module["_TVMBackendAllocWorkspace"]=function(){return(_TVMBackendAllocWorkspace=Module["_TVMBackendAllocWorkspace"]=Module["asm"]["TVMBackendAllocWorkspace"]).apply(null,arguments)};var _TVMBackendFreeWorkspace=Module["_TVMBackendFreeWorkspace"]=function(){return(_TVMBackendFreeWorkspace=Module["_TVMBackendFreeWorkspace"]=Module["asm"]["TVMBackendFreeWorkspace"]).apply(null,arguments)};var _TVMBackendRunOnce=Module["_TVMBackendRunOnce"]=function(){return(_TVMBackendRunOnce=Module["_TVMBackendRunOnce"]=Module["asm"]["TVMBackendRunOnce"]).apply(null,arguments)};var _TVMFuncFree=Module["_TVMFuncFree"]=function(){return(_TVMFuncFree=Module["_TVMFuncFree"]=Module["asm"]["TVMFuncFree"]).apply(null,arguments)};var _TVMByteArrayFree=Module["_TVMByteArrayFree"]=function(){return(_TVMByteArrayFree=Module["_TVMByteArrayFree"]=Module["asm"]["TVMByteArrayFree"]).apply(null,arguments)};var _TVMFuncCall=Module["_TVMFuncCall"]=function(){return(_TVMFuncCall=Module["_TVMFuncCall"]=Module["asm"]["TVMFuncCall"]).apply(null,arguments)};var _TVMCFuncSetReturn=Module["_TVMCFuncSetReturn"]=function(){return(_TVMCFuncSetReturn=Module["_TVMCFuncSetReturn"]=Module["asm"]["TVMCFuncSetReturn"]).apply(null,arguments)};var _TVMFuncCreateFromCFunc=Module["_TVMFuncCreateFromCFunc"]=function(){return(_TVMFuncCreateFromCFunc=Module["_TVMFuncCreateFromCFunc"]=Module["asm"]["TVMFuncCreateFromCFunc"]).apply(null,arguments)};var _TVMStreamCreate=Module["_TVMStreamCreate"]=function(){return(_TVMStreamCreate=Module["_TVMStreamCreate"]=Module["asm"]["TVMStreamCreate"]).apply(null,arguments)};var _TVMStreamFree=Module["_TVMStreamFree"]=function(){return(_TVMStreamFree=Module["_TVMStreamFree"]=Module["asm"]["TVMStreamFree"]).apply(null,arguments)};var _TVMSetStream=Module["_TVMSetStream"]=function(){return(_TVMSetStream=Module["_TVMSetStream"]=Module["asm"]["TVMSetStream"]).apply(null,arguments)};var _TVMSynchronize=Module["_TVMSynchronize"]=function(){return(_TVMSynchronize=Module["_TVMSynchronize"]=Module["asm"]["TVMSynchronize"]).apply(null,arguments)};var _TVMStreamStreamSynchronize=Module["_TVMStreamStreamSynchronize"]=function(){return(_TVMStreamStreamSynchronize=Module["_TVMStreamStreamSynchronize"]=Module["asm"]["TVMStreamStreamSynchronize"]).apply(null,arguments)};var _TVMCbArgToReturn=Module["_TVMCbArgToReturn"]=function(){return(_TVMCbArgToReturn=Module["_TVMCbArgToReturn"]=Module["asm"]["TVMCbArgToReturn"]).apply(null,arguments)};var _TVMDeviceAllocDataSpace=Module["_TVMDeviceAllocDataSpace"]=function(){return(_TVMDeviceAllocDataSpace=Module["_TVMDeviceAllocDataSpace"]=Module["asm"]["TVMDeviceAllocDataSpace"]).apply(null,arguments)};var _TVMDeviceAllocDataSpaceWithScope=Module["_TVMDeviceAllocDataSpaceWithScope"]=function(){return(_TVMDeviceAllocDataSpaceWithScope=Module["_TVMDeviceAllocDataSpaceWithScope"]=Module["asm"]["TVMDeviceAllocDataSpaceWithScope"]).apply(null,arguments)};var _TVMDeviceFreeDataSpace=Module["_TVMDeviceFreeDataSpace"]=function(){return(_TVMDeviceFreeDataSpace=Module["_TVMDeviceFreeDataSpace"]=Module["asm"]["TVMDeviceFreeDataSpace"]).apply(null,arguments)};var _TVMDeviceCopyDataFromTo=Module["_TVMDeviceCopyDataFromTo"]=function(){return(_TVMDeviceCopyDataFromTo=Module["_TVMDeviceCopyDataFromTo"]=Module["asm"]["TVMDeviceCopyDataFromTo"]).apply(null,arguments)};var __ZN3tvm7runtime8Registry8RegisterERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb=Module["__ZN3tvm7runtime8Registry8RegisterERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb"]=function(){return(__ZN3tvm7runtime8Registry8RegisterERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb=Module["__ZN3tvm7runtime8Registry8RegisterERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb"]=Module["asm"]["_ZN3tvm7runtime8Registry8RegisterERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEb"]).apply(null,arguments)};var _TVMBackendParallelLaunch=Module["_TVMBackendParallelLaunch"]=function(){return(_TVMBackendParallelLaunch=Module["_TVMBackendParallelLaunch"]=Module["asm"]["TVMBackendParallelLaunch"]).apply(null,arguments)};var _TVMBackendParallelBarrier=Module["_TVMBackendParallelBarrier"]=function(){return(_TVMBackendParallelBarrier=Module["_TVMBackendParallelBarrier"]=Module["asm"]["TVMBackendParallelBarrier"]).apply(null,arguments)};var __ZN3tvm7runtime8Registry9ListNamesEv=Module["__ZN3tvm7runtime8Registry9ListNamesEv"]=function(){return(__ZN3tvm7runtime8Registry9ListNamesEv=Module["__ZN3tvm7runtime8Registry9ListNamesEv"]=Module["asm"]["_ZN3tvm7runtime8Registry9ListNamesEv"]).apply(null,arguments)};var __ZN3tvm7runtime9BacktraceEv=Module["__ZN3tvm7runtime9BacktraceEv"]=function(){return(__ZN3tvm7runtime9BacktraceEv=Module["__ZN3tvm7runtime9BacktraceEv"]=Module["asm"]["_ZN3tvm7runtime9BacktraceEv"]).apply(null,arguments)};var __ZN3tvm7runtime14RuntimeEnabledERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE=Module["__ZN3tvm7runtime14RuntimeEnabledERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE"]=function(){return(__ZN3tvm7runtime14RuntimeEnabledERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE=Module["__ZN3tvm7runtime14RuntimeEnabledERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE"]=Module["asm"]["_ZN3tvm7runtime14RuntimeEnabledERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray10CreateViewENS0_10ShapeTupleE10DLDataType=Module["__ZN3tvm7runtime7NDArray10CreateViewENS0_10ShapeTupleE10DLDataType"]=function(){return(__ZN3tvm7runtime7NDArray10CreateViewENS0_10ShapeTupleE10DLDataType=Module["__ZN3tvm7runtime7NDArray10CreateViewENS0_10ShapeTupleE10DLDataType"]=Module["asm"]["_ZN3tvm7runtime7NDArray10CreateViewENS0_10ShapeTupleE10DLDataType"]).apply(null,arguments)};var __ZNK3tvm7runtime7NDArray8ToDLPackEv=Module["__ZNK3tvm7runtime7NDArray8ToDLPackEv"]=function(){return(__ZNK3tvm7runtime7NDArray8ToDLPackEv=Module["__ZNK3tvm7runtime7NDArray8ToDLPackEv"]=Module["asm"]["_ZNK3tvm7runtime7NDArray8ToDLPackEv"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray5EmptyENS0_10ShapeTupleE10DLDataType8DLDeviceNS0_8OptionalINS0_6StringEEE=Module["__ZN3tvm7runtime7NDArray5EmptyENS0_10ShapeTupleE10DLDataType8DLDeviceNS0_8OptionalINS0_6StringEEE"]=function(){return(__ZN3tvm7runtime7NDArray5EmptyENS0_10ShapeTupleE10DLDataType8DLDeviceNS0_8OptionalINS0_6StringEEE=Module["__ZN3tvm7runtime7NDArray5EmptyENS0_10ShapeTupleE10DLDataType8DLDeviceNS0_8OptionalINS0_6StringEEE"]=Module["asm"]["_ZN3tvm7runtime7NDArray5EmptyENS0_10ShapeTupleE10DLDataType8DLDeviceNS0_8OptionalINS0_6StringEEE"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray20FromExternalDLTensorERK8DLTensor=Module["__ZN3tvm7runtime7NDArray20FromExternalDLTensorERK8DLTensor"]=function(){return(__ZN3tvm7runtime7NDArray20FromExternalDLTensorERK8DLTensor=Module["__ZN3tvm7runtime7NDArray20FromExternalDLTensorERK8DLTensor"]=Module["asm"]["_ZN3tvm7runtime7NDArray20FromExternalDLTensorERK8DLTensor"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray9IsAlignedERK8DLTensor=Module["__ZN3tvm7runtime7NDArray9IsAlignedERK8DLTensor"]=function(){return(__ZN3tvm7runtime7NDArray9IsAlignedERK8DLTensor=Module["__ZN3tvm7runtime7NDArray9IsAlignedERK8DLTensor"]=Module["asm"]["_ZN3tvm7runtime7NDArray9IsAlignedERK8DLTensor"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray15NewFromDLTensorEP8DLTensorRK8DLDevice=Module["__ZN3tvm7runtime7NDArray15NewFromDLTensorEP8DLTensorRK8DLDevice"]=function(){return(__ZN3tvm7runtime7NDArray15NewFromDLTensorEP8DLTensorRK8DLDevice=Module["__ZN3tvm7runtime7NDArray15NewFromDLTensorEP8DLTensorRK8DLDevice"]=Module["asm"]["_ZN3tvm7runtime7NDArray15NewFromDLTensorEP8DLTensorRK8DLDevice"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray10FromDLPackEP15DLManagedTensor=Module["__ZN3tvm7runtime7NDArray10FromDLPackEP15DLManagedTensor"]=function(){return(__ZN3tvm7runtime7NDArray10FromDLPackEP15DLManagedTensor=Module["__ZN3tvm7runtime7NDArray10FromDLPackEP15DLManagedTensor"]=Module["asm"]["_ZN3tvm7runtime7NDArray10FromDLPackEP15DLManagedTensor"]).apply(null,arguments)};var __ZNK3tvm7runtime7NDArray11CopyToBytesEPvm=Module["__ZNK3tvm7runtime7NDArray11CopyToBytesEPvm"]=function(){return(__ZNK3tvm7runtime7NDArray11CopyToBytesEPvm=Module["__ZNK3tvm7runtime7NDArray11CopyToBytesEPvm"]=Module["asm"]["_ZNK3tvm7runtime7NDArray11CopyToBytesEPvm"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray13CopyFromBytesEPKvm=Module["__ZN3tvm7runtime7NDArray13CopyFromBytesEPKvm"]=function(){return(__ZN3tvm7runtime7NDArray13CopyFromBytesEPKvm=Module["__ZN3tvm7runtime7NDArray13CopyFromBytesEPKvm"]=Module["asm"]["_ZN3tvm7runtime7NDArray13CopyFromBytesEPKvm"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray10CopyFromToEPK8DLTensorPS2_Pv=Module["__ZN3tvm7runtime7NDArray10CopyFromToEPK8DLTensorPS2_Pv"]=function(){return(__ZN3tvm7runtime7NDArray10CopyFromToEPK8DLTensorPS2_Pv=Module["__ZN3tvm7runtime7NDArray10CopyFromToEPK8DLTensorPS2_Pv"]=Module["asm"]["_ZN3tvm7runtime7NDArray10CopyFromToEPK8DLTensorPS2_Pv"]).apply(null,arguments)};var __ZNK3tvm7runtime7NDArray5ShapeEv=Module["__ZNK3tvm7runtime7NDArray5ShapeEv"]=function(){return(__ZNK3tvm7runtime7NDArray5ShapeEv=Module["__ZNK3tvm7runtime7NDArray5ShapeEv"]=Module["asm"]["_ZNK3tvm7runtime7NDArray5ShapeEv"]).apply(null,arguments)};var __ZNK3tvm7runtime7NDArray8DataTypeEv=Module["__ZNK3tvm7runtime7NDArray8DataTypeEv"]=function(){return(__ZNK3tvm7runtime7NDArray8DataTypeEv=Module["__ZNK3tvm7runtime7NDArray8DataTypeEv"]=Module["asm"]["_ZNK3tvm7runtime7NDArray8DataTypeEv"]).apply(null,arguments)};var __ZN3tvm7runtime7NDArray28AbilityOfZeroCopyForDLTensorEP8DLTensorRK8DLDevice=Module["__ZN3tvm7runtime7NDArray28AbilityOfZeroCopyForDLTensorEP8DLTensorRK8DLDevice"]=function(){return(__ZN3tvm7runtime7NDArray28AbilityOfZeroCopyForDLTensorEP8DLTensorRK8DLDevice=Module["__ZN3tvm7runtime7NDArray28AbilityOfZeroCopyForDLTensorEP8DLTensorRK8DLDevice"]=Module["asm"]["_ZN3tvm7runtime7NDArray28AbilityOfZeroCopyForDLTensorEP8DLTensorRK8DLDevice"]).apply(null,arguments)};var _TVMArrayGetTypeIndex=Module["_TVMArrayGetTypeIndex"]=function(){return(_TVMArrayGetTypeIndex=Module["_TVMArrayGetTypeIndex"]=Module["asm"]["TVMArrayGetTypeIndex"]).apply(null,arguments)};var _TVMArrayAlloc=Module["_TVMArrayAlloc"]=function(){return(_TVMArrayAlloc=Module["_TVMArrayAlloc"]=Module["asm"]["TVMArrayAlloc"]).apply(null,arguments)};var _TVMArrayFree=Module["_TVMArrayFree"]=function(){return(_TVMArrayFree=Module["_TVMArrayFree"]=Module["asm"]["TVMArrayFree"]).apply(null,arguments)};var _TVMArrayCopyFromTo=Module["_TVMArrayCopyFromTo"]=function(){return(_TVMArrayCopyFromTo=Module["_TVMArrayCopyFromTo"]=Module["asm"]["TVMArrayCopyFromTo"]).apply(null,arguments)};var _TVMArrayFromDLPack=Module["_TVMArrayFromDLPack"]=function(){return(_TVMArrayFromDLPack=Module["_TVMArrayFromDLPack"]=Module["asm"]["TVMArrayFromDLPack"]).apply(null,arguments)};var _TVMArrayToDLPack=Module["_TVMArrayToDLPack"]=function(){return(_TVMArrayToDLPack=Module["_TVMArrayToDLPack"]=Module["asm"]["TVMArrayToDLPack"]).apply(null,arguments)};var _TVMDLManagedTensorCallDeleter=Module["_TVMDLManagedTensorCallDeleter"]=function(){return(_TVMDLManagedTensorCallDeleter=Module["_TVMDLManagedTensorCallDeleter"]=Module["asm"]["TVMDLManagedTensorCallDeleter"]).apply(null,arguments)};var _TVMArrayCopyFromBytes=Module["_TVMArrayCopyFromBytes"]=function(){return(_TVMArrayCopyFromBytes=Module["_TVMArrayCopyFromBytes"]=Module["asm"]["TVMArrayCopyFromBytes"]).apply(null,arguments)};var _TVMArrayCopyToBytes=Module["_TVMArrayCopyToBytes"]=function(){return(_TVMArrayCopyToBytes=Module["_TVMArrayCopyToBytes"]=Module["asm"]["TVMArrayCopyToBytes"]).apply(null,arguments)};var _TVMObjectGetTypeIndex=Module["_TVMObjectGetTypeIndex"]=function(){return(_TVMObjectGetTypeIndex=Module["_TVMObjectGetTypeIndex"]=Module["asm"]["TVMObjectGetTypeIndex"]).apply(null,arguments)};var _TVMObjectRetain=Module["_TVMObjectRetain"]=function(){return(_TVMObjectRetain=Module["_TVMObjectRetain"]=Module["asm"]["TVMObjectRetain"]).apply(null,arguments)};var _TVMObjectDerivedFrom=Module["_TVMObjectDerivedFrom"]=function(){return(_TVMObjectDerivedFrom=Module["_TVMObjectDerivedFrom"]=Module["asm"]["TVMObjectDerivedFrom"]).apply(null,arguments)};var _TVMObjectTypeKey2Index=Module["_TVMObjectTypeKey2Index"]=function(){return(_TVMObjectTypeKey2Index=Module["_TVMObjectTypeKey2Index"]=Module["asm"]["TVMObjectTypeKey2Index"]).apply(null,arguments)};var _TVMObjectTypeIndex2Key=Module["_TVMObjectTypeIndex2Key"]=function(){return(_TVMObjectTypeIndex2Key=Module["_TVMObjectTypeIndex2Key"]=Module["asm"]["TVMObjectTypeIndex2Key"]).apply(null,arguments)};var __ZN3tvm7runtime5Timer5StartE8DLDevice=Module["__ZN3tvm7runtime5Timer5StartE8DLDevice"]=function(){return(__ZN3tvm7runtime5Timer5StartE8DLDevice=Module["__ZN3tvm7runtime5Timer5StartE8DLDevice"]=Module["asm"]["_ZN3tvm7runtime5Timer5StartE8DLDevice"]).apply(null,arguments)};var __ZN3tvm7runtime8Registry8set_bodyENS0_10PackedFuncE=Module["__ZN3tvm7runtime8Registry8set_bodyENS0_10PackedFuncE"]=function(){return(__ZN3tvm7runtime8Registry8set_bodyENS0_10PackedFuncE=Module["__ZN3tvm7runtime8Registry8set_bodyENS0_10PackedFuncE"]=Module["asm"]["_ZN3tvm7runtime8Registry8set_bodyENS0_10PackedFuncE"]).apply(null,arguments)};var __ZN3tvm7runtime8Registry6RemoveERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE=Module["__ZN3tvm7runtime8Registry6RemoveERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]=function(){return(__ZN3tvm7runtime8Registry6RemoveERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE=Module["__ZN3tvm7runtime8Registry6RemoveERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]=Module["asm"]["_ZN3tvm7runtime8Registry6RemoveERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"]).apply(null,arguments)};var __ZN3tvm7runtime15EnvCheckSignalsEv=Module["__ZN3tvm7runtime15EnvCheckSignalsEv"]=function(){return(__ZN3tvm7runtime15EnvCheckSignalsEv=Module["__ZN3tvm7runtime15EnvCheckSignalsEv"]=Module["asm"]["_ZN3tvm7runtime15EnvCheckSignalsEv"]).apply(null,arguments)};var _TVMFuncRegisterGlobal=Module["_TVMFuncRegisterGlobal"]=function(){return(_TVMFuncRegisterGlobal=Module["_TVMFuncRegisterGlobal"]=Module["asm"]["TVMFuncRegisterGlobal"]).apply(null,arguments)};var _TVMFuncGetGlobal=Module["_TVMFuncGetGlobal"]=function(){return(_TVMFuncGetGlobal=Module["_TVMFuncGetGlobal"]=Module["asm"]["TVMFuncGetGlobal"]).apply(null,arguments)};var _TVMFuncListGlobalNames=Module["_TVMFuncListGlobalNames"]=function(){return(_TVMFuncListGlobalNames=Module["_TVMFuncListGlobalNames"]=Module["asm"]["TVMFuncListGlobalNames"]).apply(null,arguments)};var _TVMFuncRemoveGlobal=Module["_TVMFuncRemoveGlobal"]=function(){return(_TVMFuncRemoveGlobal=Module["_TVMFuncRemoveGlobal"]=Module["asm"]["TVMFuncRemoveGlobal"]).apply(null,arguments)};var _TVMBackendRegisterEnvCAPI=Module["_TVMBackendRegisterEnvCAPI"]=function(){return(_TVMBackendRegisterEnvCAPI=Module["_TVMBackendRegisterEnvCAPI"]=Module["asm"]["TVMBackendRegisterEnvCAPI"]).apply(null,arguments)};var _TVMBackendRegisterSystemLibSymbol=Module["_TVMBackendRegisterSystemLibSymbol"]=function(){return(_TVMBackendRegisterSystemLibSymbol=Module["_TVMBackendRegisterSystemLibSymbol"]=Module["asm"]["TVMBackendRegisterSystemLibSymbol"]).apply(null,arguments)};var _TVMBackendAnyListSetPackedArg=Module["_TVMBackendAnyListSetPackedArg"]=function(){return(_TVMBackendAnyListSetPackedArg=Module["_TVMBackendAnyListSetPackedArg"]=Module["asm"]["TVMBackendAnyListSetPackedArg"]).apply(null,arguments)};var _TVMBackendAnyListResetItem=Module["_TVMBackendAnyListResetItem"]=function(){return(_TVMBackendAnyListResetItem=Module["_TVMBackendAnyListResetItem"]=Module["asm"]["TVMBackendAnyListResetItem"]).apply(null,arguments)};var _TVMBackendAnyListMoveFromPackedReturn=Module["_TVMBackendAnyListMoveFromPackedReturn"]=function(){return(_TVMBackendAnyListMoveFromPackedReturn=Module["_TVMBackendAnyListMoveFromPackedReturn"]=Module["asm"]["TVMBackendAnyListMoveFromPackedReturn"]).apply(null,arguments)};var __ZN3tvm7runtime6detail12LogFatalImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiSA_=Module["__ZN3tvm7runtime6detail12LogFatalImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiSA_"]=function(){return(__ZN3tvm7runtime6detail12LogFatalImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiSA_=Module["__ZN3tvm7runtime6detail12LogFatalImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiSA_"]=Module["asm"]["_ZN3tvm7runtime6detail12LogFatalImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiSA_"]).apply(null,arguments)};var __ZN3tvm7runtime6detail14LogMessageImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiiSA_=Module["__ZN3tvm7runtime6detail14LogMessageImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiiSA_"]=function(){return(__ZN3tvm7runtime6detail14LogMessageImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiiSA_=Module["__ZN3tvm7runtime6detail14LogMessageImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiiSA_"]=Module["asm"]["_ZN3tvm7runtime6detail14LogMessageImplERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiiSA_"]).apply(null,arguments)};var ___errno_location=function(){return(___errno_location=Module["asm"]["__errno_location"]).apply(null,arguments)};var _TVMWasmAllocSpace=Module["_TVMWasmAllocSpace"]=function(){return(_TVMWasmAllocSpace=Module["_TVMWasmAllocSpace"]=Module["asm"]["TVMWasmAllocSpace"]).apply(null,arguments)};var _TVMWasmFreeSpace=Module["_TVMWasmFreeSpace"]=function(){return(_TVMWasmFreeSpace=Module["_TVMWasmFreeSpace"]=Module["asm"]["TVMWasmFreeSpace"]).apply(null,arguments)};var _TVMWasmFuncCreateFromCFunc=Module["_TVMWasmFuncCreateFromCFunc"]=function(){return(_TVMWasmFuncCreateFromCFunc=Module["_TVMWasmFuncCreateFromCFunc"]=Module["asm"]["TVMWasmFuncCreateFromCFunc"]).apply(null,arguments)};var __initialize=Module["__initialize"]=function(){return(__initialize=Module["__initialize"]=Module["asm"]["_initialize"]).apply(null,arguments)};var ___cxa_is_pointer_type=function(){return(___cxa_is_pointer_type=Module["asm"]["__cxa_is_pointer_type"]).apply(null,arguments)};var calledRun;var mainArgs=undefined;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=__initialize;mainArgs=[thisProgram].concat(args);try{entryFunction();var ret=0;exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run(); 4 | 5 | this.Module = Module; 6 | this.start = Module.wasmLibraryProvider.start; 7 | this.imports = Module.wasmLibraryProvider.imports; 8 | this.wasiImport = this.imports["wasi_snapshot_preview1"]; 9 | } 10 | 11 | if (typeof module !== "undefined" && module.exports) { 12 | module.exports = EmccWASI; 13 | } 14 | -------------------------------------------------------------------------------- /public/lib/WebLLM/vicuna-7b/tokenizer.model: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/lib/WebLLM/vicuna-7b/tokenizer.model -------------------------------------------------------------------------------- /public/lib/WebLLM/vicuna-7b/vicuna-7b-v1_webgpu.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/lib/WebLLM/vicuna-7b/vicuna-7b-v1_webgpu.wasm -------------------------------------------------------------------------------- /public/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 13 | 14 | 18 | 22 | 23 | 24 | 28 | 32 | 33 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ChatLLM-Web", 3 | "short_name": "ChatLLM-Web", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "orientation": "portrait", 8 | "display_override": ["window-controls-overlay"], 9 | "scope": "/", 10 | "start_url": "/", 11 | "icons": [ 12 | { 13 | "src": "assets/icons/icon-48x48.png", 14 | "sizes": "48x48", 15 | "type": "image/png", 16 | "purpose": "maskable any" 17 | }, 18 | { 19 | "src": "assets/icons/icon-72x72.png", 20 | "sizes": "72x72", 21 | "type": "image/png", 22 | "purpose": "maskable any" 23 | }, 24 | { 25 | "src": "assets/icons/icon-96x96.png", 26 | "sizes": "96x96", 27 | "type": "image/png", 28 | "purpose": "maskable any" 29 | }, 30 | { 31 | "src": "assets/icons/icon-128x128.png", 32 | "sizes": "128x128", 33 | "type": "image/png", 34 | "purpose": "maskable any" 35 | }, 36 | { 37 | "src": "assets/icons/icon-144x144.png", 38 | "sizes": "144x144", 39 | "type": "image/png", 40 | "purpose": "maskable any" 41 | }, 42 | { 43 | "src": "assets/icons/icon-152x152.png", 44 | "sizes": "152x152", 45 | "type": "image/png", 46 | "purpose": "maskable any" 47 | }, 48 | { 49 | "src": "assets/icons/icon-192x192.png", 50 | "sizes": "192x192", 51 | "type": "image/png", 52 | "purpose": "maskable any" 53 | }, 54 | { 55 | "src": "assets/icons/icon-384x384.png", 56 | "sizes": "384x384", 57 | "type": "image/png", 58 | "purpose": "maskable any" 59 | }, 60 | { 61 | "src": "assets/icons/icon-512x512.png", 62 | "sizes": "512x512", 63 | "type": "image/png", 64 | "purpose": "maskable any" 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /public/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/user.jpg -------------------------------------------------------------------------------- /public/vicuna.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ryan-yang125/ChatLLM-Web/673934a013715def6f8c104526d1c151d0d4fe53/public/vicuna.jpeg -------------------------------------------------------------------------------- /store/chat.ts: -------------------------------------------------------------------------------- 1 | import { WebLLMInstance } from '@/hooks/web-llm'; 2 | 3 | import { testMdStr } from '@/utils/codeblock'; 4 | 5 | import { ChatConversation, InitInfo, Message } from '@/types/chat'; 6 | import { ResFromWorkerMessageEventData } from '@/types/web-llm'; 7 | 8 | import { create } from 'zustand'; 9 | import { persist } from 'zustand/middleware'; 10 | 11 | const CHATSTORE_KEY = 'chat-web-llm-store'; 12 | 13 | export const newMessage = (p: Partial): Message => ({ 14 | id: Date.now(), 15 | createTime: new Date().toLocaleString(), 16 | updateTime: new Date().toLocaleString(), 17 | type: 'user', 18 | content: '', 19 | ...p, 20 | }); 21 | 22 | export const DEFAULT_BOT_GREETING = newMessage({ 23 | type: 'assistant', 24 | content: 'Hello, I am an AI assistant. How can I help you today?', 25 | }); 26 | 27 | function createEmptyConversation(): ChatConversation { 28 | const curTime = new Date().toLocaleString(); 29 | 30 | return { 31 | id: Date.now(), 32 | messages: [], 33 | createTime: curTime, 34 | updateTime: curTime, 35 | title: 'New Conversation', 36 | }; 37 | } 38 | 39 | export interface ChatStore { 40 | conversations: ChatConversation[]; 41 | curConversationIndex: number; 42 | instructionModalStatus: boolean; 43 | initInfoTmp: InitInfo; 44 | debugMode: boolean; 45 | newConversation: () => void; 46 | delConversation: (index: number) => void; 47 | chooseConversation: (index: number) => void; 48 | delAllConversations: () => void; 49 | curConversation: () => ChatConversation; 50 | onUserInputContent: (content: string) => Promise; 51 | getMemoryMsgs: () => Message[]; 52 | updateCurConversation: ( 53 | updater: (conversation: ChatConversation) => void, 54 | ) => void; 55 | toggleInstuctionModal: (toggle: boolean) => void; 56 | toggleInitModal: (toggle: boolean) => void; 57 | workerMessageCb: (data: ResFromWorkerMessageEventData) => void; 58 | setWorkerConversationHistroy: () => void; 59 | } 60 | 61 | export const useChatStore = create()( 62 | persist( 63 | (set, get) => ({ 64 | curConversationIndex: 0, 65 | conversations: [createEmptyConversation()], 66 | instructionModalStatus: true, 67 | debugMode: process.env.NODE_ENV === 'development', 68 | initInfoTmp: { 69 | showModal: false, 70 | initMsg: [], 71 | }, 72 | newConversation() { 73 | set((state) => { 74 | return { 75 | curConversationIndex: 0, 76 | conversations: [createEmptyConversation()].concat( 77 | state.conversations, 78 | ), 79 | }; 80 | }); 81 | get().setWorkerConversationHistroy(); 82 | }, 83 | 84 | delAllConversations() { 85 | set({ 86 | curConversationIndex: 0, 87 | conversations: [createEmptyConversation()], 88 | }); 89 | WebLLMInstance.destroy(); 90 | }, 91 | 92 | chooseConversation(index) { 93 | set({ 94 | curConversationIndex: index, 95 | }); 96 | get().setWorkerConversationHistroy(); 97 | }, 98 | 99 | delConversation(index) { 100 | set((state) => { 101 | const { conversations, curConversationIndex } = state; 102 | 103 | if (conversations.length === 1) { 104 | return { 105 | curConversationIndex: 0, 106 | conversations: [createEmptyConversation()], 107 | }; 108 | } 109 | conversations.splice(index, 1); 110 | return { 111 | conversations, 112 | curConversationIndex: 113 | curConversationIndex === index 114 | ? curConversationIndex - 1 115 | : curConversationIndex, 116 | }; 117 | }); 118 | get().setWorkerConversationHistroy(); 119 | }, 120 | 121 | curConversation() { 122 | let index = get().curConversationIndex; 123 | const conversations = get().conversations; 124 | 125 | if (index < 0 || index >= conversations.length) { 126 | index = Math.min(conversations.length - 1, Math.max(0, index)); 127 | set(() => ({ curConversationIndex: index })); 128 | } 129 | 130 | const conversation = conversations[index]; 131 | 132 | return conversation; 133 | }, 134 | 135 | setWorkerConversationHistroy() { 136 | WebLLMInstance.setConversationHistroy({ 137 | ifNewConverstaion: true, 138 | workerHistoryMsg: get() 139 | .curConversation() 140 | .messages.map((msg) => [msg.type, msg.content]), 141 | curConversationIndex: get().curConversationIndex, 142 | msg: '', 143 | }); 144 | }, 145 | 146 | async onUserInputContent(content) { 147 | const userMessage: Message = newMessage({ 148 | type: 'user', 149 | content, 150 | }); 151 | 152 | const botMessage: Message = newMessage({ 153 | type: 'assistant', 154 | content: '', 155 | isLoading: true, 156 | }); 157 | // const recentMsgs = get().getMemoryMsgs(); 158 | // const toSendMsgs = recentMsgs.concat(userMessage); 159 | 160 | console.log('[User Input] ', userMessage); 161 | // update 162 | get().updateCurConversation((conversation) => { 163 | conversation.messages.push(userMessage, botMessage); 164 | }); 165 | // if (get().debugMode) { 166 | // setTimeout(() => { 167 | // get().updateCurConversation((conversation) => { 168 | // const msgs = conversation.messages; 169 | // msgs[msgs.length - 1].content = testMdStr; 170 | // msgs[msgs.length - 1].isError = false; 171 | // msgs[msgs.length - 1].isLoading = false; 172 | // msgs[msgs.length - 1].isStreaming = true; 173 | // }); 174 | // }, 3000); 175 | // return; 176 | // } 177 | 178 | WebLLMInstance.chat( 179 | { 180 | msg: content, 181 | curConversationIndex: get().curConversationIndex, 182 | }, 183 | get().workerMessageCb, 184 | ); 185 | }, 186 | workerMessageCb(data) { 187 | if (data.type === 'initing') { 188 | const initMsg = get().initInfoTmp.initMsg; 189 | if (data.action === 'append') { 190 | const appendMsg = newMessage({ 191 | type: 'init', 192 | content: data.msg, 193 | isError: !!data.ifError, 194 | }); 195 | initMsg.push(appendMsg); 196 | } else if (data.action === 'updateLast') { 197 | initMsg[initMsg.length - 1].content = data.msg; 198 | initMsg[initMsg.length - 1].isError = !!data.ifError; 199 | } 200 | set({ 201 | initInfoTmp: { 202 | initMsg, 203 | showModal: true, 204 | }, 205 | }); 206 | if (data.ifFinish) { 207 | set({ 208 | initInfoTmp: { 209 | showModal: false, 210 | initMsg: get().initInfoTmp.initMsg, 211 | }, 212 | }); 213 | } 214 | } else if (data.type === 'chatting') { 215 | const msgs = get().curConversation().messages; 216 | if (msgs[msgs.length - 1].type !== 'assistant') { 217 | const aiBotMessage: Message = newMessage({ 218 | type: 'assistant', 219 | content: '', 220 | isStreaming: true, 221 | }); 222 | get().updateCurConversation((conversation) => { 223 | conversation.messages.push(aiBotMessage); 224 | }); 225 | } 226 | 227 | get().updateCurConversation((conversation) => { 228 | const msgs = conversation.messages; 229 | msgs[msgs.length - 1].content = data.msg; 230 | msgs[msgs.length - 1].isError = !!data.ifError; 231 | msgs[msgs.length - 1].isLoading = false; 232 | if (data.ifFinish) { 233 | msgs[msgs.length - 1].isStreaming = false; 234 | msgs[msgs.length - 1].updateTime = new Date().toLocaleString(); 235 | } 236 | }); 237 | } else if (data.type === 'stats') { 238 | get().updateCurConversation((conversation) => { 239 | const msgs = conversation.messages; 240 | msgs[msgs.length - 1].statsText = data.msg; 241 | }); 242 | } 243 | }, 244 | getMemoryMsgs() { 245 | const conversation = get().curConversation(); 246 | return conversation.messages.filter((msg) => !msg.isError); 247 | }, 248 | updateCurConversation(updater) { 249 | const conversations = get().conversations; 250 | const index = get().curConversationIndex; 251 | updater(conversations[index]); 252 | set(() => ({ conversations })); 253 | }, 254 | toggleInstuctionModal(toggle) { 255 | set({ 256 | instructionModalStatus: toggle, 257 | }); 258 | }, 259 | toggleInitModal(toggle) { 260 | set({ 261 | initInfoTmp: { 262 | showModal: toggle, 263 | initMsg: [], 264 | }, 265 | }); 266 | }, 267 | }), 268 | { 269 | name: CHATSTORE_KEY, 270 | version: 1.0, 271 | partialize: (state) => 272 | Object.fromEntries( 273 | Object.entries(state).filter( 274 | ([key]) => !['initInfoTmp'].includes(key), 275 | ), 276 | ), 277 | }, 278 | ), 279 | ); 280 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .chat-markdown > pre { 6 | margin: 0px !important; 7 | padding: 0px !important; 8 | } 9 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | plugins: [require('@tailwindcss/typography'), require('daisyui')], 9 | daisyui: { 10 | styled: true, 11 | themes: ['dracula'], 12 | base: true, 13 | utils: true, 14 | logs: true, 15 | rtl: false, 16 | prefix: '', 17 | darkTheme: 'dracula', 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "paths": { 18 | "@/*": ["./*"] 19 | } 20 | }, 21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /types/chat.ts: -------------------------------------------------------------------------------- 1 | export type Message = { 2 | content: string; 3 | type: 'assistant' | 'system' | 'user' | 'init'; 4 | createTime: string; 5 | id: number; 6 | isStreaming?: boolean; 7 | isError?: boolean; 8 | isInit?: boolean; 9 | isLoading?: boolean; 10 | updateTime?: string; 11 | statsText?: string; 12 | }; 13 | 14 | export type ChatConversation = { 15 | id: number; 16 | messages: Message[]; 17 | createTime: string; 18 | updateTime: string; 19 | title: string; 20 | }; 21 | 22 | export type UpdateBotMsg = (msg: Partial) => void; 23 | 24 | export type UpdateInitMsg = (msg: Partial) => void; 25 | 26 | export type InitInfo = { 27 | showModal: boolean; 28 | initMsg: Message[]; 29 | }; 30 | -------------------------------------------------------------------------------- /types/web-llm.ts: -------------------------------------------------------------------------------- 1 | import { Message } from './chat'; 2 | 3 | type Prompts = [string, string][]; 4 | type WorkerHistoryMsg = [string, string][]; 5 | 6 | declare global { 7 | var Tokenizer: { 8 | TokenizerWasm: new (config: string) => (name: string) => Promise; 9 | init: () => Promise; 10 | }; 11 | var sentencepiece: { 12 | sentencePieceProcessor: (url: string) => void; 13 | }; 14 | var tvmjsGlobalEnv: { 15 | covId: any; 16 | asyncOnGenerate: () => Promise; 17 | asyncOnReset: () => Promise; 18 | getTokenizer: (name: string) => Promise; 19 | initialized: boolean; 20 | sentencePieceProcessor: (url: string) => void; 21 | message: string; 22 | curConversationIndex: number; 23 | workerHistoryMsg: WorkerHistoryMsg; 24 | }; 25 | var tvmjs: any; 26 | var EmccWASI: any; 27 | var importScripts: (...url: string[]) => void; 28 | } 29 | 30 | export type LLMEngine = { 31 | chat: (message: string, updateBotMsg?: any) => Promise; 32 | destroy?: () => void; 33 | greeting?: Message; 34 | init: any; 35 | }; 36 | 37 | export type PostToWorker = { 38 | type: 'init' | 'chat'; 39 | msg: string; 40 | }; 41 | 42 | export type ListenFromWorker = { 43 | type: 'init' | 'chat'; 44 | msg: string; 45 | }; 46 | 47 | export type SendToWorkerMessageEventData = { 48 | curConversationIndex: number; 49 | msg: string; 50 | workerHistoryMsg?: WorkerHistoryMsg; 51 | ifNewConverstaion?: boolean; 52 | }; 53 | 54 | export type ResFromWorkerMessageEventData = { 55 | type: 'initing' | 'chatting' | 'stats'; 56 | action: 'append' | 'updateLast'; 57 | msg: string; 58 | ifError?: boolean; 59 | ifFinish?: boolean; 60 | }; 61 | -------------------------------------------------------------------------------- /utils/codeblock.ts: -------------------------------------------------------------------------------- 1 | interface languageMap { 2 | [key: string]: string | undefined; 3 | } 4 | 5 | export const programmingLanguages: languageMap = { 6 | javascript: '.js', 7 | python: '.py', 8 | java: '.java', 9 | c: '.c', 10 | cpp: '.cpp', 11 | 'c++': '.cpp', 12 | 'c#': '.cs', 13 | ruby: '.rb', 14 | php: '.php', 15 | swift: '.swift', 16 | 'objective-c': '.m', 17 | kotlin: '.kt', 18 | typescript: '.ts', 19 | go: '.go', 20 | perl: '.pl', 21 | rust: '.rs', 22 | scala: '.scala', 23 | haskell: '.hs', 24 | lua: '.lua', 25 | shell: '.sh', 26 | sql: '.sql', 27 | html: '.html', 28 | css: '.css', 29 | }; 30 | 31 | export const generateRandomString = (length: number, lowercase = false) => { 32 | const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789'; // excluding similar looking characters like Z, 2, I, 1, O, 0 33 | let result = ''; 34 | for (let i = 0; i < length; i++) { 35 | result += chars.charAt(Math.floor(Math.random() * chars.length)); 36 | } 37 | return lowercase ? result.toLowerCase() : result; 38 | }; 39 | 40 | export const testMdStr = 41 | "Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)\n are automatically converted into HTML entities. This makes it very\n easy to include example HTML source code using Markdown -- just paste\n it and indent it, and Markdown will handle the hassle of encoding the\n ampersands and angle brackets. For example, this:\n ``` typescript\nexport const generateRandomString = (length: number, lowercase = false) => {\nconst chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789';\nlet result = '';\nfor (let i = 0; i < length; i++) {\nresult += chars.charAt(Math.floor(Math.random() * chars.length));\n}\return lowercase ? result.toLowerCase() : result;\n};"; 42 | -------------------------------------------------------------------------------- /utils/opts.ts: -------------------------------------------------------------------------------- 1 | import { saveAs } from 'file-saver'; 2 | import JSZip from 'jszip'; 3 | 4 | export async function copyToClipboard(text: string) { 5 | try { 6 | await navigator.clipboard.writeText(text); 7 | // showToast(Locale.Copy.Success); 8 | } catch (error) { 9 | const textArea = document.createElement('textarea'); 10 | textArea.value = text; 11 | document.body.appendChild(textArea); 12 | textArea.focus(); 13 | textArea.select(); 14 | try { 15 | document.execCommand('copy'); 16 | // showToast(Locale.Copy.Success); 17 | } catch (error) { 18 | // showToast(Locale.Copy.Failed); 19 | } 20 | document.body.removeChild(textArea); 21 | } 22 | } 23 | 24 | export async function exportCache() { 25 | const cacheName = 'tvmjs'; 26 | // const requestUrl = 'https://huggingface.co/mlc-ai/web-lm/resolve/main/vicuna-7b-v1/params_shard_0.bin' 27 | const zip = new JSZip(); 28 | try { 29 | const cache = await caches.open(cacheName); 30 | const keys = await cache.keys(); 31 | await Promise.all( 32 | keys.map(async (key) => { 33 | if (key.url.endsWith('bin')) { 34 | const result = await cache.match(key); 35 | if (result) { 36 | zip.file(key.url, result.blob()); 37 | console.log(key.url, 'done'); 38 | } 39 | } 40 | }), 41 | ); 42 | const content = await zip.generateAsync({ type: 'blob' }); 43 | console.log(content); 44 | saveAs(content, 'my-caches.zip'); 45 | } catch (error) { 46 | console.error(error); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /web-worker/web-llm.worker.ts: -------------------------------------------------------------------------------- 1 | import { SendToWorkerMessageEventData } from '@/types/web-llm'; 2 | 3 | const libs = [ 4 | '/lib/WebLLM/tvmjs_runtime.wasi.js', 5 | '/lib/WebLLM/tvmjs.bundle.js', 6 | // '/lib/WebLLM/llm_chat.js', 7 | '/lib/WebLLM/sentencepiece.js', 8 | ]; 9 | let initalized = false; 10 | 11 | globalThis.addEventListener( 12 | 'message', 13 | ({ data }: { data: SendToWorkerMessageEventData }) => { 14 | // load script 15 | if (!globalThis.tvmjsGlobalEnv) { 16 | globalThis.postMessage({}); 17 | initalized = true; 18 | 19 | globalThis.tvmjsGlobalEnv = globalThis.tvmjsGlobalEnv || {}; 20 | 21 | globalThis.tvmjsGlobalEnv.initialized = true; 22 | 23 | globalThis.importScripts(...libs); 24 | const localLLMChatIntance = new LLMChatInstance(); 25 | 26 | globalThis.tvmjsGlobalEnv.asyncOnGenerate = async function () { 27 | await localLLMChatIntance.generate(); 28 | }; 29 | 30 | globalThis.tvmjsGlobalEnv.asyncOnReset = async function () { 31 | await localLLMChatIntance.resetChat(); 32 | }; 33 | globalThis.tvmjsGlobalEnv.sentencePieceProcessor = (url: string) => 34 | globalThis.sentencepiece.sentencePieceProcessor(url); 35 | } 36 | globalThis.tvmjsGlobalEnv.message = data.msg || ''; 37 | globalThis.tvmjsGlobalEnv.curConversationIndex = 38 | data.curConversationIndex || 0; 39 | 40 | if (data.ifNewConverstaion) { 41 | globalThis.tvmjsGlobalEnv.asyncOnReset(); 42 | globalThis.tvmjsGlobalEnv.workerHistoryMsg = []; 43 | globalThis.tvmjsGlobalEnv.workerHistoryMsg = data.workerHistoryMsg || []; 44 | globalThis.tvmjsGlobalEnv.curConversationIndex = 45 | data.curConversationIndex || 0; 46 | console.log('switch to new conversation: ', data.curConversationIndex); 47 | return; 48 | } 49 | 50 | globalThis.tvmjsGlobalEnv.asyncOnGenerate(); 51 | }, 52 | { passive: true }, 53 | ); 54 | 55 | /** 56 | * Helper to keep track of history conversations. 57 | */ 58 | class Conversation { 59 | system: any; 60 | roles: any; 61 | offset: any; 62 | seps: any; 63 | convId: number | null; 64 | contextWindowStart: number; 65 | constructor(config: any) { 66 | this.system = config.system; 67 | this.roles = config.roles; 68 | this.offset = config.offset; 69 | this.seps = config.seps; 70 | this.convId = null; 71 | this.contextWindowStart = 0; 72 | } 73 | 74 | /** 75 | * Get prompt arrays with the first one as system. 76 | * 77 | * @returns The prompt array. 78 | */ 79 | getPromptArray() { 80 | if (this.seps.length == 0) { 81 | throw Error('Need seps to work'); 82 | } 83 | let ret = [this.system + this.seps[0]]; 84 | 85 | for (let i = 0; i < tvmjsGlobalEnv.workerHistoryMsg.length; ++i) { 86 | const item = tvmjsGlobalEnv.workerHistoryMsg[i]; 87 | const role = item[0]; 88 | const message = item[1]; 89 | if (message !== undefined && message != '') { 90 | ret.push(role + ': ' + message + this.seps[i % this.seps.length]); 91 | } else { 92 | ret.push(role + ':'); 93 | } 94 | } 95 | return ret; 96 | } 97 | 98 | /** 99 | * Get prompt arrays that has not been fed as input 100 | * 101 | * @returns The prompt array. 102 | */ 103 | getPromptArrayUnproccessed() { 104 | if (this.seps.length == 0) { 105 | throw Error('Need seps to work'); 106 | } 107 | if (tvmjsGlobalEnv.workerHistoryMsg.length < 3) { 108 | throw Error('needs to call getLastPromptArray for the first message'); 109 | } 110 | let ret = [this.seps[this.seps.length - 1]]; 111 | for ( 112 | let i = tvmjsGlobalEnv.workerHistoryMsg.length - 2; 113 | i < tvmjsGlobalEnv.workerHistoryMsg.length; 114 | ++i 115 | ) { 116 | const item = tvmjsGlobalEnv.workerHistoryMsg[i]; 117 | const role = item[0]; 118 | const message = item[1]; 119 | if (message !== undefined && message != '') { 120 | ret.push(role + ': ' + message + this.seps[i % this.seps.length]); 121 | } else { 122 | ret.push(role + ':'); 123 | } 124 | } 125 | return ret; 126 | } 127 | 128 | /** 129 | * Get last prompt array with prefix as system. 130 | * 131 | * @returns The prompt array. 132 | */ 133 | getLastPromptArray() { 134 | if (this.seps.length == 0) { 135 | throw Error('Need seps to work'); 136 | } 137 | let ret = [this.system + this.seps[0]]; 138 | 139 | for ( 140 | let i = tvmjsGlobalEnv.workerHistoryMsg.length - 2; 141 | i < tvmjsGlobalEnv.workerHistoryMsg.length; 142 | ++i 143 | ) { 144 | const item = tvmjsGlobalEnv.workerHistoryMsg[i]; 145 | const role = item[0]; 146 | const message = item[1]; 147 | if (message !== undefined && message != '') { 148 | ret.push(role + ': ' + message + this.seps[i % this.seps.length]); 149 | } else { 150 | ret.push(role + ':'); 151 | } 152 | } 153 | return ret; 154 | } 155 | 156 | reset() { 157 | tvmjsGlobalEnv.workerHistoryMsg = []; 158 | this.convId = null; 159 | } 160 | 161 | getStopStr() { 162 | return this.seps[this.seps.length - 1]; 163 | } 164 | 165 | appendMessage(role: string, message: string) { 166 | tvmjsGlobalEnv.workerHistoryMsg.push([role, message]); 167 | } 168 | 169 | switchConversation(message: [string, string][]) { 170 | tvmjsGlobalEnv.workerHistoryMsg = message; 171 | this.convId = tvmjsGlobalEnv.covId; 172 | } 173 | } 174 | 175 | function defaultConversation(maxWindowLength = 2048) { 176 | return new Conversation({ 177 | system: 178 | "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions. Follow the user's instructions carefully. Respond using markdown.", 179 | roles: ['user', 'assistant'], 180 | maxWindowLength: maxWindowLength, 181 | offset: 0, 182 | seps: [' ', ''], 183 | }); 184 | } 185 | 186 | class LLMChatPipeline { 187 | tvm: any; 188 | logger: { 189 | (...data: any[]): void; 190 | (...data: any[]): void; 191 | (message?: any, ...optionalParams: any[]): void; 192 | }; 193 | tokenizer: any; 194 | bosTokenId: number; 195 | eosTokenId: number; 196 | maxWindowLength: any; 197 | maxGenLength: any; 198 | meanGenLength: any; 199 | streamInterval: number; 200 | decodingTotalTime: number; 201 | decodingTotalTokens: number; 202 | encodingTotalTime: number; 203 | encodingTotalTokens: number; 204 | conversation: Conversation; 205 | device: any; 206 | vm: any; 207 | encoding: any; 208 | decoding: any; 209 | params: any; 210 | fclearKVCaches: any; 211 | kvCache: any; 212 | logitsOnCPU: any; 213 | kvCacheLength: number; 214 | clearCache: boolean; 215 | constructor( 216 | tvm: any, 217 | tokenizer: void, 218 | cacheMetadata: { ParamSize: any } | any, 219 | config: { maxWindowLength: any; maxGenLength: any; meanGenLength: any }, 220 | ) { 221 | if (cacheMetadata == undefined) { 222 | throw Error('Expect cacheMetadata'); 223 | } 224 | this.tvm = tvm; 225 | this.logger = console.log; 226 | this.tokenizer = tokenizer; 227 | this.bosTokenId = 1; 228 | this.eosTokenId = 2; 229 | 230 | this.maxWindowLength = config.maxWindowLength; 231 | this.maxGenLength = config.maxGenLength; 232 | this.meanGenLength = config.meanGenLength; 233 | this.streamInterval = 1; 234 | 235 | this.decodingTotalTime = 0; 236 | this.decodingTotalTokens = 0; 237 | this.encodingTotalTime = 0; 238 | this.encodingTotalTokens = 0; 239 | 240 | this.conversation = defaultConversation(this.maxWindowLength); 241 | 242 | this.device = this.tvm.webgpu(); 243 | this.vm = this.tvm.detachFromCurrentScope( 244 | this.tvm.createVirtualMachine(this.device), 245 | ); 246 | this.encoding = this.tvm.detachFromCurrentScope( 247 | this.vm.getFunction('encoding'), 248 | ); 249 | this.decoding = this.tvm.detachFromCurrentScope( 250 | this.vm.getFunction('decoding'), 251 | ); 252 | this.params = this.tvm.detachFromCurrentScope( 253 | this.tvm.getParamsFromCache('param', cacheMetadata.ParamSize), 254 | ); 255 | const fcreateCache = this.vm.getFunction('create_kv_cache'); 256 | this.fclearKVCaches = this.tvm.detachFromCurrentScope( 257 | this.tvm.getGlobalFunc('vm.builtin.attention_kv_cache_array_clear'), 258 | ); 259 | 260 | // use extern config for now 261 | this.kvCache = this.tvm.detachFromCurrentScope(fcreateCache()); 262 | // fill with pad token 263 | this.logitsOnCPU = undefined; 264 | 265 | this.kvCacheLength = 0; 266 | this.clearCache = true; 267 | } 268 | 269 | dispose() { 270 | // note: tvm instance is not owned by this class 271 | this.params.dispose(); 272 | this.decoding.dispose(); 273 | this.encoding.dispose(); 274 | this.vm.dispose(); 275 | this.kvCache.dispose(); 276 | this.fclearKVCaches.dispose(); 277 | if (this.logitsOnCPU != undefined) { 278 | this.logitsOnCPU.dispose(); 279 | } 280 | } 281 | 282 | #clearKVCache() { 283 | this.fclearKVCaches(this.kvCache); 284 | this.kvCacheLength = 0; 285 | } 286 | 287 | #forward(inputs: { shape: number[] }, curPos: any) { 288 | this.tvm.beginScope(); 289 | var retValue; 290 | const seqLenShape = this.tvm.makeShapeTuple([curPos]); 291 | if (inputs.shape[1] > 1) { 292 | retValue = this.encoding(inputs, seqLenShape, this.kvCache, this.params); 293 | } else { 294 | retValue = this.decoding(inputs, seqLenShape, this.kvCache, this.params); 295 | } 296 | const logits = this.tvm.detachFromCurrentScope(retValue.get(0)); 297 | this.tvm.endScope(); 298 | this.tvm.attachToCurrentScope(logits); 299 | return logits; 300 | } 301 | 302 | // NOTE: caller must call device.sync() 303 | #updateLogitsOnCPU(logits: { shape: any[]; dtype: any }) { 304 | if (this.logitsOnCPU == undefined) { 305 | this.logitsOnCPU = this.tvm.detachFromCurrentScope( 306 | this.tvm.empty(logits.shape, logits.dtype, this.tvm.cpu()), 307 | ); 308 | } else { 309 | if (logits.shape[0] != this.logitsOnCPU.shape[0]) { 310 | throw Error('We expect the size of logits to remain unchanged'); 311 | } 312 | } 313 | this.logitsOnCPU.copyFrom(logits); 314 | } 315 | 316 | async sampleTokenFromLogits(logits: any, temperature = 0.8, top_p = 0.95) { 317 | this.tvm.beginScope(); 318 | this.#updateLogitsOnCPU(logits); 319 | this.tvm.endScope(); 320 | await this.device.sync(); 321 | return this.tvm.sampleTopPFromLogits(this.logitsOnCPU, temperature, top_p); 322 | } 323 | 324 | async getInputTokens() { 325 | let tokens = [this.bosTokenId]; 326 | let prompts = ['']; 327 | if (tvmjsGlobalEnv.workerHistoryMsg.length <= 2) { 328 | prompts = this.conversation.getPromptArray(); 329 | } else { 330 | tokens.pop(); 331 | prompts = this.conversation.getPromptArrayUnproccessed(); 332 | } 333 | tokens.push(...(await this.tokenizer.encodeIds(prompts[0]))); 334 | let ctxLength = tokens.length; 335 | let context = []; 336 | let need_shift_window = false; 337 | for (let i = prompts.length - 1; i > 0; --i) { 338 | const encoded = this.tokenizer.encodeIds(prompts[i]); 339 | ctxLength += encoded.length; 340 | if ( 341 | this.kvCacheLength + ctxLength + this.meanGenLength >= 342 | this.maxWindowLength 343 | ) { 344 | need_shift_window = true; 345 | break; 346 | } 347 | context.unshift(encoded); 348 | } 349 | if (!need_shift_window) { 350 | for (const ctx of context) { 351 | tokens.push(...ctx); 352 | } 353 | return tokens; 354 | } 355 | // need shift window and re-encode 356 | this.logger('need shift window'); 357 | this.kvCacheLength = 0; 358 | this.clearCache = true; 359 | // abandon all tokens we collected 360 | tokens = [this.bosTokenId]; 361 | let all_prompts = this.conversation.getPromptArray(); 362 | tokens.push(...(await this.tokenizer.encodeIds(all_prompts[0]))); 363 | context = []; 364 | ctxLength = tokens.length; 365 | //only keep 10% of the window context 366 | const fill_factor = 0.1; 367 | for (let i = all_prompts.length - 1; i > 0; --i) { 368 | const encoded = this.tokenizer.encodeIds(all_prompts[i]); 369 | ctxLength += encoded.length; 370 | if ( 371 | ctxLength >= fill_factor * this.maxWindowLength && 372 | i + 2 < all_prompts.length 373 | ) { 374 | break; 375 | } 376 | context.unshift(encoded); 377 | } 378 | for (const ctx of context) { 379 | tokens.push(...ctx); 380 | } 381 | if (tokens.length + this.meanGenLength >= this.maxWindowLength) { 382 | throw Error('Exceed max window length curr=' + tokens.length); 383 | } 384 | return tokens; 385 | } 386 | 387 | resetChat() { 388 | if (this.conversation) { 389 | this.conversation.reset(); 390 | } 391 | this.#clearKVCache(); 392 | this.decodingTotalTime = 0; 393 | this.encodingTotalTime = 0; 394 | this.decodingTotalTokens = 0; 395 | this.encodingTotalTokens = 0; 396 | } 397 | 398 | async generate( 399 | inputPrompt: any, 400 | callbackUpdateResponse: (arg0: number, arg1: string) => void, 401 | ) { 402 | // switch to new Conversation 403 | if (this.conversation.convId !== tvmjsGlobalEnv.covId) { 404 | } 405 | this.conversation.appendMessage(this.conversation.roles[0], inputPrompt); 406 | this.conversation.appendMessage(this.conversation.roles[1], ''); 407 | const stopStr = this.conversation.getStopStr(); 408 | const tokens = await this.getInputTokens(); 409 | const inputTokenLength = tokens.length; 410 | 411 | var outputPrompt = ''; 412 | if (this.clearCache) { 413 | this.#clearKVCache(); 414 | this.clearCache = false; 415 | } 416 | const maxGenLen = Math.min( 417 | this.maxGenLength, 418 | this.maxWindowLength - tokens.length, 419 | ); 420 | if (maxGenLen < this.meanGenLength) { 421 | throw Error('Too small window size config'); 422 | } 423 | let step = 0; 424 | for ( 425 | ; 426 | step < maxGenLen && 427 | this.kvCacheLength + inputTokenLength + step < this.maxWindowLength; 428 | ++step 429 | ) { 430 | this.tvm.beginScope(); 431 | var inputData; 432 | 433 | let tstart = performance.now(); 434 | if (step == 0) { 435 | inputData = this.tvm.empty([1, tokens.length], 'int32', this.device); 436 | inputData.copyFrom(tokens); 437 | } else { 438 | inputData = this.tvm.empty([1, 1], 'int32', this.device); 439 | inputData.copyFrom(tokens.slice(tokens.length - 1)); 440 | } 441 | const logits = this.tvm.detachFromCurrentScope( 442 | this.#forward(inputData, this.kvCacheLength + inputTokenLength + step), 443 | ); 444 | this.tvm.endScope(); 445 | 446 | const nextToken = await this.sampleTokenFromLogits(logits); 447 | logits.dispose(); 448 | 449 | tokens.push(nextToken); 450 | const outputTokens = tokens.slice(inputTokenLength); 451 | outputPrompt = this.tokenizer.decodeIds(outputTokens); 452 | 453 | if (nextToken == this.eosTokenId) break; 454 | 455 | const stopPos = outputPrompt.lastIndexOf(stopStr); 456 | if (stopPos != -1) { 457 | outputPrompt = outputPrompt.substring(0, stopPos); 458 | break; 459 | } 460 | let tend = performance.now(); 461 | if (step != 0) { 462 | this.decodingTotalTokens += 1; 463 | this.decodingTotalTime += (tend - tstart) / 1000; 464 | } else { 465 | this.encodingTotalTime += (tend - tstart) / 1000; 466 | this.encodingTotalTokens += inputTokenLength; 467 | } 468 | 469 | if (step % this.streamInterval == 0) { 470 | callbackUpdateResponse(step, outputPrompt); 471 | } 472 | } 473 | this.kvCacheLength += tokens.length - 1; 474 | tvmjsGlobalEnv.workerHistoryMsg[ 475 | tvmjsGlobalEnv.workerHistoryMsg.length - 1 476 | ][1] = outputPrompt; 477 | return outputPrompt; 478 | } 479 | 480 | async evaluate() { 481 | // run a canonical evaluation of the flow 482 | this.#clearKVCache(); 483 | const testPrompt = 'The capital of Canada is'; 484 | const ids = await this.tokenizer.encodeIds(testPrompt); 485 | const inputPromptSize = ids.length; 486 | const tokens = Array.from(ids); 487 | tokens.unshift(this.bosTokenId); 488 | if (tokens.length == 0) { 489 | throw Error('empty token'); 490 | } 491 | 492 | this.tvm.beginScope(); 493 | const inputData = this.tvm.empty([1, tokens.length], 'int32', this.device); 494 | inputData.copyFrom(tokens); 495 | const encodingStart = performance.now(); 496 | this.#forward(inputData, tokens.length); 497 | this.tvm.endScope(); 498 | await this.device.sync(); 499 | 500 | const decodingStart = performance.now(); 501 | 502 | this.tvm.beginScope(); 503 | const firstSampleToken = this.tvm 504 | .empty([1, 1], 'int32', this.device) 505 | .copyFrom([6234]); 506 | this.#updateLogitsOnCPU(this.#forward(firstSampleToken, tokens.length + 1)); 507 | await this.device.sync(); 508 | this.tvm.endScope(); 509 | 510 | const decodingEnd = performance.now(); 511 | const msg = 512 | `encoding-time=${((decodingStart - encodingStart) / 1000).toFixed( 513 | 4, 514 | )} sec` + 515 | `decoding-time=${((decodingEnd - decodingStart) / 1000).toFixed(4)} sec`; 516 | 517 | // simply log tokens for eyeballing. 518 | console.log('Logits:'); 519 | console.log(this.logitsOnCPU.toArray()); 520 | console.log(msg); 521 | } 522 | 523 | /** 524 | * async preload webgpu pipelines when possible. 525 | */ 526 | async asyncLoadWebGPUPiplines() { 527 | await this.tvm.asyncLoadWebGPUPiplines(this.vm.getInternalModule()); 528 | } 529 | 530 | runtimeStatsText() { 531 | return ( 532 | `encoding: ${(this.encodingTotalTokens / this.encodingTotalTime).toFixed( 533 | 4, 534 | )} tokens/sec, ` + 535 | `decoding: ${(this.decodingTotalTokens / this.decodingTotalTime).toFixed( 536 | 4, 537 | )} tokens/sec` 538 | ); 539 | } 540 | } 541 | 542 | /** 543 | * A instance that can be used to facilitate deployment. 544 | */ 545 | class LLMChatInstance { 546 | requestInProgress: boolean; 547 | config: any; 548 | tvm: any; 549 | pipeline: any; 550 | logger: { 551 | (...data: any[]): void; 552 | (...data: any[]): void; 553 | (message?: any, ...optionalParams: any[]): void; 554 | }; 555 | debugTest: boolean; 556 | constructor() { 557 | this.requestInProgress = false; 558 | this.config = undefined; 559 | this.tvm = undefined; 560 | this.pipeline = undefined; 561 | this.logger = console.log; 562 | this.debugTest = false; 563 | } 564 | /** 565 | * Initialize TVM 566 | * @param wasmUrl URL to wasm source. 567 | * @param cacheUrl URL to NDArray cache. 568 | * @param logger Custom logger. 569 | */ 570 | async #asyncInitTVM(wasmUrl: RequestInfo, cacheUrl: any) { 571 | if (this.tvm !== undefined) { 572 | return; 573 | } 574 | this.logger = console.log; 575 | 576 | const wasmSource = await (await fetch(wasmUrl)).arrayBuffer(); 577 | const tvm = await tvmjs.instantiate( 578 | new Uint8Array(wasmSource), 579 | new EmccWASI(), 580 | this.logger, 581 | ); 582 | // intialize WebGPU 583 | try { 584 | const output = await tvmjs.detectGPUDevice(); 585 | if (output !== undefined) { 586 | var label = 'WebGPU'; 587 | if (output.adapterInfo.description.length != 0) { 588 | label += ' - ' + output.adapterInfo.description; 589 | } else { 590 | label += ' - ' + output.adapterInfo.vendor; 591 | } 592 | this.appendMessage('init', 'Initialize GPU device: ' + label); 593 | tvm.initWebGPU(output.device); 594 | } else { 595 | this.appendMessage('error', 'This browser env do not support WebGPU'); 596 | this.reset(); 597 | throw Error('This browser env do not support WebGPU'); 598 | } 599 | } catch (err: any) { 600 | this.appendMessage( 601 | 'error', 602 | 'Find an error initializing the WebGPU device ' + err.toString(), 603 | ); 604 | console.log(err); 605 | this.reset(); 606 | throw Error('Find an error initializing WebGPU: ' + err.toString()); 607 | } 608 | this.tvm = tvm; 609 | const initProgressCallback = (report: { text: any }) => { 610 | this.updateLastMessage('initing', report.text); 611 | }; 612 | tvm.registerInitProgressCallback(initProgressCallback); 613 | 614 | await tvm.fetchNDArrayCache(cacheUrl, tvm.webgpu()); 615 | } 616 | /** 617 | * Async initialize instance. 618 | */ 619 | async asyncInit() { 620 | if (this.pipeline !== undefined) return; 621 | await this.#asyncInitConfig(); 622 | await this.#asyncInitTVM(this.config.wasmUrl, this.config.cacheUrl); 623 | await this.#asyncInitPipeline(); 624 | } 625 | 626 | /** 627 | * Async initialize config 628 | */ 629 | async #asyncInitConfig() { 630 | if (this.config !== undefined) return; 631 | this.config = await (await fetch('/lib/WebLLM/config.json')).json(); 632 | } 633 | 634 | /** 635 | * Initialize the pipeline 636 | * 637 | * @param tokenizerModel The url to tokenizer model. 638 | */ 639 | async #asyncInitPipeline() { 640 | if (this.pipeline !== undefined) return; 641 | // initialize UX and tokenizer 642 | const tokenizer = await tvmjsGlobalEnv.sentencePieceProcessor( 643 | this.config.tokenizer, 644 | ); 645 | this.pipeline = this.tvm.withNewScope(() => { 646 | return new LLMChatPipeline( 647 | this.tvm, 648 | tokenizer, 649 | this.tvm.cacheMetadata, 650 | this.config, 651 | ); 652 | }); 653 | await this.pipeline.asyncLoadWebGPUPiplines(); 654 | this.appendMessage('initing', 'All initialization finished.', true); 655 | } 656 | 657 | appendMessage(kind: string, text: string, ifFinish?: boolean) { 658 | if (kind == 'initing') { 659 | text = '[System Initalize] ' + text; 660 | } 661 | console.log(`[${kind}] ${text}`); 662 | globalThis.postMessage({ 663 | type: 'initing', 664 | action: 'append', 665 | msg: text, 666 | ifError: kind == 'error', 667 | ifFinish: !!ifFinish, 668 | }); 669 | } 670 | 671 | updateLastMessage(type: string, text: string, ifFinish?: boolean) { 672 | if (type == 'initing') { 673 | text = `[System Initalize] ${text}`; 674 | } 675 | globalThis.postMessage({ 676 | type, 677 | action: 'updateLast', 678 | msg: text, 679 | ifFinish: !!ifFinish, 680 | }); 681 | } 682 | 683 | async respondTestMessage(repeat: number) { 684 | const testMessage = 'I am a friendly bot. Please ask questions.'; 685 | const encodedResult = await this.pipeline.tokenizer.encodeIds(testMessage); 686 | 687 | const currentIds = []; 688 | for (let k = 0; k < repeat; ++k) { 689 | for (let i = 0; i < encodedResult.length; ++i) { 690 | currentIds.push(encodedResult[i]); 691 | const msg = this.pipeline.tokenizer.decodeIds(currentIds); 692 | this.updateLastMessage('chatting', msg); 693 | await new Promise((resolve) => setTimeout(resolve, 50)); 694 | } 695 | } 696 | } 697 | 698 | resetChat() { 699 | if (this.pipeline) { 700 | this.pipeline.resetChat(); 701 | } 702 | } 703 | 704 | /** 705 | * Run generate 706 | */ 707 | async generate() { 708 | if (this.requestInProgress) { 709 | return; 710 | } 711 | 712 | this.requestInProgress = true; 713 | 714 | try { 715 | await this.asyncInit(); 716 | } catch (err: any) { 717 | this.appendMessage('error', 'Init error, ' + err.toString()); 718 | console.log(err); 719 | this.reset(); 720 | this.requestInProgress = false; 721 | return; 722 | } 723 | 724 | if (this.debugTest) { 725 | await this.pipeline.evaluate(); 726 | this.requestInProgress = false; 727 | return; 728 | } 729 | 730 | const prompt = tvmjsGlobalEnv.message; 731 | if (prompt == '') { 732 | this.requestInProgress = false; 733 | return; 734 | } 735 | 736 | const callbackUpdateResponse = (step: any, msg: string) => { 737 | if (msg.endsWith('##')) { 738 | msg = msg.substring(0, msg.length - 2); 739 | } else if (msg.endsWith('#')) { 740 | msg = msg.substring(0, msg.length - 1); 741 | } 742 | this.updateLastMessage('chatting', msg); 743 | }; 744 | try { 745 | const output = await this.pipeline.generate( 746 | prompt, 747 | callbackUpdateResponse, 748 | ); 749 | this.updateLastMessage('chatting', output, true); 750 | this.updateLastMessage('stats', this.pipeline.runtimeStatsText()); 751 | console.log(this.pipeline.runtimeStatsText()); 752 | } catch (err: any) { 753 | this.appendMessage('error', 'Generate error, ' + err.toString()); 754 | console.log(err); 755 | this.reset(); 756 | } 757 | this.requestInProgress = false; 758 | } 759 | 760 | /** 761 | * Reset the instance; 762 | */ 763 | reset() { 764 | this.tvm = undefined; 765 | if (this.pipeline !== undefined) { 766 | this.pipeline.dispose(); 767 | } 768 | this.pipeline = undefined; 769 | } 770 | } 771 | --------------------------------------------------------------------------------