Initial commit

This commit is contained in:
StableStudio 2023-05-12 10:36:19 -05:00
commit a65d4877ad
354 changed files with 39338 additions and 0 deletions

67
.eslintrc.json Normal file
View File

@ -0,0 +1,67 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"ecmaFeatures": { "jsx": true },
"sourceType": "module",
"project": "./tsconfig.json",
"extraFileExtensions": [".md"]
},
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:prettier/recommended",
"plugin:markdown/recommended"
],
"plugins": ["react", "react-hooks", "import"],
"settings": { "react": { "version": "detect" } },
"rules": {
"prettier/prettier": ["error", {}, { "usePrettierrc": true }],
"react/react-in-jsx-scope": "off",
"react/jsx-no-undef": "off",
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "off",
"react/no-unknown-property": ["error", { "ignore": ["css"] }],
"react/display-name": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }
],
"no-unused-vars": [
"error",
{ "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }
],
"import/order": [
"error",
{
"newlines-between": "always-and-inside-groups",
"alphabetize": { "order": "asc", "caseInsensitive": true },
"groups": ["builtin", "external", "parent", "index", "sibling"],
"pathGroups": [
{ "pattern": "~/**", "group": "external" },
{ "pattern": ".", "group": "sibling" }
]
}
],
"sort-imports": [
"error",
{
"ignoreCase": true,
"ignoreDeclarationSort": true
}
]
}
}

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
.DS_Store
.idea
*.iml
node_modules
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

8
.husky/common.sh Normal file
View File

@ -0,0 +1,8 @@
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Windows 10, Git Bash and Yarn workaround
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

12
.husky/pre-push Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
# Ensure the entire project still compiles
blue=$(tput setaf 4)
normal=$(tput sgr0)
printf "%b" "${blue}Type checking... ${normal}"
yarn stablestudio-ui build:types
# Run the lint-staged job in the root package.json
yarn lint-staged

3
.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"endOfLine": "auto"
}

30
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch UI in Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
},
{
"name": "Launch UI in Edge",
"type": "msedge",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
},
{
"name": "Attach to Chrome",
"port": 9222,
"request": "attach",
"type": "pwa-chrome",
"urlFilter": "http://localhost:3000/*",
"webRoot": "${workspaceFolder}"
}
]
}

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}

File diff suppressed because one or more lines are too long

807
.yarn/releases/yarn-3.3.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

7
.yarnrc.yml Normal file
View File

@ -0,0 +1,7 @@
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
yarnPath: .yarn/releases/yarn-3.3.0.cjs

127
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,127 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at [Stability AI](https://stability.ai).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
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.

97
README.md Normal file
View File

@ -0,0 +1,97 @@
<div align="center">
![StableStudio](./misc/Banner.png)
# StableStudio by [Stability AI](https://stability.ai/)
**👋 Welcome to the community repository for StableStudio, the open-source version of [DreamStudio](https://www.dreamstudio.ai)**
**🗺 Contents [🚀 Quick Start](#quick-start) · [ About](#about) · [🙋 FAQ](#faq) · [🧑‍💻 Contributing](#contributing)**
**📚 Documentation [🎨 UI](./packages/stablestudio-ui/README.md) · [🔌 Plugins](./packages/stablestudio-plugin/README.md) · <a href="https://platform.stability.ai" target="_blank">⚡️ platform.stability.ai</a>**
**🔗 Links <a href="https://discord.gg/wHM9XjyVpU" target="_blank">🎮 Discord</a> · <a href="https://dreamstudio.ai" target="_blank">🌈 DreamStudio</a> · <a href="https://github.com/Stability-AI/StableStudio/issues">🛟 Bugs & Support</a> · <a href="https://github.com/Stability-AI/StableStudio/discussions">💬 Discussion</a>**
</div>
<div align="center" style="display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 1em; margin: 4em 0;">
<img src="./misc/GenerateScreenshot.png" style="width: 400px; max-width: 600px; flex-grow: 1;" />
<img src="./misc/EditScreenshot.png" style="width: 400px; max-width: 600px; flex-grow: 1;" />
</div>
# <a id="quick-start" href="#quick-start">🚀 Quick Start</a>
You'll need to have [Node.js](https://nodejs.org/en/) and [Yarn](https://yarnpkg.com/) installed.
Once that's done, you can run the following commands...
```bash
git clone https://github.com/Stability-AI/StableStudio.git
cd StableStudio
yarn
yarn dev
```
_**That's it! 🎉**_
StableStudio will be running at [localhost:3000](http://localhost:3000) by default.
You'll need to have your [API key](https://platform.stability.ai/docs/getting-started/authentication) handy to use the default [Stability API](https://platform.stability.ai/docs/getting-started) plugin.
If you don't have one, you can create an account on [DreamStudio](https://dreamstudio.ai) and get a key from the [account page](https://dreamstudio.ai/account).
# <a id="about" href="#about"> About</a>
<div style="display: flex; justify-content: center; align-items: center; gap: 1em; margin: 0 0 2em 0;">
<img src="./misc/PainterWithRobot.png" style="flex-grow: 1; flex-shrink: 1;" />
</div>
StableStudio is [Stability AI](https://stability.ai)'s official open-source variant of [DreamStudio](https://www.dreamstudio.ai), our user interface for generative AI.
It is a web-based application that allows users to create and edit generated images.
We're not entirely sure where this project is going just yet, but we're excited to see what the community does with it!
# <a id="faq" href="#faq">🙋 FAQ</a>
## What's the difference between StableStudio and [DreamStudio](https://dreamstudio.ai)?
_Not much!_ There are a few tweaks we made to make the project more community-friendly:
- We removed [DreamStudio](https://dreamstudio.ai)-specific branding.
- All "over-the-wire" API calls have been replaced by a [plugin system](./packages/stablestudio-plugin/README.md) which allows you to easily swap out the back-end.
- On release, we'll only be providing a plugin for the Stability API, but with a little bit of TypeScript, you can [create your own](./packages/stablestudio-plugin/README.md).
- We removed Stability-specific account features such as billing, API key management, etc.
- These features are still available at [DreamStudio's account page](https://dreamstudio.ai/account).
## Will [DreamStudio](https://dreamstudio.ai) still be supported?
_Yes!_ Stability's hosted deployment of StableStudio will remain [DreamStudio](https://dreamstudio.ai).
It will continue to get updates and stay up-to-date with StableStudio whenever possible.
# <a id="contributing" href="#contributing">🧑‍💻 Contributing</a>
<div style="display: flex; justify-content: center; align-items: center; gap: 1em; margin: 0 0 2em 0;">
<img src="./misc/ProgrammingRobots.png" style="flex-grow: 1; flex-shrink: 1;" />
</div>
_**Community contributions are encouraged!**_
_**The UI package's [README](./packages/stablestudio-ui/README.md) is a great place to start.**_
Bug fixes, documentation, general clean-up, new features, etc. are all welcome.
Here are some useful links...
- [Discussion](https://github.com/Stability-AI/StableStudio/discussions)
- [Open Issues](https://github.com/Stability-AI/StableStudio/issues)
- [Open Pull Requests](https://github.com/Stability-AI/StableStudio/pulls)
- [Code of Conduct](./CODE_OF_CONDUCT.md)

BIN
misc/Banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

BIN
misc/Banner.psd Normal file

Binary file not shown.

BIN
misc/CyberPyramid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
misc/DeveloperMode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
misc/EditScreenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

BIN
misc/ExamplePlugin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
misc/GenerateScreenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
misc/InstallPlugin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
misc/PainterWithRobot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
misc/ProgrammingRobots.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
misc/ProjectCard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

BIN
misc/ProjectCard.psd Normal file

Binary file not shown.

BIN
misc/RobotsHoldingHands.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
misc/SorcererWithReact.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"license": "MIT",
"packageManager": "yarn@3.3.0",
"workspaces": {
"packages": [
"packages/*"
]
},
"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-ui": "yarn workspace @stability/stablestudio-ui",
"dev:use-example-plugin": "cross-env VITE_USE_EXAMPLE_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"
},
"devDependencies": {
"cross-env": "^7.0.3",
"husky": "^8.0.3",
"lint-staged": "^13.1.2",
"rimraf": "^3.0.2",
"yarn": "^1.22.19"
},
"lint-staged": {
"./packages/ui/**/*.{ts,tsx,js,jsx,md}": [
"prettier --write",
"eslint --fix"
]
}
}

View File

@ -0,0 +1 @@
{ "extends": ["../../.eslintrc.json"] }

View File

@ -0,0 +1 @@
lib

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,39 @@
{
"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"
}
}

View File

@ -0,0 +1,21 @@
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();

View File

@ -0,0 +1,82 @@
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 },
},
})),
}));

