обавлены новые модели стикеров и улучшения интерфейса

This commit is contained in:
kazachilo 2025-04-10 17:30:19 +03:00
parent 6acc9fb65c
commit 01f2647ecb
81 changed files with 6717 additions and 218 deletions

BIN
src/assets/emo/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
src/assets/emo/10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
src/assets/emo/11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
src/assets/emo/12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
src/assets/emo/13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/emo/14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
src/assets/emo/15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/assets/emo/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/assets/emo/17.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
src/assets/emo/18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/emo/19.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/emo/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/assets/emo/20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/emo/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
src/assets/emo/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/assets/emo/23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/emo/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/emo/25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
src/assets/emo/26.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
src/assets/emo/27.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
src/assets/emo/28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
src/assets/emo/29.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/assets/emo/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/assets/emo/30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
src/assets/emo/31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
src/assets/emo/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
src/assets/emo/33.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
src/assets/emo/34.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
src/assets/emo/35.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
src/assets/emo/36.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/assets/emo/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
src/assets/emo/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/assets/emo/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
src/assets/emo/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
src/assets/emo/8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
src/assets/emo/9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,71 @@
1) half of body, Face struggling to hold up a comically large trophy. Conveying mock pride and exhaustion - хороший стабильный результат
2) half of body, clutching a giant plush teddy bear to their chest. Conveying comfort and fondness - хороший стабильный результат
3) half of body looks with adoration at the perfect single rose, which it gracefully holds in its hand. An expression of romance and appreciation - хороший стабильный результат
4) half of body, With a cup of warm tea in his hands, his face looks wery tired, clean face - хороший стабильный результат кроме детей
5) upper half of body, target to face, holding a beautifully wrapped gift box. Conveying anticipation or excitement - хороший стабильный результат
6) Half body. Facelooking contentedly at a small bouquet of flowers. Conveying joy and appreciation - хороший стабильный результат
7) Half body. Face covering their mouth in a silent scream face is expressing surprise and shock - хороший стабильный результат
8) Full body. Face wearing headphones and dancing enthusiastically. Not looking at the camera. Conveying joy and freedom - хороший стабильный результат
9) Full body. Face looking nervous while holding a microphone at a karaoke, not looking at the camera. Conveying nervousness and anxiety before starting singing - хороший стабильный результат
10) half body, make a green bloody zombie, wery angry with a cup of coffee in his hands - хороший стабильный результат
11) full body, homeless sitting in the trash. torn dirty clothes - хороший стабильный результат
12) half body, Make hulk head, maximum anger, green skin - очень хороший но редко не стабильный результат
13) half body, focus to head, holds out one mug of beer at arm's length to the viewer - хороший почти всегда стабильный результат
14) half body, fully clothed, laughs so hard going to cry - хороший результат но очень разнообразный
15) half body, fully clothed, shakes one fist holding it out to the viewer - хороший реузльтат на мужчинах, на женщинах не самый стабильный
16) half body, fully clothed, boxing, holding his hands in a protective position near his head - хороший стабильный результат
17) Half of body, full face, holding a tiny kitten with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets - хороший стабильный результат
18) Half of body, full face, holding a tiny puppy with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets - хороший стабильный результат
19) Full body, wearing a bright superhero cape while trying to make a dramatic entrance but tripping over. Conveying a mix of confidence and clumsiness - не плохой результат
20) Half of body, face scrunched up in delight, holding an ice cream cone thats too big to handle. Conveying carefree joy and summer vibes- хороший стабильный результат
21) Half body, dressed as a wizard, conjuring colorful sparks from a magic wand, with a look of intense concentration. Conveying magic and wonder - хороший стабильный результат
22) Half of the body, with big dragon wings on its back and fiery breath, looked surprised, holding a tiny dragon egg in its hands - хороший стабильный результат
23) Half body, fully clothed, in a cyberpunk outfit with neon lights - стабильно хорошо
24) Half of body, wearing a cloak and holding a glowing spellbook, surrounded by floating magical runes, looking determined - супер стабильный результат
25) Half of body, as a pirate captain with a parrot on the shoulder - стабильный результат
26) Half of body, dressed as a cybernetic samurai with a glowing katana, clear face - не плохой результат
27) Half of body, dressed as a mad scientist with wild hair, looking excitedly - очень стабильный результат
28) Half of body, elegantly dressed, holding a glittering glass of red wine, eyes sparkling with delight, as if savoring a fine vintage - очень стабильный результат
29) half body, greets by raising onlu one hand up - достаточно стабильно
30) Half of body, with both hands raised high in a classic “thumbs up” gesture, wearing a bright smile that expresses confidence and positivity - очень стабильно
31) Half body, holding a big heart in both hands, eyes shining with love and joy - крайне стабильный результат
32) Half body, focus on face, turned into a thick green slime, Green slime underfoot, The body is green slime. Green slime on the head
33) full body, focus on face, A man is riding a horse. horse in iron armor war
34) half body, a man made of fire, body on fire, fire on his head, very angry, hands clenched into fists
35) Half of body, vividly dressed as Doctor Strange, with his iconic cloak billowing dramatically behind him. He is holding a swirling, glowing portal with one hand, while intricate magical symbols and runes surround him. His expression is focused and determined as he channels mystical energy, creating a mesmerizing vibrant portal that seems to shimmer with colors of blue and purple
36) half body, Captain America

View File

