diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..06c85ad56e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+# Treat the generated single-file WebUI build as binary for diff purposes.
+# Git's pack-file delta compression still works (byte-level), but this prevents
+# git diff from printing the entire minified file on every change.
+tools/server/public/index.html -diff
diff --git a/.gitignore b/.gitignore
index 73954e8f5d..7997029849 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,6 +95,8 @@
# Server Web UI temporary files
/tools/server/webui/node_modules
/tools/server/webui/dist
+# we no longer use gz for index.html
+/tools/server/public/index.html.gz
# Python
diff --git a/tools/server/CMakeLists.txt b/tools/server/CMakeLists.txt
index fc4cb5dcc8..6520ca4902 100644
--- a/tools/server/CMakeLists.txt
+++ b/tools/server/CMakeLists.txt
@@ -38,7 +38,7 @@ set(TARGET_SRCS
server-models.h
)
set(PUBLIC_ASSETS
- index.html.gz
+ index.html
loading.html
)
diff --git a/tools/server/README-dev.md b/tools/server/README-dev.md
index 1dd00b72e4..a9c1e7385f 100644
--- a/tools/server/README-dev.md
+++ b/tools/server/README-dev.md
@@ -259,6 +259,6 @@ npm run test
npm run build
```
-After `public/index.html.gz` has been generated, rebuild `llama-server` as described in the [build](#build) section to include the updated UI.
+After `public/index.html` has been generated, rebuild `llama-server` as described in the [build](#build) section to include the updated UI.
**Note:** The Vite dev server automatically proxies API requests to `http://localhost:8080`. Make sure `llama-server` is running on that port during development.
diff --git a/tools/server/public/index.html b/tools/server/public/index.html
new file mode 100644
index 0000000000..5767e2045b
--- /dev/null
+++ b/tools/server/public/index.html
@@ -0,0 +1,508 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz
deleted file mode 100644
index adc7939d3b..0000000000
Binary files a/tools/server/public/index.html.gz and /dev/null differ
diff --git a/tools/server/server-http.cpp b/tools/server/server-http.cpp
index 3466512d0c..69cdb4ecba 100644
--- a/tools/server/server-http.cpp
+++ b/tools/server/server-http.cpp
@@ -9,7 +9,7 @@
#include
// auto generated files (see README.md for details)
-#include "index.html.gz.hpp"
+#include "index.html.hpp"
#include "loading.html.hpp"
//
@@ -256,16 +256,11 @@ bool server_http_context::init(const common_params & params) {
}
} else {
// using embedded static index.html
- srv->Get(params.api_prefix + "/", [](const httplib::Request & req, httplib::Response & res) {
- if (req.get_header_value("Accept-Encoding").find("gzip") == std::string::npos) {
- res.set_content("Error: gzip is not supported by this browser", "text/plain");
- } else {
- res.set_header("Content-Encoding", "gzip");
- // COEP and COOP headers, required by pyodide (python interpreter)
- res.set_header("Cross-Origin-Embedder-Policy", "require-corp");
- res.set_header("Cross-Origin-Opener-Policy", "same-origin");
- res.set_content(reinterpret_cast(index_html_gz), index_html_gz_len, "text/html; charset=utf-8");
- }
+ srv->Get(params.api_prefix + "/", [](const httplib::Request & /*req*/, httplib::Response & res) {
+ // COEP and COOP headers, required by pyodide (python interpreter)
+ res.set_header("Cross-Origin-Embedder-Policy", "require-corp");
+ res.set_header("Cross-Origin-Opener-Policy", "same-origin");
+ res.set_content(reinterpret_cast(index_html), index_html_len, "text/html; charset=utf-8");
return false;
});
}
diff --git a/tools/server/webui/package.json b/tools/server/webui/package.json
index f5cdc9e47f..c417638ea4 100644
--- a/tools/server/webui/package.json
+++ b/tools/server/webui/package.json
@@ -50,7 +50,6 @@
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-storybook": "^10.2.4",
"eslint-plugin-svelte": "^3.0.0",
- "fflate": "^0.8.2",
"globals": "^16.0.0",
"http-server": "^14.1.1",
"mdast": "^3.0.0",
diff --git a/tools/server/webui/scripts/install-git-hooks.sh b/tools/server/webui/scripts/install-git-hooks.sh
index d14e281389..f4ca3f6eef 100755
--- a/tools/server/webui/scripts/install-git-hooks.sh
+++ b/tools/server/webui/scripts/install-git-hooks.sh
@@ -83,7 +83,7 @@ if [ -n "$WEBUI_CHANGES" ]; then
fi
# Check if build output exists and is newer than source files
- BUILD_FILE="../public/index.html.gz"
+ BUILD_FILE="../public/index.html"
NEEDS_BUILD=false
if [ ! -f "$BUILD_FILE" ]; then
@@ -127,9 +127,9 @@ if [ -n "$WEBUI_CHANGES" ]; then
cd ../../..
# Check if build output was created/updated
- if [ -f "tools/server/public/index.html.gz" ]; then
+ if [ -f "tools/server/public/index.html" ]; then
# Add the build output and commit it
- git add tools/server/public/index.html.gz
+ git add tools/server/public/index.html
if ! git diff --cached --quiet; then
echo "Committing updated build output..."
git commit -m "chore: update webui build output"
diff --git a/tools/server/webui/scripts/post-build.sh b/tools/server/webui/scripts/post-build.sh
index a49d6cc107..55e46d5d5c 100755
--- a/tools/server/webui/scripts/post-build.sh
+++ b/tools/server/webui/scripts/post-build.sh
@@ -1,3 +1,3 @@
rm -rf ../public/_app;
rm ../public/favicon.svg;
-rm ../public/index.html;
+rm -f ../public/index.html.gz; # deprecated, but may still be generated by older versions of the build process
diff --git a/tools/server/webui/vite.config.ts b/tools/server/webui/vite.config.ts
index e4408f09e4..af6234b763 100644
--- a/tools/server/webui/vite.config.ts
+++ b/tools/server/webui/vite.config.ts
@@ -1,6 +1,5 @@
import tailwindcss from '@tailwindcss/vite';
import { sveltekit } from '@sveltejs/kit/vite';
-import * as fflate from 'fflate';
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
@@ -20,15 +19,13 @@ const GUIDE_FOR_FRONTEND = `
-->
`.trim();
-const MAX_BUNDLE_SIZE = 2 * 1024 * 1024;
-
/**
* the maximum size of an embedded asset in bytes,
* e.g. maximum size of embedded font (see node_modules/katex/dist/fonts/*.woff2)
*/
const MAX_ASSET_SIZE = 32000;
-/** public/index.html.gz minified flag */
+/** public/index.html minified flag */
const ENABLE_JS_MINIFICATION = true;
function llamaCppBuildPlugin() {
@@ -40,7 +37,6 @@ function llamaCppBuildPlugin() {
setTimeout(() => {
try {
const indexPath = resolve('../public/index.html');
- const gzipPath = resolve('../public/index.html.gz');
if (!existsSync(indexPath)) {
return;
@@ -62,25 +58,10 @@ function llamaCppBuildPlugin() {
content = content.replace(/\r/g, '');
content = GUIDE_FOR_FRONTEND + '\n' + content;
- const compressed = fflate.gzipSync(Buffer.from(content, 'utf-8'), { level: 9 });
-
- compressed[0x4] = 0;
- compressed[0x5] = 0;
- compressed[0x6] = 0;
- compressed[0x7] = 0;
- compressed[0x9] = 0;
-
- if (compressed.byteLength > MAX_BUNDLE_SIZE) {
- throw new Error(
- `Bundle size is too large (${Math.ceil(compressed.byteLength / 1024)} KB).\n` +
- `Please reduce the size of the frontend or increase MAX_BUNDLE_SIZE in vite.config.ts.\n`
- );
- }
-
- writeFileSync(gzipPath, compressed);
- console.log('✓ Created index.html.gz');
+ writeFileSync(indexPath, content, 'utf-8');
+ console.log('✓ Updated index.html');
} catch (error) {
- console.error('Failed to create gzip file:', error);
+ console.error('Failed to update index.html:', error);
}
}, 100);
}