View File

@ -0,0 +1,21 @@
{
"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 }
]
}
}

View File

@ -0,0 +1,2 @@
./src/Proto/Generated/**/*
./api-interfaces/**

View File

@ -0,0 +1,4 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["./src/Proto/Generated/**"]
}

View File

@ -0,0 +1,2 @@
api-interfaces
lib

View File

@ -0,0 +1,2 @@
./src/Proto/Generated/**/*
./api-interfaces/**

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,46 @@
{
"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"
}
}

View File

@ -0,0 +1,21 @@
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();

View File

@ -0,0 +1,69 @@
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}`
);

View File

@ -0,0 +1,236 @@
// @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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
// @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);
}
}

View File

@ -0,0 +1,279 @@
// @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 }
]);

View File

@ -0,0 +1,57 @@
// @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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,480 @@
// @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();

View File

@ -0,0 +1,178 @@
// @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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,436 @@
// @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();

View File

@ -0,0 +1,9 @@
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";

View File

@ -0,0 +1,616 @@
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",
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"
> => {
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()
),
},
}),
},
})
);
}
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: Generation.DiffusionSampler.SAMPLER_DDIM,
},
}),
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
),
getStableDiffusionStyles: () => [
{
id: "enhance",
name: "Enhance",
imageURL: "https://dreamstudio.ai/presets/enhance.png",
},
{
id: "anime",
name: "Anime",
imageURL: "https://dreamstudio.ai/presets/anime.png",
},
{
id: "photographic",
name: "Photographic",
imageURL: "https://dreamstudio.ai/presets/photographic.png",
},
{
id: "digital-art",
name: "Digital art",
imageURL: "https://dreamstudio.ai/presets/digital-art.png",
},
{
id: "comic-book",
name: "Comic book",
imageURL: "https://dreamstudio.ai/presets/comic-book.png",
},
{
id: "fantasy-art",
name: "Fantasy art",
imageURL: "https://dreamstudio.ai/presets/fantasy-art.png",
},
{
id: "analog-film",
name: "Analog film",
imageURL: "https://dreamstudio.ai/presets/analog-film.png",
},
{
id: "neon-punk",
name: "Neon punk",
imageURL: "https://dreamstudio.ai/presets/neon-punk.png",
},
{
id: "isometric",
name: "Isometric",
imageURL: "https://dreamstudio.ai/presets/isometric.png",
},
{
id: "low-poly",
name: "Low poly",
imageURL: "https://dreamstudio.ai/presets/low-poly.png",
},
{
id: "origami",
name: "Origami",
imageURL: "https://dreamstudio.ai/presets/origami.png",
},
{
id: "line-art",
name: "Line art",
imageURL: "https://dreamstudio.ai/presets/line-art.png",
},
{
id: "modeling-compound",
name: "Craft clay",
imageURL: "https://dreamstudio.ai/presets/modeling-compound.png",
},
{
id: "cinematic",
name: "Cinematic",
imageURL: "https://dreamstudio.ai/presets/cinematic.png",
},
{
id: "3d-model",
name: "3D model",
imageURL: "https://dreamstudio.ai/presets/3d-model.png",
},
{
id: "pixel-art",
name: "Pixel art",
imageURL: "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/1072239614644994169) · [🌈 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\`...
![](/media/api_keys_screenshot.png)
If you don't already have a key, you can create one via the plus button...
![](/media/create_api_key_screenshot.png)
You can copy your API key by clicking the copy button...
![](/media/copy_api_key_screenshot.png)
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;

View File

@ -0,0 +1,21 @@
{
"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 }
]
}
}

View File

@ -0,0 +1 @@
{ "extends": ["../../.eslintrc.json"] }

View File

@ -0,0 +1 @@
lib

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,39 @@
{
"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"
}
}

View File

@ -0,0 +1,21 @@
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();

View File

@ -0,0 +1,3 @@
import * as StableStudio from "@stability/stablestudio-plugin";
export const createPlugin = StableStudio.createPlugin(() => ({}));

View File

@ -0,0 +1,21 @@
{
"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 }
]
}
}

View File

@ -0,0 +1 @@
{ "extends": ["../../.eslintrc.json"] }

View File

@ -0,0 +1 @@
lib

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,39 @@
{
"name": "@stability/stablestudio-plugin-webui",
"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"
}
}

View File

@ -0,0 +1,21 @@
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();

View File

@ -0,0 +1,3 @@
import * as StableStudio from "@stability/stablestudio-plugin";
export const createPlugin = StableStudio.createPlugin(() => ({}));

View File

@ -0,0 +1,21 @@
{
"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 }
]
}
}

View File

@ -0,0 +1 @@
{ "extends": ["../../.eslintrc.json"] }

View File

@ -0,0 +1 @@
lib

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,119 @@
<div align="center">
# 🔌 Plugins
**🗺 Contents [ About](#about) · [📦 Installation](#installation) · [🤝 Contract](#technology) · [🔮 Future](#conventions)**
**[⬆️ Top-Level README](../../README.md)**
![MagicalElectricPlugs](../../misc/MagicalElectricPlugs.png)
### 🚧 👷 **PLUGINS ARE EXPERIMENTAL AND NOT FINAL** 🛠 🚧
_The contract and implementation are [likely to change](https://github.com/Stability-AI/StableStudio/issues/3)..._
</div>
# <a id="about" href="#about"> About</a>
In order to make StableStudio easier to extend, we've ripped out the "back-end" into a plugin system.
This means you can implement an entirely different inference stack, StableStudio doesn't care if it's local or a hosted API.
## ⭐️ Features
We're hoping this list expands [over time](#future), but here's what's available right now...
- **🏞 Image Generation**
All aspects of image generation are handled by plugins including the default input, how styles are implemented, how to fetch existing images, etc.
- **🪪 Plugin Manifest**
Plugins can provide a manifest with a markdown description, author details, version information, etc.
- **⚙️ Plugin Settings**
Plugins can declare settings which are available to the user in the settings menu.
## 🧪 Development
**If you want to play around with an example plugin which has nice developer tooling, check out the [example plugin](../stablestudio-plugin-example/src/index.ts).**
You can load the UI using example plugin instead of the default [Stability plugin](../stablestudio-plugin-stability/src/index.ts) by running...
```bash
yarn dev:use-example-plugin
```
Any changes you make within the [example plugin](../stablestudio-plugin-example/src/index.ts) will be hot-reloaded into StableStudio.
# <a id="installation" href="#installation">📦 Installation</a>
**This is mainly a feature intended for developers, we're [likely to change](https://github.com/Stability-AI/StableStudio/issues/3) how plugins work for end-users.**
_Never install plugins from untrusted sources!_
Although they are sand-boxed to the browser, a malicious actor could read through your image history or steal your API key if you're not careful.
To install a plugin, first enable "developer mode" in the settings menu...
![DeveloperMode](../../misc/DeveloperMode.png)
Now you can point to any fetch-able JavaScript file which exports a plugin...
![InstallPlugin](../../misc/InstallPlugin.png)
If loaded successfully, you'll see it in the settings menu...
![ExamplePlugin](../../misc/ExamplePlugin.png)
✅ _**That's it!**_
As of now, you can only have one active plugin at a time.
The main purpose of plugins in their current form is to allow developers to experiment with different inference stacks.
# <a id="contract" href="#contract">🤝 Contract</a>
**Check out the [TypeScript source](./src/Plugin.ts) to see full documentation of the API.**
Plugins are effectively just a bag of JavaScript functions.
StableStudio calls these functions for core functionality, such as `createStableDiffusionImages`, `getStableDiffusionStyles`, `getStableDiffusionDefaultInput`, etc.
Functionality degrades gracefully, for example, if you don't implement `getStableDiffusionStyles`, no styles will be shown in the UI.
# <a id="future" href="#future">🔮 Future</a>
Plugins were mostly created to rip out calls to Stability's [gRPC API](https://platform.stability.ai), so their functionality is quite limited.
**Given the importance of a robust plugin system, we're really hoping to [gather feedback](https://github.com/Stability-AI/StableStudio/issues/3) on how we can improve the API.**
Here's what's on our mind when it comes to the future of StableStudio plugins...
- **🧠 More Inference Stacks**
The default [Stability plugin](../stablestudio-plugin-stability/src/index.ts) enables inference relying on [Stability's API](../stablestudio-plugin-stability/src/index.ts), but we're hoping to expand support for local inference.
We're particularly interested in creating a plugin for using [`stable-diffusion-webui`](https://github.com/AUTOMATIC1111/stable-diffusion-webui)'s [REST API](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/API).
Though it's not fully-ready, we're excited about the future of [WebGPU](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API), and would love to support it via a plugin.
_We've stubbed out two empty packages to house these potential plugins..._
[`stablestudio-plugin-webui`](../stablestudio-plugin-webui/src/index.ts)
[`stablestudio-plugin-webgpu`](../stablestudio-plugin-webgpu/src/index.ts)
- **🎨 Deeper UI Extensibility**
Currently plugins can only change "back-end" functionality. We'd love to allow plugins to create entire new features or modify existing ones.
- **🧱 Multiple Plugins**
Only one plugin can be loaded at a time with our current implementation. Allowing multiple plugins to play nicely with each other would be a huge win.
- **🛍 Plugin Library**
If there is enough interest and community momentum, we'd love to create a plugin library where users can easily install plugins from a curated list.

View File

@ -0,0 +1,39 @@
{
"name": "@stability/stablestudio-plugin",
"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\""
},
"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"
},
"dependencies": {
"zustand": "^4.3.7"
}
}

View File

@ -0,0 +1,21 @@
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();

View File

@ -0,0 +1,297 @@
import { createStore, StoreApi } from "zustand";
/**
* Function used to create a `Plugin`
*
* ```ts
* import * as StableStudio from "@stability/stablestudio-plugin";
*
* // You need to export your plugin like this...
* export const createPlugin = StableStudio.createPlugin(() => ({}));
* ```
*
* It returns a function waiting for `PluginCreateContext` as an argument, which the UI provides
*/
export const createPlugin =
<P extends PluginTypeHelper>(
createPlugin: (options: {
context: PluginCreateContext;
set: StoreApi<Plugin<P>>["setState"];
get: StoreApi<Plugin<P>>["getState"];
}) => Plugin<P>
) =>
(context: PluginCreateContext) =>
createStore<Plugin<P>>((set, get) => createPlugin({ set, get, context }));
/** `PluginCreateContext` is passed to the `createPlugin` function and provides some useful functions */
type PluginCreateContext = {
/** Get the git hash of the repository */
getGitHash: () => string;
/** Get a random prompt for image generation */
getStableDiffusionRandomPrompt: () => string;
};
/** `PluginManifest` is used to describe your plugin on the settings page */
export type PluginManifest = {
/** What is your plugin called? */
name?: string;
/** A link to your plugin's icon */
icon?: URLString;
/** A link to your plugin's website */
link?: URLString;
/** Your plugin version, no versioning schema is currently enforced */
version?: string;
/** What's the license, no licensing schema is currently enforced */
license?: string;
/** Who made this plugin? */
author?: string;
/** What does your plugin do? */
description?: Markdown;
};
export type PluginSettingCommon = {
/** What is your plugin called? */
title?: string;
/** What is your plugin called? */
description?: Markdown;
/** Is this setting required? If so, users will be forced to provide an input */
required?: boolean;
};
/** `PluginSetting` allows for `string`, `number`, and `boolean` input types */
export type PluginSetting<T> =
| PluginSettingString<T>
| PluginSettingNumber<T>
| PluginSettingBoolean<T>;
/** `PluginSetting` which is displayed and input as a `string` */
export type PluginSettingString<T = string> = PluginSettingCommon & {
type: "string";
/** The current `value` */
value?: T;
/** If you provide `options`, this will become a dropdown */
options?: { label: string; value: T }[];
/** The `placeholder` input `string` */
placeholder?: string;
/** Given a `value`, how should it be displayed? Useful if your value is a `Date` for example */
formatter?: (value: T) => string;
/** Given a `string`, how should it be saved as a `value`? */
parser?: (string: string) => T;
/** Determines whether this input is displayed as a `password` type */
password?: boolean;
};
/** `PluginSetting` which is displayed and input as a `number` */
export type PluginSettingNumber<T = number> = PluginSettingCommon & {
type: "number";
/** The current `value` */
value?: T;
/** The `placeholder` input `number` */
placeholder?: number;
/** Enforces an inclusive `min` allowed `value` */
min?: number;
/** Enforces an inclusive `max` allowed `value` */
max?: number;
/** Enforces a `step` size between each `value` */
step?: number;
/** Given a `value`, how can it formatted as a `number`? */
formatter?: (value: T) => number;
/** Given a `number`, how should it be saved as a `value`? */
parser?: (value: number) => T;
/** Determines whether to use a slider or input. Uses `input` by default */
variant?: "slider" | "input";
};
/** `PluginSetting` which is displayed and input as a `boolean` */
export type PluginSettingBoolean<T = boolean> = PluginSettingCommon & {
type: "boolean";
/** The current `value` */
value?: T;
};
/** `PluginStatus` is displayed via an indicator on the `/settings` page */
export type PluginStatus = {
/** Determines the text displayed next to the `indicator` icon */
text?: string;
/** Determines the `indicator` color and icon */
indicator?: "success" | "error" | "warning" | "info" | "loading";
};
/** `PluginSettings` is a map of the settings your plugin will show on the `/settings` page */
export type PluginSettings = {
/** Each setting needs a unique `key` */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[settingKey: string]: PluginSetting<any>;
};
/** Useful for strictly-typing things */
export type PluginTypeHelper = { settings?: PluginSettings };
export type PluginTypeHelperDefault = { settings: undefined };
/** The `Plugin` type defines the API which StableStudio uses to provide functionality via plugins */
export type Plugin<P extends PluginTypeHelper = PluginTypeHelperDefault> = {
/** You should provide a `PluginManifest`, otherwise the UI shows a warning */
manifest?: PluginManifest;
/** The most fundamental function needed for stable diffusion generations */
createStableDiffusionImages?: (options?: {
/** The `StableDiffusionInput` you've been asked to generate, if empty, you could still return a random image */
input?: StableDiffusionInput;
/** Determines how many images will be created using the given `StableDiffusionInput` */
count?: number;
}) => MaybePromise<StableDiffusionImages | undefined>;
/** This function provides historical access to generated images. If omitted, the app will lose its history on refresh */
getStableDiffusionExistingImages?: (options?: {
/** How many images the UI is requesting */
limit?: number;
/** The `ID` of last image the UI has access to, it should be omitted from the response */
exclusiveStartImageID?: ID;
}) => MaybePromise<StableDiffusionImages[] | undefined>;
/** If more than one `StableDiffusionModel`, you can return them via this function and they will be presented as a dropdown in the UI */
getStableDiffusionModels?: () => MaybePromise<
StableDiffusionModel[] | undefined
>;
/** If more than one `StableDiffusionStyle`, you can return them via this function and they will be presented as a dropdown in the UI */
getStableDiffusionStyles?: () => MaybePromise<
StableDiffusionStyle[] | undefined
>;
/** Determines the default count passed to `createStableDiffusionImages` */
getStableDiffusionDefaultCount?: () => number | undefined;
/** Determines the default input passed to `createStableDiffusionImages` and is also used when setting up a new generation */
getStableDiffusionDefaultInput?: () => StableDiffusionInput | undefined;
/** If you support deleting existing images by `ID`, this function will enable a deletion UI */
deleteStableDiffusionImages?: (options?: {
imageIDs?: ID[];
}) => MaybePromise<void>;
/** Determines whether to display a `PluginStatus` and sets its contents */
getStatus?: () => MaybePromise<PluginStatus | undefined>;
/** If your plugin has `settings` you want to make available on the `/settings page, you can declare them here` */
settings?: P["settings"];
/** Handles changes in `settings`, you'll need to actually use Zustand's `set` to persist the change */
setSetting?: (
settingKey: keyof P["settings"],
value: string | number | boolean
) => void;
} & P;
export type StableDiffusionInput = {
prompts?: StableDiffusionPrompt[];
/** If `getStableDiffusionModels` is available and a `StableDiffusionModel` is selected, this is its `ID` */
model?: ID;
/** If `getStableDiffusionStyles` is available and a `StableDiffusionStyle` is selected, this is its `ID` */
style?: ID;
width?: number;
height?: number;
cfgScale?: number;
steps?: number;
seed?: number;
/** `StableDiffusionInputImage` in the form of a black and white mask used for in-painting and out-painting */
maskImage?: StableDiffusionInputImage;
/** `StableDiffusionInputImage` which is used for image-to-image generations such as creating variations */
initialImage?: StableDiffusionInputImage;
};
export type StableDiffusionPrompt = {
text?: string;
/** Value between `-1` and `1` */
weight?: number;
};
/** This controls how a `StableDiffusionModel` is displayed in the UI */
export type StableDiffusionModel = {
id: ID;
name?: string;
description?: string;
image?: URLString;
};
/** This controls how a `StableDiffusionStyle` is displayed in the UI */
export type StableDiffusionStyle = {
id: ID;
name?: string;
description?: string;
image?: URLString;
};
export type StableDiffusionInputImage = {
blob?: Blob;
/** Value between `0` and `1` */
weight?: number;
};
/** Since multiple images can be generated at once, this is how they are grouped */
export type StableDiffusionImages = {
id: ID;
/** If `exclusiveStartImageID` is set, this means more images exist for this group and the `ID` is passed to `getStableDiffusionExistingImages` */
exclusiveStartImageID?: ID;
images?: StableDiffusionImage[];
};
export type StableDiffusionImage = {
id: ID;
createdAt?: Date;
/** The `StableDiffusionInput` used to create this image */
input?: StableDiffusionInput;
blob?: Blob;
};
/** Allows both asynchronous and synchronous return types */
type MaybePromise<T> = T | Promise<T>;
/** In this context, an `ID` represents a unique-within-this-plugin `ID`, no schema is enforced */
export type ID = string;
/** A valid URL */
export type URLString = string;
/** Markdown string which is rendered as markdown in the UI */
export type Markdown = string;

