├── .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 |
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 | 
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 | [](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 | 
81 |
82 | 
83 |
84 | ## 🌟 History
85 | [](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 | {
87 | const conversationName = window.prompt('Enter name: ');
88 | if (!conversationName) {
89 | return;
90 | }
91 | chatStore.updateCurConversation((conversation) => {
92 | conversation.title = conversationName;
93 | });
94 | }}
95 | className="btn btn-ghost btn-xs"
96 | >
97 |
98 |
99 | chatStore.delConversation(curConversationIndex)}
101 | className="btn btn-ghost btn-xs"
102 | >
103 |
104 |
105 |
106 |
107 |
111 | {chatStore.curConversation()?.messages.map((item, i) => (
112 |
118 |
130 |
131 |
132 | {item.updateTime}
133 |
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 |
163 |
164 |
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 |
chatStore.toggleInitModal(false)}
29 | >
30 | ✕
31 |
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 | chatStore.toggleInstuctionModal(false)}
93 | >
94 | Okay, Let's start!
95 |
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 |
chatStore.toggleInstuctionModal(true)}
17 | className="btn btn-ghost btn-xs"
18 | >
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
38 |
39 |
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 |
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 |
73 | {isCopied ? : }
74 |
75 |
76 |
77 |
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 |
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 |
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 | 
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 | [](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 | 
71 |
72 | 
73 |
74 | ## LICENSE
75 |
76 | [MIT](./LICENSE)
77 |
--------------------------------------------------------------------------------
/docs/README_JA.md:
--------------------------------------------------------------------------------
1 |
2 |
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 | 
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 | [](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 | 
80 |
81 | 
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 | {/* Open drawer */}
65 |
66 |
67 |
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 |
--------------------------------------------------------------------------------