commit eea5b6cdf4069ebcd65ccfe749d73134970673e6 Author: Daniel Legt Date: Mon May 1 15:47:25 2023 +0300 Initial State Commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..dac5d40 --- /dev/null +++ b/go.mod @@ -0,0 +1,31 @@ +module danlegt.com/stablediffusion-friends + +go 1.20 + +require github.com/gin-gonic/gin v1.9.0 + +require ( + github.com/bytedance/sonic v1.8.8 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.13.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1c6b954 --- /dev/null +++ b/go.sum @@ -0,0 +1,82 @@ +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q= +github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= +github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/lib/rtypes/sdnode.go b/lib/rtypes/sdnode.go new file mode 100644 index 0000000..c9c0cd9 --- /dev/null +++ b/lib/rtypes/sdnode.go @@ -0,0 +1,82 @@ +package rtypes + +import "fmt" + +// A stable diffusion node +type SDNode struct { + URL string `json:"url"` + Port int `json:"port"` + Status bool `json:"status"` +} + +func (node SDNode) GetDomainBase() string { + return fmt.Sprintf("http://%v:%v/", node.URL, node.Port) +} + +func (node SDNode) GetTextToImageLink() string { + return fmt.Sprintf("%vsdapi/v1/txt2img", node.GetDomainBase()) +} + +type SDTextToImageRequest struct { + Prompt string `json:"prompt"` // "a beautiful blonde woman, woman, blonde, beautiful, masterpiece, illustration", + SamplerName string `json:"sampler_name"` // "Euler", + BatchSize int `json:"batch_size"` // 1, + Steps int `json:"steps"` // 25, + CfgScale float32 `json:"cfg_scale"` // 7, + Width int `json:"width"` // 512, + Height int `json:"height"` // 512, + NegativePrompt string `json:"negative_prompt"` // "ugly, destroyed, artifacts", + SamplerIndex string `json:"sampler_index"` // "Euler", + SendImages bool `json:"send_images"` // true, + SaveImages bool `json:"save_images"` // false +} + +type SDTextToImageResponse struct { + Images []string `json:"images"` + Parameters SDTextToImageResponseParameters `json:"parameters"` + Info string `json:"info"` +} + +type SDTextToImageResponseParameters struct { + EnableHDR bool `json:"enable_hr"` // false, + DenoisingStrength float32 `json:"denoising_strength"` // 0, + FirstphaseWidth float32 `json:"firstphase_width"` // 0, + FirstphaseHeight float32 `json:"firstphase_height"` // 0, + HrScale float32 `json:"hr_scale"` // 2, + HrUpscaler string `json:"hr_upscaler"` // null, + HrSecondPassSteps float32 `json:"hr_second_pass_steps"` // 0, + HrResizeX float32 `json:"hr_resize_x"` // 0, + HrResizeY float32 `json:"hr_resize_y"` // 0, + Prompt string `json:"prompt"` // "a beautiful blonde woman, woman, blonde, beautiful, masterpiece, illustration", + Styles []string `json:"styles"` // null, + Seed float32 `json:"seed"` // -1, + Subseed float32 `json:"subseed"` // -1, + SubseedStrength float32 `json:"subseed_strength"` // 0, + SeedResizeFromH float32 `json:"seed_resize_from_h"` // -1, + SeedResizeFromW float32 `json:"seed_resize_from_w"` // -1, + Sampler_name string `json:"sampler_name"` // "Euler", + Batch_size float32 `json:"batch_size"` // 1, + NIterations float32 `json:"n_iter"` // 1, + Steps float32 `json:"steps"` // 25, + CFGScale float32 `json:"cfg_scale"` // 7, + Width int `json:"width"` // 512, + Height int `json:"height"` // 512, + RestoreFaces bool `json:"restore_faces"` // false, + Tiling bool `json:"tiling"` // false, + DoNotSaveSamples bool `json:"do_not_save_samples"` // false, + DoNotSaveGrid bool `json:"do_not_save_grid"` // false, + NegativePrompt string `json:"negative_prompt"` // "ugly, destroyed, artifacts", + Eta string `json:"eta"` // null, + Schurn float32 `json:"s_churn"` // 0, + Stmax string `json:"s_tmax"` // null, + Stmin float32 `json:"s_tmin"` // 0, + Snoise float32 `json:"s_noise"` // 1, + OverrideSettings string `json:"override_settings"` // null, + OverrideSettingsRestoreAfterwards bool `json:"override_settings_restore_afterwards"` // true, + ScriptArgs []string `json:"script_args"` // [], + SamplerIndex string `json:"sampler_index"` // "Euler", + ScriptName string `json:"script_name"` // null, + SendImages bool `json:"send_images"` // true, + SaveImages bool `json:"save_images"` // false, + AlwaysonScripts interface{} `json:"alwayson_scripts"` // {} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..7c94322 --- /dev/null +++ b/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + "danlegt.com/stablediffusion-friends/lib/rtypes" + "github.com/gin-gonic/gin" +) + +var nodes [1]rtypes.SDNode = [...]rtypes.SDNode{ + rtypes.SDNode{ + URL: "127.0.0.1", + Port: 7860, + Status: false, + }, +} + +var imagesToDisplay []string + +func main() { + r := gin.Default() + runLoaders(r) + + r.GET("/", func(c *gin.Context) { + c.HTML(http.StatusOK, "index.html", nil) + }) + + r.POST("/api/image/generate", func(c *gin.Context) { + + imageDescriptior := c.PostForm("image_description") + + // Build the request + request := rtypes.SDTextToImageRequest{ + Prompt: imageDescriptior, + SamplerName: "DPM2", + BatchSize: 1, + Steps: 25, + CfgScale: 8, + Width: 512, + Height: 512, + NegativePrompt: "nsfw, porn, naked, nude, nipple, penis, dick, vagina, asshole, visible nipple, nsfl, not safe for work, nudity, artifact, deformed, multiple limbs, ugly, gore, blood, sex, pornography", + SamplerIndex: "Euler", + SendImages: true, + SaveImages: false, + } + + body, err := json.Marshal(request) + if err != nil { + c.AbortWithError(500, err) + return + } + + r, err := http.NewRequest("POST", nodes[0].GetTextToImageLink(), bytes.NewBuffer(body)) + if err != nil { + c.AbortWithError(500, err) + return + } + + r.Header.Add("Content-Type", "application/json") + client := &http.Client{} + res, err := client.Do(r) + if err != nil { + c.AbortWithError(500, err) + return + } + + defer res.Body.Close() + + responseJson := &rtypes.SDTextToImageResponse{} + err = json.NewDecoder(res.Body).Decode(responseJson) + if err != nil { + fmt.Println("Failed to decode the JSON") + c.AbortWithError(500, err) + return + } + + c.JSON(http.StatusOK, responseJson) + }) + + r.POST("/api/image/submit", func(c *gin.Context) { + + imageData := c.PostForm("image_data") + imagesToDisplay = append(imagesToDisplay[:], imageData) + + fmt.Printf("Got a new image to display, currently %v in queue\n", len(imagesToDisplay)) + + c.JSON(200, gin.H{ + "queue_position": len(imagesToDisplay), + }) + }) + + r.GET("/api/image", func(c *gin.Context) { + + if len(imagesToDisplay) <= 0 { + c.JSON(200, [0]string{}) + return + } + + newImage, newImagesToDisplay := imagesToDisplay[0], imagesToDisplay[1:] + + // Actually pop it + imagesToDisplay = newImagesToDisplay + + c.JSON(200, gin.H{ + "image": newImage, + "queue_left": len(imagesToDisplay), + }) + + }) + + r.GET("/api/image/queue", func(c *gin.Context) { + c.JSON(200, imagesToDisplay) + }) + + r.Run() + +} + +func runLoaders(r *gin.Engine) { + r.Static("/public", "./public") + r.LoadHTMLGlob("templates/**/*.html") +} diff --git a/public/css/buttons.css b/public/css/buttons.css new file mode 100644 index 0000000..b0a9fdf --- /dev/null +++ b/public/css/buttons.css @@ -0,0 +1,46 @@ +.btn-95 { + background-color: #c0c0c0; + color: black; + border: 2px outset gray; + border-radius: 0px; + font-size: 16px; + font-family: "Arial", sans-serif; + padding: 6px 12px; + text-align: center; + text-decoration: none; + display: inline-block; + cursor: pointer; +} + +.btn-95:hover:not(:disabled) { + background-color: #d8d8d8; +} + +.btn-95:active:not(:disabled) { + background-color: #b8b8b8; + border: 2px inset gray; +} + +.btn-95:disabled { + cursor: not-allowed; + opacity: .8; +} + + +textarea { + background-color: #c0c0c0; + color: black; + border: 2px outset gray; + font-size: 16px; + font-family: "Arial", sans-serif; + padding: 6px 12px; + resize: vertical; +} + +textarea:hover { + background-color: #d8d8d8; +} + +textarea:focus { + background-color: #e8e8e8; +} \ No newline at end of file diff --git a/public/css/vaporwave.css b/public/css/vaporwave.css new file mode 100644 index 0000000..bd1e7d2 --- /dev/null +++ b/public/css/vaporwave.css @@ -0,0 +1,67 @@ +.overlay { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: transparent; + background-size: 5px 5px, 5px 5px; + background-position: -1px -1px, -1px -1px; + background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px); + mix-blend-mode: difference; +} + +.glitch { + clip-path: polygon(0 0, 100% 0, 100% 0.5em, 0 0.5em); + animation: glitch 10s linear infinite; + transform: translatex(0.1rem); +} + +@keyframes glitch { + to { + clip-path: polygon(0 calc(100% - .5em), 100% calc(100% - .5em), 0 100%, 0 100%); + } +} + +.sun { + width: 40vh; + height: 40vh; + font-size: 1rem; + border-radius: 20vh; + position: relative; + overflow: hidden; +} + +.sun:before { + content: ""; + display: block; + position: absolute; + top: 0; + height: 50%; + background-color: #f54171; + background: linear-gradient(0deg, #2b1165 0%, #1a3a82 37%, #ab24b1 69%, #f54171 100%); + background-size: 40vh 40vh; + width: 100%; +} + +.sun:after { + content: ""; + display: block; + position: absolute; + bottom: 0; + width: 100%; + height: 50%; + background-color: #f54171; + background: linear-gradient(0deg, #2b1165 0%, #1a3a82 37%, #ab24b1 69%, #f54171 100%); + background-size: 40vh 40vh; + background-position: bottom center; + clip-path: polygon(0 -10em, 100% -10em, 100% -10.5em, 0 -10.5em, 0 -9em, 100% -9em, 100% -9.5em, 0 -9.5em, 0 -8em, 100% -8em, 100% -8.5em, 0 -8.5em, 0 -7em, 100% -7em, 100% -7.5em, 0 -7.5em, 0 -6em, 100% -6em, 100% -6.5em, 0 -6.5em, 0 -5em, 100% -5em, 100% -5.5em, 0 -5.5em, 0 -4em, 100% -4em, 100% -4.5em, 0 -4.5em, 0 -3em, 100% -3em, 100% -3.5em, 0 -3.5em, 0 -2em, 100% -2em, 100% -2.5em, 0 -2.5em, 0 -1em, 100% -1em, 100% -1.5em, 0 -1.5em, 0 0, 100% 0, 100% -0.5em, 0 -0.5em, 0 0, 100% 0, 100% 0.5em, 0 0.5em, 0 1em, 100% 1em, 100% 1.5em, 0 1.5em, 0 2em, 100% 2em, 100% 2.5em, 0 2.5em, 0 3em, 100% 3em, 100% 3.5em, 0 3.5em, 0 4em, 100% 4em, 100% 4.5em, 0 4.5em, 0 5em, 100% 5em, 100% 5.5em, 0 5.5em, 0 6em, 100% 6em, 100% 6.5em, 0 6.5em, 0 7em, 100% 7em, 100% 7.5em, 0 7.5em, 0 8em, 100% 8em, 100% 8.5em, 0 8.5em, 0 9em, 100% 9em, 100% 9.5em, 0 9.5em); + animation: lightEffect 20s linear infinite reverse; +} + +@keyframes lightEffect { + to { + clip-path: polygon(0 0, 100% 0, 100% 0.5em, 0 0.5em, 0 1em, 100% 1em, 100% 1.5em, 0 1.5em, 0 2em, 100% 2em, 100% 2.5em, 0 2.5em, 0 3em, 100% 3em, 100% 3.5em, 0 3.5em, 0 4em, 100% 4em, 100% 4.5em, 0 4.5em, 0 5em, 100% 5em, 100% 5.5em, 0 5.5em, 0 6em, 100% 6em, 100% 6.5em, 0 6.5em, 0 7em, 100% 7em, 100% 7.5em, 0 7.5em, 0 8em, 100% 8em, 100% 8.5em, 0 8.5em, 0 9em, 100% 9em, 100% 9.5em, 0 9.5em, 0 10em, 100% 10em, 100% 10em, 0 10em, 0 11em, 100% 11em, 100% 11.5em, 0 11.5em, 0 12em, 100% 12em, 100% 12.5em, 0 12.5em, 0 13em, 100% 13em, 100% 13.5em, 0 13.5em, 0 14em, 100% 14em, 100% 14.5em, 0 14.5em, 0 15em, 100% 15em, 100% 15.5em, 0 15.5em, 0 16em, 100% 16em, 100% 16.5em, 0 16.5em, 0 17em, 100% 17em, 100% 17.5em, 0 17.5em, 0 18em, 100% 18em, 100% 18.5em, 0 18.5em, 0 19em, 100% 19em, 100% 19.5em, 0 19.5em, 0 20em, 100% 20em, 100% 20.5em, 0 20.5em); + } +} \ No newline at end of file diff --git a/public/img/Daniel.png b/public/img/Daniel.png new file mode 100644 index 0000000..0927560 Binary files /dev/null and b/public/img/Daniel.png differ diff --git a/public/img/gifs/loading.gif b/public/img/gifs/loading.gif new file mode 100644 index 0000000..5fc6cd8 Binary files /dev/null and b/public/img/gifs/loading.gif differ diff --git a/public/img/icons/broken.svg b/public/img/icons/broken.svg new file mode 100644 index 0000000..e3d9d66 --- /dev/null +++ b/public/img/icons/broken.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/img/posters/1.jpeg b/public/img/posters/1.jpeg new file mode 100644 index 0000000..6bd78ed Binary files /dev/null and b/public/img/posters/1.jpeg differ diff --git a/public/img/posters/2.png b/public/img/posters/2.png new file mode 100644 index 0000000..81b9702 Binary files /dev/null and b/public/img/posters/2.png differ diff --git a/public/img/posters/3.jpeg b/public/img/posters/3.jpeg new file mode 100644 index 0000000..06402b6 Binary files /dev/null and b/public/img/posters/3.jpeg differ diff --git a/public/img/posters/3.png b/public/img/posters/3.png new file mode 100644 index 0000000..adaaa5f Binary files /dev/null and b/public/img/posters/3.png differ diff --git a/public/img/vaporwave/1.png b/public/img/vaporwave/1.png new file mode 100644 index 0000000..b526cd3 Binary files /dev/null and b/public/img/vaporwave/1.png differ diff --git a/public/img/vaporwave/2.png b/public/img/vaporwave/2.png new file mode 100644 index 0000000..a013e99 Binary files /dev/null and b/public/img/vaporwave/2.png differ diff --git a/public/img/vaporwave/3.png b/public/img/vaporwave/3.png new file mode 100644 index 0000000..83ebb64 Binary files /dev/null and b/public/img/vaporwave/3.png differ diff --git a/public/img/vaporwave/4.png b/public/img/vaporwave/4.png new file mode 100644 index 0000000..e14133b Binary files /dev/null and b/public/img/vaporwave/4.png differ diff --git a/public/img/vaporwave/5.png b/public/img/vaporwave/5.png new file mode 100644 index 0000000..50834dc Binary files /dev/null and b/public/img/vaporwave/5.png differ diff --git a/public/img/vaporwave/6.png b/public/img/vaporwave/6.png new file mode 100644 index 0000000..8f5685d Binary files /dev/null and b/public/img/vaporwave/6.png differ diff --git a/public/img/vaporwave/7.png b/public/img/vaporwave/7.png new file mode 100644 index 0000000..7e1d08f Binary files /dev/null and b/public/img/vaporwave/7.png differ diff --git a/public/img/vaporwave/8.png b/public/img/vaporwave/8.png new file mode 100644 index 0000000..9f3ca85 Binary files /dev/null and b/public/img/vaporwave/8.png differ diff --git a/public/img/vaporwave/9.png b/public/img/vaporwave/9.png new file mode 100644 index 0000000..f8c03a7 Binary files /dev/null and b/public/img/vaporwave/9.png differ diff --git a/public/js/main.js b/public/js/main.js new file mode 100644 index 0000000..5536225 --- /dev/null +++ b/public/js/main.js @@ -0,0 +1,187 @@ +document.addEventListener(`DOMContentLoaded`, e => { + handleImageGeneratorForm(); +}) + +const randomPrompts = [ + `A charming skyscraper, nightfall`, + `An intense action figure of a disruptive shrew in an empty marsh, in the golden hour.`, +] + +var generatedImage = ``; +var nextSubmitAllowedTime = 0; + +function generateRandomPrompt() { + + const sentences = [ + `_TYPE_ of _SUBJECT_ _ACTION_ _ENVIRONMENT_, _EXTRAS_`, + ] + + const types = [ + `An illustration`, + `A digital illustration`, + `A realistic illustration`, + `A artsy illustration`, + `A photograph`, + `A DSLR Picture`, + `A DSLR Photograph`, + `A digital painting`, + `A digital drawing`, + `A digital sketch`, + `A film photograph`, + ]; + + const subjects = [ + `A penguin`, + `A dog`, + `A man`, + `A woman`, + `A cat`, + `A kitten`, + `A dog`, + `A fish`, + `A squirrel`, + `A chipmunk`, + `A capybara`, + ]; + + const action = [ + `wearing a tuxedo`, + `wearing a top hat`, + `dressed with in a long skirt`, + `posing for a picture`, + `running`, + `sleeping on the left side`, + `looking at the viewer`, + `posing at the viewer`, + `posing at the viewer`, + ] + + const environments = [ + `in a green forest`, + `in a white room`, + `with an interesting background`, + `with a studio background`, + `with a realistic background`, + `with a fantasy background` + ]; + + const extras = [ + `masterpiece, masterwork, artsy, creative, imagination, (realistic:1.1)`, + `masterpiece, masterwork, artsy, creative, imagination`, + `(realistic:1.1), DSLR, picture, photograph, polaroid`, + `film photography, kodak gold, kodak, 35mm film, film picture`, + ] + + return randomItem(sentences) + .replace(/_TYPE_/g, randomItem(types)) + .replace(/_SUBJECT_/g, randomItem(subjects)) + .replace(/_ACTION_/g, randomItem(action)) + .replace(/_ENVIRONMENT_/g, randomItem(environments)) + .replace(/_EXTRAS_/g, randomItem(extras)) + +} + +function randomItem(items) { return items[Math.floor(Math.random()*items.length)]; } + +async function handleImageGeneratorForm() { + /** + * @type {HTMLFormElement} + */ + const imageGeneratorForm = document.getElementById(`image-generator`); + + if ( !!imageGeneratorForm ) { + + // Randomize the prompt as a starting point + document.getElementById(`image_description`).value = `vaporwave, (vaporwave style:1.1), synthwave, 80's, aesthetic,`; + + imageGeneratorForm.querySelector(`#random-prompt-button`).addEventListener( `click`, e => { + e.preventDefault(); + + document.getElementById(`image_description`).value = generateRandomPrompt(); + + }) + + imageGeneratorForm.querySelector(`#submit-image-button`).addEventListener( `click`, async (e) => { + + // Cancel the default post, we wills end the data to an API endpoint + e.preventDefault(); + + if ( nextSubmitAllowedTime > new Date().getTime() ) { + const s = ((nextSubmitAllowedTime - new Date().getTime()) / 1000).toFixed(1); + alert(`Please wait ${s} more seconds before trying to submit`); + return; + } + + if ( generatedImage == null || !!!generatedImage ) { + alert(`This image has already been submited`); + return; + } + + // Disable the form + imageGeneratorForm.classList.add(`loading`); + imageGeneratorForm.querySelector(`button.btn-95`).setAttribute(`disabled`, true); + + const fData = new FormData(); + fData.set(`image_data`, generatedImage); + + const response = await fetch(`/api/image/submit`, { + body: fData, + method: `POST`, + }) + .catch( err => { + alert("Something went wrong with postiong your image, please try again later."); + console.error(err); + }) + + // Enable the form + imageGeneratorForm.classList.remove(`loading`); + imageGeneratorForm.querySelector(`button.btn-95`).removeAttribute(`disabled`); + + generatedImage = null; + document.getElementById(`submit-image-button`).setAttribute(`disabled`, 123); + alert(`Your image has been submitted! Thanks for posting`); + + nextSubmitAllowedTime = new Date().getTime() + (1000 * 15); + }) + + imageGeneratorForm.addEventListener(`submit`, async (e) => { + // Cancel the default post, we wills end the data to an API endpoint + e.preventDefault(); + + // Disable the form + imageGeneratorForm.classList.add(`loading`); + imageGeneratorForm.querySelector(`button.btn-95`).setAttribute(`disabled`, true); + + const response = await fetch(`/api/image/generate`, { + body: new FormData(imageGeneratorForm), + method: `POST`, + }) + .catch( err => { + alert("Something went wrong with generating the image, please try again later."); + console.error(err); + }) + + // Enable the form + imageGeneratorForm.classList.remove(`loading`); + imageGeneratorForm.querySelector(`button.btn-95`).removeAttribute(`disabled`); + + /** + * @type {HTMLDivElement} + */ + const imageResultElement = imageGeneratorForm.querySelector(`#image-generation-result`); + const imgPlaceholder = imageResultElement.querySelector(`#tmp-img-placeholder`); + if ( !!imgPlaceholder ) { + imgPlaceholder.remove(); + } + + const r = await response.json(); + + imageResultElement.style.setProperty(`background-image`, `url('data:image/jpeg;charset=utf-8;base64,${r.images[0]}')`); + + document.getElementById(`submit-image-button`).removeAttribute(`disabled`); + + generatedImage = r.images[0]; + + }) + } +} \ No newline at end of file diff --git a/public/js/vaporwave.js b/public/js/vaporwave.js new file mode 100644 index 0000000..e69de29 diff --git a/public/main.css b/public/main.css new file mode 100644 index 0000000..e8ecd10 --- /dev/null +++ b/public/main.css @@ -0,0 +1,223 @@ +@import url("https://fonts.googleapis.com/css2?family=DotGothic16&family=Major+Mono+Display&family=Tinos:ital,wght@0,400;0,700;1,400;1,700&display=swap"); + +@import url("/public/css/buttons.css"); +@import url("/public/css/vaporwave.css"); + +*, +*:after, +*:before { + box-sizing: border-box; +} + + +body { + font-family: "DotGothic16", serif; + letter-spacing: 0.025em; + line-height: 1.5; + min-height: 100vh; + color: #393232; + background: linear-gradient(180deg, #2b1165 0%, #1a3a82 37%, #ab24b1 69%, #f54171 100%); + /* background: linear-gradient(180deg, #ab24b1 0%, #f54171 37%, #2b1165 69%, #1a3a82 100%); */ + background-color: #2b1165; + + overflow-x: hidden; +} + +img { + display: block; + max-width: 100%; +} + +article { + width: 90%; + max-width: 800px; + margin-left: auto; + margin-right: auto; + margin-top: 10vh; + margin-bottom: 10vh; + padding: 2em; + background-color: #c0c0c0; + border-left: 2px solid #eee; + border-top: 2px solid #eee; + border-right: 2px solid #444; + border-bottom: 2px solid #444; + font-size: 1rem; + position: relative; +} + +article:after { + content: "x"; + display: flex; + align-items: center; + justify-content: center; + line-height: 1; + padding-bottom: 0.25em; + position: absolute; + top: 0.75em; + right: 0.75em; + width: 1.75em; + height: 1.75em; + background-color: #c0c0c0; + border-left: 2px solid #eee; + border-top: 2px solid #eee; + border-right: 2px solid #444; + border-bottom: 2px solid #444; +} + +.headline { + font-size: 2.5em; + font-weight: 700; +} + +.subhead { + font-size: 1.25em; + margin-top: 0.25em; +} + +.article-meta { + display: flex; + flex-wrap: wrap; + flex-flow: column; + align-items: flex-start; +} + +.article-meta div:first-of-type { + margin-left: 0.75em; + font-size: 0.875em; + margin-right: auto; + padding-right: 0.75em; +} + +.article-meta div:last-of-type { + font-size: 0.875em; +} + +aside { + padding: 1em; + border-right: 1px solid #eee; + border-bottom: 1px solid #eee; + border-left: 1px solid #444; + border-top: 1px solid #444; + clear: both; +} + +.tag { + display: inline-block; + margin-right: 0.25em; + margin-top: 0.25em; + border-right: 1px solid #eee; + border-bottom: 1px solid #eee; + border-left: 1px solid #444; + border-top: 1px solid #444; + padding: 0.125em 0.375em; + text-transform: uppercase; + letter-spacing: 0.1em; +} + +h2:not(.subhead) { + font-size: 1.5em; + font-weight: 700; + padding-bottom: 0.375em; + box-shadow: 0 1px 0 0 #444, 0 2px 0 0 #eee; +} + +figure { + background-color: #c0c0c0; + box-shadow: 0 0 0 1px #eee, 0 0 0 2px #c0c0c0, 0 0 0 3px #444; + position: relative; + margin-bottom: 1.25em; + width: calc(100% + 1.5em + 2em); + + @media (min-width: 800px) { + max-width: 50%; + } +} + +figure:nth-of-type(odd) { + float: left; + margin-right: 1.5em; + margin-left: -3em; +} + +figure:nth-of-type(even) { + float: right; + margin-left: 1.5em; + margin-right: -3em; +} + +figure:after { + content: ""; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: block; + position: absolute; + background-image: linear-gradient( + to top, + rgba(#ff9100, 0.2) 0%, + rgba(#ffe630, 0.2) 60% + ), + linear-gradient(20deg, rgba(#ff0, 0.5) 0%, rgba(#ff0, 0) 35%); + box-shadow: inset 0px 0px 100px rgba(0, 0, 20, 1); + z-index: 1; +} + +figure figcaption { + font-family: "DotGothic16", monospace; + background-color: #8795e8; + box-shadow: inset 0 -1px 0 0 #020202; + color: #eee; + text-align: center; + position: absolute; + top: 0; + left: 0; + right: 0; + padding: 0.25em; + font-size: 0.875em; + z-index: 2; +} + +#image-generation-result { + border: 2px outset gray; + background-color: #c0c0c0; + padding: 2px; + margin-left: 1rem; + height: 512px; + width: 512px; + + background-size: cover; + background-position: center; + + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; +} + +.form-loader { + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + width: calc(100% - 16px); + height: 100%; + background-size: 512px; + background-position: center; + background-image: url(/public/img/gifs/loading.gif); + position: absolute; + background-repeat: no-repeat; + background-color: #c0c0c0e8; +} + +form:not(.loading) .form-loader { + display: none !important; +} + +img.vaporwave-image { + max-width: 480px; + position: absolute; + z-index: 0; +} + + diff --git a/templates/home/index.html b/templates/home/index.html new file mode 100644 index 0000000..d9d21d3 --- /dev/null +++ b/templates/home/index.html @@ -0,0 +1,130 @@ + + + + + + + + Stable Diffusion * Lightning Talk + + + + + +
+

Stable Diffusion

+

The next generation of Image Generation

+ +

+ Hey there! Thanks for hoppin' on the website, you're probably in my presentation over on zoom as well right now, + down below you will find a button to generate images which you can then send over straight into the presentation live! +

+ + + +
+
+
+
+ +
+ a smiling person in a pink hoodie, standing in front of a bright pink lighted arcade basketball game. +
Samurai Ramen
+
+

First and foremost, what sets Stable Diffusion apart is its open-source nature. This means that anyone can access and modify the code to suit their specific needs. This makes it a great option for those who are interested in tinkering with code or developing their own algorithms.

+ +

How it works

+

Now, let's talk about how most image generation algorithms work. Essentially, these algorithms use deep neural networks to generate new images based on existing ones. These networks are trained on a large dataset of images and are able to learn the patterns and features that make up a specific type of image. Once trained, the network can generate new images by altering certain parameters or inputs.

+

In the case of Stable Diffusion, the software uses a type of algorithm called a diffusion model. This model works by iteratively adding noise to an initial image, gradually making it more and more "diffused" or blurry. This process is repeated multiple times, and the resulting images are then used to generate a new image.

+

But what really sets Stable Diffusion apart is its sampler. This feature allows users to "explore" the space of possible images by generating multiple images with slightly different parameters. This means that users can easily create a wide variety of images without having to manually adjust the parameters each time.

+ +
+
Superimposed woman on cat
+
+ +

Prompts

+

Finally, let's talk about prompts. In Stable Diffusion, prompts are used to provide the algorithm with specific guidance on what type of image to generate. These prompts can be anything from a written description of the desired image to a specific set of parameters. This means that users can easily generate images that match their specific needs or interests.

+

In conclusion, Stable Diffusion is a powerful image generation software that offers a wide range of features and capabilities. Its open-source nature makes it a great option for those who are interested in developing their own algorithms, and its diffusion model and sampler make it easy to generate a wide variety of images. So if you're looking for a versatile and customizable image generation software, be sure to check out Stable Diffusion!

+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file