@ -35,6 +35,44 @@ import shieldIcon from './shield-icon.png';
import reactLogo from './react.svg';
import tokenIcon from './token_ico.png';
// Импорты изображений для эмоций
import emoTrophy from './emo/1.png';
import emoTeddyBear from './emo/2.png';
import emoRose from './emo/3.png';
import emoTea from './emo/4.png';
import emoGift from './emo/5.png';
import emoFlowers from './emo/6.png';
import emoShock from './emo/7.png';
import emoDance from './emo/8.png';
import emoKaraoke from './emo/9.png';
import emoZombie from './emo/10.png';
import emoHomeless from './emo/11.png';
import emoHulk from './emo/12.png';
import emoBeer from './emo/13.png';
import emoLaugh from './emo/14.png';
import emoThreat from './emo/15.png';
import emoBoxing from './emo/16.png';
import emoKitten from './emo/17.png';
import emoPuppy from './emo/18.png';
import emoSuperhero from './emo/19.png';
import emoIceCream from './emo/20.png';
import emoWizard from './emo/21.png';
import emoDragon from './emo/22.png';
import emoCyberpunk from './emo/23.png';
import emoMage from './emo/24.png';
import emoPirate from './emo/25.png';
import emoSamurai from './emo/26.png';
import emoScientist from './emo/27.png';
import emoWine from './emo/28.png';
import emoGreeting from './emo/29.png';
import emoThumbsUp from './emo/30.png';
import emoHeart from './emo/31.png';
import emoSlime from './emo/32.png';
import emoRider from './emo/33.png';
import emoFire from './emo/34.png';
import emoDrStrange from './emo/35.png';
import emoCaptainAmerica from './emo/36.png';
export const images = {
ahareBot,
faq,
@ -71,5 +109,43 @@ export const images = {
defaultAvatar,
shieldIcon,
reactLogo,
tokenIcon
tokenIcon,
// Изображения для эмоций
emoTrophy,
emoTeddyBear,
emoRose,
emoTea,
emoGift,
emoFlowers,
emoShock,
emoDance,
emoKaraoke,
emoZombie,
emoHomeless,
emoHulk,
emoBeer,
emoLaugh,
emoThreat,
emoBoxing,
emoKitten,
emoPuppy,
emoSuperhero,
emoIceCream,
emoWizard,
emoDragon,
emoCyberpunk,
emoMage,
emoPirate,
emoSamurai,
emoScientist,
emoWine,
emoGreeting,
emoThumbsUp,
emoHeart,
emoSlime,
emoRider,
emoFire,
emoDrStrange,
emoCaptainAmerica
};

BIN
src/assets/meme/10_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/assets/meme/1_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
src/assets/meme/2_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/meme/3_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
src/assets/meme/4_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
src/assets/meme/5_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/meme/6_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
src/assets/meme/7_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/meme/8_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
src/assets/meme/9_250x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

72
src/assets/memes.ts Normal file
View File

@ -0,0 +1,72 @@
// Интерфейс для данных мема
export interface MemeData {
id: string;
name: string;
description: string;
thumbnailUrl: string;
// base64 будет добавлен позже
}
// Список мемов
export const memes: MemeData[] = [
{
id: 'meme1',
name: 'Мем 1',
description: 'Описание мема 1',
thumbnailUrl: '/src/assets/meme/1_250x.png'
},
{
id: 'meme2',
name: 'Мем 2',
description: 'Описание мема 2',
thumbnailUrl: '/src/assets/meme/2_250x.png'
},
{
id: 'meme3',
name: 'Мем 3',
description: 'Описание мема 3',
thumbnailUrl: '/src/assets/meme/3_250x.png'
},
{
id: 'meme4',
name: 'Мем 4',
description: 'Описание мема 4',
thumbnailUrl: '/src/assets/meme/4_250x.png'
},
{
id: 'meme5',
name: 'Мем 5',
description: 'Описание мема 5',
thumbnailUrl: '/src/assets/meme/5_250x.png'
},
{
id: 'meme6',
name: 'Мем 6',
description: 'Описание мема 6',
thumbnailUrl: '/src/assets/meme/6_250x.png'
},
{
id: 'meme7',
name: 'Мем 7',
description: 'Описание мема 7',
thumbnailUrl: '/src/assets/meme/7_250x.png'
},
{
id: 'meme8',
name: 'Мем 8',
description: 'Описание мема 8',
thumbnailUrl: '/src/assets/meme/8_250x.png'
},
{
id: 'meme9',
name: 'Мем 9',
description: 'Описание мема 9',
thumbnailUrl: '/src/assets/meme/9_250x.png'
},
{
id: 'meme10',
name: 'Мем 10',
description: 'Описание мема 10',
thumbnailUrl: '/src/assets/meme/10_250x.png'
}
];

View File

@ -1,4 +1,5 @@
export const prompts: Record<string, string> = {
// Промпты для стиля "чиби"
'chibi-sportscar': 'riding in a sports car',
'chibi-skateboard': 'Riding a skateboard with the wind in the hair',
'chibi-coffee': 'Drinking coffee from a cup and smiling',
@ -21,5 +22,43 @@ export const prompts: Record<string, string> = {
'chibi-knight': 'Dressed as a knight',
'chibi-ballerina': 'Dressed as a ballerina',
'chibi-firefighter': 'Dressed as a firefighter',
'chibi-chef': 'Dressed as a chef'
'chibi-chef': 'Dressed as a chef',
// Промпты для стиля "Эмоции" (подраздел "промпты")
'emotions-trophy': 'half of body, Face struggling to hold up a comically large trophy. Conveying mock pride and exhaustion',
'emotions-teddybear': 'half of body, clutching a giant plush teddy bear to their chest. Conveying comfort and fondness',
'emotions-rose': 'half of body looks with adoration at the perfect single rose, which it gracefully holds in its hand. An expression of romance and appreciation',
'emotions-tea': 'half of body, With a cup of warm tea in his hands, his face looks wery tired, clean face',
'emotions-gift': 'upper half of body, target to face, holding a beautifully wrapped gift box. Conveying anticipation or excitement',
'emotions-flowers': 'Half body. Facelooking contentedly at a small bouquet of flowers. Conveying joy and appreciation',
'emotions-shock': 'Half body. Face covering their mouth in a silent scream face is expressing surprise and shock',
'emotions-dance': 'Full body. Face wearing headphones and dancing enthusiastically. Not looking at the camera. Conveying joy and freedom',
'emotions-karaoke': 'Full body. Face looking nervous while holding a microphone at a karaoke, not looking at the camera. Conveying nervousness and anxiety before starting singing',
'emotions-zombie': 'half body, make a green bloody zombie, wery angry with a cup of coffee in his hands',
'emotions-homeless': 'full body, homeless sitting in the trash. torn dirty clothes',
'emotions-hulk': 'half body, Make hulk head, maximum anger, green skin',
'emotions-beer': 'half body, focus to head, holds out one mug of beer at arms length to the viewer',
'emotions-laugh': 'half body, fully clothed, laughs so hard going to cry',
'emotions-threat': 'half body, fully clothed, shakes one fist holding it out to the viewer',
'emotions-boxing': 'half body, fully clothed, boxing, holding his hands in a protective position near his head',
'emotions-kitten': 'Half of body, full face, holding a tiny kitten with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets',
'emotions-puppy': 'Half of body, full face, holding a tiny puppy with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets',
'emotions-superhero': 'Full body, wearing a bright superhero cape while trying to make a dramatic entrance but tripping over. Conveying a mix of confidence and clumsiness',
'emotions-icecream': 'Half of body, face scrunched up in delight, holding an ice cream cone that is too big to handle. Conveying carefree joy and summer vibes',
'emotions-wizard': 'Half body, dressed as a wizard, conjuring colorful sparks from a magic wand, with a look of intense concentration. Conveying magic and wonder',
'emotions-dragon': 'Half of the body, with big dragon wings on its back and fiery breath, looked surprised, holding a tiny dragon egg in its hands',
'emotions-cyberpunk': 'Half body, fully clothed, in a cyberpunk outfit with neon lights',
'emotions-mage': 'Half of body, wearing a cloak and holding a glowing spellbook, surrounded by floating magical runes, looking determined',
'emotions-pirate': 'Half of body, as a pirate captain with a parrot on the shoulder',
'emotions-samurai': 'Half of body, dressed as a cybernetic samurai with a glowing katana, clear face',
'emotions-scientist': 'Half of body, dressed as a mad scientist with wild hair, looking excitedly',
'emotions-wine': 'Half of body, elegantly dressed, holding a glittering glass of red wine, eyes sparkling with delight, as if savoring a fine vintage',
'emotions-greeting': 'half body, greets by raising onlu one hand up',
'emotions-thumbsup': 'Half of body, with both hands raised high in a classic "thumbs up" gesture, wearing a bright smile that expresses confidence and positivity',
'emotions-heart': 'Half body, holding a big heart in both hands, eyes shining with love and joy',
'emotions-slime': 'Half body, focus on face, turned into a thick green slime, Green slime underfoot, The body is green slime. Green slime on the head',
'emotions-rider': 'full body, focus on face, A man is riding a horse. horse in iron armor war',
'emotions-fire': 'half body, a man made of fire, body on fire, fire on his head, very angry, hands clenched into fists',
'emotions-drstrange': 'Half of body, vividly dressed as Doctor Strange, with his iconic cloak billowing dramatically behind him. He is holding a swirling, glowing portal with one hand, while intricate magical symbols and runes surround him. His expression is focused and determined as he channels mystical energy, creating a mesmerizing vibrant portal that seems to shimmer with colors of blue and purple',
'emotions-captainamerica': 'half body, Captain America'
};

View File

@ -2,6 +2,8 @@ import React from 'react';
import { Block, ButtonBlock, DividerBlock as DividerBlockType, TextInputBlock as TextInputBlockType, GenerateButtonBlock, StepTitleBlock } from '../../types/blocks';
import ScrollableButtonsBlock from './ScrollableButtonsBlock';
import GridButtonsBlock from './GridButtonsBlock';
import GenderSelectionButtons from './GenderSelectionButtons';
import EmotionTypeButtons from './EmotionTypeButtons';
import UploadPhotoBlock from './UploadPhotoBlock';
import DividerBlock from './DividerBlock';
import TextInputBlock from './TextInputBlock';
@ -23,6 +25,14 @@ const BlockRenderer: React.FC<BlockRendererProps> = ({ block, onAction, extraPro
if (block.type === 'scrollableButtons') {
return <ScrollableButtonsBlock block={buttonBlock} onAction={onAction} selectedButtonId={selectedButtonId} />;
}
// Используем специальный компонент для блока выбора пола
if (block.id === 'genderSelection') {
return <GenderSelectionButtons block={buttonBlock} onAction={onAction} selectedButtonId={selectedButtonId} />;
}
// Используем специальный компонент для блока выбора типа эмоций
if (block.id === 'emotionTypeSelection') {
return <EmotionTypeButtons block={buttonBlock} onAction={onAction} selectedButtonId={selectedButtonId} />;
}
return <GridButtonsBlock block={buttonBlock} onAction={onAction} isInputVisible={extraProps?.visible} selectedButtonId={selectedButtonId} />;
case 'uploadPhoto':
return <UploadPhotoBlock

View File

@ -0,0 +1,66 @@
/* Стили для блока выбора типа эмоций */
.emotionTypeContainer {
width: 100%;
box-sizing: border-box;
}
.emotionTypeGrid {
display: grid;
width: 100%;
gap: 8px;
grid-template-columns: repeat(2, 1fr); /* Две колонки вместо трех */
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
.emotionButtonWrapper {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
padding: 0;
margin: 0;
min-height: 44px; /* Минимальная высота для кнопки */
}
/* Стили для кнопок выбора типа эмоций */
.emotionButton {
position: relative;
border: none;
border-radius: var(--border-radius);
padding: var(--spacing-small);
cursor: pointer;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: all 0.2s ease-in-out;
text-align: center;
background-color: #E0E0E0; /* Нейтральный цвет фона */
color: var(--color-text);
width: 100%;
height: 100%;
}
/* Стиль для выбранной кнопки */
.emotionButtonSelected {
background-color: var(--color-primary);
color: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.emotionButtonTitle {
font-weight: 600;
font-size: 1rem;
line-height: 1.2;
margin: 0;
text-align: center;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 2px;
}

View File

@ -0,0 +1,47 @@
import React from 'react';
import { ButtonBlock } from '../../types/blocks';
import styles from './EmotionTypeButtons.module.css';
interface EmotionTypeButtonsProps {
block: ButtonBlock;
onAction?: (actionType: string, actionValue: string, blockId?: string, buttonId?: string) => void;
selectedButtonId?: string;
}
const EmotionTypeButtons: React.FC<EmotionTypeButtonsProps> = ({ block, onAction, selectedButtonId }) => {
const { buttons, style } = block;
const { gap = 8, padding = "4px 16px 16px" } = style;
return (
<div
className={styles.emotionTypeContainer}
style={{ padding }}
>
<div
className={styles.emotionTypeGrid}
style={{ gap }}
>
{buttons.map((button) => (
<div
key={button.id}
className={styles.emotionButtonWrapper}
>
<button
className={`${styles.emotionButton} ${selectedButtonId === button.id ? styles.emotionButtonSelected : ''}`}
onClick={() => {
if (button.action && onAction) {
onAction(button.action.type, button.action.value, block.id, button.id);
}
}}
disabled={button.disabled}
>
<span className={styles.emotionButtonTitle}>{button.title}</span>
</button>
</div>
))}
</div>
</div>
);
};
export default EmotionTypeButtons;

View File

@ -0,0 +1,66 @@
/* Стили для блока выбора пола */
.genderSelectionContainer {
width: 100%;
box-sizing: border-box;
}
.genderSelectionGrid {
display: grid;
width: 100%;
gap: 8px;
grid-template-columns: repeat(3, 1fr);
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
.genderButtonWrapper {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
padding: 0;
margin: 0;
min-height: 44px; /* Минимальная высота для кнопки */
}
/* Стили для кнопок выбора пола */
.genderButton {
position: relative;
border: none;
border-radius: var(--border-radius);
padding: var(--spacing-small);
cursor: pointer;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: all 0.2s ease-in-out;
text-align: center;
background-color: #E0E0E0; /* Нейтральный цвет фона */
color: var(--color-text);
width: 100%;
height: 100%;
}
/* Стиль для выбранной кнопки */
.genderButtonSelected {
background-color: var(--color-primary);
color: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.genderButtonTitle {
font-weight: 600;
font-size: 1rem;
line-height: 1.2;
margin: 0;
text-align: center;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 2px;
}

View File

@ -0,0 +1,47 @@
import React from 'react';
import { ButtonBlock } from '../../types/blocks';
import styles from './GenderSelectionButtons.module.css';
interface GenderSelectionButtonsProps {
block: ButtonBlock;
onAction?: (actionType: string, actionValue: string, blockId?: string, buttonId?: string) => void;
selectedButtonId?: string;
}
const GenderSelectionButtons: React.FC<GenderSelectionButtonsProps> = ({ block, onAction, selectedButtonId }) => {
const { buttons, style } = block;
const { gap = 8, padding = "4px 16px 16px" } = style;
return (
<div
className={styles.genderSelectionContainer}
style={{ padding }}
>
<div
className={styles.genderSelectionGrid}
style={{ gap }}
>
{buttons.map((button) => (
<div
key={button.id}
className={styles.genderButtonWrapper}
>
<button
className={`${styles.genderButton} ${selectedButtonId === button.id ? styles.genderButtonSelected : ''}`}
onClick={() => {
if (button.action && onAction) {
onAction(button.action.type, button.action.value, block.id, button.id);
}
}}
disabled={button.disabled}
>
<span className={styles.genderButtonTitle}>{button.title}</span>
</button>
</div>
))}
</div>
</div>
);
};
export default GenderSelectionButtons;

View File

@ -8,7 +8,7 @@
display: flex;
flex-direction: column;
position: relative;
padding-bottom: 48px; /* Место для кнопки */
padding-bottom: 64px; /* Увеличенное место для кнопки */
}
.grid {
@ -107,7 +107,7 @@
}
.grid.expanded {
max-height: 1200px; /* Увеличенная высота для всех кнопок */
max-height: 2000px; /* Увеличенная высота для всех кнопок */
}
/* Добавляем тень при наведении на весь блок */

View File

@ -47,26 +47,56 @@
white-space: pre-line;
}
.promptContainer {
background-color: var(--color-border);
border-radius: var(--border-radius);
padding: var(--spacing-small);
.generationPreview {
width: 100%;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: var(--spacing-medium);
max-height: 100px;
overflow-y: auto;
border-radius: var(--border-radius);
overflow: hidden;
background-color: var(--color-border);
position: relative;
}
.promptLabel {
font-size: 12px;
font-weight: 600;
margin-bottom: 4px;
color: var(--color-text-secondary);
.generatedImage {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.promptText {
font-size: 12px;
word-break: break-word;
font-family: monospace;
.magicRipple {
width: 130px;
height: 130px;
border-radius: 50%;
background: radial-gradient(circle, var(--color-primary) 0%, transparent 70%);
animation: ripple 2s infinite ease-in-out;
}
.generationText {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
font-size: 16px;
font-weight: 500;
color: var(--color-text);
}
@keyframes ripple {
0% {
transform: scale(0.8);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.5;
}
100% {
transform: scale(0.8);
opacity: 1;
}
}
.buttons {

View File

@ -6,7 +6,6 @@ interface NotificationModalProps {
title: string;
message: string;
isLoading?: boolean;
promptText?: string;
onGalleryClick: () => void;
onContinueClick: () => void;
showGalleryButton?: boolean; // Параметр для управления видимостью кнопки "В галерею"
@ -14,6 +13,10 @@ interface NotificationModalProps {
continueButtonText?: string; // Новый параметр для изменения текста кнопки "Продолжить"
galleryButtonText?: string; // Новый параметр для изменения текста кнопки "В галерею"
isPrimaryGalleryButton?: boolean; // Новый параметр для управления стилем кнопки "В галерею"
taskId?: string; // ID задачи генерации
generatedImageUrl?: string; // URL сгенерированного изображения
isGenerating?: boolean; // Флаг, указывающий, что идет генерация
queuePosition?: number; // Позиция в очереди
}
const NotificationModal: React.FC<NotificationModalProps> = ({
@ -21,14 +24,17 @@ const NotificationModal: React.FC<NotificationModalProps> = ({
title,
message,
isLoading = false,
promptText,
onGalleryClick,
onContinueClick,
showGalleryButton = true, // По умолчанию кнопка "В галерею" видима
showButtons = true, // По умолчанию все кнопки видимы
continueButtonText = 'Продолжить', // По умолчанию текст кнопки "Продолжить"
galleryButtonText = 'В галерею', // По умолчанию текст кнопки "В галерею"
isPrimaryGalleryButton = true // По умолчанию кнопка "В галерею" синяя
isPrimaryGalleryButton = true, // По умолчанию кнопка "В галерею" синяя
taskId,
generatedImageUrl,
isGenerating = false,
queuePosition
}) => {
if (!isVisible) return null;
@ -43,10 +49,18 @@ const NotificationModal: React.FC<NotificationModalProps> = ({
<div className={styles.message}>{message}</div>
</div>
{promptText && (
<div className={styles.promptContainer}>
<div className={styles.promptLabel}>Использованный промпт:</div>
<div className={styles.promptText}>{promptText}</div>
{isGenerating && queuePosition !== undefined && queuePosition <= 2 && (
<div className={styles.generationPreview}>
{generatedImageUrl ? (
<img src={generatedImageUrl} alt="Сгенерированный стикер" className={styles.generatedImage} />
) : (
<>
<div className={styles.magicRipple}>
{/* Анимация магической ряби */}
</div>
<div className={styles.generationText}>Генерация...</div>
</>
)}
</div>
)}

View File

@ -74,7 +74,58 @@ export const homeScreenConfig: AppConfig = {
type: 'uploadPhoto',
id: 'photoUpload',
style: {
padding: "4px 16px 16px"
padding: "4px 16px 8px"
}
},
{
type: 'gridButtons',
id: 'genderSelection',
buttons: [
{
id: 'auto',
type: 'square',
background: {
type: 'color',
colors: ['#E0E0E0']
},
title: 'Авто',
action: {
type: 'selectGenderDetection',
value: 'auto'
}
},
{
id: 'man',
type: 'square',
background: {
type: 'color',
colors: ['#E0E0E0']
},
title: 'Мужчина',
action: {
type: 'selectGender',
value: 'man'
}
},
{
id: 'woman',
type: 'square',
background: {
type: 'color',
colors: ['#E0E0E0']
},
title: 'Женщина',
action: {
type: 'selectGender',
value: 'woman'
}
}
],
style: {
gap: 8,
padding: "4px 16px 16px",
buttonSize: 100,
columns: 3
}
},
{
@ -87,6 +138,20 @@ export const homeScreenConfig: AppConfig = {
type: 'scrollableButtons',
id: 'styleActions',
buttons: [
{
id: 'emotions',
type: 'square',
background: {
type: 'gradient',
colors: ['#2B9CFF', '#1E88E5']
},
title: 'Эмоции',
imageUrl: images.emotions,
action: {
type: 'selectStyle',
value: 'emotions'
}
},
{
id: 'chibi',
type: 'square',
@ -101,21 +166,6 @@ export const homeScreenConfig: AppConfig = {
value: 'chibi'
}
},
{
id: 'emotions',
type: 'square',
background: {
type: 'gradient',
colors: ['#2B9CFF', '#1E88E5']
},
title: 'Эмоции',
imageUrl: images.emotions,
action: {
type: 'selectStyle',
value: 'emotions'
},
disabled: true
},
{
id: 'realism',
type: 'square',
@ -145,31 +195,210 @@ export const homeScreenConfig: AppConfig = {
text: 'Выбери образ'
},
{
type: 'textInput',
id: 'customPrompt',
type: 'gridButtons',
id: 'emotionTypeSelection',
buttons: [
{
id: 'prompts',
type: 'square',
background: {
type: 'gradient',
colors: ['#2B9CFF', '#1E88E5']
},
title: 'Коллекция',
action: {
type: 'selectEmotionType',
value: 'prompts'
}
},
{
id: 'memes',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Мемы',
action: {
type: 'selectEmotionType',
value: 'memes'
}
}
],
style: {
padding: "4px 16px 16px"
gap: 8,
padding: "4px 16px 16px",
buttonSize: 100,
columns: 2
}
},
{
type: 'gridButtons',
id: 'memeSelection',
buttons: [
{
id: 'meme1',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Мем 1',
imageUrl: '/src/assets/meme/1_250x.png',
action: {
type: 'selectMeme',
value: 'meme1'
}
},
{
id: 'meme2',
type: 'square',
background: {
type: 'gradient',
colors: ['#2B9CFF', '#1E88E5']
},
title: 'Мем 2',
imageUrl: '/src/assets/meme/2_250x.png',
action: {
type: 'selectMeme',
value: 'meme2'
}
},
{
id: 'meme3',
type: 'square',
background: {
type: 'gradient',
colors: ['#4CAF50', '#45A049']
},
title: 'Мем 3',
imageUrl: '/src/assets/meme/3_250x.png',
action: {
type: 'selectMeme',
value: 'meme3'
}
},
{
id: 'meme4',
type: 'square',
background: {
type: 'gradient',
colors: ['#9C27B0', '#7B1FA2']
},
title: 'Мем 4',
imageUrl: '/src/assets/meme/4_250x.png',
action: {
type: 'selectMeme',
value: 'meme4'
}
},
{
id: 'meme5',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF5722', '#F4511E']
},
title: 'Мем 5',
imageUrl: '/src/assets/meme/5_250x.png',
action: {
type: 'selectMeme',
value: 'meme5'
}
},
{
id: 'meme6',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF9800', '#FB8C00']
},
title: 'Мем 6',
imageUrl: '/src/assets/meme/6_250x.png',
action: {
type: 'selectMeme',
value: 'meme6'
}
},
{
id: 'meme7',
type: 'square',
background: {
type: 'gradient',
colors: ['#607D8B', '#455A64']
},
title: 'Мем 7',
imageUrl: '/src/assets/meme/7_250x.png',
action: {
type: 'selectMeme',
value: 'meme7'
}
},
{
id: 'meme8',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Мем 8',
imageUrl: '/src/assets/meme/8_250x.png',
action: {
type: 'selectMeme',
value: 'meme8'
}
},
{
id: 'meme9',
type: 'square',
background: {
type: 'gradient',
colors: ['#009688', '#00796B']
},
title: 'Мем 9',
imageUrl: '/src/assets/meme/9_250x.png',
action: {
type: 'selectMeme',
value: 'meme9'
}
},
{
id: 'meme10',
type: 'square',
background: {
type: 'gradient',
colors: ['#673AB7', '#512DA8']
},
title: 'Мем 10',
imageUrl: '/src/assets/meme/10_250x.png',
action: {
type: 'selectMeme',
value: 'meme10'
}
}
],
style: {
gap: 8,
padding: "4px 16px 16px",
buttonSize: 100,
columns: 3
}
},
{
type: 'gridButtons',
id: 'emotionPromptsSelection',
buttons: [],
style: {
gap: 8,
padding: "4px 16px 16px",
buttonSize: 100,
columns: 3
}
},
{
type: 'gridButtons',
id: 'quickActions',
buttons: [
{
id: 'customPrompt',
type: 'square',
background: {
type: 'gradient',
colors: ['#2196F3', '#1976D2']
},
title: 'Свой промпт',
imageUrl: images.prompt,
action: {
type: 'function',
value: 'toggleInput'
}
}
],
buttons: [],
style: {
gap: 8,
padding: "4px 8px 16px",

View File

@ -480,144 +480,510 @@ export const stylePresets: StylePresets = {
},
emotions: {
buttons: [
// Базовые эмоции (отсортированы в начале)
{
id: 'emotions-happy',
id: 'emotions-greeting',
type: 'square',
background: {
type: 'gradient',
colors: ['#FFD700', '#FFA500']
colors: ['#4CAF50', '#45A049']
},
title: 'Радость',
icon: '😊',
title: 'Привет',
imageUrl: images.emoGreeting,
action: {
type: 'selectPreset',
value: 'happy'
value: 'greeting'
}
},
{
id: 'emotions-sad',
id: 'emotions-thumbsup',
type: 'square',
background: {
type: 'gradient',
colors: ['#2196F3', '#1976D2']
},
title: 'Грусть',
icon: '😢',
title: 'Класс',
imageUrl: images.emoThumbsUp,
action: {
type: 'selectPreset',
value: 'sad'
value: 'thumbsup'
}
},
{
id: 'emotions-angry',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF5722', '#F4511E']
},
title: 'Злость',
icon: '😠',
action: {
type: 'selectPreset',
value: 'angry'
}
},
{
id: 'emotions-love',
id: 'emotions-heart',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Любовь',
icon: '❤️',
title: 'Сердце',
imageUrl: images.emoHeart,
action: {
type: 'selectPreset',
value: 'love'
value: 'heart'
}
},
{
id: 'emotions-surprise',
id: 'emotions-laugh',
type: 'square',
background: {
type: 'gradient',
colors: ['#FFD700', '#FFA500']
},
title: 'Смех',
imageUrl: images.emoLaugh,
action: {
type: 'selectPreset',
value: 'laugh'
}
},
{
id: 'emotions-shock',
type: 'square',
background: {
type: 'gradient',
colors: ['#9C27B0', '#7B1FA2']
},
title: 'Удивление',
icon: '😲',
title: 'Шок',
imageUrl: images.emoShock,
action: {
type: 'selectPreset',
value: 'surprise'
value: 'shock'
}
},
{
id: 'emotions-fear',
id: 'emotions-threat',
type: 'square',
background: {
type: 'gradient',
colors: ['#607D8B', '#455A64']
colors: ['#FF5722', '#F4511E']
},
title: 'Страх',
icon: '😱',
title: 'Угроза',
imageUrl: images.emoThreat,
action: {
type: 'selectPreset',
value: 'fear'
value: 'threat'
}
},
{
id: 'emotions-sleepy',
type: 'square',
background: {
type: 'gradient',
colors: ['#9575CD', '#7E57C2']
},
title: 'Сонный',
icon: '😴',
action: {
type: 'selectPreset',
value: 'sleepy'
}
},
{
id: 'emotions-cool',
type: 'square',
background: {
type: 'gradient',
colors: ['#212121', '#000000']
},
title: 'Крутой',
icon: '😎',
action: {
type: 'selectPreset',
value: 'cool'
}
},
{
id: 'emotions-silly',
id: 'emotions-hulk',
type: 'square',
background: {
type: 'gradient',
colors: ['#4CAF50', '#2E7D32']
},
title: 'Глупый',
icon: '🤪',
title: 'Халк',
imageUrl: images.emoHulk,
action: {
type: 'selectPreset',
value: 'silly'
value: 'hulk'
}
},
{
id: 'emotions-thinking',
id: 'emotions-fire',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF5722', '#F4511E']
},
title: 'Огонь',
imageUrl: images.emoFire,
action: {
type: 'selectPreset',
value: 'fire'
}
},
{
id: 'emotions-tea',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Чай',
imageUrl: images.emoTea,
action: {
type: 'selectPreset',
value: 'tea'
}
},
{
id: 'emotions-dance',
type: 'square',
background: {
type: 'gradient',
colors: ['#9575CD', '#7E57C2']
},
title: 'Танец',
imageUrl: images.emoDance,
action: {
type: 'selectPreset',
value: 'dance'
}
},
// Остальные эмоции
{
id: 'emotions-trophy',
type: 'square',
background: {
type: 'gradient',
colors: ['#FFD700', '#FFA500']
},
title: 'Трофей',
imageUrl: images.emoTrophy,
action: {
type: 'selectPreset',
value: 'trophy'
}
},
{
id: 'emotions-teddybear',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Мишка',
imageUrl: images.emoTeddyBear,
action: {
type: 'selectPreset',
value: 'teddybear'
}
},
{
id: 'emotions-rose',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Роза',
imageUrl: images.emoRose,
action: {
type: 'selectPreset',
value: 'rose'
}
},
{
id: 'emotions-gift',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Подарок',
imageUrl: images.emoGift,
action: {
type: 'selectPreset',
value: 'gift'
}
},
{
id: 'emotions-flowers',
type: 'square',
background: {
type: 'gradient',
colors: ['#4CAF50', '#45A049']
},
title: 'Букет',
imageUrl: images.emoFlowers,
action: {
type: 'selectPreset',
value: 'flowers'
}
},
{
id: 'emotions-karaoke',
type: 'square',
background: {
type: 'gradient',
colors: ['#9C27B0', '#7B1FA2']
},
title: 'Караоке',
imageUrl: images.emoKaraoke,
action: {
type: 'selectPreset',
value: 'karaoke'
}
},
{
id: 'emotions-zombie',
type: 'square',
background: {
type: 'gradient',
colors: ['#4CAF50', '#2E7D32']
},
title: 'Зомби',
imageUrl: images.emoZombie,
action: {
type: 'selectPreset',
value: 'zombie'
}
},
{
id: 'emotions-homeless',
type: 'square',
background: {
type: 'gradient',
colors: ['#607D8B', '#455A64']
},
title: 'Бездомный',
imageUrl: images.emoHomeless,
action: {
type: 'selectPreset',
value: 'homeless'
}
},
{
id: 'emotions-beer',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF9800', '#F57C00']
},
title: 'Думающий',
icon: '🤔',
title: 'Пиво',
imageUrl: images.emoBeer,
action: {
type: 'selectPreset',
value: 'thinking'
value: 'beer'
}
},
{
id: 'emotions-boxing',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF5722', '#F4511E']
},
title: 'Бокс',
imageUrl: images.emoBoxing,
action: {
type: 'selectPreset',
value: 'boxing'
}
},
{
id: 'emotions-kitten',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF69B4', '#FF1493']
},
title: 'Котёнок',
imageUrl: images.emoKitten,
action: {
type: 'selectPreset',
value: 'kitten'
}
},
{
id: 'emotions-puppy',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Щенок',
imageUrl: images.emoPuppy,
action: {
type: 'selectPreset',
value: 'puppy'
}
},
{
id: 'emotions-superhero',
type: 'square',
background: {
type: 'gradient',
colors: ['#3F51B5', '#303F9F']
},
title: 'Супергерой',
imageUrl: images.emoSuperhero,
action: {
type: 'selectPreset',
value: 'superhero'
}
},
{
id: 'emotions-icecream',
type: 'square',
background: {
type: 'gradient',
colors: ['#00BCD4', '#0097A7']
},
title: 'Мороженое',
imageUrl: images.emoIceCream,
action: {
type: 'selectPreset',
value: 'icecream'
}
},
{
id: 'emotions-wizard',
type: 'square',
background: {
type: 'gradient',
colors: ['#9C27B0', '#7B1FA2']
},
title: 'Волшебник',
imageUrl: images.emoWizard,
action: {
type: 'selectPreset',
value: 'wizard'
}
},
{
id: 'emotions-dragon',
type: 'square',
background: {
type: 'gradient',
colors: ['#FF5722', '#F4511E']
},
title: 'Дракон',
imageUrl: images.emoDragon,
action: {
type: 'selectPreset',
value: 'dragon'
}
},
{
id: 'emotions-cyberpunk',
type: 'square',
background: {
type: 'gradient',
colors: ['#212121', '#000000']
},
title: 'Киберпанк',
imageUrl: images.emoCyberpunk,
action: {
type: 'selectPreset',
value: 'cyberpunk'
}
},
{
id: 'emotions-mage',
type: 'square',
background: {
type: 'gradient',
colors: ['#3F51B5', '#303F9F']
},
title: 'Маг',
imageUrl: images.emoMage,
action: {
type: 'selectPreset',
value: 'mage'
}
},
{
id: 'emotions-pirate',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Пират',
imageUrl: images.emoPirate,
action: {
type: 'selectPreset',
value: 'pirate'
}
},
{
id: 'emotions-samurai',
type: 'square',
background: {
type: 'gradient',
colors: ['#212121', '#000000']
},
title: 'Самурай',
imageUrl: images.emoSamurai,
action: {
type: 'selectPreset',
value: 'samurai'
}
},
{
id: 'emotions-scientist',
type: 'square',
background: {
type: 'gradient',
colors: ['#607D8B', '#455A64']
},
title: 'Учёный',
imageUrl: images.emoScientist,
action: {
type: 'selectPreset',
value: 'scientist'
}
},
{
id: 'emotions-wine',
type: 'square',
background: {
type: 'gradient',
colors: ['#9C27B0', '#7B1FA2']
},
title: 'Вино',
imageUrl: images.emoWine,
action: {
type: 'selectPreset',
value: 'wine'
}
},
{
id: 'emotions-slime',
type: 'square',
background: {
type: 'gradient',
colors: ['#4CAF50', '#2E7D32']
},
title: 'Слизь',
imageUrl: images.emoSlime,
action: {
type: 'selectPreset',
value: 'slime'
}
},
{
id: 'emotions-rider',
type: 'square',
background: {
type: 'gradient',
colors: ['#795548', '#5D4037']
},
title: 'Всадник',
imageUrl: images.emoRider,
action: {
type: 'selectPreset',
value: 'rider'
}
},
{
id: 'emotions-drstrange',
type: 'square',
background: {
type: 'gradient',
colors: ['#3F51B5', '#303F9F']
},
title: 'Доктор Стрэндж',
imageUrl: images.emoDrStrange,
action: {
type: 'selectPreset',
value: 'drstrange'
}
},
{
id: 'emotions-captainamerica',
type: 'square',
background: {
type: 'gradient',
colors: ['#3F51B5', '#303F9F']
},
title: 'Капитан Америка',
imageUrl: images.emoCaptainAmerica,
action: {
type: 'selectPreset',
value: 'captainamerica'
}
}
]

View File

@ -0,0 +1,637 @@
// Воркфлоу для стиля Chibi с выбором пола
export const chibiWorkflow = {
"305": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"307": {
"inputs": {
"share_norm": "both",
"share_attn": "q+k",
"scale": 0.7000000000000001,
"model": [
"309",
0
]
},
"class_type": "StyleAlignedBatchAlign",
"_meta": {
"title": "StyleAligned Batch Align"
}
},
"308": {
"inputs": {
"text_positive": "Stickerchibi:2,Flat:1.5,(full body:2,Simple details(Empty Background:2",
"text_negative": "Realism, photo-realism, real materials(full body:2",
"style": "sai-cinematic",
"log_prompt": false,
"style_positive": true,
"style_negative": true
},
"class_type": "SDXLPromptStyler",
"_meta": {
"title": "SDXL Prompt Styler"
}
},
"309": {
"inputs": {
"b1": 1.3,
"b2": 1.4000000000000001,
"s1": 0.9,
"s2": 0.2,
"model": [
"406",
0
]
},
"class_type": "FreeU_V2",
"_meta": {
"title": "FreeU_V2"
}
},
"312": {
"inputs": {
"text": [
"308",
1
],
"clip": [
"406",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"313": {
"inputs": {
"prompt_1": "Boxers, with red boxing gloves, swinging their fists",
"prompt_2": "Dressed in a Superman costume",
"prompt_3": "Dress up as Santa Claus with a rattle in your hand",
"prompt_4": "Holding a bouquet of roses in his hand and wearing a gown",
"prompt_5": "Dressed in a wide hip hop suit,Playing the guitar,tattooingdenimstreet dancedancing",
"simple_prompt_list": [
"316",
0
]
},
"class_type": "CR Simple Prompt List",
"_meta": {
"title": "CR Simple Prompt List (Legacy)"
}
},
"314": {
"inputs": {
"keyframe_interval": 1,
"loops": 1,
"transition_type": "Default",
"transition_speed": "Default",
"transition_profile": "Default",
"keyframe_format": "Deforum",
"simple_prompt_list": [
"313",
0
]
},
"class_type": "CR Simple Prompt List Keyframes",
"_meta": {
"title": "CR Simple Prompt List Keyframes (Legacy)"
}
},
"316": {
"inputs": {
"prompt_1": "military clothes",
"prompt_2": "Pirate captain with a sword",
"prompt_3": "Drinking coffee from a coffee cup and smiling",
"prompt_4": "Dressed in a spacesuit and wearing a glass helmet",
"prompt_5": "Wearing luxurious clothes, holding a red heart-shaped balloon and smiling"
},
"class_type": "CR Simple Prompt List",
"_meta": {
"title": "CR Simple Prompt List (Legacy)"
}
},
"318": {
"inputs": {},
"class_type": "Anything Everywhere3",
"_meta": {
"title": "Anything Everywhere3"
}
},
"326": {
"inputs": {
"image": "photo_2025-02-03_14-06-19.jpg",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"328": {
"inputs": {
"seed": [
"404",
0
],
"steps": 7,
"cfg": 2,
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"347",
0
],
"positive": [
"339",
0
],
"negative": [
"312",
0
],
"latent_image": [
"348",
0
],
"optional_vae": [
"305",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"339": {
"inputs": {
"text": [
"314",
0
],
"max_frames": 10,
"print_output": false,
"pre_text": [
"308",
0
],
"app_text": [
"523",
0
],
"start_frame": 0,
"end_frame": 0,
"clip": [
"406",
1
]
},
"class_type": "BatchPromptSchedule",
"_meta": {
"title": "Batch Prompt Schedule 📅🅕🅝"
}
},
"344": {
"inputs": {
"pulid_file": "ip-adapter_pulid_sdxl_fp16.safetensors"
},
"class_type": "PulidModelLoader",
"_meta": {
"title": "Load PuLID Model"
}
},
"345": {
"inputs": {
"provider": "CUDA"
},
"class_type": "PulidInsightFaceLoader",
"_meta": {
"title": "Load InsightFace (PuLID)"
}
},
"346": {
"inputs": {},
"class_type": "PulidEvaClipLoader",
"_meta": {
"title": "Load Eva Clip (PuLID)"
}
},
"347": {
"inputs": {
"method": "fidelity",
"weight": 1,
"start_at": 0,
"end_at": 1,
"model": [
"307",
0
],
"pulid": [
"344",
0
],
"eva_clip": [
"346",
0
],
"face_analysis": [
"345",
0
],
"image": [
"384",
0
]
},
"class_type": "ApplyPulid",
"_meta": {
"title": "Apply PuLID"
}
},
"348": {
"inputs": {
"width": 768,
"height": 768,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"377",
0
],
"image": [
"378",
5
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"377": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"378": {
"inputs": {
"seed": [
"404",
0
],
"steps": 6,
"cfg": 2,
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
"denoise": 0.6,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"382",
0
],
"positive": [
"382",
1
],
"negative": [
"382",
2
],
"latent_image": [
"417",
0
],
"optional_vae": [
"305",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"381": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"382": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"381",
0
],
"control_net": [
"380",
0
],
"image": [
"384",
0
],
"model": [
"307",
0
],
"positive": [
"328",
1
],
"negative": [
"328",
2
],
"image_kps": [
"328",
5
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"384": {
"inputs": {
"side_length": 512,
"side": "Longest",
"upscale_method": "nearest-exact",
"crop": "disabled",
"image": [
"563",
0
]
},
"class_type": "DF_Image_scale_to_side",
"_meta": {
"title": "Image scale to side"
}
},
"404": {
"inputs": {
"seed": 0
},
"class_type": "Seed Everywhere",
"_meta": {
"title": "Seed Everywhere"
}
},
"405": {
"inputs": {
"toggle": true,
"mode": "simple",
"num_loras": 3,
"lora_1_name": "StickersRedmond.safetensors",
"lora_1_strength": 1,
"lora_1_model_strength": 2,
"lora_1_clip_strength": 2,
"lora_2_name": "cartoon_style.pt",
"lora_2_strength": 2,
"lora_2_model_strength": 1,
"lora_2_clip_strength": 1,
"lora_3_name": "smiling.pt",
"lora_3_strength": 2,
"lora_3_model_strength": 2,
"lora_3_clip_strength": 1,
"lora_4_name": "None",
"lora_4_strength": 1,
"lora_4_model_strength": 1,
"lora_4_clip_strength": 1,
"lora_5_name": "None",
"lora_5_strength": 1,
"lora_5_model_strength": 1,
"lora_5_clip_strength": 1,
"lora_6_name": "None",
"lora_6_strength": 1,
"lora_6_model_strength": 1,
"lora_6_clip_strength": 1,
"lora_7_name": "None",
"lora_7_strength": 1,
"lora_7_model_strength": 1,
"lora_7_clip_strength": 1,
"lora_8_name": "None",
"lora_8_strength": 1,
"lora_8_model_strength": 1,
"lora_8_clip_strength": 1,
"lora_9_name": "None",
"lora_9_strength": 1,
"lora_9_model_strength": 1,
"lora_9_clip_strength": 1,
"lora_10_name": "None",
"lora_10_strength": 1,
"lora_10_model_strength": 1,
"lora_10_clip_strength": 1
},
"class_type": "easy loraStack",
"_meta": {
"title": "EasyLoraStack"
}
},
"406": {
"inputs": {
"model": [
"305",
0
],
"clip": [
"305",
1
],
"lora_stack": [
"405",
0
]
},
"class_type": "CR Apply LoRA Stack",
"_meta": {
"title": "💊 CR Apply LoRA Stack"
}
},
"417": {
"inputs": {
"upscale_method": "nearest-exact",
"width": 1024,
"height": 1024,
"crop": "disabled",
"samples": [
"328",
3
]
},
"class_type": "LatentUpscale",
"_meta": {
"title": "Увеличить латент"
}
},
"523": {
"inputs": {
"text": [
"564",
0
]
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"555",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"555": {
"inputs": {
"width": 762,
"height": 762,
"method": "lanczos",
"images": [
"563",
0
]
},
"class_type": "ImageTransformResizeAbsolute",
"_meta": {
"title": "ImageTransformResizeAbsolute"
}
},
"556": {
"inputs": {
"images": [
"555",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Предварительный просмотр изображения"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"564": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"565",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"565": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
};

View File

@ -0,0 +1,30 @@
// Типы воркфлоу
export enum WorkflowType {
CHIBI = 'chibi',
PROMPT = 'prompt',
MEME = 'meme'
}
// Импорт воркфлоу
import { chibiWorkflow } from './chibiWorkflow';
import { promptWorkflow } from './promptWorkflow';
import { memeWorkflow } from './memeWorkflow';
// Функция для получения воркфлоу по типу
export const getWorkflowByType = (type: WorkflowType) => {
switch (type) {
case WorkflowType.CHIBI:
return chibiWorkflow;
case WorkflowType.PROMPT:
return promptWorkflow;
case WorkflowType.MEME:
return memeWorkflow;
default:
return chibiWorkflow; // По умолчанию возвращаем chibi
}
};
// Экспорт всех воркфлоу
export { chibiWorkflow } from './chibiWorkflow';
export { promptWorkflow } from './promptWorkflow';
export { memeWorkflow } from './memeWorkflow';

View File

@ -0,0 +1,581 @@
// Воркфлоу для нового стиля с мемами
export const memeWorkflow = {
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"606",
0
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "man"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 698459364937105,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 711685301954594,
"steps": 10,
"cfg": 4,
"sampler_name": "euler",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp, kawaii style, Anime style"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": "half body, simple T-shirt"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 0.9,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"608",
0
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"603": {
"inputs": {
"image": "Patrick Bateman Ou.png",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "face"
}
},
"606": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0.01,
"src_ratio": 1,
"sample_ratio": 0.8,
"sample_parts": "OnlyExpression",
"crop_factor": 1.7,
"src_image": [
"567",
5
],
"sample_image": [
"603",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"608": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0,
"src_ratio": 1,
"sample_ratio": 1,
"sample_parts": "All",
"crop_factor": 1.7000000000000002,
"src_image": [
"566",
5
],
"sample_image": [
"603",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "man"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
};

View File

@ -0,0 +1,558 @@
// Воркфлоу для нового стиля с промптами
export const promptWorkflow = {
"326": {
"inputs": {
"image": "girl2.png",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"606",
0
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "girl"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 866300843763550,
"steps": 10,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 378971921426134,
"steps": 10,
"cfg": 4,
"sampler_name": "euler",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated, naked"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 1,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"566",
5
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": "Half of body, full face, holding a tiny capybara with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"587": {
"inputs": {
"filename_prefix": "ComfyUI"
},
"class_type": "SaveImage",
"_meta": {
"title": "Сохранить изображение"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"606": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0,
"src_ratio": 1,
"sample_ratio": 1,
"sample_parts": "OnlyExpression",
"crop_factor": 1.7,
"src_image": [
"567",
5
],
"sample_image": [
"566",
5
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "women"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
};

View File

@ -12,7 +12,7 @@
display: flex;
flex-direction: column;
gap: var(--spacing-large);
padding: calc(3rem + var(--spacing-small)) var(--spacing-medium) calc(6rem + var(--safe-area-inset-bottom));
padding: calc(3rem + var(--spacing-small)) var(--spacing-medium) calc(10rem + var(--safe-area-inset-bottom));
width: 100%;
box-sizing: border-box;
overflow-y: auto;
@ -242,3 +242,43 @@
margin: 0;
font-size: 0.8rem;
}
/* Стили для фиксированной кнопки "Создать стикерпак" */
.createButtonFixed {
/* Размеры и отступы как у кнопки генерации */
padding: 16px;
height: auto;
line-height: normal;
/* Размер шрифта как у кнопки генерации */
font-size: 18px;
font-weight: 600;
/* Фиксируем кнопку внизу экрана */
position: fixed;
bottom: calc(6rem + var(--safe-area-inset-bottom)); /* Увеличенный отступ от навигации */
left: var(--spacing-medium);
right: var(--spacing-medium);
width: auto; /* Вместо width: 100% */
max-width: calc(28rem - 2 * var(--spacing-medium)); /* Соответствует ширине контейнера */
margin: 0 auto; /* Центрирование */
transform: none; /* Убираем transform: translateX(-50%) */
z-index: 100; /* Увеличиваем z-index */
/* Остальные стили */
background-color: var(--color-primary);
color: white;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
transition: transform 0.2s;
text-align: center;
}
.createButtonFixed:hover {
transform: translateY(-1px); /* Исправляем hover эффект */
}
.createButtonFixed:active {
transform: translateY(1px); /* Исправляем active эффект */
}

View File

@ -1,4 +1,5 @@
import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './Gallery.module.css';
import apiService from '../services/api';
import { GeneratedImage, PendingTask } from '../types/api';
@ -7,6 +8,7 @@ import ImageWithFallback from '../components/shared/ImageWithFallback';
import NotificationModal from '../components/shared/NotificationModal';
const GalleryScreen: React.FC = () => {
const navigate = useNavigate();
const [images, setImages] = useState<GeneratedImage[]>([]);
const [pendingTasks, setPendingTasks] = useState<PendingTask[]>([]);
const [loading, setLoading] = useState(true);
@ -81,6 +83,11 @@ const GalleryScreen: React.FC = () => {
setSelectedForDelete(null);
}, []);
// Обработчик для кнопки "Создать стикерпак"
const handleCreateStickerPack = useCallback(() => {
navigate('/create-sticker-pack');
}, [navigate]);
// Обработчик клика по контейнеру для выхода из режима удаления
const handleGridClick = useCallback((e: React.MouseEvent) => {
// Проверяем, что клик был не по крестику удаления
@ -353,6 +360,16 @@ const GalleryScreen: React.FC = () => {
onGalleryClick={() => setSelectedForDelete(null)}
isPrimaryGalleryButton={false}
/>
{/* Кнопка "Создать стикерпак" */}
{!loading && !error && images.length > 0 && !isDeleteMode && (
<button
className={styles.createButtonFixed}
onClick={handleCreateStickerPack}
>
Создать стикерпак
</button>
)}
</div>
);
};

View File

@ -13,6 +13,7 @@ import { tokenPacks } from '../constants/tokenPacks';
import { getCurrentUserId } from '../constants/user';
import { useBalance } from '../contexts/BalanceContext';
import { sendTargetEvent } from '../services/analyticsService';
import { WorkflowType } from '../constants/workflows';
// Интерфейс для хранения данных о последней генерации
interface LastGenerationData {
@ -39,17 +40,26 @@ const Home: React.FC = () => {
return state?.imageData || localStorage.getItem('stickerImageData') || undefined;
});
const [isInputVisible, setIsInputVisible] = useState(false);
const [selectedStyle, setSelectedStyle] = useState<string>('chibi'); // По умолчанию выбран первый стиль
const [selectedStyleButtonId, setSelectedStyleButtonId] = useState<string | undefined>('chibi'); // Для хранения ID выбранной кнопки стиля
const [selectedStyle, setSelectedStyle] = useState<string>('emotions'); // По умолчанию выбран стиль "Эмоции"
const [selectedStyleButtonId, setSelectedStyleButtonId] = useState<string | undefined>('emotions'); // Для хранения ID выбранной кнопки стиля
const [selectedPresetId, setSelectedPresetId] = useState<string | undefined>(undefined); // Для хранения ID выбранного пресета
const [customPrompt, setCustomPrompt] = useState<string>(''); // Для хранения пользовательского промпта
// Состояния для выбора типа эмоций и мема
const [selectedEmotionType, setSelectedEmotionType] = useState<'memes' | 'prompts' | undefined>('prompts'); // По умолчанию выбран тип "Промпты"
const [selectedEmotionTypeButtonId, setSelectedEmotionTypeButtonId] = useState<string | undefined>('prompts'); // Для хранения ID выбранной кнопки типа эмоций
const [selectedMemeId, setSelectedMemeId] = useState<string | undefined>(undefined); // Для хранения ID выбранного мема
// Состояния для выбора пола
const [genderDetection, setGenderDetection] = useState<'auto' | 'manual'>('auto'); // По умолчанию автоматическое определение пола
const [manualGender, setManualGender] = useState<'man' | 'woman' | undefined>(undefined); // Для хранения выбранного пола
const [selectedGenderButtonId, setSelectedGenderButtonId] = useState<string | undefined>('auto'); // Для хранения ID выбранной кнопки пола
// Состояния для модального окна уведомления
const [isNotificationVisible, setIsNotificationVisible] = useState(false);
const [notificationTitle, setNotificationTitle] = useState('');
const [notificationMessage, setNotificationMessage] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [promptText, setPromptText] = useState('');
const [showGalleryButton, setShowGalleryButton] = useState(true);
const [showButtons, setShowButtons] = useState(true);
const [continueButtonText, setContinueButtonText] = useState('Продолжить');
@ -58,6 +68,20 @@ const Home: React.FC = () => {
const [missingTokens, setMissingTokens] = useState(0);
const [lastPurchasedPack, setLastPurchasedPack] = useState<any>(null);
// Новые состояния для отслеживания задачи генерации и изображения
const [currentTaskId, setCurrentTaskId] = useState<string | undefined>(undefined);
const [generatedImageUrl, setGeneratedImageUrl] = useState<string | undefined>(undefined);
const [checkInterval, setCheckInterval] = useState<number | null>(null);
const [queuePosition, setQueuePosition] = useState<number | undefined>(undefined);
// Состояния для отслеживания изображений
const [imagesCheckInterval, setImagesCheckInterval] = useState<number | null>(null);
// Используем useRef вместо useState для хранения начальных значений
// Это позволит избежать проблемы с асинхронным обновлением состояний
const initialImagesCountRef = useRef<number>(0);
const initialImageIdsRef = useRef<string[]>([]);
// Обработчики для модального окна
const handleGalleryClick = useCallback(() => {
setIsNotificationVisible(false);
@ -68,6 +92,34 @@ const Home: React.FC = () => {
setIsNotificationVisible(false);
}, []);
// Функция для проверки новых изображений
const checkForNewImages = useCallback(async () => {
try {
// Получаем текущий список изображений
const images = await apiService.getGeneratedImages();
// Проверяем, увеличилось ли количество изображений
if (images.length > initialImagesCountRef.current) {
// Если количество изображений увеличилось, проверяем, что первое изображение действительно новое
const latestImage = images[0];
const isNewImage = !initialImageIdsRef.current.includes(latestImage.link);
if (isNewImage) {
// Устанавливаем URL изображения только если это действительно новое изображение
setGeneratedImageUrl(latestImage.url);
// Очищаем интервал, так как изображение найдено
if (imagesCheckInterval) {
clearInterval(imagesCheckInterval);
setImagesCheckInterval(null);
}
}
}
} catch (error) {
console.error('Ошибка при проверке новых изображений:', error);
}
}, [imagesCheckInterval]);
const handleBlockAction = useCallback(async (actionType: string, actionValue: string, blockId?: string, buttonId?: string) => {
if (actionType === 'selectStyle') {
// Обработка выбора стиля
@ -81,6 +133,49 @@ const Home: React.FC = () => {
// Обработка выбора пресета
setSelectedPresetId(buttonId);
console.log('Selected preset:', actionValue, 'Button ID:', buttonId);
// Если выбран пресет, отличный от "Свой промпт", скрываем поле ввода текста
if (buttonId !== 'customPrompt') {
setIsInputVisible(false);
}
return;
}
if (actionType === 'selectGenderDetection') {
// Обработка выбора способа определения пола
setGenderDetection('auto');
setManualGender(undefined);
setSelectedGenderButtonId(buttonId);
console.log('Selected gender detection:', actionValue, 'Button ID:', buttonId);
return;
}
if (actionType === 'selectGender') {
// Обработка выбора пола
setGenderDetection('manual');
setManualGender(actionValue as 'man' | 'woman');
setSelectedGenderButtonId(buttonId);
console.log('Selected gender:', actionValue, 'Button ID:', buttonId);
return;
}
if (actionType === 'selectEmotionType') {
// Обработка выбора типа эмоций
setSelectedEmotionType(actionValue as 'memes' | 'prompts');
setSelectedEmotionTypeButtonId(buttonId);
// Сбрасываем выбранный мем или пресет при смене типа
setSelectedMemeId(undefined);
setSelectedPresetId(undefined);
console.log('Selected emotion type:', actionValue, 'Button ID:', buttonId);
return;
}
if (actionType === 'selectMeme') {
// Обработка выбора мема
setSelectedMemeId(buttonId);
setSelectedPresetId(buttonId); // Используем тот же ID для совместимости с существующей логикой
console.log('Selected meme:', actionValue, 'Button ID:', buttonId);
return;
}
@ -94,6 +189,8 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была запущена
setShowButtons(true); // Показываем кнопки
setContinueButtonText('Закрыть'); // Устанавливаем текст кнопки "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи, чтобы не отображалась анимация
setQueuePosition(undefined); // Сбрасываем позицию в очереди
setIsNotificationVisible(true);
return;
}
@ -106,6 +203,8 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была запущена
setShowButtons(true); // Показываем кнопки
setContinueButtonText('Закрыть'); // Устанавливаем текст кнопки "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи, чтобы не отображалась анимация
setQueuePosition(undefined); // Сбрасываем позицию в очереди
setIsNotificationVisible(true);
return;
}
@ -118,6 +217,8 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была запущена
setShowButtons(true); // Показываем кнопки
setContinueButtonText('Закрыть'); // Устанавливаем текст кнопки "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи, чтобы не отображалась анимация
setQueuePosition(undefined); // Сбрасываем позицию в очереди
setIsNotificationVisible(true);
return;
}
@ -154,6 +255,8 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была запущена
setShowButtons(true); // Показываем кнопки
setContinueButtonText('Закрыть'); // Устанавливаем текст кнопки "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи, чтобы не отображалась анимация
setQueuePosition(undefined); // Сбрасываем позицию в очереди
setIsNotificationVisible(true);
return;
}
@ -169,11 +272,22 @@ const Home: React.FC = () => {
return;
}
// Показываем уведомление о начале генерации
// Получаем текущий список изображений перед генерацией
try {
const currentImages = await apiService.getGeneratedImages();
// Используем ref вместо состояний для мгновенного обновления
initialImagesCountRef.current = currentImages.length;
initialImageIdsRef.current = currentImages.map(img => img.link);
} catch (error) {
console.error('Ошибка при получении списка изображений:', error);
// Продолжаем генерацию даже при ошибке получения списка
}
// Сбрасываем URL изображения и показываем уведомление о начале генерации
setGeneratedImageUrl(undefined); // Важно: сбрасываем URL изображения перед началом генерации
setNotificationTitle('Генерация стикера');
setNotificationMessage('Отправка запроса...');
setIsLoading(true);
setPromptText('');
setShowGalleryButton(true);
setShowButtons(false);
setContinueButtonText('Продолжить');
@ -182,8 +296,43 @@ const Home: React.FC = () => {
// Если выбран "Свой промпт" и введен текст, используем его
const userPrompt = selectedPresetId === 'customPrompt' && customPrompt ? customPrompt : undefined;
// Отправляем запрос на генерацию
const response = await apiService.generateImage(imageData, selectedStyle, selectedPresetId, userPrompt);
// Создаем объект с параметрами генерации
const generationOptions: any = {
promptId: selectedPresetId,
userPrompt,
genderDetection,
manualGender
};
// Если выбран тип "Мемы", добавляем ID мема
if (selectedStyle === 'emotions' && selectedEmotionType === 'memes' && selectedMemeId) {
generationOptions.memeId = selectedMemeId;
}
console.log('Generation options:', generationOptions);
// Определяем тип воркфлоу в зависимости от выбранного стиля и типа эмоций
let workflowType = WorkflowType.CHIBI;
if (selectedStyle === 'chibi') {
workflowType = WorkflowType.CHIBI;
} else if (selectedStyle === 'emotions') {
if (selectedEmotionType === 'memes') {
workflowType = WorkflowType.MEME;
} else {
workflowType = WorkflowType.PROMPT;
}
} else if (selectedStyle === 'realism') {
workflowType = WorkflowType.PROMPT;
}
console.log('Using workflow type:', workflowType, 'for style:', selectedStyle);
// Отправляем запрос на генерацию с использованием нового метода
const response = await apiService.generateImageWithWorkflow(
imageData,
workflowType,
generationOptions
);
console.log('Generation response:', response);
// Сохраняем данные о текущей генерации
@ -232,13 +381,15 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была успешно запущена
setShowButtons(true); // Показываем кнопки в случае ошибки перевода
setContinueButtonText('Закрыть'); // Меняем текст кнопки на "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи при ошибке
setQueuePosition(undefined); // Сбрасываем позицию в очереди
return;
}
// Если нет ошибки перевода, продолжаем обработку результата
if (response.result && response.usedPrompt) {
// Получаем результат и использованный промпт
const { result, usedPrompt } = response;
if (response.result) {
// Получаем результат
const { result } = response;
// Обновляем уведомление с информацией о позиции в очереди
if (result.queue_position !== undefined) {
@ -263,8 +414,30 @@ const Home: React.FC = () => {
);
}
// Устанавливаем использованный промпт, показываем кнопки и меняем текст кнопки "Продолжить" на "Закрыть"
setPromptText(usedPrompt);
// Сохраняем ID задачи
if (result.Task_ID) {
setCurrentTaskId(result.Task_ID);
// Устанавливаем позицию в очереди
if (result.queue_position !== undefined) {
setQueuePosition(result.queue_position);
}
// Запускаем интервал для проверки новых изображений
// Очищаем предыдущий интервал, если он был
if (imagesCheckInterval) {
clearInterval(imagesCheckInterval);
}
// Устанавливаем новый интервал
const intervalId = window.setInterval(() => {
checkForNewImages();
}, 2000); // Проверяем каждые 2 секунды
setImagesCheckInterval(intervalId);
}
// Показываем кнопки и меняем текст кнопки "Продолжить" на "Закрыть"
setShowButtons(true);
setContinueButtonText('Закрыть');
}
@ -278,16 +451,26 @@ const Home: React.FC = () => {
setShowGalleryButton(false); // Скрываем кнопку "В галерею", так как генерация не была успешно запущена
setShowButtons(true); // Показываем кнопки в случае ошибки
setContinueButtonText('Закрыть'); // Меняем текст кнопки на "Закрыть"
setCurrentTaskId(undefined); // Сбрасываем ID задачи при ошибке
setQueuePosition(undefined); // Сбрасываем позицию в очереди
setIsNotificationVisible(true);
}
return;
}
if (actionValue === 'toggleInput') {
// Добавляем логирование для отладки
console.log('Нажата кнопка "Свой промпт"', {
blockId,
buttonId,
selectedStyle,
selectedEmotionType,
isInputVisible: !isInputVisible // Новое значение
});
setIsInputVisible(prev => !prev);
// Устанавливаем selectedPresetId в 'customPrompt' при нажатии на кнопку "Свой промпт"
setSelectedPresetId('customPrompt');
console.log('Выбран свой промпт, установлен ID:', 'customPrompt');
return;
}
@ -313,9 +496,11 @@ const Home: React.FC = () => {
return;
}
// Если выбрана любая другая кнопка, скрываем поле ввода
setIsInputVisible(false);
}, [navigate, imageData, selectedStyle, selectedPresetId, customPrompt, lastGenerationData]);
// Если выбрана любая другая кнопка (кроме "Свой промпт"), скрываем поле ввода
if (!(actionType === 'function' && actionValue === 'toggleInput' && buttonId === 'customPrompt')) {
setIsInputVisible(false);
}
}, [navigate, imageData, selectedStyle, selectedPresetId, customPrompt, lastGenerationData, genderDetection, manualGender, selectedEmotionType, selectedMemeId, imagesCheckInterval, checkForNewImages]);
// Эффект для обновления window.history.state при загрузке из localStorage
useEffect(() => {
@ -350,19 +535,31 @@ const Home: React.FC = () => {
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
// Очищаем интервалы при размонтировании компонента
if (imagesCheckInterval) {
clearInterval(imagesCheckInterval);
}
if (checkInterval) {
clearInterval(checkInterval);
}
};
}, []);
}, [imagesCheckInterval, checkInterval]);
// Функция для получения кнопок в зависимости от блока
const getBlockButtons = useCallback((block: any) => {
if (block.id === 'quickActions') {
// Берем кнопку "Свой промпт" из конфигурации
const customPromptButton = block.buttons[0];
// Добавляем к ней кнопки из выбранного стиля
return [customPromptButton, ...(stylePresets[selectedStyle]?.buttons || [])];
// Возвращаем только кнопки из выбранного стиля
return stylePresets[selectedStyle]?.buttons || [];
}
if (block.id === 'emotionPromptsSelection' && selectedStyle === 'emotions' && selectedEmotionType === 'prompts') {
// Возвращаем только кнопки из стиля "Эмоции"
return stylePresets.emotions?.buttons || [];
}
return block.buttons;
}, [selectedStyle]);
}, [selectedStyle, selectedEmotionType]);
return (
<div className={styles.container}>
@ -372,13 +569,16 @@ const Home: React.FC = () => {
title={notificationTitle}
message={notificationMessage}
isLoading={isLoading}
promptText={promptText}
onGalleryClick={handleGalleryClick}
onContinueClick={handleContinueClick}
showGalleryButton={showGalleryButton}
showButtons={showButtons}
continueButtonText={continueButtonText}
isPrimaryGalleryButton={true}
taskId={currentTaskId}
generatedImageUrl={generatedImageUrl}
isGenerating={!!currentTaskId}
queuePosition={queuePosition}
/>
{/* Компонент обработки обратной связи */}
@ -491,9 +691,82 @@ const Home: React.FC = () => {
/>
{/* Блоки из конфигурации */}
<div className={styles.blocks}>
{homeScreenConfig.homeScreen.blocks
.filter(block => block.type !== 'generateButton')
.map((block) => {
{(() => {
// Получаем все блоки из конфигурации
const allBlocks = homeScreenConfig.homeScreen.blocks.filter(block => block.type !== 'generateButton');
// Создаем массив блоков для отображения в нужном порядке
const blocksToRender = [];
// Проходим по всем блокам и добавляем их в массив для отображения в нужном порядке
for (const block of allBlocks) {
// Блоки для выбора типа эмоций показываем только если выбран стиль "Эмоции"
if (block.id === 'emotionTypeTitle' || block.id === 'emotionTypeSelection') {
if (selectedStyle === 'emotions') {
blocksToRender.push(block);
}
continue;
}
// Блок с полем ввода текста (customPrompt) показываем после emotionTypeSelection и перед emotionPromptsSelection
// если выбран стиль "Эмоции" и тип "Промпты" и нажата кнопка "Свой промпт"
if (block.id === 'customPrompt') {
// Для стиля "Чиби" показываем в обычном порядке
if (selectedStyle === 'chibi' && isInputVisible) {
blocksToRender.push(block);
}
// Для стиля "Эмоции" и типа "Промпты" блок будет добавлен позже в специальном месте
continue;
}
// Блок выбора мемов показываем только если выбран стиль "Эмоции" и тип "Мемы"
if (block.id === 'memeSelection') {
if (selectedStyle === 'emotions' && selectedEmotionType === 'memes') {
blocksToRender.push(block);
}
continue;
}
// Блок выбора промптов для эмоций показываем только если выбран стиль "Эмоции" и тип "Промпты"
if (block.id === 'emotionPromptsSelection') {
if (selectedStyle === 'emotions' && selectedEmotionType === 'prompts') {
// Если выбран стиль "Эмоции" и тип "Промпты", то сначала добавляем поле ввода текста,
// если оно должно быть видимым
if (isInputVisible) {
const textInputBlock = allBlocks.find(b => b.id === 'customPrompt');
if (textInputBlock) {
blocksToRender.push(textInputBlock);
}
}
// Затем добавляем блок с промптами
blocksToRender.push(block);
}
continue;
}
// Блок с пресетами (quickActions) показываем только если выбран стиль "Чиби" или не выбран стиль "Эмоции"
if (block.id === 'quickActions') {
if (selectedStyle !== 'emotions') {
blocksToRender.push(block);
}
continue;
}
// Блок с заголовком "Выбери образ" (step3) показываем только если не выбран стиль "Эмоции" или уже выбран тип эмоций
if (block.id === 'step3') {
if (selectedStyle !== 'emotions' || selectedEmotionType !== undefined) {
blocksToRender.push(block);
}
continue;
}
// Остальные блоки показываем всегда
blocksToRender.push(block);
}
// Отображаем блоки
return blocksToRender.map((block) => {
// Создаем копию блока с модифицированными кнопками
const modifiedBlock = {
...block,
@ -508,6 +781,18 @@ const Home: React.FC = () => {
} else if (block.id === 'quickActions') {
// Для блока пресетов передаем ID выбранного пресета
selectedButtonId = selectedPresetId;
} else if (block.id === 'genderSelection') {
// Для блока выбора пола передаем ID выбранной кнопки пола
selectedButtonId = selectedGenderButtonId;
} else if (block.id === 'emotionTypeSelection') {
// Для блока выбора типа эмоций передаем ID выбранной кнопки типа эмоций
selectedButtonId = selectedEmotionTypeButtonId;
} else if (block.id === 'memeSelection') {
// Для блока выбора мема передаем ID выбранного мема
selectedButtonId = selectedMemeId;
} else if (block.id === 'emotionPromptsSelection') {
// Для блока выбора промптов для эмоций передаем ID выбранного пресета
selectedButtonId = selectedPresetId;
}
return (
@ -522,7 +807,8 @@ const Home: React.FC = () => {
} : undefined}
/>
);
})}
});
})()}
</div>
{homeScreenConfig.homeScreen.blocks
.filter(block => block.type === 'generateButton')

View File

@ -141,6 +141,15 @@
padding: calc(var(--spacing-medium) / 4) var(--spacing-medium) var(--spacing-medium) var(--spacing-medium);
box-sizing: border-box;
max-width: 100%;
position: relative; /* Добавляем для правильного позиционирования кнопки */
}
/* Стили для кнопки удаления на карточке стикерпака */
.packItem .deleteButton {
position: absolute;
top: 8px;
right: 8px;
z-index: 2;
}
.packItem:hover {
@ -230,8 +239,10 @@
.detailsHeader {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: var(--spacing-medium);
position: relative;
}
.backButton {
@ -241,14 +252,17 @@
cursor: pointer;
font-weight: 500;
padding: var(--spacing-small);
margin-right: var(--spacing-small);
position: absolute;
left: 0;
top: 0;
}
.detailsTitle {
flex-grow: 1;
font-size: 1.2rem;
font-weight: 500;
color: var(--color-text);
text-align: center;
margin: var(--spacing-small) 0;
}
.deleteButton {
@ -323,7 +337,8 @@
display: flex;
justify-content: center;
gap: var(--spacing-medium);
margin-top: var(--spacing-medium);
margin: var(--spacing-medium) 0;
width: 100%;
}
.addStickerButton {

View File

@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
import styles from './StickerPacks.module.css';
import { stickerService } from '../services/stickerService';
import { getCurrentUserId } from '../constants/user';
import NotificationModal from '../components/shared/NotificationModal';
// Функция для удаления дописанной части из названия стикерпака
const cleanPackTitle = (title: string): string => {
@ -31,6 +32,10 @@ const StickerPacks: React.FC = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedPack, setSelectedPack] = useState<StickerPack | null>(null);
const [packToDelete, setPackToDelete] = useState<string | null>(null);
const [isDeleting, setIsDeleting] = useState(false);
const [stickerToDelete, setStickerToDelete] = useState<string | null>(null);
const [isDeletingSticker, setIsDeletingSticker] = useState(false);
useEffect(() => {
const fetchStickerPacks = async () => {
@ -76,18 +81,24 @@ const StickerPacks: React.FC = () => {
setSelectedPack(null);
};
const handleDeletePack = async (packName: string) => {
if (!confirm('Вы уверены, что хотите удалить этот стикерпак?')) {
return;
}
const handleDeletePack = (packName: string) => {
setPackToDelete(packName);
};
try {
await stickerService.deleteStickerPack(packName);
setStickerPacks(prevPacks => prevPacks.filter(pack => pack.name !== packName));
setSelectedPack(null);
} catch (err) {
console.error('Ошибка при удалении стикерпака:', err);
alert('Не удалось удалить стикерпак');
const handleConfirmDelete = async () => {
if (packToDelete) {
try {
setIsDeleting(true);
await stickerService.deleteStickerPack(packToDelete);
setStickerPacks(prevPacks => prevPacks.filter(pack => pack.name !== packToDelete));
setSelectedPack(null);
setIsDeleting(false);
setPackToDelete(null);
} catch (err) {
console.error('Ошибка при удалении стикерпака:', err);
alert('Не удалось удалить стикерпак');
setIsDeleting(false);
}
}
};
@ -97,34 +108,41 @@ const StickerPacks: React.FC = () => {
}
};
const handleDeleteSticker = async (fileId: string) => {
const handleDeleteSticker = (fileId: string) => {
if (!fileId) {
alert('Не удалось определить ID стикера');
return;
}
if (!confirm('Вы уверены, что хотите удалить этот стикер?')) {
return;
}
setStickerToDelete(fileId);
};
try {
await stickerService.deleteStickerByFileId(fileId);
const handleConfirmDeleteSticker = async () => {
if (stickerToDelete) {
try {
setIsDeletingSticker(true);
await stickerService.deleteStickerByFileId(stickerToDelete);
// Обновляем список стикеров в выбранном стикерпаке
if (selectedPack) {
const updatedPack = await stickerService.getStickerPack(selectedPack.name);
setSelectedPack(updatedPack);
// Обновляем список стикеров в выбранном стикерпаке
if (selectedPack) {
const updatedPack = await stickerService.getStickerPack(selectedPack.name);
setSelectedPack(updatedPack);
// Также обновляем стикерпак в общем списке
setStickerPacks(prevPacks =>
prevPacks.map(pack =>
pack.name === selectedPack.name ? updatedPack : pack
)
);
// Также обновляем стикерпак в общем списке
setStickerPacks(prevPacks =>
prevPacks.map(pack =>
pack.name === selectedPack.name ? updatedPack : pack
)
);
}
setIsDeletingSticker(false);
setStickerToDelete(null);
} catch (err) {
console.error('Ошибка при удалении стикера:', err);
alert('Не удалось удалить стикер');
setIsDeletingSticker(false);
}
} catch (err) {
console.error('Ошибка при удалении стикера:', err);
alert('Не удалось удалить стикер');
}
};
@ -204,6 +222,17 @@ const StickerPacks: React.FC = () => {
</div>
))}
</div>
{/* Кнопка удаления стикерпака */}
<button
className={styles.deleteButton}
onClick={(e) => {
e.stopPropagation(); // Предотвращаем всплытие события
handleDeletePack(pack.name);
}}
>
Удалить
</button>
</div>
))}
</div>
@ -227,11 +256,22 @@ const StickerPacks: React.FC = () => {
Назад
</button>
<h2 className={styles.detailsTitle}>{cleanPackTitle(selectedPack.title)}</h2>
</div>
{/* Перемещенный блок с кнопками */}
<div className={styles.detailsActions}>
<button
className={styles.deleteButton}
onClick={() => handleDeletePack(selectedPack.name)}
className={styles.addStickerButton}
onClick={() => navigate(`/add-sticker/${selectedPack.name}`)}
>
Удалить
Добавить стикер
</button>
<button
className={styles.openInTelegramButton}
onClick={handleOpenInTelegram}
>
Открыть в Telegram
</button>
</div>
@ -262,24 +302,36 @@ const StickerPacks: React.FC = () => {
</div>
))}
</div>
<div className={styles.detailsActions}>
<button
className={styles.addStickerButton}
onClick={() => navigate(`/add-sticker/${selectedPack.name}`)}
>
Добавить стикер
</button>
<button
className={styles.openInTelegramButton}
onClick={handleOpenInTelegram}
>
Открыть в Telegram
</button>
</div>
</div>
)}
{/* Модальное окно подтверждения удаления стикерпака */}
<NotificationModal
isVisible={!!packToDelete}
title="Удаление стикерпака"
message="Вы уверены, что хотите удалить этот стикерпак?"
isLoading={isDeleting}
showGalleryButton={true}
galleryButtonText="Отмена"
continueButtonText="Удалить"
onContinueClick={handleConfirmDelete}
onGalleryClick={() => setPackToDelete(null)}
isPrimaryGalleryButton={false}
/>
{/* Модальное окно подтверждения удаления стикера */}
<NotificationModal
isVisible={!!stickerToDelete}
title="Удаление стикера"
message="Вы уверены, что хотите удалить этот стикер?"
isLoading={isDeletingSticker}
showGalleryButton={true}
galleryButtonText="Отмена"
continueButtonText="Удалить"
onContinueClick={handleConfirmDeleteSticker}
onGalleryClick={() => setStickerToDelete(null)}
isPrimaryGalleryButton={false}
/>
</div>
);
};

View File

@ -1,9 +1,11 @@
import { GenerationResponse, ApiError as ApiErrorType, GeneratedImage, PendingTask, GenerationResult } from '../types/api';
import { GenerationResponse, ApiError as ApiErrorType, GeneratedImage, PendingTask, GenerationResult, GenerationOptions } from '../types/api';
import { baseWorkflow } from '../constants/baseWorkflow';
import { WorkflowType, getWorkflowByType } from '../constants/workflows';
import { prompts } from '../assets/prompts';
import translateService from './translateService';
import { getCurrentUserId, isTelegramWebAppAvailable } from '../constants/user';
import { trackStickerGeneration, trackRejectedPrompt } from './analyticsService';
import memeService from './memeService';
const API_BASE_URL = 'https://stickerserver.gymnasticstuff.uk';
@ -252,6 +254,7 @@ const apiService = {
}
},
// Существующий метод для генерации изображений (для обратной совместимости)
async generateImage(imageData: string, style?: string, promptId?: string, userPrompt?: string): Promise<GenerationResult> {
try {
// Создаем копию базового воркфлоу
@ -358,6 +361,168 @@ const apiService = {
}
throw new Error('Failed to generate image');
}
},
// Новый метод для генерации изображений с использованием выбранного воркфлоу
async generateImageWithWorkflow(
imageData: string,
workflowType: WorkflowType,
options: GenerationOptions
): Promise<GenerationResult> {
try {
// Получаем базовый воркфлоу в зависимости от типа
const workflow = JSON.parse(JSON.stringify(getWorkflowByType(workflowType)));
// Вставляем изображение пользователя в узел 563
workflow['563'].inputs.image = imageData;
// Настраиваем определение пола
const genderSwitchNode = workflowType === WorkflowType.CHIBI ? '564' : '689';
workflow[genderSwitchNode].inputs.select = options.genderDetection === 'auto' ? 1 : 2;
// Если выбрано ручное определение пола
if (options.genderDetection === 'manual' && options.manualGender) {
const genderNode = workflowType === WorkflowType.CHIBI ? '565' : '769';
workflow[genderNode].inputs.text = options.manualGender;
}
// Переменная для хранения использованного промпта
let usedPrompt = '';
let translationFailed = false;
// Обрабатываем специфичные для каждого типа воркфлоу параметры
switch (workflowType) {
case WorkflowType.CHIBI:
// Обработка промпта для CHIBI
if (options.userPrompt && options.promptId === 'customPrompt') {
// Используем существующий код для перевода
const result = await this.handlePromptTranslation(options.userPrompt);
if (result.translationFailed) {
return result;
}
workflow['316'].inputs.prompt_1 = result.usedPrompt || '';
usedPrompt = result.usedPrompt || '';
} else if (options.promptId && prompts[options.promptId]) {
workflow['316'].inputs.prompt_1 = prompts[options.promptId];
usedPrompt = prompts[options.promptId];
}
break;
case WorkflowType.PROMPT:
// Обработка промпта для PROMPT
if (options.userPrompt && options.promptId === 'customPrompt') {
// Используем существующий код для перевода
const result = await this.handlePromptTranslation(options.userPrompt);
if (result.translationFailed) {
return result;
}
workflow['585'].inputs.text = result.usedPrompt || '';
usedPrompt = result.usedPrompt || '';
} else if (options.promptId && prompts[options.promptId]) {
workflow['585'].inputs.text = prompts[options.promptId];
usedPrompt = prompts[options.promptId];
}
break;
case WorkflowType.MEME:
// Загружаем мем для стиля с мемами
if (options.memeId) {
const memeBase64 = memeService.getMemeBase64(options.memeId);
workflow['603'].inputs.image = memeBase64;
} else {
return {
translationFailed: true,
errorDetails: 'Не указан ID мема для стиля MEME'
};
}
break;
}
// Определяем тег на основе выбранного типа воркфлоу
const tag = workflowType === WorkflowType.CHIBI ? 'chibi' : 'image_generation';
// Создаем строку JSON для workflow
const workflowJson = JSON.stringify(workflow);
// Создаем тело запроса
const requestBodyJson = `{"tag":"${tag}","user_id":${getCurrentUserId()},"workflow":${workflowJson}}`;
// Сохраняем JSON для отладки только при локальной разработке
if (!isTelegramWebAppAvailable()) {
const blob = new Blob([requestBodyJson], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'generation_request.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Отправляем запрос
const response = await fetch(`${API_BASE_URL}/generate_image`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: requestBodyJson
});
if (!response.ok) {
const errorData: ApiErrorType = await response.json();
throw new GenerationError(errorData.detail);
}
const result = await response.json() as GenerationResponse;
// Отслеживаем событие генерации стикера
if (usedPrompt) {
trackStickerGeneration(usedPrompt);
}
// Возвращаем результат и использованный промпт
return {
result,
usedPrompt,
translationFailed: false
};
} catch (error) {
if (error instanceof GenerationError) {
throw error;
}
throw new Error('Failed to generate image');
}
},
// Вспомогательный метод для обработки перевода промпта
async handlePromptTranslation(userPrompt: string): Promise<GenerationResult> {
console.log('Переводим пользовательский промпт:', userPrompt);
// Используем существующий метод перевода
const translationResult = await translateService.translateWithLLM(userPrompt);
if (translationResult.success) {
// Успешный перевод
console.log('Переведенный промпт:', translationResult.text);
return {
translationFailed: false,
usedPrompt: translationResult.text
};
} else {
// Перевод не удался
console.error('Не удалось перевести промпт:', translationResult.text);
// Отслеживаем событие неудавшейся генерации
trackRejectedPrompt(userPrompt);
// Возвращаем ошибку
return {
translationFailed: true,
usedPrompt: 'Недопустимый промпт',
errorDetails: translationResult.text
};
}
}
};

View File

@ -0,0 +1,56 @@
import { memes, MemeData } from '../assets/memes';
/**
* Сервис для работы с мемами
*/
/**
* Получить список всех мемов
* @returns Массив мемов
*/
export const getMemesList = (): MemeData[] => {
return memes;
};
/**
* Получить мем по ID
* @param id ID мема
* @returns Объект мема или undefined, если мем не найден
*/
export const getMemeById = (id: string): MemeData | undefined => {
return memes.find(meme => meme.id === id);
};
/**
* Получить путь к изображению мема по ID
* Возвращает путь в формате для Linux системы: 512meme/(номер)_512x.png
* @param id ID мема (формат: meme1, meme2, ...)
* @returns Путь к изображению мема или пустая строка, если мем не найден
*/
export const getMemeBase64 = (id: string): string => {
// Извлекаем номер из ID мема (например, из "meme5" получаем "5")
const memeNumber = id.replace('meme', '');
// Проверяем, что номер валидный
if (!memeNumber || isNaN(Number(memeNumber)) || Number(memeNumber) < 1 || Number(memeNumber) > 10) {
console.error(`[Ошибка] Некорректный ID мема: ${id}`);
return '';
}
// Формируем путь к изображению мема в формате для Linux системы с добавлением "x"
const memePath = `512meme/${memeNumber}_512x.png`;
console.log(`[Мем] Запрошен мем с ID: ${id}, путь: ${memePath}`);
return memePath;
};
/**
* Экспорт всех функций сервиса
*/
const memeService = {
getMemesList,
getMemeById,
getMemeBase64
};
export default memeService;

View File

@ -61,6 +61,15 @@ export interface StickerSetResponse {
user_id: number;
}
// Интерфейс для параметров метода generateImage
export interface GenerationOptions {
promptId?: string;
userPrompt?: string;
memeId?: string;
genderDetection: 'auto' | 'manual';
manualGender?: 'man' | 'woman' | 'boy' | 'girl';
}
// Интерфейс для ответа от apiService.generateImage
export interface GenerationResult {
result?: GenerationResponse;

View File

@ -15,7 +15,7 @@ export interface BlockButton {
imageUrl?: string;
color?: string;
action?: {
type: 'route' | 'function' | 'selectStyle' | 'selectPreset';
type: 'route' | 'function' | 'selectStyle' | 'selectPreset' | 'selectWorkflowType' | 'selectGenderDetection' | 'selectGender' | 'selectMeme' | 'selectEmotionType';
value: string;
};
disabled?: boolean;

View File

@ -0,0 +1,4 @@
563 - загрузка base64 изображение
316 - промпт (только первый который military clothes меняем на свой)
565 - выбор пола человека ручной
564 - переключатель автоматического определения или выбора вручную пола человека (1 - автоматическое, 2 - ручное)

View File

@ -0,0 +1,636 @@
{
"305": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"307": {
"inputs": {
"share_norm": "both",
"share_attn": "q+k",
"scale": 0.7000000000000001,
"model": [
"309",
0
]
},
"class_type": "StyleAlignedBatchAlign",
"_meta": {
"title": "StyleAligned Batch Align"
}
},
"308": {
"inputs": {
"text_positive": "Stickerchibi:2,Flat:1.5,(full body:2,Simple details(Empty Background:2",
"text_negative": "Realism, photo-realism, real materials(full body:2",
"style": "sai-cinematic",
"log_prompt": false,
"style_positive": true,
"style_negative": true
},
"class_type": "SDXLPromptStyler",
"_meta": {
"title": "SDXL Prompt Styler"
}
},
"309": {
"inputs": {
"b1": 1.3,
"b2": 1.4000000000000001,
"s1": 0.9,
"s2": 0.2,
"model": [
"406",
0
]
},
"class_type": "FreeU_V2",
"_meta": {
"title": "FreeU_V2"
}
},
"312": {
"inputs": {
"text": [
"308",
1
],
"clip": [
"406",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"313": {
"inputs": {
"prompt_1": "Boxers, with red boxing gloves, swinging their fists",
"prompt_2": "Dressed in a Superman costume",
"prompt_3": "Dress up as Santa Claus with a rattle in your hand",
"prompt_4": "Holding a bouquet of roses in his hand and wearing a gown",
"prompt_5": "Dressed in a wide hip hop suit,Playing the guitar,tattooingdenimstreet dancedancing",
"simple_prompt_list": [
"316",
0
]
},
"class_type": "CR Simple Prompt List",
"_meta": {
"title": "CR Simple Prompt List (Legacy)"
}
},
"314": {
"inputs": {
"keyframe_interval": 1,
"loops": 1,
"transition_type": "Default",
"transition_speed": "Default",
"transition_profile": "Default",
"keyframe_format": "Deforum",
"simple_prompt_list": [
"313",
0
]
},
"class_type": "CR Simple Prompt List Keyframes",
"_meta": {
"title": "CR Simple Prompt List Keyframes (Legacy)"
}
},
"316": {
"inputs": {
"prompt_1": "military clothes",
"prompt_2": "Pirate captain with a sword",
"prompt_3": "Drinking coffee from a coffee cup and smiling",
"prompt_4": "Dressed in a spacesuit and wearing a glass helmet",
"prompt_5": "Wearing luxurious clothes, holding a red heart-shaped balloon and smiling"
},
"class_type": "CR Simple Prompt List",
"_meta": {
"title": "CR Simple Prompt List (Legacy)"
}
},
"318": {
"inputs": {},
"class_type": "Anything Everywhere3",
"_meta": {
"title": "Anything Everywhere3"
}
},
"326": {
"inputs": {
"image": "photo_2025-02-03_14-06-19.jpg",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"328": {
"inputs": {
"seed": [
"404",
0
],
"steps": 7,
"cfg": 2,
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"347",
0
],
"positive": [
"339",
0
],
"negative": [
"312",
0
],
"latent_image": [
"348",
0
],
"optional_vae": [
"305",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"339": {
"inputs": {
"text": [
"314",
0
],
"max_frames": 10,
"print_output": false,
"pre_text": [
"308",
0
],
"app_text": [
"523",
0
],
"start_frame": 0,
"end_frame": 0,
"clip": [
"406",
1
]
},
"class_type": "BatchPromptSchedule",
"_meta": {
"title": "Batch Prompt Schedule 📅🅕🅝"
}
},
"344": {
"inputs": {
"pulid_file": "ip-adapter_pulid_sdxl_fp16.safetensors"
},
"class_type": "PulidModelLoader",
"_meta": {
"title": "Load PuLID Model"
}
},
"345": {
"inputs": {
"provider": "CUDA"
},
"class_type": "PulidInsightFaceLoader",
"_meta": {
"title": "Load InsightFace (PuLID)"
}
},
"346": {
"inputs": {},
"class_type": "PulidEvaClipLoader",
"_meta": {
"title": "Load Eva Clip (PuLID)"
}
},
"347": {
"inputs": {
"method": "fidelity",
"weight": 1,
"start_at": 0,
"end_at": 1,
"model": [
"307",
0
],
"pulid": [
"344",
0
],
"eva_clip": [
"346",
0
],
"face_analysis": [
"345",
0
],
"image": [
"384",
0
]
},
"class_type": "ApplyPulid",
"_meta": {
"title": "Apply PuLID"
}
},
"348": {
"inputs": {
"width": 768,
"height": 768,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"377",
0
],
"image": [
"378",
5
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"377": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"378": {
"inputs": {
"seed": [
"404",
0
],
"steps": 6,
"cfg": 2,
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
"denoise": 0.6,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"382",
0
],
"positive": [
"382",
1
],
"negative": [
"382",
2
],
"latent_image": [
"417",
0
],
"optional_vae": [
"305",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"381": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"382": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"381",
0
],
"control_net": [
"380",
0
],
"image": [
"384",
0
],
"model": [
"307",
0
],
"positive": [
"328",
1
],
"negative": [
"328",
2
],
"image_kps": [
"328",
5
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"384": {
"inputs": {
"side_length": 512,
"side": "Longest",
"upscale_method": "nearest-exact",
"crop": "disabled",
"image": [
"563",
0
]
},
"class_type": "DF_Image_scale_to_side",
"_meta": {
"title": "Image scale to side"
}
},
"404": {
"inputs": {
"seed": 0
},
"class_type": "Seed Everywhere",
"_meta": {
"title": "Seed Everywhere"
}
},
"405": {
"inputs": {
"toggle": true,
"mode": "simple",
"num_loras": 3,
"lora_1_name": "StickersRedmond.safetensors",
"lora_1_strength": 1,
"lora_1_model_strength": 2,
"lora_1_clip_strength": 2,
"lora_2_name": "cartoon_style.pt",
"lora_2_strength": 2,
"lora_2_model_strength": 1,
"lora_2_clip_strength": 1,
"lora_3_name": "smiling.pt",
"lora_3_strength": 2,
"lora_3_model_strength": 2,
"lora_3_clip_strength": 1,
"lora_4_name": "None",
"lora_4_strength": 1,
"lora_4_model_strength": 1,
"lora_4_clip_strength": 1,
"lora_5_name": "None",
"lora_5_strength": 1,
"lora_5_model_strength": 1,
"lora_5_clip_strength": 1,
"lora_6_name": "None",
"lora_6_strength": 1,
"lora_6_model_strength": 1,
"lora_6_clip_strength": 1,
"lora_7_name": "None",
"lora_7_strength": 1,
"lora_7_model_strength": 1,
"lora_7_clip_strength": 1,
"lora_8_name": "None",
"lora_8_strength": 1,
"lora_8_model_strength": 1,
"lora_8_clip_strength": 1,
"lora_9_name": "None",
"lora_9_strength": 1,
"lora_9_model_strength": 1,
"lora_9_clip_strength": 1,
"lora_10_name": "None",
"lora_10_strength": 1,
"lora_10_model_strength": 1,
"lora_10_clip_strength": 1
},
"class_type": "easy loraStack",
"_meta": {
"title": "EasyLoraStack"
}
},
"406": {
"inputs": {
"model": [
"305",
0
],
"clip": [
"305",
1
],
"lora_stack": [
"405",
0
]
},
"class_type": "CR Apply LoRA Stack",
"_meta": {
"title": "💊 CR Apply LoRA Stack"
}
},
"417": {
"inputs": {
"upscale_method": "nearest-exact",
"width": 1024,
"height": 1024,
"crop": "disabled",
"samples": [
"328",
3
]
},
"class_type": "LatentUpscale",
"_meta": {
"title": "Увеличить латент"
}
},
"523": {
"inputs": {
"text": [
"564",
0
]
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"555",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"555": {
"inputs": {
"width": 762,
"height": 762,
"method": "lanczos",
"images": [
"563",
0
]
},
"class_type": "ImageTransformResizeAbsolute",
"_meta": {
"title": "ImageTransformResizeAbsolute"
}
},
"556": {
"inputs": {
"images": [
"555",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "Предварительный просмотр изображения"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"564": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"565",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"565": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
}

View File

@ -0,0 +1,6 @@
563 - загрузка base64 лицо
562 - получение base64 результата
689 - переключатель автоматического определения пола человека или ручного (1- автоматическое, 2- ручное)
769 - ввод пола человека
585 - промпт

View File

@ -0,0 +1,525 @@
{
"326": {
"inputs": {
"image": "Screenshot_20.png",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"567",
5
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "man"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 378971921426134,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 378971921426134,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp, kawaii style, Anime style"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": "half body, looking at viewer, with empty space around"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 0.9,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"566",
5
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": "character belting out a song into a microphone, full of energy and passion"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"587": {
"inputs": {
"filename_prefix": "ComfyUI"
},
"class_type": "SaveImage",
"_meta": {
"title": "Сохранить изображение"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "woomen"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
}

View File

@ -0,0 +1,557 @@
{
"326": {
"inputs": {
"image": "girl2.png",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"606",
0
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "instantid-controlnet.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "girl"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 866300843763550,
"steps": 10,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 378971921426134,
"steps": 10,
"cfg": 4,
"sampler_name": "euler",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated, naked"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 1,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"566",
5
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": "Half of body, full face, holding a tiny capybara with both hands, looking at it with exaggerated amazement. Conveying love and adoration for pets"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"587": {
"inputs": {
"filename_prefix": "ComfyUI"
},
"class_type": "SaveImage",
"_meta": {
"title": "Сохранить изображение"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"606": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0,
"src_ratio": 1,
"sample_ratio": 1,
"sample_parts": "OnlyExpression",
"crop_factor": 1.7,
"src_image": [
"567",
5
],
"sample_image": [
"566",
5
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "woomen"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
}

View File

@ -0,0 +1,6 @@
603 - загрузка изображения мема лежит по пути 512meme\(1_512.png - 10_512.png) формат путя нужно указывать для линукс системы. номера изображенйи соответствуют номеру мема на кнопке на фронте
563 - загрузка base64 лицо
562 - получение base64 результата
689 - переключатель автоматического определения пола человека или ручного (1- автоматическое, 2- ручное)
769 - ввод пола человека
585 - промпт в meme не используется

View File

@ -0,0 +1,580 @@
{
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"606",
0
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "man"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "✴️ U-NAI Get Text"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 698459364937105,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 711685301954594,
"steps": 10,
"cfg": 4,
"sampler_name": "euler",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp, kawaii style, Anime style"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": "half body, simple T-shirt"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить контрольную точку"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 0.9,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"608",
0
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"603": {
"inputs": {
"image": "Patrick Bateman Ou.png",
"upload": "image"
},
"class_type": "LoadImage",
"_meta": {
"title": "face"
}
},
"606": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0.01,
"src_ratio": 1,
"sample_ratio": 0.8,
"sample_parts": "OnlyExpression",
"crop_factor": 1.7,
"src_image": [
"567",
5
],
"sample_image": [
"603",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"608": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0,
"src_ratio": 1,
"sample_ratio": 1,
"sample_parts": "All",
"crop_factor": 1.7000000000000002,
"src_image": [
"566",
5
],
"sample_image": [
"603",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "man"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
}
}

View File

@ -0,0 +1,606 @@
{
"326": {
"inputs": {
"image": "512.png"
},
"class_type": "LoadImage",
"_meta": {
"title": "Загрузить изображение"
}
},
"376": {
"inputs": {
"rmbgmodel": [
"615",
0
],
"image": [
"606",
0
]
},
"class_type": "BRIA_RMBG_Zho",
"_meta": {
"title": "🧹BRIA RMBG"
}
},
"379": {
"inputs": {
"instantid_file": "ip-adapter.bin"
},
"class_type": "InstantIDModelLoader",
"_meta": {
"title": "Load InstantID Model"
}
},
"380": {
"inputs": {
"control_net_name": "diffusion_pytorch_model.safetensors"
},
"class_type": "ControlNetLoader",
"_meta": {
"title": "Загрузить модель ControlNet"
}
},
"523": {
"inputs": {
"text": [
"689",
0
],
"text2": "Man"
},
"class_type": "ShowText|pysssss",
"_meta": {
"title": "Show Text 🐍"
}
},
"536": {
"inputs": {
"text_input": "Identify if the person in the image is a man, woman, boy or girl. Answer with just one word.",
"model_name": "Qwen2-VL-2B",
"memory_mode": "Balanced (8-bit)",
"max_new_tokens": 512,
"temperature": 0.7000000000000001,
"top_p": 0.8,
"fps": 1,
"image": [
"563",
0
]
},
"class_type": "Qwen2VLNode",
"_meta": {
"title": "Qwen2-VL Model"
}
},
"539": {
"inputs": {
"aggressive": false,
"image": [
"376",
0
]
},
"class_type": "FreeMemoryImage",
"_meta": {
"title": "Free Memory (Image)"
}
},
"562": {
"inputs": {
"Actions": "Send to websocket",
"images": [
"539",
0
]
},
"class_type": "ImageOutput",
"_meta": {
"title": "Image(s) To Websocket (Base64)"
}
},
"563": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
},
"566": {
"inputs": {
"seed": 378971921426134,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"576",
0
],
"positive": [
"590",
0
],
"negative": [
"588",
0
],
"latent_image": [
"591",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"567": {
"inputs": {
"seed": 378971921426134,
"steps": 8,
"cfg": 4,
"sampler_name": "dpmpp_2m_sde",
"scheduler": "karras",
"denoise": 1,
"preview_method": "auto",
"vae_decode": "true",
"model": [
"582",
0
],
"positive": [
"582",
1
],
"negative": [
"582",
2
],
"latent_image": [
"577",
0
],
"optional_vae": [
"575",
2
]
},
"class_type": "KSampler (Efficient)",
"_meta": {
"title": "KSampler (Efficient)"
}
},
"569": {
"inputs": {
"text": ", Sticker, svg, vector art, sharp, kawaii style, Anime style"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"570": {
"inputs": {
"text": "shiny, photo, photography, soft, nsfw, nude, ugly, broken, watermark, oversaturated"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"571": {
"inputs": {
"text": "half body, looking at viewer, with empty space around"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"573": {
"inputs": {
"provider": "CUDA"
},
"class_type": "InstantIDFaceAnalysis",
"_meta": {
"title": "InstantID Face Analysis"
}
},
"575": {
"inputs": {
"ckpt_name": "dreamshaperXL_lightningDPMSDE.safetensors"
},
"class_type": "CheckpointLoaderSimple",
"_meta": {
"title": "Загрузить сheckpoint"
}
},
"576": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"575",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"577": {
"inputs": {
"width": 1016,
"height": 1016,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"578": {
"inputs": {
"lora_name": "StickersRedmond.safetensors",
"strength_model": 0.9,
"strength_clip": 1,
"model": [
"575",
0
],
"clip": [
"575",
1
]
},
"class_type": "LoraLoader",
"_meta": {
"title": "Загрузить LoRA"
}
},
"579": {
"inputs": {
"hard_mode": true,
"boost": true,
"model": [
"578",
0
]
},
"class_type": "Automatic CFG",
"_meta": {
"title": "Automatic CFG"
}
},
"580": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"589",
0
],
"text_b": [
"569",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"581": {
"inputs": {
"text": [
"580",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"582": {
"inputs": {
"weight": 1,
"start_at": 0,
"end_at": 1,
"instantid": [
"379",
0
],
"insightface": [
"573",
0
],
"control_net": [
"380",
0
],
"image": [
"584",
0
],
"model": [
"579",
0
],
"positive": [
"581",
0
],
"negative": [
"583",
0
],
"image_kps": [
"608",
0
]
},
"class_type": "ApplyInstantID",
"_meta": {
"title": "Apply InstantID"
}
},
"583": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"578",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"584": {
"inputs": {
"upscale_method": "lanczos",
"megapixels": 1,
"image": [
"563",
0
]
},
"class_type": "ImageScaleToTotalPixels",
"_meta": {
"title": "Масштабировать изображение до общего количества пикселей"
}
},
"585": {
"inputs": {
"text": ""
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"587": {
"inputs": {
"filename_prefix": "ComfyUI"
},
"class_type": "SaveImage",
"_meta": {
"title": "Сохранить изображение"
}
},
"588": {
"inputs": {
"text": [
"570",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"589": {
"inputs": {
"delimiter": "",
"clean_whitespace": "false",
"text_a": [
"609",
0
],
"text_b": [
"585",
0
]
},
"class_type": "Text Concatenate",
"_meta": {
"title": "Text Concatenate"
}
},
"590": {
"inputs": {
"text": [
"589",
0
],
"clip": [
"575",
1
]
},
"class_type": "CLIPTextEncode",
"_meta": {
"title": "Кодирование текста CLIP (Запрос)"
}
},
"591": {
"inputs": {
"width": 1024,
"height": 1024,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {
"title": "Пустое латентное изображение"
}
},
"603": {
"inputs": {
"image": "Screenshot_цув4.png"
},
"class_type": "LoadImage",
"_meta": {
"title": "face"
}
},
"606": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0.01,
"src_ratio": 1,
"sample_ratio": 1.2,
"sample_parts": "OnlyExpression",
"crop_factor": 1.7,
"src_image": [
"567",
5
],
"sample_image": [
"770",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"608": {
"inputs": {
"rotate_pitch": 0,
"rotate_yaw": 0,
"rotate_roll": 0,
"blink": 0,
"eyebrow": 0,
"wink": 0,
"pupil_x": 0,
"pupil_y": 0,
"aaa": 0,
"eee": 0,
"woo": 0,
"smile": 0,
"src_ratio": 1,
"sample_ratio": 1,
"sample_parts": "All",
"crop_factor": 1.7,
"src_image": [
"566",
5
],
"sample_image": [
"770",
0
]
},
"class_type": "ExpressionEditor",
"_meta": {
"title": "Expression Editor (PHM)"
}
},
"609": {
"inputs": {
"separator": ", ",
"arg1": [
"523",
0
],
"arg2": [
"571",
0
]
},
"class_type": "PromptUtilitiesJoinStringList",
"_meta": {
"title": "Join String List"
}
},
"615": {
"inputs": {},
"class_type": "BRIA_RMBG_ModelLoader_Zho",
"_meta": {
"title": "🧹BRIA_RMBG Model Loader"
}
},
"689": {
"inputs": {
"select": 1,
"sel_mode": false,
"input1": [
"536",
0
],
"input2": [
"769",
0
]
},
"class_type": "ImpactSwitch",
"_meta": {
"title": "Switch (Any)"
}
},
"769": {
"inputs": {
"text": "woomen"
},
"class_type": "CR Text",
"_meta": {
"title": "🔤 CR Text"
}
},
"770": {
"inputs": {
"image": ""
},
"class_type": "Load Image (Base64)",
"_meta": {
"title": "Load Image (Base64)"
}
}
}