llama.cpp
.devops
nix
apps.nix devshells.nix docker.nix jetson-support.nix nixpkgs-instances.nix package-gguf-py.nix package.nix python-scripts.nix scope.nix sif.nix.github
ISSUE_TEMPLATE
010-bug-compilation.yml 011-bug-results.yml 019-bug-misc.yml 020-enhancement.yml 030-research.yml 040-refactor.yml config.ymlworkflows
bench.yml.disabled build-cache.yml build-cmake-pkg.yml build-linux-cross.yml build.yml check-vendor.yml close-issue.yml copilot-setup-steps.yml docker.yml editorconfig.yml gguf-publish.yml labeler.yml pre-tokenizer-hashes.yml python-check-requirements.yml python-lint.yml python-type-check.yml release.yml server-metal.yml server-webui.yml server.yml update-ops-docs.yml winget.ymlbenches
cmake
arm64-apple-clang.cmake arm64-windows-llvm.cmake build-info.cmake common.cmake download-models.cmake git-vars.cmake license.cmake llama-config.cmake.in llama.pc.in riscv64-spacemit-linux-gnu-gcc.cmake x64-windows-llvm.cmakecommon
jinja
README.md caps.cpp caps.h lexer.cpp lexer.h parser.cpp parser.h runtime.cpp runtime.h string.cpp string.h utils.h value.cpp value.hdocs
multimodal
MobileVLM.md gemma3.md glmedge.md granitevision.md llava.md minicpmo2.6.md minicpmo4.0.md minicpmv2.5.md minicpmv2.6.md minicpmv4.0.md minicpmv4.5.mdops
BLAS.csv CANN.csv CPU.csv CUDA.csv Metal.csv OpenCL.csv SYCL.csv Vulkan.csv WebGPU.csv ZenDNN.csv zDNN.csvexamples
llama.android
app
src
lib
.gitignore build.gradle.kts consumer-rules.pro proguard-rules.promodel-conversion
scripts
causal
compare-embeddings-logits.sh compare-logits.py convert-model.sh modelcard.template run-casual-gen-embeddings-org.py run-converted-model-embeddings-logits.sh run-converted-model.sh run-org-model.pyembedding
compare-embeddings-logits.sh convert-model.sh modelcard.template run-converted-model.sh run-original-model.pyutils
__init__.py check-nmse.py common.py compare_tokens.py create-collection-add-model.sh curl-embedding-server.sh hf-add-model-to-collection.py hf-create-collection.py hf-create-model.py hf-upload-gguf-model.py inspect-converted-model.sh inspect-org-model.py perplexity-gen.sh perplexity-run-simple.sh perplexity-run.sh quantize.sh run-embedding-server.sh semantic_check.py tensor-info.pysycl
CMakeLists.txt README.md build.sh ls-sycl-device.cpp run-llama2.sh test.sh win-build-sycl.bat win-run-llama2.bat win-test.batggml
include
ggml-alloc.h ggml-backend.h ggml-blas.h ggml-cann.h ggml-cpp.h ggml-cpu.h ggml-cuda.h ggml-hexagon.h ggml-metal.h ggml-opencl.h ggml-opt.h ggml-rpc.h ggml-sycl.h ggml-virtgpu.h ggml-vulkan.h ggml-webgpu.h ggml-zdnn.h ggml-zendnn.h ggml.h gguf.hsrc
ggml-cann
CMakeLists.txt acl_tensor.cpp acl_tensor.h aclnn_ops.cpp aclnn_ops.h common.h ggml-cann.cppggml-cpu
CMakeLists.txt arch-fallback.h binary-ops.cpp binary-ops.h common.h ggml-cpu-impl.h ggml-cpu.c ggml-cpu.cpp hbm.cpp hbm.h ops.cpp ops.h quants.c quants.h repack.cpp repack.h simd-mappings.h traits.cpp traits.h unary-ops.cpp unary-ops.h vec.cpp vec.hggml-cuda
template-instances
fattn-mma-f16-instance-ncols1_1-ncols2_16.cu fattn-mma-f16-instance-ncols1_1-ncols2_32.cu fattn-mma-f16-instance-ncols1_1-ncols2_8.cu fattn-mma-f16-instance-ncols1_16-ncols2_1.cu fattn-mma-f16-instance-ncols1_16-ncols2_2.cu fattn-mma-f16-instance-ncols1_16-ncols2_4.cu fattn-mma-f16-instance-ncols1_2-ncols2_16.cu fattn-mma-f16-instance-ncols1_2-ncols2_32.cu fattn-mma-f16-instance-ncols1_2-ncols2_4.cu fattn-mma-f16-instance-ncols1_2-ncols2_8.cu fattn-mma-f16-instance-ncols1_32-ncols2_1.cu fattn-mma-f16-instance-ncols1_32-ncols2_2.cu fattn-mma-f16-instance-ncols1_4-ncols2_16.cu fattn-mma-f16-instance-ncols1_4-ncols2_2.cu fattn-mma-f16-instance-ncols1_4-ncols2_4.cu fattn-mma-f16-instance-ncols1_4-ncols2_8.cu fattn-mma-f16-instance-ncols1_64-ncols2_1.cu fattn-mma-f16-instance-ncols1_8-ncols2_1.cu fattn-mma-f16-instance-ncols1_8-ncols2_2.cu fattn-mma-f16-instance-ncols1_8-ncols2_4.cu fattn-mma-f16-instance-ncols1_8-ncols2_8.cu fattn-tile-instance-dkq112-dv112.cu fattn-tile-instance-dkq128-dv128.cu fattn-tile-instance-dkq256-dv256.cu fattn-tile-instance-dkq40-dv40.cu fattn-tile-instance-dkq576-dv512.cu fattn-tile-instance-dkq64-dv64.cu fattn-tile-instance-dkq72-dv72.cu fattn-tile-instance-dkq80-dv80.cu fattn-tile-instance-dkq96-dv96.cu fattn-vec-instance-f16-f16.cu fattn-vec-instance-f16-q4_0.cu fattn-vec-instance-f16-q4_1.cu fattn-vec-instance-f16-q5_0.cu fattn-vec-instance-f16-q5_1.cu fattn-vec-instance-f16-q8_0.cu fattn-vec-instance-q4_0-f16.cu fattn-vec-instance-q4_0-q4_0.cu fattn-vec-instance-q4_0-q4_1.cu fattn-vec-instance-q4_0-q5_0.cu fattn-vec-instance-q4_0-q5_1.cu fattn-vec-instance-q4_0-q8_0.cu fattn-vec-instance-q4_1-f16.cu fattn-vec-instance-q4_1-q4_0.cu fattn-vec-instance-q4_1-q4_1.cu fattn-vec-instance-q4_1-q5_0.cu fattn-vec-instance-q4_1-q5_1.cu fattn-vec-instance-q4_1-q8_0.cu fattn-vec-instance-q5_0-f16.cu fattn-vec-instance-q5_0-q4_0.cu fattn-vec-instance-q5_0-q4_1.cu fattn-vec-instance-q5_0-q5_0.cu fattn-vec-instance-q5_0-q5_1.cu fattn-vec-instance-q5_0-q8_0.cu fattn-vec-instance-q5_1-f16.cu fattn-vec-instance-q5_1-q4_0.cu fattn-vec-instance-q5_1-q4_1.cu fattn-vec-instance-q5_1-q5_0.cu fattn-vec-instance-q5_1-q5_1.cu fattn-vec-instance-q5_1-q8_0.cu fattn-vec-instance-q8_0-f16.cu fattn-vec-instance-q8_0-q4_0.cu fattn-vec-instance-q8_0-q4_1.cu fattn-vec-instance-q8_0-q5_0.cu fattn-vec-instance-q8_0-q5_1.cu fattn-vec-instance-q8_0-q8_0.cu generate_cu_files.py mmf-instance-ncols_1.cu mmf-instance-ncols_10.cu mmf-instance-ncols_11.cu mmf-instance-ncols_12.cu mmf-instance-ncols_13.cu mmf-instance-ncols_14.cu mmf-instance-ncols_15.cu mmf-instance-ncols_16.cu mmf-instance-ncols_2.cu mmf-instance-ncols_3.cu mmf-instance-ncols_4.cu mmf-instance-ncols_5.cu mmf-instance-ncols_6.cu mmf-instance-ncols_7.cu mmf-instance-ncols_8.cu mmf-instance-ncols_9.cu mmq-instance-iq1_s.cu mmq-instance-iq2_s.cu mmq-instance-iq2_xs.cu mmq-instance-iq2_xxs.cu mmq-instance-iq3_s.cu mmq-instance-iq3_xxs.cu mmq-instance-iq4_nl.cu mmq-instance-iq4_xs.cu mmq-instance-mxfp4.cu mmq-instance-q2_k.cu mmq-instance-q3_k.cu mmq-instance-q4_0.cu mmq-instance-q4_1.cu mmq-instance-q4_k.cu mmq-instance-q5_0.cu mmq-instance-q5_1.cu mmq-instance-q5_k.cu mmq-instance-q6_k.cu mmq-instance-q8_0.cuggml-hexagon
htp
CMakeLists.txt act-ops.c argsort-ops.c binary-ops.c cmake-toolchain.cmake cpy-ops.c flash-attn-ops.c get-rows-ops.c hex-dma.c hex-dma.h hex-dump.h hex-fastdiv.h hex-utils.h htp-ctx.h htp-msg.h htp-ops.h htp_iface.idl hvx-arith.h hvx-base.h hvx-copy.h hvx-div.h hvx-dump.h hvx-exp.h hvx-floor.h hvx-inverse.h hvx-reduce.h hvx-scale.h hvx-sigmoid.h hvx-sqrt.h hvx-types.h hvx-utils.h main.c matmul-ops.c rope-ops.c set-rows-ops.c softmax-ops.c sum-rows-ops.c unary-ops.c worker-pool.c worker-pool.hggml-metal
CMakeLists.txt ggml-metal-common.cpp ggml-metal-common.h ggml-metal-context.h ggml-metal-context.m ggml-metal-device.cpp ggml-metal-device.h ggml-metal-device.m ggml-metal-impl.h ggml-metal-ops.cpp ggml-metal-ops.h ggml-metal.cpp ggml-metal.metalggml-opencl
kernels
add.cl add_id.cl argsort.cl clamp.cl concat.cl conv2d.cl conv2d_f16_f32.cl cpy.cl cvt.cl diag_mask_inf.cl div.cl embed_kernel.py expm1.cl fill.cl flash_attn_f16.cl flash_attn_f32.cl flash_attn_f32_f16.cl gelu.cl gemm_moe_mxfp4_f32.cl gemv_moe_mxfp4_f32.cl gemv_noshuffle.cl gemv_noshuffle_general.cl gemv_noshuffle_general_q8_0_f32.cl get_rows.cl glu.cl group_norm.cl im2col_f16.cl im2col_f32.cl mean.cl mul.cl mul_mat_Ab_Bi_8x4.cl mul_mat_f16_f32.cl mul_mm_f16_f32_kq_kqv.cl mul_mm_f16_f32_l4_lm.cl mul_mm_f32_f32_l4_lm.cl mul_mm_q6_k_f32_l4_lm.cl mul_mm_q8_0_f32_8x4.cl mul_mm_q8_0_f32_l4_lm.cl mul_mv_f16_f16.cl mul_mv_f16_f32.cl mul_mv_f16_f32_1row.cl mul_mv_f16_f32_l4.cl mul_mv_f32_f32.cl mul_mv_id_mxfp4_f32.cl mul_mv_id_mxfp4_f32_flat.cl mul_mv_id_q4_0_f32_8x_flat.cl mul_mv_id_q8_0_f32.cl mul_mv_id_q8_0_f32_flat.cl mul_mv_mxfp4_f32.cl mul_mv_mxfp4_f32_flat.cl mul_mv_q4_0_f32.cl mul_mv_q4_0_f32_1d_16x_flat.cl mul_mv_q4_0_f32_1d_8x_flat.cl mul_mv_q4_0_f32_8x_flat.cl mul_mv_q4_0_f32_v.cl mul_mv_q4_k_f32.cl mul_mv_q6_k_f32.cl mul_mv_q6_k_f32_flat.cl mul_mv_q8_0_f32.cl mul_mv_q8_0_f32_flat.cl norm.cl pad.cl relu.cl repeat.cl rms_norm.cl rope.cl scale.cl set_rows.cl sigmoid.cl silu.cl softmax_4_f16.cl softmax_4_f32.cl softmax_f16.cl softmax_f32.cl softplus.cl solve_tri.cl sqr.cl sqrt.cl ssm_conv.cl sub.cl sum_rows.cl tanh.cl transpose.cl tri.cl tsembd.cl upscale.clggml-sycl
CMakeLists.txt add-id.cpp add-id.hpp backend.hpp binbcast.cpp binbcast.hpp common.cpp common.hpp concat.cpp concat.hpp conv.cpp conv.hpp convert.cpp convert.hpp count-equal.cpp count-equal.hpp cpy.cpp cpy.hpp dequantize.hpp dmmv.cpp dmmv.hpp element_wise.cpp element_wise.hpp gemm.hpp getrows.cpp getrows.hpp ggml-sycl.cpp gla.cpp gla.hpp im2col.cpp im2col.hpp mmq.cpp mmq.hpp mmvq.cpp mmvq.hpp norm.cpp norm.hpp outprod.cpp outprod.hpp pad.cpp pad.hpp pad_reflect_1d.cpp pad_reflect_1d.hpp presets.hpp quantize.hpp quants.hpp repeat_back.cpp repeat_back.hpp roll.cpp roll.hpp rope.cpp rope.hpp set.cpp set.hpp set_rows.cpp set_rows.hpp softmax.cpp softmax.hpp ssm_conv.cpp ssm_conv.hpp sycl_hw.cpp sycl_hw.hpp tsembd.cpp tsembd.hpp vecdotq.hpp wkv.cpp wkv.hppggml-virtgpu
backend
CMakeLists.txt apir_cs_ggml-rpc-back.cpp backend-convert.h backend-dispatched-backend.cpp backend-dispatched-buffer-type.cpp backend-dispatched-buffer.cpp backend-dispatched-device.cpp backend-dispatched.cpp backend-dispatched.gen.h backend-dispatched.h backend-virgl-apir.h backend.cppggml-vulkan
vulkan-shaders
CMakeLists.txt abs.comp acc.comp add.comp add1.comp add_id.comp arange.comp argmax.comp argsort.comp argsort_large.comp ceil.comp clamp.comp concat.comp contig_copy.comp conv2d_dw.comp conv2d_mm.comp conv_transpose_1d.comp copy.comp copy_from_quant.comp copy_to_quant.comp copy_transpose.comp cos.comp count_equal.comp count_experts.comp cumsum.comp cumsum_multipass1.comp cumsum_multipass2.comp dequant_f32.comp dequant_funcs.glsl dequant_funcs_cm2.glsl dequant_head.glsl dequant_iq1_m.comp dequant_iq1_s.comp dequant_iq2_s.comp dequant_iq2_xs.comp dequant_iq2_xxs.comp dequant_iq3_s.comp dequant_iq3_xxs.comp dequant_iq4_nl.comp dequant_iq4_xs.comp dequant_mxfp4.comp dequant_q2_k.comp dequant_q3_k.comp dequant_q4_0.comp dequant_q4_1.comp dequant_q4_k.comp dequant_q5_0.comp dequant_q5_1.comp dequant_q5_k.comp dequant_q6_k.comp dequant_q8_0.comp diag.comp diag_mask_inf.comp div.comp exp.comp fill.comp flash_attn.comp flash_attn_base.glsl flash_attn_cm1.comp flash_attn_cm2.comp flash_attn_mask_opt.comp flash_attn_split_k_reduce.comp floor.comp geglu.comp geglu_erf.comp geglu_quick.comp gelu.comp gelu_erf.comp gelu_quick.comp generic_binary_head.glsl generic_head.glsl generic_unary_head.glsl get_rows.comp get_rows_quant.comp glu_head.glsl glu_main.glsl group_norm.comp hardsigmoid.comp hardswish.comp im2col.comp im2col_3d.comp l2_norm.comp leaky_relu.comp log.comp mul.comp mul_mat_split_k_reduce.comp mul_mat_vec.comp mul_mat_vec_base.glsl mul_mat_vec_iface.glsl mul_mat_vec_iq1_m.comp mul_mat_vec_iq1_s.comp mul_mat_vec_iq2_s.comp mul_mat_vec_iq2_xs.comp mul_mat_vec_iq2_xxs.comp mul_mat_vec_iq3_s.comp mul_mat_vec_iq3_xxs.comp mul_mat_vec_nc.comp mul_mat_vec_p021.comp mul_mat_vec_q2_k.comp mul_mat_vec_q3_k.comp mul_mat_vec_q4_k.comp mul_mat_vec_q5_k.comp mul_mat_vec_q6_k.comp mul_mat_vecq.comp mul_mat_vecq_funcs.glsl mul_mm.comp mul_mm_cm2.comp mul_mm_funcs.glsl mul_mm_id_funcs.glsl mul_mmq.comp mul_mmq_funcs.glsl mul_mmq_shmem_types.glsl multi_add.comp neg.comp norm.comp opt_step_adamw.comp opt_step_sgd.comp pad.comp pool2d.comp quantize_q8_1.comp reglu.comp relu.comp repeat.comp repeat_back.comp rms_norm.comp rms_norm_back.comp rms_norm_partials.comp roll.comp rope_funcs.glsl rope_head.glsl rope_multi.comp rope_neox.comp rope_norm.comp rope_params.glsl rope_vision.comp round.comp rte.glsl scale.comp sigmoid.comp silu.comp silu_back.comp sin.comp soft_max.comp soft_max_back.comp soft_max_large1.comp soft_max_large2.comp soft_max_large3.comp soft_max_large_common.glsl softplus.comp solve_tri.comp sqrt.comp square.comp ssm_conv.comp ssm_scan.comp step.comp sub.comp sum_rows.comp sum_rows.glsl swiglu.comp swiglu_oai.comp tanh.comp timestep_embedding.comp topk_argsort.comp topk_moe.comp topk_nary_search.comp tri.comp trunc.comp types.glsl upscale.comp utils.glsl vulkan-shaders-gen.cpp wkv6.comp wkv7.comp xielu.compggml-webgpu
wgsl-shaders
argmax.wgsl argsort.wgsl argsort_merge.wgsl binary.wgsl common_decls.tmpl cpy.tmpl.wgsl cumsum.wgsl embed_wgsl.py flash_attn.wgsl get_rows.tmpl.wgsl glu.tmpl.wgsl memset.wgsl mul_mat.tmpl.wgsl mul_mat_decls.tmpl mul_mat_reg_tile.tmpl.wgsl mul_mat_subgroup_matrix.tmpl.wgsl mul_mat_vec.tmpl.wgsl pad.wgsl rms_norm.wgsl rope.tmpl.wgsl scale.tmpl.wgsl set_rows.wgsl soft_max.tmpl.wgsl sum_rows.wgsl unary.wgslgguf-py
gguf
scripts
gguf_convert_endian.py gguf_dump.py gguf_editor_gui.py gguf_hash.py gguf_new_metadata.py gguf_set_metadata.pygrammars
README.md arithmetic.gbnf c.gbnf chess.gbnf english.gbnf japanese.gbnf json.gbnf json_arr.gbnf list.gbnfmedia
llama0-banner.png llama0-logo.png llama1-banner.png llama1-icon-transparent.png llama1-icon-transparent.svg llama1-icon.png llama1-icon.svg llama1-logo.png llama1-logo.svg matmul.png matmul.svgmodels
templates
Apertus-8B-Instruct.jinja ByteDance-Seed-OSS.jinja CohereForAI-c4ai-command-r-plus-tool_use.jinja CohereForAI-c4ai-command-r7b-12-2024-tool_use.jinja GLM-4.6.jinja Kimi-K2-Instruct.jinja Kimi-K2-Thinking.jinja MiMo-VL.jinja MiniMax-M2.jinja Mistral-Small-3.2-24B-Instruct-2506.jinja NVIDIA-Nemotron-3-Nano-30B-A3B-BF16.jinja NVIDIA-Nemotron-Nano-v2.jinja NousResearch-Hermes-2-Pro-Llama-3-8B-tool_use.jinja NousResearch-Hermes-3-Llama-3.1-8B-tool_use.jinja Qwen-QwQ-32B.jinja Qwen-Qwen2.5-7B-Instruct.jinja Qwen-Qwen3-0.6B.jinja Qwen3-Coder.jinja README.md deepseek-ai-DeepSeek-R1-Distill-Llama-8B.jinja deepseek-ai-DeepSeek-R1-Distill-Qwen-32B.jinja deepseek-ai-DeepSeek-V3.1.jinja fireworks-ai-llama-3-firefunction-v2.jinja google-gemma-2-2b-it.jinja ibm-granite-granite-3.3-2B-Instruct.jinja llama-cpp-deepseek-r1.jinja llama-cpp-lfm2.jinja llama-cpp-rwkv-world.jinja meetkai-functionary-medium-v3.1.jinja meetkai-functionary-medium-v3.2.jinja meta-llama-Llama-3.1-8B-Instruct.jinja meta-llama-Llama-3.2-3B-Instruct.jinja meta-llama-Llama-3.3-70B-Instruct.jinja microsoft-Phi-3.5-mini-instruct.jinja mistralai-Ministral-3-14B-Reasoning-2512.jinja mistralai-Mistral-Nemo-Instruct-2407.jinja moonshotai-Kimi-K2.jinja openai-gpt-oss-120b.jinja unsloth-Apriel-1.5.jinja unsloth-mistral-Devstral-Small-2507.jinja upstage-Solar-Open-100B.jinjarequirements
requirements-all.txt requirements-compare-llama-bench.txt requirements-convert_hf_to_gguf.txt requirements-convert_hf_to_gguf_update.txt requirements-convert_legacy_llama.txt requirements-convert_llama_ggml_to_gguf.txt requirements-convert_lora_to_gguf.txt requirements-gguf_editor_gui.txt requirements-pydantic.txt requirements-server-bench.txt requirements-test-tokenizer-random.txt requirements-tool_bench.txtscripts
bench-models.sh build-info.sh check-requirements.sh compare-commits.sh compare-llama-bench.py compare-logprobs.py create_ops_docs.py debug-test.sh fetch_server_test_models.py gen-authors.sh gen-unicode-data.py get-flags.mk get-hellaswag.sh get-pg.sh get-wikitext-103.sh get-wikitext-2.sh get-winogrande.sh get_chat_template.py hf.sh install-oneapi.bat pr2wt.sh serve-static.js server-bench.py sync-ggml-am.sh sync-ggml.last sync-ggml.sh sync_vendor.py tool_bench.py tool_bench.sh verify-checksum-models.py xxd.cmakesrc
models
afmoe.cpp apertus.cpp arcee.cpp arctic.cpp arwkv7.cpp baichuan.cpp bailingmoe.cpp bailingmoe2.cpp bert.cpp bitnet.cpp bloom.cpp chameleon.cpp chatglm.cpp codeshell.cpp cogvlm.cpp cohere2-iswa.cpp command-r.cpp dbrx.cpp deci.cpp deepseek.cpp deepseek2.cpp dots1.cpp dream.cpp ernie4-5-moe.cpp ernie4-5.cpp exaone-moe.cpp exaone.cpp exaone4.cpp falcon-h1.cpp falcon.cpp gemma-embedding.cpp gemma.cpp gemma2-iswa.cpp gemma3.cpp gemma3n-iswa.cpp glm4-moe.cpp glm4.cpp gpt2.cpp gptneox.cpp granite-hybrid.cpp granite.cpp graph-context-mamba.cpp grok.cpp grovemoe.cpp hunyuan-dense.cpp hunyuan-moe.cpp internlm2.cpp jais.cpp jamba.cpp kimi-linear.cpp lfm2.cpp llada-moe.cpp llada.cpp llama-iswa.cpp llama.cpp maincoder.cpp mamba.cpp mimo2-iswa.cpp minicpm3.cpp minimax-m2.cpp mistral3.cpp models.h modern-bert.cpp mpt.cpp nemotron-h.cpp nemotron.cpp neo-bert.cpp olmo.cpp olmo2.cpp olmoe.cpp openai-moe-iswa.cpp openelm.cpp orion.cpp pangu-embedded.cpp phi2.cpp phi3.cpp plamo.cpp plamo2.cpp plamo3.cpp plm.cpp qwen.cpp qwen2.cpp qwen2moe.cpp qwen2vl.cpp qwen3.cpp qwen35.cpp qwen35moe.cpp qwen3moe.cpp qwen3next.cpp qwen3vl-moe.cpp qwen3vl.cpp refact.cpp rnd1.cpp rwkv6-base.cpp rwkv6.cpp rwkv6qwen2.cpp rwkv7-base.cpp rwkv7.cpp seed-oss.cpp smallthinker.cpp smollm3.cpp stablelm.cpp starcoder.cpp starcoder2.cpp step35-iswa.cpp t5-dec.cpp t5-enc.cpp wavtokenizer-dec.cpp xverse.cpptests
peg-parser
simple-tokenize.cpp simple-tokenize.h test-basic.cpp test-gbnf-generation.cpp test-json-parser.cpp test-json-serialization.cpp test-unicode.cpp tests.htools
cvector-generator
CMakeLists.txt README.md completions.txt cvector-generator.cpp mean.hpp negative.txt pca.hpp positive.txtmtmd
legacy-models
convert_image_encoder_to_gguf.py glmedge-convert-image-encoder-to-gguf.py glmedge-surgery.py llava_surgery.py llava_surgery_v2.py minicpmv-convert-image-encoder-to-gguf.py minicpmv-surgery.pymodels
cogvlm.cpp conformer.cpp glm4v.cpp internvl.cpp kimik25.cpp kimivl.cpp llama4.cpp llava.cpp minicpmv.cpp mobilenetv5.cpp models.h pixtral.cpp qwen2vl.cpp qwen3vl.cpp siglip.cpp whisper-enc.cpp youtuvl.cppserver
public_legacy
colorthemes.css completion.js favicon.ico index-new.html index.html index.js json-schema-to-grammar.mjs loading.html prompt-formats.js style.css system-prompts.js theme-beeninorder.css theme-ketivah.css theme-mangotango.css theme-playground.css theme-polarnight.css theme-snowstorm.csspublic_simplechat
datautils.mjs index.html readme.md simplechat.css simplechat.js simplechat_screens.webp ui.mjstests
unit
test_basic.py test_chat_completion.py test_compat_anthropic.py test_compat_oai_responses.py test_completion.py test_ctx_shift.py test_embedding.py test_infill.py test_lora.py test_rerank.py test_router.py test_security.py test_sleep.py test_slot_save.py test_speculative.py test_template.py test_tokenize.py test_tool_call.py test_vision_api.pywebui
.storybook
ModeWatcherDecorator.svelte TooltipProviderDecorator.svelte main.ts preview.ts vitest.setup.tssrc
lib
components
app
chat
ChatAttachments
ChatAttachmentPreview.svelte ChatAttachmentThumbnailFile.svelte ChatAttachmentThumbnailImage.svelte ChatAttachmentsList.svelte ChatAttachmentsViewAll.svelteChatForm
ChatFormActions
ChatFormActionFileAttachments.svelte ChatFormActionRecord.svelte ChatFormActionSubmit.svelte ChatFormActions.svelteChatMessages
ChatMessage.svelte ChatMessageActions.svelte ChatMessageAssistant.svelte ChatMessageBranchingControls.svelte ChatMessageEditForm.svelte ChatMessageStatistics.svelte ChatMessageSystem.svelte ChatMessageThinkingBlock.svelte ChatMessageUser.svelte ChatMessages.svelteChatScreen
ChatScreen.svelte ChatScreenDragOverlay.svelte ChatScreenHeader.svelte ChatScreenProcessingInfo.sveltedialogs
DialogChatAttachmentPreview.svelte DialogChatAttachmentsViewAll.svelte DialogChatError.svelte DialogChatSettings.svelte DialogConfirmation.svelte DialogConversationSelection.svelte DialogConversationTitleUpdate.svelte DialogEmptyFileAlert.svelte DialogModelInformation.svelte DialogModelNotAvailable.sveltemisc
ActionButton.svelte ActionDropdown.svelte BadgeChatStatistic.svelte BadgeInfo.svelte BadgeModality.svelte CodePreviewDialog.svelte ConversationSelection.svelte CopyToClipboardIcon.svelte KeyboardShortcutInfo.svelte MarkdownContent.svelte RemoveButton.svelte SearchInput.svelte SyntaxHighlightedCode.svelteui
alert-dialog
alert-dialog-action.svelte alert-dialog-cancel.svelte alert-dialog-content.svelte alert-dialog-description.svelte alert-dialog-footer.svelte alert-dialog-header.svelte alert-dialog-overlay.svelte alert-dialog-title.svelte alert-dialog-trigger.svelte index.tscard
card-action.svelte card-content.svelte card-description.svelte card-footer.svelte card-header.svelte card-title.svelte card.svelte index.tsdialog
dialog-close.svelte dialog-content.svelte dialog-description.svelte dialog-footer.svelte dialog-header.svelte dialog-overlay.svelte dialog-title.svelte dialog-trigger.svelte index.tsdropdown-menu
dropdown-menu-checkbox-item.svelte dropdown-menu-content.svelte dropdown-menu-group-heading.svelte dropdown-menu-group.svelte dropdown-menu-item.svelte dropdown-menu-label.svelte dropdown-menu-radio-group.svelte dropdown-menu-radio-item.svelte dropdown-menu-separator.svelte dropdown-menu-shortcut.svelte dropdown-menu-sub-content.svelte dropdown-menu-sub-trigger.svelte dropdown-menu-trigger.svelte index.tspopover
index.ts popover-close.svelte popover-content.svelte popover-portal.svelte popover-trigger.svelte popover.svelteselect
index.ts select-content.svelte select-group-heading.svelte select-group.svelte select-item.svelte select-label.svelte select-scroll-down-button.svelte select-scroll-up-button.svelte select-separator.svelte select-trigger.sveltesheet
index.ts sheet-close.svelte sheet-content.svelte sheet-description.svelte sheet-footer.svelte sheet-header.svelte sheet-overlay.svelte sheet-title.svelte sheet-trigger.sveltesidebar
constants.ts context.svelte.ts index.ts sidebar-content.svelte sidebar-footer.svelte sidebar-group-action.svelte sidebar-group-content.svelte sidebar-group-label.svelte sidebar-group.svelte sidebar-header.svelte sidebar-input.svelte sidebar-inset.svelte sidebar-menu-action.svelte sidebar-menu-badge.svelte sidebar-menu-button.svelte sidebar-menu-item.svelte sidebar-menu-skeleton.svelte sidebar-menu-sub-button.svelte sidebar-menu-sub-item.svelte sidebar-menu-sub.svelte sidebar-menu.svelte sidebar-provider.svelte sidebar-rail.svelte sidebar-separator.svelte sidebar-trigger.svelte sidebar.sveltetable
index.ts table-body.svelte table-caption.svelte table-cell.svelte table-footer.svelte table-head.svelte table-header.svelte table-row.svelte table.svelteconstants
auto-scroll.ts binary-detection.ts default-context.ts floating-ui-constraints.ts icons.ts input-classes.ts latex-protection.ts literal-html.ts localstorage-keys.ts max-bundle-size.ts precision.ts processing-info.ts settings-config.ts supported-file-types.ts table-html-restorer.ts tooltip-config.ts viewport.tsstores
chat.svelte.ts conversations.svelte.ts models.svelte.ts persisted.svelte.ts server.svelte.ts settings.svelte.tsutils
api-headers.ts api-key-validation.ts attachment-display.ts attachment-type.ts audio-recording.ts autoresize-textarea.ts branching.ts browser-only.ts clipboard.ts config-helpers.ts conversation-utils.ts convert-files-to-extra.ts file-preview.ts file-type.ts formatters.ts index.ts is-ime-composing.ts latex-protection.ts modality-file-validation.ts model-names.ts pdf-processing.ts portal-to-body.ts precision.ts process-uploaded-files.ts svg-to-png.ts syntax-highlight-language.ts text-files.ts text.ts webp-to-png.tstests
llama.cpp/tools/server/public_legacy/index.html
raw
1<html>
2<head>
3 <meta charset="UTF-8">
4 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
5 <meta name="color-scheme" content="light dark">
6 <title>llama.cpp - chat</title>
7
8 <style>
9 body {
10 font-family: system-ui;
11 font-size: 90%;
12 }
13
14 .grid-container {
15 display: grid;
16 grid-template-columns: auto auto auto;
17 padding: 10px;
18 }
19
20 .grid-item {
21 padding: 5px;
22 /* font-size: 30px; */
23 text-align: center;
24 }
25
26 #container {
27 margin: 0em auto;
28 display: flex;
29 flex-direction: column;
30 justify-content: space-between;
31 height: 100%;
32 }
33
34 main {
35 margin: 3px;
36 display: flex;
37 flex-direction: column;
38 justify-content: space-between;
39 gap: 1em;
40
41 flex-grow: 1;
42 overflow-y: auto;
43
44 border: 1px solid #ccc;
45 border-radius: 5px;
46 padding: 0.5em;
47 }
48
49 h1 {
50 text-align: center;
51 }
52
53 .customlink:link {
54 color: white;
55 background-color: #007aff;
56 font-weight: 600;
57 text-decoration: none;
58 float: right;
59 margin-top: 30px;
60 display: flex;
61 flex-direction: row;
62 gap: 0.5em;
63 justify-content: flex-end;
64 border-radius: 4px;
65 padding: 8px;
66 }
67
68 .customlink:visited {
69 color: white;
70 background-color: #007aff;
71 font-weight: 600;
72 text-decoration: none;
73 float: right;
74 margin-top: 30px;
75 display: flex;
76 flex-direction: row;
77 gap: 0.5em;
78 justify-content: flex-end;
79 padding: 8px;
80 }
81
82 .customlink:hover {
83 color: white;
84 background-color: #0070ee;
85 font-weight: 600;
86 text-decoration: none;
87 float: right;
88 margin-top: 30px;
89 display: flex;
90 flex-direction: row;
91 gap: 0.5em;
92 justify-content: flex-end;
93 padding: 8px;
94 }
95
96 .customlink:active {
97 color: #0070ee;
98 background-color: #80b3ef;
99 font-weight: 600;
100 text-decoration: none;
101 float: right;
102 margin-top: 30px;
103 display: flex;
104 flex-direction: row;
105 gap: 0.5em;
106 justify-content: flex-end;
107 padding: 8px;
108 }
109
110 body {
111 max-width: 600px;
112 min-width: 300px;
113 line-height: 1.2;
114 margin: 0 auto;
115 padding: 0 0.5em;
116 }
117
118 p {
119 overflow-wrap: break-word;
120 word-wrap: break-word;
121 hyphens: auto;
122 margin-top: 0.5em;
123 margin-bottom: 0.5em;
124 }
125
126 #write form {
127 margin: 1em 0 0 0;
128 display: flex;
129 flex-direction: column;
130 gap: 0.5em;
131 align-items: stretch;
132 }
133
134 .message-controls {
135 display: flex;
136 justify-content: flex-end;
137 }
138 .message-controls > div:nth-child(2) {
139 display: flex;
140 flex-direction: column;
141 gap: 0.5em;
142 }
143 .message-controls > div:nth-child(2) > div {
144 display: flex;
145 margin-left: auto;
146 gap: 0.5em;
147 }
148
149 fieldset {
150 border: none;
151 padding: 0;
152 margin: 0;
153 }
154
155 fieldset.two {
156 display: grid;
157 grid-template: "a a";
158 gap: 1em;
159 }
160
161 fieldset.three {
162 display: grid;
163 grid-template: "a a a";
164 gap: 1em;
165 }
166
167 details {
168 border: 1px solid #aaa;
169 border-radius: 4px;
170 padding: 0.5em 0.5em 0;
171 margin-top: 0.5em;
172 }
173
174 summary {
175 font-weight: bold;
176 margin: -0.5em -0.5em 0;
177 padding: 0.5em;
178 cursor: pointer;
179 }
180
181 details[open] {
182 padding: 0.5em;
183 }
184
185 .prob-set {
186 padding: 0.3em;
187 border-bottom: 1px solid #ccc;
188 }
189
190 .popover-content {
191 position: absolute;
192 background-color: white;
193 padding: 0.2em;
194 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
195 }
196
197 textarea {
198 padding: 5px;
199 flex-grow: 1;
200 width: 100%;
201 }
202
203 pre code {
204 display: block;
205 background-color: #222;
206 color: #ddd;
207 }
208
209 code {
210 font-family: monospace;
211 padding: 0.1em 0.3em;
212 border-radius: 3px;
213 }
214
215 fieldset label {
216 margin: 0.5em 0;
217 display: block;
218 }
219
220 fieldset label.slim {
221 margin: 0 0.5em;
222 display: inline;
223 }
224
225 header,
226 footer {
227 text-align: center;
228 }
229
230 footer {
231 font-size: 80%;
232 color: #888;
233 }
234
235 .mode-chat textarea[name=prompt] {
236 height: 4.5em;
237 }
238
239 .mode-completion textarea[name=prompt] {
240 height: 10em;
241 }
242
243 [contenteditable] {
244 display: inline-block;
245 white-space: pre-wrap;
246 outline: 0px solid transparent;
247 }
248
249 @keyframes loading-bg-wipe {
250 0% {
251 background-position: 0%;
252 }
253
254 100% {
255 background-position: 100%;
256 }
257 }
258
259 .loading {
260 --loading-color-1: #eeeeee00;
261 --loading-color-2: #eeeeeeff;
262 background-size: 50% 100%;
263 background-image: linear-gradient(90deg, var(--loading-color-1), var(--loading-color-2), var(--loading-color-1));
264 animation: loading-bg-wipe 2s linear infinite;
265 }
266
267 @media (prefers-color-scheme: dark) {
268 .loading {
269 --loading-color-1: #22222200;
270 --loading-color-2: #222222ff;
271 }
272
273 .popover-content {
274 background-color: black;
275 }
276 }
277 </style>
278
279 <script type="module">
280 import {
281 html, h, signal, effect, computed, render, useSignal, useEffect, useRef, Component
282 } from './index.js';
283
284 import { llama } from './completion.js';
285 import { SchemaConverter } from './json-schema-to-grammar.mjs';
286
287 let selected_image = false;
288 var slot_id = -1;
289
290 const session = signal({
291 prompt: "This is a conversation between User and Llama, a friendly chatbot. Llama is helpful, kind, honest, good at writing, and never fails to answer any requests immediately and with precision.",
292 template: "{{prompt}}\n\n{{history}}\n{{char}}:",
293 historyTemplate: "{{name}}: {{message}}",
294 transcript: [],
295 type: "chat", // "chat" | "completion"
296 char: "Llama",
297 user: "User",
298 image_selected: ''
299 })
300
301 const params = signal({
302 n_predict: 400,
303 temperature: 0.7,
304 repeat_last_n: 256, // 0 = disable penalty, -1 = context size
305 repeat_penalty: 1.18, // 1.0 = disabled
306 dry_multiplier: 0.0, // 0.0 = disabled, 0.8 works well
307 dry_base: 1.75, // 0.0 = disabled
308 dry_allowed_length: 2, // tokens extending repetitions beyond this receive penalty, 2 works well
309 dry_penalty_last_n: -1, // how many tokens to scan for repetitions (0 = disable penalty, -1 = context size)
310 top_k: 40, // <= 0 to use vocab size
311 top_p: 0.95, // 1.0 = disabled
312 min_p: 0.05, // 0 = disabled
313 xtc_probability: 0.0, // 0 = disabled;
314 xtc_threshold: 0.1, // > 0.5 disables XTC;
315 typical_p: 1.0, // 1.0 = disabled
316 presence_penalty: 0.0, // 0.0 = disabled
317 frequency_penalty: 0.0, // 0.0 = disabled
318 mirostat: 0, // 0/1/2
319 mirostat_tau: 5, // target entropy
320 mirostat_eta: 0.1, // learning rate
321 grammar: '',
322 n_probs: 0, // no completion_probabilities,
323 min_keep: 0, // min probs from each sampler,
324 image_data: [],
325 cache_prompt: true,
326 api_key: ''
327 })
328
329 /* START: Support for storing prompt templates and parameters in browsers LocalStorage */
330
331 const local_storage_storageKey = "llamacpp_server_local_storage";
332
333 function local_storage_setDataFromObject(tag, content) {
334 localStorage.setItem(local_storage_storageKey + '/' + tag, JSON.stringify(content));
335 }
336
337 function local_storage_setDataFromRawText(tag, content) {
338 localStorage.setItem(local_storage_storageKey + '/' + tag, content);
339 }
340
341 function local_storage_getDataAsObject(tag) {
342 const item = localStorage.getItem(local_storage_storageKey + '/' + tag);
343 if (!item) {
344 return null;
345 } else {
346 return JSON.parse(item);
347 }
348 }
349
350 function local_storage_getDataAsRawText(tag) {
351 const item = localStorage.getItem(local_storage_storageKey + '/' + tag);
352 if (!item) {
353 return null;
354 } else {
355 return item;
356 }
357 }
358
359 // create a container for user templates and settings
360
361 const savedUserTemplates = signal({})
362 const selectedUserTemplate = signal({ name: '', template: { session: {}, params: {} } })
363
364 // let's import locally saved templates and settings if there are any
365 // user templates and settings are stored in one object
366 // in form of { "templatename": "templatedata" } and { "settingstemplatename":"settingsdata" }
367
368 console.log('Importing saved templates')
369
370 let importedTemplates = local_storage_getDataAsObject('user_templates')
371
372 if (importedTemplates) {
373 // saved templates were successfully imported.
374
375 console.log('Processing saved templates and updating default template')
376 params.value = { ...params.value, image_data: [] };
377
378 //console.log(importedTemplates);
379 savedUserTemplates.value = importedTemplates;
380
381 //override default template
382 savedUserTemplates.value.default = { session: session.value, params: params.value }
383 local_storage_setDataFromObject('user_templates', savedUserTemplates.value)
384 } else {
385 // no saved templates detected.
386
387 console.log('Initializing LocalStorage and saving default template')
388
389 savedUserTemplates.value = { "default": { session: session.value, params: params.value } }
390 local_storage_setDataFromObject('user_templates', savedUserTemplates.value)
391 }
392
393 function userTemplateResetToDefault() {
394 console.log('Resetting template to default')
395 selectedUserTemplate.value.name = 'default';
396 selectedUserTemplate.value.data = savedUserTemplates.value['default'];
397 }
398
399 function userTemplateApply(t) {
400 session.value = t.data.session;
401 session.value = { ...session.value, image_selected: '' };
402 params.value = t.data.params;
403 params.value = { ...params.value, image_data: [] };
404 }
405
406 function userTemplateResetToDefaultAndApply() {
407 userTemplateResetToDefault()
408 userTemplateApply(selectedUserTemplate.value)
409 }
410
411 function userTemplateLoadAndApplyAutosaved() {
412 // get autosaved last used template
413 let lastUsedTemplate = local_storage_getDataAsObject('user_templates_last')
414
415 if (lastUsedTemplate) {
416
417 console.log('Autosaved template found, restoring')
418
419 selectedUserTemplate.value = lastUsedTemplate
420 }
421 else {
422
423 console.log('No autosaved template found, using default template')
424 // no autosaved last used template was found, so load from default.
425
426 userTemplateResetToDefault()
427 }
428
429 console.log('Applying template')
430 // and update internal data from templates
431
432 userTemplateApply(selectedUserTemplate.value)
433 }
434
435 //console.log(savedUserTemplates.value)
436 //console.log(selectedUserTemplate.value)
437
438 function userTemplateAutosave() {
439 console.log('Template Autosave...')
440 if (selectedUserTemplate.value.name == 'default') {
441 // we don't want to save over default template, so let's create a new one
442 let newTemplateName = 'UserTemplate-' + Date.now().toString()
443 let newTemplate = { 'name': newTemplateName, 'data': { 'session': session.value, 'params': params.value } }
444
445 console.log('Saving as ' + newTemplateName)
446
447 // save in the autosave slot
448 local_storage_setDataFromObject('user_templates_last', newTemplate)
449
450 // and load it back and apply
451 userTemplateLoadAndApplyAutosaved()
452 } else {
453 local_storage_setDataFromObject('user_templates_last', { 'name': selectedUserTemplate.value.name, 'data': { 'session': session.value, 'params': params.value } })
454 }
455 }
456
457 console.log('Checking for autosaved last used template')
458 userTemplateLoadAndApplyAutosaved()
459
460 /* END: Support for storing prompt templates and parameters in browsers LocalStorage */
461
462 const tts = window.speechSynthesis;
463 const ttsVoice = signal(null)
464
465 const llamaStats = signal(null)
466 const controller = signal(null)
467
468 // currently generating a completion?
469 const generating = computed(() => controller.value != null)
470
471 // has the user started a chat?
472 const chatStarted = computed(() => session.value.transcript.length > 0)
473
474 const transcriptUpdate = (transcript) => {
475 session.value = {
476 ...session.value,
477 transcript
478 }
479 }
480
481 // simple template replace
482 const template = (str, extraSettings) => {
483 let settings = session.value;
484 if (extraSettings) {
485 settings = { ...settings, ...extraSettings };
486 }
487 return String(str).replaceAll(/\{\{(.*?)\}\}/g, (_, key) => template(settings[key]));
488 }
489
490 async function runLlama(prompt, llamaParams, char) {
491 const currentMessages = [];
492 const history = session.value.transcript;
493 if (controller.value) {
494 throw new Error("already running");
495 }
496 controller.value = new AbortController();
497 for await (const chunk of llama(prompt, llamaParams, { controller: controller.value, api_url: new URL('.', document.baseURI).href })) {
498 const data = chunk.data;
499
500 if (data.stop) {
501 while (
502 currentMessages.length > 0 &&
503 currentMessages[currentMessages.length - 1].content.match(/\n$/) != null
504 ) {
505 currentMessages.pop();
506 }
507 transcriptUpdate([...history, [char, currentMessages]])
508 console.log("Completion finished: '", currentMessages.map(msg => msg.content).join(''), "', summary: ", data);
509 } else {
510 currentMessages.push(data);
511 slot_id = data.slot_id;
512 if (selected_image && !data.multimodal) {
513 alert("The server was not compiled for multimodal or the model projector can't be loaded.");
514 return;
515 }
516 transcriptUpdate([...history, [char, currentMessages]])
517 }
518
519 if (data.timings) {
520 llamaStats.value = data;
521 }
522 }
523
524 controller.value = null;
525 }
526
527 // send message to server
528 const chat = async (msg) => {
529 if (controller.value) {
530 console.log('already running...');
531 return;
532 }
533
534 transcriptUpdate([...session.value.transcript, ["{{user}}", msg]])
535
536 let prompt = template(session.value.template, {
537 message: msg,
538 history: session.value.transcript.flatMap(
539 ([name, data]) =>
540 template(
541 session.value.historyTemplate,
542 {
543 name,
544 message: Array.isArray(data) ?
545 data.map(msg => msg.content).join('').replace(/^\s/, '') :
546 data,
547 }
548 )
549 ).join("\n"),
550 });
551 if (selected_image) {
552 prompt = `A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.\nUSER:[img-10]${msg}\nASSISTANT:`;
553 }
554 await runLlama(prompt, {
555 ...params.value,
556 slot_id: slot_id,
557 stop: ["</s>", template("{{char}}:"), template("{{user}}:")],
558 }, "{{char}}");
559 }
560
561 const runCompletion = () => {
562 if (controller.value) {
563 console.log('already running...');
564 return;
565 }
566 const { prompt } = session.value;
567 transcriptUpdate([...session.value.transcript, ["", prompt]]);
568 runLlama(prompt, {
569 ...params.value,
570 slot_id: slot_id,
571 stop: [],
572 }, "").finally(() => {
573 session.value.prompt = session.value.transcript.map(([_, data]) =>
574 Array.isArray(data) ? data.map(msg => msg.content).join('') : data
575 ).join('');
576 session.value.transcript = [];
577 })
578 }
579
580 const stop = (e) => {
581 e.preventDefault();
582 if (controller.value) {
583 controller.value.abort();
584 controller.value = null;
585 }
586 }
587
588 const reset = (e) => {
589 stop(e);
590 transcriptUpdate([]);
591 }
592
593 const uploadImage = (e) => {
594 e.preventDefault();
595 document.getElementById("fileInput").click();
596 document.getElementById("fileInput").addEventListener("change", function (event) {
597 const selectedFile = event.target.files[0];
598 if (selectedFile) {
599 const reader = new FileReader();
600 reader.onload = function () {
601 const image_data = reader.result;
602 session.value = { ...session.value, image_selected: image_data };
603 params.value = {
604 ...params.value, image_data: [
605 { data: image_data.replace(/data:image\/[^;]+;base64,/, ''), id: 10 }]
606 }
607 };
608 selected_image = true;
609 reader.readAsDataURL(selectedFile);
610 }
611 });
612 }
613
614 const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
615 const talkRecognition = SpeechRecognition ? new SpeechRecognition() : null;
616 function MessageInput() {
617 const message = useSignal("");
618
619 const talkActive = useSignal(false);
620 const sendOnTalk = useSignal(false);
621 const talkStop = (e) => {
622 if (e) e.preventDefault();
623
624 talkActive.value = false;
625 talkRecognition?.stop();
626 }
627 const talk = (e) => {
628 e.preventDefault();
629
630 if (talkRecognition)
631 talkRecognition.start();
632 else
633 alert("Speech recognition is not supported by this browser.");
634 }
635 if(talkRecognition) {
636 talkRecognition.onstart = () => {
637 talkActive.value = true;
638 }
639 talkRecognition.onresult = (e) => {
640 if (event.results.length > 0) {
641 message.value = event.results[0][0].transcript;
642 if (sendOnTalk.value) {
643 submit(e);
644 }
645 }
646 }
647 talkRecognition.onspeechend = () => {
648 talkStop();
649 }
650 }
651
652 const ttsVoices = useSignal(tts?.getVoices() || []);
653 const ttsVoiceDefault = computed(() => ttsVoices.value.find(v => v.default));
654 if (tts) {
655 tts.onvoiceschanged = () => {
656 ttsVoices.value = tts.getVoices();
657 }
658 }
659
660 const submit = (e) => {
661 stop(e);
662 chat(message.value);
663 message.value = "";
664 }
665
666 const enterSubmits = (event) => {
667 if (event.which === 13 && !event.shiftKey) {
668 submit(event);
669 }
670 }
671
672 return html`
673 <form onsubmit=${submit}>
674 <div>
675 <textarea
676 className=${generating.value ? "loading" : null}
677 oninput=${(e) => message.value = e.target.value}
678 onkeypress=${enterSubmits}
679 placeholder="Say something..."
680 rows=2
681 type="text"
682 value="${message}"
683 />
684 </div>
685 <div class="message-controls">
686 <div> </div>
687 <div>
688 <div>
689 <button type="submit" disabled=${generating.value || talkActive.value}>Send</button>
690 <button disabled=${generating.value || talkActive.value} onclick=${uploadImage}>Upload Image</button>
691 <button onclick=${stop} disabled=${!generating.value}>Stop</button>
692 <button onclick=${reset}>Reset</button>
693 </div>
694 <div>
695 <a href="#" style="cursor: help;" title="Help" onclick=${e => {
696 e.preventDefault();
697 alert(`STT supported by your browser: ${SpeechRecognition ? 'Yes' : 'No'}\n` +
698 `(TTS and speech recognition are not provided by llama.cpp)\n` +
699 `Note: STT requires HTTPS to work.`);
700 }}>[?]</a>
701 <button disabled=${generating.value} onclick=${talkActive.value ? talkStop : talk}>${talkActive.value ? "Stop Talking" : "Talk"}</button>
702 <div>
703 <input type="checkbox" id="send-on-talk" name="send-on-talk" checked="${sendOnTalk}" onchange=${(e) => sendOnTalk.value = e.target.checked} />
704 <label for="send-on-talk" style="line-height: initial;">Send after talking</label>
705 </div>
706 </div>
707 <div>
708 <a href="#" style="cursor: help;" title="Help" onclick=${e => {
709 e.preventDefault();
710 alert(`TTS supported by your browser: ${tts ? 'Yes' : 'No'}\n(TTS and speech recognition are not provided by llama.cpp)`);
711 }}>[?]</a>
712 <label for="tts-voices" style="line-height: initial;">Bot Voice:</label>
713 <select id="tts-voices" name="tts-voices" onchange=${(e) => ttsVoice.value = e.target.value} style="max-width: 100px;">
714 <option value="" selected="${!ttsVoice.value}">None</option>
715 ${[
716 ...(ttsVoiceDefault.value ? [ttsVoiceDefault.value] : []),
717 ...ttsVoices.value.filter(v => !v.default),
718 ].map(
719 v => html`<option value="${v.name}" selected="${ttsVoice.value === v.name}">${v.name} (${v.lang}) ${v.default ? '(default)' : ''}</option>`
720 )}
721 </select>
722 </div>
723 </div>
724 </div>
725 </form>
726 `
727 }
728
729 function CompletionControls() {
730 const submit = (e) => {
731 stop(e);
732 runCompletion();
733 }
734 return html`
735 <div>
736 <button onclick=${submit} type="button" disabled=${generating.value}>Start</button>
737 <button onclick=${stop} disabled=${!generating.value}>Stop</button>
738 <button onclick=${reset}>Reset</button>
739 </div>`;
740 }
741
742 const ChatLog = (props) => {
743 const messages = session.value.transcript;
744 const container = useRef(null)
745
746 useEffect(() => {
747 // scroll to bottom (if needed)
748 const parent = container.current.parentElement;
749 if (parent && parent.scrollHeight <= parent.scrollTop + parent.offsetHeight + 300) {
750 parent.scrollTo(0, parent.scrollHeight)
751 }
752 }, [messages])
753
754 const ttsChatLineActiveIx = useSignal(undefined);
755 const ttsChatLine = (e, ix, msg) => {
756 if (e) e.preventDefault();
757
758 if (!tts || !ttsVoice.value || !('SpeechSynthesisUtterance' in window)) return;
759
760 const ttsVoices = tts.getVoices();
761 const voice = ttsVoices.find(v => v.name === ttsVoice.value);
762 if (!voice) return;
763
764 if (ttsChatLineActiveIx.value !== undefined) {
765 tts.cancel();
766 if (ttsChatLineActiveIx.value === ix) {
767 ttsChatLineActiveIx.value = undefined;
768 return;
769 }
770 }
771
772 ttsChatLineActiveIx.value = ix;
773 let ttsUtter = new SpeechSynthesisUtterance(msg);
774 ttsUtter.voice = voice;
775 ttsUtter.onend = e => {
776 ttsChatLineActiveIx.value = undefined;
777 };
778 tts.speak(ttsUtter);
779 }
780
781 const isCompletionMode = session.value.type === 'completion'
782
783 // Try play the last bot message
784 const lastCharChatLinesIxs = useSignal([]);
785 const lastCharChatLinesIxsOld = useSignal([]);
786 useEffect(() => {
787 if (
788 !isCompletionMode
789 && lastCharChatLinesIxs.value.length !== lastCharChatLinesIxsOld.value.length
790 && !generating.value
791 ) {
792 const ix = lastCharChatLinesIxs.value[lastCharChatLinesIxs.value.length - 1];
793 if (ix !== undefined) {
794 const msg = messages[ix];
795 ttsChatLine(null, ix, Array.isArray(msg) ? msg[1].map(m => m.content).join('') : msg);
796 }
797
798 lastCharChatLinesIxsOld.value = structuredClone(lastCharChatLinesIxs.value);
799 }
800 }, [generating.value]);
801
802 const chatLine = ([user, data], index) => {
803 let message
804 const isArrayMessage = Array.isArray(data);
805 const text = isArrayMessage ?
806 data.map(msg => msg.content).join('') :
807 data;
808 if (params.value.n_probs > 0 && isArrayMessage) {
809 message = html`<${Probabilities} data=${data} />`
810 } else {
811 message = isCompletionMode ?
812 text :
813 html`<${Markdownish} text=${template(text)} />`
814 }
815
816 const fromBot = user && user === '{{char}}';
817 if (fromBot && !lastCharChatLinesIxs.value.includes(index))
818 lastCharChatLinesIxs.value.push(index);
819
820 if (user) {
821 return html`
822 <div>
823 <p key=${index}><strong>${template(user)}:</strong> ${message}</p>
824 ${
825 fromBot && ttsVoice.value
826 && html`<button disabled=${generating.value} onclick=${e => ttsChatLine(e, index, text)} aria-label=${ttsChatLineActiveIx.value === index ? 'Pause' : 'Play'}>${ ttsChatLineActiveIx.value === index ? 'โธ๏ธ' : 'โถ๏ธ' }</div>`
827 }
828 </div>
829 `;
830 } else {
831 return isCompletionMode ?
832 html`<span key=${index}>${message}</span>` :
833 html`<div><p key=${index}>${message}</p></div>`
834 }
835 };
836
837 const handleCompletionEdit = (e) => {
838 session.value.prompt = e.target.innerText;
839 session.value.transcript = [];
840 }
841
842 return html`
843 <div id="chat" ref=${container} key=${messages.length}>
844 <img style="width: 60%;${!session.value.image_selected ? `display: none;` : ``}" src="${session.value.image_selected}"/>
845 <span contenteditable=${isCompletionMode} ref=${container} oninput=${handleCompletionEdit}>
846 ${messages.flatMap(chatLine)}
847 </span>
848 </div>`;
849 };
850
851 const ConfigForm = (props) => {
852 const updateSession = (el) => session.value = { ...session.value, [el.target.name]: el.target.value }
853 const updateParams = (el) => params.value = { ...params.value, [el.target.name]: el.target.value }
854 const updateParamsFloat = (el) => params.value = { ...params.value, [el.target.name]: parseFloat(el.target.value) }
855 const updateParamsInt = (el) => params.value = { ...params.value, [el.target.name]: Math.floor(parseFloat(el.target.value)) }
856 const updateParamsBool = (el) => params.value = { ...params.value, [el.target.name]: el.target.checked }
857
858 const grammarJsonSchemaPropOrder = signal('')
859 const updateGrammarJsonSchemaPropOrder = (el) => grammarJsonSchemaPropOrder.value = el.target.value
860 const convertJSONSchemaGrammar = async () => {
861 try {
862 let schema = JSON.parse(params.value.grammar)
863 const converter = new SchemaConverter({
864 prop_order: grammarJsonSchemaPropOrder.value
865 .split(',')
866 .reduce((acc, cur, i) => ({ ...acc, [cur.trim()]: i }), {}),
867 allow_fetch: true,
868 })
869 schema = await converter.resolveRefs(schema, 'input')
870 converter.visit(schema, '')
871 params.value = {
872 ...params.value,
873 grammar: converter.formatGrammar(),
874 }
875 } catch (e) {
876 alert(`Convert failed: ${e.message}`)
877 }
878 }
879
880 const FloatField = ({ label, max, min, name, step, value }) => {
881 return html`
882 <div>
883 <label for="${name}">${label}</label>
884 <input type="range" id="${name}" min="${min}" max="${max}" step="${step}" name="${name}" value="${value}" oninput=${updateParamsFloat} />
885 <span>${value}</span>
886 </div>
887 `
888 };
889
890 const IntField = ({ label, max, min, name, value }) => {
891 return html`
892 <div>
893 <label for="${name}">${label}</label>
894 <input type="range" id="${name}" min="${min}" max="${max}" name="${name}" value="${value}" oninput=${updateParamsInt} />
895 <span>${value}</span>
896 </div>
897 `
898 };
899
900 const BoolField = ({ label, name, value }) => {
901 return html`
902 <div>
903 <label for="${name}">${label}</label>
904 <input type="checkbox" id="${name}" name="${name}" checked="${value}" onclick=${updateParamsBool} />
905 </div>
906 `
907 };
908
909 const userTemplateReset = (e) => {
910 e.preventDefault();
911 userTemplateResetToDefaultAndApply()
912 }
913
914 const UserTemplateResetButton = () => {
915 if (selectedUserTemplate.value.name == 'default') {
916 return html`
917 <button disabled>Using default template</button>
918 `
919 }
920
921 return html`
922 <button onclick=${userTemplateReset}>Reset all to default</button>
923 `
924 };
925
926 useEffect(() => {
927 // autosave template on every change
928 userTemplateAutosave()
929 }, [session.value, params.value])
930
931 const GrammarControl = () => (
932 html`
933 <div>
934 <label for="template">Grammar</label>
935 <textarea id="grammar" name="grammar" placeholder="Use gbnf or JSON Schema+convert" value="${params.value.grammar}" rows=4 oninput=${updateParams}/>
936 <input type="text" name="prop-order" placeholder="order: prop1,prop2,prop3" oninput=${updateGrammarJsonSchemaPropOrder} />
937 <button type="button" onclick=${convertJSONSchemaGrammar}>Convert JSON Schema</button>
938 </div>
939 `
940 );
941
942 const PromptControlFieldSet = () => (
943 html`
944 <fieldset>
945 <div>
946 <label htmlFor="prompt">Prompt</label>
947 <textarea type="text" name="prompt" value="${session.value.prompt}" oninput=${updateSession}/>
948 </div>
949 </fieldset>
950 `
951 );
952
953 const ChatConfigForm = () => (
954 html`
955 ${PromptControlFieldSet()}
956
957 <fieldset class="two">
958 <div>
959 <label for="user">User name</label>
960 <input type="text" name="user" value="${session.value.user}" oninput=${updateSession} />
961 </div>
962
963 <div>
964 <label for="bot">Bot name</label>
965 <input type="text" name="char" value="${session.value.char}" oninput=${updateSession} />
966 </div>
967 </fieldset>
968
969 <fieldset>
970 <div>
971 <label for="template">Prompt template</label>
972 <textarea id="template" name="template" value="${session.value.template}" rows=4 oninput=${updateSession}/>
973 </div>
974
975 <div>
976 <label for="template">Chat history template</label>
977 <textarea id="template" name="historyTemplate" value="${session.value.historyTemplate}" rows=1 oninput=${updateSession}/>
978 </div>
979 ${GrammarControl()}
980 </fieldset>
981 `
982 );
983
984 const CompletionConfigForm = () => (
985 html`
986 ${PromptControlFieldSet()}
987 <fieldset>${GrammarControl()}</fieldset>
988 `
989 );
990
991 return html`
992 <form>
993 <fieldset class="two">
994 <${UserTemplateResetButton}/>
995 <div>
996 <label class="slim"><input type="radio" name="type" value="chat" checked=${session.value.type === "chat"} oninput=${updateSession} /> Chat</label>
997 <label class="slim"><input type="radio" name="type" value="completion" checked=${session.value.type === "completion"} oninput=${updateSession} /> Completion</label>
998 </div>
999 </fieldset>
1000
1001 ${session.value.type === 'chat' ? ChatConfigForm() : CompletionConfigForm()}
1002
1003 <fieldset class="two">
1004 ${IntField({ label: "Predictions", max: 2048, min: -1, name: "n_predict", value: params.value.n_predict })}
1005 ${FloatField({ label: "Temperature", max: 2.0, min: 0.0, name: "temperature", step: 0.01, value: params.value.temperature })}
1006 ${FloatField({ label: "Penalize repeat sequence", max: 2.0, min: 0.0, name: "repeat_penalty", step: 0.01, value: params.value.repeat_penalty })}
1007 ${IntField({ label: "Consider N tokens for penalize", max: 2048, min: 0, name: "repeat_last_n", value: params.value.repeat_last_n })}
1008 ${IntField({ label: "Top-K sampling", max: 100, min: -1, name: "top_k", value: params.value.top_k })}
1009 ${FloatField({ label: "Top-P sampling", max: 1.0, min: 0.0, name: "top_p", step: 0.01, value: params.value.top_p })}
1010 ${FloatField({ label: "Min-P sampling", max: 1.0, min: 0.0, name: "min_p", step: 0.01, value: params.value.min_p })}
1011 </fieldset>
1012 <details>
1013 <summary>More options</summary>
1014 <fieldset class="two">
1015 ${FloatField({ label: "Typical P", max: 1.0, min: 0.0, name: "typical_p", step: 0.01, value: params.value.typical_p })}
1016 ${FloatField({ label: "Presence penalty", max: 1.0, min: 0.0, name: "presence_penalty", step: 0.01, value: params.value.presence_penalty })}
1017 ${FloatField({ label: "Frequency penalty", max: 1.0, min: 0.0, name: "frequency_penalty", step: 0.01, value: params.value.frequency_penalty })}
1018 ${FloatField({ label: "DRY Penalty Multiplier", max: 5.0, min: 0.0, name: "dry_multiplier", step: 0.01, value: params.value.dry_multiplier })}
1019 ${FloatField({ label: "DRY Base", max: 3.0, min: 1.0, name: "dry_base", step: 0.01, value: params.value.dry_base })}
1020 ${IntField({ label: "DRY Allowed Length", max: 10, min: 2, step: 1, name: "dry_allowed_length", value: params.value.dry_allowed_length })}
1021 ${IntField({ label: "DRY Penalty Last N", max: 2048, min: -1, step: 16, name: "dry_penalty_last_n", value: params.value.dry_penalty_last_n })}
1022 ${FloatField({ label: "XTC probability", max: 1.0, min: 0.0, name: "xtc_probability", step: 0.01, value: params.value.xtc_probability })}
1023 ${FloatField({ label: "XTC threshold", max: 0.5, min: 0.0, name: "xtc_threshold", step: 0.01, value: params.value.xtc_threshold })}
1024 </fieldset>
1025 <hr />
1026 <fieldset class="three">
1027 <div>
1028 <label><input type="radio" name="mirostat" value="0" checked=${params.value.mirostat == 0} oninput=${updateParamsInt} /> no Mirostat</label>
1029 <label><input type="radio" name="mirostat" value="1" checked=${params.value.mirostat == 1} oninput=${updateParamsInt} /> Mirostat v1</label>
1030 <label><input type="radio" name="mirostat" value="2" checked=${params.value.mirostat == 2} oninput=${updateParamsInt} /> Mirostat v2</label>
1031 </div>
1032 ${FloatField({ label: "Mirostat tau", max: 10.0, min: 0.0, name: "mirostat_tau", step: 0.01, value: params.value.mirostat_tau })}
1033 ${FloatField({ label: "Mirostat eta", max: 1.0, min: 0.0, name: "mirostat_eta", step: 0.01, value: params.value.mirostat_eta })}
1034 </fieldset>
1035 <fieldset>
1036 ${IntField({ label: "Show Probabilities", max: 10, min: 0, name: "n_probs", value: params.value.n_probs })}
1037 </fieldset>
1038 <fieldset>
1039 ${IntField({ label: "Min Probabilities from each Sampler", max: 10, min: 0, name: "min_keep", value: params.value.min_keep })}
1040 </fieldset>
1041 <fieldset>
1042 <label for="api_key">API Key</label>
1043 <input type="text" name="api_key" value="${params.value.api_key}" placeholder="Enter API key" oninput=${updateParams} />
1044 </fieldset>
1045 </details>
1046 </form>
1047 `
1048 }
1049
1050 const probColor = (p) => {
1051 const r = Math.floor(192 * (1 - p));
1052 const g = Math.floor(192 * p);
1053 return `rgba(${r},${g},0,0.3)`;
1054 }
1055
1056 const Probabilities = (params) => {
1057 return params.data.map(msg => {
1058 const { completion_probabilities } = msg;
1059 if (
1060 !completion_probabilities ||
1061 completion_probabilities.length === 0
1062 ) return msg.content
1063
1064 if (completion_probabilities.length > 1) {
1065 // Not for byte pair
1066 if (completion_probabilities[0].content.startsWith('byte: \\')) return msg.content
1067
1068 const splitData = completion_probabilities.map(prob => ({
1069 content: prob.content,
1070 completion_probabilities: [prob]
1071 }))
1072 return html`<${Probabilities} data=${splitData} />`
1073 }
1074
1075 const { probs, content } = completion_probabilities[0]
1076 const found = probs.find(p => p.tok_str === msg.content)
1077 const pColor = found ? probColor(found.prob) : 'transparent'
1078
1079 const popoverChildren = html`
1080 <div class="prob-set">
1081 ${probs.map((p, index) => {
1082 return html`
1083 <div
1084 key=${index}
1085 title=${`prob: ${p.prob}`}
1086 style=${{
1087 padding: '0.3em',
1088 backgroundColor: p.tok_str === content ? probColor(p.prob) : 'transparent'
1089 }}
1090 >
1091 <span>${p.tok_str}: </span>
1092 <span>${Math.floor(p.prob * 100)}%</span>
1093 </div>
1094 `
1095 })}
1096 </div>
1097 `
1098
1099 return html`
1100 <${Popover} style=${{ backgroundColor: pColor }} popoverChildren=${popoverChildren}>
1101 ${msg.content.match(/\n/gim) ? html`<br />` : msg.content}
1102 </>
1103 `
1104 });
1105 }
1106
1107 // poor mans markdown replacement
1108 const Markdownish = (params) => {
1109 const chunks = params.text.split('```');
1110
1111 for (let i = 0; i < chunks.length; i++) {
1112 if (i % 2 === 0) { // outside code block
1113 chunks[i] = chunks[i]
1114 .replace(/&/g, '&')
1115 .replace(/</g, '<')
1116 .replace(/>/g, '>')
1117 .replace(/(^|\n)#{1,6} ([^\n]*)(?=([^`]*`[^`]*`)*[^`]*$)/g, '$1<h3>$2</h3>')
1118 .replace(/\*\*(.*?)\*\*(?=([^`]*`[^`]*`)*[^`]*$)/g, '<strong>$1</strong>')
1119 .replace(/__(.*?)__(?=([^`]*`[^`]*`)*[^`]*$)/g, '<strong>$1</strong>')
1120 .replace(/\*(.*?)\*(?=([^`]*`[^`]*`)*[^`]*$)/g, '<em>$1</em>')
1121 .replace(/_(.*?)_(?=([^`]*`[^`]*`)*[^`]*$)/g, '<em>$1</em>')
1122 .replace(/```.*?\n([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
1123 .replace(/`(.*?)`/g, '<code>$1</code>')
1124 .replace(/\n/gim, '<br />');
1125 } else { // inside code block
1126 chunks[i] = `<pre><code>${chunks[i]}</code></pre>`;
1127 }
1128 }
1129
1130 const restoredText = chunks.join('');
1131
1132 return html`<span dangerouslySetInnerHTML=${{ __html: restoredText }} />`;
1133 };
1134
1135 const ModelGenerationInfo = (params) => {
1136 if (!llamaStats.value) {
1137 return html`<span/>`
1138 }
1139 return html`
1140 <span>
1141 ${llamaStats.value.tokens_predicted} predicted, ${llamaStats.value.tokens_cached} cached, ${llamaStats.value.timings.predicted_per_token_ms.toFixed()}ms per token, ${llamaStats.value.timings.predicted_per_second.toFixed(2)} tokens per second
1142 </span>
1143 `
1144 }
1145
1146
1147 // simple popover impl
1148 const Popover = (props) => {
1149 const isOpen = useSignal(false);
1150 const position = useSignal({ top: '0px', left: '0px' });
1151 const buttonRef = useRef(null);
1152 const popoverRef = useRef(null);
1153
1154 const togglePopover = () => {
1155 if (buttonRef.current) {
1156 const rect = buttonRef.current.getBoundingClientRect();
1157 position.value = {
1158 top: `${rect.bottom + window.scrollY}px`,
1159 left: `${rect.left + window.scrollX}px`,
1160 };
1161 }
1162 isOpen.value = !isOpen.value;
1163 };
1164
1165 const handleClickOutside = (event) => {
1166 if (popoverRef.current && !popoverRef.current.contains(event.target) && !buttonRef.current.contains(event.target)) {
1167 isOpen.value = false;
1168 }
1169 };
1170
1171 useEffect(() => {
1172 document.addEventListener('mousedown', handleClickOutside);
1173 return () => {
1174 document.removeEventListener('mousedown', handleClickOutside);
1175 };
1176 }, []);
1177
1178 return html`
1179 <span style=${props.style} ref=${buttonRef} onClick=${togglePopover}>${props.children}</span>
1180 ${isOpen.value && html`
1181 <${Portal} into="#portal">
1182 <div
1183 ref=${popoverRef}
1184 class="popover-content"
1185 style=${{
1186 top: position.value.top,
1187 left: position.value.left,
1188 }}
1189 >
1190 ${props.popoverChildren}
1191 </div>
1192 </${Portal}>
1193 `}
1194 `;
1195 };
1196
1197 // Source: preact-portal (https://github.com/developit/preact-portal/blob/master/src/preact-portal.js)
1198 /** Redirect rendering of descendants into the given CSS selector */
1199 class Portal extends Component {
1200 componentDidUpdate(props) {
1201 for (let i in props) {
1202 if (props[i] !== this.props[i]) {
1203 return setTimeout(this.renderLayer);
1204 }
1205 }
1206 }
1207
1208 componentDidMount() {
1209 this.isMounted = true;
1210 this.renderLayer = this.renderLayer.bind(this);
1211 this.renderLayer();
1212 }
1213
1214 componentWillUnmount() {
1215 this.renderLayer(false);
1216 this.isMounted = false;
1217 if (this.remote && this.remote.parentNode) this.remote.parentNode.removeChild(this.remote);
1218 }
1219
1220 findNode(node) {
1221 return typeof node === 'string' ? document.querySelector(node) : node;
1222 }
1223
1224 renderLayer(show = true) {
1225 if (!this.isMounted) return;
1226
1227 // clean up old node if moving bases:
1228 if (this.props.into !== this.intoPointer) {
1229 this.intoPointer = this.props.into;
1230 if (this.into && this.remote) {
1231 this.remote = render(html`<${PortalProxy} />`, this.into, this.remote);
1232 }
1233 this.into = this.findNode(this.props.into);
1234 }
1235
1236 this.remote = render(html`
1237 <${PortalProxy} context=${this.context}>
1238 ${show && this.props.children || null}
1239 </${PortalProxy}>
1240 `, this.into, this.remote);
1241 }
1242
1243 render() {
1244 return null;
1245 }
1246 }
1247 // high-order component that renders its first child if it exists.
1248 // used as a conditional rendering proxy.
1249 class PortalProxy extends Component {
1250 getChildContext() {
1251 return this.props.context;
1252 }
1253 render({ children }) {
1254 return children || null;
1255 }
1256 }
1257
1258 function App(props) {
1259 useEffect(() => {
1260 const query = new URLSearchParams(location.search).get("q");
1261 if (query) chat(query);
1262 }, []);
1263
1264 return html`
1265 <div class="mode-${session.value.type}">
1266 <header>
1267 <div class="grid-container">
1268 <div class="grid-item"></div>
1269 <div class="grid-item"><h1>llama.cpp</h1></div>
1270 <div class="grid-item"><a class="customlink" href="index-new.html">New UI</a></div>
1271 </div>
1272 </header>
1273
1274 <main id="content">
1275 <${chatStarted.value ? ChatLog : ConfigForm} />
1276 </main>
1277
1278 <section id="write">
1279 <${session.value.type === 'chat' ? MessageInput : CompletionControls} />
1280 </section>
1281
1282 <footer>
1283 <p><${ModelGenerationInfo} /></p>
1284 <p>Powered by <a href="https://github.com/ggml-org/llama.cpp">llama.cpp</a> and <a href="https://ggml.ai">ggml.ai</a>.</p>
1285 </footer>
1286 </div>
1287 `;
1288 }
1289
1290 render(h(App), document.querySelector('#container'));
1291 </script>
1292</head>
1293
1294<body>
1295 <div id="container">
1296 <input type="file" id="fileInput" accept="image/*" style="display: none;">
1297 </div>
1298 <div id="portal"></div>
1299</body>
1300
1301</html>