Commit
•
d443007
1
Parent(s):
5ff56f1
Upload 138 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -0
- mlc-llm-main/.clang-format +8 -0
- mlc-llm-main/.gitignore +323 -0
- mlc-llm-main/.gitmodules +6 -0
- mlc-llm-main/3rdparty/tokenizers-cpp/CMakeLists.txt +81 -0
- mlc-llm-main/3rdparty/tokenizers-cpp/Cargo.toml +13 -0
- mlc-llm-main/3rdparty/tokenizers-cpp/src/lib.rs +187 -0
- mlc-llm-main/3rdparty/tokenizers-cpp/tokenizers.h +101 -0
- mlc-llm-main/CMakeLists.txt +148 -0
- mlc-llm-main/LICENSE +201 -0
- mlc-llm-main/README.md +65 -0
- mlc-llm-main/android/.gitignore +3 -0
- mlc-llm-main/android/MLCChat/.gitignore +15 -0
- mlc-llm-main/android/MLCChat/app/.gitignore +1 -0
- mlc-llm-main/android/MLCChat/app/build.gradle +71 -0
- mlc-llm-main/android/MLCChat/app/proguard-rules.pro +21 -0
- mlc-llm-main/android/MLCChat/app/src/main/AndroidManifest.xml +36 -0
- mlc-llm-main/android/MLCChat/app/src/main/ic_launcher-playstore.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/ChatState.java +117 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Config.java +12 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Downloader.java +109 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/LLMChat.java +97 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MainActivity.java +178 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MessageAdapter.java +83 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MessageData.java +26 -0
- mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Utils.java +73 -0
- mlc-llm-main/android/MLCChat/app/src/main/jni/Android.mk +75 -0
- mlc-llm-main/android/MLCChat/app/src/main/jni/Application.mk +5 -0
- mlc-llm-main/android/MLCChat/app/src/main/jni/tvm_runtime.h +7 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/drawable/bot_rounded_corner.xml +16 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/drawable/user_rounded_corner.xml +16 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/layout/activity_main.xml +92 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/layout/bot_message.xml +30 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/layout/user_message.xml +30 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
.gitattributes
CHANGED
@@ -32,3 +32,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
mlc-llm-main/site/gif/ios-demo.gif filter=lfs diff=lfs merge=lfs -text
|
36 |
+
mlc-llm-main/site/img/android/android-studio.png filter=lfs diff=lfs merge=lfs -text
|
mlc-llm-main/.clang-format
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Run the following command to reformat a file:
|
2 |
+
# clang-format -i -style=Google <file>
|
3 |
+
# Or use clang-format-diff to only reformat the changed lines:
|
4 |
+
# https://clang.llvm.org/docs/ClangFormat.html
|
5 |
+
BasedOnStyle: Google
|
6 |
+
DerivePointerAlignment: false
|
7 |
+
ColumnLimit: 100
|
8 |
+
PointerAlignment: Left
|
mlc-llm-main/.gitignore
ADDED
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
dist/
|
2 |
+
params/
|
3 |
+
*.bak
|
4 |
+
# Byte-compiled / optimized / DLL files
|
5 |
+
__pycache__/
|
6 |
+
*.py[cod]
|
7 |
+
*$py.class
|
8 |
+
|
9 |
+
.DS_Store
|
10 |
+
|
11 |
+
*.S
|
12 |
+
# C extensions
|
13 |
+
*.so
|
14 |
+
|
15 |
+
build*
|
16 |
+
|
17 |
+
*.ll
|
18 |
+
.npm
|
19 |
+
# Distribution / packaging
|
20 |
+
.Python
|
21 |
+
env/
|
22 |
+
build/
|
23 |
+
build-*/
|
24 |
+
develop-eggs/
|
25 |
+
dist/
|
26 |
+
downloads/
|
27 |
+
eggs/
|
28 |
+
.eggs/
|
29 |
+
lib/
|
30 |
+
lib64/
|
31 |
+
parts/
|
32 |
+
sdist/
|
33 |
+
var/
|
34 |
+
wheels/
|
35 |
+
pip-wheel-metadata/
|
36 |
+
share/python-wheels/
|
37 |
+
*.egg-info/
|
38 |
+
.installed.cfg
|
39 |
+
*.egg
|
40 |
+
MANIFEST
|
41 |
+
|
42 |
+
.conda/
|
43 |
+
# PyInstaller
|
44 |
+
# Usually these files are written by a python script from a template
|
45 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
46 |
+
*.manifest
|
47 |
+
*.spec
|
48 |
+
|
49 |
+
# Generated by python/gen_requirements.py
|
50 |
+
python/requirements/*.txt
|
51 |
+
|
52 |
+
# Installer logs
|
53 |
+
pip-log.txt
|
54 |
+
pip-delete-this-directory.txt
|
55 |
+
|
56 |
+
# Unit test / coverage reports
|
57 |
+
htmlcov/
|
58 |
+
.tox/
|
59 |
+
.nox/
|
60 |
+
.coverage
|
61 |
+
.coverage.*
|
62 |
+
.cache
|
63 |
+
nosetests.xml
|
64 |
+
coverage.xml
|
65 |
+
*.cover
|
66 |
+
*.py,cover
|
67 |
+
.hypothesis/
|
68 |
+
.pytest_cache/
|
69 |
+
|
70 |
+
# Translations
|
71 |
+
*.mo
|
72 |
+
*.pot
|
73 |
+
|
74 |
+
# Django stuff:
|
75 |
+
*.log
|
76 |
+
local_settings.py
|
77 |
+
db.sqlite3
|
78 |
+
db.sqlite3-journal
|
79 |
+
|
80 |
+
# Flask stuff:
|
81 |
+
instance/
|
82 |
+
.webassets-cache
|
83 |
+
|
84 |
+
# Scrapy stuff:
|
85 |
+
.scrapy
|
86 |
+
|
87 |
+
# Sphinx documentation
|
88 |
+
docs/_build/
|
89 |
+
docs/_staging/
|
90 |
+
|
91 |
+
# PyBuilder
|
92 |
+
target/
|
93 |
+
/target/
|
94 |
+
|
95 |
+
# Jupyter Notebook
|
96 |
+
.ipynb_checkpoints
|
97 |
+
|
98 |
+
# IPython
|
99 |
+
profile_default/
|
100 |
+
ipython_config.py
|
101 |
+
|
102 |
+
# pyenv
|
103 |
+
.python-version
|
104 |
+
|
105 |
+
# pipenv
|
106 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
107 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
108 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
109 |
+
# install all needed dependencies.
|
110 |
+
#Pipfile.lock
|
111 |
+
|
112 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
113 |
+
__pypackages__/
|
114 |
+
|
115 |
+
# Celery stuff
|
116 |
+
celerybeat-schedule
|
117 |
+
celerybeat.pid
|
118 |
+
|
119 |
+
# SageMath parsed files
|
120 |
+
*.sage.py
|
121 |
+
|
122 |
+
# Environments
|
123 |
+
.env
|
124 |
+
.venv
|
125 |
+
env/
|
126 |
+
venv/
|
127 |
+
ENV/
|
128 |
+
env.bak/
|
129 |
+
venv.bak/
|
130 |
+
|
131 |
+
# Spyder project settings
|
132 |
+
.spyderproject
|
133 |
+
.spyproject
|
134 |
+
|
135 |
+
# Rope project settings
|
136 |
+
.ropeproject
|
137 |
+
*~
|
138 |
+
*.pyc
|
139 |
+
*~
|
140 |
+
config.mk
|
141 |
+
config.cmake
|
142 |
+
Win32
|
143 |
+
*.dir
|
144 |
+
perf
|
145 |
+
*.wasm
|
146 |
+
.emscripten
|
147 |
+
|
148 |
+
## IOS
|
149 |
+
DerivedData/
|
150 |
+
|
151 |
+
## Java
|
152 |
+
*.class
|
153 |
+
jvm/*/target/
|
154 |
+
jvm/*/*/target/
|
155 |
+
jvm/native/*/generated
|
156 |
+
jvm/native/src/main/native/org_apache_tvm_native_c_api.h
|
157 |
+
*.worksheet
|
158 |
+
*.idea
|
159 |
+
*.iml
|
160 |
+
*.classpath
|
161 |
+
*.project
|
162 |
+
*.settings
|
163 |
+
*/node_modules/
|
164 |
+
|
165 |
+
## Various settings
|
166 |
+
*.pbxuser
|
167 |
+
!default.pbxuser
|
168 |
+
*.mode1v3
|
169 |
+
!default.mode1v3
|
170 |
+
*.mode2v3
|
171 |
+
!default.mode2v3
|
172 |
+
*.perspectivev3
|
173 |
+
!default.perspectivev3
|
174 |
+
xcuserdata/
|
175 |
+
.pkl_memoize_*
|
176 |
+
|
177 |
+
.emscripten*
|
178 |
+
.m2
|
179 |
+
|
180 |
+
# Compiled Dynamic libraries
|
181 |
+
*.so
|
182 |
+
*.dylib
|
183 |
+
*.dll
|
184 |
+
|
185 |
+
# Compiled Object files
|
186 |
+
*.slo
|
187 |
+
*.lo
|
188 |
+
*.o
|
189 |
+
*.obj
|
190 |
+
|
191 |
+
# Precompiled Headers
|
192 |
+
*.gch
|
193 |
+
*.pch
|
194 |
+
|
195 |
+
# Compiled Static libraries
|
196 |
+
*.lai
|
197 |
+
*.la
|
198 |
+
*.a
|
199 |
+
*.lib
|
200 |
+
|
201 |
+
# Executables
|
202 |
+
*.exe
|
203 |
+
*.out
|
204 |
+
*.app
|
205 |
+
|
206 |
+
## Other
|
207 |
+
*.moved-aside
|
208 |
+
*.xccheckout
|
209 |
+
*.xcscmblueprint
|
210 |
+
.DS_Store
|
211 |
+
tags
|
212 |
+
cscope*
|
213 |
+
*.lock
|
214 |
+
|
215 |
+
# vim temporary files
|
216 |
+
*.swp
|
217 |
+
*.swo
|
218 |
+
|
219 |
+
# TVM generated code
|
220 |
+
perf
|
221 |
+
.bash_history
|
222 |
+
# *.json
|
223 |
+
*.params
|
224 |
+
*.ro
|
225 |
+
*.onnx
|
226 |
+
*.h5
|
227 |
+
synset.txt
|
228 |
+
cat.jpg
|
229 |
+
cat.png
|
230 |
+
docs.tgz
|
231 |
+
cat.png
|
232 |
+
*.mlmodel
|
233 |
+
tvm_u.*
|
234 |
+
tvm_t.*
|
235 |
+
# Mac OS X
|
236 |
+
.DS_Store
|
237 |
+
|
238 |
+
# Jetbrain
|
239 |
+
.idea
|
240 |
+
.ipython
|
241 |
+
.jupyter
|
242 |
+
.nv
|
243 |
+
.pylint.d
|
244 |
+
.python_history
|
245 |
+
.pytest_cache
|
246 |
+
.local
|
247 |
+
cmake-build-debug
|
248 |
+
|
249 |
+
# Visual Studio
|
250 |
+
.vs
|
251 |
+
|
252 |
+
# Visual Studio Code
|
253 |
+
.vscode
|
254 |
+
|
255 |
+
# tmp file
|
256 |
+
.nfs*
|
257 |
+
|
258 |
+
# keys
|
259 |
+
*.pem
|
260 |
+
*.p12
|
261 |
+
*.pfx
|
262 |
+
*.cer
|
263 |
+
*.crt
|
264 |
+
*.der
|
265 |
+
|
266 |
+
# patch sentinel
|
267 |
+
patched.txt
|
268 |
+
|
269 |
+
# Python type checking
|
270 |
+
.mypy_cache/
|
271 |
+
.pyre/
|
272 |
+
|
273 |
+
# pipenv files
|
274 |
+
Pipfile
|
275 |
+
Pipfile.lock
|
276 |
+
|
277 |
+
# conda package artifacts
|
278 |
+
conda/Dockerfile.cuda*
|
279 |
+
conda/pkg
|
280 |
+
.node_repl_history
|
281 |
+
# nix files
|
282 |
+
.envrc
|
283 |
+
*.nix
|
284 |
+
|
285 |
+
# Docker files
|
286 |
+
.sudo_as_admin_successful
|
287 |
+
|
288 |
+
# Downloaded models/datasets
|
289 |
+
.tvm_test_data
|
290 |
+
.dgl
|
291 |
+
.caffe2
|
292 |
+
|
293 |
+
# Local docs build
|
294 |
+
_docs/
|
295 |
+
jvm/target
|
296 |
+
.config/configstore/
|
297 |
+
.ci-py-scripts/
|
298 |
+
|
299 |
+
# Generated Hexagon files
|
300 |
+
src/runtime/hexagon/rpc/hexagon_rpc.h
|
301 |
+
src/runtime/hexagon/rpc/hexagon_rpc_skel.c
|
302 |
+
src/runtime/hexagon/rpc/hexagon_rpc_stub.c
|
303 |
+
|
304 |
+
# Local tvm-site checkout
|
305 |
+
tvm-site/
|
306 |
+
|
307 |
+
# Generated docs files
|
308 |
+
gallery/how_to/work_with_microtvm/micro_tvmc.py
|
309 |
+
|
310 |
+
# Test sample data files
|
311 |
+
!tests/python/ci/sample_prs/*.json
|
312 |
+
|
313 |
+
# Used in CI to communicate between Python and Jenkins
|
314 |
+
.docker-image-names/
|
315 |
+
|
316 |
+
# Printed TIR code on disk
|
317 |
+
*.tir
|
318 |
+
|
319 |
+
# GDB history file
|
320 |
+
.gdb_history
|
321 |
+
|
322 |
+
3rdparty
|
323 |
+
dist
|
mlc-llm-main/.gitmodules
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[submodule "3rdparty/sentencepiece-js"]
|
2 |
+
path = 3rdparty/sentencepiece-js
|
3 |
+
url = https://github.com/tqchen/sentencepiece-js
|
4 |
+
[submodule "3rdparty/argparse"]
|
5 |
+
path = 3rdparty/argparse
|
6 |
+
url = https://github.com/p-ranav/argparse
|
mlc-llm-main/3rdparty/tokenizers-cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# update to contain more rust flags
|
2 |
+
set(TOKENIZERS_CPP_RUST_FLAGS "")
|
3 |
+
set(TOKENIZERS_CPP_CARGO_TARGET "")
|
4 |
+
|
5 |
+
# extra link libraries
|
6 |
+
set(TOKENIZERS_CPP_LINK_LIBS "")
|
7 |
+
set(CARGO_EXTRA_ENVS "")
|
8 |
+
|
9 |
+
if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
10 |
+
set(TOKENIZERS_CPP_CARGO_TARGET aarch64-apple-ios)
|
11 |
+
# add extra dependency needed for rust tokenizer in iOS
|
12 |
+
find_library(FOUNDATION_LIB Foundation)
|
13 |
+
find_library(SECURITY_LIB Security)
|
14 |
+
list(APPEND TOKENIZERS_CPP_LINK_LIBS ${FOUNDATION_LIB} ${SECURITY_LIB})
|
15 |
+
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
16 |
+
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
17 |
+
set(TOKENIZERS_CPP_CARGO_TARGET aarch64-apple-darwin)
|
18 |
+
endif()
|
19 |
+
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
|
20 |
+
set(TOKENIZERS_CPP_CARGO_TARGET aarch64-linux-android)
|
21 |
+
set(CARGO_EXTRA_ENVS
|
22 |
+
AR_aarch64_linux_android=${ANDROID_TOOLCHAIN_ROOT}/bin/llvm-ar
|
23 |
+
CC_aarch64_linux_android=${ANDROID_TOOLCHAIN_ROOT}/bin/aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang
|
24 |
+
CXX_aarch64_linux_android=${ANDROID_TOOLCHAIN_ROOT}/bin/aarch64-linux-android${ANDROID_NATIVE_API_LEVEL}-clang++
|
25 |
+
)
|
26 |
+
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
27 |
+
set(TOKENIZERS_CPP_CARGO_TARGET x86_64-pc-windows-msvc)
|
28 |
+
endif()
|
29 |
+
|
30 |
+
if(WIN32)
|
31 |
+
list(APPEND TOKENIZERS_CPP_LINK_LIBS
|
32 |
+
wsock32 ws2_32 Bcrypt
|
33 |
+
iphlpapi userenv psapi
|
34 |
+
)
|
35 |
+
endif()
|
36 |
+
|
37 |
+
set(TOKENIZERS_CPP_CARGO_FLAGS "")
|
38 |
+
set(TOKENIZERS_CPP_CARGO_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
39 |
+
set(TOKENIZERS_CPP_CARGO_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
40 |
+
|
41 |
+
if (NOT TOKENIZERS_CPP_CARGO_TARGET STREQUAL "")
|
42 |
+
list(APPEND TOKENIZERS_CPP_CARGO_FLAGS --target ${TOKENIZERS_CPP_CARGO_TARGET})
|
43 |
+
set(TOKENIZERS_CPP_CARGO_BINARY_DIR
|
44 |
+
"${TOKENIZERS_CPP_CARGO_BINARY_DIR}/${TOKENIZERS_CPP_CARGO_TARGET}")
|
45 |
+
endif()
|
46 |
+
|
47 |
+
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
48 |
+
set(TOKENIZERS_CPP_CARGO_BINARY_DIR "${TOKENIZERS_CPP_CARGO_BINARY_DIR}/debug")
|
49 |
+
else ()
|
50 |
+
list(APPEND TOKENIZERS_CPP_CARGO_FLAGS --release)
|
51 |
+
set(TOKENIZERS_CPP_CARGO_BINARY_DIR "${TOKENIZERS_CPP_CARGO_BINARY_DIR}/release")
|
52 |
+
endif ()
|
53 |
+
|
54 |
+
get_filename_component(TOKENIZERS_CPP_CARGO_SOURCE_PATH ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
|
55 |
+
|
56 |
+
if(MSVC)
|
57 |
+
set(TOKENIZERS_CPP_LIB "${TOKENIZERS_CPP_CARGO_BINARY_DIR}/tokenizers_cpp.lib")
|
58 |
+
else()
|
59 |
+
set(TOKENIZERS_CPP_LIB "${TOKENIZERS_CPP_CARGO_BINARY_DIR}/libtokenizers_cpp.a")
|
60 |
+
endif()
|
61 |
+
set(TOKENIZERS_CPP_INCLUDE ${TOKENIZERS_CPP_CARGO_SOURCE_PATH})
|
62 |
+
|
63 |
+
# NOTE: need to use cmake -E env to be portable in win
|
64 |
+
|
65 |
+
add_custom_command(
|
66 |
+
OUTPUT ${TOKENIZERS_CPP_LIB}
|
67 |
+
COMMAND
|
68 |
+
${CMAKE_COMMAND} -E env
|
69 |
+
CARGO_TARGET_DIR=${TOKENIZERS_CPP_CARGO_TARGET_DIR}
|
70 |
+
${CARGO_EXTRA_ENVS}
|
71 |
+
RUSTFLAGS="${TOKENIZERS_CPP_RUST_FLAGS}"
|
72 |
+
cargo build ${TOKENIZERS_CPP_CARGO_FLAGS}
|
73 |
+
WORKING_DIRECTORY ${TOKENIZERS_CPP_CARGO_SOURCE_PATH}
|
74 |
+
POST_BUILD COMMAND
|
75 |
+
${CMAKE_COMMAND} -E copy
|
76 |
+
${TOKENIZERS_CPP_LIB} "${CMAKE_CURRENT_BINARY_DIR}"
|
77 |
+
)
|
78 |
+
|
79 |
+
add_library(tokenizers INTERFACE ${TOKENIZERS_CPP_LIB})
|
80 |
+
target_link_libraries(tokenizers INTERFACE ${TOKENIZERS_CPP_LIB} ${TOKENIZERS_CPP_LINK_LIBS})
|
81 |
+
target_include_directories(tokenizers INTERFACE ${TOKENIZERS_CPP_INCLUDE})
|
mlc-llm-main/3rdparty/tokenizers-cpp/Cargo.toml
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[package]
|
2 |
+
name = "tokenizers-cpp"
|
3 |
+
version = "0.1.0"
|
4 |
+
edition = "2018"
|
5 |
+
|
6 |
+
[lib]
|
7 |
+
crate-type = ["staticlib"]
|
8 |
+
|
9 |
+
[dependencies]
|
10 |
+
|
11 |
+
tokenizers = { version = "0.13.3", default-features = false, features = ["onig"] }
|
12 |
+
serde = { version = "1.0", features = [ "derive" ] }
|
13 |
+
serde_json = "1.0"
|
mlc-llm-main/3rdparty/tokenizers-cpp/src/lib.rs
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// A simple C wrapper of tokenzier library
|
2 |
+
use serde_json::Value;
|
3 |
+
use std::{collections::HashMap, str::FromStr};
|
4 |
+
use tokenizers::models::bpe::BPE;
|
5 |
+
use tokenizers::pre_tokenizers::byte_level::ByteLevel;
|
6 |
+
use tokenizers::tokenizer::Tokenizer;
|
7 |
+
|
8 |
+
pub struct TokenizerWrapper {
|
9 |
+
tokenizer: Tokenizer,
|
10 |
+
encode_ids: Vec<u32>,
|
11 |
+
decode_str: String,
|
12 |
+
}
|
13 |
+
|
14 |
+
pub type Vocab = HashMap<String, u32>;
|
15 |
+
pub type Merges = Vec<(String, String)>;
|
16 |
+
|
17 |
+
impl TokenizerWrapper {
|
18 |
+
pub fn from_str(json: &str) -> TokenizerWrapper {
|
19 |
+
TokenizerWrapper {
|
20 |
+
tokenizer: Tokenizer::from_str(json).unwrap().into(),
|
21 |
+
encode_ids: Vec::new(),
|
22 |
+
decode_str: String::new(),
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
+
pub fn byte_level_bpe_from_str(
|
27 |
+
vocab: &str,
|
28 |
+
merges: &str,
|
29 |
+
added_tokens: &str,
|
30 |
+
) -> TokenizerWrapper {
|
31 |
+
let vocab_json: Value = serde_json::from_str(vocab).unwrap();
|
32 |
+
let added_tokens_json: Value = serde_json::from_str(added_tokens).unwrap();
|
33 |
+
let mut vocab = HashMap::new();
|
34 |
+
match vocab_json {
|
35 |
+
Value::Object(m) => {
|
36 |
+
for (token, id) in m {
|
37 |
+
if let Value::Number(id) = id {
|
38 |
+
let id = id.as_u64().unwrap() as u32;
|
39 |
+
vocab.insert(token, id);
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
_ => panic!("Invalid vocab.json file."),
|
44 |
+
};
|
45 |
+
match added_tokens_json {
|
46 |
+
Value::Object(m) => {
|
47 |
+
for (token, id) in m {
|
48 |
+
if let Value::Number(id) = id {
|
49 |
+
let id = id.as_u64().unwrap() as u32;
|
50 |
+
vocab.insert(token, id);
|
51 |
+
}
|
52 |
+
}
|
53 |
+
}
|
54 |
+
_ => panic!("Invalid added_tokens.json file."),
|
55 |
+
}
|
56 |
+
|
57 |
+
let merges = merges
|
58 |
+
.lines()
|
59 |
+
.filter(|line| !line.starts_with("#version"))
|
60 |
+
.map(|line| {
|
61 |
+
let parts = line.split(' ').collect::<Vec<_>>();
|
62 |
+
if parts.len() != 2 {
|
63 |
+
panic!("Invalid merges.txt file.")
|
64 |
+
}
|
65 |
+
return (parts[0].to_string(), parts[1].to_string()); // Add the `return` keyword here
|
66 |
+
})
|
67 |
+
.collect::<Vec<(String, String)>>();
|
68 |
+
let byte_level = ByteLevel::new(
|
69 |
+
/*add_prefix_space=*/ false, /*trim_offsets=*/ false,
|
70 |
+
/*use_regex=*/ false,
|
71 |
+
);
|
72 |
+
let mut tokenizer = Tokenizer::new(BPE::new(vocab, merges));
|
73 |
+
tokenizer
|
74 |
+
.with_pre_tokenizer(byte_level)
|
75 |
+
.with_decoder(byte_level);
|
76 |
+
TokenizerWrapper {
|
77 |
+
tokenizer: tokenizer,
|
78 |
+
encode_ids: Vec::new(),
|
79 |
+
decode_str: String::new(),
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
pub fn encode(&mut self, text: &str, add_special_tokens: bool) {
|
84 |
+
self.encode_ids = Vec::from(
|
85 |
+
self.tokenizer
|
86 |
+
.encode(text, add_special_tokens)
|
87 |
+
.unwrap()
|
88 |
+
.get_ids(),
|
89 |
+
);
|
90 |
+
}
|
91 |
+
|
92 |
+
pub fn decode(&mut self, ids: Vec<u32>, skip_special_tokens: bool) {
|
93 |
+
self.decode_str = self.tokenizer.decode(ids, skip_special_tokens).unwrap();
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
#[no_mangle]
|
98 |
+
extern "C" fn tokenizers_new_from_str(input_cstr: *const u8, len: usize) -> *mut TokenizerWrapper {
|
99 |
+
unsafe {
|
100 |
+
let json = std::str::from_utf8(std::slice::from_raw_parts(input_cstr, len)).unwrap();
|
101 |
+
return Box::into_raw(Box::new(TokenizerWrapper::from_str(json)));
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
#[no_mangle]
|
106 |
+
extern "C" fn byte_level_bpe_tokenizers_new_from_str(
|
107 |
+
input_vocab_str: *const u8,
|
108 |
+
len_vocab: usize,
|
109 |
+
input_merges_str: *const u8,
|
110 |
+
len_merges: usize,
|
111 |
+
input_added_tokens_str: *const u8,
|
112 |
+
len_added_tokens: usize,
|
113 |
+
) -> *mut TokenizerWrapper {
|
114 |
+
unsafe {
|
115 |
+
let vocab =
|
116 |
+
std::str::from_utf8(std::slice::from_raw_parts(input_vocab_str, len_vocab)).unwrap();
|
117 |
+
let merges =
|
118 |
+
std::str::from_utf8(std::slice::from_raw_parts(input_merges_str, len_merges)).unwrap();
|
119 |
+
let added_tokens = std::str::from_utf8(std::slice::from_raw_parts(
|
120 |
+
input_added_tokens_str,
|
121 |
+
len_added_tokens,
|
122 |
+
))
|
123 |
+
.unwrap();
|
124 |
+
return Box::into_raw(Box::new(TokenizerWrapper::byte_level_bpe_from_str(
|
125 |
+
vocab,
|
126 |
+
merges,
|
127 |
+
added_tokens,
|
128 |
+
)));
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
#[no_mangle]
|
133 |
+
extern "C" fn tokenizers_encode(
|
134 |
+
handle: *mut TokenizerWrapper,
|
135 |
+
input_cstr: *const u8,
|
136 |
+
len: usize,
|
137 |
+
add_special_tokens: i32,
|
138 |
+
) {
|
139 |
+
unsafe {
|
140 |
+
let input_data = std::str::from_utf8(std::slice::from_raw_parts(input_cstr, len)).unwrap();
|
141 |
+
(*handle).encode(input_data, add_special_tokens != 0);
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
#[no_mangle]
|
146 |
+
extern "C" fn tokenizers_get_encode_ids(
|
147 |
+
handle: *mut TokenizerWrapper,
|
148 |
+
out_data: *mut *mut u32,
|
149 |
+
out_len: *mut usize,
|
150 |
+
) {
|
151 |
+
unsafe {
|
152 |
+
*out_data = (*handle).encode_ids.as_mut_ptr();
|
153 |
+
*out_len = (*handle).encode_ids.len()
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
#[no_mangle]
|
158 |
+
extern "C" fn tokenizers_decode(
|
159 |
+
handle: *mut TokenizerWrapper,
|
160 |
+
input_ids: *const u32,
|
161 |
+
len: usize,
|
162 |
+
skip_special_tokens: i32,
|
163 |
+
) {
|
164 |
+
unsafe {
|
165 |
+
let input_data = Vec::from(std::slice::from_raw_parts(input_ids, len));
|
166 |
+
(*handle).decode(input_data, skip_special_tokens != 0);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
#[no_mangle]
|
171 |
+
extern "C" fn tokenizers_get_decode_str(
|
172 |
+
handle: *mut TokenizerWrapper,
|
173 |
+
out_cstr: *mut *mut u8,
|
174 |
+
out_len: *mut usize,
|
175 |
+
) {
|
176 |
+
unsafe {
|
177 |
+
*out_cstr = (*handle).decode_str.as_mut_ptr();
|
178 |
+
*out_len = (*handle).decode_str.len();
|
179 |
+
}
|
180 |
+
}
|
181 |
+
|
182 |
+
#[no_mangle]
|
183 |
+
extern "C" fn tokenizers_free(wrapper: *mut TokenizerWrapper) {
|
184 |
+
unsafe {
|
185 |
+
drop(Box::from_raw(wrapper));
|
186 |
+
}
|
187 |
+
}
|
mlc-llm-main/3rdparty/tokenizers-cpp/tokenizers.h
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* Copyright (c) 2023 by Contributors
|
3 |
+
* \file tokenizers.cc
|
4 |
+
* \brief C binding to tokenizers
|
5 |
+
*/
|
6 |
+
#ifndef TOKENIZERS_H_
|
7 |
+
#define TOKENIZERS_H_
|
8 |
+
|
9 |
+
// The C API
|
10 |
+
#ifdef __cplusplus
|
11 |
+
extern "C" {
|
12 |
+
#endif
|
13 |
+
|
14 |
+
#include <stddef.h>
|
15 |
+
#include <stdint.h>
|
16 |
+
|
17 |
+
typedef void* TokenizerHandle;
|
18 |
+
|
19 |
+
TokenizerHandle tokenizers_new_from_str(const char* json, size_t len);
|
20 |
+
|
21 |
+
TokenizerHandle byte_level_bpe_tokenizers_new_from_str(const char* vocab, size_t vocab_len,
|
22 |
+
const char* merges, size_t merges_len,
|
23 |
+
const char* added_tokens,
|
24 |
+
size_t added_tokens_len);
|
25 |
+
|
26 |
+
void tokenizers_encode(TokenizerHandle handle, const char* data, size_t len, int add_special_token);
|
27 |
+
|
28 |
+
void tokenizers_decode(TokenizerHandle handle, const uint32_t* data, size_t len,
|
29 |
+
int skip_special_token);
|
30 |
+
|
31 |
+
void tokenizers_get_decode_str(TokenizerHandle handle, const char** data, size_t* len);
|
32 |
+
|
33 |
+
void tokenizers_get_encode_ids(TokenizerHandle handle, const uint32_t** id_data, size_t* len);
|
34 |
+
|
35 |
+
void tokenizers_free(TokenizerHandle handle);
|
36 |
+
|
37 |
+
#ifdef __cplusplus
|
38 |
+
}
|
39 |
+
#endif
|
40 |
+
|
41 |
+
#ifdef __cplusplus
|
42 |
+
|
43 |
+
#include <string>
|
44 |
+
#include <vector>
|
45 |
+
|
46 |
+
// simple c++ binding
|
47 |
+
namespace tokenizers {
|
48 |
+
|
49 |
+
/*!
|
50 |
+
* \brief A simple c++ header of tokenizer via C API.
|
51 |
+
*/
|
52 |
+
class Tokenizer {
|
53 |
+
public:
|
54 |
+
Tokenizer(const Tokenizer&) = delete;
|
55 |
+
Tokenizer(Tokenizer&& other) { std::swap(other.handle_, handle_); }
|
56 |
+
|
57 |
+
~Tokenizer() {
|
58 |
+
if (handle_ != nullptr) {
|
59 |
+
tokenizers_free(handle_);
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
// use i32 to be consistent with sentencepiece
|
64 |
+
std::vector<int32_t> Encode(const std::string& text, bool add_special_token) {
|
65 |
+
tokenizers_encode(handle_, text.data(), text.length(), static_cast<int>(add_special_token));
|
66 |
+
const uint32_t* data;
|
67 |
+
size_t len;
|
68 |
+
tokenizers_get_encode_ids(handle_, &data, &len);
|
69 |
+
return std::vector<int32_t>(data, data + len);
|
70 |
+
}
|
71 |
+
|
72 |
+
// use i32 to be consistent with sentencepiece
|
73 |
+
std::string Decode(const std::vector<int32_t>& ids, bool skip_special_token) {
|
74 |
+
tokenizers_decode(handle_, reinterpret_cast<const uint32_t*>(ids.data()), ids.size(),
|
75 |
+
static_cast<int>(skip_special_token));
|
76 |
+
const char* data;
|
77 |
+
size_t len;
|
78 |
+
tokenizers_get_decode_str(handle_, &data, &len);
|
79 |
+
return std::string(data, len);
|
80 |
+
}
|
81 |
+
|
82 |
+
// avoid from_file so we don't have file system
|
83 |
+
static Tokenizer FromJSON(const std::string& json) {
|
84 |
+
return Tokenizer(tokenizers_new_from_str(json.data(), json.length()));
|
85 |
+
}
|
86 |
+
|
87 |
+
static Tokenizer FromBPE(const std::string& vocab, const std::string& merges,
|
88 |
+
const std::string& added_tokens) {
|
89 |
+
return Tokenizer(byte_level_bpe_tokenizers_new_from_str(
|
90 |
+
vocab.data(), vocab.length(), merges.data(), merges.length(), added_tokens.data(),
|
91 |
+
added_tokens.length()));
|
92 |
+
}
|
93 |
+
|
94 |
+
private:
|
95 |
+
Tokenizer(TokenizerHandle handle) : handle_(handle) {}
|
96 |
+
// internal handle
|
97 |
+
TokenizerHandle handle_{nullptr};
|
98 |
+
};
|
99 |
+
} // namespace tokenizers
|
100 |
+
#endif
|
101 |
+
#endif // TOKENIZERS_H_
|
mlc-llm-main/CMakeLists.txt
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required(VERSION 3.18)
|
2 |
+
project(mlc_llm C CXX)
|
3 |
+
|
4 |
+
include(CheckCXXCompilerFlag)
|
5 |
+
if(NOT MSVC)
|
6 |
+
check_cxx_compiler_flag("-std=c++17" SUPPORT_CXX17)
|
7 |
+
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_CXX_FLAGS}")
|
8 |
+
set(CMAKE_CUDA_STANDARD 17)
|
9 |
+
else()
|
10 |
+
check_cxx_compiler_flag("/std:c++17" SUPPORT_CXX17)
|
11 |
+
set(CMAKE_CXX_FLAGS "/std:c++17 ${CMAKE_CXX_FLAGS}")
|
12 |
+
set(CMAKE_CUDA_STANDARD 17)
|
13 |
+
endif()
|
14 |
+
|
15 |
+
if(EXISTS ${CMAKE_BINARY_DIR}/config.cmake)
|
16 |
+
include(${CMAKE_BINARY_DIR}/config.cmake)
|
17 |
+
else()
|
18 |
+
if(EXISTS ${CMAKE_SOURCE_DIR}/config.cmake)
|
19 |
+
include(${CMAKE_SOURCE_DIR}/config.cmake)
|
20 |
+
endif()
|
21 |
+
endif()
|
22 |
+
|
23 |
+
if(NOT CMAKE_BUILD_TYPE)
|
24 |
+
set(
|
25 |
+
CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type" FORCE
|
26 |
+
)
|
27 |
+
message(STATUS "Setting default build type to " ${CMAKE_BUILD_TYPE})
|
28 |
+
endif(NOT CMAKE_BUILD_TYPE)
|
29 |
+
|
30 |
+
option(MLC_LLM_INSTALL_STATIC_LIB "Install static lib instead of cli" OFF)
|
31 |
+
|
32 |
+
if (MLC_LLM_INSTALL_STATIC_LIB)
|
33 |
+
set(BUILD_STATIC_RUNTIME ON)
|
34 |
+
endif()
|
35 |
+
|
36 |
+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
37 |
+
|
38 |
+
# tvm runtime config: minimize runtime components
|
39 |
+
set(USE_RPC OFF)
|
40 |
+
set(USE_MICRO OFF)
|
41 |
+
set(USE_GRAPH_EXECUTOR OFF)
|
42 |
+
set(USE_GRAPH_EXECUTOR_DEBUG OFF)
|
43 |
+
set(USE_AOT_EXECUTOR OFF)
|
44 |
+
set(USE_PROFILER OFF)
|
45 |
+
set(USE_GTEST OFF)
|
46 |
+
set(USE_LIBBACKTRACE OFF)
|
47 |
+
add_subdirectory($ENV{TVM_HOME} tvm EXCLUDE_FROM_ALL)
|
48 |
+
|
49 |
+
# sentencepiece config
|
50 |
+
option(SPM_ENABLE_SHARED "override sentence piece config" OFF)
|
51 |
+
option(SPM_ENABLE_TCMALLOC "" OFF)
|
52 |
+
|
53 |
+
|
54 |
+
set(MLC_LLM_RUNTIME_LINKER_LIB "")
|
55 |
+
# provide macro if it does not exist in cmake system
|
56 |
+
# it is OK to skip those since we do not provide these apps in the ios
|
57 |
+
# instead just link to the sentencepiece directly
|
58 |
+
if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
59 |
+
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
|
60 |
+
set_property (TARGET ${TARGET} PROPERTY
|
61 |
+
XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
|
62 |
+
endmacro (set_xcode_property)
|
63 |
+
endif()
|
64 |
+
|
65 |
+
add_subdirectory(3rdparty/sentencepiece-js/sentencepiece sentencepiece EXCLUDE_FROM_ALL)
|
66 |
+
add_subdirectory(3rdparty/tokenizers-cpp tokenizers EXCLUDE_FROM_ALL)
|
67 |
+
|
68 |
+
|
69 |
+
tvm_file_glob(GLOB_RECURSE MLC_LLM_SRCS cpp/*.cc)
|
70 |
+
tvm_file_glob(GLOB_RECURSE MLC_CLI_SRCS cpp/cli_main.cc)
|
71 |
+
list(REMOVE_ITEM MLC_LLM_SRCS ${MLC_CLI_SRCS})
|
72 |
+
|
73 |
+
add_library(mlc_llm_objs OBJECT ${MLC_LLM_SRCS})
|
74 |
+
add_library(mlc_cli_objs OBJECT ${MLC_CLI_SRCS})
|
75 |
+
|
76 |
+
set(
|
77 |
+
MLC_LLM_INCLUDES
|
78 |
+
$ENV{TVM_HOME}/include
|
79 |
+
$ENV{TVM_HOME}/3rdparty/dlpack/include
|
80 |
+
$ENV{TVM_HOME}/3rdparty/dmlc-core/include
|
81 |
+
)
|
82 |
+
|
83 |
+
set(MLC_LLM_COMPILE_DEFS DMLC_USE_LOGGING_LIBRARY=<tvm/runtime/logging.h>)
|
84 |
+
|
85 |
+
target_include_directories(mlc_llm_objs PRIVATE ${MLC_LLM_INCLUDES})
|
86 |
+
target_compile_definitions(mlc_llm_objs PRIVATE ${MLC_LLM_COMPILE_DEFS})
|
87 |
+
target_include_directories(mlc_llm_objs PRIVATE 3rdparty/sentencepiece-js/sentencepiece/src)
|
88 |
+
target_include_directories(mlc_llm_objs PRIVATE 3rdparty/tokenizers-cpp)
|
89 |
+
target_compile_definitions(mlc_llm_objs PRIVATE -DMLC_LLM_EXPORTS)
|
90 |
+
|
91 |
+
add_library(mlc_llm SHARED $<TARGET_OBJECTS:mlc_llm_objs>)
|
92 |
+
add_library(mlc_llm_static STATIC $<TARGET_OBJECTS:mlc_llm_objs>)
|
93 |
+
add_dependencies(mlc_llm_static sentencepiece-static tokenizers tvm_runtime)
|
94 |
+
set_target_properties(mlc_llm_static PROPERTIES OUTPUT_NAME mlc_llm)
|
95 |
+
|
96 |
+
target_link_libraries(mlc_llm PUBLIC tvm_runtime)
|
97 |
+
target_link_libraries(mlc_llm PRIVATE sentencepiece)
|
98 |
+
# note: somehow cmake needs to specify the dependency twice
|
99 |
+
target_link_libraries(mlc_llm PRIVATE tokenizers)
|
100 |
+
|
101 |
+
# Exmaple app that may depends on mlc_llm
|
102 |
+
add_executable(mlc_chat_cli $<TARGET_OBJECTS:mlc_cli_objs>)
|
103 |
+
target_include_directories(mlc_cli_objs PRIVATE ${MLC_LLM_INCLUDES})
|
104 |
+
target_include_directories(mlc_cli_objs PRIVATE 3rdparty/argparse/include)
|
105 |
+
target_compile_definitions(mlc_cli_objs PRIVATE ${MLC_LLM_COMPILE_DEFS})
|
106 |
+
|
107 |
+
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
|
108 |
+
target_link_libraries(mlc_llm PRIVATE log)
|
109 |
+
target_link_libraries(mlc_chat_cli PRIVATE log)
|
110 |
+
endif()
|
111 |
+
|
112 |
+
if (MLC_LLM_INSTALL_STATIC_LIB)
|
113 |
+
target_link_libraries(
|
114 |
+
mlc_chat_cli PRIVATE mlc_llm_static sentencepiece-static tokenizers)
|
115 |
+
target_link_libraries(
|
116 |
+
mlc_chat_cli PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,tvm_runtime>")
|
117 |
+
else()
|
118 |
+
target_link_libraries(mlc_chat_cli PUBLIC mlc_llm)
|
119 |
+
endif()
|
120 |
+
|
121 |
+
# when this option is on,
|
122 |
+
# we install all static lib deps into lib
|
123 |
+
if (MLC_LLM_INSTALL_STATIC_LIB)
|
124 |
+
install(TARGETS
|
125 |
+
mlc_llm_static
|
126 |
+
sentencepiece-static
|
127 |
+
tvm_runtime
|
128 |
+
LIBRARY DESTINATION lib${LIB_SUFFIX}
|
129 |
+
)
|
130 |
+
# tokenizers need special handling as it builds from rust
|
131 |
+
if(MSVC)
|
132 |
+
install(FILES ${CMAKE_BINARY_DIR}/tokenizers/libtokenizers_cpp.lib
|
133 |
+
DESTINATION lib${LIB_SUFFIX}
|
134 |
+
)
|
135 |
+
else()
|
136 |
+
install(FILES ${CMAKE_BINARY_DIR}/tokenizers/libtokenizers_cpp.a
|
137 |
+
DESTINATION lib${LIB_SUFFIX}
|
138 |
+
)
|
139 |
+
endif()
|
140 |
+
else()
|
141 |
+
install(TARGETS mlc_chat_cli tvm_runtime mlc_llm
|
142 |
+
mlc_llm_static
|
143 |
+
sentencepiece-static
|
144 |
+
RUNTIME_DEPENDENCY_SET tokenizers
|
145 |
+
RUNTIME DESTINATION bin
|
146 |
+
LIBRARY DESTINATION lib${LIB_SUFFIX}
|
147 |
+
)
|
148 |
+
endif()
|
mlc-llm-main/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
mlc-llm-main/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# MLC LLM
|
2 |
+
|
3 |
+
| [Project](https://mlc.ai/mlc-llm/) | [Blog](https://mlc.ai/blog/blog/2023/05/01/bringing-accelerated-llm-to-consumer-hardware) | [Demo: iOS](https://mlc.ai/mlc-llm/#iphone) | [Demo: Android](https://mlc.ai/mlc-llm/#android) | [Demo: CLI](https://mlc.ai/mlc-llm/#windows-linux-mac) | [WebLLM](https://mlc.ai/web-llm/) | [WebStableDiffusion](https://mlc.ai/web-stable-diffusion/) |
|
4 |
+
|
5 |
+
MLC LLM is a **universal solution** that allows **any language models** to be **deployed natively** on a diverse set of hardware backends and native applications, plus a **productive framework** for everyone to further optimize model performance for their own use cases.
|
6 |
+
|
7 |
+
Our mission is to **enable everyone to develop, optimize and deploy AI models natively on everyone's devices**.
|
8 |
+
|
9 |
+
Everything runs locally with no server support and accelerated with local GPUs on your phone and laptops.
|
10 |
+
[Supported platforms](https://github.com/mlc-ai/mlc-llm/issues/15) include:
|
11 |
+
* iPhone, iPad;
|
12 |
+
* Android phones;
|
13 |
+
* Metal GPUs and Intel/ARM MacBooks;
|
14 |
+
* AMD, Intel and NVIDIA GPUs via Vulkan on Windows and Linux;
|
15 |
+
* NVIDIA GPUs via CUDA on Windows and Linux;
|
16 |
+
* WebGPU on browsers (through companion project [WebLLM](https://github.com/mlc-ai/web-llm/tree/main)).
|
17 |
+
|
18 |
+
**[Check out our instruction page to try out!](https://mlc.ai/mlc-llm/)**
|
19 |
+
|
20 |
+
<p align="center">
|
21 |
+
<img src="site/gif/ios-demo.gif" height="700">
|
22 |
+
</p>
|
23 |
+
|
24 |
+
## What is MLC LLM?
|
25 |
+
|
26 |
+
In recent years, there has been remarkable progress in generative artificial intelligence (AI) and large language models (LLMs), which are becoming increasingly prevalent. Thanks to open-source initiatives, it is now possible to develop personal AI assistants using open-sourced models. However, LLMs tend to be resource-intensive and computationally demanding. To create a scalable service, developers may need to rely on powerful clusters and expensive hardware to run model inference. Additionally, deploying LLMs presents several challenges, such as their ever-evolving model innovation, memory constraints, and the need for potential optimization techniques.
|
27 |
+
|
28 |
+
The goal of this project is to enable the development, optimization, and deployment of AI models for inference across a range of devices, including not just server-class hardware, but also users' browsers, laptops, and mobile apps. To achieve this, we need to address the diverse nature of compute devices and deployment environments. Some of the key challenges include:
|
29 |
+
|
30 |
+
- Supporting different models of CPUs, GPUs, and potentially other co-processors and accelerators.
|
31 |
+
- Deploying on the native environment of user devices, which may not have python or other necessary dependencies readily available.
|
32 |
+
- Addressing memory constraints by carefully planning allocation and aggressively compressing model parameters.
|
33 |
+
|
34 |
+
MLC LLM offers a repeatable, systematic, and customizable workflow that empowers developers and AI system researchers to implement models and optimizations in a productivity-focused, Python-first approach. This methodology enables quick experimentation with new models, new ideas and new compiler passes, followed by native deployment to the desired targets. Furthermore, we are continuously expanding LLM acceleration by broadening TVM backends to make model compilation more transparent and efficient.
|
35 |
+
|
36 |
+
## How does MLC Enable Universal Native Deployment?
|
37 |
+
|
38 |
+
The cornerstone of our solution is machine learning compilation ([MLC](https://mlc.ai/)), which we leverage to efficiently deploy AI models. We build on the shoulders of open-source ecosystems, including tokenizers from HuggingFace and Google, as well as open-source LLMs like Llama, Vicuna, Dolly, MOSS and more. Our primary workflow is based on [Apache TVM Unity](https://github.com/apache/tvm/tree/unity), an exciting ongoing development in the Apache TVM Community.
|
39 |
+
|
40 |
+
- Dynamic shape: We bake a language model as a TVM IRModule with native dynamic shape support, avoiding the need for extra padding to the maximum length and reducing both computation amount and memory usage.
|
41 |
+
- Composable ML compilation optimizations: we perform many model deployment optimizations, such as better compilation code transformation, fusion, memory planning, library offloading and manual code optimization can be easily incorporated as TVM's IRModule transformations exposed as Python APIs.
|
42 |
+
- Quantization: We utilize low-bit quantizations to compress the model weights and leverage TVM's loop-level TensorIR to quickly customize code generations for different compression encoding schemes.
|
43 |
+
- Runtime: The final generated libraries run on the native environment, with TVM runtime that comes with minimal dependencies, which supports various GPU driver APIs and native language bindings (C, JavaScript, etc).
|
44 |
+
|
45 |
+
<img src="site/img/diag.svg" alt="Architecture Diagram" height=""/>
|
46 |
+
|
47 |
+
Additionally, we also provide a lightweight C++-based example CLI app that showcases how to wrap up the compiled artifacts and necessary pre/post-processing, which will hopefully clarify the workflow to embed them into native applications.
|
48 |
+
|
49 |
+
As a starting point, MLC generates GPU shaders for CUDA, Vulkan and Metal. It is possible to add more support, such as OpenCL, sycl, webgpu-native, through improvements to TVM compiler and runtime. MLC also supports various CPU targets including ARM and x86 via LLVM.
|
50 |
+
|
51 |
+
We heavily rely on open-source ecosystem, more specifically, [TVM Unity](https://discuss.tvm.apache.org/t/establish-tvm-unity-connection-a-technical-strategy/13344), an exciting latest development in the TVM project that enables python-first interactive MLC development experiences that allows us to easily compose new optimizations all in Python, and incrementally bring our app to the environment of interest. We also leveraged optimizations such as fused quantization kernels, first class dynamic shape support and diverse GPU backends.
|
52 |
+
|
53 |
+
## Links
|
54 |
+
|
55 |
+
- You might also be interested in [WebLLM](https://github.com/mlc-ai/web-llm/tree/main), our companion derived project that focus on bringing LLM to browsers.
|
56 |
+
- Project page for [instructions](site/index.md).
|
57 |
+
- [Local build Instructions for ios App](ios/README.md).
|
58 |
+
- You might want to check out our online public [Machine Learning Compilation course](https://mlc.ai) for a systematic
|
59 |
+
walkthrough of our approaches.
|
60 |
+
|
61 |
+
## Acknowledgements
|
62 |
+
|
63 |
+
This project is initiated by members from CMU catalyst, UW SAMPL, SJTU, OctoML and the MLC community. We would love to continue developing and supporting the open-source ML community.
|
64 |
+
|
65 |
+
This project is only possible thanks to the shoulders open-source ecosystems that we stand on. We want to thank the Apache TVM community and developers of the TVM Unity effort. The open-source ML community members made these models publicly available. PyTorch and Hugging Face communities that make these models accessible. We would like to thank the teams behind Vicuna, SentencePiece, LLaMA, Alpaca and MOSS. We also would like to thank the Vulkan, Swift, C++, Python Rust communities that enables this project.
|
mlc-llm-main/android/.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
MLCChat/app/src/main/jni/*.h
|
2 |
+
MLCChat/app/src/main/jni/*.cc
|
3 |
+
MLCChat/app/src/main/obj
|
mlc-llm-main/android/MLCChat/.gitignore
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.iml
|
2 |
+
.gradle
|
3 |
+
/local.properties
|
4 |
+
/.idea/caches
|
5 |
+
/.idea/libraries
|
6 |
+
/.idea/modules.xml
|
7 |
+
/.idea/workspace.xml
|
8 |
+
/.idea/navEditor.xml
|
9 |
+
/.idea/assetWizardSettings.xml
|
10 |
+
.DS_Store
|
11 |
+
/build
|
12 |
+
/captures
|
13 |
+
.externalNativeBuild
|
14 |
+
.cxx
|
15 |
+
local.properties
|
mlc-llm-main/android/MLCChat/app/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
/build
|
mlc-llm-main/android/MLCChat/app/build.gradle
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
apply plugin: 'com.android.application'
|
2 |
+
|
3 |
+
task generateJniHeaders(type: Exec, description: 'Generate JNI Headers') {
|
4 |
+
def headerPath = "${project.projectDir}/src/main/jni"
|
5 |
+
def classPath = "${project.projectDir}/../../build/tvm_home/jvm/core/target/*"
|
6 |
+
def filePath = "${project.projectDir}/../../build/tvm_home/jvm/core/src/main/java/org/apache/tvm/LibInfo.java"
|
7 |
+
commandLine "javac", "-h", headerPath, "-classpath", classPath, filePath
|
8 |
+
doLast {
|
9 |
+
file("${headerPath}/org_apache_tvm_LibInfo.h").renameTo(file("${headerPath}/org_apache_tvm_native_c_api.h"))
|
10 |
+
}
|
11 |
+
}
|
12 |
+
|
13 |
+
task copyFiles(type: Copy, description: 'Copy Sources for ndk-build') {
|
14 |
+
dependsOn "generateJniHeaders"
|
15 |
+
def ndkFilesPath = "${project.projectDir}/../../build/tvm_home/jvm/native/src/main/native"
|
16 |
+
def srcPath = "${project.projectDir}/src/main/jni/"
|
17 |
+
|
18 |
+
from "${ndkFilesPath}/org_apache_tvm_native_c_api.cc", "${ndkFilesPath}/jni_helper_func.h"
|
19 |
+
into srcPath
|
20 |
+
}
|
21 |
+
|
22 |
+
task deleteLibs(type: Delete, description: "Delete Compiled Libraries") {
|
23 |
+
dependsOn "copyFiles"
|
24 |
+
def libsPath = "${project.projectDir}/src/main/libs"
|
25 |
+
delete libsPath
|
26 |
+
}
|
27 |
+
|
28 |
+
task buildJni(type: Exec, description: 'Build JNI libs') {
|
29 |
+
dependsOn "deleteLibs"
|
30 |
+
def buildPath = "${project.projectDir}/src/main/jni"
|
31 |
+
commandLine "ndk-build", "--directory", buildPath
|
32 |
+
}
|
33 |
+
|
34 |
+
tasks.withType(JavaCompile) {
|
35 |
+
compileTask -> compileTask.dependsOn buildJni
|
36 |
+
}
|
37 |
+
|
38 |
+
android {
|
39 |
+
compileSdkVersion 33
|
40 |
+
defaultConfig {
|
41 |
+
applicationId "ai.mlc.mlcchat"
|
42 |
+
minSdkVersion 26
|
43 |
+
targetSdkVersion 33
|
44 |
+
versionCode 1
|
45 |
+
versionName "1.0"
|
46 |
+
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
47 |
+
ndk {
|
48 |
+
abiFilters 'arm64-v8a'
|
49 |
+
}
|
50 |
+
}
|
51 |
+
buildTypes {
|
52 |
+
release {
|
53 |
+
minifyEnabled false
|
54 |
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
55 |
+
}
|
56 |
+
}
|
57 |
+
sourceSets {
|
58 |
+
main {
|
59 |
+
jni.srcDirs = []
|
60 |
+
jniLibs.srcDirs = ['src/main/libs']
|
61 |
+
}
|
62 |
+
}
|
63 |
+
namespace 'ai.mlc.mlcchat'
|
64 |
+
ndkVersion '25.2.9519653'
|
65 |
+
}
|
66 |
+
|
67 |
+
dependencies {
|
68 |
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
69 |
+
implementation 'com.google.android.material:material:1.9.0'
|
70 |
+
implementation files("${project.projectDir}/../../build/tvm_home/jvm/core/target/tvm4j-core-0.0.1-SNAPSHOT.jar")
|
71 |
+
}
|
mlc-llm-main/android/MLCChat/app/proguard-rules.pro
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Add project specific ProGuard rules here.
|
2 |
+
# You can control the set of applied configuration files using the
|
3 |
+
# proguardFiles setting in build.gradle.
|
4 |
+
#
|
5 |
+
# For more details, see
|
6 |
+
# http://developer.android.com/guide/developing/tools/proguard.html
|
7 |
+
|
8 |
+
# If your project uses WebView with JS, uncomment the following
|
9 |
+
# and specify the fully qualified class name to the JavaScript interface
|
10 |
+
# class:
|
11 |
+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
12 |
+
# public *;
|
13 |
+
#}
|
14 |
+
|
15 |
+
# Uncomment this to preserve the line number information for
|
16 |
+
# debugging stack traces.
|
17 |
+
#-keepattributes SourceFile,LineNumberTable
|
18 |
+
|
19 |
+
# If you keep the line number information, uncomment this to
|
20 |
+
# hide the original source file name.
|
21 |
+
#-renamesourcefileattribute SourceFile
|
mlc-llm-main/android/MLCChat/app/src/main/AndroidManifest.xml
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
3 |
+
xmlns:tools="http://schemas.android.com/tools">
|
4 |
+
|
5 |
+
<uses-permission android:name="android.permission.INTERNET" />
|
6 |
+
<uses-permission
|
7 |
+
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
8 |
+
android:maxSdkVersion="32"
|
9 |
+
tools:ignore="ScopedStorage" />
|
10 |
+
|
11 |
+
<application
|
12 |
+
android:allowBackup="true"
|
13 |
+
android:dataExtractionRules="@xml/data_extraction_rules"
|
14 |
+
android:fullBackupContent="@xml/backup_rules"
|
15 |
+
android:icon="@mipmap/ic_launcher"
|
16 |
+
android:label="@string/app_name"
|
17 |
+
android:roundIcon="@mipmap/ic_launcher_round"
|
18 |
+
android:supportsRtl="true"
|
19 |
+
android:theme="@style/Theme.MLCChat"
|
20 |
+
tools:targetApi="31">
|
21 |
+
<uses-native-library
|
22 |
+
android:name="libOpenCL.so"
|
23 |
+
android:required="false"/>
|
24 |
+
<activity
|
25 |
+
android:name=".MainActivity"
|
26 |
+
android:screenOrientation="portrait"
|
27 |
+
android:exported="true">
|
28 |
+
<intent-filter>
|
29 |
+
<action android:name="android.intent.action.MAIN" />
|
30 |
+
|
31 |
+
<category android:name="android.intent.category.LAUNCHER" />
|
32 |
+
</intent-filter>
|
33 |
+
</activity>
|
34 |
+
</application>
|
35 |
+
|
36 |
+
</manifest>
|
mlc-llm-main/android/MLCChat/app/src/main/ic_launcher-playstore.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/ChatState.java
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import java.util.concurrent.ExecutorService;
|
4 |
+
import java.util.concurrent.Executors;
|
5 |
+
|
6 |
+
import android.content.Context;
|
7 |
+
import android.os.Handler;
|
8 |
+
|
9 |
+
public class ChatState {
|
10 |
+
private boolean resetRequested;
|
11 |
+
private boolean stopRequested;
|
12 |
+
private final ExecutorService executorService;
|
13 |
+
private final Handler handler;
|
14 |
+
|
15 |
+
private final LLMChat backend;
|
16 |
+
|
17 |
+
public ChatState(Handler h, Context c) {
|
18 |
+
resetRequested = false;
|
19 |
+
stopRequested = false;
|
20 |
+
executorService = Executors.newSingleThreadExecutor();
|
21 |
+
handler = h;
|
22 |
+
backend = new LLMChat(c);
|
23 |
+
executorService.execute(() -> {
|
24 |
+
backend.Init();
|
25 |
+
Utils.sendInitDone(h);
|
26 |
+
});
|
27 |
+
}
|
28 |
+
|
29 |
+
public void stop() {
|
30 |
+
if (isStopRequested()) return;
|
31 |
+
requestStop();
|
32 |
+
executorService.execute(this::finishStop);
|
33 |
+
}
|
34 |
+
|
35 |
+
public void reset() {
|
36 |
+
stop();
|
37 |
+
if (isResetRequested()) return;
|
38 |
+
requestReset();
|
39 |
+
executorService.execute(() -> {
|
40 |
+
backend.ResetChat();
|
41 |
+
finishReset();
|
42 |
+
Utils.sendReset(handler);
|
43 |
+
});
|
44 |
+
}
|
45 |
+
|
46 |
+
public synchronized void requestReset() {
|
47 |
+
assert !resetRequested;
|
48 |
+
resetRequested = true;
|
49 |
+
}
|
50 |
+
|
51 |
+
public synchronized void finishReset() {
|
52 |
+
assert resetRequested;
|
53 |
+
resetRequested = false;
|
54 |
+
}
|
55 |
+
|
56 |
+
public synchronized boolean isResetRequested() {
|
57 |
+
return resetRequested;
|
58 |
+
}
|
59 |
+
|
60 |
+
public synchronized void requestStop() {
|
61 |
+
assert !stopRequested;
|
62 |
+
stopRequested = true;
|
63 |
+
}
|
64 |
+
|
65 |
+
public synchronized void finishStop() {
|
66 |
+
assert stopRequested;
|
67 |
+
stopRequested = false;
|
68 |
+
}
|
69 |
+
|
70 |
+
public synchronized boolean isStopRequested() {
|
71 |
+
return stopRequested;
|
72 |
+
}
|
73 |
+
|
74 |
+
void generate(String text) {
|
75 |
+
assert !isStopRequested() && !isResetRequested();
|
76 |
+
executorService.execute(() -> Generate(text, handler));
|
77 |
+
}
|
78 |
+
|
79 |
+
|
80 |
+
void Dummy(String text, Handler handler) {
|
81 |
+
String result = "";
|
82 |
+
for (int i = 0; i < 8; ++i) {
|
83 |
+
try {
|
84 |
+
Thread.sleep(1000);
|
85 |
+
if (isStopRequested()) {
|
86 |
+
break;
|
87 |
+
}
|
88 |
+
result = result + " aba";
|
89 |
+
Utils.sendUpdateMessage(result, handler);
|
90 |
+
} catch (InterruptedException e) {
|
91 |
+
e.printStackTrace();
|
92 |
+
}
|
93 |
+
}
|
94 |
+
Utils.sendEnd("encode: 100.0 tok/s, decode: 100.0 tok/s", handler);
|
95 |
+
}
|
96 |
+
|
97 |
+
void Generate(String prompt, Handler handler) {
|
98 |
+
// System.err.println("Start generating");
|
99 |
+
backend.Encode(prompt);
|
100 |
+
// System.err.println("Encoding " + prompt);
|
101 |
+
while (!backend.Stopped()) {
|
102 |
+
backend.Decode();
|
103 |
+
// System.err.println("[INFO] " + backend.GetMessage());
|
104 |
+
Utils.sendUpdateMessage(backend.GetMessage(), handler);
|
105 |
+
if (isStopRequested()) {
|
106 |
+
break;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
String stats = backend.RuntimeStatsText();
|
110 |
+
Utils.sendEnd(stats, handler);
|
111 |
+
}
|
112 |
+
|
113 |
+
public void terminate() {
|
114 |
+
Utils.terminate(executorService);
|
115 |
+
}
|
116 |
+
|
117 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Config.java
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
public class Config {
|
4 |
+
public static final int UPD_MSG = 0;
|
5 |
+
public static final int APP_MSG = 1;
|
6 |
+
public static final int END = 2;
|
7 |
+
public static final int RESET = 3;
|
8 |
+
public static final int PARAMS_DONE = 4;
|
9 |
+
public static final int INIT_DONE = 5;
|
10 |
+
public static final String MSG_KEY = "message";
|
11 |
+
public static final String STATS_KEY = "stats";
|
12 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Downloader.java
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import android.content.Context;
|
4 |
+
import android.os.Environment;
|
5 |
+
import android.os.Handler;
|
6 |
+
|
7 |
+
import java.io.DataInputStream;
|
8 |
+
import java.io.File;
|
9 |
+
import java.io.FileNotFoundException;
|
10 |
+
import java.io.FileOutputStream;
|
11 |
+
import java.io.IOException;
|
12 |
+
import java.io.InputStream;
|
13 |
+
import java.net.MalformedURLException;
|
14 |
+
import java.net.URL;
|
15 |
+
import java.nio.file.Files;
|
16 |
+
import java.nio.file.StandardCopyOption;
|
17 |
+
import java.util.HashMap;
|
18 |
+
import java.util.Map;
|
19 |
+
import java.util.concurrent.ExecutorService;
|
20 |
+
import java.util.concurrent.Executors;
|
21 |
+
|
22 |
+
public class Downloader {
|
23 |
+
private ExecutorService executorService;
|
24 |
+
private Handler handler;
|
25 |
+
private boolean isDownloading;
|
26 |
+
|
27 |
+
private Context context;
|
28 |
+
|
29 |
+
private HashMap<String, String> files;
|
30 |
+
|
31 |
+
public Downloader(Handler h, Context c) {
|
32 |
+
handler = h;
|
33 |
+
context = c;
|
34 |
+
executorService = Executors.newSingleThreadExecutor();
|
35 |
+
isDownloading = false;
|
36 |
+
files = new HashMap<>();
|
37 |
+
}
|
38 |
+
|
39 |
+
public synchronized void startDownload() {
|
40 |
+
assert !isDownloading;
|
41 |
+
isDownloading = true;
|
42 |
+
}
|
43 |
+
|
44 |
+
public synchronized void endDownload() {
|
45 |
+
assert isDownloading;
|
46 |
+
isDownloading = false;
|
47 |
+
}
|
48 |
+
|
49 |
+
public synchronized boolean inDownload() {
|
50 |
+
return isDownloading;
|
51 |
+
}
|
52 |
+
|
53 |
+
public void addFile(String url, String path) {
|
54 |
+
assert !inDownload();
|
55 |
+
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), path);
|
56 |
+
if (!file.exists()) {
|
57 |
+
files.put(url, path);
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
public static String reportProgress(int done, int all) {
|
62 |
+
return String.format("[System] downloading [%d / %d]", done, all);
|
63 |
+
}
|
64 |
+
|
65 |
+
public void download() {
|
66 |
+
startDownload();
|
67 |
+
executorService.execute(() -> {
|
68 |
+
HashMap<String, String> filesToDownload = new HashMap<>(files);
|
69 |
+
files.clear();
|
70 |
+
int n = filesToDownload.size();
|
71 |
+
int i = 0;
|
72 |
+
if (n > 0) {
|
73 |
+
Utils.sendAppendMessage(reportProgress(i, n), handler);
|
74 |
+
}
|
75 |
+
for (Map.Entry<String, String> entry : filesToDownload.entrySet()) {
|
76 |
+
try {
|
77 |
+
File temp = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "temp");
|
78 |
+
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), entry.getValue());
|
79 |
+
if (!file.exists()) {
|
80 |
+
URL url = new URL(entry.getKey());
|
81 |
+
InputStream inputStream = url.openStream();
|
82 |
+
DataInputStream dataInputStream =
|
83 |
+
new DataInputStream(inputStream);
|
84 |
+
byte[] buffer = new byte[1024];
|
85 |
+
int length;
|
86 |
+
|
87 |
+
FileOutputStream fileOutputStream = new FileOutputStream(temp);
|
88 |
+
while ((length = dataInputStream.read(buffer)) > 0) {
|
89 |
+
fileOutputStream.write(buffer, 0, length);
|
90 |
+
}
|
91 |
+
|
92 |
+
Files.createDirectories(file.toPath().getParent());
|
93 |
+
Files.move(temp.toPath(), file.toPath(), StandardCopyOption.ATOMIC_MOVE);
|
94 |
+
}
|
95 |
+
++i;
|
96 |
+
Utils.sendUpdateMessage(reportProgress(i, n), handler);
|
97 |
+
} catch (IOException e) {
|
98 |
+
throw new RuntimeException(e);
|
99 |
+
}
|
100 |
+
}
|
101 |
+
endDownload();
|
102 |
+
Utils.sendParamsDone(handler);
|
103 |
+
});
|
104 |
+
}
|
105 |
+
|
106 |
+
public void terminate() {
|
107 |
+
Utils.terminate(executorService);
|
108 |
+
}
|
109 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/LLMChat.java
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import android.content.Context;
|
4 |
+
import android.os.Environment;
|
5 |
+
|
6 |
+
import org.apache.tvm.Device;
|
7 |
+
import org.apache.tvm.Function;
|
8 |
+
import org.apache.tvm.Module;
|
9 |
+
|
10 |
+
public class LLMChat {
|
11 |
+
private Function encode_func_;
|
12 |
+
private Function decode_func_;
|
13 |
+
private Function get_message_;
|
14 |
+
private Function stopped_func_;
|
15 |
+
private Function reset_chat_func_;
|
16 |
+
private Function runtime_stats_text_func_;
|
17 |
+
private Module llm_chat_;
|
18 |
+
private final Context context;
|
19 |
+
|
20 |
+
public LLMChat(Context c) {
|
21 |
+
this.context = c;
|
22 |
+
}
|
23 |
+
|
24 |
+
public void Init() {
|
25 |
+
Function systemlib_func = Function.getFunction("runtime.SystemLib");
|
26 |
+
assert systemlib_func != null;
|
27 |
+
Module lib = systemlib_func.invoke().asModule();
|
28 |
+
assert lib != null;
|
29 |
+
Function fcreate = Function.getFunction("mlc.llm_chat_create");
|
30 |
+
assert fcreate != null;
|
31 |
+
String dist_path = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
|
32 |
+
String tokenizer_path = dist_path + "/vicuna-v1-7b/tokenizer.model";
|
33 |
+
String param_path = dist_path + "/vicuna-v1-7b/params";
|
34 |
+
System.err.println("[INFO] " + tokenizer_path);
|
35 |
+
System.err.println("[INFO] " + param_path);
|
36 |
+
System.err.println("[INFO] Before LLM Chat create");
|
37 |
+
llm_chat_ = fcreate.pushArg(lib).pushArg(tokenizer_path).pushArg(param_path).pushArg(Device.opencl().deviceType).pushArg(0).invoke().asModule();
|
38 |
+
System.err.println("[INFO] LLM Chat created!");
|
39 |
+
encode_func_ = llm_chat_.getFunction("encode");
|
40 |
+
decode_func_ = llm_chat_.getFunction("decode");
|
41 |
+
get_message_ = llm_chat_.getFunction("get_message");
|
42 |
+
|
43 |
+
stopped_func_ = llm_chat_.getFunction("stopped");
|
44 |
+
reset_chat_func_ = llm_chat_.getFunction("reset_chat");
|
45 |
+
|
46 |
+
runtime_stats_text_func_ = llm_chat_.getFunction("runtime_stats_text");
|
47 |
+
|
48 |
+
assert encode_func_ != null;
|
49 |
+
assert decode_func_ != null;
|
50 |
+
assert stopped_func_ != null;
|
51 |
+
assert runtime_stats_text_func_ != null;
|
52 |
+
|
53 |
+
String model = "vicuna";
|
54 |
+
String conv_template = "vicuna_v1.1";
|
55 |
+
int max_gen_len = 512 + 256;
|
56 |
+
double temperature = 0.7;
|
57 |
+
double top_p = 0.95;
|
58 |
+
int stream_interval = 1;
|
59 |
+
int max_window_size = 512 + 256;
|
60 |
+
int mean_gen_len = 128;
|
61 |
+
double shift_fill_factor = 0.2;
|
62 |
+
llm_chat_.getFunction("init_chat").pushArg(model).pushArg(conv_template).pushArg(max_gen_len).pushArg(temperature).pushArg(top_p).pushArg(stream_interval).pushArg(max_window_size).pushArg(mean_gen_len).pushArg(shift_fill_factor).invoke();
|
63 |
+
|
64 |
+
systemlib_func.release();
|
65 |
+
lib.release();
|
66 |
+
fcreate.release();
|
67 |
+
|
68 |
+
System.err.println("[INFO] Init done");
|
69 |
+
}
|
70 |
+
public void Evaluate() {
|
71 |
+
llm_chat_.getFunction("evaluate").invoke();
|
72 |
+
}
|
73 |
+
|
74 |
+
public String GetMessage() {
|
75 |
+
return get_message_.invoke().asString();
|
76 |
+
}
|
77 |
+
|
78 |
+
public void Encode(String prompt) {
|
79 |
+
encode_func_.pushArg(prompt).invoke();
|
80 |
+
}
|
81 |
+
|
82 |
+
public boolean Stopped() {
|
83 |
+
return stopped_func_.invoke().asLong() != 0;
|
84 |
+
}
|
85 |
+
|
86 |
+
public void Decode() {
|
87 |
+
decode_func_.invoke();
|
88 |
+
}
|
89 |
+
|
90 |
+
public String RuntimeStatsText() {
|
91 |
+
return runtime_stats_text_func_.invoke().asString();
|
92 |
+
}
|
93 |
+
|
94 |
+
public void ResetChat() {
|
95 |
+
reset_chat_func_.invoke();
|
96 |
+
}
|
97 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MainActivity.java
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import android.app.DownloadManager;
|
4 |
+
import android.content.BroadcastReceiver;
|
5 |
+
import android.content.Context;
|
6 |
+
import android.content.Intent;
|
7 |
+
import android.content.IntentFilter;
|
8 |
+
import android.net.Uri;
|
9 |
+
import android.os.Bundle;
|
10 |
+
import android.os.Environment;
|
11 |
+
import android.os.Handler;
|
12 |
+
import android.os.Looper;
|
13 |
+
import android.os.Message;
|
14 |
+
import android.widget.Button;
|
15 |
+
import android.widget.EditText;
|
16 |
+
import android.widget.ListView;
|
17 |
+
import android.widget.TextView;
|
18 |
+
|
19 |
+
import androidx.annotation.NonNull;
|
20 |
+
import androidx.appcompat.app.AppCompatActivity;
|
21 |
+
|
22 |
+
import java.io.File;
|
23 |
+
import java.nio.file.Files;
|
24 |
+
import java.nio.file.Path;
|
25 |
+
import java.nio.file.Paths;
|
26 |
+
import java.util.concurrent.ConcurrentHashMap;
|
27 |
+
|
28 |
+
public class MainActivity extends AppCompatActivity {
|
29 |
+
private MessageAdapter messageAdapter;
|
30 |
+
private Button sendButton;
|
31 |
+
private Button resetButton;
|
32 |
+
private EditText editText;
|
33 |
+
private ListView listView;
|
34 |
+
private TextView speedText;
|
35 |
+
private Handler handler;
|
36 |
+
private ChatState chatState;
|
37 |
+
private Context context;
|
38 |
+
|
39 |
+
private Downloader downloader;
|
40 |
+
|
41 |
+
@Override
|
42 |
+
protected void onCreate(Bundle savedInstanceState) {
|
43 |
+
super.onCreate(savedInstanceState);
|
44 |
+
setContentView(R.layout.activity_main);
|
45 |
+
sendButton = findViewById(R.id.send);
|
46 |
+
resetButton = findViewById(R.id.reset);
|
47 |
+
editText = findViewById(R.id.input);
|
48 |
+
listView = findViewById(R.id.messages);
|
49 |
+
speedText = findViewById(R.id.speed);
|
50 |
+
|
51 |
+
context = getApplicationContext();
|
52 |
+
|
53 |
+
messageAdapter = new MessageAdapter(this);
|
54 |
+
listView.setAdapter(messageAdapter);
|
55 |
+
handler = new Handler(Looper.getMainLooper()) {
|
56 |
+
@Override
|
57 |
+
public void handleMessage(@NonNull Message msg) {
|
58 |
+
super.handleMessage(msg);
|
59 |
+
Bundle bundle = msg.getData();
|
60 |
+
switch (msg.what) {
|
61 |
+
case Config.INIT_DONE:
|
62 |
+
assert messageAdapter.isBotLast();
|
63 |
+
updateMessage(new MessageData(MessageRole.BOT, "[System] Ready to chat"));
|
64 |
+
resumeSend();
|
65 |
+
resumeReset();
|
66 |
+
break;
|
67 |
+
case Config.UPD_MSG:
|
68 |
+
assert messageAdapter.isBotLast();
|
69 |
+
updateMessage(new MessageData(MessageRole.BOT, bundle.getString(Config.MSG_KEY)));
|
70 |
+
break;
|
71 |
+
case Config.APP_MSG:
|
72 |
+
appendMessage(new MessageData(MessageRole.BOT, bundle.getString(Config.MSG_KEY)));
|
73 |
+
break;
|
74 |
+
case Config.END:
|
75 |
+
speedText.setText(bundle.getString(Config.STATS_KEY));
|
76 |
+
resumeSend();
|
77 |
+
break;
|
78 |
+
case Config.PARAMS_DONE:
|
79 |
+
init();
|
80 |
+
break;
|
81 |
+
case Config.RESET:
|
82 |
+
reset();
|
83 |
+
break;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
};
|
87 |
+
// System starting: freeze send and reset
|
88 |
+
freezeSend();
|
89 |
+
freezeReset();
|
90 |
+
// Prepare tokenizer and model params
|
91 |
+
downloader = new Downloader(handler, context);
|
92 |
+
prepareParams();
|
93 |
+
}
|
94 |
+
|
95 |
+
private void init() {
|
96 |
+
// Follow up after param is confirmed
|
97 |
+
// Chat state will initialize in another thread
|
98 |
+
appendMessage(new MessageData(MessageRole.BOT, "[System] Initializing..."));
|
99 |
+
chatState = new ChatState(handler, context);
|
100 |
+
|
101 |
+
sendButton.setOnClickListener(v -> {
|
102 |
+
String message = freezeSend();
|
103 |
+
appendMessage(new MessageData(MessageRole.USER, message));
|
104 |
+
appendMessage(new MessageData(MessageRole.BOT, ""));
|
105 |
+
chatState.generate(message);
|
106 |
+
});
|
107 |
+
resetButton.setOnClickListener(v -> {
|
108 |
+
freezeSend();
|
109 |
+
freezeReset();
|
110 |
+
chatState.reset();
|
111 |
+
});
|
112 |
+
}
|
113 |
+
|
114 |
+
private void prepareParams() {
|
115 |
+
appendMessage(new MessageData(MessageRole.BOT, "[System] Preparing Parameters..."));
|
116 |
+
String model_name = "vicuna-v1-7b";
|
117 |
+
String base_url = "https://huggingface.co/mlc-ai/demo-vicuna-v1-7b-int4/resolve/main";
|
118 |
+
downloader.addFile(base_url + "/tokenizer.model", model_name + "/tokenizer.model");
|
119 |
+
downloader.addFile(base_url + "/float16/ndarray-cache.json", model_name + "/params/ndarray-cache.json");
|
120 |
+
for (int i = 0; i <= 131; ++i) {
|
121 |
+
String param_name = "params_shard_" + i + ".bin";
|
122 |
+
downloader.addFile(base_url + "/float16/" + param_name, model_name + "/params/" + param_name);
|
123 |
+
}
|
124 |
+
downloader.download();
|
125 |
+
}
|
126 |
+
|
127 |
+
|
128 |
+
private String freezeSend() {
|
129 |
+
String text = editText.getText().toString();
|
130 |
+
editText.getText().clear();
|
131 |
+
editText.setEnabled(false);
|
132 |
+
sendButton.setEnabled(false);
|
133 |
+
sendButton.setAlpha((float) 0.1);
|
134 |
+
return text;
|
135 |
+
}
|
136 |
+
|
137 |
+
private void resumeSend() {
|
138 |
+
sendButton.setEnabled(true);
|
139 |
+
sendButton.setAlpha((float) 1.0);
|
140 |
+
editText.setEnabled(true);
|
141 |
+
}
|
142 |
+
|
143 |
+
private void freezeReset() {
|
144 |
+
resetButton.setEnabled(false);
|
145 |
+
}
|
146 |
+
|
147 |
+
private void resumeReset() {
|
148 |
+
resetButton.setEnabled(true);
|
149 |
+
}
|
150 |
+
|
151 |
+
@Override
|
152 |
+
protected void onRestart() {
|
153 |
+
super.onRestart();
|
154 |
+
}
|
155 |
+
|
156 |
+
@Override
|
157 |
+
protected void onDestroy() {
|
158 |
+
super.onDestroy();
|
159 |
+
chatState.terminate();
|
160 |
+
downloader.terminate();
|
161 |
+
}
|
162 |
+
|
163 |
+
private void appendMessage(MessageData messageData) {
|
164 |
+
messageAdapter.appendMessage(messageData);
|
165 |
+
}
|
166 |
+
|
167 |
+
private void updateMessage(MessageData messageData) {
|
168 |
+
messageAdapter.updateMessage(messageData);
|
169 |
+
}
|
170 |
+
|
171 |
+
private void reset() {
|
172 |
+
resumeSend();
|
173 |
+
editText.getText().clear();
|
174 |
+
messageAdapter.reset();
|
175 |
+
resumeReset();
|
176 |
+
}
|
177 |
+
|
178 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MessageAdapter.java
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import android.content.Context;
|
4 |
+
import android.view.LayoutInflater;
|
5 |
+
import android.view.View;
|
6 |
+
import android.view.ViewGroup;
|
7 |
+
import android.widget.BaseAdapter;
|
8 |
+
import android.widget.TextView;
|
9 |
+
|
10 |
+
import java.util.ArrayList;
|
11 |
+
import java.util.List;
|
12 |
+
|
13 |
+
public class MessageAdapter extends BaseAdapter {
|
14 |
+
private List<MessageData> messages;
|
15 |
+
private Context context;
|
16 |
+
|
17 |
+
public MessageAdapter(Context c) {
|
18 |
+
super();
|
19 |
+
context = c;
|
20 |
+
messages = new ArrayList<MessageData>();
|
21 |
+
}
|
22 |
+
|
23 |
+
public void appendMessage(MessageData m) {
|
24 |
+
messages.add(m);
|
25 |
+
notifyDataSetChanged();
|
26 |
+
}
|
27 |
+
|
28 |
+
public void updateMessage(MessageData m) {
|
29 |
+
messages.set(messages.size() - 1, m);
|
30 |
+
notifyDataSetChanged();
|
31 |
+
}
|
32 |
+
|
33 |
+
public boolean isBotLast() {
|
34 |
+
return messages.get(messages.size() - 1).isBot();
|
35 |
+
}
|
36 |
+
|
37 |
+
public int size() {
|
38 |
+
return messages.size();
|
39 |
+
}
|
40 |
+
|
41 |
+
public void reset() {
|
42 |
+
messages.clear();
|
43 |
+
notifyDataSetChanged();
|
44 |
+
}
|
45 |
+
|
46 |
+
@Override
|
47 |
+
public int getCount() {
|
48 |
+
return messages.size();
|
49 |
+
}
|
50 |
+
|
51 |
+
@Override
|
52 |
+
public Object getItem(int position) {
|
53 |
+
return messages.get(position);
|
54 |
+
}
|
55 |
+
|
56 |
+
@Override
|
57 |
+
public long getItemId(int position) {
|
58 |
+
return position;
|
59 |
+
}
|
60 |
+
|
61 |
+
@Override
|
62 |
+
public View getView(int position, View convertView, ViewGroup parent) {
|
63 |
+
MessageViewHolder holder = new MessageViewHolder();
|
64 |
+
LayoutInflater inflater = LayoutInflater.from(context);
|
65 |
+
MessageData chatMessage = messages.get(position);
|
66 |
+
if (chatMessage.isBot()) {
|
67 |
+
convertView = inflater.inflate(R.layout.bot_message, null);
|
68 |
+
holder.textView = convertView.findViewById(R.id.bot_message);
|
69 |
+
holder.textView.setText(chatMessage.getText());
|
70 |
+
convertView.setTag(holder);
|
71 |
+
} else {
|
72 |
+
convertView = inflater.inflate(R.layout.user_message, null);
|
73 |
+
holder.textView = convertView.findViewById(R.id.user_message);
|
74 |
+
holder.textView.setText(chatMessage.getText());
|
75 |
+
convertView.setTag(holder);
|
76 |
+
}
|
77 |
+
return convertView;
|
78 |
+
}
|
79 |
+
|
80 |
+
static class MessageViewHolder {
|
81 |
+
public TextView textView;
|
82 |
+
}
|
83 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/MessageData.java
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import androidx.annotation.NonNull;
|
4 |
+
|
5 |
+
enum MessageRole {
|
6 |
+
BOT, USER
|
7 |
+
}
|
8 |
+
|
9 |
+
public class MessageData {
|
10 |
+
|
11 |
+
private final MessageRole messageRole;
|
12 |
+
private final String text;
|
13 |
+
|
14 |
+
public MessageData(MessageRole r, String t) {
|
15 |
+
messageRole = r;
|
16 |
+
text = t;
|
17 |
+
}
|
18 |
+
|
19 |
+
public boolean isBot() {
|
20 |
+
return messageRole == MessageRole.BOT;
|
21 |
+
}
|
22 |
+
|
23 |
+
public String getText() {
|
24 |
+
return text;
|
25 |
+
}
|
26 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/java/ai/mlc/mlcchat/Utils.java
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
package ai.mlc.mlcchat;
|
2 |
+
|
3 |
+
import android.os.Bundle;
|
4 |
+
import android.os.Handler;
|
5 |
+
import android.os.Message;
|
6 |
+
|
7 |
+
import java.util.concurrent.ExecutorService;
|
8 |
+
import java.util.concurrent.TimeUnit;
|
9 |
+
|
10 |
+
public class Utils {
|
11 |
+
public static void sendUpdateMessage(String text, Handler handler) {
|
12 |
+
Bundle bundle = new Bundle();
|
13 |
+
bundle.putString(Config.MSG_KEY, text);
|
14 |
+
Message message = new Message();
|
15 |
+
message.setData(bundle);
|
16 |
+
message.what = Config.UPD_MSG;
|
17 |
+
handler.sendMessage(message);
|
18 |
+
}
|
19 |
+
|
20 |
+
public static void sendAppendMessage(String text, Handler handler) {
|
21 |
+
Bundle bundle = new Bundle();
|
22 |
+
bundle.putString(Config.MSG_KEY, text);
|
23 |
+
Message message = new Message();
|
24 |
+
message.setData(bundle);
|
25 |
+
message.what = Config.APP_MSG;
|
26 |
+
handler.sendMessage(message);
|
27 |
+
}
|
28 |
+
|
29 |
+
public static void sendEnd(String stats, Handler handler) {
|
30 |
+
Bundle bundle = new Bundle();
|
31 |
+
bundle.putString(Config.STATS_KEY, stats);
|
32 |
+
Message message = new Message();
|
33 |
+
message.setData(bundle);
|
34 |
+
message.what = Config.END;
|
35 |
+
handler.sendMessage(message);
|
36 |
+
}
|
37 |
+
|
38 |
+
public static void sendReset(Handler handler) {
|
39 |
+
Message message = new Message();
|
40 |
+
message.what = Config.RESET;
|
41 |
+
handler.sendMessage(message);
|
42 |
+
}
|
43 |
+
|
44 |
+
public static void sendInitDone(Handler handler) {
|
45 |
+
Message message = new Message();
|
46 |
+
message.what = Config.INIT_DONE;
|
47 |
+
handler.sendMessage(message);
|
48 |
+
}
|
49 |
+
|
50 |
+
public static void sendParamsDone(Handler handler) {
|
51 |
+
Message message = new Message();
|
52 |
+
message.what = Config.PARAMS_DONE;
|
53 |
+
handler.sendMessage(message);
|
54 |
+
}
|
55 |
+
|
56 |
+
public static void terminate(ExecutorService executorService) {
|
57 |
+
executorService.shutdown(); // Disable new tasks from being submitted
|
58 |
+
try {
|
59 |
+
// Wait a while for existing tasks to terminate
|
60 |
+
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
|
61 |
+
executorService.shutdownNow(); // Cancel currently executing tasks
|
62 |
+
// Wait a while for tasks to respond to being cancelled
|
63 |
+
if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
|
64 |
+
System.err.println("Pool did not terminate");
|
65 |
+
}
|
66 |
+
} catch (InterruptedException ie) {
|
67 |
+
// (Re-)Cancel if current thread also interrupted
|
68 |
+
executorService.shutdownNow();
|
69 |
+
// Preserve interrupt status
|
70 |
+
Thread.currentThread().interrupt();
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
mlc-llm-main/android/MLCChat/app/src/main/jni/Android.mk
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2 |
+
# or more contributor license agreements. See the NOTICE file
|
3 |
+
# distributed with this work for additional information
|
4 |
+
# regarding copyright ownership. The ASF licenses this file
|
5 |
+
# to you under the Apache License, Version 2.0 (the
|
6 |
+
# "License"); you may not use this file except in compliance
|
7 |
+
# with the License. You may obtain a copy of the License at
|
8 |
+
#
|
9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10 |
+
#
|
11 |
+
# Unless required by applicable law or agreed to in writing,
|
12 |
+
# software distributed under the License is distributed on an
|
13 |
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14 |
+
# KIND, either express or implied. See the License for the
|
15 |
+
# specific language governing permissions and limitations
|
16 |
+
# under the License.
|
17 |
+
|
18 |
+
LOCAL_PATH := $(call my-dir)
|
19 |
+
MY_PATH := $(abspath $(LOCAL_PATH))
|
20 |
+
LIB_PATH := $(MY_PATH)/../../../../../build/lib
|
21 |
+
TVM_HOME := $(MY_PATH)/../../../../../build/tvm_home
|
22 |
+
|
23 |
+
#####################################################
|
24 |
+
|
25 |
+
include $(CLEAR_VARS)
|
26 |
+
LOCAL_MODULE := local_mlc_llm
|
27 |
+
LOCAL_SRC_FILES := $(LIB_PATH)/libmlc_llm.a
|
28 |
+
include $(PREBUILT_STATIC_LIBRARY)
|
29 |
+
|
30 |
+
#####################################################
|
31 |
+
|
32 |
+
include $(CLEAR_VARS)
|
33 |
+
LOCAL_MODULE := local_sentencepiece
|
34 |
+
LOCAL_SRC_FILES := $(LIB_PATH)/libsentencepiece.a
|
35 |
+
include $(PREBUILT_STATIC_LIBRARY)
|
36 |
+
|
37 |
+
#####################################################
|
38 |
+
|
39 |
+
include $(CLEAR_VARS)
|
40 |
+
LOCAL_MODULE := local_tokenizers_cpp
|
41 |
+
LOCAL_SRC_FILES := $(LIB_PATH)/libtokenizers_cpp.a
|
42 |
+
include $(PREBUILT_STATIC_LIBRARY)
|
43 |
+
|
44 |
+
#####################################################
|
45 |
+
|
46 |
+
include $(CLEAR_VARS)
|
47 |
+
LOCAL_MODULE := local_tvm_runtime
|
48 |
+
LOCAL_SRC_FILES := $(LIB_PATH)/libtvm_runtime.a
|
49 |
+
include $(PREBUILT_STATIC_LIBRARY)
|
50 |
+
|
51 |
+
#####################################################
|
52 |
+
|
53 |
+
include $(CLEAR_VARS)
|
54 |
+
LOCAL_MODULE := local_model_android
|
55 |
+
LOCAL_SRC_FILES := $(LIB_PATH)/libmodel_android.a
|
56 |
+
include $(PREBUILT_STATIC_LIBRARY)
|
57 |
+
|
58 |
+
#####################################################
|
59 |
+
|
60 |
+
include $(CLEAR_VARS)
|
61 |
+
LOCAL_MODULE = tvm4j_runtime_packed
|
62 |
+
LOCAL_SRC_FILES := org_apache_tvm_native_c_api.cc
|
63 |
+
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib/ -llog -pthread -ldl -lm
|
64 |
+
LOCAL_C_INCLUDES := $(TVM_HOME)/include \
|
65 |
+
$(TVM_HOME)/3rdparty/dlpack/include \
|
66 |
+
$(TVM_HOME)/3rdparty/dmlc-core/include \
|
67 |
+
$(MY_PATH)
|
68 |
+
# LOCAL_C_FLAGS := -static
|
69 |
+
|
70 |
+
LOCAL_WHOLE_STATIC_LIBRARIES := local_mlc_llm local_tvm_runtime local_model_android
|
71 |
+
LOCAL_STATIC_LIBRARIES := local_sentencepiece local_tokenizers_cpp
|
72 |
+
LOCAL_CPP_FEATURES += exceptions
|
73 |
+
LOCAL_ARM_MODE := arm
|
74 |
+
|
75 |
+
include $(BUILD_SHARED_LIBRARY)
|
mlc-llm-main/android/MLCChat/app/src/main/jni/Application.mk
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
APP_PLATFORM := android-24
|
2 |
+
APP_ABI := arm64-v8a
|
3 |
+
APP_STL := c++_static
|
4 |
+
|
5 |
+
APP_CPPFLAGS += -DTVM_LOG_STACK_TRACE=0 -DTVM4J_ANDROID=1 -std=c++17 -Oz -frtti
|
mlc-llm-main/android/MLCChat/app/src/main/jni/tvm_runtime.h
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#define DMLC_USE_LOGGING_LIBRARY <tvm/runtime/logging.h>
|
2 |
+
#define TVM_USE_LIBBACKTRACE 0
|
3 |
+
|
4 |
+
#include <dlfcn.h>
|
5 |
+
#include <dmlc/logging.h>
|
6 |
+
#include <dmlc/thread_local.h>
|
7 |
+
#include <tvm/runtime/c_runtime_api.h>
|
mlc-llm-main/android/MLCChat/app/src/main/res/drawable/bot_rounded_corner.xml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
3 |
+
<stroke
|
4 |
+
android:width="1dp"
|
5 |
+
android:color="@color/bot_background" />
|
6 |
+
|
7 |
+
<solid android:color="@color/bot_background" />
|
8 |
+
|
9 |
+
<padding
|
10 |
+
android:left="1dp"
|
11 |
+
android:right="1dp"
|
12 |
+
android:bottom="1dp"
|
13 |
+
android:top="1dp" />
|
14 |
+
|
15 |
+
<corners android:radius="10dp" />
|
16 |
+
</shape>
|
mlc-llm-main/android/MLCChat/app/src/main/res/drawable/user_rounded_corner.xml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
3 |
+
<stroke
|
4 |
+
android:width="1dp"
|
5 |
+
android:color="@color/material_dynamic_primary80" />
|
6 |
+
|
7 |
+
<solid android:color="@color/material_dynamic_primary80" />
|
8 |
+
|
9 |
+
<padding
|
10 |
+
android:left="1dp"
|
11 |
+
android:right="1dp"
|
12 |
+
android:bottom="1dp"
|
13 |
+
android:top="1dp" />
|
14 |
+
|
15 |
+
<corners android:radius="10dp" />
|
16 |
+
</shape>
|
mlc-llm-main/android/MLCChat/app/src/main/res/layout/activity_main.xml
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
3 |
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
4 |
+
xmlns:tools="http://schemas.android.com/tools"
|
5 |
+
android:layout_width="match_parent"
|
6 |
+
android:layout_height="match_parent"
|
7 |
+
tools:context=".MainActivity">
|
8 |
+
|
9 |
+
<com.google.android.material.appbar.MaterialToolbar
|
10 |
+
android:id="@+id/toolbar"
|
11 |
+
android:layout_width="match_parent"
|
12 |
+
android:layout_height="wrap_content"
|
13 |
+
android:background="?attr/colorPrimary"
|
14 |
+
android:minHeight="?attr/actionBarSize"
|
15 |
+
android:theme="?attr/actionBarTheme"
|
16 |
+
app:layout_constraintBottom_toTopOf="@+id/speed"
|
17 |
+
app:layout_constraintEnd_toEndOf="parent"
|
18 |
+
app:layout_constraintStart_toStartOf="parent"
|
19 |
+
app:layout_constraintTop_toTopOf="parent">
|
20 |
+
|
21 |
+
<androidx.appcompat.widget.AppCompatTextView
|
22 |
+
android:layout_width="wrap_content"
|
23 |
+
android:layout_height="match_parent"
|
24 |
+
android:text="MLC Chat"
|
25 |
+
android:textColor="@color/design_default_color_on_primary"
|
26 |
+
android:layout_gravity="center"
|
27 |
+
android:textAppearance="@style/TextAppearance.Material3.HeadlineMedium" />
|
28 |
+
|
29 |
+
<androidx.appcompat.widget.AppCompatButton
|
30 |
+
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
31 |
+
android:id="@+id/reset"
|
32 |
+
android:layout_width="wrap_content"
|
33 |
+
android:layout_height="match_parent"
|
34 |
+
android:text="reset"
|
35 |
+
android:textColor="@color/design_default_color_on_primary"
|
36 |
+
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
|
37 |
+
android:layout_marginEnd="5dp"
|
38 |
+
android:layout_gravity="end" />
|
39 |
+
|
40 |
+
</com.google.android.material.appbar.MaterialToolbar>
|
41 |
+
|
42 |
+
<androidx.appcompat.widget.AppCompatTextView
|
43 |
+
android:id="@+id/speed"
|
44 |
+
android:layout_width="match_parent"
|
45 |
+
android:layout_height="wrap_content"
|
46 |
+
android:textAlignment="center"
|
47 |
+
app:layout_constraintBottom_toTopOf="@id/messages"
|
48 |
+
app:layout_constraintEnd_toEndOf="parent"
|
49 |
+
app:layout_constraintStart_toStartOf="parent"
|
50 |
+
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
51 |
+
|
52 |
+
|
53 |
+
<androidx.appcompat.widget.AppCompatEditText
|
54 |
+
android:id="@+id/input"
|
55 |
+
android:layout_width="0dp"
|
56 |
+
android:layout_height="wrap_content"
|
57 |
+
android:layout_marginStart="5dp"
|
58 |
+
android:layout_marginEnd="5dp"
|
59 |
+
android:layout_marginBottom="5dp"
|
60 |
+
android:hint="Inputs..."
|
61 |
+
android:inputType="textMultiLine"
|
62 |
+
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
63 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
64 |
+
app:layout_constraintEnd_toStartOf="@+id/send"
|
65 |
+
app:layout_constraintStart_toStartOf="parent" />
|
66 |
+
|
67 |
+
<androidx.appcompat.widget.AppCompatButton
|
68 |
+
android:id="@+id/send"
|
69 |
+
android:layout_width="wrap_content"
|
70 |
+
android:layout_height="wrap_content"
|
71 |
+
android:layout_marginTop="5dp"
|
72 |
+
android:layout_marginBottom="5dp"
|
73 |
+
android:layout_marginStart="5dp"
|
74 |
+
android:layout_marginEnd="5dp"
|
75 |
+
android:text="Send"
|
76 |
+
android:textAppearance="@style/TextAppearance.Material3.SearchBar"
|
77 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
78 |
+
app:layout_constraintEnd_toEndOf="parent"
|
79 |
+
app:layout_constraintStart_toEndOf="@+id/input"
|
80 |
+
app:layout_constraintTop_toBottomOf="@+id/messages" />
|
81 |
+
|
82 |
+
<ListView
|
83 |
+
android:id="@+id/messages"
|
84 |
+
android:layout_width="match_parent"
|
85 |
+
android:layout_height="0dp"
|
86 |
+
android:divider="@null"
|
87 |
+
android:stackFromBottom="true"
|
88 |
+
android:transcriptMode="normal"
|
89 |
+
app:layout_constraintTop_toBottomOf="@id/speed"
|
90 |
+
app:layout_constraintBottom_toTopOf="@id/send" />
|
91 |
+
|
92 |
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
mlc-llm-main/android/MLCChat/app/src/main/res/layout/bot_message.xml
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
3 |
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
4 |
+
xmlns:tools="http://schemas.android.com/tools"
|
5 |
+
android:layout_width="match_parent"
|
6 |
+
android:layout_height="match_parent"
|
7 |
+
android:layout_marginEnd="50dp"
|
8 |
+
android:orientation="vertical">
|
9 |
+
|
10 |
+
<androidx.appcompat.widget.AppCompatTextView
|
11 |
+
android:id="@+id/bot_message"
|
12 |
+
android:layout_width="wrap_content"
|
13 |
+
android:layout_height="wrap_content"
|
14 |
+
android:layout_margin="5dp"
|
15 |
+
android:maxWidth="300dp"
|
16 |
+
android:background="@drawable/bot_rounded_corner"
|
17 |
+
android:gravity="start"
|
18 |
+
android:padding="10dp"
|
19 |
+
android:text="aaa"
|
20 |
+
android:textColor="#FFFFFF"
|
21 |
+
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
22 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
23 |
+
app:layout_constraintEnd_toEndOf="parent"
|
24 |
+
app:layout_constraintHorizontal_bias="0.0"
|
25 |
+
app:layout_constraintStart_toStartOf="parent"
|
26 |
+
app:layout_constraintTop_toTopOf="parent"
|
27 |
+
app:layout_constraintVertical_bias="0.0" />
|
28 |
+
|
29 |
+
|
30 |
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
mlc-llm-main/android/MLCChat/app/src/main/res/layout/user_message.xml
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
3 |
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
4 |
+
xmlns:tools="http://schemas.android.com/tools"
|
5 |
+
android:layout_width="match_parent"
|
6 |
+
android:layout_height="match_parent"
|
7 |
+
android:layout_marginStart="50dp"
|
8 |
+
android:orientation="vertical">
|
9 |
+
|
10 |
+
<androidx.appcompat.widget.AppCompatTextView
|
11 |
+
android:id="@+id/user_message"
|
12 |
+
android:layout_width="wrap_content"
|
13 |
+
android:layout_height="wrap_content"
|
14 |
+
android:layout_margin="5dp"
|
15 |
+
android:maxWidth="300dp"
|
16 |
+
android:gravity="start"
|
17 |
+
android:padding="10dp"
|
18 |
+
android:text="aaa"
|
19 |
+
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
20 |
+
android:background="@drawable/user_rounded_corner"
|
21 |
+
android:textColor="@color/design_default_color_on_primary"
|
22 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
23 |
+
app:layout_constraintEnd_toEndOf="parent"
|
24 |
+
app:layout_constraintHorizontal_bias="1.0"
|
25 |
+
app:layout_constraintStart_toStartOf="parent"
|
26 |
+
app:layout_constraintTop_toTopOf="parent"
|
27 |
+
app:layout_constraintVertical_bias="0.0" />
|
28 |
+
|
29 |
+
|
30 |
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
3 |
+
<background android:drawable="@color/ic_launcher_background"/>
|
4 |
+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
5 |
+
</adaptive-icon>
|
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
2 |
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
3 |
+
<background android:drawable="@color/ic_launcher_background"/>
|
4 |
+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
5 |
+
</adaptive-icon>
|
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
ADDED
![]() |
mlc-llm-main/android/MLCChat/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
ADDED
![]() |