mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-03-24 10:18:51 +00:00
feat: add embedded WebUI (#1207)
This commit is contained in:
parent
61d8331ef3
commit
862a6586cb
73
.github/workflows/build.yml
vendored
73
.github/workflows/build.yml
vendored
@ -21,11 +21,13 @@ on:
|
|||||||
"**/*.c",
|
"**/*.c",
|
||||||
"**/*.cpp",
|
"**/*.cpp",
|
||||||
"**/*.cu",
|
"**/*.cu",
|
||||||
|
"examples/server/frontend/**",
|
||||||
]
|
]
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
paths:
|
paths:
|
||||||
[
|
[
|
||||||
|
".github/workflows/**",
|
||||||
"**/CMakeLists.txt",
|
"**/CMakeLists.txt",
|
||||||
"**/Makefile",
|
"**/Makefile",
|
||||||
"**/*.h",
|
"**/*.h",
|
||||||
@ -33,6 +35,7 @@ on:
|
|||||||
"**/*.c",
|
"**/*.c",
|
||||||
"**/*.cpp",
|
"**/*.cpp",
|
||||||
"**/*.cu",
|
"**/*.cu",
|
||||||
|
"examples/server/frontend/**",
|
||||||
]
|
]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@ -53,6 +56,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
@ -106,6 +119,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
@ -174,6 +197,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Get commit hash
|
- name: Get commit hash
|
||||||
id: commit
|
id: commit
|
||||||
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }}
|
||||||
@ -223,6 +256,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
id: depends
|
id: depends
|
||||||
run: |
|
run: |
|
||||||
@ -294,6 +337,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Install cuda-toolkit
|
- name: Install cuda-toolkit
|
||||||
id: cuda-toolkit
|
id: cuda-toolkit
|
||||||
if: ${{ matrix.build == 'cuda12' }}
|
if: ${{ matrix.build == 'cuda12' }}
|
||||||
@ -399,6 +452,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Cache ROCm Installation
|
- name: Cache ROCm Installation
|
||||||
id: cache-rocm
|
id: cache-rocm
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@ -502,6 +565,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9
|
||||||
|
|
||||||
- name: Free disk space
|
- name: Free disk space
|
||||||
run: |
|
run: |
|
||||||
# Remove preinstalled SDKs and caches not needed for this job
|
# Remove preinstalled SDKs and caches not needed for this job
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "ggml"]
|
[submodule "ggml"]
|
||||||
path = ggml
|
path = ggml
|
||||||
url = https://github.com/ggml-org/ggml.git
|
url = https://github.com/ggml-org/ggml.git
|
||||||
|
[submodule "examples/server/frontend"]
|
||||||
|
path = examples/server/frontend
|
||||||
|
url = https://github.com/leejet/stable-ui.git
|
||||||
|
|||||||
@ -1,6 +1,73 @@
|
|||||||
set(TARGET sd-server)
|
set(TARGET sd-server)
|
||||||
|
|
||||||
|
option(SD_SERVER_BUILD_FRONTEND "Build server frontend with pnpm" ON)
|
||||||
|
|
||||||
|
set(FRONTEND_DIR "${CMAKE_CURRENT_SOURCE_DIR}/frontend")
|
||||||
|
set(GENERATED_HTML_HEADER "${FRONTEND_DIR}/dist/gen_index_html.h")
|
||||||
|
|
||||||
|
set(HAVE_FRONTEND_BUILD OFF)
|
||||||
|
|
||||||
|
if(SD_SERVER_BUILD_FRONTEND AND EXISTS "${FRONTEND_DIR}")
|
||||||
|
if(WIN32)
|
||||||
|
find_program(PNPM_EXECUTABLE NAMES pnpm.cmd pnpm)
|
||||||
|
else()
|
||||||
|
find_program(PNPM_EXECUTABLE NAMES pnpm)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(PNPM_EXECUTABLE)
|
||||||
|
message(STATUS "Frontend dir found: ${FRONTEND_DIR}")
|
||||||
|
message(STATUS "pnpm found: ${PNPM_EXECUTABLE}")
|
||||||
|
|
||||||
|
set(HAVE_FRONTEND_BUILD ON)
|
||||||
|
|
||||||
|
add_custom_target(${TARGET}_frontend_install
|
||||||
|
COMMAND "${PNPM_EXECUTABLE}" -C "${FRONTEND_DIR}" install
|
||||||
|
WORKING_DIRECTORY "${FRONTEND_DIR}"
|
||||||
|
COMMENT "Installing frontend dependencies"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(${TARGET}_frontend_build
|
||||||
|
COMMAND "${PNPM_EXECUTABLE}" -C "${FRONTEND_DIR}" run build
|
||||||
|
WORKING_DIRECTORY "${FRONTEND_DIR}"
|
||||||
|
COMMENT "Building frontend"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(${TARGET}_frontend_header
|
||||||
|
COMMAND "${PNPM_EXECUTABLE}" -C "${FRONTEND_DIR}" run build:header
|
||||||
|
WORKING_DIRECTORY "${FRONTEND_DIR}"
|
||||||
|
COMMENT "Generating gen_index_html.h"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(${TARGET}_frontend_build ${TARGET}_frontend_install)
|
||||||
|
add_dependencies(${TARGET}_frontend_header ${TARGET}_frontend_build)
|
||||||
|
|
||||||
|
add_custom_target(${TARGET}_frontend
|
||||||
|
DEPENDS ${TARGET}_frontend_header
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties("${GENERATED_HTML_HEADER}" PROPERTIES GENERATED TRUE)
|
||||||
|
else()
|
||||||
|
message(WARNING "pnpm not found, frontend build disabled")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "Frontend disabled or directory not found: ${FRONTEND_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(${TARGET} main.cpp)
|
add_executable(${TARGET} main.cpp)
|
||||||
|
|
||||||
|
if(HAVE_FRONTEND_BUILD)
|
||||||
|
add_dependencies(${TARGET} ${TARGET}_frontend)
|
||||||
|
target_sources(${TARGET} PRIVATE "${GENERATED_HTML_HEADER}")
|
||||||
|
target_include_directories(${TARGET} PRIVATE "${FRONTEND_DIR}/dist")
|
||||||
|
target_compile_definitions(${TARGET} PRIVATE HAVE_INDEX_HTML)
|
||||||
|
message(STATUS "HAVE_INDEX_HTML enabled")
|
||||||
|
else()
|
||||||
|
message(STATUS "HAVE_INDEX_HTML disabled")
|
||||||
|
endif()
|
||||||
|
|
||||||
install(TARGETS ${TARGET} RUNTIME)
|
install(TARGETS ${TARGET} RUNTIME)
|
||||||
target_link_libraries(${TARGET} PRIVATE stable-diffusion ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(${TARGET} PRIVATE stable-diffusion ${CMAKE_THREAD_LIBS_INIT})
|
||||||
target_compile_features(${TARGET} PUBLIC c_std_11 cxx_std_17)
|
target_compile_features(${TARGET} PUBLIC c_std_11 cxx_std_17)
|
||||||
@ -1,3 +1,92 @@
|
|||||||
|
# Frontend
|
||||||
|
|
||||||
|
## Build with Frontend
|
||||||
|
|
||||||
|
The server can optionally build the web frontend and embed it into the binary as `gen_index_html.h`.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
Install the following tools:
|
||||||
|
|
||||||
|
* **Node.js** ≥ 22.18
|
||||||
|
https://nodejs.org/
|
||||||
|
|
||||||
|
* **pnpm** ≥ 10
|
||||||
|
Install via npm:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g pnpm
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node -v
|
||||||
|
pnpm -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install frontend dependencies
|
||||||
|
|
||||||
|
Go to the frontend directory and install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd examples/server/frontend
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build the server with CMake
|
||||||
|
|
||||||
|
Enable the frontend build option when configuring CMake:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DSD_SERVER_BUILD_FRONTEND=ON
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
If `pnpm` is available, the build system will automatically run:
|
||||||
|
|
||||||
|
```
|
||||||
|
pnpm run build
|
||||||
|
pnpm run build:header
|
||||||
|
```
|
||||||
|
|
||||||
|
and embed the generated frontend into the server binary.
|
||||||
|
|
||||||
|
## Frontend Repository
|
||||||
|
|
||||||
|
The web frontend is maintained in a **separate repository**, https://github.com/leejet/stable-ui.
|
||||||
|
|
||||||
|
If you want to modify the UI or frontend logic, please submit pull requests to the **frontend repository**.
|
||||||
|
|
||||||
|
This repository (`stable-diffusion.cpp`) only vendors the frontend periodically. Changes from the frontend repo are synchronized:
|
||||||
|
|
||||||
|
* approximately **every 1–2 weeks**, or
|
||||||
|
* when there are **major frontend updates**
|
||||||
|
|
||||||
|
Because of this, frontend changes will **not appear here immediately** after being merged upstream.
|
||||||
|
|
||||||
|
## Using an external frontend
|
||||||
|
|
||||||
|
By default, the server uses the **embedded frontend** generated during the build (`gen_index_html.h`).
|
||||||
|
|
||||||
|
You can also serve a custom frontend file instead of the embedded one by using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--serve-html-path <path-to-index.html>
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sd-server --serve-html-path ./index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, the server will load and serve the specified `index.html` file instead of the embedded frontend. This is useful when:
|
||||||
|
|
||||||
|
* developing or testing frontend changes
|
||||||
|
* using a custom UI
|
||||||
|
* avoiding rebuilding the binary after frontend modifications
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
1
examples/server/frontend
Submodule
1
examples/server/frontend
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 1a34176cd6d39ad3a226b2b69047e71f6797f6bc
|
||||||
@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
#include "common/common.hpp"
|
#include "common/common.hpp"
|
||||||
|
|
||||||
|
#ifdef HAVE_INDEX_HTML
|
||||||
|
#include "frontend/dist/gen_index_html.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
// ----------------------- helpers -----------------------
|
// ----------------------- helpers -----------------------
|
||||||
@ -380,7 +384,13 @@ int main(int argc, const char** argv) {
|
|||||||
return httplib::Server::HandlerResponse::Unhandled;
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
});
|
});
|
||||||
|
|
||||||
// root
|
// index html
|
||||||
|
std::string index_html;
|
||||||
|
#ifdef HAVE_INDEX_HTML
|
||||||
|
index_html.assign(reinterpret_cast<const char*>(index_html_bytes), index_html_size);
|
||||||
|
#else
|
||||||
|
index_html = "Stable Diffusion Server is running";
|
||||||
|
#endif
|
||||||
svr.Get("/", [&](const httplib::Request&, httplib::Response& res) {
|
svr.Get("/", [&](const httplib::Request&, httplib::Response& res) {
|
||||||
if (!svr_params.serve_html_path.empty()) {
|
if (!svr_params.serve_html_path.empty()) {
|
||||||
std::ifstream file(svr_params.serve_html_path);
|
std::ifstream file(svr_params.serve_html_path);
|
||||||
@ -392,7 +402,7 @@ int main(int argc, const char** argv) {
|
|||||||
res.set_content("Error: Unable to read HTML file", "text/plain");
|
res.set_content("Error: Unable to read HTML file", "text/plain");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.set_content("Stable Diffusion Server is running", "text/plain");
|
res.set_content(index_html, "text/html");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user