diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 65ae5ec..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.DS_Store
-/zig-cache/
-/zig-out/
-/node_modules/
-/src/app/dist/
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 81bc6f3..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "llama.cpp"]
- path = llama.cpp
- url = https://github.com/ggerganov/llama.cpp
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 76f5567..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "editor.formatOnSave": true,
-
- "[javascript][json][jsonc][typescript][typescriptreact][javascriptreact][html][css][markdown]": {
- "editor.defaultFormatter": "esbenp.prettier-vscode"
- },
- "[swift][c][cpp]": {
- "editor.tabSize": 4
- },
- "[sql]": {
- "editor.defaultFormatter": "adpyke.vscode-sql-formatter"
- }
-}
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index 2f8a332..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,161 +0,0 @@
-MIT License
-
-Copyright (c) 2023 Kamil Tomšík
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-**Open-Source Acknowledgment**
-
-This Software, "Ava PLS", incorporates and uses open-source software components.
-The use of these components is acknowledged herein, and their respective
-licenses are included below. By using Ava PLS, you acknowledge and agree to
-respect and comply with the terms and conditions of the following open-source
-licenses.
-
-**List of Open-Source Software Components**
-
-1. [Zig language](https://ziglang.org/) - MIT
-2. [llama.cpp](https://github.com/ggerganov/llama.cpp) - MIT
-3. [Preact](https://preactjs.com/) - MIT
-4. [Twind](https://twind.style/) - MIT
-5. [Lucide](https://github.com/lucide-icons/lucide) - MIT
-
----
-
-**Zig License**
-
-The MIT License (Expat)
-
-Copyright (c) Zig contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
----
-
-**llamma.cpp License**
-
-MIT License
-
-Copyright (c) 2023 Georgi Gerganov
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
-
-**Preact License**
-
-The MIT License (MIT)
-
-Copyright (c) 2015-present Jason Miller
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
-
-**Twind License**
-
-MIT License
-
-Copyright (c) 2022 [these people](https://github.com/tw-in-js/twind/graphs/contributors)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
-
-**Lucide License**
-
-ISC License
-
-Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index 3e51db6..0000000
--- a/README.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Ava PLS
-
-Air-gapped Virtual Assistant / Personal Language Server\
-[Website](https://avapls.com) | [Twitter](https://twitter.com/cztomsik) | [Discord](https://discord.gg/C47qUJPkkf)
-
-https://github.com/cztomsik/ava/assets/3526922/790dd1a2-5e59-4a63-a05a-f255b5677269
-
-https://github.com/cztomsik/ava/assets/3526922/22dce230-3d91-476d-83b7-22ddcc41fb87
-
-https://github.com/cztomsik/ava/assets/3526922/64f16a97-6575-4006-bb81-c46e1f5cfcaa
-
-https://github.com/cztomsik/ava/assets/3526922/1dcf38a5-cfc9-4b20-9f2e-deb15145d964
-
-## Tech stack
-
-- Zig, C++, Swift UI, SQLite
-- Preact, Preact Signals, Twind
-
-## Local Development
-
-Make sure you have:
-
-- [Zig 0.12.0-dev.1769+bf5ab5451](https://ziglang.org/download/)
-- [Node.js 20.5.1](https://nodejs.org/)
- - only needed for fetching dependencies
-- Xcode (for macOS)
-- pkg-config (`brew install pkg-config`)
-
-```bash
-npm install
-npm run watch
-zig build && ./zig-out/bin/ava_aarch64 # or ./zig-out/bin/ava_x86_64
-```
-
-## Headless mode (works on Linux!)
-
-It is now possible to build Ava in headless mode. This will start a server
-and you can connect to it using a web browser.
-
-This is useful if you want to deploy Ava somewhere and connect to it remotely,
-or if you are using Linux, because we don't have Qt/GTK support yet.
-
-```bash
-zig build -Dheadless=true && ./zig-out/bin/ava_aarch64 # or ./zig-out/bin/ava_x86_64
-```
-
-## macOS 12.6+ (Monterey)
-
-Xcode is needed because of Swift UI
-
-```
-sudo xcode-select -switch /Applications/Xcode.app
-```
-
-## Production build
-
-```bash
-./src/macos/create_dmg.sh
-```
-
-Or on Windows:
-
-```bash
-./src/windows/create_zip.sh
-```
-
-## License
-
-MIT
-
-## Contributing
-
-Bug reports and pull requests are welcome but if you want to do a bigger change, please open an issue first to discuss it.
diff --git a/_gui.zig b/_gui.zig
deleted file mode 100644
index 93283ab..0000000
--- a/_gui.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-// Zig has recently disallowed usage of @embedFile outside of the package path,
-// which is where the root source file is located. We need to @embedFile
-// both README.md and zig-out/app/main.js so this is a workaround for that.
-//
-// On top of that, we can easily switch between headless and GUI mode just by
-// changing the root source file.
-pub usingnamespace @import("src/main.zig");
-
-pub usingnamespace if (@import("builtin").os.tag == .windows) @import("src/windows/winmain.zig") else struct {};
diff --git a/_headless.zig b/_headless.zig
deleted file mode 100644
index 696f63b..0000000
--- a/_headless.zig
+++ /dev/null
@@ -1,8 +0,0 @@
-// Zig has recently disallowed usage of @embedFile outside of the package path,
-// which is where the root source file is located. We need to @embedFile
-// both README.md and zig-out/app/main.js so this is a workaround for that.
-//
-// On top of that, we can easily switch between headless and GUI mode just by
-// changing the root source file.
-pub usingnamespace @import("src/main.zig");
-pub usingnamespace @import("src/cli.zig");
diff --git a/build.zig b/build.zig
deleted file mode 100644
index b83edba..0000000
--- a/build.zig
+++ /dev/null
@@ -1,99 +0,0 @@
-const std = @import("std");
-
-pub fn build(b: *std.Build) !void {
- // const target_query = b.standardTargetOptionsQueryOnly(.{});
- // if (target.query.os_tag == .macos and target.query.os_version_min == null) {
- // target.query.os_version_min = .{ .semver = try std.SemanticVersion.parse("12.6.0") };
- // std.log.debug("Setting macOS deployment target to {}", .{target.query.os_version_min.?});
- // }
-
- const target = b.standardTargetOptions(.{});
- const optimize = b.standardOptimizeOption(.{});
- const headless = b.option(bool, "headless", "Build headless webserver") orelse false;
-
- const options = .{
- .name = "ava",
- .root_source_file = .{ .path = if (headless) "_headless.zig" else "_gui.zig" },
- .target = target,
- .optimize = optimize,
-
- // For some reason, linux binaries are huge. Strip them in release mode.
- .strip = optimize != .Debug,
- };
-
- if (headless) {
- try buildExe(b, b.addExecutable(options));
- } else switch (target.result.os.tag) {
- .macos => try buildExe(b, @import("src/macos/BuildMacos.zig").create(b, options)),
- .windows => try buildExe(b, @import("src/windows/BuildWindows.zig").create(b, options)),
- else => return error.UnsupportedOs,
- }
-}
-
-fn buildExe(b: *std.Build, exe: anytype) !void {
- exe.addIncludePath(.{ .path = "llama.cpp" });
-
- const sqlite = b.dependency("ava-sqlite", .{ .bundle = exe.rootModuleTarget().os.tag != .macos });
- exe.root_module.addImport("ava-sqlite", sqlite.module("ava-sqlite"));
- if (@hasField(@TypeOf(exe.*), "sdk")) sqlite.module("ava-sqlite").addSystemIncludePath(.{ .path = b.fmt("{s}/usr/include", .{exe.sdk}) });
-
- try addLlama(b, exe);
-
- const suffix = if (exe.rootModuleTarget().os.tag == .windows) ".exe" else "";
- const bin = b.addInstallBinFile(exe.getEmittedBin(), b.fmt("ava_{s}{s}", .{ @tagName(exe.rootModuleTarget().cpu.arch), suffix }));
- b.getInstallStep().dependOn(&bin.step);
-}
-
-fn addLlama(b: *std.Build, exe: anytype) !void {
- const cflags = try flags(b, exe, &.{"-std=c11"});
- const cxxflags = try flags(b, exe, &.{"-std=c++11"});
-
- const sources: []const []const u8 = &.{
- "ggml.c",
- "ggml-alloc.c",
- "ggml-backend.c",
- "ggml-quants.c",
- "ggml-metal.m",
- "llama.cpp",
- };
-
- for (sources) |f| {
- const is_cpp = std.mem.endsWith(u8, f, ".cpp");
- if (std.mem.endsWith(u8, f, ".m") and exe.rootModuleTarget().os.tag != .macos) continue;
-
- const o = b.addObject(.{
- .name = std.fs.path.basename(f),
- .target = exe.root_module.resolved_target.?,
- .optimize = .ReleaseFast, // always optimize llama.cpp
- });
-
- o.defineCMacro("_GNU_SOURCE", null);
- o.addIncludePath(.{ .path = "llama.cpp" });
- o.addCSourceFile(.{ .file = .{ .path = b.pathJoin(&.{ "llama.cpp", f }) }, .flags = if (is_cpp) cxxflags else cflags });
- if (is_cpp) o.linkLibCpp() else o.linkLibC();
- if (@hasField(@TypeOf(exe.*), "sdk")) exe.applySDK(o);
- exe.addObject(o);
- }
-
- if (exe.rootModuleTarget().os.tag == .macos) {
- exe.linkFramework("Foundation");
- exe.linkFramework("Metal");
- exe.linkFramework("MetalKit");
-
- // Copy the *.metal file so that it can be loaded at runtime
- const copy_metal_step = b.addInstallBinFile(.{ .path = "llama.cpp/ggml-metal.metal" }, "ggml-metal.metal");
- b.getInstallStep().dependOn(©_metal_step.step);
- }
-}
-
-fn flags(b: *std.Build, exe: anytype, prefix: []const []const u8) ![]const []const u8 {
- var res = std.ArrayList([]const u8).init(b.allocator);
- try res.appendSlice(prefix);
- try res.appendSlice(&.{ "-fPIC", "-Ofast", "-DNDEBUG", "-DGGML_USE_K_QUANTS" });
-
- if (exe.rootModuleTarget().os.tag == .macos) {
- try res.appendSlice(&.{ "-DGGML_USE_METAL", "-DGGML_METAL_NDEBUG" });
- }
-
- return res.items;
-}
diff --git a/build.zig.zon b/build.zig.zon
deleted file mode 100644
index b7fa504..0000000
--- a/build.zig.zon
+++ /dev/null
@@ -1,14 +0,0 @@
-.{
- .name = "ava",
- .version = "0.0.1",
-
- .dependencies = .{
- .@"ava-sqlite" = .{
- .url = "https://github.com/cztomsik/ava-sqlite/archive/c48ac06.tar.gz",
- .hash = "122049ceedb98046f5d3362145b5f67a93d52d33a7a5357885795971be2f5bffcd45",
- },
- },
- .paths = .{
- "",
- },
-}
diff --git a/include/ava.h b/include/ava.h
deleted file mode 100644
index 8b9a84c..0000000
--- a/include/ava.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// API for the AVA HTTP server
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int ava_start();
-int ava_stop();
-int ava_get_port();
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/website/index.html b/index.html
similarity index 100%
rename from website/index.html
rename to index.html
diff --git a/llama.cpp b/llama.cpp
deleted file mode 160000
index 1912211..0000000
--- a/llama.cpp
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 191221178f51b6e81122c5bda0fd79620e547d07
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 310ae76..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,566 +0,0 @@
-{
- "name": "ava",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "ava",
- "hasInstallScript": true,
- "dependencies": {
- "@preact/signals": "^1.1.5",
- "@twind/core": "^1.1.3",
- "@twind/preset-radix-ui": "^1.0.7",
- "@twind/preset-tailwind": "^1.1.4",
- "lucide": "^0.284.0",
- "preact": "^10.16.0"
- },
- "devDependencies": {
- "esbuild": "^0.18.20",
- "typescript": "^5.0.2",
- "undom": "^0.4.0"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
- "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
- "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
- "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
- "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
- "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
- "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
- "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
- "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
- "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
- "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
- "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
- "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
- "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
- "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
- "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
- "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
- "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
- "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
- "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
- "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
- "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
- "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@preact/signals": {
- "version": "1.1.5",
- "license": "MIT",
- "dependencies": {
- "@preact/signals-core": "^1.3.1"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- },
- "peerDependencies": {
- "preact": "10.x"
- }
- },
- "node_modules/@preact/signals-core": {
- "version": "1.3.1",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- }
- },
- "node_modules/@twind/core": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@twind/core/-/core-1.1.3.tgz",
- "integrity": "sha512-/B/aNFerMb2IeyjSJy3SJxqVxhrT77gBDknLMiZqXIRr4vNJqiuhx7KqUSRzDCwUmyGuogkamz+aOLzN6MeSLw==",
- "funding": [
- {
- "type": "Open Collective",
- "url": "https://opencollective.com/twind"
- },
- {
- "type": "Github Sponsor",
- "url": "https://github.com/sponsors/tw-in-js"
- },
- {
- "type": "Ko-fi",
- "url": "https://ko-fi.com/twind"
- }
- ],
- "dependencies": {
- "csstype": "^3.1.1"
- },
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "typescript": "^4.8.4"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@twind/preset-radix-ui": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/@twind/preset-radix-ui/-/preset-radix-ui-1.0.7.tgz",
- "integrity": "sha512-EyQtZ/PqTA4Cf5qOc8Gjy56ZwZMd5Nk+Zsm4ZRE8b7fdiMhH3FbCSXjCUeFluSgaIhdMbaVHV2AOa6Z0RBSkBQ==",
- "funding": [
- {
- "type": "Open Collective",
- "url": "https://opencollective.com/twind"
- },
- {
- "type": "Github Sponsor",
- "url": "https://github.com/sponsors/tw-in-js"
- },
- {
- "type": "Ko-fi",
- "url": "https://ko-fi.com/twind"
- }
- ],
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "@twind/core": "^1.1.0",
- "typescript": "^4.8.4"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@twind/preset-tailwind": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@twind/preset-tailwind/-/preset-tailwind-1.1.4.tgz",
- "integrity": "sha512-zv85wrP/DW4AxgWrLfH7kyGn/KJF3K04FMLVl2AjoxZGYdCaoZDkL8ma3hzaKQ+WGgBFRubuB/Ku2Rtv/wjzVw==",
- "funding": [
- {
- "type": "Open Collective",
- "url": "https://opencollective.com/twind"
- },
- {
- "type": "Github Sponsor",
- "url": "https://github.com/sponsors/tw-in-js"
- },
- {
- "type": "Ko-fi",
- "url": "https://ko-fi.com/twind"
- }
- ],
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "@twind/core": "^1.1.0",
- "typescript": "^4.8.4"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/csstype": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
- },
- "node_modules/esbuild": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
- "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/android-arm": "0.18.20",
- "@esbuild/android-arm64": "0.18.20",
- "@esbuild/android-x64": "0.18.20",
- "@esbuild/darwin-arm64": "0.18.20",
- "@esbuild/darwin-x64": "0.18.20",
- "@esbuild/freebsd-arm64": "0.18.20",
- "@esbuild/freebsd-x64": "0.18.20",
- "@esbuild/linux-arm": "0.18.20",
- "@esbuild/linux-arm64": "0.18.20",
- "@esbuild/linux-ia32": "0.18.20",
- "@esbuild/linux-loong64": "0.18.20",
- "@esbuild/linux-mips64el": "0.18.20",
- "@esbuild/linux-ppc64": "0.18.20",
- "@esbuild/linux-riscv64": "0.18.20",
- "@esbuild/linux-s390x": "0.18.20",
- "@esbuild/linux-x64": "0.18.20",
- "@esbuild/netbsd-x64": "0.18.20",
- "@esbuild/openbsd-x64": "0.18.20",
- "@esbuild/sunos-x64": "0.18.20",
- "@esbuild/win32-arm64": "0.18.20",
- "@esbuild/win32-ia32": "0.18.20",
- "@esbuild/win32-x64": "0.18.20"
- }
- },
- "node_modules/lucide": {
- "version": "0.284.0",
- "resolved": "https://registry.npmjs.org/lucide/-/lucide-0.284.0.tgz",
- "integrity": "sha512-wn58Gg9Vo2R5Jno32QC91muetNw5BtwY9rni5j9KNxJwvwWl2etDQng1n5hnnHfgJg8rl+FJkwCEqTEm2g152w=="
- },
- "node_modules/preact": {
- "version": "10.16.0",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- }
- },
- "node_modules/typescript": {
- "version": "5.1.6",
- "devOptional": true,
- "license": "Apache-2.0",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/undom": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/undom/-/undom-0.4.0.tgz",
- "integrity": "sha512-8azrUL2oaprTIKl//+dbx9BMDt3kW1TyBfRpYdemK1zBJe63AUu6O28nzv/Fx1maJAtkwlD8a6312MqomDYFOg==",
- "dev": true
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index 393655b..0000000
--- a/package.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "private": true,
- "name": "ava",
- "module": "main.tsx",
- "type": "module",
- "scripts": {
- "postinstall": "git submodule update --init --recursive",
- "bundle": "esbuild ./src/app/main.tsx --bundle --outdir=./zig-out/app",
- "build": "npm run check && npm test && npm run bundle -- --minify --define:DEV=false --define:NEXT=false",
- "watch": "npm run bundle -- --sourcemap=inline --watch --define:DEV=true --define:NEXT=true",
- "check": "tsc --noEmit",
- "test": "node --loader ./src/app/_test-util/loader.js --test ./src/app/*/*.test.*"
- },
- "prettier": {
- "semi": false,
- "arrowParens": "avoid",
- "printWidth": 125
- },
- "dependencies": {
- "@preact/signals": "^1.1.5",
- "@twind/core": "^1.1.3",
- "@twind/preset-radix-ui": "^1.0.7",
- "@twind/preset-tailwind": "^1.1.4",
- "lucide": "^0.284.0",
- "preact": "^10.16.0"
- },
- "devDependencies": {
- "esbuild": "^0.18.20",
- "typescript": "^5.0.2",
- "undom": "^0.4.0"
- },
- "overrides": {
- "typescript": "^5.0.2"
- }
-}
diff --git a/website/screenshot.png b/screenshot.png
similarity index 100%
rename from website/screenshot.png
rename to screenshot.png
diff --git a/src/api.zig b/src/api.zig
deleted file mode 100644
index 21d7f0b..0000000
--- a/src/api.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const std = @import("std");
-
-pub usingnamespace @import("api/chat.zig");
-pub usingnamespace @import("api/download.zig");
-pub usingnamespace @import("api/find-models.zig");
-pub usingnamespace @import("api/generate.zig");
-pub usingnamespace @import("api/log.zig");
-pub usingnamespace @import("api/models.zig");
-pub usingnamespace @import("api/prompts.zig");
-pub usingnamespace @import("api/proxy.zig");
-pub usingnamespace @import("api/system-info.zig");
diff --git a/src/api/chat.zig b/src/api/chat.zig
deleted file mode 100644
index ba8a3da..0000000
--- a/src/api/chat.zig
+++ /dev/null
@@ -1,83 +0,0 @@
-const db = @import("../db.zig");
-const server = @import("../server.zig");
-
-pub fn @"GET /chat"(ctx: *server.Context) !void {
- var stmt = try db.query(
- \\SELECT id, name,
- \\(SELECT content FROM ChatMessage WHERE chat_id = Chat.id ORDER BY id DESC LIMIT 1) as last_message
- \\FROM Chat ORDER BY id DESC
- , .{});
- defer stmt.deinit();
-
- return ctx.sendJson(stmt.iterator(struct { id: u32, name: []const u8, last_message: ?[]const u8 }));
-}
-
-pub fn @"POST /chat"(ctx: *server.Context) !void {
- const data = try ctx.readJson(struct {
- name: []const u8,
- prompt: ?[]const u8,
- });
-
- var stmt = try db.query("INSERT INTO Chat (name, prompt) VALUES (?, ?) RETURNING *", .{ data.name, data.prompt });
- defer stmt.deinit();
-
- try ctx.sendJson(try stmt.read(db.Chat));
-}
-
-pub fn @"GET /chat/:id"(ctx: *server.Context, id: u32) !void {
- var stmt = try db.query("SELECT * FROM Chat WHERE id = ?", .{id});
- defer stmt.deinit();
-
- return ctx.sendJson(try stmt.read(db.Chat));
-}
-
-pub fn @"PUT /chat/:id"(ctx: *server.Context, id: u32, data: db.Chat) !void {
- try db.exec("UPDATE Chat SET name = ?, prompt = ? WHERE id = ?", .{ data.name, data.prompt, id });
- return ctx.noContent();
-}
-
-pub fn @"GET /chat/:id/messages"(ctx: *server.Context, id: u32) !void {
- var stmt = try db.query("SELECT * FROM ChatMessage WHERE chat_id = ? ORDER BY id", .{id});
- defer stmt.deinit();
-
- return ctx.sendJson(stmt.iterator(db.ChatMessage));
-}
-
-pub fn @"POST /chat/:id/messages"(ctx: *server.Context, id: u32) !void {
- const data = try ctx.readJson(struct {
- role: []const u8,
- content: []const u8,
- });
-
- var stmt = try db.query("INSERT INTO ChatMessage (chat_id, role, content) VALUES (?, ?, ?) RETURNING *", .{ id, data.role, data.content });
- defer stmt.deinit();
-
- try ctx.sendJson(try stmt.read(db.ChatMessage));
-}
-
-pub fn @"GET /chat/:id/messages/:message_id"(ctx: *server.Context, id: u32, message_id: u32) !void {
- var stmt = try db.query("SELECT * FROM ChatMessage WHERE id = ? AND chat_id = ?", .{ message_id, id });
- defer stmt.deinit();
-
- return ctx.sendJson(try stmt.read(db.ChatMessage));
-}
-
-pub fn @"PUT /chat/:id/messages/:message_id"(ctx: *server.Context, id: u32, message_id: u32) !void {
- const data = try ctx.readJson(struct {
- role: []const u8,
- content: []const u8,
- });
-
- try db.exec("UPDATE ChatMessage SET role = ?, content = ? WHERE id = ? AND chat_id = ?", .{ data.role, data.content, message_id, id });
- return ctx.noContent();
-}
-
-pub fn @"DELETE /chat/:id/messages/:message_id"(ctx: *server.Context, id: u32, message_id: u32) !void {
- try db.exec("DELETE FROM ChatMessage WHERE id = ? AND chat_id = ?", .{ message_id, id });
- return ctx.noContent();
-}
-
-pub fn @"DELETE /chat/:id"(ctx: *server.Context, id: u32) !void {
- try db.exec("DELETE FROM Chat WHERE id = ?", .{id});
- return ctx.noContent();
-}
diff --git a/src/api/download.zig b/src/api/download.zig
deleted file mode 100644
index a11d9ba..0000000
--- a/src/api/download.zig
+++ /dev/null
@@ -1,59 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const server = @import("../server.zig");
-const util = @import("../util.zig");
-
-pub fn @"POST /download"(ctx: *server.Context) !void {
- const url = try ctx.readJson([]const u8);
- inline for (.{ "Content-Type", "Content-Length", "Host", "Referer", "Origin" }) |h| {
- _ = ctx.res.request.headers.delete(h);
- }
-
- var client: std.http.Client = .{ .allocator = ctx.arena };
- defer client.deinit();
-
- if (builtin.target.os.tag == .windows) {
- try client.ca_bundle.rescan(ctx.arena);
- const start = client.ca_bundle.bytes.items.len;
- try client.ca_bundle.bytes.appendSlice(ctx.arena, @embedFile("../windows/amazon1.cer"));
- try client.ca_bundle.parseCert(ctx.arena, @intCast(start), std.time.timestamp());
- }
-
- var req = try client.open(.GET, try std.Uri.parse(url), ctx.res.request.headers, .{});
- defer req.deinit();
-
- try req.send(.{});
- try req.wait();
-
- if (req.response.status != .ok) {
- return ctx.sendJson(.{ .@"error" = try std.fmt.allocPrint(ctx.arena, "Invalid status code: `{d}`", .{req.response.status}) });
- }
-
- const content_type = req.response.headers.getFirstValue("Content-Type") orelse "";
- if (!std.mem.eql(u8, content_type, "binary/octet-stream")) {
- return ctx.sendJson(.{ .@"error" = try std.fmt.allocPrint(ctx.arena, "Invalid content type: `{s}`", .{content_type}) });
- }
-
- const path = try util.getWritableHomePath(ctx.arena, &.{ "models", std.fs.path.basename(url) });
- const tmp_path = try std.fmt.allocPrint(ctx.arena, "{s}.part", .{path});
- var file = try std.fs.createFileAbsolute(tmp_path, .{});
- defer file.close();
- errdefer std.fs.deleteFileAbsolute(tmp_path) catch {};
-
- var reader = req.reader();
- var writer = file.writer();
-
- // connection buffer seems to be 80KB so let's do two reads per write
- var buf: [160 * 1024]u8 = undefined;
- var progress: usize = 0;
- while (reader.readAll(&buf)) |n| {
- try writer.writeAll(buf[0..n]);
- if (n < buf.len) break;
-
- progress += n;
- try ctx.sendJson(.{ .progress = progress });
- } else |_| return ctx.sendJson(.{ .@"error" = "Failed to download the model" });
-
- try std.fs.renameAbsolute(tmp_path, path);
- try ctx.sendJson(.{ .path = path });
-}
diff --git a/src/api/find-models.zig b/src/api/find-models.zig
deleted file mode 100644
index a15d4ed..0000000
--- a/src/api/find-models.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const std = @import("std");
-const server = @import("../server.zig");
-
-pub fn @"POST /find-models"(ctx: *server.Context) !void {
- var models_found = std.ArrayList(struct { path: []const u8, size: ?u64 }).init(ctx.arena);
-
- const path = try ctx.readJson([]const u8);
-
- var dir = try std.fs.openDirAbsolute(path, .{ .iterate = true });
- defer dir.close();
-
- var walker = try dir.walk(ctx.arena);
- defer walker.deinit();
-
- while (try walker.next()) |entry| switch (entry.kind) {
- .file => if (std.mem.endsWith(u8, entry.basename, ".gguf")) {
- const file = try dir.openFile(entry.path, .{ .mode = .read_only });
- defer file.close();
-
- try models_found.append(.{
- .path = try std.fs.path.join(ctx.arena, &.{ path, entry.path }),
- .size = (try file.stat()).size,
- });
- },
- .directory => _ = if (walker.stack.items.len > 3) walker.stack.pop(),
- else => {},
- };
-
- return ctx.sendJson(models_found.items);
-}
diff --git a/src/api/generate.zig b/src/api/generate.zig
deleted file mode 100644
index 2b642a2..0000000
--- a/src/api/generate.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const std = @import("std");
-const server = @import("../server.zig");
-const db = @import("../db.zig");
-const llama = @import("../llama.zig");
-
-const GenerateParams = struct {
- model_id: u32,
- prompt: []const u8,
- max_tokens: u32 = 2048,
- trim_first: bool = false,
- sampling: llama.SamplingParams = .{},
-};
-
-pub fn @"POST /generate"(ctx: *server.Context, params: GenerateParams) !void {
- try ctx.sendJson(.{ .status = "Waiting for the model..." });
- const model_path = try db.getString(ctx.arena, "SELECT path FROM Model WHERE id = ?", .{params.model_id});
- var cx = try llama.Pool.get(model_path, 60_000);
- defer llama.Pool.release(cx);
-
- try ctx.sendJson(.{ .status = "Reading the history..." });
- try cx.prepare(params.prompt, ¶ms.sampling);
-
- while (cx.n_past < cx.tokens.items.len) {
- try ctx.sendJson(.{ .status = try std.fmt.allocPrint(ctx.arena, "Reading the history... ({}/{})", .{ cx.n_past, cx.tokens.items.len }) });
- _ = try cx.evalOnce();
- }
-
- // TODO: send enums/unions
- try ctx.sendJson(.{ .status = "" });
-
- var tokens: u32 = 0;
-
- while (try cx.generate(¶ms.sampling)) |content| {
- try ctx.sendJson(.{
- .content = if (tokens == 0 and params.trim_first) std.mem.trimLeft(u8, content, " \t\n\r") else content,
- });
-
- tokens += 1;
- if (tokens >= params.max_tokens) break;
- }
-}
diff --git a/src/api/log.zig b/src/api/log.zig
deleted file mode 100644
index 82b87c5..0000000
--- a/src/api/log.zig
+++ /dev/null
@@ -1,6 +0,0 @@
-const server = @import("../server.zig");
-const util = @import("../util.zig");
-
-pub fn @"GET /log"(ctx: *server.Context) !void {
- try ctx.sendChunk(try util.Logger.dump(ctx.arena));
-}
diff --git a/src/api/models.zig b/src/api/models.zig
deleted file mode 100644
index a34731e..0000000
--- a/src/api/models.zig
+++ /dev/null
@@ -1,49 +0,0 @@
-const std = @import("std");
-const db = @import("../db.zig");
-const server = @import("../server.zig");
-const util = @import("../util.zig");
-
-pub fn @"GET /models"(ctx: *server.Context) !void {
- var stmt = try db.query("SELECT * FROM Model ORDER BY id", .{});
- defer stmt.deinit();
-
- var rows = std.ArrayList(struct { id: u32, name: []const u8, path: []const u8, imported: bool, size: ?u64 }).init(ctx.arena);
- var it = stmt.iterator(db.Model);
- while (try it.next()) |m| {
- try rows.append(.{
- .id = m.id,
- .name = try ctx.arena.dupe(u8, m.name),
- .path = try ctx.arena.dupe(u8, m.path),
- .imported = m.imported,
- .size = util.getFileSize(m.path) catch null,
- });
- }
-
- return ctx.sendJson(rows.items);
-}
-
-pub fn @"POST /models"(ctx: *server.Context) !void {
- const data = try ctx.readJson(struct {
- name: []const u8,
- path: []const u8,
- imported: bool = false,
- });
-
- var stmt = try db.query("INSERT INTO Model (name, path, imported) VALUES (?, ?, ?) RETURNING *", .{ data.name, data.path, data.imported });
- defer stmt.deinit();
-
- try ctx.sendJson(try stmt.read(db.Model));
-}
-
-pub fn @"PUT /models/:id"(ctx: *server.Context, id: u32, data: db.Model) !void {
- try db.exec("UPDATE Model SET name = ?, path = ? WHERE id = ?", .{ data.name, data.path, id });
- return ctx.noContent();
-}
-
-pub fn @"DELETE /models/:id"(ctx: *server.Context, id: []const u8) !void {
- const path = try db.getString(ctx.arena, "SELECT path FROM Model WHERE id = ?", .{id});
- const imported = try db.get(bool, "SELECT imported FROM Model WHERE id = ?", .{id});
- try db.exec("DELETE FROM Model WHERE id = ?", .{id});
- if (!imported) std.fs.deleteFileAbsolute(path) catch {};
- return ctx.noContent();
-}
diff --git a/src/api/prompts.zig b/src/api/prompts.zig
deleted file mode 100644
index 6cd6c00..0000000
--- a/src/api/prompts.zig
+++ /dev/null
@@ -1,26 +0,0 @@
-const db = @import("../db.zig");
-const server = @import("../server.zig");
-
-pub fn @"GET /prompts"(ctx: *server.Context) !void {
- var stmt = try db.query("SELECT * FROM Prompt ORDER BY id", .{});
- defer stmt.deinit();
-
- return ctx.sendJson(stmt.iterator(db.Prompt));
-}
-
-pub fn @"POST /prompts"(ctx: *server.Context) !void {
- const data = try ctx.readJson(struct {
- name: []const u8,
- prompt: []const u8,
- });
-
- var stmt = try db.query("INSERT INTO Prompt (name, prompt) VALUES (?, ?) RETURNING *", .{ data.name, data.prompt });
- defer stmt.deinit();
-
- try ctx.sendJson(try stmt.read(db.Prompt));
-}
-
-pub fn @"DELETE /prompts/:id"(ctx: *server.Context, id: u32) !void {
- try db.exec("DELETE FROM Prompt WHERE id = ?", .{id});
- return ctx.noContent();
-}
diff --git a/src/api/proxy.zig b/src/api/proxy.zig
deleted file mode 100644
index e51c92f..0000000
--- a/src/api/proxy.zig
+++ /dev/null
@@ -1,40 +0,0 @@
-const std = @import("std");
-const server = @import("../server.zig");
-
-pub fn @"POST /proxy"(ctx: *server.Context) !void {
- const url = try ctx.readJson([]const u8);
-
- inline for (.{ "Accept-Encoding", "Content-Type", "Content-Length", "Host", "Referer", "Origin" }) |h| {
- _ = ctx.res.request.headers.delete(h);
- }
- try ctx.res.request.headers.append("Accept-Encoding", "gzip, deflate");
-
- var client: std.http.Client = .{ .allocator = ctx.arena };
- defer client.deinit();
-
- var req = try client.open(.GET, try std.Uri.parse(url), ctx.res.request.headers, .{});
- defer req.deinit();
-
- try req.send(.{});
- try req.wait();
-
- ctx.res.status = req.response.status;
- ctx.res.headers = try req.response.headers.clone(ctx.arena);
- ctx.res.transfer_encoding = .chunked;
- _ = ctx.res.headers.delete("Transfer-Encoding");
- _ = ctx.res.headers.delete("Content-Encoding");
- _ = ctx.res.headers.delete("Content-Length");
- _ = ctx.res.headers.delete("Link"); // Otherwise browser will try to preload non-existent resources
- try ctx.res.send();
-
- var buf: [512]u8 = undefined;
- var written: usize = 0;
-
- while (true) {
- if (written == req.response.content_length) break;
- const n = try req.read(buf[0..]);
- if (n == 0) break;
- try ctx.res.writeAll(buf[0..n]);
- written += n;
- }
-}
diff --git a/src/api/system-info.zig b/src/api/system-info.zig
deleted file mode 100644
index cbc8b54..0000000
--- a/src/api/system-info.zig
+++ /dev/null
@@ -1,47 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const server = @import("../server.zig");
-
-pub fn @"GET /system-info"(ctx: *server.Context) !void {
- const user_home = try std.process.getEnvVarOwned(ctx.arena, if (builtin.target.os.tag == .windows) "USERPROFILE" else "HOME");
- const user_downloads = try std.fs.path.join(ctx.arena, &.{ user_home, "Downloads" });
-
- return ctx.sendJson(.{
- .os = builtin.os.tag,
- .os_version = try getOsVersion(ctx.arena),
- .arch = builtin.cpu.arch,
- .cpu_count = std.Thread.getCpuCount() catch 0,
- .total_system_memory = std.process.totalSystemMemory() catch 0,
- .user_home = user_home,
- .user_downloads = user_downloads,
- });
-}
-
-fn getOsVersion(allocator: std.mem.Allocator) ![]const u8 {
- if (comptime builtin.os.tag == .macos) {
- var f = try std.fs.openFileAbsolute("/System/Library/CoreServices/.SystemVersionPlatform.plist", .{});
- defer f.close();
-
- var contents = try f.readToEndAlloc(allocator, 1024);
- defer allocator.free(contents);
-
- if (std.mem.indexOf(u8, contents, "ProductVersion")) |a| {
- if (std.mem.indexOf(u8, contents[a..], "")) |b| {
- if (std.mem.indexOf(u8, contents[a + b ..], "")) |c| {
- return allocator.dupe(u8, contents[a + b + 8 .. a + b + c]);
- }
- }
- }
- }
-
- if (comptime builtin.os.tag == .windows) {
- var info: std.os.windows.RTL_OSVERSIONINFOW = undefined;
- info.dwOSVersionInfoSize = @sizeOf(@TypeOf(info));
-
- if (std.os.windows.ntdll.RtlGetVersion(&info) == .SUCCESS) {
- return std.fmt.allocPrint(allocator, "{d}.{d}", .{ info.dwMajorVersion, info.dwMinorVersion });
- }
- }
-
- return "unknown";
-}
diff --git a/src/app/App.tsx b/src/app/App.tsx
deleted file mode 100644
index 4cd2ed2..0000000
--- a/src/app/App.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { ErrorBoundary, ModalBackdrop } from "./_components"
-import { Sidebar } from "./Sidebar"
-import { router } from "./router"
-
-const gridTemplate = `
- "sidebar list header header" auto
- "sidebar list main details" 1fr
- "sidebar list footer footer" auto / min-content min-content 1fr min-content
-`
-
-export const App = () => {
- return (
-
-
-
-
-
-
-
-
- )
-}
diff --git a/src/app/Sidebar.tsx b/src/app/Sidebar.tsx
deleted file mode 100644
index 9ec05c0..0000000
--- a/src/app/Sidebar.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { ModelSelect, NavLink, Resizable, SearchField } from "./_components"
-
-export const Sidebar = () => {
- return (
-
- {false ? : }
-
-
- Chat
- Quick Tools
- {NEXT && Workflows}
- Playground
-
-
- Settings
-
-
- Twitter
- Discord
-
-
-
-
- )
-}
-
-const SidebarHeader = ({ title, class: className = "" }) => (
-
{title}
-)
-
-const SidebarLink = props => (
-
-)
diff --git a/src/app/_components/Alert.tsx b/src/app/_components/Alert.tsx
deleted file mode 100644
index c613c34..0000000
--- a/src/app/_components/Alert.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-export const Alert = ({ class: className = "", children }) => {
- return (
-
- {children}
-
- )
-}
diff --git a/src/app/_components/AutoGrowTextarea.tsx b/src/app/_components/AutoGrowTextarea.tsx
deleted file mode 100644
index 294ec3a..0000000
--- a/src/app/_components/AutoGrowTextarea.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-export const AutoGrowTextarea = ({ class: className = "", ...props }) => (
-
-)
diff --git a/src/app/_components/AutoScroll.tsx b/src/app/_components/AutoScroll.tsx
deleted file mode 100644
index a242658..0000000
--- a/src/app/_components/AutoScroll.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { useSignal } from "@preact/signals"
-import { useEffect, useRef } from "preact/hooks"
-
-/**
- * Automatically scrolls to the bottom of the parent element. If the user
- * scrolls up, auto-scrolling is disabled until the user scrolls to the bottom
- * again.
- */
-export const AutoScroll = () => {
- const enabled = useSignal(true)
- const ref = useRef(null)
-
- useEffect(() => {
- const el = ref.current!
- const container = el.parentElement!
-
- const handleWheel = e => {
- if (e.deltaY < 0) {
- // Disable auto-scrolling when scrolling up
- enabled.value = false
- }
-
- setTimeout(() => {
- // Re-enable auto-scrolling if this was triggered by the user
- if (container.scrollHeight - container.scrollTop - container.clientHeight <= 200) {
- enabled.value = true
- }
- }, 100)
- }
-
- const scrollToBottom = () => {
- if (enabled.value) {
- // Chrome does not like { behavior: "smooth", block: "start" }
- el.scrollIntoView()
- }
- }
-
- const observer = new MutationObserver(scrollToBottom)
- observer.observe(container, { characterData: true, childList: true, subtree: true })
- container.addEventListener("wheel", handleWheel, { passive: true })
-
- // Initial scroll
- scrollToBottom()
-
- return () => {
- container.removeEventListener("wheel", handleWheel)
- observer.disconnect()
- }
- }, [])
-
- return
-}
diff --git a/src/app/_components/Button.tsx b/src/app/_components/Button.tsx
deleted file mode 100644
index f876c34..0000000
--- a/src/app/_components/Button.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Link } from "./Link"
-
-export const Button = ({ class: className = "", submit = false, primary = submit, text = false, ...props }) => {
- props.type = submit ? "submit" : "button"
-
- props.class = `h-8 border rounded-md inline-flex items-center justify-center px-${text ? 1 : 3} text-sm bg-gradient-to-b ${
- text
- ? "border-transparent"
- : primary
- ? "bg-primary(10 dark:11) from-primary(8 dark:9) text-sky(1 dark:4) border-primary(8 dark:10)"
- : "bg-neutral-5 from(white dark:neutral-11) text-neutral-12 border-neutral-6 shadow-thin"
- } ${className}`
-
- return props.href ? :
-}
diff --git a/src/app/_components/Checkbox.tsx b/src/app/_components/Checkbox.tsx
deleted file mode 100644
index f2fef9c..0000000
--- a/src/app/_components/Checkbox.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-export const Checkbox = ({ label, value, onChange }) => {
- return (
-
- )
-}
diff --git a/src/app/_components/Dropdown.tsx b/src/app/_components/Dropdown.tsx
deleted file mode 100644
index a92d635..0000000
--- a/src/app/_components/Dropdown.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { useRef, useEffect } from "preact/hooks"
-
-/**
- * Container for a button and a dropdown menu.
- * Show/hides the dropdown menu when clicked.
- */
-export const Dropdown = ({ class: className = "", ...props }) => {
- const ref = useRef(null)
-
- useEffect(() => {
- const handleClick = ({ target }) => {
- const el = ref.current!
- el.querySelector(".dropdown-menu")?.classList.toggle(
- "show",
- el.contains(target) && !target.matches(".dropdown-menu :is(a, button)")
- )
- }
-
- document.addEventListener("click", handleClick)
- return () => document.removeEventListener("click", handleClick)
- }, [])
-
- return
-}
diff --git a/src/app/_components/ErrorBoundary.tsx b/src/app/_components/ErrorBoundary.tsx
deleted file mode 100644
index ec65702..0000000
--- a/src/app/_components/ErrorBoundary.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { useEffect, useErrorBoundary } from "preact/hooks"
-import { useSignal } from "@preact/signals"
-import { Modal } from "./Modal"
-
-const fetch = window.fetch
-
-/**
- * A component that catches errors in the component tree and unhandled promise
- * rejections and displays them in a modal.
- */
-export const ErrorBoundary = ({ children, ...props }) => {
- const lastError = useSignal(null)
-
- // Errors in the component tree (render, event handlers, etc.)
- useErrorBoundary(err => console.error((lastError.value = err)))
-
- // Unhandled promise rejections (fetch, async, etc.)
- useEffect(() => {
- const listener = rej => (lastError.value = rej.reason)
- addEventListener("unhandledrejection", listener)
-
- return () => removeEventListener("unhandledrejection", listener)
- })
-
- // Fetch errors
- useEffect(() => {
- window.fetch = async (...args) => {
- const res = await fetch(...args)
-
- if (!res.ok) {
- const err = new Error(`${res.status} ${res.statusText}`)
- err["response"] = res
- throw err
- }
-
- return res
- }
-
- return () => (window.fetch = fetch)
- }, [])
-
- // Clear the error when the user closes the modal
- const reset = () => (lastError.value = null)
-
- return (
-
- {children}
-
- {lastError.value && (
-
- An unexpected error occurred. ({lastError.value.constructor.name})
- {lastError.value.message ?? lastError.value}
-
- )}
-
- )
-}
diff --git a/src/app/_components/Form.tsx b/src/app/_components/Form.tsx
deleted file mode 100644
index b16f916..0000000
--- a/src/app/_components/Form.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { createContext, JSX } from "preact"
-import { useContext, useEffect, useRef } from "preact/hooks"
-import { useForm, UseFormProps } from "../_hooks"
-
-export type FormProps = UseFormProps & JSX.HTMLAttributes
-
-const FormContext = createContext>(null as any)
-
-export const Form = ({ onSubmit, onChange, data, ...props }: FormProps) => {
- const form = useForm({ data, onSubmit, onChange })
- const ref = useRef(null)
-
- useEffect(() => {
- const form = ref.current!
-
- // prevent default form submission
- form.addEventListener("submit", e => e.preventDefault())
-
- // Focus the first element with autofocus or the first input
- // TODO: maybe