Compare commits
28 Commits
better-plu
...
stablestud
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b9e34dcda | ||
|
|
1dc1fad664 | ||
|
|
896e91818f | ||
|
|
8d363baa58 | ||
|
|
54d703c38e | ||
|
|
f8adbd1e60 | ||
|
|
e111ca023c | ||
|
|
7174ae2ab3 | ||
|
|
e35446e9ef | ||
|
|
1fd566802d | ||
|
|
508173cbb3 | ||
|
|
5646d76c3e | ||
|
|
f07733c227 | ||
|
|
6fcdee3da0 | ||
|
|
fad621417d | ||
|
|
3800549123 | ||
|
|
d10af830f0 | ||
|
|
8c704abcb6 | ||
|
|
0785bc4751 | ||
|
|
75c7b7e51e | ||
|
|
14dc64e8b1 | ||
|
|
bfd60288d3 | ||
|
|
39da8e3bb5 | ||
|
|
58075b422e | ||
|
|
e0f787c4d7 | ||
|
|
158ccf298b | ||
|
|
76772d7b9a | ||
|
|
4ae2e1766e |
43
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: "Build Tauri App"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- tauri
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest, ubuntu-20.04, windows-latest]
|
||||
permissions:
|
||||
contents: "write"
|
||||
packages: "write"
|
||||
pull-requests: "read"
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: install dependencies (ubuntu only)
|
||||
if: matrix.platform == 'ubuntu-20.04'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
- name: install frontend dependencies
|
||||
run: yarn install
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tagName: stablestudio-v__VERSION__
|
||||
releaseName: "StableStudio v__VERSION__"
|
||||
releaseBody: "See the assets to download this version and install."
|
||||
releaseDraft: true
|
||||
prerelease: true
|
||||
56
.github/workflows/comfy_windows.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: "Windows Release Repackaging with ZIP"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- tauri
|
||||
|
||||
jobs:
|
||||
repackage_comfyui:
|
||||
permissions:
|
||||
contents: "write"
|
||||
packages: "write"
|
||||
pull-requests: "read"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y p7zip-full
|
||||
sudo apt-get install -y zip
|
||||
|
||||
wget -nv https://github.com/comfyanonymous/ComfyUI/releases/download/latest/ComfyUI_windows_portable_nvidia_cu118_or_cpu.7z
|
||||
|
||||
7z x ComfyUI_windows_portable_nvidia_cu118_or_cpu.7z
|
||||
|
||||
rm ComfyUI_windows_portable_nvidia_cu118_or_cpu.7z
|
||||
|
||||
mv ComfyUI_windows_portable ComfyUI
|
||||
|
||||
# remove ALL cache files recursively (.pyc, .pyo, __pycache__, etc.)
|
||||
find ComfyUI -type f -name '*.pyc' -delete
|
||||
find ComfyUI -type f -name '*.pyo' -delete
|
||||
find ComfyUI -type d -name '__pycache__' -delete
|
||||
|
||||
# remove ALL .git files recursively
|
||||
rm -rf ComfyUI/.git
|
||||
rm -rf ComfyUI/.github
|
||||
rm -rf ComfyUI/.ci
|
||||
rm -rf ComfyUI/.gitignore
|
||||
|
||||
zip -r -9 -q ComfyUI_windows_portable.zip ComfyUI -x "*.DS_Store" -x "__MACOSX" -x "*.git*" -x "*.ci*" -x "*.github*" -x "*.gitignore*" -x "*.pyc" -x "*.pyo" -x "__pycache__"
|
||||
du -sh ComfyUI_windows_portable.zip
|
||||
|
||||
mkdir ComfyUI_bundle
|
||||
mv ComfyUI_windows_portable.zip ComfyUI_bundle/ComfyUI_windows_portable.zip
|
||||
|
||||
- name: Upload binaries to S3
|
||||
uses: shallwefootball/s3-upload-action@master
|
||||
with:
|
||||
aws_key_id: ${{ secrets.AWS_KEY_ID }}
|
||||
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws_bucket: ${{ secrets.AWS_BUCKET }}
|
||||
source_dir: ComfyUI_bundle
|
||||
destination_dir: ComfyUI
|
||||
endpoint: https://4f71c105ddc191f1fdc56ad4be97f44f.r2.cloudflarestorage.com/stability-downloads
|
||||
2
.gitignore
vendored
@@ -11,3 +11,5 @@ node_modules
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
**/src-tauri/comfyui/*
|
||||
|
||||
5
.vscode/settings.json
vendored
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"rust-analyzer.linkedProjects": [
|
||||
".\\packages\\stablestudio-ui\\src-tauri\\Cargo.toml"
|
||||
]
|
||||
}
|
||||
|
||||
10
package.json
@@ -9,13 +9,8 @@
|
||||
"scripts": {
|
||||
"postinstall": "node -e \"try { require('husky').install() } catch (e) {if (e.code !== 'MODULE_NOT_FOUND') throw e}\" && yarn build",
|
||||
"stablestudio-plugin": "yarn workspace @stability/stablestudio-plugin",
|
||||
"stablestudio-plugin-example": "yarn workspace @stability/stablestudio-plugin-example",
|
||||
"stablestudio-plugin-stability": "yarn workspace @stability/stablestudio-plugin-stability",
|
||||
"stablestudio-plugin-webgpu": "yarn workspace @stability/stablestudio-plugin-webgpu",
|
||||
"stablestudio-plugin-webui": "yarn workspace @stability/stablestudio-plugin-webui",
|
||||
"stablestudio-plugin-comfy": "yarn workspace @stability/stablestudio-plugin-comfy",
|
||||
"stablestudio-ui": "yarn workspace @stability/stablestudio-ui",
|
||||
"dev:use-example-plugin": "cross-env VITE_USE_EXAMPLE_PLUGIN=true yarn dev",
|
||||
"dev:use-webui-plugin": "cross-env VITE_USE_WEBUI_PLUGIN=true yarn dev",
|
||||
"dev": "yarn workspaces foreach --all --interlaced --verbose --parallel --jobs unlimited run dev",
|
||||
"build": "yarn workspaces foreach --all --interlaced --verbose --jobs unlimited run build",
|
||||
"clean": "yarn workspaces foreach --all --interlaced --verbose --parallel --jobs unlimited run clean && rimraf node_modules"
|
||||
@@ -32,5 +27,8 @@
|
||||
"prettier --write",
|
||||
"eslint --fix"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^20.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@stability/stablestudio-plugin-webui",
|
||||
"name": "@stability/stablestudio-plugin-comfy",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
54
packages/stablestudio-plugin-comfy/src/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
|
||||
export const createPlugin = StableStudio.createPlugin(() => ({
|
||||
manifest: {
|
||||
name: "ComfyUI Backend",
|
||||
author: "StabilityAI",
|
||||
version: "0.0.1",
|
||||
license: "MIT",
|
||||
description: "An interface for generating images with ComfyUI",
|
||||
},
|
||||
|
||||
createStableDiffusionImages: async () => {
|
||||
(
|
||||
(document.getElementById("comfyui-window") as any)?.contentWindow as any
|
||||
)?.app.queuePrompt(1, 1);
|
||||
|
||||
const image = await fetch(`${window.location.origin}/DummyImage.png`);
|
||||
const blob = await image.blob();
|
||||
const createdAt = new Date();
|
||||
|
||||
return {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
images: [
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
getStatus: () => {
|
||||
return {
|
||||
indicator: "success",
|
||||
text: "Ready",
|
||||
};
|
||||
},
|
||||
}));
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "@stability/stablestudio-plugin-example",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf lib && rimraf node_modules",
|
||||
"build:types": "ttsc --project tsconfig.json",
|
||||
"build:javascript": "tsx scripts/Build.ts",
|
||||
"build": "yarn build:types && yarn build:javascript",
|
||||
"dev": "nodemon --watch src --ext ts,tsx,json --exec \"yarn build\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@stability/stablestudio-plugin": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"eslint": "8.22.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-markdown": "^3.0.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^3.12.1",
|
||||
"ttypescript": "^1.5.13",
|
||||
"typescript": "4.8.4",
|
||||
"typescript-transform-paths": "^3.4.4"
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
|
||||
export const createPlugin = StableStudio.createPlugin<{
|
||||
imagesGeneratedSoFar: number;
|
||||
settings: {
|
||||
exampleSetting: StableStudio.PluginSettingString;
|
||||
};
|
||||
}>(({ set, get }) => ({
|
||||
imagesGeneratedSoFar: 0,
|
||||
|
||||
manifest: {
|
||||
name: "Example Plugin",
|
||||
author: "Bobby Joe",
|
||||
link: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
icon: `${window.location.origin}/DummyImage.png`,
|
||||
version: "1.2.3",
|
||||
license: "MIT",
|
||||
description: "An example plugin for StableStudio",
|
||||
},
|
||||
|
||||
createStableDiffusionImages: async () => {
|
||||
const image = await fetch(`${window.location.origin}/DummyImage.png`);
|
||||
const blob = await image.blob();
|
||||
const createdAt = new Date();
|
||||
|
||||
set(({ imagesGeneratedSoFar }) => ({
|
||||
imagesGeneratedSoFar: imagesGeneratedSoFar + 4,
|
||||
}));
|
||||
|
||||
return {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
images: [
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
getStatus: () => {
|
||||
const { imagesGeneratedSoFar } = get();
|
||||
return {
|
||||
indicator: "success",
|
||||
text:
|
||||
imagesGeneratedSoFar > 0
|
||||
? `${imagesGeneratedSoFar} images generated`
|
||||
: "Ready",
|
||||
};
|
||||
},
|
||||
|
||||
settings: {
|
||||
exampleSetting: {
|
||||
type: "string" as const,
|
||||
default: "Hello, World!",
|
||||
placeholder: "Example setting",
|
||||
},
|
||||
},
|
||||
|
||||
setSetting: (key, value) =>
|
||||
set(({ settings }) => ({
|
||||
settings: {
|
||||
[key]: { ...settings[key], value: value as string },
|
||||
},
|
||||
})),
|
||||
}));
|
||||
@@ -1,2 +0,0 @@
|
||||
./src/Proto/Generated/**/*
|
||||
./api-interfaces/**
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["./src/Proto/Generated/**"]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
api-interfaces
|
||||
lib
|
||||
@@ -1,2 +0,0 @@
|
||||
./src/Proto/Generated/**/*
|
||||
./api-interfaces/**
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Stability AI
|
||||
|
||||
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.
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"name": "@stability/stablestudio-plugin-stability",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf lib && rimraf api-interfaces && rimraf node_modules",
|
||||
"generate:proto": "tsx scripts/GenerateProto.ts",
|
||||
"build:types": "ttsc --project tsconfig.json",
|
||||
"build:javascript": "tsx scripts/Build.ts",
|
||||
"build": "yarn build:types && yarn build:javascript",
|
||||
"dev": "nodemon --watch src --ext ts,json --exec \"yarn build\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@protobuf-ts/grpcweb-transport": "^2.8.2",
|
||||
"@protobuf-ts/runtime": "^2.8.1",
|
||||
"@protobuf-ts/runtime-rpc": "^2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@protobuf-ts/plugin": "^2.8.1",
|
||||
"@types/node": "^18.11.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"concurrently": "^7.6.0",
|
||||
"eslint": "8.22.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-markdown": "^3.0.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"ts-proto": "^1.133.0",
|
||||
"tsx": "^3.12.1",
|
||||
"ttypescript": "^1.5.13",
|
||||
"typescript": "4.8.4",
|
||||
"typescript-transform-paths": "^3.4.4"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import * as ESBuild from "esbuild";
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
await ESBuild.build({
|
||||
entryPoints: ["src/index.ts"],
|
||||
outdir: "lib",
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
minify: true,
|
||||
splitting: true,
|
||||
format: "esm",
|
||||
target: ["esnext"],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
@@ -1,69 +0,0 @@
|
||||
import * as ChildProcess from "child_process";
|
||||
import * as FileSystem from "fs";
|
||||
import * as Path from "path";
|
||||
|
||||
// Set up input and output directories
|
||||
|
||||
const inputDirectoryPath = Path.join(__dirname, "../api-interfaces");
|
||||
const outputDirectoryPath = Path.join(__dirname, "../src/Proto/Generated");
|
||||
|
||||
// Remove and recreate the output directory
|
||||
|
||||
FileSystem.existsSync(outputDirectoryPath) &&
|
||||
FileSystem.rmSync(outputDirectoryPath, { recursive: true });
|
||||
|
||||
FileSystem.mkdirSync(outputDirectoryPath);
|
||||
|
||||
// Set up proto directories
|
||||
|
||||
const protoDirPath = `${inputDirectoryPath}/src/proto` as const;
|
||||
const tensorProtoDirPath =
|
||||
`${inputDirectoryPath}/src/tensorizer/proto` as const;
|
||||
|
||||
// Clone latest tensorizer git repository
|
||||
|
||||
const tensorizerGitPath = `${inputDirectoryPath}/src/tensorizer`;
|
||||
|
||||
// Clone and force update the api-interfaces Git repository
|
||||
|
||||
!FileSystem.existsSync(inputDirectoryPath) &&
|
||||
ChildProcess.execSync(
|
||||
`git clone https://github.com/Stability-AI/api-interfaces.git ${inputDirectoryPath}`
|
||||
);
|
||||
|
||||
ChildProcess.execSync("git reset --hard origin/main", {
|
||||
cwd: inputDirectoryPath,
|
||||
});
|
||||
|
||||
// Clone and force update the tensorizer Git repository
|
||||
|
||||
!FileSystem.existsSync(`${tensorizerGitPath}/.git`) &&
|
||||
ChildProcess.execSync(
|
||||
`git clone https://github.com/coreweave/tensorizer.git ${tensorizerGitPath}`
|
||||
);
|
||||
|
||||
ChildProcess.execSync("git reset --hard origin/main", {
|
||||
cwd: tensorizerGitPath,
|
||||
});
|
||||
|
||||
// Copy tensors.proto from tensorizer to api-interfaces proto directory
|
||||
|
||||
FileSystem.copyFileSync(
|
||||
`${tensorProtoDirPath}/tensors.proto`,
|
||||
`${protoDirPath}/tensors.proto`
|
||||
);
|
||||
|
||||
// Get all the proto paths and source files
|
||||
|
||||
const protoPaths = [
|
||||
protoDirPath,
|
||||
...FileSystem.readdirSync(protoDirPath)
|
||||
.filter((file) => file.endsWith(".proto"))
|
||||
.map((file) => Path.join(protoDirPath, file)),
|
||||
].join(" ");
|
||||
|
||||
// Generate TypeScript files from the final list of proto files
|
||||
|
||||
ChildProcess.execSync(
|
||||
`npx protoc --ts_out ${outputDirectoryPath} --proto_path ${protoPaths}`
|
||||
);
|
||||
@@ -1,236 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "dashboard.proto" (package "gooseai", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||
import { DashboardService } from "./dashboard";
|
||||
import type { GetAutoChargeRequest } from "./dashboard";
|
||||
import type { AutoChargeIntent } from "./dashboard";
|
||||
import type { CreateAutoChargeIntentRequest } from "./dashboard";
|
||||
import type { Charges } from "./dashboard";
|
||||
import type { GetChargesRequest } from "./dashboard";
|
||||
import type { Charge } from "./dashboard";
|
||||
import type { CreateChargeRequest } from "./dashboard";
|
||||
import type { UserPasswordChangeTicket } from "./dashboard";
|
||||
import type { UpdateUserInfoRequest } from "./dashboard";
|
||||
import type { ClientSettings } from "./dashboard";
|
||||
import type { UpdateDefaultOrganizationRequest } from "./dashboard";
|
||||
import type { APIKeyFindRequest } from "./dashboard";
|
||||
import type { APIKey } from "./dashboard";
|
||||
import type { APIKeyRequest } from "./dashboard";
|
||||
import type { Metrics } from "./dashboard";
|
||||
import type { GetMetricsRequest } from "./dashboard";
|
||||
import type { Organization } from "./dashboard";
|
||||
import type { GetOrganizationRequest } from "./dashboard";
|
||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||
import type { User } from "./dashboard";
|
||||
import type { EmptyRequest } from "./dashboard";
|
||||
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||
/**
|
||||
* @generated from protobuf service gooseai.DashboardService
|
||||
*/
|
||||
export interface IDashboardServiceClient {
|
||||
/**
|
||||
* Get info
|
||||
*
|
||||
* @generated from protobuf rpc: GetMe(gooseai.EmptyRequest) returns (gooseai.User);
|
||||
*/
|
||||
getMe(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, User>;
|
||||
/**
|
||||
* @generated from protobuf rpc: GetOrganization(gooseai.GetOrganizationRequest) returns (gooseai.Organization);
|
||||
*/
|
||||
getOrganization(input: GetOrganizationRequest, options?: RpcOptions): UnaryCall<GetOrganizationRequest, Organization>;
|
||||
/**
|
||||
* @generated from protobuf rpc: GetMetrics(gooseai.GetMetricsRequest) returns (gooseai.Metrics);
|
||||
*/
|
||||
getMetrics(input: GetMetricsRequest, options?: RpcOptions): UnaryCall<GetMetricsRequest, Metrics>;
|
||||
/**
|
||||
* API key management
|
||||
*
|
||||
* @generated from protobuf rpc: CreateAPIKey(gooseai.APIKeyRequest) returns (gooseai.APIKey);
|
||||
*/
|
||||
createAPIKey(input: APIKeyRequest, options?: RpcOptions): UnaryCall<APIKeyRequest, APIKey>;
|
||||
/**
|
||||
* @generated from protobuf rpc: DeleteAPIKey(gooseai.APIKeyFindRequest) returns (gooseai.APIKey);
|
||||
*/
|
||||
deleteAPIKey(input: APIKeyFindRequest, options?: RpcOptions): UnaryCall<APIKeyFindRequest, APIKey>;
|
||||
/**
|
||||
* User settings
|
||||
*
|
||||
* @generated from protobuf rpc: UpdateDefaultOrganization(gooseai.UpdateDefaultOrganizationRequest) returns (gooseai.User);
|
||||
*/
|
||||
updateDefaultOrganization(input: UpdateDefaultOrganizationRequest, options?: RpcOptions): UnaryCall<UpdateDefaultOrganizationRequest, User>;
|
||||
/**
|
||||
* @generated from protobuf rpc: GetClientSettings(gooseai.EmptyRequest) returns (gooseai.ClientSettings);
|
||||
*/
|
||||
getClientSettings(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, ClientSettings>;
|
||||
/**
|
||||
* @generated from protobuf rpc: SetClientSettings(gooseai.ClientSettings) returns (gooseai.ClientSettings);
|
||||
*/
|
||||
setClientSettings(input: ClientSettings, options?: RpcOptions): UnaryCall<ClientSettings, ClientSettings>;
|
||||
/**
|
||||
* @generated from protobuf rpc: UpdateUserInfo(gooseai.UpdateUserInfoRequest) returns (gooseai.User);
|
||||
*/
|
||||
updateUserInfo(input: UpdateUserInfoRequest, options?: RpcOptions): UnaryCall<UpdateUserInfoRequest, User>;
|
||||
/**
|
||||
* @generated from protobuf rpc: CreatePasswordChangeTicket(gooseai.EmptyRequest) returns (gooseai.UserPasswordChangeTicket);
|
||||
*/
|
||||
createPasswordChangeTicket(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, UserPasswordChangeTicket>;
|
||||
/**
|
||||
* @generated from protobuf rpc: DeleteAccount(gooseai.EmptyRequest) returns (gooseai.User);
|
||||
*/
|
||||
deleteAccount(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, User>;
|
||||
/**
|
||||
* Payment functions
|
||||
*
|
||||
* @generated from protobuf rpc: CreateCharge(gooseai.CreateChargeRequest) returns (gooseai.Charge);
|
||||
*/
|
||||
createCharge(input: CreateChargeRequest, options?: RpcOptions): UnaryCall<CreateChargeRequest, Charge>;
|
||||
/**
|
||||
* @generated from protobuf rpc: GetCharges(gooseai.GetChargesRequest) returns (gooseai.Charges);
|
||||
*/
|
||||
getCharges(input: GetChargesRequest, options?: RpcOptions): UnaryCall<GetChargesRequest, Charges>;
|
||||
/**
|
||||
* @generated from protobuf rpc: CreateAutoChargeIntent(gooseai.CreateAutoChargeIntentRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
createAutoChargeIntent(input: CreateAutoChargeIntentRequest, options?: RpcOptions): UnaryCall<CreateAutoChargeIntentRequest, AutoChargeIntent>;
|
||||
/**
|
||||
* @generated from protobuf rpc: UpdateAutoChargeIntent(gooseai.CreateAutoChargeIntentRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
updateAutoChargeIntent(input: CreateAutoChargeIntentRequest, options?: RpcOptions): UnaryCall<CreateAutoChargeIntentRequest, AutoChargeIntent>;
|
||||
/**
|
||||
* @generated from protobuf rpc: GetAutoChargeIntent(gooseai.GetAutoChargeRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
getAutoChargeIntent(input: GetAutoChargeRequest, options?: RpcOptions): UnaryCall<GetAutoChargeRequest, AutoChargeIntent>;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf service gooseai.DashboardService
|
||||
*/
|
||||
export class DashboardServiceClient implements IDashboardServiceClient, ServiceInfo {
|
||||
typeName = DashboardService.typeName;
|
||||
methods = DashboardService.methods;
|
||||
options = DashboardService.options;
|
||||
constructor(private readonly _transport: RpcTransport) {
|
||||
}
|
||||
/**
|
||||
* Get info
|
||||
*
|
||||
* @generated from protobuf rpc: GetMe(gooseai.EmptyRequest) returns (gooseai.User);
|
||||
*/
|
||||
getMe(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, User> {
|
||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<EmptyRequest, User>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: GetOrganization(gooseai.GetOrganizationRequest) returns (gooseai.Organization);
|
||||
*/
|
||||
getOrganization(input: GetOrganizationRequest, options?: RpcOptions): UnaryCall<GetOrganizationRequest, Organization> {
|
||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<GetOrganizationRequest, Organization>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: GetMetrics(gooseai.GetMetricsRequest) returns (gooseai.Metrics);
|
||||
*/
|
||||
getMetrics(input: GetMetricsRequest, options?: RpcOptions): UnaryCall<GetMetricsRequest, Metrics> {
|
||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<GetMetricsRequest, Metrics>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* API key management
|
||||
*
|
||||
* @generated from protobuf rpc: CreateAPIKey(gooseai.APIKeyRequest) returns (gooseai.APIKey);
|
||||
*/
|
||||
createAPIKey(input: APIKeyRequest, options?: RpcOptions): UnaryCall<APIKeyRequest, APIKey> {
|
||||
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<APIKeyRequest, APIKey>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: DeleteAPIKey(gooseai.APIKeyFindRequest) returns (gooseai.APIKey);
|
||||
*/
|
||||
deleteAPIKey(input: APIKeyFindRequest, options?: RpcOptions): UnaryCall<APIKeyFindRequest, APIKey> {
|
||||
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<APIKeyFindRequest, APIKey>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* User settings
|
||||
*
|
||||
* @generated from protobuf rpc: UpdateDefaultOrganization(gooseai.UpdateDefaultOrganizationRequest) returns (gooseai.User);
|
||||
*/
|
||||
updateDefaultOrganization(input: UpdateDefaultOrganizationRequest, options?: RpcOptions): UnaryCall<UpdateDefaultOrganizationRequest, User> {
|
||||
const method = this.methods[5], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<UpdateDefaultOrganizationRequest, User>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: GetClientSettings(gooseai.EmptyRequest) returns (gooseai.ClientSettings);
|
||||
*/
|
||||
getClientSettings(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, ClientSettings> {
|
||||
const method = this.methods[6], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<EmptyRequest, ClientSettings>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: SetClientSettings(gooseai.ClientSettings) returns (gooseai.ClientSettings);
|
||||
*/
|
||||
setClientSettings(input: ClientSettings, options?: RpcOptions): UnaryCall<ClientSettings, ClientSettings> {
|
||||
const method = this.methods[7], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<ClientSettings, ClientSettings>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: UpdateUserInfo(gooseai.UpdateUserInfoRequest) returns (gooseai.User);
|
||||
*/
|
||||
updateUserInfo(input: UpdateUserInfoRequest, options?: RpcOptions): UnaryCall<UpdateUserInfoRequest, User> {
|
||||
const method = this.methods[8], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<UpdateUserInfoRequest, User>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: CreatePasswordChangeTicket(gooseai.EmptyRequest) returns (gooseai.UserPasswordChangeTicket);
|
||||
*/
|
||||
createPasswordChangeTicket(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, UserPasswordChangeTicket> {
|
||||
const method = this.methods[9], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<EmptyRequest, UserPasswordChangeTicket>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: DeleteAccount(gooseai.EmptyRequest) returns (gooseai.User);
|
||||
*/
|
||||
deleteAccount(input: EmptyRequest, options?: RpcOptions): UnaryCall<EmptyRequest, User> {
|
||||
const method = this.methods[10], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<EmptyRequest, User>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Payment functions
|
||||
*
|
||||
* @generated from protobuf rpc: CreateCharge(gooseai.CreateChargeRequest) returns (gooseai.Charge);
|
||||
*/
|
||||
createCharge(input: CreateChargeRequest, options?: RpcOptions): UnaryCall<CreateChargeRequest, Charge> {
|
||||
const method = this.methods[11], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<CreateChargeRequest, Charge>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: GetCharges(gooseai.GetChargesRequest) returns (gooseai.Charges);
|
||||
*/
|
||||
getCharges(input: GetChargesRequest, options?: RpcOptions): UnaryCall<GetChargesRequest, Charges> {
|
||||
const method = this.methods[12], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<GetChargesRequest, Charges>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: CreateAutoChargeIntent(gooseai.CreateAutoChargeIntentRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
createAutoChargeIntent(input: CreateAutoChargeIntentRequest, options?: RpcOptions): UnaryCall<CreateAutoChargeIntentRequest, AutoChargeIntent> {
|
||||
const method = this.methods[13], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<CreateAutoChargeIntentRequest, AutoChargeIntent>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: UpdateAutoChargeIntent(gooseai.CreateAutoChargeIntentRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
updateAutoChargeIntent(input: CreateAutoChargeIntentRequest, options?: RpcOptions): UnaryCall<CreateAutoChargeIntentRequest, AutoChargeIntent> {
|
||||
const method = this.methods[14], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<CreateAutoChargeIntentRequest, AutoChargeIntent>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: GetAutoChargeIntent(gooseai.GetAutoChargeRequest) returns (gooseai.AutoChargeIntent);
|
||||
*/
|
||||
getAutoChargeIntent(input: GetAutoChargeRequest, options?: RpcOptions): UnaryCall<GetAutoChargeRequest, AutoChargeIntent> {
|
||||
const method = this.methods[15], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<GetAutoChargeRequest, AutoChargeIntent>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "engines.proto" (package "gooseai", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||
import { EnginesService } from "./engines";
|
||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||
import type { Engines } from "./engines";
|
||||
import type { ListEnginesRequest } from "./engines";
|
||||
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||
/**
|
||||
* @generated from protobuf service gooseai.EnginesService
|
||||
*/
|
||||
export interface IEnginesServiceClient {
|
||||
/**
|
||||
* @generated from protobuf rpc: ListEngines(gooseai.ListEnginesRequest) returns (gooseai.Engines);
|
||||
*/
|
||||
listEngines(input: ListEnginesRequest, options?: RpcOptions): UnaryCall<ListEnginesRequest, Engines>;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf service gooseai.EnginesService
|
||||
*/
|
||||
export class EnginesServiceClient implements IEnginesServiceClient, ServiceInfo {
|
||||
typeName = EnginesService.typeName;
|
||||
methods = EnginesService.methods;
|
||||
options = EnginesService.options;
|
||||
constructor(private readonly _transport: RpcTransport) {
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: ListEngines(gooseai.ListEnginesRequest) returns (gooseai.Engines);
|
||||
*/
|
||||
listEngines(input: ListEnginesRequest, options?: RpcOptions): UnaryCall<ListEnginesRequest, Engines> {
|
||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<ListEnginesRequest, Engines>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "engines.proto" (package "gooseai", syntax proto3)
|
||||
// tslint:disable
|
||||
import { ServiceType } from "@protobuf-ts/runtime-rpc";
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
/**
|
||||
* Engine info struct
|
||||
*
|
||||
* @generated from protobuf message gooseai.EngineInfo
|
||||
*/
|
||||
export interface EngineInfo {
|
||||
/**
|
||||
* @generated from protobuf field: string id = 1;
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* @generated from protobuf field: string owner = 2;
|
||||
*/
|
||||
owner: string;
|
||||
/**
|
||||
* @generated from protobuf field: bool ready = 3;
|
||||
*/
|
||||
ready: boolean;
|
||||
/**
|
||||
* @generated from protobuf field: gooseai.EngineType type = 4;
|
||||
*/
|
||||
type: EngineType;
|
||||
/**
|
||||
* @generated from protobuf field: gooseai.EngineTokenizer tokenizer = 5;
|
||||
*/
|
||||
tokenizer: EngineTokenizer;
|
||||
/**
|
||||
* @generated from protobuf field: string name = 6;
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* @generated from protobuf field: string description = 7;
|
||||
*/
|
||||
description: string;
|
||||
}
|
||||
/**
|
||||
* Empty
|
||||
*
|
||||
* @generated from protobuf message gooseai.ListEnginesRequest
|
||||
*/
|
||||
export interface ListEnginesRequest {
|
||||
}
|
||||
/**
|
||||
* Engine info list
|
||||
*
|
||||
* @generated from protobuf message gooseai.Engines
|
||||
*/
|
||||
export interface Engines {
|
||||
/**
|
||||
* @generated from protobuf field: repeated gooseai.EngineInfo engine = 1;
|
||||
*/
|
||||
engine: EngineInfo[];
|
||||
}
|
||||
/**
|
||||
* Possible engine type
|
||||
*
|
||||
* @generated from protobuf enum gooseai.EngineType
|
||||
*/
|
||||
export enum EngineType {
|
||||
/**
|
||||
* @generated from protobuf enum value: TEXT = 0;
|
||||
*/
|
||||
TEXT = 0,
|
||||
/**
|
||||
* @generated from protobuf enum value: PICTURE = 1;
|
||||
*/
|
||||
PICTURE = 1,
|
||||
/**
|
||||
* @generated from protobuf enum value: AUDIO = 2;
|
||||
*/
|
||||
AUDIO = 2,
|
||||
/**
|
||||
* @generated from protobuf enum value: VIDEO = 3;
|
||||
*/
|
||||
VIDEO = 3,
|
||||
/**
|
||||
* @generated from protobuf enum value: CLASSIFICATION = 4;
|
||||
*/
|
||||
CLASSIFICATION = 4,
|
||||
/**
|
||||
* @generated from protobuf enum value: STORAGE = 5;
|
||||
*/
|
||||
STORAGE = 5
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf enum gooseai.EngineTokenizer
|
||||
*/
|
||||
export enum EngineTokenizer {
|
||||
/**
|
||||
* @generated from protobuf enum value: GPT2 = 0;
|
||||
*/
|
||||
GPT2 = 0,
|
||||
/**
|
||||
* @generated from protobuf enum value: PILE = 1;
|
||||
*/
|
||||
PILE = 1
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class EngineInfo$Type extends MessageType<EngineInfo> {
|
||||
constructor() {
|
||||
super("gooseai.EngineInfo", [
|
||||
{ no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "owner", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "ready", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||
{ no: 4, name: "type", kind: "enum", T: () => ["gooseai.EngineType", EngineType] },
|
||||
{ no: 5, name: "tokenizer", kind: "enum", T: () => ["gooseai.EngineTokenizer", EngineTokenizer] },
|
||||
{ no: 6, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 7, name: "description", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<EngineInfo>): EngineInfo {
|
||||
const message = { id: "", owner: "", ready: false, type: 0, tokenizer: 0, name: "", description: "" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<EngineInfo>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: EngineInfo): EngineInfo {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string id */ 1:
|
||||
message.id = reader.string();
|
||||
break;
|
||||
case /* string owner */ 2:
|
||||
message.owner = reader.string();
|
||||
break;
|
||||
case /* bool ready */ 3:
|
||||
message.ready = reader.bool();
|
||||
break;
|
||||
case /* gooseai.EngineType type */ 4:
|
||||
message.type = reader.int32();
|
||||
break;
|
||||
case /* gooseai.EngineTokenizer tokenizer */ 5:
|
||||
message.tokenizer = reader.int32();
|
||||
break;
|
||||
case /* string name */ 6:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* string description */ 7:
|
||||
message.description = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: EngineInfo, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string id = 1; */
|
||||
if (message.id !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.id);
|
||||
/* string owner = 2; */
|
||||
if (message.owner !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.owner);
|
||||
/* bool ready = 3; */
|
||||
if (message.ready !== false)
|
||||
writer.tag(3, WireType.Varint).bool(message.ready);
|
||||
/* gooseai.EngineType type = 4; */
|
||||
if (message.type !== 0)
|
||||
writer.tag(4, WireType.Varint).int32(message.type);
|
||||
/* gooseai.EngineTokenizer tokenizer = 5; */
|
||||
if (message.tokenizer !== 0)
|
||||
writer.tag(5, WireType.Varint).int32(message.tokenizer);
|
||||
/* string name = 6; */
|
||||
if (message.name !== "")
|
||||
writer.tag(6, WireType.LengthDelimited).string(message.name);
|
||||
/* string description = 7; */
|
||||
if (message.description !== "")
|
||||
writer.tag(7, WireType.LengthDelimited).string(message.description);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message gooseai.EngineInfo
|
||||
*/
|
||||
export const EngineInfo = new EngineInfo$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListEnginesRequest$Type extends MessageType<ListEnginesRequest> {
|
||||
constructor() {
|
||||
super("gooseai.ListEnginesRequest", []);
|
||||
}
|
||||
create(value?: PartialMessage<ListEnginesRequest>): ListEnginesRequest {
|
||||
const message = {};
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListEnginesRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListEnginesRequest): ListEnginesRequest {
|
||||
return target ?? this.create();
|
||||
}
|
||||
internalBinaryWrite(message: ListEnginesRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message gooseai.ListEnginesRequest
|
||||
*/
|
||||
export const ListEnginesRequest = new ListEnginesRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Engines$Type extends MessageType<Engines> {
|
||||
constructor() {
|
||||
super("gooseai.Engines", [
|
||||
{ no: 1, name: "engine", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => EngineInfo }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Engines>): Engines {
|
||||
const message = { engine: [] };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Engines>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Engines): Engines {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* repeated gooseai.EngineInfo engine */ 1:
|
||||
message.engine.push(EngineInfo.internalBinaryRead(reader, reader.uint32(), options));
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Engines, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* repeated gooseai.EngineInfo engine = 1; */
|
||||
for (let i = 0; i < message.engine.length; i++)
|
||||
EngineInfo.internalBinaryWrite(message.engine[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message gooseai.Engines
|
||||
*/
|
||||
export const Engines = new Engines$Type();
|
||||
/**
|
||||
* @generated ServiceType for protobuf service gooseai.EnginesService
|
||||
*/
|
||||
export const EnginesService = new ServiceType("gooseai.EnginesService", [
|
||||
{ name: "ListEngines", options: {}, I: ListEnginesRequest, O: Engines }
|
||||
]);
|
||||
@@ -1,57 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "generation.proto" (package "gooseai", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||
import { GenerationService } from "./generation";
|
||||
import type { ChainRequest } from "./generation";
|
||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||
import type { Answer } from "./generation";
|
||||
import type { Request } from "./generation";
|
||||
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||
/**
|
||||
*
|
||||
* gRPC services
|
||||
*
|
||||
*
|
||||
* @generated from protobuf service gooseai.GenerationService
|
||||
*/
|
||||
export interface IGenerationServiceClient {
|
||||
/**
|
||||
* @generated from protobuf rpc: Generate(gooseai.Request) returns (stream gooseai.Answer);
|
||||
*/
|
||||
generate(input: Request, options?: RpcOptions): ServerStreamingCall<Request, Answer>;
|
||||
/**
|
||||
* @generated from protobuf rpc: ChainGenerate(gooseai.ChainRequest) returns (stream gooseai.Answer);
|
||||
*/
|
||||
chainGenerate(input: ChainRequest, options?: RpcOptions): ServerStreamingCall<ChainRequest, Answer>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* gRPC services
|
||||
*
|
||||
*
|
||||
* @generated from protobuf service gooseai.GenerationService
|
||||
*/
|
||||
export class GenerationServiceClient implements IGenerationServiceClient, ServiceInfo {
|
||||
typeName = GenerationService.typeName;
|
||||
methods = GenerationService.methods;
|
||||
options = GenerationService.options;
|
||||
constructor(private readonly _transport: RpcTransport) {
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: Generate(gooseai.Request) returns (stream gooseai.Answer);
|
||||
*/
|
||||
generate(input: Request, options?: RpcOptions): ServerStreamingCall<Request, Answer> {
|
||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<Request, Answer>("serverStreaming", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: ChainGenerate(gooseai.ChainRequest) returns (stream gooseai.Answer);
|
||||
*/
|
||||
chainGenerate(input: ChainRequest, options?: RpcOptions): ServerStreamingCall<ChainRequest, Answer> {
|
||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<ChainRequest, Answer>("serverStreaming", this._transport, method, opt, input);
|
||||
}
|
||||
}
|
||||
@@ -1,480 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "google/protobuf/struct.proto" (package "google.protobuf", syntax proto3)
|
||||
// tslint:disable
|
||||
//
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||
import { isJsonObject } from "@protobuf-ts/runtime";
|
||||
import { typeofJsonValue } from "@protobuf-ts/runtime";
|
||||
import type { JsonValue } from "@protobuf-ts/runtime";
|
||||
import type { JsonReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { JsonWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { JsonObject } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
/**
|
||||
* `Struct` represents a structured data value, consisting of fields
|
||||
* which map to dynamically typed values. In some languages, `Struct`
|
||||
* might be supported by a native representation. For example, in
|
||||
* scripting languages like JS a struct is represented as an
|
||||
* object. The details of that representation are described together
|
||||
* with the proto support for the language.
|
||||
*
|
||||
* The JSON representation for `Struct` is JSON object.
|
||||
*
|
||||
* @generated from protobuf message google.protobuf.Struct
|
||||
*/
|
||||
export interface Struct {
|
||||
/**
|
||||
* Unordered map of dynamically typed values.
|
||||
*
|
||||
* @generated from protobuf field: map<string, google.protobuf.Value> fields = 1;
|
||||
*/
|
||||
fields: {
|
||||
[key: string]: Value;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* `Value` represents a dynamically typed value which can be either
|
||||
* null, a number, a string, a boolean, a recursive struct value, or a
|
||||
* list of values. A producer of value is expected to set one of these
|
||||
* variants. Absence of any variant indicates an error.
|
||||
*
|
||||
* The JSON representation for `Value` is JSON value.
|
||||
*
|
||||
* @generated from protobuf message google.protobuf.Value
|
||||
*/
|
||||
export interface Value {
|
||||
/**
|
||||
* @generated from protobuf oneof: kind
|
||||
*/
|
||||
kind: {
|
||||
oneofKind: "nullValue";
|
||||
/**
|
||||
* Represents a null value.
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.NullValue null_value = 1;
|
||||
*/
|
||||
nullValue: NullValue;
|
||||
} | {
|
||||
oneofKind: "numberValue";
|
||||
/**
|
||||
* Represents a double value.
|
||||
*
|
||||
* @generated from protobuf field: double number_value = 2;
|
||||
*/
|
||||
numberValue: number;
|
||||
} | {
|
||||
oneofKind: "stringValue";
|
||||
/**
|
||||
* Represents a string value.
|
||||
*
|
||||
* @generated from protobuf field: string string_value = 3;
|
||||
*/
|
||||
stringValue: string;
|
||||
} | {
|
||||
oneofKind: "boolValue";
|
||||
/**
|
||||
* Represents a boolean value.
|
||||
*
|
||||
* @generated from protobuf field: bool bool_value = 4;
|
||||
*/
|
||||
boolValue: boolean;
|
||||
} | {
|
||||
oneofKind: "structValue";
|
||||
/**
|
||||
* Represents a structured value.
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.Struct struct_value = 5;
|
||||
*/
|
||||
structValue: Struct;
|
||||
} | {
|
||||
oneofKind: "listValue";
|
||||
/**
|
||||
* Represents a repeated `Value`.
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.ListValue list_value = 6;
|
||||
*/
|
||||
listValue: ListValue;
|
||||
} | {
|
||||
oneofKind: undefined;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* `ListValue` is a wrapper around a repeated field of values.
|
||||
*
|
||||
* The JSON representation for `ListValue` is JSON array.
|
||||
*
|
||||
* @generated from protobuf message google.protobuf.ListValue
|
||||
*/
|
||||
export interface ListValue {
|
||||
/**
|
||||
* Repeated field of dynamically typed values.
|
||||
*
|
||||
* @generated from protobuf field: repeated google.protobuf.Value values = 1;
|
||||
*/
|
||||
values: Value[];
|
||||
}
|
||||
/**
|
||||
* `NullValue` is a singleton enumeration to represent the null value for the
|
||||
* `Value` type union.
|
||||
*
|
||||
* The JSON representation for `NullValue` is JSON `null`.
|
||||
*
|
||||
* @generated from protobuf enum google.protobuf.NullValue
|
||||
*/
|
||||
export enum NullValue {
|
||||
/**
|
||||
* Null value.
|
||||
*
|
||||
* @generated from protobuf enum value: NULL_VALUE = 0;
|
||||
*/
|
||||
NULL_VALUE = 0
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Struct$Type extends MessageType<Struct> {
|
||||
constructor() {
|
||||
super("google.protobuf.Struct", [
|
||||
{ no: 1, name: "fields", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => Value } }
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* Encode `Struct` to JSON object.
|
||||
*/
|
||||
internalJsonWrite(message: Struct, options: JsonWriteOptions): JsonValue {
|
||||
let json: JsonObject = {};
|
||||
for (let [k, v] of Object.entries(message.fields)) {
|
||||
json[k] = Value.toJson(v);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
/**
|
||||
* Decode `Struct` from JSON object.
|
||||
*/
|
||||
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Struct): Struct {
|
||||
if (!isJsonObject(json))
|
||||
throw new globalThis.Error("Unable to parse message " + this.typeName + " from JSON " + typeofJsonValue(json) + ".");
|
||||
if (!target)
|
||||
target = this.create();
|
||||
for (let [k, v] of globalThis.Object.entries(json)) {
|
||||
target.fields[k] = Value.fromJson(v);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<Struct>): Struct {
|
||||
const message = { fields: {} };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Struct>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Struct): Struct {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* map<string, google.protobuf.Value> fields */ 1:
|
||||
this.binaryReadMap1(message.fields, reader, options);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
private binaryReadMap1(map: Struct["fields"], reader: IBinaryReader, options: BinaryReadOptions): void {
|
||||
let len = reader.uint32(), end = reader.pos + len, key: keyof Struct["fields"] | undefined, val: Struct["fields"][any] | undefined;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case 1:
|
||||
key = reader.string();
|
||||
break;
|
||||
case 2:
|
||||
val = Value.internalBinaryRead(reader, reader.uint32(), options);
|
||||
break;
|
||||
default: throw new globalThis.Error("unknown map entry field for field google.protobuf.Struct.fields");
|
||||
}
|
||||
}
|
||||
map[key ?? ""] = val ?? Value.create();
|
||||
}
|
||||
internalBinaryWrite(message: Struct, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* map<string, google.protobuf.Value> fields = 1; */
|
||||
for (let k of Object.keys(message.fields)) {
|
||||
writer.tag(1, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k);
|
||||
writer.tag(2, WireType.LengthDelimited).fork();
|
||||
Value.internalBinaryWrite(message.fields[k], writer, options);
|
||||
writer.join().join();
|
||||
}
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message google.protobuf.Struct
|
||||
*/
|
||||
export const Struct = new Struct$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Value$Type extends MessageType<Value> {
|
||||
constructor() {
|
||||
super("google.protobuf.Value", [
|
||||
{ no: 1, name: "null_value", kind: "enum", oneof: "kind", T: () => ["google.protobuf.NullValue", NullValue] },
|
||||
{ no: 2, name: "number_value", kind: "scalar", oneof: "kind", T: 1 /*ScalarType.DOUBLE*/ },
|
||||
{ no: 3, name: "string_value", kind: "scalar", oneof: "kind", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 4, name: "bool_value", kind: "scalar", oneof: "kind", T: 8 /*ScalarType.BOOL*/ },
|
||||
{ no: 5, name: "struct_value", kind: "message", oneof: "kind", T: () => Struct },
|
||||
{ no: 6, name: "list_value", kind: "message", oneof: "kind", T: () => ListValue }
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* Encode `Value` to JSON value.
|
||||
*/
|
||||
internalJsonWrite(message: Value, options: JsonWriteOptions): JsonValue {
|
||||
if (message.kind.oneofKind === undefined)
|
||||
throw new globalThis.Error();
|
||||
switch (message.kind.oneofKind) {
|
||||
case undefined: throw new globalThis.Error();
|
||||
case "boolValue": return message.kind.boolValue;
|
||||
case "nullValue": return null;
|
||||
case "numberValue": return message.kind.numberValue;
|
||||
case "stringValue": return message.kind.stringValue;
|
||||
case "listValue":
|
||||
let listValueField = this.fields.find(f => f.no === 6);
|
||||
if (listValueField?.kind !== "message")
|
||||
throw new globalThis.Error();
|
||||
return listValueField.T().toJson(message.kind.listValue);
|
||||
case "structValue":
|
||||
let structValueField = this.fields.find(f => f.no === 5);
|
||||
if (structValueField?.kind !== "message")
|
||||
throw new globalThis.Error();
|
||||
return structValueField.T().toJson(message.kind.structValue);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Decode `Value` from JSON value.
|
||||
*/
|
||||
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Value): Value {
|
||||
if (!target)
|
||||
target = this.create();
|
||||
switch (typeof json) {
|
||||
case "number":
|
||||
target.kind = { oneofKind: "numberValue", numberValue: json };
|
||||
break;
|
||||
case "string":
|
||||
target.kind = { oneofKind: "stringValue", stringValue: json };
|
||||
break;
|
||||
case "boolean":
|
||||
target.kind = { oneofKind: "boolValue", boolValue: json };
|
||||
break;
|
||||
case "object":
|
||||
if (json === null) {
|
||||
target.kind = { oneofKind: "nullValue", nullValue: NullValue.NULL_VALUE };
|
||||
}
|
||||
else if (globalThis.Array.isArray(json)) {
|
||||
target.kind = { oneofKind: "listValue", listValue: ListValue.fromJson(json) };
|
||||
}
|
||||
else {
|
||||
let val = Struct.fromJson(json);
|
||||
target.kind = { oneofKind: "structValue", structValue: Struct.fromJson(json) };
|
||||
}
|
||||
break;
|
||||
default: throw new globalThis.Error("Unable to parse " + this.typeName + " from JSON " + typeofJsonValue(json));
|
||||
}
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<Value>): Value {
|
||||
const message = { kind: { oneofKind: undefined } };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Value>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Value): Value {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* google.protobuf.NullValue null_value */ 1:
|
||||
message.kind = {
|
||||
oneofKind: "nullValue",
|
||||
nullValue: reader.int32()
|
||||
};
|
||||
break;
|
||||
case /* double number_value */ 2:
|
||||
message.kind = {
|
||||
oneofKind: "numberValue",
|
||||
numberValue: reader.double()
|
||||
};
|
||||
break;
|
||||
case /* string string_value */ 3:
|
||||
message.kind = {
|
||||
oneofKind: "stringValue",
|
||||
stringValue: reader.string()
|
||||
};
|
||||
break;
|
||||
case /* bool bool_value */ 4:
|
||||
message.kind = {
|
||||
oneofKind: "boolValue",
|
||||
boolValue: reader.bool()
|
||||
};
|
||||
break;
|
||||
case /* google.protobuf.Struct struct_value */ 5:
|
||||
message.kind = {
|
||||
oneofKind: "structValue",
|
||||
structValue: Struct.internalBinaryRead(reader, reader.uint32(), options, (message.kind as any).structValue)
|
||||
};
|
||||
break;
|
||||
case /* google.protobuf.ListValue list_value */ 6:
|
||||
message.kind = {
|
||||
oneofKind: "listValue",
|
||||
listValue: ListValue.internalBinaryRead(reader, reader.uint32(), options, (message.kind as any).listValue)
|
||||
};
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* google.protobuf.NullValue null_value = 1; */
|
||||
if (message.kind.oneofKind === "nullValue")
|
||||
writer.tag(1, WireType.Varint).int32(message.kind.nullValue);
|
||||
/* double number_value = 2; */
|
||||
if (message.kind.oneofKind === "numberValue")
|
||||
writer.tag(2, WireType.Bit64).double(message.kind.numberValue);
|
||||
/* string string_value = 3; */
|
||||
if (message.kind.oneofKind === "stringValue")
|
||||
writer.tag(3, WireType.LengthDelimited).string(message.kind.stringValue);
|
||||
/* bool bool_value = 4; */
|
||||
if (message.kind.oneofKind === "boolValue")
|
||||
writer.tag(4, WireType.Varint).bool(message.kind.boolValue);
|
||||
/* google.protobuf.Struct struct_value = 5; */
|
||||
if (message.kind.oneofKind === "structValue")
|
||||
Struct.internalBinaryWrite(message.kind.structValue, writer.tag(5, WireType.LengthDelimited).fork(), options).join();
|
||||
/* google.protobuf.ListValue list_value = 6; */
|
||||
if (message.kind.oneofKind === "listValue")
|
||||
ListValue.internalBinaryWrite(message.kind.listValue, writer.tag(6, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message google.protobuf.Value
|
||||
*/
|
||||
export const Value = new Value$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListValue$Type extends MessageType<ListValue> {
|
||||
constructor() {
|
||||
super("google.protobuf.ListValue", [
|
||||
{ no: 1, name: "values", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Value }
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* Encode `ListValue` to JSON array.
|
||||
*/
|
||||
internalJsonWrite(message: ListValue, options: JsonWriteOptions): JsonValue {
|
||||
return message.values.map(v => Value.toJson(v));
|
||||
}
|
||||
/**
|
||||
* Decode `ListValue` from JSON array.
|
||||
*/
|
||||
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: ListValue): ListValue {
|
||||
if (!globalThis.Array.isArray(json))
|
||||
throw new globalThis.Error("Unable to parse " + this.typeName + " from JSON " + typeofJsonValue(json));
|
||||
if (!target)
|
||||
target = this.create();
|
||||
let values = json.map(v => Value.fromJson(v));
|
||||
target.values.push(...values);
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<ListValue>): ListValue {
|
||||
const message = { values: [] };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListValue>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListValue): ListValue {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* repeated google.protobuf.Value values */ 1:
|
||||
message.values.push(Value.internalBinaryRead(reader, reader.uint32(), options));
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: ListValue, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* repeated google.protobuf.Value values = 1; */
|
||||
for (let i = 0; i < message.values.length; i++)
|
||||
Value.internalBinaryWrite(message.values[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message google.protobuf.ListValue
|
||||
*/
|
||||
export const ListValue = new ListValue$Type();
|
||||
@@ -1,178 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "project.proto" (package "gooseai", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
||||
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
|
||||
import { ProjectService } from "./project";
|
||||
import type { DeleteAssetsResponse } from "./project";
|
||||
import type { DeleteAssetsRequest } from "./project";
|
||||
import type { QueryAssetsResponse } from "./project";
|
||||
import type { QueryAssetsRequest } from "./project";
|
||||
import type { UntagAssetsResponse } from "./project";
|
||||
import type { UntagAssetsRequest } from "./project";
|
||||
import type { TagAssetsResponse } from "./project";
|
||||
import type { TagAssetsRequest } from "./project";
|
||||
import type { DeleteProjectRequest } from "./project";
|
||||
import type { GetProjectRequest } from "./project";
|
||||
import type { ListProjectRequest } from "./project";
|
||||
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
|
||||
import type { UpdateProjectRequest } from "./project";
|
||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||
import type { Project } from "./project";
|
||||
import type { CreateProjectRequest } from "./project";
|
||||
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
|
||||
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
|
||||
/**
|
||||
*
|
||||
* gRPC services
|
||||
*
|
||||
*
|
||||
* @generated from protobuf service gooseai.ProjectService
|
||||
*/
|
||||
export interface IProjectServiceClient {
|
||||
/**
|
||||
* Create a new project if it does not exist
|
||||
*
|
||||
* @generated from protobuf rpc: Create(gooseai.CreateProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
create(input: CreateProjectRequest, options?: RpcOptions): UnaryCall<CreateProjectRequest, Project>;
|
||||
/**
|
||||
* Update an existing project
|
||||
*
|
||||
* @generated from protobuf rpc: Update(gooseai.UpdateProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
update(input: UpdateProjectRequest, options?: RpcOptions): UnaryCall<UpdateProjectRequest, Project>;
|
||||
/**
|
||||
* List all the projects for an organization
|
||||
*
|
||||
* @generated from protobuf rpc: List(gooseai.ListProjectRequest) returns (stream gooseai.Project);
|
||||
*/
|
||||
list(input: ListProjectRequest, options?: RpcOptions): ServerStreamingCall<ListProjectRequest, Project>;
|
||||
/**
|
||||
* Get a project
|
||||
*
|
||||
* @generated from protobuf rpc: Get(gooseai.GetProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
get(input: GetProjectRequest, options?: RpcOptions): UnaryCall<GetProjectRequest, Project>;
|
||||
/**
|
||||
* Delete a project
|
||||
*
|
||||
* @generated from protobuf rpc: Delete(gooseai.DeleteProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
delete(input: DeleteProjectRequest, options?: RpcOptions): UnaryCall<DeleteProjectRequest, Project>;
|
||||
/**
|
||||
* Add or remove tags from an asset
|
||||
*
|
||||
* @generated from protobuf rpc: TagAssets(gooseai.TagAssetsRequest) returns (gooseai.TagAssetsResponse);
|
||||
*/
|
||||
tagAssets(input: TagAssetsRequest, options?: RpcOptions): UnaryCall<TagAssetsRequest, TagAssetsResponse>;
|
||||
/**
|
||||
* @generated from protobuf rpc: UntagAssets(gooseai.UntagAssetsRequest) returns (gooseai.UntagAssetsResponse);
|
||||
*/
|
||||
untagAssets(input: UntagAssetsRequest, options?: RpcOptions): UnaryCall<UntagAssetsRequest, UntagAssetsResponse>;
|
||||
/**
|
||||
* Query the assets of a project, with additional filtering
|
||||
*
|
||||
* @generated from protobuf rpc: QueryAssets(gooseai.QueryAssetsRequest) returns (gooseai.QueryAssetsResponse);
|
||||
*/
|
||||
queryAssets(input: QueryAssetsRequest, options?: RpcOptions): UnaryCall<QueryAssetsRequest, QueryAssetsResponse>;
|
||||
/**
|
||||
* Delete one or more assets of a project
|
||||
*
|
||||
* @generated from protobuf rpc: DeleteAssets(gooseai.DeleteAssetsRequest) returns (gooseai.DeleteAssetsResponse);
|
||||
*/
|
||||
deleteAssets(input: DeleteAssetsRequest, options?: RpcOptions): UnaryCall<DeleteAssetsRequest, DeleteAssetsResponse>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* gRPC services
|
||||
*
|
||||
*
|
||||
* @generated from protobuf service gooseai.ProjectService
|
||||
*/
|
||||
export class ProjectServiceClient implements IProjectServiceClient, ServiceInfo {
|
||||
typeName = ProjectService.typeName;
|
||||
methods = ProjectService.methods;
|
||||
options = ProjectService.options;
|
||||
constructor(private readonly _transport: RpcTransport) {
|
||||
}
|
||||
/**
|
||||
* Create a new project if it does not exist
|
||||
*
|
||||
* @generated from protobuf rpc: Create(gooseai.CreateProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
create(input: CreateProjectRequest, options?: RpcOptions): UnaryCall<CreateProjectRequest, Project> {
|
||||
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<CreateProjectRequest, Project>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Update an existing project
|
||||
*
|
||||
* @generated from protobuf rpc: Update(gooseai.UpdateProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
update(input: UpdateProjectRequest, options?: RpcOptions): UnaryCall<UpdateProjectRequest, Project> {
|
||||
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<UpdateProjectRequest, Project>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* List all the projects for an organization
|
||||
*
|
||||
* @generated from protobuf rpc: List(gooseai.ListProjectRequest) returns (stream gooseai.Project);
|
||||
*/
|
||||
list(input: ListProjectRequest, options?: RpcOptions): ServerStreamingCall<ListProjectRequest, Project> {
|
||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<ListProjectRequest, Project>("serverStreaming", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Get a project
|
||||
*
|
||||
* @generated from protobuf rpc: Get(gooseai.GetProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
get(input: GetProjectRequest, options?: RpcOptions): UnaryCall<GetProjectRequest, Project> {
|
||||
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<GetProjectRequest, Project>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Delete a project
|
||||
*
|
||||
* @generated from protobuf rpc: Delete(gooseai.DeleteProjectRequest) returns (gooseai.Project);
|
||||
*/
|
||||
delete(input: DeleteProjectRequest, options?: RpcOptions): UnaryCall<DeleteProjectRequest, Project> {
|
||||
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<DeleteProjectRequest, Project>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Add or remove tags from an asset
|
||||
*
|
||||
* @generated from protobuf rpc: TagAssets(gooseai.TagAssetsRequest) returns (gooseai.TagAssetsResponse);
|
||||
*/
|
||||
tagAssets(input: TagAssetsRequest, options?: RpcOptions): UnaryCall<TagAssetsRequest, TagAssetsResponse> {
|
||||
const method = this.methods[5], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<TagAssetsRequest, TagAssetsResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf rpc: UntagAssets(gooseai.UntagAssetsRequest) returns (gooseai.UntagAssetsResponse);
|
||||
*/
|
||||
untagAssets(input: UntagAssetsRequest, options?: RpcOptions): UnaryCall<UntagAssetsRequest, UntagAssetsResponse> {
|
||||
const method = this.methods[6], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<UntagAssetsRequest, UntagAssetsResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Query the assets of a project, with additional filtering
|
||||
*
|
||||
* @generated from protobuf rpc: QueryAssets(gooseai.QueryAssetsRequest) returns (gooseai.QueryAssetsResponse);
|
||||
*/
|
||||
queryAssets(input: QueryAssetsRequest, options?: RpcOptions): UnaryCall<QueryAssetsRequest, QueryAssetsResponse> {
|
||||
const method = this.methods[7], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<QueryAssetsRequest, QueryAssetsResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* Delete one or more assets of a project
|
||||
*
|
||||
* @generated from protobuf rpc: DeleteAssets(gooseai.DeleteAssetsRequest) returns (gooseai.DeleteAssetsResponse);
|
||||
*/
|
||||
deleteAssets(input: DeleteAssetsRequest, options?: RpcOptions): UnaryCall<DeleteAssetsRequest, DeleteAssetsResponse> {
|
||||
const method = this.methods[8], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<DeleteAssetsRequest, DeleteAssetsResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
}
|
||||
@@ -1,436 +0,0 @@
|
||||
// @generated by protobuf-ts 2.8.2
|
||||
// @generated from protobuf file "tensors.proto" (package "tensors", syntax proto3)
|
||||
// tslint:disable
|
||||
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
||||
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
||||
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
||||
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
|
||||
import { WireType } from "@protobuf-ts/runtime";
|
||||
import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
/**
|
||||
* @generated from protobuf message tensors.Tensor
|
||||
*/
|
||||
export interface Tensor {
|
||||
/**
|
||||
* @generated from protobuf field: tensors.Dtype dtype = 1;
|
||||
*/
|
||||
dtype: Dtype;
|
||||
/**
|
||||
* @generated from protobuf field: repeated int64 shape = 2;
|
||||
*/
|
||||
shape: bigint[];
|
||||
/**
|
||||
* @generated from protobuf field: bytes data = 3;
|
||||
*/
|
||||
data: Uint8Array;
|
||||
/**
|
||||
* @generated from protobuf field: optional tensors.AttributeType attr_type = 4;
|
||||
*/
|
||||
attrType?: AttributeType;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message tensors.Attribute
|
||||
*/
|
||||
export interface Attribute {
|
||||
/**
|
||||
* @generated from protobuf field: string name = 1;
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* @generated from protobuf oneof: value
|
||||
*/
|
||||
value: {
|
||||
oneofKind: "module";
|
||||
/**
|
||||
* @generated from protobuf field: tensors.Module module = 3;
|
||||
*/
|
||||
module: Module;
|
||||
} | {
|
||||
oneofKind: "tensor";
|
||||
/**
|
||||
* @generated from protobuf field: tensors.Tensor tensor = 4;
|
||||
*/
|
||||
tensor: Tensor;
|
||||
} | {
|
||||
oneofKind: "string";
|
||||
/**
|
||||
* @generated from protobuf field: string string = 5;
|
||||
*/
|
||||
string: string;
|
||||
} | {
|
||||
oneofKind: "int64";
|
||||
/**
|
||||
* @generated from protobuf field: int64 int64 = 6;
|
||||
*/
|
||||
int64: bigint;
|
||||
} | {
|
||||
oneofKind: "float";
|
||||
/**
|
||||
* @generated from protobuf field: float float = 7;
|
||||
*/
|
||||
float: number;
|
||||
} | {
|
||||
oneofKind: "bool";
|
||||
/**
|
||||
* @generated from protobuf field: bool bool = 8;
|
||||
*/
|
||||
bool: boolean;
|
||||
} | {
|
||||
oneofKind: undefined;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message tensors.Module
|
||||
*/
|
||||
export interface Module {
|
||||
/**
|
||||
* @generated from protobuf field: string name = 1;
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* @generated from protobuf field: repeated string names = 2;
|
||||
*/
|
||||
names: string[];
|
||||
/**
|
||||
* @generated from protobuf field: repeated tensors.Attribute attributes = 3;
|
||||
*/
|
||||
attributes: Attribute[];
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf enum tensors.Dtype
|
||||
*/
|
||||
export enum Dtype {
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_INVALID = 0;
|
||||
*/
|
||||
DT_INVALID = 0,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_FLOAT32 = 1;
|
||||
*/
|
||||
DT_FLOAT32 = 1,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_FLOAT64 = 2;
|
||||
*/
|
||||
DT_FLOAT64 = 2,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_FLOAT16 = 3;
|
||||
*/
|
||||
DT_FLOAT16 = 3,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_BFLOAT16 = 4;
|
||||
*/
|
||||
DT_BFLOAT16 = 4,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_COMPLEX32 = 5;
|
||||
*/
|
||||
DT_COMPLEX32 = 5,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_COMPLEX64 = 6;
|
||||
*/
|
||||
DT_COMPLEX64 = 6,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_COMPLEX128 = 7;
|
||||
*/
|
||||
DT_COMPLEX128 = 7,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_UINT8 = 8;
|
||||
*/
|
||||
DT_UINT8 = 8,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_INT8 = 9;
|
||||
*/
|
||||
DT_INT8 = 9,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_INT16 = 10;
|
||||
*/
|
||||
DT_INT16 = 10,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_INT32 = 11;
|
||||
*/
|
||||
DT_INT32 = 11,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_INT64 = 12;
|
||||
*/
|
||||
DT_INT64 = 12,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_BOOL = 13;
|
||||
*/
|
||||
DT_BOOL = 13,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_QUINT8 = 14;
|
||||
*/
|
||||
DT_QUINT8 = 14,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_QINT8 = 15;
|
||||
*/
|
||||
DT_QINT8 = 15,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_QINT32 = 16;
|
||||
*/
|
||||
DT_QINT32 = 16,
|
||||
/**
|
||||
* @generated from protobuf enum value: DT_QUINT4_2 = 17;
|
||||
*/
|
||||
DT_QUINT4_2 = 17
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf enum tensors.AttributeType
|
||||
*/
|
||||
export enum AttributeType {
|
||||
/**
|
||||
* @generated from protobuf enum value: AT_PARAMETER = 0;
|
||||
*/
|
||||
AT_PARAMETER = 0,
|
||||
/**
|
||||
* @generated from protobuf enum value: AT_BUFFER = 1;
|
||||
*/
|
||||
AT_BUFFER = 1
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Tensor$Type extends MessageType<Tensor> {
|
||||
constructor() {
|
||||
super("tensors.Tensor", [
|
||||
{ no: 1, name: "dtype", kind: "enum", T: () => ["tensors.Dtype", Dtype] },
|
||||
{ no: 2, name: "shape", kind: "scalar", repeat: 1 /*RepeatType.PACKED*/, T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
|
||||
{ no: 3, name: "data", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
||||
{ no: 4, name: "attr_type", kind: "enum", opt: true, T: () => ["tensors.AttributeType", AttributeType] }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Tensor>): Tensor {
|
||||
const message = { dtype: 0, shape: [], data: new Uint8Array(0) };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Tensor>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Tensor): Tensor {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* tensors.Dtype dtype */ 1:
|
||||
message.dtype = reader.int32();
|
||||
break;
|
||||
case /* repeated int64 shape */ 2:
|
||||
if (wireType === WireType.LengthDelimited)
|
||||
for (let e = reader.int32() + reader.pos; reader.pos < e;)
|
||||
message.shape.push(reader.int64().toBigInt());
|
||||
else
|
||||
message.shape.push(reader.int64().toBigInt());
|
||||
break;
|
||||
case /* bytes data */ 3:
|
||||
message.data = reader.bytes();
|
||||
break;
|
||||
case /* optional tensors.AttributeType attr_type */ 4:
|
||||
message.attrType = reader.int32();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Tensor, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* tensors.Dtype dtype = 1; */
|
||||
if (message.dtype !== 0)
|
||||
writer.tag(1, WireType.Varint).int32(message.dtype);
|
||||
/* repeated int64 shape = 2; */
|
||||
if (message.shape.length) {
|
||||
writer.tag(2, WireType.LengthDelimited).fork();
|
||||
for (let i = 0; i < message.shape.length; i++)
|
||||
writer.int64(message.shape[i]);
|
||||
writer.join();
|
||||
}
|
||||
/* bytes data = 3; */
|
||||
if (message.data.length)
|
||||
writer.tag(3, WireType.LengthDelimited).bytes(message.data);
|
||||
/* optional tensors.AttributeType attr_type = 4; */
|
||||
if (message.attrType !== undefined)
|
||||
writer.tag(4, WireType.Varint).int32(message.attrType);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message tensors.Tensor
|
||||
*/
|
||||
export const Tensor = new Tensor$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Attribute$Type extends MessageType<Attribute> {
|
||||
constructor() {
|
||||
super("tensors.Attribute", [
|
||||
{ no: 1, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "module", kind: "message", oneof: "value", T: () => Module },
|
||||
{ no: 4, name: "tensor", kind: "message", oneof: "value", T: () => Tensor },
|
||||
{ no: 5, name: "string", kind: "scalar", oneof: "value", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 6, name: "int64", kind: "scalar", oneof: "value", T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
|
||||
{ no: 7, name: "float", kind: "scalar", oneof: "value", T: 2 /*ScalarType.FLOAT*/ },
|
||||
{ no: 8, name: "bool", kind: "scalar", oneof: "value", T: 8 /*ScalarType.BOOL*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Attribute>): Attribute {
|
||||
const message = { name: "", value: { oneofKind: undefined } };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Attribute>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Attribute): Attribute {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string name */ 1:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* tensors.Module module */ 3:
|
||||
message.value = {
|
||||
oneofKind: "module",
|
||||
module: Module.internalBinaryRead(reader, reader.uint32(), options, (message.value as any).module)
|
||||
};
|
||||
break;
|
||||
case /* tensors.Tensor tensor */ 4:
|
||||
message.value = {
|
||||
oneofKind: "tensor",
|
||||
tensor: Tensor.internalBinaryRead(reader, reader.uint32(), options, (message.value as any).tensor)
|
||||
};
|
||||
break;
|
||||
case /* string string */ 5:
|
||||
message.value = {
|
||||
oneofKind: "string",
|
||||
string: reader.string()
|
||||
};
|
||||
break;
|
||||
case /* int64 int64 */ 6:
|
||||
message.value = {
|
||||
oneofKind: "int64",
|
||||
int64: reader.int64().toBigInt()
|
||||
};
|
||||
break;
|
||||
case /* float float */ 7:
|
||||
message.value = {
|
||||
oneofKind: "float",
|
||||
float: reader.float()
|
||||
};
|
||||
break;
|
||||
case /* bool bool */ 8:
|
||||
message.value = {
|
||||
oneofKind: "bool",
|
||||
bool: reader.bool()
|
||||
};
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Attribute, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string name = 1; */
|
||||
if (message.name !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.name);
|
||||
/* tensors.Module module = 3; */
|
||||
if (message.value.oneofKind === "module")
|
||||
Module.internalBinaryWrite(message.value.module, writer.tag(3, WireType.LengthDelimited).fork(), options).join();
|
||||
/* tensors.Tensor tensor = 4; */
|
||||
if (message.value.oneofKind === "tensor")
|
||||
Tensor.internalBinaryWrite(message.value.tensor, writer.tag(4, WireType.LengthDelimited).fork(), options).join();
|
||||
/* string string = 5; */
|
||||
if (message.value.oneofKind === "string")
|
||||
writer.tag(5, WireType.LengthDelimited).string(message.value.string);
|
||||
/* int64 int64 = 6; */
|
||||
if (message.value.oneofKind === "int64")
|
||||
writer.tag(6, WireType.Varint).int64(message.value.int64);
|
||||
/* float float = 7; */
|
||||
if (message.value.oneofKind === "float")
|
||||
writer.tag(7, WireType.Bit32).float(message.value.float);
|
||||
/* bool bool = 8; */
|
||||
if (message.value.oneofKind === "bool")
|
||||
writer.tag(8, WireType.Varint).bool(message.value.bool);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message tensors.Attribute
|
||||
*/
|
||||
export const Attribute = new Attribute$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Module$Type extends MessageType<Module> {
|
||||
constructor() {
|
||||
super("tensors.Module", [
|
||||
{ no: 1, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "names", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "attributes", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Attribute }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Module>): Module {
|
||||
const message = { name: "", names: [], attributes: [] };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Module>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Module): Module {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string name */ 1:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* repeated string names */ 2:
|
||||
message.names.push(reader.string());
|
||||
break;
|
||||
case /* repeated tensors.Attribute attributes */ 3:
|
||||
message.attributes.push(Attribute.internalBinaryRead(reader, reader.uint32(), options));
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Module, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string name = 1; */
|
||||
if (message.name !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.name);
|
||||
/* repeated string names = 2; */
|
||||
for (let i = 0; i < message.names.length; i++)
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.names[i]);
|
||||
/* repeated tensors.Attribute attributes = 3; */
|
||||
for (let i = 0; i < message.attributes.length; i++)
|
||||
Attribute.internalBinaryWrite(message.attributes[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message tensors.Module
|
||||
*/
|
||||
export const Module = new Module$Type();
|
||||
@@ -1,9 +0,0 @@
|
||||
export * as Dashboard from "./Generated/dashboard";
|
||||
export * from "./Generated/dashboard.client";
|
||||
export * as Engines from "./Generated/engines";
|
||||
export * from "./Generated/engines.client";
|
||||
export * as Generation from "./Generated/generation";
|
||||
export * from "./Generated/generation.client";
|
||||
export * as Project from "./Generated/project";
|
||||
export * from "./Generated/project.client";
|
||||
export * from "./Generated/google/protobuf/struct";
|
||||
@@ -1,634 +0,0 @@
|
||||
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
|
||||
import { RpcError } from "@protobuf-ts/runtime-rpc";
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
|
||||
import {
|
||||
EnginesServiceClient,
|
||||
Generation,
|
||||
GenerationServiceClient,
|
||||
Project,
|
||||
ProjectServiceClient,
|
||||
Struct,
|
||||
} from "./Proto";
|
||||
|
||||
const getStableDiffusionDefaultCount = () => 4;
|
||||
const getStableDiffusionDefaultInputFromPrompt = (prompt: string) => ({
|
||||
prompts: [
|
||||
{
|
||||
text: prompt,
|
||||
weight: 1,
|
||||
},
|
||||
|
||||
{
|
||||
text: "",
|
||||
weight: -0.75,
|
||||
},
|
||||
],
|
||||
|
||||
model: "stable-diffusion-xl-beta-v2-2-2",
|
||||
sampler: { id: "0", name: "DDIM" },
|
||||
style: "enhance",
|
||||
|
||||
width: 512,
|
||||
height: 512,
|
||||
|
||||
cfgScale: 7,
|
||||
steps: 50,
|
||||
});
|
||||
|
||||
export const createPlugin = StableStudio.createPlugin<{
|
||||
settings: {
|
||||
apiKey: StableStudio.PluginSettingString;
|
||||
};
|
||||
}>(({ context, set }) => {
|
||||
const functionsWhichNeedAPIKey = (
|
||||
apiKey?: string
|
||||
): Pick<
|
||||
StableStudio.Plugin,
|
||||
| "createStableDiffusionImages"
|
||||
| "getStableDiffusionExistingImages"
|
||||
| "getStableDiffusionModels"
|
||||
| "deleteStableDiffusionImages"
|
||||
| "getStatus"
|
||||
| "getStableDiffusionSamplers"
|
||||
> => {
|
||||
if (!apiKey)
|
||||
return {
|
||||
createStableDiffusionImages: undefined,
|
||||
getStableDiffusionExistingImages: undefined,
|
||||
getStableDiffusionModels: undefined,
|
||||
deleteStableDiffusionImages: undefined,
|
||||
|
||||
getStatus: () => ({
|
||||
indicator: "error",
|
||||
text: "Missing API key",
|
||||
}),
|
||||
};
|
||||
|
||||
const transport = new GrpcWebFetchTransport({
|
||||
baseUrl: "https://grpc.stability.ai",
|
||||
meta: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
|
||||
"stability-client-id": "StableStudio",
|
||||
"stability-client-version": context.getGitHash(),
|
||||
},
|
||||
});
|
||||
|
||||
const generation = new GenerationServiceClient(transport);
|
||||
const engines = new EnginesServiceClient(transport);
|
||||
const project = new ProjectServiceClient(transport);
|
||||
|
||||
return {
|
||||
createStableDiffusionImages: async (options) => {
|
||||
const count = options?.count ?? getStableDiffusionDefaultCount();
|
||||
const defaultStableDiffusionInput =
|
||||
getStableDiffusionDefaultInputFromPrompt(
|
||||
context.getStableDiffusionRandomPrompt()
|
||||
);
|
||||
|
||||
const input = {
|
||||
...defaultStableDiffusionInput,
|
||||
...options?.input,
|
||||
};
|
||||
|
||||
const width = input.width ?? defaultStableDiffusionInput.width;
|
||||
const height = input.height ?? defaultStableDiffusionInput.height;
|
||||
|
||||
const prompt =
|
||||
input.prompts?.map(
|
||||
({ text = context.getStableDiffusionRandomPrompt(), weight }) =>
|
||||
Generation.Prompt.create({
|
||||
prompt: { oneofKind: "text", text },
|
||||
parameters: { weight },
|
||||
})
|
||||
) ?? [];
|
||||
|
||||
// add init and mask
|
||||
if (input.maskImage?.blob) {
|
||||
prompt.push(
|
||||
Generation.Prompt.create({
|
||||
parameters: { init: false, weight: 1 },
|
||||
prompt: {
|
||||
oneofKind: "artifact",
|
||||
artifact: Generation.Artifact.create({
|
||||
type: Generation.ArtifactType.ARTIFACT_MASK,
|
||||
mime: "image/png",
|
||||
data: {
|
||||
oneofKind: "binary",
|
||||
binary: new Uint8Array(
|
||||
await input.maskImage.blob.arrayBuffer()
|
||||
),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (input.initialImage?.blob) {
|
||||
prompt.push(
|
||||
Generation.Prompt.create({
|
||||
parameters: { init: true, weight: input.initialImage.weight },
|
||||
prompt: {
|
||||
oneofKind: "artifact",
|
||||
artifact: Generation.Artifact.create({
|
||||
type: Generation.ArtifactType.ARTIFACT_IMAGE,
|
||||
mime: "image/png",
|
||||
data: {
|
||||
oneofKind: "binary",
|
||||
binary: new Uint8Array(
|
||||
await input.initialImage.blob.arrayBuffer()
|
||||
),
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.log(input.sampler.id ? parseInt(input.sampler.id) : 0);
|
||||
|
||||
const imageParams = Generation.ImageParameters.create({
|
||||
width: BigInt(width),
|
||||
height: BigInt(height),
|
||||
|
||||
steps: BigInt(input.steps),
|
||||
samples: BigInt(count),
|
||||
seed: Array.from({ length: count }, () => input.seed ?? 0),
|
||||
|
||||
transform: Generation.TransformType.create({
|
||||
type: {
|
||||
oneofKind: "diffusion",
|
||||
diffusion: input.sampler.id ? parseInt(input.sampler.id) : 0,
|
||||
},
|
||||
}),
|
||||
|
||||
parameters: [
|
||||
Generation.StepParameter.create({
|
||||
sampler: Generation.SamplerParameters.create({
|
||||
cfgScale: input.cfgScale,
|
||||
}),
|
||||
|
||||
scaledStep: 0,
|
||||
schedule: Generation.ScheduleParameters.create({
|
||||
start: input.initialImage
|
||||
? 1 - (input.initialImage.weight ?? 0)
|
||||
: 1,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const extras = (input.style || input.width !== input.height) && {
|
||||
extras: Struct.fromJson({
|
||||
$IPC: {
|
||||
preset: input.style,
|
||||
...(input.width !== input.height && { mode: "multistage" }),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const request = generation.chainGenerate({
|
||||
requestId: "",
|
||||
stage: [
|
||||
{
|
||||
id: "Main",
|
||||
|
||||
request: Generation.Request.create({
|
||||
prompt,
|
||||
|
||||
engineId: input.model,
|
||||
requestedType: Generation.ArtifactType.ARTIFACT_IMAGE,
|
||||
params: { oneofKind: "image", image: imageParams },
|
||||
|
||||
...extras,
|
||||
}),
|
||||
|
||||
onStatus: [
|
||||
{
|
||||
target: "Asset",
|
||||
reason: [],
|
||||
action: [
|
||||
Generation.StageAction.PASS,
|
||||
Generation.StageAction.RETURN,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
id: "Asset",
|
||||
|
||||
request: Generation.Request.create({
|
||||
engineId: "asset-service",
|
||||
params: {
|
||||
oneofKind: "asset",
|
||||
asset: {
|
||||
projectId: "",
|
||||
action: Generation.AssetAction.ASSET_PUT,
|
||||
use: Generation.AssetUse.OUTPUT,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
onStatus: [
|
||||
{ action: [Generation.StageAction.RETURN], reason: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let id: string | undefined;
|
||||
const images: StableStudio.StableDiffusionImage[] = [];
|
||||
|
||||
for await (const response of request.responses) {
|
||||
for (const artifact of response.artifacts) {
|
||||
if (
|
||||
artifact.type === Generation.ArtifactType.ARTIFACT_TEXT &&
|
||||
artifact.finishReason === Generation.FinishReason.FILTER
|
||||
)
|
||||
throw new RpcError("Banned word detected!", "BANNED_TERM");
|
||||
|
||||
if (
|
||||
artifact.type === Generation.ArtifactType.ARTIFACT_IMAGE &&
|
||||
artifact.data.oneofKind === "binary"
|
||||
) {
|
||||
id = response.requestId;
|
||||
images.push({
|
||||
input: {
|
||||
...input,
|
||||
seed: artifact.seed,
|
||||
},
|
||||
id: artifact.uuid,
|
||||
blob: new Blob([artifact.data.binary], { type: "image/png" }),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id ? { id, images } : undefined;
|
||||
},
|
||||
|
||||
getStableDiffusionExistingImages: async (options) => {
|
||||
const { limit, exclusiveStartImageID } = { limit: 25, ...options };
|
||||
if (limit <= 0) return [];
|
||||
|
||||
const { response } = await project.queryAssets({
|
||||
id: "",
|
||||
limit: BigInt(limit),
|
||||
startKey: exclusiveStartImageID,
|
||||
use: [Project.ProjectAssetUse.OUTPUT],
|
||||
sortDir: Project.ProjectSortDir.DESC,
|
||||
tags: {},
|
||||
});
|
||||
|
||||
type ImageWithBlobPromise = Omit<
|
||||
StableStudio.StableDiffusionImage,
|
||||
"blob"
|
||||
> & { blob: Promise<Blob> };
|
||||
|
||||
type ImagesWithBlobPromises = Record<
|
||||
StableStudio.ID,
|
||||
Omit<StableStudio.StableDiffusionImages, "images"> & {
|
||||
images: ImageWithBlobPromise[];
|
||||
}
|
||||
>;
|
||||
|
||||
const images = response.assets.reduce((previous, response) => {
|
||||
if (
|
||||
!response.request ||
|
||||
response.request.params.oneofKind !== "image"
|
||||
)
|
||||
return previous;
|
||||
|
||||
const prompts = response.request.prompt.reduce((prompts, prompt) => {
|
||||
if (
|
||||
prompt.prompt.oneofKind !== "artifact" ||
|
||||
prompt.prompt.artifact.data.oneofKind !== "text"
|
||||
)
|
||||
return prompts;
|
||||
|
||||
return [
|
||||
...prompts,
|
||||
{
|
||||
text: prompt.prompt.artifact.data.text,
|
||||
weight: prompt.parameters?.weight ?? 1,
|
||||
},
|
||||
];
|
||||
}, [] as StableStudio.StableDiffusionPrompt[]);
|
||||
|
||||
if (prompts.length === 0) return previous;
|
||||
|
||||
const id = response.request.requestId.split(":")[0];
|
||||
if (!id) return previous;
|
||||
|
||||
const imageID = response.id;
|
||||
const createdAt = new Date(Number(response.createdAt) * 1000);
|
||||
|
||||
const model = response.request.engineId;
|
||||
const style = parseExtras(response.request.extras?.fields).$IPC
|
||||
?.preset;
|
||||
|
||||
const width = response.request.params.image.width
|
||||
? Number(response.request.params.image.width)
|
||||
: undefined;
|
||||
|
||||
const height = response.request.params.image.height
|
||||
? Number(response.request.params.image.height)
|
||||
: undefined;
|
||||
|
||||
const cfgScale = response.request.params.image.parameters.reduce(
|
||||
(_, parameters) =>
|
||||
parameters.sampler?.cfgScale
|
||||
? Number(parameters.sampler.cfgScale)
|
||||
: undefined,
|
||||
undefined as number | undefined
|
||||
);
|
||||
|
||||
const steps = response.request.params.image.steps
|
||||
? Number(response.request.params.image.steps)
|
||||
: undefined;
|
||||
|
||||
const seed = response.request.params.image.seed[0]
|
||||
? Number(response.request.params.image.seed[0])
|
||||
: undefined;
|
||||
|
||||
const input: StableStudio.StableDiffusionInput = {
|
||||
prompts,
|
||||
|
||||
model,
|
||||
style,
|
||||
|
||||
width,
|
||||
height,
|
||||
|
||||
cfgScale,
|
||||
steps,
|
||||
seed,
|
||||
};
|
||||
|
||||
const src = response.uri
|
||||
?.replace(
|
||||
"https://object.lga1.coreweave.com/stability-staging-assets",
|
||||
"https://staging-cdn.stability.ai/assets"
|
||||
)
|
||||
?.replace(
|
||||
"https://object.lga1.coreweave.com/stability-assets",
|
||||
"https://cdn.stability.ai/assets"
|
||||
);
|
||||
|
||||
const image = {
|
||||
id: imageID,
|
||||
createdAt,
|
||||
input,
|
||||
blob: fetch(src).then((response) => response.blob()),
|
||||
};
|
||||
|
||||
return {
|
||||
...previous,
|
||||
[id]: {
|
||||
...previous[id],
|
||||
...(exclusiveStartImageID === imageID && {
|
||||
exclusiveStartImageID: imageID,
|
||||
}),
|
||||
|
||||
images: [...(previous[id]?.images ?? []), image],
|
||||
id: id,
|
||||
},
|
||||
};
|
||||
}, {} as ImagesWithBlobPromises);
|
||||
|
||||
return Promise.all(
|
||||
Object.values(images).map(async ({ id, images }) => ({
|
||||
id,
|
||||
images: await Promise.all(
|
||||
images?.map(async ({ blob, ...image }) => ({
|
||||
...image,
|
||||
blob: await blob,
|
||||
}))
|
||||
),
|
||||
exclusiveStartImageID: images?.[images.length - 1]?.id,
|
||||
}))
|
||||
);
|
||||
},
|
||||
|
||||
getStableDiffusionModels: async () => {
|
||||
const request = await engines.listEngines({});
|
||||
const allEngines = await request.response.engine;
|
||||
return allEngines.filter((engine) => engine.type === 1 && engine.ready);
|
||||
},
|
||||
|
||||
deleteStableDiffusionImages: async (options) => {
|
||||
const imageIDs = options?.imageIDs;
|
||||
imageIDs &&
|
||||
(await project.deleteAssets({ id: "", assetIds: imageIDs }));
|
||||
},
|
||||
|
||||
getStatus: () => ({
|
||||
indicator: "success",
|
||||
text: "Ready",
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
...functionsWhichNeedAPIKey(
|
||||
localStorage.getItem("stability-apiKey") ?? undefined
|
||||
),
|
||||
|
||||
getStableDiffusionSamplers: () => [
|
||||
{ id: "0", name: "DDIM" },
|
||||
{ id: "1", name: "DDPM" },
|
||||
{ id: "2", name: "K Euler" },
|
||||
{ id: "3", name: "K Euler Ancestral" },
|
||||
{ id: "4", name: "K Heun" },
|
||||
{ id: "5", name: "K DPM 2" },
|
||||
{ id: "6", name: "K DPM 2 Ancestral" },
|
||||
{ id: "7", name: "K LMS" },
|
||||
{ id: "8", name: "K DPM++ 2S Ancestral" },
|
||||
{ id: "9", name: "K DPM++ 2M" },
|
||||
{ id: "10", name: "K DPM++ SDE" },
|
||||
],
|
||||
|
||||
getStableDiffusionStyles: () => [
|
||||
{
|
||||
id: "enhance",
|
||||
name: "Enhance",
|
||||
image: "https://dreamstudio.ai/presets/enhance.png",
|
||||
},
|
||||
{
|
||||
id: "anime",
|
||||
name: "Anime",
|
||||
image: "https://dreamstudio.ai/presets/anime.png",
|
||||
},
|
||||
{
|
||||
id: "photographic",
|
||||
name: "Photographic",
|
||||
image: "https://dreamstudio.ai/presets/photographic.png",
|
||||
},
|
||||
{
|
||||
id: "digital-art",
|
||||
name: "Digital art",
|
||||
image: "https://dreamstudio.ai/presets/digital-art.png",
|
||||
},
|
||||
{
|
||||
id: "comic-book",
|
||||
name: "Comic book",
|
||||
image: "https://dreamstudio.ai/presets/comic-book.png",
|
||||
},
|
||||
{
|
||||
id: "fantasy-art",
|
||||
name: "Fantasy art",
|
||||
image: "https://dreamstudio.ai/presets/fantasy-art.png",
|
||||
},
|
||||
{
|
||||
id: "analog-film",
|
||||
name: "Analog film",
|
||||
image: "https://dreamstudio.ai/presets/analog-film.png",
|
||||
},
|
||||
{
|
||||
id: "neon-punk",
|
||||
name: "Neon punk",
|
||||
image: "https://dreamstudio.ai/presets/neon-punk.png",
|
||||
},
|
||||
{
|
||||
id: "isometric",
|
||||
name: "Isometric",
|
||||
image: "https://dreamstudio.ai/presets/isometric.png",
|
||||
},
|
||||
{
|
||||
id: "low-poly",
|
||||
name: "Low poly",
|
||||
image: "https://dreamstudio.ai/presets/low-poly.png",
|
||||
},
|
||||
{
|
||||
id: "origami",
|
||||
name: "Origami",
|
||||
image: "https://dreamstudio.ai/presets/origami.png",
|
||||
},
|
||||
{
|
||||
id: "line-art",
|
||||
name: "Line art",
|
||||
image: "https://dreamstudio.ai/presets/line-art.png",
|
||||
},
|
||||
{
|
||||
id: "modeling-compound",
|
||||
name: "Craft clay",
|
||||
image: "https://dreamstudio.ai/presets/modeling-compound.png",
|
||||
},
|
||||
{
|
||||
id: "cinematic",
|
||||
name: "Cinematic",
|
||||
image: "https://dreamstudio.ai/presets/cinematic.png",
|
||||
},
|
||||
{
|
||||
id: "3d-model",
|
||||
name: "3D model",
|
||||
image: "https://dreamstudio.ai/presets/3d-model.png",
|
||||
},
|
||||
{
|
||||
id: "pixel-art",
|
||||
name: "Pixel art",
|
||||
image: "https://dreamstudio.ai/presets/pixel-art.png",
|
||||
},
|
||||
],
|
||||
|
||||
getStableDiffusionDefaultCount,
|
||||
getStableDiffusionDefaultInput: () =>
|
||||
getStableDiffusionDefaultInputFromPrompt(
|
||||
context.getStableDiffusionRandomPrompt()
|
||||
),
|
||||
|
||||
settings: {
|
||||
apiKey: {
|
||||
type: "string",
|
||||
|
||||
title: "API key",
|
||||
description:
|
||||
"You can find your Stability API key at https://dreamstudio.ai/account",
|
||||
|
||||
placeholder: "sk-...",
|
||||
required: true,
|
||||
password: true,
|
||||
|
||||
value: localStorage.getItem("stability-apiKey") ?? "",
|
||||
},
|
||||
},
|
||||
|
||||
setSetting: (key, value) => {
|
||||
set(({ settings }) => ({
|
||||
settings: {
|
||||
...settings,
|
||||
[key]: { ...settings[key], value: value as string },
|
||||
},
|
||||
}));
|
||||
|
||||
if (key === "apiKey" && typeof value === "string") {
|
||||
localStorage.setItem("stability-apiKey", value);
|
||||
set((plugin) => ({ ...plugin, ...functionsWhichNeedAPIKey(value) }));
|
||||
}
|
||||
},
|
||||
|
||||
manifest: {
|
||||
author: "Stability AI",
|
||||
description: markdownDescription,
|
||||
name: "Stability AI",
|
||||
license: "MIT",
|
||||
link: "https://stability.ai",
|
||||
version: "0.0.0",
|
||||
icon: "https://stability.ai/favicon.ico",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function parseExtras(extras: any): any | undefined {
|
||||
if (!extras) return undefined;
|
||||
|
||||
if (extras.kind?.oneofKind === "structValue") {
|
||||
return parseExtras(extras.kind.structValue.fields);
|
||||
} else if (extras.kind?.oneofKind === "listValue") {
|
||||
return extras.listValue.values.map(parseExtras);
|
||||
} else if (extras.kind?.oneofKind === "numberValue") {
|
||||
return Number(extras.kind.numberValue);
|
||||
} else if (extras.kind?.oneofKind === "stringValue") {
|
||||
return extras.kind.stringValue;
|
||||
} else if (extras.kind?.oneofKind === "boolValue") {
|
||||
return extras.kind.boolValue;
|
||||
} else if (extras.kind?.oneofKind === undefined) {
|
||||
return {
|
||||
...Object.keys(extras).reduce((previous, key) => {
|
||||
return { ...previous, [key]: parseExtras(extras[key]) };
|
||||
}, {}),
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const markdownDescription = `
|
||||
# Welcome to StableStudio!
|
||||
|
||||
## [📖 README](https://github.com/Stability-AI/StableStudio) · [🎮 Discord](https://discord.com/channels/1002292111942635562/1108055793674227782) · [🌈 DreamStudio](https://dreamstudio.ai) · [💬 Discussion](https://github.com/Stability-AI/StableStudio/discussions)
|
||||
|
||||
# Setup
|
||||
|
||||
To get started, you'll need to sign up for a [DreamStudio](https://dreamstudio.ai) account.
|
||||
|
||||
Once you're logged in, head to the [account page](https://dreamstudio.ai/account).
|
||||
|
||||
You should see a section called \`API keys\`...
|
||||

|
||||
|
||||
If you don't already have a key, you can create one via the plus button...
|
||||

|
||||
|
||||
You can copy your API key by clicking the copy button...
|
||||

|
||||
|
||||
You'll be asked to accept the terms of service.
|
||||
|
||||
Now, paste the key into the field below...
|
||||
|
||||
The plugin status should change to \`Ready\` once everything is working.
|
||||
` as const;
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
|
||||
"outDir": "./lib",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
{ "transform": "typescript-transform-paths" },
|
||||
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{ "extends": ["../../.eslintrc.json"] }
|
||||
@@ -1 +0,0 @@
|
||||
lib
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Stability AI
|
||||
|
||||
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.
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "@stability/stablestudio-plugin-webgpu",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf lib && rimraf node_modules",
|
||||
"build:types": "ttsc --project tsconfig.json",
|
||||
"build:javascript": "tsx scripts/Build.ts",
|
||||
"build": "yarn build:types && yarn build:javascript",
|
||||
"dev": "nodemon --watch src --ext ts,tsx,json --exec \"yarn build\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@stability/stablestudio-plugin": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"eslint": "8.22.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-markdown": "^3.0.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^3.12.1",
|
||||
"ttypescript": "^1.5.13",
|
||||
"typescript": "4.8.4",
|
||||
"typescript-transform-paths": "^3.4.4"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import * as ESBuild from "esbuild";
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
await ESBuild.build({
|
||||
entryPoints: ["src/index.ts"],
|
||||
outdir: "lib",
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
minify: true,
|
||||
splitting: true,
|
||||
format: "esm",
|
||||
target: ["esnext"],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
@@ -1,3 +0,0 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
|
||||
export const createPlugin = StableStudio.createPlugin(() => ({}));
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
|
||||
"outDir": "./lib",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
{ "transform": "typescript-transform-paths" },
|
||||
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{ "extends": ["../../.eslintrc.json"] }
|
||||
@@ -1 +0,0 @@
|
||||
lib
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Stability AI
|
||||
|
||||
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.
|
||||
@@ -1,67 +0,0 @@
|
||||
<div align="center">
|
||||
|
||||
# 🔌 [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui) Plugin
|
||||
|
||||
**🗺 Contents – [ℹ️ About](#about) · [⚙️ Usage](#usage) · [⭐️ Features](#features)**
|
||||
|
||||
**[⬆️ Top-Level README](../../README.md)**
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
# <a id="about" href="#about">ℹ️ About</a>
|
||||
|
||||
This plugin enables StableStudio to run using [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui), which means you can generate images entirely on your own machine!
|
||||
|
||||
Thanks goes to [Terry Jia](https://github.com/jtydhr88) for the original work on this plugin.
|
||||
|
||||
# <a id="usage" href="#usage">⚙️ Usage</a>
|
||||
|
||||
1. First, you'll need to configure your local installation of `stable-diffusion-webui` to run without the UI and with CORS enabled.
|
||||
|
||||
**Windows**
|
||||
|
||||
Edit the command line arguments within `webui-user.bat`:
|
||||
|
||||
```
|
||||
set COMMANDLINE_ARGS=--nowebui --cors-allow-origins=http://localhost:3000
|
||||
```
|
||||
|
||||
**Mac**
|
||||
|
||||
Edit the command line arguments within `webui-macos-env.sh`:
|
||||
|
||||
```
|
||||
export COMMANDLINE_ARGS="--nowebui --cors-allow-origins=http://localhost:3000"
|
||||
```
|
||||
|
||||
2. Start `stable-diffusion-webui` and look for `INFO: Uvicorn running on http://127.0.0.1:7861`.
|
||||
|
||||
You can make sure everything is running correctly by checking to see if [`http://127.0.0.1:7861/docs`](http://127.0.0.1:7861/docs) displays API documentation.
|
||||
|
||||
3. Within your installation of StableStudio, run `yarn dev:use-webui-plugin`.
|
||||
|
||||
_**That's it!**_ 🎉 You should now be able to generate images using your local machine.
|
||||
|
||||
## <a id="image-history" href="#image-history">💾 Image History</a>
|
||||
|
||||
To persist your image history, you'll need to install the [`sd-webui-StableStudio`](https://github.com/jtydhr88/sd-webui-StableStudio) extension for `stable-diffusion-webui`.
|
||||
|
||||
> 🛑 Be wary installing third-party extensions for `stable-diffusion-webui`, it's always a good idea to check before running untrusted code.
|
||||
|
||||
# <a id="features" href="#features">⭐️ Features</a>
|
||||
|
||||
Missing something? Please [let us know](https://github.com/Stability-AI/StableStudio/issues/new/choose)!
|
||||
|
||||
- [x] Text-to-image
|
||||
- [x] Image-to-image
|
||||
- [x] Basic features (prompt, negative prompt, steps, batch size, image size)
|
||||
- [x] Model selection
|
||||
- [x] Sampler selection
|
||||
- [x] Masking, in-painting, and out-painting
|
||||
- [x] Settings storage
|
||||
- [x] Accurate plugin status
|
||||
- [x] [Loading existing images]("#image-history)
|
||||
- [x] Upscaling
|
||||
- [ ] Lora support
|
||||
@@ -1,21 +0,0 @@
|
||||
import * as ESBuild from "esbuild";
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
await ESBuild.build({
|
||||
entryPoints: ["src/index.ts"],
|
||||
outdir: "lib",
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
minify: true,
|
||||
splitting: true,
|
||||
format: "esm",
|
||||
target: ["esnext"],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
@@ -1,184 +0,0 @@
|
||||
import { StableDiffusionInput } from "@stability/stablestudio-plugin";
|
||||
|
||||
export function base64ToBlob(base64: string, contentType = ""): Promise<Blob> {
|
||||
return fetch(`data:${contentType};base64,${base64}`).then((res) =>
|
||||
res.blob()
|
||||
);
|
||||
}
|
||||
|
||||
export function blobToBase64(blob: Blob): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.onerror = reject;
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchOptions(baseUrl: string | undefined) {
|
||||
const optionsResponse = await fetch(`${baseUrl}/sdapi/v1/options`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
return await optionsResponse.json();
|
||||
}
|
||||
|
||||
export async function setOptions(baseUrl: string | undefined, options: any) {
|
||||
const optionsResponse = await fetch(`${baseUrl}/sdapi/v1/options`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(options),
|
||||
});
|
||||
|
||||
return await optionsResponse.json();
|
||||
}
|
||||
|
||||
export async function getImageInfo(
|
||||
baseUrl: string | undefined,
|
||||
base64image: any
|
||||
) {
|
||||
const imageInfoResponse = await fetch(`${baseUrl}/sdapi/v1/png-info`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ image: base64image }),
|
||||
});
|
||||
|
||||
const imageInfoJson = await imageInfoResponse.json();
|
||||
|
||||
const info = imageInfoJson.info.split("\n");
|
||||
|
||||
const data: any = {};
|
||||
|
||||
if (info.length === 0) {
|
||||
return data;
|
||||
}
|
||||
|
||||
data.prompt = info[0];
|
||||
|
||||
let detailIndex = 1;
|
||||
|
||||
if (info.length === 3) {
|
||||
data.nagtivePrompt = info[1].split(":")[1].trim();
|
||||
|
||||
detailIndex = 2;
|
||||
}
|
||||
|
||||
const details = info[detailIndex].split(",");
|
||||
|
||||
details.map((detail: any) => {
|
||||
const detailInfo = detail.trim().split(":");
|
||||
|
||||
data[detailInfo[0]] = detailInfo[1].trim();
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function testForHistoryPlugin(webuiHostUrl: string) {
|
||||
// timeout after 1 second
|
||||
const finished = Promise.race([
|
||||
fetch(`${webuiHostUrl}/StableStudio/get-generated-images`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
limit: 1,
|
||||
}),
|
||||
}),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error("Request timed out")), 1000)
|
||||
),
|
||||
]);
|
||||
|
||||
try {
|
||||
await finished;
|
||||
return (finished as any).ok;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function constructPayload(
|
||||
options: {
|
||||
input?: StableDiffusionInput | undefined;
|
||||
count?: number | undefined;
|
||||
},
|
||||
isUpscale = false,
|
||||
upscaler: string | undefined
|
||||
) {
|
||||
const { sampler, prompts, initialImage, maskImage, width, height, steps } =
|
||||
options?.input ?? {};
|
||||
|
||||
// Construct payload
|
||||
const data: any = {
|
||||
seed: options?.input?.seed === 0 ? -1 : options?.input?.seed,
|
||||
cfgScale: options?.input?.cfgScale ?? 7,
|
||||
};
|
||||
|
||||
if (isUpscale) {
|
||||
/*
|
||||
Upscaling values
|
||||
*/
|
||||
|
||||
data.upscaling_resize_w = width ?? 512;
|
||||
data.upscaling_resize_h = height ?? 512;
|
||||
data.upscaler_1 = upscaler;
|
||||
} else {
|
||||
/*
|
||||
regular image generation values
|
||||
*/
|
||||
|
||||
data.width = width ?? 512;
|
||||
data.height = height ?? 512;
|
||||
|
||||
data.sampler_name = sampler?.name ?? "";
|
||||
data.sampler_index = sampler?.name ?? "";
|
||||
|
||||
data.prompt =
|
||||
prompts?.find((p) => (p.text && (p.weight ?? 0) > 0) ?? 0 > 0)?.text ??
|
||||
"";
|
||||
data.negative_prompt =
|
||||
prompts?.find((p) => (p.text && (p.weight ?? 0) < 0) ?? 0 < 0)?.text ??
|
||||
"";
|
||||
|
||||
data.steps = steps ?? 20;
|
||||
data.batch_size = options?.count;
|
||||
data.save_images = true;
|
||||
}
|
||||
|
||||
if (initialImage?.weight && !isUpscale) {
|
||||
data.denoising_strength = 1 - initialImage.weight;
|
||||
}
|
||||
|
||||
if (initialImage?.blob) {
|
||||
const initImgB64 = await blobToBase64(initialImage?.blob);
|
||||
|
||||
if (isUpscale) {
|
||||
data.image = initImgB64.split(",")[1];
|
||||
} else {
|
||||
data.init_images = [initImgB64.split(",")[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (maskImage?.blob) {
|
||||
const maskImgB64 = await blobToBase64(maskImage?.blob);
|
||||
|
||||
data.mask = maskImgB64.split(",")[1];
|
||||
|
||||
data.inpainting_mask_invert = 1; // Mask mode
|
||||
data.inpainting_fill = 1; // Masked content
|
||||
data.inpaint_full_res = false; // Inpaint area
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
import { StableDiffusionImage } from "@stability/stablestudio-plugin";
|
||||
|
||||
import {
|
||||
base64ToBlob,
|
||||
constructPayload,
|
||||
fetchOptions,
|
||||
getImageInfo,
|
||||
setOptions,
|
||||
testForHistoryPlugin,
|
||||
} from "./Utilities";
|
||||
|
||||
const manifest = {
|
||||
name: "stable-diffusion-webui",
|
||||
author: "Terry Jia",
|
||||
link: "https://github.com/jtydhr88",
|
||||
icon: `${window.location.origin}/DummyImage.png`,
|
||||
version: "0.0.0",
|
||||
license: "MIT",
|
||||
description:
|
||||
"This plugin uses [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui) as its back-end for inference",
|
||||
};
|
||||
|
||||
const webuiUpscalers = [
|
||||
{
|
||||
label: "None",
|
||||
value: "None",
|
||||
},
|
||||
{
|
||||
label: "Lanczos",
|
||||
value: "Lanczos",
|
||||
},
|
||||
{
|
||||
label: "Nearest",
|
||||
value: "Nearest",
|
||||
},
|
||||
{
|
||||
label: "ESRGAN_4x",
|
||||
value: "ESRGAN_4x",
|
||||
},
|
||||
{
|
||||
label: "LDSR",
|
||||
value: "LDSR",
|
||||
},
|
||||
{
|
||||
label: "R-ESRGAN 4x+",
|
||||
value: "R-ESRGAN 4x+",
|
||||
},
|
||||
{
|
||||
label: "R-ESRGAN 4x+ Anime6B",
|
||||
value: "R-ESRGAN 4x+ Anime6B",
|
||||
},
|
||||
{
|
||||
label: "ScuNET GAN",
|
||||
value: "ScuNET GAN",
|
||||
},
|
||||
{
|
||||
label: "ScuNET PSNR",
|
||||
value: "ScuNET PSNR",
|
||||
},
|
||||
{
|
||||
label: "SwinIR_4x",
|
||||
value: "SwinIR_4x",
|
||||
},
|
||||
];
|
||||
|
||||
const getNumber = (strValue: string | null, defaultValue: number) => {
|
||||
let retValue = defaultValue;
|
||||
|
||||
if (strValue) {
|
||||
retValue = Number(strValue);
|
||||
}
|
||||
|
||||
return retValue;
|
||||
};
|
||||
|
||||
const getStableDiffusionDefaultCount = () => 4;
|
||||
export const createPlugin = StableStudio.createPlugin<{
|
||||
settings: {
|
||||
baseUrl: StableStudio.PluginSettingString;
|
||||
upscaler: StableStudio.PluginSettingString;
|
||||
historyImagesCount: StableStudio.PluginSettingNumber;
|
||||
};
|
||||
}>(({ set, get }) => {
|
||||
const webuiLoad = (
|
||||
webuiHostUrl?: string
|
||||
): Pick<
|
||||
StableStudio.Plugin,
|
||||
| "createStableDiffusionImages"
|
||||
| "getStatus"
|
||||
| "getStableDiffusionModels"
|
||||
| "getStableDiffusionSamplers"
|
||||
| "getStableDiffusionDefaultCount"
|
||||
| "getStableDiffusionDefaultInput"
|
||||
| "getStableDiffusionExistingImages"
|
||||
> => {
|
||||
webuiHostUrl = webuiHostUrl ?? "http://127.0.0.1:7861";
|
||||
|
||||
return {
|
||||
createStableDiffusionImages: async (options) => {
|
||||
if (!options) {
|
||||
throw new Error("options is required");
|
||||
}
|
||||
|
||||
// fetch the current webui options (model/sampler/etc)
|
||||
const webUIOptions = await fetchOptions(webuiHostUrl);
|
||||
|
||||
const { model, sampler, initialImage } = options?.input ?? {};
|
||||
options.count = options?.count ?? getStableDiffusionDefaultCount();
|
||||
|
||||
// quickly save the sampler and model name to local storage
|
||||
if (sampler?.name) {
|
||||
localStorage.setItem("webui-saved-sampler", sampler.name);
|
||||
}
|
||||
|
||||
if (model) {
|
||||
localStorage.setItem("webui-saved-model", model);
|
||||
}
|
||||
|
||||
// little hacky until StableStudio is better with upscaling
|
||||
const isUpscale =
|
||||
options?.input?.initialImage?.weight === 1 &&
|
||||
model === "esrgan-v1-x2plus";
|
||||
|
||||
// WebUI doesn't have the right model loaded, switch the model
|
||||
if (model && model !== webUIOptions.sd_model_checkpoint && !isUpscale) {
|
||||
localStorage.setItem("webui-saved-model", model);
|
||||
const modelResponse = await setOptions(webuiHostUrl, {
|
||||
sd_model_checkpoint: model,
|
||||
});
|
||||
|
||||
if (modelResponse.ok) {
|
||||
console.log("applied model");
|
||||
}
|
||||
}
|
||||
|
||||
// Construct payload for webui
|
||||
const data = await constructPayload(
|
||||
options,
|
||||
isUpscale,
|
||||
get().settings.upscaler.value
|
||||
);
|
||||
|
||||
// Send payload to webui
|
||||
const response = await fetch(
|
||||
initialImage
|
||||
? isUpscale
|
||||
? `${webuiHostUrl}/sdapi/v1/extra-single-image`
|
||||
: `${webuiHostUrl}/sdapi/v1/img2img`
|
||||
: `${webuiHostUrl}/sdapi/v1/txt2img`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
}
|
||||
);
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
const images = [];
|
||||
const createdAt = new Date();
|
||||
|
||||
if (isUpscale) {
|
||||
// Upscaling only returns one image
|
||||
const blob = await base64ToBlob(responseData.image, "image/jpeg");
|
||||
|
||||
const image = {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt: createdAt,
|
||||
blob: blob,
|
||||
input: {
|
||||
model: model ?? "",
|
||||
},
|
||||
};
|
||||
|
||||
images.push(image);
|
||||
} else {
|
||||
// Image generation returns an array of images
|
||||
const startIndex =
|
||||
responseData.images.length > data.batch_size ? 1 : 0;
|
||||
|
||||
for (let i = startIndex; i < responseData.images.length; i++) {
|
||||
const blob = await base64ToBlob(
|
||||
responseData.images[i],
|
||||
"image/jpeg"
|
||||
);
|
||||
|
||||
const image: StableDiffusionImage = {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
input: {
|
||||
prompts: options?.input?.prompts ?? [],
|
||||
steps: options?.input?.steps ?? 0,
|
||||
seed: responseData.images[i].seed,
|
||||
model: model ?? "",
|
||||
width: options?.input?.width ?? 512,
|
||||
height: options?.input?.height ?? 512,
|
||||
cfgScale: options?.input?.cfgScale ?? 7,
|
||||
sampler: sampler ?? { id: "", name: "" },
|
||||
},
|
||||
};
|
||||
|
||||
images.push(image);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
images: images,
|
||||
};
|
||||
},
|
||||
|
||||
getStableDiffusionModels: async () => {
|
||||
const response = await fetch(`${webuiHostUrl}/sdapi/v1/sd-models`);
|
||||
const responseData = await response.json();
|
||||
|
||||
return responseData.map((model: any) => ({
|
||||
id: model.title,
|
||||
name: model.model_name,
|
||||
}));
|
||||
},
|
||||
|
||||
getStatus: async () => {
|
||||
const optionsResponse = await fetch(`${webuiHostUrl}/sdapi/v1/options`);
|
||||
const hasWebuiHistoryPlugin = await testForHistoryPlugin(
|
||||
`${webuiHostUrl}`
|
||||
);
|
||||
|
||||
return optionsResponse.ok
|
||||
? {
|
||||
indicator: hasWebuiHistoryPlugin ? "success" : "info",
|
||||
text: `Ready ${
|
||||
hasWebuiHistoryPlugin ? "with" : "without"
|
||||
} history plugin`,
|
||||
}
|
||||
: {
|
||||
indicator: "error",
|
||||
text: "unable to connect webui on " + webuiHostUrl,
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const webuiHostUrl =
|
||||
localStorage.getItem("webui-host-url") ?? "http://127.0.0.1:7861";
|
||||
|
||||
return {
|
||||
...webuiLoad(webuiHostUrl),
|
||||
|
||||
getStableDiffusionDefaultCount: () => 4,
|
||||
|
||||
getStableDiffusionDefaultInput: () => {
|
||||
return {
|
||||
steps: 20,
|
||||
sampler: {
|
||||
id: localStorage.getItem("webui-saved-sampler") ?? "",
|
||||
name: localStorage.getItem("webui-saved-sampler") ?? "",
|
||||
},
|
||||
model: localStorage.getItem("webui-saved-model") ?? "",
|
||||
};
|
||||
},
|
||||
|
||||
getStableDiffusionSamplers: async () => {
|
||||
const response = await fetch(`${webuiHostUrl}/sdapi/v1/samplers`);
|
||||
const responseData = await response.json();
|
||||
|
||||
return responseData.map((sampler: any) => ({
|
||||
id: sampler.name,
|
||||
name: sampler.name,
|
||||
}));
|
||||
},
|
||||
|
||||
getStableDiffusionExistingImages: async () => {
|
||||
const existingImagesResponse = await fetch(
|
||||
`${webuiHostUrl}/StableStudio/get-generated-images`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
limit: get().settings.historyImagesCount.value,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (!existingImagesResponse.ok) {
|
||||
console.warn("unable to get existing data from webui");
|
||||
}
|
||||
|
||||
const responseData = await existingImagesResponse.json();
|
||||
|
||||
const images = [];
|
||||
|
||||
for (let i = 0; i < responseData.length; i++) {
|
||||
const imageInfo = await getImageInfo(
|
||||
webuiHostUrl,
|
||||
responseData[i].content
|
||||
);
|
||||
|
||||
const blob = await base64ToBlob(responseData[i].content, "image/jpeg");
|
||||
|
||||
const timestampInSeconds = responseData[i].create_date;
|
||||
const timestampInMilliseconds = timestampInSeconds * 1000;
|
||||
const createdAt = new Date(timestampInMilliseconds);
|
||||
|
||||
const stableDiffusionImage = {
|
||||
id: responseData[i].image_name,
|
||||
createdAt: createdAt,
|
||||
blob: blob,
|
||||
input: {
|
||||
prompts: [
|
||||
{
|
||||
text: imageInfo["prompt"],
|
||||
weight: imageInfo["CFG scale"],
|
||||
},
|
||||
],
|
||||
style: "",
|
||||
steps: Number(imageInfo["Steps"]) ?? -1,
|
||||
seed: Number(imageInfo["Seed"]) ?? -1,
|
||||
model: imageInfo["Model"] ?? "",
|
||||
width: responseData[i].width,
|
||||
height: responseData[i].height,
|
||||
},
|
||||
};
|
||||
|
||||
images.push(stableDiffusionImage);
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
images: images,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
settings: {
|
||||
baseUrl: {
|
||||
type: "string",
|
||||
title: "Host URL",
|
||||
placeholder: "http://127.0.0.1:7861",
|
||||
value: localStorage.getItem("webui-host-url") ?? "",
|
||||
description:
|
||||
"The URL of the `stable-diffusion-webui` host, usually http://127.0.0.1:7861",
|
||||
},
|
||||
|
||||
upscaler: {
|
||||
type: "string",
|
||||
title: "Upscaler 1",
|
||||
options: webuiUpscalers,
|
||||
value: localStorage.getItem("upscaler1") ?? webuiUpscalers[0].value,
|
||||
description:
|
||||
"Select the upscaler used when downloading images at more than 1x size",
|
||||
},
|
||||
|
||||
historyImagesCount: {
|
||||
type: "number",
|
||||
title: "History image count",
|
||||
description: "How many images should be fetched from local history?",
|
||||
min: 0,
|
||||
max: 50,
|
||||
step: 1,
|
||||
variant: "slider",
|
||||
value: getNumber(localStorage.getItem("historyImagesCount"), 20),
|
||||
},
|
||||
},
|
||||
|
||||
setSetting: (key, value) => {
|
||||
set(({ settings }) => ({
|
||||
settings: {
|
||||
...settings,
|
||||
[key]: { ...settings[key], value: value as string },
|
||||
},
|
||||
}));
|
||||
|
||||
if (key === "baseUrl" && typeof value === "string") {
|
||||
localStorage.setItem("webui-host-url", value);
|
||||
set((plugin) => ({ ...plugin, ...webuiLoad(value) }));
|
||||
} else if (key === "upscaler" && typeof value === "string") {
|
||||
localStorage.setItem("upscaler1", value);
|
||||
} else if (key === "historyImagesCount" && typeof value === "number") {
|
||||
localStorage.setItem("historyImagesCount", value.toString());
|
||||
}
|
||||
},
|
||||
|
||||
manifest,
|
||||
};
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
|
||||
"outDir": "./lib",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
{ "transform": "typescript-transform-paths" },
|
||||
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,8 @@
|
||||
"build:preview": "yarn build:types && vite build --mode preview",
|
||||
"build:production": "yarn build:types && vite build --mode production",
|
||||
"dev:types": "tsc --noEmit --watch",
|
||||
"dev": "vite"
|
||||
"dev": "cargo tauri dev",
|
||||
"dev:vite": "vite"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/css": "^11.10.5",
|
||||
@@ -21,11 +22,11 @@
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
"@reecelucas/react-use-hotkeys": "^2.0.0",
|
||||
"@stability/stablestudio-plugin": "workspace:^",
|
||||
"@stability/stablestudio-plugin-example": "workspace:^",
|
||||
"@stability/stablestudio-plugin-stability": "workspace:^",
|
||||
"@stability/stablestudio-plugin-comfy": "workspace:^",
|
||||
"@tanstack/react-query": "^4.22.0",
|
||||
"@tanstack/react-query-devtools": "^4.22.0",
|
||||
"@tanstack/react-virtual": "beta",
|
||||
"@tauri-apps/api": "^1.4.0",
|
||||
"buffer": "^6.0.3",
|
||||
"date-fns": "^2.29.3",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -54,6 +55,7 @@
|
||||
"remark-custom-heading-id": "^1.0.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"tailwind-merge": "^1.8.1",
|
||||
"tauri-plugin-upload": "https://github.com/tauri-apps/tauri-plugin-upload#v1",
|
||||
"throttled-queue": "^2.1.4",
|
||||
"tiny-invariant": "^1.3.1",
|
||||
"ts-custom-error": "^3.3.1",
|
||||
|
||||
3
packages/stablestudio-ui/src-tauri/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
4279
packages/stablestudio-ui/src-tauri/Cargo.lock
generated
Normal file
34
packages/stablestudio-ui/src-tauri/Cargo.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.4.0", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.4.1", features = [ "fs-all", "path-all", "process-command-api", "devtools"] }
|
||||
tauri-plugin-upload = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
zip = "0.6.6"
|
||||
zip-extensions = "0.6.1"
|
||||
reqwest = { version = "0.11.6", features = ["blocking"] }
|
||||
tiny_http = "0.12.0"
|
||||
portpicker = "0.1.1"
|
||||
http = "0.2.9"
|
||||
sysinfo = "0.29.5"
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
3
packages/stablestudio-ui/src-tauri/build.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
BIN
packages/stablestudio-ui/src-tauri/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/128x128@2x.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 540 B |
BIN
packages/stablestudio-ui/src-tauri/icons/Square107x107Logo.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square142x142Logo.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square284x284Logo.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square30x30Logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square310x310Logo.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square71x71Logo.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/Square89x89Logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/icon.icns
Normal file
BIN
packages/stablestudio-ui/src-tauri/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
packages/stablestudio-ui/src-tauri/icons/icon.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
123
packages/stablestudio-ui/src-tauri/src/main.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use tauri::api::process::Command;
|
||||
use tauri::utils::config::{AppUrl, WindowConfig};
|
||||
use tauri::{RunEvent, WindowBuilder, WindowUrl};
|
||||
use tauri_plugin_upload;
|
||||
|
||||
mod server;
|
||||
|
||||
fn main() {
|
||||
let port = portpicker::pick_unused_port().expect("failed to find unused port");
|
||||
|
||||
let mut context = tauri::generate_context!();
|
||||
let url = format!("http://localhost:{}", port).parse().unwrap();
|
||||
let window_url = WindowUrl::External(url);
|
||||
// rewrite the config so the IPC is enabled on this URL
|
||||
if !cfg!(dev) {
|
||||
context.config_mut().build.dist_dir = AppUrl::Url(window_url.clone());
|
||||
}
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(server::Builder::new(port).build())
|
||||
.setup(move |app| {
|
||||
WindowBuilder::from_config(
|
||||
app,
|
||||
WindowConfig {
|
||||
url: {
|
||||
if cfg!(dev) {
|
||||
Default::default()
|
||||
} else {
|
||||
window_url
|
||||
}
|
||||
},
|
||||
height: 950.0,
|
||||
width: 1800.0,
|
||||
resizable: true,
|
||||
title: "StableStudio".to_string(),
|
||||
fullscreen: false,
|
||||
center: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.build()?;
|
||||
Ok(())
|
||||
})
|
||||
.plugin(tauri_plugin_upload::init())
|
||||
.invoke_handler(tauri::generate_handler![extract_zip, launch_comfy])
|
||||
.build(context)
|
||||
.expect("error while building tauri application")
|
||||
.run(move |_app_handle, event| match event {
|
||||
RunEvent::ExitRequested { .. } => {
|
||||
println!("Killing comfy...");
|
||||
tauri::api::process::kill_children();
|
||||
println!("Backend gracefully shutdown.");
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
// tauri command to extract a zip from an arbitrary file path
|
||||
#[tauri::command]
|
||||
fn extract_zip(path: String, target_dir: String) -> Result<String, String> {
|
||||
println!("extracting zip from {} to {}", path, target_dir);
|
||||
let file = File::open(path).unwrap();
|
||||
let mut archive = zip::ZipArchive::new(file).unwrap();
|
||||
|
||||
// unarchive in a thread
|
||||
let handle = std::thread::spawn(move || {
|
||||
archive.extract(target_dir).unwrap();
|
||||
});
|
||||
|
||||
handle.join().unwrap();
|
||||
|
||||
println!("extracted zip");
|
||||
Ok("completed".to_string())
|
||||
}
|
||||
|
||||
// tauri command to launch python process
|
||||
#[tauri::command]
|
||||
fn launch_comfy(path: String) -> Result<String, String> {
|
||||
// set working directory
|
||||
std::env::set_current_dir(path.clone()).unwrap();
|
||||
|
||||
// test to make sure its not already running (just test port 5000)
|
||||
println!("Checking for existing comfy process...");
|
||||
|
||||
// just try to connect to the port
|
||||
let resp = reqwest::blocking::get("http://localhost:5000");
|
||||
if resp.is_ok() {
|
||||
println!("Comfy already running, skipping launch.");
|
||||
return Ok("completed".to_string());
|
||||
}
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let (mut rx, _child) = Command::new({
|
||||
if cfg!(unix) {
|
||||
"python_embeded/python"
|
||||
} else if cfg!(windows) {
|
||||
"python_embeded/python.exe"
|
||||
} else if cfg!(macos) {
|
||||
"python_embeded/python.app"
|
||||
} else {
|
||||
panic!("Unsupported platform")
|
||||
}
|
||||
})
|
||||
.args(["-s", "ComfyUI/main.py", "--port", "5000"])
|
||||
.envs(HashMap::from([("PYTHONUNBUFFERED".into(), "1".into())]))
|
||||
.spawn()
|
||||
.expect("Failed to spawn ComfyUI process");
|
||||
|
||||
// print output from python process
|
||||
while let Some(i) = rx.recv().await {
|
||||
println!("ComfyUI: {:?}", i);
|
||||
}
|
||||
});
|
||||
|
||||
println!("--> launching comfy...");
|
||||
|
||||
Ok("completed".to_string())
|
||||
}
|
||||
209
packages/stablestudio-ui/src-tauri/src/server.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
use std::{collections::HashMap, fs::{File, self}, sync::Arc};
|
||||
|
||||
use http::{Uri, HeaderValue, HeaderName};
|
||||
use tauri::{
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Runtime,
|
||||
};
|
||||
use tiny_http::{Header, Response as HttpResponse, Server};
|
||||
|
||||
pub struct Response {
|
||||
headers: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn add_header<H: Into<String>, V: Into<String>>(&mut self, header: H, value: V) {
|
||||
self.headers.insert(header.into(), value.into());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder {
|
||||
port: u16
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new(port: u16) -> Self {
|
||||
Self {
|
||||
port
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let port = self.port;
|
||||
|
||||
PluginBuilder::new("localhost")
|
||||
.setup(move |app| {
|
||||
let server = Server::http(&format!("localhost:{port}")).expect("Unable to spawn server");
|
||||
let server = Arc::new(server);
|
||||
let mut guards = Vec::with_capacity(4);
|
||||
|
||||
let path_resolver = app.path_resolver();
|
||||
let appdata_path = path_resolver.app_data_dir().unwrap().as_os_str().to_str().unwrap().to_string();
|
||||
|
||||
for _ in 0..5 {
|
||||
let server = server.clone();
|
||||
let asset_resolver = app.asset_resolver();
|
||||
let appdata_path = appdata_path.clone();
|
||||
let guard = std::thread::spawn(move || {
|
||||
// aquire a copy of appdata_path
|
||||
for mut req in server.incoming_requests() {
|
||||
let path = req
|
||||
.url()
|
||||
.parse::<Uri>()
|
||||
.map(|uri| uri.path().to_string())
|
||||
.unwrap_or_else(|_| req.url().into());
|
||||
|
||||
let split_path = path.split("/").collect::<Vec<&str>>();
|
||||
let sliced_path = &split_path[1..split_path.len()];
|
||||
|
||||
let (file_name, mimetype, external_url): (
|
||||
Option<String>,
|
||||
Option<String>,
|
||||
Option<String>,
|
||||
) = match sliced_path {
|
||||
["lib" | "scripts", ..] => (
|
||||
Some(sliced_path.clone().join("/")),
|
||||
Some("application/javascript".to_string()),
|
||||
None,
|
||||
),
|
||||
["style.css"] => (
|
||||
Some("style.css".to_owned()),
|
||||
Some("text/css".to_string()),
|
||||
None,
|
||||
),
|
||||
["comfyui"] => (
|
||||
Some("index.html".to_owned()),
|
||||
Some("text/html".to_string()),
|
||||
None,
|
||||
),
|
||||
["api" | "prompt" | "object_info" | "view" | "queue" | "extensions", ..] => (
|
||||
None,
|
||||
None,
|
||||
Some(
|
||||
"http://localhost:5000/".to_string() + &sliced_path.join("/") + "?" + &req.url().split("?").collect::<Vec<&str>>()[1..].join("?"),
|
||||
),
|
||||
),
|
||||
[] | [_, _, ..] | [&_] => (None, None, None),
|
||||
};
|
||||
|
||||
if let Some(file_name) = file_name {
|
||||
let path_name = format!(
|
||||
"{}/ComfyUI/ComfyUI/web/{}",
|
||||
appdata_path.clone(),
|
||||
file_name
|
||||
);
|
||||
|
||||
let file = File::open(&path_name);
|
||||
|
||||
if file.is_err() {
|
||||
println!("file not found: {}", path_name);
|
||||
return;
|
||||
}
|
||||
|
||||
// replace "/ws" with "/api/ws" in the file
|
||||
let mut file_contents = fs::read_to_string(&path_name).unwrap();
|
||||
file_contents = file_contents.replace(
|
||||
"`ws${window.location.protocol === \"https:\" ? \"s\" : \"\"}://${location.host}/ws${existingSession}`",
|
||||
"`ws://localhost:5000/ws${existingSession}`"
|
||||
);
|
||||
|
||||
let response = HttpResponse::from_data(file_contents.as_bytes()).with_status_code(200).with_header(
|
||||
Header::from_bytes("Content-Type", mimetype.unwrap().as_str()).unwrap(),
|
||||
);
|
||||
|
||||
req.respond(response).expect("unable to setup response");
|
||||
println!("served file: {}", path_name);
|
||||
} else if let Some(external_url) = external_url {
|
||||
println!("forwarding request to {}", external_url);
|
||||
|
||||
let mut content = String::new();
|
||||
req.as_reader().read_to_string(&mut content).unwrap();
|
||||
|
||||
// forward the request (using same headers and method and body)
|
||||
let mut res: reqwest::blocking::Request = reqwest::blocking::Client::new()
|
||||
.request(
|
||||
reqwest::Method::from_bytes(req.method().as_str().as_bytes())
|
||||
.unwrap(),
|
||||
external_url,
|
||||
)
|
||||
.body(content)
|
||||
.build().unwrap();
|
||||
|
||||
for header in req.headers() {
|
||||
res.headers_mut().insert(
|
||||
HeaderName::from_bytes(header.field.as_str().as_bytes()).unwrap(),
|
||||
HeaderValue::from_str(header.value.as_str()).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let res = match reqwest::blocking::Client::new().execute(res) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
println!("error forwarding request: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let status = res.status();
|
||||
let headers = res.headers().clone();
|
||||
|
||||
// copy the response into the body
|
||||
let mut response = HttpResponse::from_data(res.bytes().unwrap().to_vec()).with_status_code(status.as_u16() as u16);
|
||||
|
||||
// set the response headers
|
||||
for header in headers.into_iter() {
|
||||
response.add_header(Header::from_bytes(header.0.unwrap().as_str(), header.1.to_str().unwrap()).unwrap());
|
||||
}
|
||||
|
||||
req.respond(response).expect("unable to setup response");
|
||||
|
||||
|
||||
} else {
|
||||
#[allow(unused_mut)]
|
||||
if let Some(mut asset) = asset_resolver.get(path.to_string()) {
|
||||
|
||||
let mut response = Response {
|
||||
headers: Default::default(),
|
||||
};
|
||||
|
||||
response.add_header("Content-Type", asset.mime_type);
|
||||
if let Some(csp) = asset.csp_header {
|
||||
response
|
||||
.headers
|
||||
.insert("Content-Security-Policy".into(), csp);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(response_csp) =
|
||||
response.headers.get("Content-Security-Policy")
|
||||
{
|
||||
let html = String::from_utf8_lossy(&asset.bytes);
|
||||
let body =
|
||||
html.replacen(tauri::utils::html::CSP_TOKEN, response_csp, 1);
|
||||
asset.bytes = body.as_bytes().to_vec();
|
||||
}
|
||||
|
||||
let mut resp = HttpResponse::from_data(asset.bytes);
|
||||
for (header, value) in response.headers {
|
||||
if let Ok(h) = Header::from_bytes(header.as_bytes(), value) {
|
||||
resp.add_header(h);
|
||||
}
|
||||
}
|
||||
req.respond(resp).expect("unable to setup response");
|
||||
} else {
|
||||
req.respond(
|
||||
HttpResponse::from_string("404 - Not Found")
|
||||
.with_status_code(404),
|
||||
)
|
||||
.expect("unable to setup response");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
guards.push(guard);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
}
|
||||
66
packages/stablestudio-ui/src-tauri/tauri.conf.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeBuildCommand": "yarn build",
|
||||
"beforeDevCommand": "yarn dev:vite",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"package": {
|
||||
"productName": "StableStudio",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"fs": {
|
||||
"all": true,
|
||||
"scope": ["$APPDATA/**"]
|
||||
},
|
||||
"path": {
|
||||
"all": true
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "GraphicsAndDesign",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.stabilityai.stablestudio",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "",
|
||||
"wix": {
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": []
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,14 @@
|
||||
import {
|
||||
BaseDirectory,
|
||||
exists,
|
||||
FileEntry,
|
||||
readDir,
|
||||
removeFile,
|
||||
} from "@tauri-apps/api/fs";
|
||||
import { appDataDir } from "@tauri-apps/api/path";
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { download } from "tauri-plugin-upload";
|
||||
import { Comfy } from "~/Comfy";
|
||||
import { Router } from "~/Router";
|
||||
import { Shortcut } from "~/Shortcut";
|
||||
import { Theme } from "~/Theme";
|
||||
@@ -9,26 +20,46 @@ import { TopBar } from "./TopBar";
|
||||
|
||||
export function App() {
|
||||
const isMobileDevice = Theme.useIsMobileDevice();
|
||||
const { isSetup, message, progress } = App.useSetupState();
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<Providers>
|
||||
<div className="absolute top-0 left-0 -z-50 h-screen w-screen dark:bg-zinc-800" />
|
||||
<div className="absolute top-0 left-0 flex h-screen w-screen flex-col text-white sm:overflow-x-auto">
|
||||
<Shortcut.Palette />
|
||||
<TopBar />
|
||||
<Sidebars />
|
||||
<div className="flex min-h-0 grow overflow-auto sm:min-w-[1000px]">
|
||||
<Sidebar position="left" />
|
||||
<div className="shrink grow overflow-y-auto">
|
||||
<Router />
|
||||
</div>
|
||||
<Sidebar position="right" />
|
||||
</div>
|
||||
{isMobileDevice && <BottomBar />}
|
||||
<div className="absolute left-0 top-0 -z-50 h-screen w-screen dark:bg-zinc-800" />
|
||||
<div className="absolute left-0 top-0 flex h-screen w-screen flex-col text-white sm:overflow-x-auto">
|
||||
{isSetup !== App.SetupState.ComfyRunning ? (
|
||||
<>
|
||||
<div className="flex flex-grow flex-col items-center justify-center gap-16">
|
||||
<h1 className="text-6xl font-bold">Welcome to StableStudio</h1>
|
||||
<div className="flex w-full flex-col items-center gap-4">
|
||||
<p className="font-mono opacity-75">{message}</p>
|
||||
<Theme.Progress
|
||||
className="max-w-[25rem]"
|
||||
value={progress * 100}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Shortcut.Palette />
|
||||
<TopBar />
|
||||
<Sidebars />
|
||||
<div className="flex min-h-0 grow overflow-auto sm:min-w-[1000px]">
|
||||
<Sidebar position="left" />
|
||||
<div className="relative shrink grow overflow-y-auto">
|
||||
<Router />
|
||||
<Comfy />
|
||||
</div>
|
||||
<Sidebar position="right" />
|
||||
</div>
|
||||
{isMobileDevice && <BottomBar />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Providers>
|
||||
),
|
||||
[isMobileDevice]
|
||||
[isMobileDevice, isSetup, message, progress]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,4 +70,145 @@ export declare namespace App {
|
||||
export namespace App {
|
||||
App.Sidebar = Sidebar;
|
||||
App.TopBar = TopBar;
|
||||
|
||||
export enum SetupState {
|
||||
NotStarted,
|
||||
ComfyInstalled,
|
||||
WeightsInstalled,
|
||||
ComfyRunning,
|
||||
}
|
||||
|
||||
export async function listAppDataDir(path: string) {
|
||||
try {
|
||||
if (
|
||||
await exists(path, {
|
||||
dir: BaseDirectory.AppData,
|
||||
})
|
||||
) {
|
||||
return (
|
||||
(await readDir(path, {
|
||||
dir: BaseDirectory.AppData,
|
||||
})) ?? []
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const useSetupState = () => {
|
||||
const [isSetup, setIsSetup] = useState<SetupState>(SetupState.NotStarted);
|
||||
const [message, setMessage] = useState<string>("");
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
const nonce = useRef<number>(0);
|
||||
|
||||
const check = useCallback(async () => {
|
||||
if (isSetup !== SetupState.NotStarted || nonce.current !== 0) return;
|
||||
nonce.current++;
|
||||
|
||||
let entries: FileEntry[] = await listAppDataDir(
|
||||
"comfyui/ComfyUI/models/checkpoints"
|
||||
);
|
||||
|
||||
// filter for actual files (not directories or symlinks or "put_checkpoints_here" files)
|
||||
entries = entries.filter((entry) => entry.name?.includes("."));
|
||||
|
||||
console.log(entries);
|
||||
const appDataPath = await appDataDir();
|
||||
|
||||
if (entries.length === 0) {
|
||||
const comfyExists = await exists("comdyui/ComfyUI/main.py", {
|
||||
dir: BaseDirectory.AppData,
|
||||
});
|
||||
|
||||
if (!comfyExists) {
|
||||
setIsSetup(SetupState.NotStarted);
|
||||
setMessage("Installing ComfyUI...");
|
||||
|
||||
// delete the old comfyui zip if it exists
|
||||
if (
|
||||
!(await exists("comfyui.zip", {
|
||||
dir: BaseDirectory.AppData,
|
||||
}))
|
||||
) {
|
||||
let comulativeProgress = 0;
|
||||
|
||||
console.log("downloading comfyui");
|
||||
|
||||
await download(
|
||||
"https://pub-5e5adf378ed14628a527d735b7743e4e.r2.dev/stability-downloads/ComfyUI/ComfyUI_windows_portable.zip",
|
||||
`${appDataPath}\\comfyui.zip`,
|
||||
(p, total) => {
|
||||
comulativeProgress += p;
|
||||
setProgress(comulativeProgress / total);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
setMessage("Extracting ComfyUI...");
|
||||
try {
|
||||
const result = await invoke("extract_zip", {
|
||||
path: `${appDataPath}/comfyui.zip`,
|
||||
targetDir: `${appDataPath}`,
|
||||
});
|
||||
|
||||
if (result !== "completed") {
|
||||
throw new Error("Failed to extract comfyui.zip");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setIsSetup(SetupState.NotStarted);
|
||||
setMessage(`Error installing ComfyUI: ${error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await removeFile("comfyui.zip", {
|
||||
dir: BaseDirectory.AppData,
|
||||
});
|
||||
}
|
||||
|
||||
setIsSetup(SetupState.ComfyInstalled);
|
||||
setMessage("Downloading Stable Diffusion...");
|
||||
|
||||
let comulativeProgress = 0;
|
||||
|
||||
console.log("downloading weights");
|
||||
|
||||
await download(
|
||||
"https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.safetensors",
|
||||
`${appDataPath}/comfyui/ComfyUI/models/checkpoints/v2-1_768-ema-pruned.safetensors`,
|
||||
(p, total) => {
|
||||
comulativeProgress += p;
|
||||
setProgress(comulativeProgress / total);
|
||||
}
|
||||
);
|
||||
|
||||
setMessage("done");
|
||||
}
|
||||
|
||||
setIsSetup(SetupState.WeightsInstalled);
|
||||
setMessage("Starting ComfyUI...");
|
||||
|
||||
// start comfy
|
||||
const result = await invoke("launch_comfy", {
|
||||
path: `${appDataPath}/comfyui`,
|
||||
});
|
||||
|
||||
if (result !== "completed") {
|
||||
setMessage(`Error launching ComfyUI: ${result}`);
|
||||
throw new Error("Failed to launch ComfyUI");
|
||||
}
|
||||
|
||||
setIsSetup(SetupState.ComfyRunning);
|
||||
}, [isSetup]);
|
||||
|
||||
useEffect(() => {
|
||||
check();
|
||||
}, [check]);
|
||||
|
||||
return { isSetup, message, progress };
|
||||
};
|
||||
}
|
||||
|
||||
81
packages/stablestudio-ui/src/Comfy/index.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
export type Comfy = {
|
||||
setup: () => void;
|
||||
registerNodes: () => void;
|
||||
loadGraphData: (graph: Graph) => void;
|
||||
graphToPrompt: () => Promise<{
|
||||
workflow: any;
|
||||
prompt: any;
|
||||
}>;
|
||||
handleFile: (file: File) => void;
|
||||
refreshComboInNodes: () => Promise<void>;
|
||||
queuePrompt: (number: number, batchCount: number) => Promise<void>;
|
||||
clean: () => void;
|
||||
};
|
||||
|
||||
export type Graph = {
|
||||
last_node_id: number;
|
||||
last_link_id: number;
|
||||
nodes: {
|
||||
id: number;
|
||||
type: string;
|
||||
pos: [number, number];
|
||||
size: {
|
||||
0: number;
|
||||
1: number;
|
||||
};
|
||||
flags: Record<string, unknown>;
|
||||
order: number;
|
||||
mode: number;
|
||||
inputs: {
|
||||
name: string;
|
||||
type: string;
|
||||
link: number;
|
||||
}[];
|
||||
outputs: {
|
||||
name: string;
|
||||
type: string;
|
||||
links: number[];
|
||||
slot_index: number;
|
||||
}[];
|
||||
properties: Record<string, unknown>;
|
||||
widgets_values: any[];
|
||||
}[];
|
||||
links: [
|
||||
number, // id
|
||||
number, // input_node_id
|
||||
number, // input_slot_index
|
||||
number, // output_node_id
|
||||
number, // output_slot_index
|
||||
string // type
|
||||
][];
|
||||
groups: any;
|
||||
config: any;
|
||||
extra: any;
|
||||
version: number;
|
||||
};
|
||||
|
||||
export function Comfy() {
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<iframe
|
||||
id="comfyui-window"
|
||||
src="/comfyui"
|
||||
className={classes(
|
||||
"absolute h-full w-full",
|
||||
!location.pathname.startsWith("/nodes") &&
|
||||
"pointer-events-none h-0 w-0 opacity-0"
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export namespace Comfy {
|
||||
export const get = (): Comfy | null =>
|
||||
((
|
||||
(document.getElementById("comfyui-window") as HTMLIFrameElement)
|
||||
?.contentWindow as Window & { app: Comfy }
|
||||
)?.app as Comfy) ?? null;
|
||||
}
|
||||
61
packages/stablestudio-ui/src/Comfy/plugin.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
|
||||
import { Comfy } from ".";
|
||||
|
||||
export const createPlugin = StableStudio.createPlugin(() => ({
|
||||
manifest: {
|
||||
name: "ComfyUI Backend",
|
||||
author: "StabilityAI",
|
||||
version: "0.0.1",
|
||||
license: "MIT",
|
||||
description: "An interface for generating images with ComfyUI",
|
||||
},
|
||||
|
||||
createStableDiffusionImages: async () => {
|
||||
const comfy = Comfy.get();
|
||||
|
||||
if (!comfy) {
|
||||
console.log(document.getElementById("comfyui-window"));
|
||||
throw new Error("ComfyUI is not loaded");
|
||||
}
|
||||
|
||||
await comfy.queuePrompt(1, 1);
|
||||
|
||||
const image = await fetch(`${window.location.origin}/DummyImage.png`);
|
||||
const blob = await image.blob();
|
||||
const createdAt = new Date();
|
||||
|
||||
return {
|
||||
id: `${Math.random() * 10000000}`,
|
||||
images: [
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
{
|
||||
id: `${Math.random() * 10000000}`,
|
||||
createdAt,
|
||||
blob,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
getStatus: () => {
|
||||
return {
|
||||
indicator: "success",
|
||||
text: "Ready",
|
||||
};
|
||||
},
|
||||
}));
|
||||
@@ -1,10 +1,8 @@
|
||||
import { RpcError } from "@protobuf-ts/runtime-rpc";
|
||||
|
||||
import { Snackbar } from "./Snackbar";
|
||||
|
||||
export type Exception = {
|
||||
/** The underlying error */
|
||||
readonly cause: Error | RpcError;
|
||||
readonly cause: Error;
|
||||
|
||||
/** Human-readable description of the underlying error */
|
||||
readonly description: string;
|
||||
@@ -20,9 +18,6 @@ export declare namespace Exception {
|
||||
export namespace Exception {
|
||||
Exception.Snackbar = Snackbar;
|
||||
|
||||
const defaultMessage =
|
||||
"Something went wrong on our end, please try again later";
|
||||
|
||||
export function is(value: unknown): value is Exception {
|
||||
if (!value && typeof value !== "object") return false;
|
||||
const exception = value as Exception;
|
||||
@@ -36,23 +31,6 @@ export namespace Exception {
|
||||
|
||||
export function create(unknown: unknown = {}): Exception {
|
||||
console.error(unknown);
|
||||
|
||||
if (
|
||||
unknown instanceof RpcError ||
|
||||
(unknown instanceof Error && unknown.name === "RpcError")
|
||||
) {
|
||||
const rpcError = unknown as RpcError;
|
||||
return {
|
||||
cause: rpcError,
|
||||
description: translateError(rpcError),
|
||||
status: isBannedTermError(rpcError)
|
||||
? "BANNED_TERM"
|
||||
: isOutOfCreditsError(rpcError)
|
||||
? "OUT_OF_CREDITS"
|
||||
: rpcError.code,
|
||||
};
|
||||
}
|
||||
|
||||
const error =
|
||||
unknown instanceof Error ? unknown : new Error(toJSON(unknown));
|
||||
|
||||
@@ -61,154 +39,4 @@ export namespace Exception {
|
||||
description: error.message,
|
||||
};
|
||||
}
|
||||
|
||||
function translateError(error: RpcError): string {
|
||||
switch (true) {
|
||||
case error.message.includes("Completion canceled by user."):
|
||||
return "Canceled";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to remove the only API key remaining."
|
||||
):
|
||||
return "Sorry, you can't delete your only API key";
|
||||
|
||||
case error.message.includes("Unable to get organization for request."):
|
||||
return "We couldn't find the organization you're asking for";
|
||||
|
||||
case isOutOfCreditsError(error):
|
||||
return "Not enough credits";
|
||||
|
||||
case isBannedTermError(error):
|
||||
return "Something isn't quite right with your prompts";
|
||||
|
||||
case error.message.includes("Unable to get user for request."):
|
||||
return "We couldn't find the user you're asking for";
|
||||
|
||||
case error.message.includes("Unable to locate request organization."):
|
||||
return "We couldn't find the organization you're asking for ";
|
||||
|
||||
case error.message.includes("Error filtering prompts."):
|
||||
return "Something isn't quite right with your prompts";
|
||||
|
||||
case error.message.includes("Invalid prompts detected"):
|
||||
return "Something isn't quite right with your prompts";
|
||||
|
||||
case error.message.includes("no prompts provided"):
|
||||
return "You have to provide at least one prompt";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to create a new billing ticket for this request."
|
||||
):
|
||||
return "We couldn't create a charge for some reason";
|
||||
|
||||
case error.message.includes("cannot use empty Id for project file"):
|
||||
return "You have to specify a project";
|
||||
|
||||
case error.message.includes("Incorrect time range provided."):
|
||||
return "Something was wrong with the times you provided";
|
||||
|
||||
case error.message.includes("must provide image parameters"):
|
||||
return "Something isn't right with the image you provided";
|
||||
|
||||
case error.message.includes("cannot create project with deleted status"):
|
||||
return "That project was already deleted";
|
||||
|
||||
case error.message.includes("Incorrect amount value."):
|
||||
return "You can't charge less than $0.00";
|
||||
|
||||
case error.message.includes('API key with ID "'):
|
||||
return "We couldn't find the API key you're asking for";
|
||||
|
||||
case error.message.includes('Unable to find organization with ID "'):
|
||||
return "We couldn't find the organization you're asking for";
|
||||
|
||||
case error.message.includes("No auto-charge intent."):
|
||||
return "You aren't set up for auto-charging";
|
||||
|
||||
case error.message.includes(
|
||||
"You do not have permission to access this resource."
|
||||
):
|
||||
return "You don't the right permissions";
|
||||
|
||||
case error.message.includes("EmailNotVerifiedMessage"):
|
||||
return "You still need to verify your email address";
|
||||
|
||||
case error.message.includes(
|
||||
"user is not a member of the requested organization"
|
||||
):
|
||||
return "You aren't a member of that organization";
|
||||
|
||||
case error.message.includes(
|
||||
"You have insufficient privileges to access this resource."
|
||||
):
|
||||
return "You don't have the right permissions";
|
||||
|
||||
case error.message.includes("You have too many API keys."):
|
||||
return "There are too many API keys";
|
||||
|
||||
case error.message.includes("Unable to set default organization."):
|
||||
return "We couldn't set your default organization";
|
||||
|
||||
case error.message.includes("Unable to update client settings."):
|
||||
return "We couldn't update your settings";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to connect to the prompt filter requested"
|
||||
):
|
||||
return "We couldn't properly filter your prompt";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to generate cost env for this request."
|
||||
):
|
||||
return "We couldn't generate a cost estimate for your request";
|
||||
|
||||
case error.message.includes("Unable to connect to the engine requested"):
|
||||
return "Something's wrong with the model your're trying to use";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to connect to the classifier requested"
|
||||
):
|
||||
return "We couldn't use the classifier you're asking for";
|
||||
|
||||
case error.message.includes("An unexpected server error occurred."):
|
||||
return defaultMessage;
|
||||
|
||||
case error.message.includes("Unable to create a new API key."):
|
||||
return "We couldn't create an API key for some reason";
|
||||
|
||||
case error.message.includes("Unable to delete the API key."):
|
||||
return "We couldn't delete the API key for some reason";
|
||||
|
||||
case error.message.includes("Unable to create an auto-charge intent:"):
|
||||
return "We couldn't set up auto-charge for some reason";
|
||||
|
||||
case error.message.includes("Unable to get auto-charge intent."):
|
||||
return "We couldn't get your auto-charge settings";
|
||||
|
||||
case error.message.includes(
|
||||
"Unable to create a checkout session for this charge."
|
||||
):
|
||||
return "We couldn't create a charge for some reason";
|
||||
|
||||
case error.message.includes("Unable to get charges."):
|
||||
return "We couldn't get your charges";
|
||||
|
||||
case error.message.includes("Unable to delete account, contact support"):
|
||||
return "We couldn't delete your account, please contact support";
|
||||
|
||||
case error.message.includes("image dimensions must be multiples of 64"):
|
||||
return "We somehow sent an image with the wrong dimensions";
|
||||
|
||||
default:
|
||||
return defaultMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export function isBannedTermError(error: RpcError): boolean {
|
||||
return error.code === "BANNED_TERM";
|
||||
}
|
||||
|
||||
export function isOutOfCreditsError(error: RpcError): boolean {
|
||||
return error.message.includes("does not have enough balance");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { StableDiffusionInput } from "@stability/stablestudio-plugin";
|
||||
|
||||
import { Generation } from "~/Generation";
|
||||
import { GlobalState } from "~/GlobalState";
|
||||
import { Plugin } from "~/Plugin";
|
||||
|
||||
import { Image } from "./Image";
|
||||
import { Inputs } from "./Inputs";
|
||||
|
||||
@@ -12,29 +12,56 @@ export function Sidebar() {
|
||||
|
||||
if (!input?.id) return null;
|
||||
return (
|
||||
<App.Sidebar.Tab.Set
|
||||
defaultActive
|
||||
name="Generate"
|
||||
route="/generate"
|
||||
position="left"
|
||||
index={0}
|
||||
icon={Theme.Icon.Generate}
|
||||
enabled={
|
||||
location.pathname.startsWith("/generate") ||
|
||||
location.pathname.startsWith("/edit")
|
||||
}
|
||||
bottom={
|
||||
<App.Sidebar.Tab.Bottom>
|
||||
<Generation.Image.Create.Button
|
||||
id={input.id}
|
||||
onIdleClick={() => createDream()}
|
||||
fullWidth
|
||||
/>
|
||||
</App.Sidebar.Tab.Bottom>
|
||||
}
|
||||
>
|
||||
<Sidebar.Tab id={input.id} />
|
||||
</App.Sidebar.Tab.Set>
|
||||
<>
|
||||
<App.Sidebar.Tab.Set
|
||||
defaultActive
|
||||
name="Generate"
|
||||
route="/generate"
|
||||
position="left"
|
||||
index={0}
|
||||
icon={Theme.Icon.Generate}
|
||||
enabled={
|
||||
location.pathname.startsWith("/generate") ||
|
||||
location.pathname.startsWith("/edit") ||
|
||||
location.pathname.startsWith("/nodes")
|
||||
}
|
||||
bottom={
|
||||
<App.Sidebar.Tab.Bottom>
|
||||
<Generation.Image.Create.Button
|
||||
id={input.id}
|
||||
onIdleClick={() => createDream()}
|
||||
fullWidth
|
||||
/>
|
||||
</App.Sidebar.Tab.Bottom>
|
||||
}
|
||||
>
|
||||
<Sidebar.Tab id={input.id} />
|
||||
</App.Sidebar.Tab.Set>
|
||||
<App.Sidebar.Tab.Set
|
||||
defaultActive
|
||||
name="Nodes"
|
||||
route="/nodes"
|
||||
position="left"
|
||||
index={2}
|
||||
icon={Theme.Icon.Rectangle}
|
||||
enabled={
|
||||
location.pathname.startsWith("/generate") ||
|
||||
location.pathname.startsWith("/edit") ||
|
||||
location.pathname.startsWith("/nodes")
|
||||
}
|
||||
bottom={
|
||||
<App.Sidebar.Tab.Bottom>
|
||||
<Generation.Image.Create.Button
|
||||
id={input.id}
|
||||
onIdleClick={() => createDream()}
|
||||
fullWidth
|
||||
/>
|
||||
</App.Sidebar.Tab.Bottom>
|
||||
}
|
||||
>
|
||||
<Sidebar.Tab id={input.id} />
|
||||
</App.Sidebar.Tab.Set>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ export function Ratio({
|
||||
}) {
|
||||
const { input } = Generation.Image.Input.use(id);
|
||||
const { closest, ratios } = Ratios.use(id, fullControl);
|
||||
const [timer, setTimer] = React.useState<NodeJS.Timeout | null>(null);
|
||||
const [timer, setTimer] = React.useState<ReturnType<
|
||||
typeof setTimeout
|
||||
> | null>(null);
|
||||
const [forceTooltipOpen, setForceTooltipOpen] = React.useState(false);
|
||||
|
||||
const onChange = useCallback(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import { Buffer } from "buffer";
|
||||
import { Buffer as Buffer_ } from "buffer";
|
||||
|
||||
import { cx } from "@emotion/css";
|
||||
import { css as cssImport } from "@emotion/react";
|
||||
@@ -46,6 +46,8 @@ declare global {
|
||||
var copy: typeof immer;
|
||||
var throttle: typeof throttle_;
|
||||
var toJSON: (value: unknown) => string;
|
||||
|
||||
var Buffer: typeof Buffer_;
|
||||
}
|
||||
|
||||
namespace IDNamespace {
|
||||
@@ -60,7 +62,7 @@ namespace IDNamespace {
|
||||
|
||||
globalThis.ID = IDNamespace;
|
||||
|
||||
globalThis.Buffer = Buffer;
|
||||
globalThis.Buffer = Buffer_;
|
||||
|
||||
globalThis.React = ReactImport;
|
||||
globalThis.useState = ReactImport.useState;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import * as StableStudio from "@stability/stablestudio-plugin";
|
||||
import * as StableStudioPluginExample from "@stability/stablestudio-plugin-example";
|
||||
import * as StableStudioPluginStability from "@stability/stablestudio-plugin-stability";
|
||||
import * as StableStudioPluginWebUI from "@stability/stablestudio-plugin-webui";
|
||||
import * as StableStudioPluginComfy from "~/Comfy/plugin";
|
||||
|
||||
import { Environment } from "~/Environment";
|
||||
import { Generation } from "~/Generation";
|
||||
@@ -113,12 +111,7 @@ namespace State {
|
||||
};
|
||||
|
||||
export const use = GlobalState.create<State>((set) => {
|
||||
const { createPlugin: createRootPlugin } =
|
||||
Environment.get("USE_EXAMPLE_PLUGIN") === "true"
|
||||
? StableStudioPluginExample
|
||||
: Environment.get("USE_WEBUI_PLUGIN") === "true"
|
||||
? StableStudioPluginWebUI
|
||||
: StableStudioPluginStability;
|
||||
const { createPlugin: createRootPlugin } = StableStudioPluginComfy;
|
||||
|
||||
return {
|
||||
rootPlugin: createRootPlugin({
|
||||
|
||||
@@ -42,6 +42,10 @@ export namespace Router {
|
||||
path: "/edit",
|
||||
element: <Editor />,
|
||||
},
|
||||
{
|
||||
path: "/nodes",
|
||||
element: <div className="hidden h-0 w-0" />,
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
element: <Settings />,
|
||||
|
||||
@@ -135,7 +135,7 @@ export namespace Key {
|
||||
|
||||
export const useIsActive = (key: Key) => {
|
||||
const [active, setActive] = useState(false);
|
||||
const activeTimeout = useRef<NodeJS.Timeout>();
|
||||
const activeTimeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
|
||||
useOnDown(
|
||||
key,
|
||||
|
||||
@@ -112,7 +112,7 @@ export function Dropdown<Options extends Dropdown.Options>({
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="pointer-events-none absolute top-0 right-1 inline-block h-full">
|
||||
<div className="pointer-events-none absolute right-1 top-0 inline-block h-full">
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
{open ? (
|
||||
<Theme.Icon.ChevronUp className="h-6 w-6" />
|
||||
|
||||
19
packages/stablestudio-ui/src/Theme/Progress/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
export type Progress = Styleable & {
|
||||
value?: number;
|
||||
};
|
||||
|
||||
export function Progress({ value, className }: Progress) {
|
||||
return (
|
||||
<div
|
||||
className={classes(
|
||||
"relative h-2 w-full overflow-hidden rounded-full bg-white/10",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="duration-50 bg-brand-500 absolute left-0 top-0 h-full"
|
||||
style={{ width: `${value}%` }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -34,8 +34,12 @@ export function Tooltip({
|
||||
openMechanism?: "click" | "hover";
|
||||
}) {
|
||||
const [show, setShow] = useState(false);
|
||||
const [timer, setTimer] = useState<NodeJS.Timeout | null>(null);
|
||||
const [leaveTimer, setLeaveTimer] = useState<NodeJS.Timeout | null>(null);
|
||||
const [timer, setTimer] = useState<ReturnType<typeof setTimeout> | null>(
|
||||
null
|
||||
);
|
||||
const [leaveTimer, setLeaveTimer] = useState<ReturnType<
|
||||
typeof setTimeout
|
||||
> | null>(null);
|
||||
const [position, setPosition] = useState<{
|
||||
top: number;
|
||||
left: number;
|
||||
@@ -142,8 +146,8 @@ export function Tooltip({
|
||||
className={classes(
|
||||
"absolute z-[999999] h-2 w-2 -translate-x-1/2 -translate-y-1/2 rotate-45 border-zinc-700 bg-zinc-900",
|
||||
placement === "top" && "border-b border-r",
|
||||
placement === "bottom" && "border-t border-l",
|
||||
placement === "left" && "border-t border-r",
|
||||
placement === "bottom" && "border-l border-t",
|
||||
placement === "left" && "border-r border-t",
|
||||
placement === "right" && "border-b border-l"
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -19,6 +19,7 @@ import { New } from "./New";
|
||||
import { NumberInput } from "./NumberInput";
|
||||
import { Page } from "./Page";
|
||||
import { Popout } from "./Popout";
|
||||
import { Progress } from "./Progress";
|
||||
import { Skeleton } from "./Skeleton";
|
||||
import { Slider } from "./Slider";
|
||||
import * as Snackbar from "./Snackbar";
|
||||
@@ -54,6 +55,7 @@ export declare namespace Theme {
|
||||
Stars,
|
||||
Snackbar,
|
||||
Label,
|
||||
Progress,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -84,6 +86,7 @@ export namespace Theme {
|
||||
Theme.Tooltip = Tooltip;
|
||||
Theme.Snackbar = Snackbar;
|
||||
Theme.Label = Label;
|
||||
Theme.Progress = Progress;
|
||||
|
||||
export const useDark = () => Mode.use().dark;
|
||||
export const useIsMobileDevice = () => {
|
||||
|
||||
@@ -4,6 +4,11 @@ import react from "@vitejs/plugin-react";
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
|
||||
const redirectComfy = {
|
||||
target: "http://localhost:5000",
|
||||
changeOrigin: true,
|
||||
};
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => {
|
||||
const gitHash = ChildProcess.execSync("git rev-parse HEAD").toString().trim();
|
||||
@@ -21,6 +26,27 @@ export default defineConfig(({ mode }) => {
|
||||
server: {
|
||||
port: 3000,
|
||||
fs: { strict: false },
|
||||
proxy: {
|
||||
"/comfyui": {
|
||||
target: "http://localhost:5000",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/comfyui/, ""),
|
||||
},
|
||||
"/lib": redirectComfy,
|
||||
"/scripts": redirectComfy,
|
||||
"/style.css": redirectComfy,
|
||||
"/ws": {
|
||||
target: "http://localhost:5000",
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
"/api": redirectComfy,
|
||||
"/prompt": redirectComfy,
|
||||
"/extensions": redirectComfy,
|
||||
"/object_info": redirectComfy,
|
||||
"/view": redirectComfy,
|
||||
"/queue": redirectComfy,
|
||||
},
|
||||
},
|
||||
|
||||
optimizeDeps: {
|
||||
|
||||