View File

@ -0,0 +1 @@
export * from "./Plugin";

View File

@ -0,0 +1,21 @@
{
"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 }
]
}
}

View File

@ -0,0 +1 @@
{ "extends": ["../../.eslintrc.json"] }

3
packages/stablestudio-ui/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
stats.html
dist

View File

@ -0,0 +1,21 @@
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.

View File

@ -0,0 +1,341 @@
<div align="center">
# 🎨 UI
**🗺 Contents [ About](#about) · [🦾 Technology](#technology) · [🏗 Structure](#structure) · [🤝 Conventions](#conventions)**
**[⬆️ Top-Level README](../../README.md)**
![ManStandingBeforeUI](../../misc/ManStandingBeforeUI.png)
</div>
# <a id="about" href="#about"> About</a>
_Welcome to the UI package for StableStudio!_
**If you're ready to dive in and make changes, be sure to read about [technology](#technology), [structure](#structure), [conventions](#conventions), and [plugins](../stablestudio-plugin/README.md) first.**
## 📜 History
StableStudio represents a new direction for [DreamStudio](https://dreamstudio.ai) with renewed focus on open-source and community-driven development, but the project has an interesting backstory...
- **Pre-Stable Diffusion Launch**
_Summer 2022_
[DreamStudio](https://dreamstudio.ai) began as passion-project by [@nin](https://twitter.com/nin_artificial) with the goal of creating an all-in-one creative studio for generative animations using Disco Diffusion. He and several collaborators wrote the original UI using Vue.js and a local Python back-end. With the imminent arrival of Stable Diffusion, focus shifted toward creating an easy-to-use interface for image generation so the release of the model would be as accessible as possible.
- **Post-Stable Diffusion Launch**
_August 2022  November 2022_
Following the release of Stable Diffusion, [DreamStudio](https://dreamstudio.ai) served as a vehicle for new models and features shipped by [Stability AI](http://stability.ai). This period saw the introduction of [in-painting](https://platform.stability.ai/docs/features/inpainting?tab=typescript), [out-painting](https://platform.stability.ai/docs/features/inpainting?tab=typescript), and [image-to-image](https://platform.stability.ai/docs/features/image-to-image?tab=typescript).
- **React**
_December 2022 April 2023_
In early December, work began on a new infinite-canvas version of the existing editor. Given the need to manage complicated state and side effects declaratively, the decision was made to switch the editor to React. Once a working editor MVP was finished, the opportunity was taken to rewrite the entire app while also shipping a re-imagined UX.
- **StableStudio**
_Present Future_
The breakneck speed of the Stable Diffusion community has proven distributing generative AI is better achieved through open-source development. We're hopeful StableStudio can serve as a hub for community collaboration and a home for exciting new features.
# <a id="technology" href="#technology">🦾 Technology</a>
![SorcererWithReact](../../misc/SorcererWithReact.png)
- **[TypeScript](https://www.typescriptlang.org/)**  Type safety ftw!
- **[Vite](https://vitejs.dev/)** Bundler and live-development tool. You can see the full config in [`vite.config.ts`](./vite.config.ts)
- **[React](https://reactjs.org/)**   We're using React with modern hooks and functional components
- **[Zustand](https://docs.pmnd.rs/zustand/getting-started/introduction)**   Extremely fast and easy-to-use state management, it's powerful and tiny!
- **[Tailwind](https://tailwindcss.com/)**  Our prefered method of styling components, the config is at [`tailwind.config.js`](./tailwind.config.cjs)
- **[Emotion](https://emotion.sh/docs/introduction)**  For when we need to break free of Tailwind and write "native CSS"
# <a id="structure" href="#structure">🏗 Structure</a>
![CyberPyramid](../../misc/CyberPyramid.png)
## 🧱 Domain-Driven Design
**The most important aspect of this codebase's structure is adherence to domain-driven design.**
This means we organize code around the _concepts_ rather than technical implementation details.
For example, if we identify a _concept_, let's say `User`, we would create a `User` "domain."
The `User` domain would _own_ all user-related code, including visual representation, state, hooks, etc.
Most domains are _composed_ of smaller domains; a hypothetical `User` domain might be composed of `User.State`, `User.Avatar`, `User.Preferences`, `User.Details`, etc.
_This structure is fractal in nature,_ meaning `User.Details` might itself be composed of `User.Details.SocialMedia`, `User.Details.ContactInformation`, `User.Details.UpdateRequest`, etc.
### \*️⃣ Domain Syntax
Here's an example of how we might represent a `User` domain in code...
```tsx
import { Avatar } from "./Avatar";
import { Preferences } from "./Preferences";
import { Details } from "./Details";
export type User = {
id: ID;
avatar?: User.Avatar;
preferences?: User.Preferences;
details?: User.Details;
};
export function User({ id }: User.Props) {
const user = User.use(id);
return (
<>
<User.Avatar avatar={avatar} />
<User.Preferences preferences={preferences} />
<User.Details details={details} />
</>
);
}
export declare namespace User {
export { Avatar, Preferences, Details };
}
export namespace User {
User.Avatar = Avatar;
User.Preferences = Preferences;
User.Details = Details;
export type Props = {
id?: ID;
};
export const use = (id: ID) => {
// Make an API call for the user or something
};
}
```
This syntax takes advantage of TypeScript's declaration merging feature to enable nice fluent-style APIs for domains...
```tsx
import { User } from "./User";
// You can use `User` as a type
const bob: User = { id: "bob" };
function App(id: ID) {
// You can use `User` as a namespace
const user = User.use(id);
const userPreferences = User.Preferences.use(id);
// You can use `User` as a component
return (
<>
<User id={user.id} />
<User.Preferences id={user.id} />
</>
);
}
```
Here is an example of a real domain ([`Editor.Camera`](./src/Editor/Camera/index.tsx)) you'll find in the app...
```tsx
// Owner of all things camera-related in the editor
Editor.Camera;
// Centers the camera in the editor
Editor.Camera.Center;
// The hand tool is used for panning around
Editor.Camera.Hand;
// For resetting the camera to the default view
Editor.Camera.Reset;
// Specifies keyboard shortcuts for camera actions
Editor.Camera.Shortcuts;
// Controls the zoom level of the camera and mouse wheel controls
Editor.Camera.Zoom;
```
Quick note about the `export declare namespace User` syntax from the first example...
This is needed when a namespace exports a type.
It's an unfortunate bit of syntax which might [not be needed](https://github.com/microsoft/TypeScript/issues/39865) in the future.
If you want to discuss this further, please check out [this issue](https://github.com/Stability-AI/StableStudio/issues/7).
### 📁 Directories and Files
_Domains are usually correlated one-to-one with file/folder structure._
For example, the [`Editor.Camera`](./src/Editor/Camera/index.tsx) domain mentioned above is composed of the following files...
```
./src/Editor/Camera/
├── Center.tsx
├── Hand.tsx
├── Reset.tsx
├── Shortcut.tsx
├── Zoom.tsx
└── index.tsx
```
This means if you see a domain like [`Generation.Image.Download`](./src/Generation/Image/Download/index.tsx), you can expect to find it at `./src/Generation/Image/Download`.
All root-level domains located at the top-level of the [`./src`](./src) folder and can be imported using the shorthand syntax...
```ts
import { ExampleDomain } from "~/ExampleDomain";
import { ExampleDomain } from "../../../../../ExampleDomain";
// ^ If you were deep in the folder tree, it would look like this without the `~` alias
```
### 📋 Structuring Tips
- **Look for repeated references to a word or concept**
For example, if you're working in a `User` domain and find yourself using the word "avatar" a lot, you might want to create a `User.Avatar` domain
- **Compound words are structuring hints**
Domains like `DeviceInformation` might be better represented as `Device.Information`.
- **Plural domains are very important**
The singular [`Generation.Image.Input`](./src/Generation/Image/Input/index.tsx) domain owns everything related to the concept of what's being fed to an image generation, but [`Generation.Image.Inputs`](./src/Generation/Image/index.tsx) owns the state of all inputs as a collective.
Plural domains are usually exported at the same level as their singular counterparts, such as [`Editor.Dream`](./src/Editor/Dream/index.tsx) and [`Editor.Dreams`](./src/Editor/Dream/Dreams.tsx).
### ⭐️ Important Domains
- **[`App`](./src/App/index.tsx)** Owner of app-level functionality such as the React root, sidebars, providers, etc.
- **[`Generation.Image`](./src/Generation/Image/index.tsx)** Likely the largest domain, owns all things related to image generation
- **[`Generation.Image.Session`](./src/Generation/Image/Session/index.tsx)** Domain which was poorly named and grew too large as a result, manages the active "image generation session"
- **[`Editor`](./src/GlobalVariables/index.tsd)** Home of all editor functionality
- **[`Plugin`](./src/Plugin/index.ts)** Owner of plugin setup and access, contains the important `Plugin.use` hook
- **[`Theme`](./src/Theme/index.ts)**  Contains the StableStudio's design system and common components such as `Theme.Icon`, `Theme.Button`, etc.
- **[`Shortcut`](./src/Shortcut/index.ts)**  Contains the StableStudio's keyboard shortcut system and menu
- **[`GlobalState`](./src/GlobalState/index.ts)**  Mostly a pass-through wrapper around [Zustand](https://docs.pmnd.rs/zustand/getting-started/introduction)
- <span id="global-variables">**[`GlobalVariables`](./src/GlobalVariables/index.ts)**</span> Extremely useful functions and types available across the StableStudio without needing any imports (`css`, `classes`, `useEffect`, etc.)
# <a id="conventions" href="#conventions">🤝 Conventions</a>
![RobotsHoldingHands](../../misc/RobotsHoldingHands.png)
## 💅 Styles and CSS
Most styling in StableStudio is implemented with [Tailwind CSS](https://tailwindcss.com/).
The [`Theme`](./src/Theme/index.ts) domain contains a bunch of useful pre-made components, make sure to check there first if you need something "off-the-shelf."
You can use the [`classes`](#global-variables) function anywhere without imports if you need conditional styling or to break apart class names...
```tsx
function Example({
isEmphasized,
isDisabled,
children,
}: PropsWithChildren<{
isEmphasized?: boolean;
isDisabled: boolean;
}>) {
return (
<div
className={classes(
"bg-gray-100",
isEmphasized && "bg-red-500 text-4xl font-bold",
isDisabled && "text-xs opacity-50"
)}
>
{children}
</div>
);
}
```
You can always "break glass" and use raw CSS via the globally-available `css` function if you need to, but please try to avoid it...
```tsx
function Example() {
return (
<div
css={css`
::-webkit-scrollbar {
display: none;
}
`}
>
Hello, World!
</div>
);
}
```
## 🏛 State Management via [Zustand](https://docs.pmnd.rs/zustand/getting-started/introduction)
StableStudio uses [Zustand](https://docs.pmnd.rs/zustand/getting-started/introduction) for state management, which is honestly super cool.
It's fast and small, you can read through the whole codebase in a few minutes.
We originally used [Recoil](https://recoiljs.org/) it couldn't handle "hot" paths nearly as well.
Whenever you need globally-available state, you can use the [`GlobalState`](./src/GlobalState/index.ts) domain, which wraps Zustand...
```tsx
import { GlobalState } from "~/GlobalState";
function Count() {
const count = Count.use();
const setCount = Count.useSet();
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<span>{count}</span>
</div>
);
}
export namespace Count {
export const use = State.use(({ count }) => count);
export const useSet = () =>
State.use(({ setCount }) => setCount, GlobalState.shallow);
}
type State = {
count: number;
setCount: (count: number) => void;
};
namespace State {
const store = GlobalState.create<State>((set) => ({
count: 0,
setCount: (count) => set({ count }),
}));
export const use = store;
}
```
Notice how the `Count` domain exports `Count.use` and `Count.useSet` instead of exporting its state directly.
This allows us to change the state implementation without breaking any code that uses it.
Finally, you can see `GlobalState.shallow` used to [limit rerenders](https://github.com/pmndrs/zustand#selecting-multiple-state-slices).

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>StableStudio</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover" />
<link rel="stylesheet" href="./src/Theme/index.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link
rel="preload"
href="Inter.ttf"
as="font"
type="font/ttf"
crossorigin
/>
</head>
<body>
<div
id="tooltip-root"
class="dark h-[100vh] w-[100vw] overflow-hidden text-white"
></div>
<div id="modal-root" class="dark overflow-hidden text-white"></div>
<div id="app" class="dark"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,97 @@
{
"name": "@stability/stablestudio-ui",
"version": "1.0.0",
"license": "MIT",
"type": "module",
"scripts": {
"clean": "rimraf dist && rimraf node_modules",
"lint": "eslint \"./src/**/*.{ts,tsx}\"",
"lint:fix": "yarn lint --fix",
"build:types": "tsc --noEmit",
"build": "yarn build:preview",
"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"
},
"dependencies": {
"@emotion/css": "^11.10.5",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@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:^",
"@tanstack/react-query": "^4.22.0",
"@tanstack/react-query-devtools": "^4.22.0",
"@tanstack/react-virtual": "beta",
"buffer": "^6.0.3",
"date-fns": "^2.29.3",
"file-saver": "^2.0.5",
"flexsearch": "^0.7.31",
"framer-motion": "^8.5.0",
"idb-keyval": "^6.2.0",
"immer": "^9.0.18",
"jszip": "^3.10.1",
"konva": "^8.4.2",
"lodash.throttle": "^4.1.1",
"lucide-react": "^0.105.0",
"minisearch": "^6.0.0",
"notistack": "^3.0.0-alpha.11",
"query-string": "^8.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-konva": "^18.2.3",
"react-konva-utils": "^0.3.1",
"react-markdown": "^8.0.7",
"react-router-dom": "^6.7.0",
"react-slider": "^2.0.4",
"react-syntax-highlighter": "^15.5.0",
"react-use": "^17.4.0",
"react-virtualized-auto-sizer": "^1.0.7",
"react-window": "^1.8.8",
"remark-custom-heading-id": "^1.0.0",
"remark-gfm": "^3.0.1",
"tailwind-merge": "^1.8.1",
"throttled-queue": "^2.1.4",
"tiny-invariant": "^1.3.1",
"ts-custom-error": "^3.3.1",
"unified": "^10.1.2",
"zundo": "beta",
"zustand": "^4.3.2"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"@types/file-saver": "^2.0.5",
"@types/lodash.throttle": "^4.1.7",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-slider": "^1.3.1",
"@types/react-syntax-highlighter": "^15.5.6",
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"@vitejs/plugin-react": "^3.0.1",
"autoprefixer": "^10.4.13",
"eslint": "8.32.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-markdown": "^3.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.21",
"prettier": "^2.8.3",
"prettier-plugin-tailwindcss": "^0.2.1",
"rimraf": "^4.1.1",
"rollup-plugin-visualizer": "^5.9.0",
"tailwindcss": "^3.2.4",
"tsx": "^3.12.2",
"typescript": "4.9.4",
"typescript-styled-plugin": "^0.18.2",
"vite": "^4.0.4",
"vite-tsconfig-paths": "^4.0.5"
}
}

View File

@ -0,0 +1,9 @@
// This project includes code from `caniuse-lite` by Ben Briggs, available under a CC BY 4.0 license.
// The original work can be found at the repository: https://github.com/browserslist/caniuse-lite.
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

View File

@ -0,0 +1,52 @@
var l = (t) => {
let e,
i = new Set(),
r = (o, u) => {
let s = typeof o == "function" ? o(e) : o;
if (!Object.is(s, e)) {
let g = e;
(e = u ?? typeof s != "object" ? s : Object.assign({}, e, s)),
i.forEach((p) => p(e, g));
}
},
a = () => e,
n = {
setState: r,
getState: a,
subscribe: (o) => (i.add(o), () => i.delete(o)),
destroy: () => {
(import.meta.env && import.meta.env.MODE) !== "production" &&
console.warn(
"[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."
),
i.clear();
},
};
return (e = t(r, a, n)), n;
},
d = (t) => (t ? l(t) : l),
c = (t) => (e) => d((i, r) => t({ set: i, get: r, context: e }));
var m = c(() => ({
manifest: {
name: "Example Plugin",
description: "An example plugin for StableStudio",
version: "1.2.3",
author: "Bobby Joe",
license: "MIT",
link: "https://github.com",
icon: "https://place.dog/100/100",
},
getStatus: () => ({
indicator: "success",
message: "This plugin is working",
}),
settings: {
exampleSetting: {
type: "string",
default: "Hello, World!",
placeholder: "Example setting",
},
},
}));
export { m as createPlugin };
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1,52 @@
var l = (t) => {
let e,
i = new Set(),
r = (o, u) => {
let s = typeof o == "function" ? o(e) : o;
if (!Object.is(s, e)) {
let g = e;
(e = u ?? typeof s != "object" ? s : Object.assign({}, e, s)),
i.forEach((p) => p(e, g));
}
},
a = () => e,
n = {
setState: r,
getState: a,
subscribe: (o) => (i.add(o), () => i.delete(o)),
destroy: () => {
(import.meta.env && import.meta.env.MODE) !== "production" &&
console.warn(
"[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."
),
i.clear();
},
};
return (e = t(r, a, n)), n;
},
d = (t) => (t ? l(t) : l),
c = (t) => (e) => d((i, r) => t({ set: i, get: r, context: e }));
var m = c(() => ({
// manifest: {
// name: "Example Plugin",
// description: "An example plugin for StableStudio",
// version: "1.2.3",
// author: "Bobby Joe",
// license: "MIT",
// link: "https://github.com",
// icon: "place.dog/100/100",
// },
getStatus: () => ({
indicator: "success",
message: "This plugin is working",
}),
settings: {
exampleSetting: {
type: "string",
default: "Hello, World!",
placeholder: "Example setting",
},
},
}));
export { m as createPlugin };
//# sourceMappingURL=index.js.map

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 KiB

Some files were not shown because too many files have changed in this diff Show More