├── .github └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── .gitignore ├── .idea ├── .gitignore ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── LICENSE ├── PATCHNOTE.md ├── README.md ├── client ├── assets │ ├── caveat-cyrillic-ext-wght-normal.woff2 │ ├── caveat-cyrillic-wght-normal.woff2 │ ├── caveat-latin-ext-wght-normal.woff2 │ ├── caveat-latin-wght-normal.woff2 │ ├── cozy-nest-style-sdnext.css │ ├── cozy-nest-style.css │ ├── index.css │ ├── index.js │ ├── kofi-cup-border.png │ └── worker-json.js └── index.html ├── cozy-nest-client ├── .env ├── .env.production ├── .eslintrc.cjs ├── .gitignore ├── CozyNestEventBus.js ├── LICENSE ├── README.md ├── chakra │ ├── ButtonWithConfirmDialog.jsx │ ├── Checkbox.theme.ts │ ├── Input.theme.ts │ ├── Modal.theme.ts │ ├── Tabs.theme.ts │ └── chakra-theme.ts ├── cozy-prompt │ ├── App.jsx │ ├── CozyPrompt.css │ ├── main.jsx │ ├── mode-prompt.js │ ├── prompt_highlight_rules.js │ └── useExternalTextareaObserver.js ├── cozy-types.d.ts ├── cozy.build.js ├── cozy_extra_network │ ├── CozyExtraNetworks.jsx │ ├── CozyExtraNetworks.scss │ ├── ExtraNetworksCard.jsx │ ├── FolderTreeFilter.jsx │ ├── FolderTreeFilter.scss │ ├── ImageUpload.scss │ ├── ImageUploadModal.jsx │ ├── LazyComponent.jsx │ └── main.jsx ├── extra-network │ ├── ExtraNetworks.css │ ├── ExtraNetworks.jsx │ ├── LoaderContext.jsx │ └── main.jsx ├── image-browser │ ├── App.css │ ├── App.jsx │ ├── Browser.jsx │ ├── Controls.jsx │ ├── CozyImage.jsx │ ├── CozyImageInfo.jsx │ ├── CozyTags.jsx │ ├── ImagesContext.tsx │ ├── MockImageBrowser.jsx │ ├── editor │ │ ├── ExifEditor.css │ │ └── ExifEditor.jsx │ ├── index.css │ ├── index.html │ └── main.jsx ├── index.html ├── main.jsx ├── main │ ├── Constants.js │ ├── CozyLogger.js │ ├── Loading.js │ ├── SimpleTimer.js │ ├── Utils.css │ ├── Utils.jsx │ ├── _dev.js │ ├── cozy-utils.js │ ├── dom_ids.js │ ├── kofi-cup-border.png │ ├── modal │ │ ├── Modal.jsx │ │ └── Module.jsx │ ├── nevysha-cozy-nest.js │ ├── override_ui.js │ ├── svg.js │ ├── svg_for_react.jsx │ └── tweaks │ │ ├── clear-generated-image.js │ │ ├── cozy-alert.js │ │ ├── troubleshot-dialog.js │ │ └── various-tweaks.js ├── package-lock.json ├── package.json ├── settings │ ├── App.css │ ├── App.jsx │ ├── Header.jsx │ ├── OuputFolderSelector.jsx │ ├── PopoverColorPicker.jsx │ ├── main.jsx │ └── useClickOutside.js ├── static │ ├── caveat-cyrillic-ext-wght-normal.woff2 │ ├── caveat-cyrillic-wght-normal.woff2 │ ├── caveat-latin-ext-wght-normal.woff2 │ ├── caveat-latin-wght-normal.woff2 │ ├── cozy-nest-style-sdnext.css │ └── cozy-nest-style.css ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── data └── .keepme ├── javascript └── nevysha-cozy-nest.js ├── preload.py ├── screenshots ├── Screenshot 2023-05-03 100850.png ├── chrome-capture-2023-4-1 (1).png ├── chrome-capture-2023-4-1 (2).png ├── chrome-capture-2023-4-1 (3).png ├── chrome-capture-2023-4-1.gif ├── chrome-capture-2023-4-1.png ├── chrome-capture-2023-4-2 (1).png ├── chrome-capture-2023-4-2.gif └── chrome-capture-2023-4-2.png ├── scripts ├── cozy_lib │ ├── CozyLogger.py │ ├── CozyNestConfig.py │ ├── Static.py │ ├── cozy_extra_network.py │ ├── cozynest_image_browser.py │ └── tools.py └── nevysha_cozy_nest.py └── version_data.json /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Issue]: " 4 | labels: [] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! 11 | **Please include as much information as possible, including screenshots, logs, and steps to reproduce the issue.** 12 | - type: markdown 13 | attributes: 14 | value: | 15 | **Please note that Cozy-Nest is quite hacky and experimental, so it's not uncommon to see bugs and compatibility issues with others extensions.** 16 | If possible, please try to reproduce the issue with only Cozy-Nest enabled, or specify the extension having compatibility issues. 17 | - type: markdown 18 | attributes: 19 | value: | 20 | Don't forget to include the troubleshooting info. To get them, follow these steps: 21 | 1. Open Cozy-Nest 22 | 2. Click on the magic wand icon in the top right corner 23 | 3. Click the link "click here to gather relevant info" 24 | 4. Paste the screenshot bellow along with your issue description. 25 | - type: textarea 26 | id: what-happened 27 | attributes: 28 | label: What happened? 29 | description: Please include troubleshooting info from Cozy-Nest. You can paste image directly inside the form bellow. Also tell us, what did you expect to happen. 30 | placeholder: Tell us what you see! 31 | value: "A bug happened!" 32 | validations: 33 | required: true 34 | - type: dropdown 35 | id: webui 36 | attributes: 37 | label: Webui 38 | description: Which webui are you using? 39 | options: 40 | - Automatic1111's webui 41 | - SD.Next (Vlad's fork webui) 42 | validations: 43 | required: true 44 | - type: dropdown 45 | id: browsers 46 | attributes: 47 | label: What browsers are you seeing the problem on? 48 | multiple: true 49 | options: 50 | - Firefox 51 | - Chrome 52 | - Safari 53 | - Microsoft Edge 54 | - Something else (please specify) 55 | validations: 56 | required: true 57 | - type: textarea 58 | id: additional-info 59 | attributes: 60 | label: Additional info 61 | description: Please provide any additional information you think might be relevant. 62 | placeholder: ... 63 | value: "A bug happened!" 64 | validations: 65 | required: false 66 | - type: textarea 67 | id: browser-logs 68 | attributes: 69 | label: Relevant browser log output 70 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 71 | render: shell 72 | - type: textarea 73 | id: webui-logs 74 | attributes: 75 | label: Relevant log output from the webui 76 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 77 | render: shell 78 | - type: checkboxes 79 | id: terms 80 | attributes: 81 | label: Checklist 82 | description: Before submitting this issue, please make sure you've done the following 83 | options: 84 | - label: I have searched the issues to make sure this is not a duplicate 85 | required: true 86 | - label: Webui is up to date 87 | required: true 88 | - label: Cozy-Nest is up to date 89 | required: true 90 | - label: All my extensions are up to date 91 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Cozy-Nest community 4 | url: https://github.com/Nevysha/Cozy-Nest/discussions/categories/general 5 | about: Please ask and answer questions here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for Cozy-Nest 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | 6 | body: 7 | - type: textarea 8 | id: description 9 | attributes: 10 | label: Feature description 11 | description: Describe the feature in a clear and simple way 12 | value: "I would like to see..." -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cozy-Nest.iml 2 | nevyui_settings.json 3 | data/images.cache 4 | /scripts/cozy_lib/log_enabled 5 | /scripts/__pycache__/ 6 | /scripts/cozy_lib/__pycache__/ 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PATCHNOTE.md: -------------------------------------------------------------------------------- 1 | ## Compatibility 2 | 3 | - Automatic1111's webui 1.6.0 release WIP. 4 | - Not compatible with SD Next. 5 | 6 | ## Minor changes & fixes in 2.4.4 7 | - [x] wip fixes for Automatic1111's webui 1.6.0 release 8 | 9 | ## Minor changes & fixes in 2.4.3 10 | - [x] Fix for SD Next compatibility Version: 3bcca6f9 3bcca6f9 06/07/2023. 11 | - [x] Add proper warning to SD Next users if they are using incompatible style parameters. 12 | - [x] Fix CozyNest=No which was not properly disabling Cozy Nest. 13 | - [x] Various fix and optimizations. 14 | 15 | ## Minor changes & fixes in 2.4.2 16 | - [x] Sort folder tree by name 17 | - [x] Allow for preview in those format '.png', '.jpg', '.jpeg', '.webp' (it will take the most recent available) 18 | - [x] Choose between full or deferred loading for Extra Network (default to full as you need a LOT of items to see a difference) 19 | - [x] Small bug fix 20 | 21 | ## Minor changes & fixes in 2.4.1 22 | - [x] Small various fix 23 | 24 | ## New features in 2.4.0 25 | - [x] Dedicated Extra Network component more stable and faster. 26 | - [x] Compatible with Civitai Helper (and hard requirement to generate civitai.info file) 27 | - [x] Search field 28 | - [x] NSFW filter 29 | - [x] Mark as NSFW 30 | - [x] Folder tree view (toggleable) 31 | - [x] Multithread image indexer for image browser 32 | 33 | ## Minor changes & fixes in 2.3.4 34 | - [x] Compatibility with https://github.com/DominikDoom/a1111-sd-webui-tagcomplete (ctrl+space to autocomplete tags in Cozy Prompt) 35 | - [x] Synthax color in prompt for wildcard (ie: '\_\_devilkkw/body-1/eyes_iris_colors\_\_') 36 | - [x] Synthax color in prompt for attention value (':1.1', ':2.3', ...) 37 | - [x] Keybinding to increase or decrease attention value (ctrl+up, ctrl+down) 38 | 39 | ## Minor changes & fixes in 2.3.3 40 | - [x] Do not preload Extra Network tab but wait for a user click 41 | 42 | ## Minor changes & fixes in 2.3.2 43 | - [x] Fix Cozy Prompt for SD.Next compatibility 44 | 45 | ## Minor changes & fixes in 2.3.1 46 | - [x] May work in SD.Next. Cozy Prompt is disabled in SD.Next. 47 | 48 | ## New features in 2.3.0 49 | - [x] Civitai Helper and its 4 button on thumbnails should work properly. 50 | - [x] Add a "clear" button to extras gallery 51 | - [x] press escape key to close right panels 52 | - [x] Color mode (light, dark) from Cozy Nest settings 53 | - [x] Add clear button in prompt 54 | - [x] Customize caret size for prompt 55 | - [x] Color for lycoris and hypernetworks in prompt 56 | - [x] Move prompt tools button ("redo last prompt", ...) 57 | - [x] Add a secondary accent color in settings, applied to some elements (open scripts...) 58 | - [x] Reworked a lots of padding for a cleaner and more compact view 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nevysha's Cozy Nest 2 | 3 | _Find your cozy spot on Auto1111's webui_ 4 | 5 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G2L55CD) 6 | 7 | ![](https://nevysha.art/wp-content/uploads/2023/01/nevy-icon-1-256-round.png) 8 | 9 | Cozy Nest is a UI extension for Automatic's sd-webui. 10 | 11 | ## Compatibility 12 | 13 | - From Automatic1111's webui 1.6.0 release. 14 | - Not compatible with SD Next. 15 | 16 | - ![](https://placehold.co/15x15/f03c15/f03c15.png) SD Next compatibily is on standby for latest SD.Next version. But I'm in talk with Vlado for a better and deeper integration in SD.Next 17 | 18 | ## Requirements 19 | Cozy Nest rely on two others popular extensions which HAVE to be installed : 20 | - [Tag Complete](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete) 21 | - [Civitai Helper](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper) 22 | 23 | ## Features: 24 | - [x] Fully integrated Image Browser. Lots of bugs and missing features. Please be kind with Github issues. 25 | - [x] Send to txt2img / img2img / … 26 | - [x] Search 27 | - [x] Tag your images and filter by tag 28 | - [x] Edit exif metadata 29 | - [x] Archive, hide or delete images 30 | - [x] Optimized web browser memory usage for image not visible (unload them / replace with dummy div) 31 | - [x] manage new image generated 32 | - [x] Automatically get image output folder (without grid folder) 33 | - [x] Drag and drop image 34 | - [x] Multithread image indexer for fast startup after first load (~20s for 2150 images on a stock i7-9700K) 35 | - [x] Dedicated Extra Network component more stable and faster. 36 | - [x] Moved in a dedicated right slidable panel 37 | - [x] Compatible with Civitai Helper (and hard requirement to generate civitai.info file) 38 | - [x] Search field 39 | - [x] NSFW filter 40 | - [x] Mark as NSFW 41 | - [x] Folder tree view filter (toggleable) 42 | - [x] Enhanced prompt editor with color (in txt2img and img2img) - It can be disabled through settings 43 | - [x] Compatibility with https://github.com/DominikDoom/a1111-sd-webui-tagcomplete (ctrl+space to autocomplete tags in Cozy Prompt) 44 | - [x] Synthax color in prompt for wildcard (ie: '\_\_devilkkw/body-1/eyes_iris_colors\_\_') 45 | - [x] Synthax color in prompt for attention value (':1.1', ':2.3', ...) 46 | - [x] Keybinding to increase or decrease attention value (ctrl+up, ctrl+down) 47 | - [x] Resizable panels 48 | - [x] Full Screen Inpainting 49 | - [x] Enhanced Ui 50 | - [x] Customizable tab menu position (top, left, centered) 51 | - [x] Closable side panel with esc key 52 | - [x] Dark or Light theme through Cozy Nest settings 53 | - [x] Save resize bar position / panel ratio in local storage 54 | - [x] Customize font color 55 | - [x] Customize accent color 56 | - [x] Add or remove accent to the generate buttons 57 | - [x] Customize font size 58 | - [x] Setting to center the top menu tabs 59 | - [x] Setting to remove the gap between checkpoint and other quicksetting 60 | - [x] Setting to center quicksetting 61 | - [x] Loading screen with estimated percentage based on previous loading time 62 | - [x] Drag and Drop tab button inside or outside a “tab container” to bring them or move them from/out main menu 63 | - [x] Bypass Cozy Nest by adding `CozyNest=No` in URL param (ie: http://localhost:7860/?CozyNest=No) - useful for mobile 64 | - [x] Fetch version from a dedicated json file hosted directly in the repo to an easier view of update of Cozy Nest. 65 | 66 |
67 | 68 | ![](https://placehold.co/15x15/f03c15/f03c15.png) **I won't support mobile usage. Although you can use Cozy Nest on your desktop and add `CozyNest=No` in the URL when using webui from your mobile.** 69 | 70 | Tested in Chrome, should work in Firefox with minor bug. I plan to fix it later. 71 | 72 | ## Known Issue 73 | 74 | - [ ] Metadata display in image browser may display "Error parsing metadata" 75 | - [ ] Partial compatibility with Firefox and Opera GX 76 | - [ ] Most tweak will not support a live window resize (nor F11 to go fullscreen) 77 | 78 | It's made by being a bit hacky on the DOM to tweaks Gradio default features and existing css of Auto1111. It will probably break with each update of auto1111, but I'll try to keep it up to date. 79 | 80 | 81 | # Installation 82 | 1) Open your SD-Webui 83 | 2) Goto Extension Tab 84 | 3) add Extenion by pasting this URL 85 | https://github.com/Nevysha/Cozy-Nest 86 | 87 | Or search for Cozy Nest in the extension tab 88 | 89 | # Looks 90 | 91 | ![Screenshot 2023-06-24 154827](https://github.com/Nevysha/Cozy-Nest/assets/122687716/7db13230-6a27-4f16-98fd-3df84e83c8ff) 92 | ![Cozy-Prompt-Demo](https://github.com/Nevysha/Cozy-Nest/assets/122687716/af97707e-d686-45bf-a28d-08584a2a067c) 93 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-2%20(1).png?raw=true) 94 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/Screenshot%202023-05-03%20100850.png?raw=true) 95 | 96 | ## Video 97 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-1.gif?raw=true) 98 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-2.gif?raw=true) 99 | 100 | ## Screenshots 101 | 102 | ### Main look 103 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-1.png?raw=true) 104 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-1%20(1).png?raw=true) 105 | 106 | ### Resizable Panels (txt2img and img2img) 107 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-2.png?raw=true) 108 | 109 | ### Full Screen Inpainting 110 | ![](https://github.com/Nevysha/Cozy-Nest/blob/main/screenshots/chrome-capture-2023-4-1%20(3).png?raw=true) 111 | 112 | 113 | # Contribution 114 | 115 | Not allowing contribution. Pull Request will be rejected. 116 | 117 | # Licence 118 | AGPLv3 119 | 120 | Need a specific licence for integration in a commercial project ? 121 | Contact me on discord. 122 | 123 | # Credits 124 | * [DominikDoom](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete) used part of is code to retrieve valid extra networks 125 | * [anapnoe](https://github.com/anapnoe/stable-diffusion-webui-ux)'s incredible work on its fork of sd-webui 126 | * [AUTOMATIC1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui)'s work on sd-webui 127 | -------------------------------------------------------------------------------- /client/assets/caveat-cyrillic-ext-wght-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nevysha/Cozy-Nest/a7db35843d10356b347d6add4d81132afbf03e6f/client/assets/caveat-cyrillic-ext-wght-normal.woff2 -------------------------------------------------------------------------------- /client/assets/caveat-cyrillic-wght-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nevysha/Cozy-Nest/a7db35843d10356b347d6add4d81132afbf03e6f/client/assets/caveat-cyrillic-wght-normal.woff2 -------------------------------------------------------------------------------- /client/assets/caveat-latin-ext-wght-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nevysha/Cozy-Nest/a7db35843d10356b347d6add4d81132afbf03e6f/client/assets/caveat-latin-ext-wght-normal.woff2 -------------------------------------------------------------------------------- /client/assets/caveat-latin-wght-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nevysha/Cozy-Nest/a7db35843d10356b347d6add4d81132afbf03e6f/client/assets/caveat-latin-wght-normal.woff2 -------------------------------------------------------------------------------- /client/assets/cozy-nest-style-sdnext.css: -------------------------------------------------------------------------------- 1 | body { 2 | overflow: hidden !important; 3 | } 4 | 5 | .nevysha.skip-interrupt-wrapper { 6 | justify-content: space-between; 7 | } 8 | 9 | .nevysha.skip-interrupt-wrapper button { 10 | width: 50%; 11 | } 12 | 13 | #tooltip-container { 14 | margin-top: 25px; 15 | } -------------------------------------------------------------------------------- /client/assets/kofi-cup-border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nevysha/Cozy-Nest/a7db35843d10356b347d6add4d81132afbf03e6f/client/assets/kofi-cup-border.png -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite App 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /cozy-nest-client/.env: -------------------------------------------------------------------------------- 1 | VITE_CONTEXT=DEV 2 | PROMPT_LOGGING=0 -------------------------------------------------------------------------------- /cozy-nest-client/.env.production: -------------------------------------------------------------------------------- 1 | VITE_CONTEXT=PROD 2 | PROMPT_LOGGING=0 -------------------------------------------------------------------------------- /cozy-nest-client/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:react-hooks/recommended', 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | plugins: ['react-refresh'], 11 | rules: { 12 | 'react-refresh/only-export-components': 'warn', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /cozy-nest-client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /cozy-nest-client/CozyNestEventBus.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'eventemitter3'; 2 | 3 | /** 4 | * Singleton class that handles the event bus for the Cozy Nest extension. 5 | * user eventemitter3 6 | */ 7 | class CozyNestEventBus extends EventEmitter{ 8 | constructor() { 9 | super(); 10 | } 11 | } 12 | 13 | export default new CozyNestEventBus(); -------------------------------------------------------------------------------- /cozy-nest-client/README.md: -------------------------------------------------------------------------------- 1 | # Cozy Nest Client 2 | 3 | **![#f03c15](https://placehold.co/15x15/f03c15/f03c15.png) f you are looking for the Automatic1111's webui extension, please look [HERE](https://github.com/Nevysha/Cozy-Nest). This folder is for non-built source code of Cozy Nest client.** 4 | 5 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G2L55CD) 6 | 7 | ![](https://nevysha.art/wp-content/uploads/2023/01/nevy-icon-1-256-round.png) 8 | 9 | ## Installation 10 | 11 | ```bash 12 | git clone https://github.com/Nevysha/Cozy-Nest.git 13 | cd Cozy-Nest/cozy-nest-client 14 | npm install 15 | ``` 16 | 17 | ## Usage 18 | 19 | You need to have Cozy-Nest extension installed on a1111, and a1111 running. 20 | 21 | ```bash 22 | # start a1111 webui server 23 | cd Cozy-Nest/cozy-nest-client 24 | npm run dev 25 | # access client at http://localhost: 26 | ``` 27 | 28 | ## Build 29 | 30 | ```bash 31 | cd Cozy-Nest/cozy-nest-client 32 | # check output folder in vite.config.ts. It is hard coded atm. 33 | npm run build 34 | ``` -------------------------------------------------------------------------------- /cozy-nest-client/chakra/ButtonWithConfirmDialog.jsx: -------------------------------------------------------------------------------- 1 | import React, {useRef} from 'react' 2 | import {useDisclosure} from "@chakra-ui/react"; 3 | import { 4 | AlertDialog, 5 | AlertDialogBody, 6 | AlertDialogFooter, 7 | AlertDialogHeader, 8 | AlertDialogContent, 9 | AlertDialogOverlay, 10 | AlertDialogCloseButton, 11 | } from '@chakra-ui/react' 12 | import {Button} from "../image-browser/App.jsx"; 13 | 14 | export function ButtonWithConfirmDialog({message, buttonLabel, confirmLabel, cancelLabel, onConfirm, style}) { 15 | const { isOpen, onOpen, onClose } = useDisclosure() 16 | const cancelRef = useRef() 17 | 18 | const _buttonLabel = buttonLabel || confirmLabel 19 | 20 | if (style) { 21 | style = {...style, width: '100%'} 22 | } 23 | else 24 | style = {width: '100%'} 25 | 26 | return ( 27 | <> 28 | 33 | 34 | 40 | 41 | 42 | 43 | Confirm Action 44 | 45 | 46 | 47 | {message} 48 | 49 | 50 | 51 | 57 | 65 | 66 | 67 | 68 | 69 | 70 | ) 71 | } -------------------------------------------------------------------------------- /cozy-nest-client/chakra/Checkbox.theme.ts: -------------------------------------------------------------------------------- 1 | import {createMultiStyleConfigHelpers} from "@chakra-ui/react"; 2 | import {checkboxAnatomy, radioAnatomy} from "@chakra-ui/anatomy"; 3 | 4 | const { definePartsStyle, defineMultiStyleConfig } = 5 | createMultiStyleConfigHelpers(checkboxAnatomy.keys) 6 | 7 | export const checkboxTheme = defineMultiStyleConfig({ 8 | defaultProps: { 9 | variant: 'nevysha' 10 | }, 11 | variants: { nevysha: definePartsStyle({ 12 | control: { 13 | boxShadow: 'var(--input-shadow)', 14 | border: '1px solid var(--ae-input-border-color) !important', 15 | borderRadius: 'var(--checkbox-border-radius)', 16 | backgroundColor: 'var(--checkbox-background-color)', 17 | lineHeight: 'var(--line-sm)', 18 | } 19 | }) }, 20 | }) 21 | 22 | const { 23 | definePartsStyle: radioDefinePartsStyle, 24 | defineMultiStyleConfig: radioDefineMultiStyleConfig 25 | } = createMultiStyleConfigHelpers(radioAnatomy.keys); 26 | 27 | export const radioTheme = radioDefineMultiStyleConfig({ 28 | defaultProps: { 29 | variant: 'nevysha' 30 | }, 31 | variants: { nevysha: radioDefinePartsStyle({ 32 | control: { 33 | boxShadow: 'var(--input-shadow)', 34 | border: '1px solid var(--ae-input-border-color) !important', 35 | // borderRadius: 'var(--checkbox-border-radius)', 36 | backgroundColor: 'var(--checkbox-background-color)', 37 | lineHeight: 'var(--line-sm)', 38 | } 39 | }) }, 40 | }) 41 | 42 | 43 | -------------------------------------------------------------------------------- /cozy-nest-client/chakra/Input.theme.ts: -------------------------------------------------------------------------------- 1 | import {createMultiStyleConfigHelpers} from "@chakra-ui/react"; 2 | import {inputAnatomy, numberInputAnatomy} from "@chakra-ui/anatomy"; 3 | 4 | let { definePartsStyle, defineMultiStyleConfig } = 5 | createMultiStyleConfigHelpers(inputAnatomy.keys) 6 | 7 | export const inputTheme = defineMultiStyleConfig({ 8 | defaultProps: { 9 | variant: 'nevysha' 10 | }, 11 | variants: { nevysha: definePartsStyle({ 12 | field: { 13 | outline: 'none!important', 14 | boxShadow: 'var(--input-shadow)', 15 | border: '1px solid var(--ae-input-border-color) !important', 16 | borderRadius: '0 !important', 17 | backgroundColor: 'var(--input-background-fill) !important', 18 | padding: 'var(--input-padding) !important', 19 | width: '100%', 20 | color: 'var(--body-text-color)', 21 | fontSize: 'var(--input-text-size)', 22 | lineHeight: 'var(--line-sm)', 23 | fontFamily: 'monospace !important', 24 | } 25 | }) }, 26 | }) 27 | 28 | const { 29 | definePartsStyle: numberInputDefinePartsStyle, 30 | defineMultiStyleConfig: numberInputDefineMultiStyleConfig 31 | } = createMultiStyleConfigHelpers(numberInputAnatomy.keys); 32 | 33 | export const numberInputTheme = numberInputDefineMultiStyleConfig({ 34 | defaultProps: { 35 | variant: 'nevysha' 36 | }, 37 | variants: { nevysha: numberInputDefinePartsStyle({ 38 | field: { 39 | outline: 'none!important', 40 | boxShadow: 'var(--input-shadow)', 41 | border: '1px solid var(--ae-input-border-color) !important', 42 | borderRadius: '0 !important', 43 | backgroundColor: 'var(--input-background-fill) !important', 44 | padding: 'var(--input-padding) !important', 45 | width: '100%', 46 | color: 'var(--body-text-color)', 47 | fontSize: 'var(--input-text-size) !important', 48 | lineHeight: 'var(--line-sm)', 49 | fontFamily: 'monospace !important', 50 | }, 51 | stepperGroup: { 52 | border: '1px solid var(--ae-input-border-color) !important', 53 | borderTop: 'none !important', 54 | borderRight: 'none !important', 55 | }, 56 | stepper: { 57 | color: 'var(--body-text-color)', 58 | borderTop: 'none !important', 59 | borderLeft: 'none !important', 60 | } 61 | }) }, 62 | }) -------------------------------------------------------------------------------- /cozy-nest-client/chakra/Modal.theme.ts: -------------------------------------------------------------------------------- 1 | import {createMultiStyleConfigHelpers} from "@chakra-ui/react"; 2 | import {modalAnatomy} from "@chakra-ui/anatomy"; 3 | 4 | let { definePartsStyle, defineMultiStyleConfig } = 5 | createMultiStyleConfigHelpers(modalAnatomy.keys) 6 | 7 | export const modalTheme = defineMultiStyleConfig({ 8 | defaultProps: { 9 | variant: 'nevysha' 10 | }, 11 | variants: { 12 | nevysha: 13 | definePartsStyle({ 14 | dialog: { 15 | opacity: 1, 16 | width: '800px', 17 | marginRight: 'auto', 18 | marginLeft: 'auto', 19 | transform: 'none', 20 | maxWidth: 'fit-content', 21 | background: 'none', 22 | }, 23 | }), 24 | 'nevysha-confirm': 25 | definePartsStyle({ 26 | dialog: { 27 | opacity: 1, 28 | width: '800px', 29 | marginRight: 'auto', 30 | marginLeft: 'auto', 31 | transform: 'none', 32 | maxWidth: 'fit-content', 33 | border: '1px solid var(--ae-input-border-color)', 34 | backgroundColor: 'var(--block-background-fill)', 35 | color: 'var(--body-text-color)', 36 | borderRadius: '0 !important', 37 | fontSize: 'var(--body-text-size)', 38 | }, 39 | footer: { 40 | display: 'flex !important', 41 | gap: '5px', 42 | } 43 | }) 44 | }, 45 | }) -------------------------------------------------------------------------------- /cozy-nest-client/chakra/Tabs.theme.ts: -------------------------------------------------------------------------------- 1 | import {createMultiStyleConfigHelpers} from "@chakra-ui/react"; 2 | import {tabsAnatomy} from "@chakra-ui/anatomy"; 3 | 4 | const { definePartsStyle, defineMultiStyleConfig } = 5 | createMultiStyleConfigHelpers(tabsAnatomy.keys) 6 | 7 | export const tabsTheme = defineMultiStyleConfig({ 8 | defaultProps: { 9 | variant: 'nevysha' 10 | }, 11 | variants: { 12 | nevysha: definePartsStyle({ 13 | tab: { 14 | marginBottom: '-1px', 15 | border: '1px solid transparent', 16 | borderColor: 'transparent', 17 | borderBottom: 'none', 18 | borderRadius: '0 !important', 19 | padding: 'var(--size-1) var(--size-4) !important', 20 | color: 'var(--body-text-color-subdued) !important', 21 | fontWeight: 'var(--section-header-text-weight) !important', 22 | fontSize: 'var(--section-header-text-size) !important', 23 | borderTop: '2px solid transparent !important', 24 | _selected: { 25 | borderTop: '2px solid var(--ae-primary-color) !important', 26 | backgroundColor: 'var(--tab-nav-background-color-selected) !important', 27 | color: 'var(--body-text-color) !important', 28 | }, 29 | _focus: { 30 | outline: 'none' 31 | }, 32 | _hover: { 33 | outline: 'none', 34 | borderRight: '1px solid transparent', 35 | borderLeft: '1px solid transparent', 36 | } 37 | }, 38 | tabpanel: { 39 | border: '1px solid var(--border-color-primary)', 40 | borderTop: 'none', 41 | borderBottomRightRadius: 'var(--container-radius)', 42 | borderBottomLeftRadius: 'var(--container-radius)', 43 | padding: 'var(--block-padding)', 44 | backgroundColor: 'var(--tab-nav-background-color-selected) !important', 45 | gap: '20px', 46 | display: 'flex', 47 | flexDirection: 'column', 48 | height: '500px', 49 | overflowY: 'auto', 50 | } 51 | }), 52 | nevyshaExtraNetwork: definePartsStyle({ 53 | root: { 54 | height: '100% !important', 55 | display: 'flex', 56 | flexDirection: 'column' 57 | }, 58 | tabpanels: { 59 | height: '100% !important', 60 | }, 61 | tab: { 62 | marginBottom: '-1px', 63 | border: '1px solid transparent', 64 | borderColor: 'transparent', 65 | borderBottom: 'none', 66 | borderRadius: '0 !important', 67 | padding: 'var(--size-1) var(--size-4) !important', 68 | color: 'var(--body-text-color-subdued) !important', 69 | fontWeight: 'var(--section-header-text-weight) !important', 70 | fontSize: 'var(--section-header-text-size) !important', 71 | borderTop: '2px solid transparent !important', 72 | _selected: { 73 | borderTop: '2px solid var(--ae-primary-color) !important', 74 | backgroundColor: 'var(--tab-nav-background-color-selected) !important', 75 | color: 'var(--body-text-color) !important', 76 | }, 77 | _focus: { 78 | outline: 'none' 79 | }, 80 | _hover: { 81 | outline: 'none', 82 | borderRight: '1px solid transparent', 83 | borderLeft: '1px solid transparent', 84 | } 85 | }, 86 | tabpanel: { 87 | border: '1px solid var(--border-color-primary)', 88 | borderTop: 'none', 89 | borderBottomRightRadius: 'var(--container-radius)', 90 | borderBottomLeftRadius: 'var(--container-radius)', 91 | padding: 'var(--block-padding)', 92 | backgroundColor: 'var(--tab-nav-background-color-selected) !important', 93 | gap: '20px', 94 | display: 'flex', 95 | flexDirection: 'column', 96 | height: '100%', 97 | overflowY: 'auto', 98 | } 99 | }) 100 | }, 101 | }) -------------------------------------------------------------------------------- /cozy-nest-client/chakra/chakra-theme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from '@chakra-ui/react' 2 | 3 | 4 | import {inputTheme, numberInputTheme} from "./Input.theme"; 5 | import {tabsTheme} from "./Tabs.theme"; 6 | import {checkboxTheme, radioTheme} from "./Checkbox.theme"; 7 | import {modalTheme} from "./Modal.theme"; 8 | 9 | export const theme = extendTheme({ 10 | fontSizes: { 11 | md: 'var(--body-text-size)', 12 | }, 13 | components: { 14 | Input: inputTheme, 15 | Tabs: tabsTheme, 16 | Checkbox: checkboxTheme, 17 | NumberInput: numberInputTheme, 18 | Radio: radioTheme, 19 | Modal: modalTheme, 20 | }, 21 | }) -------------------------------------------------------------------------------- /cozy-nest-client/cozy-prompt/CozyPrompt.css: -------------------------------------------------------------------------------- 1 | .CozyPrompt { 2 | min-height: 100px; 3 | max-height: 800px; 4 | width: 100%; 5 | border: 1px solid var(--ae-input-border-color) !important; 6 | } 7 | 8 | .CozyPrompt .container { 9 | display: flex; 10 | flex-direction: column; 11 | width: 100%; 12 | height: 100%; 13 | } 14 | .CozyPrompt .ace_cursor-layer { 15 | z-index: 900; 16 | } 17 | .CozyPrompt .ace_cursor-layer .ace_cursor { 18 | z-index: 901; 19 | background-color: var(--ae-primary-color); 20 | position: fixed; 21 | width: 2px !important; 22 | } 23 | .CozyPrompt.bold-cursor .ace_cursor-layer .ace_cursor { 24 | width: 9px !important; 25 | } 26 | @keyframes blink-ace-animate { 27 | from, to { opacity: 0.5; } 28 | 60% { opacity: 0; } 29 | } 30 | 31 | @keyframes blink-ace-animate-smooth { 32 | from, to { opacity: 0.5; } 33 | 45% { opacity: 0.5; } 34 | 60% { opacity: 0; } 35 | 85% { opacity: 0; } 36 | } 37 | .ace_active-line { 38 | background: #ffffff0d !important; 39 | } 40 | .ace_completion-highlight { 41 | color: var(--ae-primary-color) !important; 42 | } 43 | .ace_editor.ace_autocomplete { 44 | width: 400px !important; 45 | } 46 | div.ace_editor.ace_autocomplete.ace_dark.ace-github-dark > div.ace_scroller > div > div.ace_layer.ace_text-layer > div.ace_line { 47 | display: flex !important; 48 | flex-direction: row !important; 49 | width: 380px !important; 50 | } 51 | div.ace_editor.ace_autocomplete.ace_dark.ace-github-dark > div.ace_scroller > div > div.ace_layer.ace_text-layer > div.ace_line > span.ace_completion-spacer { 52 | flex:1 !important; 53 | } 54 | .CozyPrompt { 55 | /*padding: 10px;*/ 56 | background-color: var(--input-background-fill) !important; 57 | } 58 | .CozyPrompt .ace_editor { 59 | background-color: var(--input-background-fill) !important; 60 | } 61 | .CozyPrompt .ace_scrollbar::-webkit-scrollbar { 62 | width: 5px; 63 | } 64 | .CozyPrompt .ace_scrollbar::-webkit-scrollbar-track { 65 | background-color: transparent; 66 | } 67 | .CozyPrompt .ace_scrollbar::-webkit-scrollbar-thumb { 68 | background-color: var(--ae-primary-color); 69 | border-radius: 20px; 70 | } 71 | .CozyPrompt__resize-handle { 72 | width: 100%; 73 | height: 10px; 74 | /* background-color: var(--ae-input-border-color); */ 75 | cursor: row-resize; 76 | display: flex; 77 | flex-direction: column; 78 | justify-content: center; 79 | align-items: center; 80 | margin: 2px 0; 81 | } 82 | .CozyPrompt__resize-handle-line { 83 | height: 2px; 84 | background-image: repeating-linear-gradient(to right, var(--vertical-line-bg-color) 0, var(--vertical-line-bg-color) 7px, transparent 1px, transparent 14px); 85 | background-size: 100% 13px; 86 | opacity: 0.7; 87 | width: 50%; 88 | } 89 | 90 | /*Editor color*/ 91 | .ace_text-layer { 92 | color: var(--body-text-color); 93 | font-family: monospace !important; 94 | } 95 | .ace_open-bracket, .ace_close-bracket { 96 | color: var(--ae-primary-color); 97 | font-weight: bold;; 98 | /*font-size: 1.1em;*/ 99 | } 100 | .ace_open-bracket-0, .ace_close-bracket-0 { 101 | color: violet; 102 | } 103 | .ace_open-bracket-1, .ace_close-bracket-1 { 104 | color: var(--ae-primary-color); 105 | } 106 | .ace_open-bracket-2, .ace_close-bracket-2 { 107 | color: hotpink; 108 | } 109 | .ace_open-bracket-3, .ace_close-bracket-3 { 110 | color: greenyellow; 111 | } 112 | .ace_open-bracket-4, .ace_close-bracket-4 { 113 | color: #fa662a; 114 | } 115 | .ace_token { 116 | color: #cccc96; 117 | font-weight: bold; 118 | /*margin: 0 3px;*/ 119 | } 120 | .ace_attention { 121 | color: #f35a5a; 122 | } 123 | .ace_lora-begin, .ace_lora-end, .ace_lora-inner { 124 | color: #08c2d3; 125 | } 126 | .ace_hypernetwork-begin, .ace_hypernetwork-end, .ace_hypernetwork-inner, 127 | .ace_hypernet-begin, .ace_hypernet-end, .ace_hypernet-inner { 128 | color: #ff6800; 129 | } 130 | .ace_lyco-begin, .ace_lyco-end, .ace_lyco-inner { 131 | color: #c444d5; 132 | } 133 | .ace_wildcard { 134 | color: #4cd041; 135 | font-style: italic; 136 | } 137 | .ace_lora-begin, .ace_lora-end, 138 | .ace_hypernetwork-begin, .ace_hypernetwork-end, 139 | .ace_hypernet-begin, .ace_hypernet-end, 140 | .ace_lyco-begin, .ace_lyco-end { 141 | font-weight: bold; 142 | /*font-size: 1.1em;*/ 143 | filter: brightness(1.2); 144 | } -------------------------------------------------------------------------------- /cozy-nest-client/cozy-prompt/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from 'react-dom/client' 3 | import {App} from "./App.jsx"; 4 | import {ChakraProvider} from '@chakra-ui/react' 5 | import {theme} from "../chakra/chakra-theme.ts"; 6 | 7 | export default async function startCozyPrompt(parentId, containerId, tabId) { 8 | return new Promise((resolve, reject) => { 9 | try { 10 | _startCozyPrompt(parentId, containerId, tabId, resolve); 11 | } catch (e) { 12 | reject(e); 13 | } 14 | }); 15 | } 16 | 17 | function _startCozyPrompt(parentId, containerId, tabId, resolve) { 18 | // 19 | if (!document.getElementById(parentId)) { 20 | setTimeout(() => startCozyPrompt(), 200) 21 | return 22 | } 23 | 24 | const settingsDiv = document.createElement("div"); 25 | settingsDiv.id = containerId; 26 | settingsDiv.style = 'display: flex; height: fit-content; width: 100%;' 27 | 28 | document.getElementById(parentId) 29 | .insertBefore(settingsDiv, document.getElementById(parentId).firstChild); 30 | 31 | ReactDOM.createRoot(document.getElementById(containerId)).render( 32 | 33 | 34 | 35 | 36 | , 37 | ) 38 | } -------------------------------------------------------------------------------- /cozy-nest-client/cozy-prompt/mode-prompt.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/prompt", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text"], function (require, exports, module) { 2 | const oop = require("ace/lib/oop"); 3 | const TextMode = require("ace/mode/text").Mode; 4 | const CustomHighlightRules = require("ace/mode/prompt_highlight_rules").CustomHighlightRules; 5 | 6 | // Define the CustomMode constructor 7 | function CustomMode() { 8 | this.HighlightRules = CustomHighlightRules; 9 | } 10 | 11 | // Inherit from the base TextMode 12 | oop.inherits(CustomMode, TextMode); 13 | 14 | // Set the mode's name 15 | CustomMode.prototype.$id = "ace/mode/prompt"; 16 | 17 | (function() { 18 | }).call(CustomMode.prototype); 19 | 20 | // Export the mode 21 | exports.Mode = CustomMode; 22 | }); -------------------------------------------------------------------------------- /cozy-nest-client/cozy-prompt/prompt_highlight_rules.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/prompt_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function (require, exports, module) { 2 | const oop = require("ace/lib/oop"); 3 | const TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules; 4 | 5 | // Define the CustomHighlightRules constructor 6 | function CustomHighlightRules() { 7 | // Create an instance of the base TextHighlightRules 8 | TextHighlightRules.call(this); 9 | 10 | // Define the regex patterns for different token types 11 | 12 | const openBracket = /[\(\[\{]/; 13 | const closeBracket = /[\)\]\}]/; 14 | 15 | let bracketLevel = 0; 16 | 17 | this.$rules = { 18 | start: [ 19 | { 20 | token: () => { 21 | bracketLevel++; 22 | return `open-bracket.open-bracket-${(bracketLevel) % 4}`; 23 | }, 24 | next: "inner", 25 | regex: openBracket 26 | }, 27 | { 28 | token: () => { 29 | bracketLevel--; 30 | return `close-bracket.close-bracket-${(bracketLevel+1) % 4}`; 31 | }, 32 | regex: closeBracket, 33 | next: "start" 34 | }, 35 | { regex: /', token: "lora-end", next: "start" }, 49 | { regex: /:\d+(\.\d+)?/, token: "attention" }, 50 | { regex: /\w+/, token: "lora-inner" }, 51 | ], 52 | hypernetwork: [ 53 | { regex: '>', token: "hypernetwork-end", next: "start" }, 54 | { regex: /:\d+(\.\d+)?/, token: "attention" }, 55 | { regex: /\w+/, token: "hypernetwork-inner" }, 56 | ], 57 | hypernet: [ 58 | { regex: '>', token: "hypernet-end", next: "start" }, 59 | { regex: /:\d+(\.\d+)?/, token: "attention" }, 60 | { regex: /\w+/, token: "hypernet-inner" }, 61 | ], 62 | lyco: [ 63 | { regex: '>', token: "lyco-end", next: "start" }, 64 | { regex: /:\d+(\.\d+)?/, token: "attention" }, 65 | { regex: /\w+/, token: "lyco-inner" }, 66 | ], 67 | inner: [ 68 | { 69 | token: () => { 70 | bracketLevel++; 71 | return `open-bracket.open-bracket-${(bracketLevel) % 4}`; 72 | }, 73 | regex: openBracket, 74 | next: "inner" 75 | }, 76 | { regex: /:\d+(\.\d+)?/, token: "attention" }, 77 | { regex: /[,|:]/, token: "token" }, 78 | { regex: /__.+__/, token: "wildcard" }, 79 | { regex: /\w+/, token: "inner-bracket" }, 80 | { 81 | token: () => { 82 | bracketLevel--; 83 | return `close-bracket.close-bracket-${(bracketLevel+1) % 4}`; 84 | }, 85 | regex: closeBracket, 86 | next: "start" 87 | }, 88 | ] 89 | }; 90 | } 91 | 92 | // Inherit from the base TextHighlightRules 93 | oop.inherits(CustomHighlightRules, TextHighlightRules); 94 | 95 | // Export the highlight rules 96 | exports.CustomHighlightRules = CustomHighlightRules; 97 | }); 98 | -------------------------------------------------------------------------------- /cozy-nest-client/cozy-prompt/useExternalTextareaObserver.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import {CozyLogger} from "../main/CozyLogger.js"; 3 | 4 | const useExternalTextareaObserver = (textareaSelector) => { 5 | const [value, setValue] = useState(''); 6 | 7 | useEffect(() => { 8 | const observerCallback = (mutationsList) => { 9 | for (const mutation of mutationsList) { 10 | if (mutation.type === 'attributes') { 11 | const externalTextarea = document.querySelector(textareaSelector); 12 | setValue(externalTextarea.value); 13 | } 14 | } 15 | }; 16 | 17 | const observerOptions = { 18 | attributes: true, 19 | characterData: true, 20 | childList: true, 21 | subtree: true, 22 | }; 23 | 24 | const observer = new MutationObserver(observerCallback); 25 | const externalTextarea = document.querySelector(textareaSelector); 26 | 27 | if (externalTextarea) { 28 | observer.observe(externalTextarea, observerOptions); 29 | setValue(externalTextarea.value); 30 | } 31 | 32 | return () => { 33 | observer.disconnect(); 34 | }; 35 | }, [textareaSelector]); 36 | 37 | return value; 38 | }; 39 | 40 | export default useExternalTextareaObserver; 41 | -------------------------------------------------------------------------------- /cozy-nest-client/cozy-types.d.ts: -------------------------------------------------------------------------------- 1 | // type for image 2 | export type Image = { 3 | path: string, 4 | hash: string, 5 | metadata: { 6 | date: number 7 | exif: { 8 | parameters: string, 9 | 'cozy-nest-tags'?: string 10 | 'cozy-nest-hidden'?: string 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cozy-nest-client/cozy.build.js: -------------------------------------------------------------------------------- 1 | //post build script run by Nodejs 2 | 3 | //copy cozy-nest-style.css and cozy-nest-style-sdnext.css to cozy-nest-client/assets 4 | import {copyFile, readdir, rename } from 'fs/promises'; 5 | import {join} from 'path'; 6 | import { fileURLToPath } from 'url'; 7 | import * as path from "path"; 8 | import chalk from 'chalk'; 9 | 10 | const log = console.log 11 | const relPath = (to) => path.relative(join(process.cwd(), '../'), to) 12 | 13 | log("") 14 | log( 15 | chalk.blue.bold("## "), 16 | chalk.blue("Cozy Nest post build script"), 17 | chalk.blue.bold(" ##")) 18 | 19 | const __filename = fileURLToPath(import.meta.url); 20 | const __dirname = path.dirname(__filename); 21 | 22 | const cozyNestStyleCss = join(__dirname, 'main/cozy-nest-style.css'); 23 | const cozyNestStyleSdnextCss = join(__dirname, 'main/cozy-nest-style-sdnext.css'); 24 | 25 | const cozyNestStyleCssDest = join(__dirname, '../client/assets/cozy-nest-style.css'); 26 | const cozyNestStyleSdnextCssDest = join(__dirname, '../client/assets/cozy-nest-style-sdnext.css'); 27 | 28 | const config = { 29 | folderCopy: [ 30 | { 31 | from: join(__dirname, 'static'), 32 | to: join(__dirname, '../client/assets') 33 | } 34 | ], 35 | copy: [ 36 | { 37 | from: join(__dirname, 'node_modules/ace-builds/src-noconflict/worker-json.js'), 38 | to: join(__dirname, '../client/assets/worker-json.js') 39 | }, 40 | ], 41 | // move: [ 42 | // { 43 | // from: join(__dirname, '../client/assets/cozy-nest.loader.min.js'), 44 | // to: join(__dirname, '../javascript/cozy-nest.loader.min.js') 45 | // } 46 | // ] 47 | } 48 | 49 | 50 | async function build() { 51 | 52 | config.folderCopy = config.folderCopy || []; 53 | config.copy = config.copy || []; 54 | config.move = config.move || []; 55 | 56 | // copy whole folders 57 | for (const folderCopy of config.folderCopy) { 58 | 59 | log( 60 | chalk.blue(`Copying folders`), 61 | chalk.blue.bold(` ${relPath(folderCopy.from)} → ${relPath(folderCopy.to)}`) 62 | ) 63 | 64 | // list each file in the folder 65 | const files = await readdir(folderCopy.from); 66 | for (const file of files) { 67 | // copy each file to the destination 68 | await copyFile( 69 | path.join(folderCopy.from, file), 70 | path.join(folderCopy.to, file) 71 | ); 72 | log( 73 | chalk.green(' COPY'), 74 | chalk.green.bold(` ${relPath(path.join(folderCopy.from, file))} → ${relPath(path.join(folderCopy.to, file))}`)) 75 | } 76 | } 77 | 78 | // copy files 79 | log( 80 | chalk.blue(`Copying files`)) 81 | for (const copy of config.copy) { 82 | await copyFile(copy.from, copy.to); 83 | log( 84 | chalk.green(' COPY'), 85 | chalk.green.bold(` ${relPath(copy.from)} → ${relPath(copy.to)}`)) 86 | } 87 | 88 | // move file 89 | log( 90 | chalk.blue(`Moving files`)) 91 | for (const move of config.move) { 92 | await rename(move.from, move.to); 93 | log( 94 | chalk.green(' MOVE'), 95 | chalk.green.bold(` ${relPath(move.from)} → ${relPath(move.to)}`)) 96 | } 97 | } 98 | (async () => { 99 | await build(); 100 | })(); 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /cozy-nest-client/cozy_extra_network/CozyExtraNetworks.jsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from "react"; 2 | import {useEffect} from "react"; 3 | import {Loading} from "../image-browser/App.jsx"; 4 | import {Checkbox, Tab, TabList, TabPanel, TabPanels, Tabs} from "@chakra-ui/react"; 5 | import './CozyExtraNetworks.scss' 6 | import {ExtraNetworksCard} from "./ExtraNetworksCard.jsx"; 7 | import {Column, Row, RowFullWidth} from "../main/Utils.jsx"; 8 | import {SvgForReact} from "../main/svg_for_react.jsx"; 9 | import {FolderTreeFilter} from "./FolderTreeFilter.jsx"; 10 | import {FiRefreshCcw as RefreshIcon} from "react-icons/fi"; 11 | 12 | const nevyshaScrollbar = { 13 | '&::-webkit-scrollbar': { 14 | width: '5px', 15 | }, 16 | '&::-webkit-scrollbar-track': { 17 | backgroundColor: 'transparent' 18 | }, 19 | '&::-webkit-scrollbar-thumb': { 20 | backgroundColor: 'var(--ae-primary-color)', 21 | borderRadius: '20px', 22 | }, 23 | } 24 | 25 | const indexRef = [] 26 | 27 | export function CozyExtraNetworks() { 28 | 29 | const [extraNetworks, setExtraNetworks] = React.useState([]) 30 | const [folders, setFolders] = React.useState([]) 31 | const [ready, setReady] = React.useState(false) 32 | const [fullyLoaded, setFullyLoaded] = React.useState(false) 33 | 34 | const [searchString, setSearchString] = React.useState('') 35 | const [displayFolderFilter, setDisplayFolderFilter] = React.useState({ 36 | 'models': false, 37 | }) 38 | const [nsfwFilter, setNsfwFilter] = React.useState(false) 39 | 40 | const [selectedTab, setSelectedTab] = React.useState(null) 41 | 42 | useEffect(() => { 43 | (async () => { 44 | await load() 45 | })(); 46 | }, []) 47 | 48 | const load = async () => { 49 | 50 | const endpoint = COZY_NEST_CONFIG.deferred_cozy_extra_networks_loading ? 51 | '/cozy-nest/extra_networks' : '/cozy-nest/extra_networks/full' 52 | 53 | const response = await fetch(endpoint) 54 | if (response.status !== 200) { 55 | CozyLogger.error('failed to fetch extra networks', response) 56 | return; 57 | } 58 | const _enJson = await response.json() 59 | 60 | const _displayFolderFilter = {} 61 | Object.keys(_enJson).forEach((network, index) => { 62 | network = String(network); 63 | _displayFolderFilter[network] = false 64 | }) 65 | 66 | const responseFolders = await fetch('/cozy-nest/extra_networks/folders') 67 | if (responseFolders.status !== 200) { 68 | CozyLogger.error('failed to fetch extra networks folders', responseFolders) 69 | return; 70 | } 71 | const _folders = await responseFolders.json() 72 | 73 | setFolders(_folders) 74 | setExtraNetworks(_enJson) 75 | setDisplayFolderFilter(_displayFolderFilter) 76 | setReady(true) 77 | if (!COZY_NEST_CONFIG.deferred_cozy_extra_networks_loading) { 78 | setFullyLoaded(true) 79 | } 80 | } 81 | 82 | const reload = async () => { 83 | setFolders([]) 84 | setExtraNetworks([]) 85 | setReady(false) 86 | setFullyLoaded(false) 87 | setSelectedTab(null) 88 | 89 | await load() 90 | } 91 | 92 | 93 | 94 | useEffect(() => { 95 | 96 | if (!nsfwFilter) return; 97 | if (fullyLoaded) return; 98 | 99 | setReady(false); 100 | 101 | (async () => { 102 | const response = await fetch('/cozy-nest/extra_networks/full') 103 | if (response.status === 200) { 104 | const json = await response.json() 105 | setExtraNetworks(json) 106 | setReady(true) 107 | setFullyLoaded(true) 108 | setSelectedTab(indexRef[0]) 109 | } 110 | else { 111 | CozyLogger.error('failed to fetch full extra networks info', response) 112 | } 113 | })() 114 | }, [nsfwFilter]) 115 | 116 | function buildExtraNetworks() { 117 | 118 | const EnTabs = []; 119 | const EnTabPanels = []; 120 | 121 | const style = { 122 | border: 'none', 123 | height: '100%', 124 | borderBottom: '1px solid var(--ae-input-border-color)', 125 | borderTop: '1px solid var(--tab-nav-background-color-selected)', 126 | }; 127 | 128 | Object.keys(extraNetworks).forEach((network, index) => { 129 | let tabName = String(network); 130 | indexRef.push(network) 131 | if (network === 'embeddings') { 132 | tabName = 'Textual Inversion' 133 | } 134 | EnTabs.push( 135 | {tabName} 136 | ) 137 | EnTabPanels.push( 138 | 139 |
140 | {extraNetworks[network].map((item, index) => { 141 | return ( 142 | 148 | ) 149 | })} 150 |
151 |
152 | ) 153 | }) 154 | 155 | return {EnTabs, EnTabPanels} 156 | } 157 | 158 | function onTabSelect(index) { 159 | setSelectedTab(indexRef[index]) 160 | setSelectedFolder(null) 161 | } 162 | 163 | const [selectedFolder, setSelectedFolder] = React.useState(null) 164 | function folderSelectHandler({element}) { 165 | CozyLogger.debug('folderSelectHandler', {element}) 166 | 167 | if (element.name === 'all' || !element.metadata) { 168 | setSelectedFolder(null) 169 | return 170 | } 171 | setSelectedFolder(element.metadata.path) 172 | 173 | } 174 | 175 | function changeFolderFilterForTab(selectedTabName, value) { 176 | displayFolderFilter[selectedTabName] = value 177 | setDisplayFolderFilter({...displayFolderFilter}) 178 | } 179 | 180 | const Ui = buildExtraNetworks() 181 | 182 | const hasSubFolders = folders[selectedTab] && !folders[selectedTab].empty 183 | 184 | return ( 185 |
186 | {!ready && } 187 | {ready && 188 | 189 |