ui: build-time gzip compression (#24571)
* ui: keep original file name and path * fix nocache * ui: build-time gzip compression
This commit is contained in:
@@ -16,6 +16,7 @@ set(HF_VERSION "" CACHE STRING "Version to download (empty = resolve from
|
|||||||
set(HF_ENABLED "" CACHE STRING "Whether to allow HF Bucket download (ON/OFF)")
|
set(HF_ENABLED "" CACHE STRING "Whether to allow HF Bucket download (ON/OFF)")
|
||||||
set(BUILD_UI "" CACHE STRING "Build UI via npm (ON/OFF)")
|
set(BUILD_UI "" CACHE STRING "Build UI via npm (ON/OFF)")
|
||||||
set(LLAMA_UI_EMBED "" CACHE STRING "Path to llama-ui-embed helper")
|
set(LLAMA_UI_EMBED "" CACHE STRING "Path to llama-ui-embed helper")
|
||||||
|
set(LLAMA_UI_GZIP "" CACHE STRING "Apply gzip compress to assets to save bandwidth")
|
||||||
|
|
||||||
set(DIST_DIR "${UI_BINARY_DIR}/dist")
|
set(DIST_DIR "${UI_BINARY_DIR}/dist")
|
||||||
set(SRC_DIST_DIR "${UI_SOURCE_DIR}/dist")
|
set(SRC_DIST_DIR "${UI_SOURCE_DIR}/dist")
|
||||||
@@ -225,6 +226,33 @@ function(hf_download version out_var out_resolved)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(emit_files dist_dir)
|
function(emit_files dist_dir)
|
||||||
|
# If gzip is requested, compress every asset into a parallel _gzip/ tree
|
||||||
|
# the structure stays the same; for ex: /abc/def --> /_gzip/abc/def
|
||||||
|
# embed.cpp will check for _gzip and will pick it up
|
||||||
|
if(LLAMA_UI_GZIP AND EXISTS "${dist_dir}/index.html")
|
||||||
|
find_program(GZIP_EXECUTABLE gzip)
|
||||||
|
if(NOT GZIP_EXECUTABLE)
|
||||||
|
message(WARNING "UI: LLAMA_UI_GZIP requested but gzip not found, embedding uncompressed")
|
||||||
|
else()
|
||||||
|
set(gzip_dir "${dist_dir}/_gzip")
|
||||||
|
file(REMOVE_RECURSE "${gzip_dir}")
|
||||||
|
file(GLOB_RECURSE all_files RELATIVE "${dist_dir}" "${dist_dir}/*")
|
||||||
|
foreach(f ${all_files})
|
||||||
|
get_filename_component(dst_dir "${gzip_dir}/${f}" DIRECTORY)
|
||||||
|
file(MAKE_DIRECTORY "${dst_dir}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GZIP_EXECUTABLE}" -c "${dist_dir}/${f}"
|
||||||
|
OUTPUT_FILE "${gzip_dir}/${f}"
|
||||||
|
RESULT_VARIABLE gz_rc
|
||||||
|
)
|
||||||
|
if(NOT gz_rc EQUAL 0)
|
||||||
|
message(FATAL_ERROR "UI: gzip failed for ${f}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "UI: gzip compression applied (${gzip_dir})")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
set(args "${UI_CPP}" "${UI_H}")
|
set(args "${UI_CPP}" "${UI_H}")
|
||||||
if(EXISTS "${dist_dir}/index.html")
|
if(EXISTS "${dist_dir}/index.html")
|
||||||
list(APPEND args "${dist_dir}")
|
list(APPEND args "${dist_dir}")
|
||||||
|
|||||||
@@ -319,8 +319,26 @@ bool server_http_context::init(const common_params & params) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#if defined(LLAMA_UI_HAS_ASSETS)
|
#if defined(LLAMA_UI_HAS_ASSETS)
|
||||||
|
static auto handle_gzip_header = [](const httplib::Request & req, httplib::Response & res) {
|
||||||
|
if (!llama_ui_use_gzip()) {
|
||||||
|
// no gzip build, skip
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (req.get_header_value("Accept-Encoding").find("gzip") == std::string::npos) {
|
||||||
|
res.status = 415; // unsupported media type
|
||||||
|
res.set_content("Error: gzip is not supported by this browser", "text/plain");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
res.set_header("Content-Encoding", "gzip");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
auto serve_asset_cached = [](const std::string & name, bool isolation) {
|
auto serve_asset_cached = [](const std::string & name, bool isolation) {
|
||||||
return [name, isolation](const httplib::Request & req, httplib::Response & res) {
|
return [name, isolation](const httplib::Request & req, httplib::Response & res) {
|
||||||
|
if (!handle_gzip_header(req, res)) {
|
||||||
|
return true; // returns error message
|
||||||
|
}
|
||||||
const llama_ui_asset * a = llama_ui_find_asset(name);
|
const llama_ui_asset * a = llama_ui_find_asset(name);
|
||||||
if (!a) { res.status = 404; return false; }
|
if (!a) { res.status = 404; return false; }
|
||||||
res.set_header("ETag", a->etag);
|
res.set_header("ETag", a->etag);
|
||||||
@@ -340,7 +358,10 @@ bool server_http_context::init(const common_params & params) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto serve_asset_nocache = [](const std::string & name) {
|
auto serve_asset_nocache = [](const std::string & name) {
|
||||||
return [name](const httplib::Request & /*req*/, httplib::Response & res) {
|
return [name](const httplib::Request & req, httplib::Response & res) {
|
||||||
|
if (!handle_gzip_header(req, res)) {
|
||||||
|
return true; // returns error message
|
||||||
|
}
|
||||||
const llama_ui_asset * a = llama_ui_find_asset(name);
|
const llama_ui_asset * a = llama_ui_find_asset(name);
|
||||||
if (!a) {
|
if (!a) {
|
||||||
res.status = 404;
|
res.status = 404;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
set(TARGET llama-ui)
|
set(TARGET llama-ui)
|
||||||
|
|
||||||
set(LLAMA_UI_HF_BUCKET "ggml-org/llama-ui" CACHE STRING "Hugging Face bucket name for prebuilt UI assets")
|
set(LLAMA_UI_HF_BUCKET "ggml-org/llama-ui" CACHE STRING "Hugging Face bucket name for prebuilt UI assets")
|
||||||
|
set(LLAMA_UI_GZIP ON CACHE BOOL "Apply gzip compress to assets to save bandwidth")
|
||||||
|
|
||||||
# Backward compat: forward old var to new one
|
# Backward compat: forward old var to new one
|
||||||
if(DEFINED LLAMA_BUILD_WEBUI)
|
if(DEFINED LLAMA_BUILD_WEBUI)
|
||||||
@@ -83,6 +84,7 @@ add_custom_target(llama-ui-assets ALL
|
|||||||
"-DHF_ENABLED=${LLAMA_USE_PREBUILT_UI}"
|
"-DHF_ENABLED=${LLAMA_USE_PREBUILT_UI}"
|
||||||
"-DBUILD_UI=${LLAMA_BUILD_UI}"
|
"-DBUILD_UI=${LLAMA_BUILD_UI}"
|
||||||
"-DLLAMA_UI_EMBED=${LLAMA_UI_EMBED_EXE}"
|
"-DLLAMA_UI_EMBED=${LLAMA_UI_EMBED_EXE}"
|
||||||
|
"-DLLAMA_UI_GZIP=${LLAMA_UI_GZIP}"
|
||||||
-P "${PROJECT_SOURCE_DIR}/scripts/ui-assets.cmake"
|
-P "${PROJECT_SOURCE_DIR}/scripts/ui-assets.cmake"
|
||||||
COMMENT "Provisioning UI assets"
|
COMMENT "Provisioning UI assets"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
|
|||||||
+9
-4
@@ -1,7 +1,7 @@
|
|||||||
// llama-ui-embed: generate ui.cpp / ui.h that embed UI assets as C arrays.
|
// llama-ui-embed: generate ui.cpp / ui.h that embed UI assets as C arrays.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// llama-ui-embed <out_cpp> <out_h> [<asset_dir>]
|
// llama-ui-embed <out_cpp> <out_h> <asset_dir>
|
||||||
//
|
//
|
||||||
// Recursively embeds every regular file under <asset_dir>.
|
// Recursively embeds every regular file under <asset_dir>.
|
||||||
// Asset names are relative paths from <asset_dir> (e.g. "_app/immutable/bundle.HASH.js").
|
// Asset names are relative paths from <asset_dir> (e.g. "_app/immutable/bundle.HASH.js").
|
||||||
@@ -147,10 +147,13 @@ int main(int argc, char ** argv) {
|
|||||||
|
|
||||||
const std::string out_cpp = argv[1];
|
const std::string out_cpp = argv[1];
|
||||||
const std::string out_h = argv[2];
|
const std::string out_h = argv[2];
|
||||||
const std::string in_dir = argv[3];
|
const std::string asset_dir = argv[3];
|
||||||
|
|
||||||
|
const bool use_gzip = std::filesystem::exists(asset_dir + "/_gzip");
|
||||||
|
const std::string in_dir = use_gzip ? (asset_dir + "/_gzip") : asset_dir;
|
||||||
|
|
||||||
std::vector<asset_entry> assets;
|
std::vector<asset_entry> assets;
|
||||||
if (argc == 4) {
|
if (!in_dir.empty()) {
|
||||||
const std::filesystem::path dir = in_dir;
|
const std::filesystem::path dir = in_dir;
|
||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
@@ -238,7 +241,8 @@ int main(int argc, char ** argv) {
|
|||||||
" std::string etag;\n"
|
" std::string etag;\n"
|
||||||
" std::string type;\n"
|
" std::string type;\n"
|
||||||
"};\n\n"
|
"};\n\n"
|
||||||
"const llama_ui_asset * llama_ui_find_asset(const std::string & name);\n";
|
"const llama_ui_asset * llama_ui_find_asset(const std::string & name);\n"
|
||||||
|
"bool llama_ui_use_gzip();\n";
|
||||||
h += fmt("const std::array<llama_ui_asset, %d> & llama_ui_get_assets();\n", n_assets);
|
h += fmt("const std::array<llama_ui_asset, %d> & llama_ui_get_assets();\n", n_assets);
|
||||||
|
|
||||||
std::string cpp;
|
std::string cpp;
|
||||||
@@ -294,6 +298,7 @@ int main(int argc, char ** argv) {
|
|||||||
" return empty;\n"
|
" return empty;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
}
|
}
|
||||||
|
cpp += fmt("bool llama_ui_use_gzip() { return %s; }\n", use_gzip ? "true" : "false");
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
ok = write_if_different(out_h, h) && ok;
|
ok = write_if_different(out_h, h) && ok;
|
||||||
|
|||||||
Reference in New Issue
Block a user