Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -570,7 +570,7 @@ label {
|
|
| 570 |
letter-spacing: 0.8px;
|
| 571 |
}
|
| 572 |
|
| 573 |
-
select, textarea {
|
| 574 |
padding: 12px 14px;
|
| 575 |
border: 1px solid var(--border);
|
| 576 |
border-radius: 8px;
|
|
@@ -583,7 +583,7 @@ select, textarea {
|
|
| 583 |
box-sizing: border-box;
|
| 584 |
}
|
| 585 |
|
| 586 |
-
select:focus, textarea:focus {
|
| 587 |
border-color: var(--primary);
|
| 588 |
box-shadow: 0 0 10px rgba(204, 255, 0, 0.2);
|
| 589 |
}
|
|
@@ -674,6 +674,36 @@ textarea {
|
|
| 674 |
.aspect-ratio-btn.active { background-color: var(--primary); color: #000; border-color: var(--primary); box-shadow: 0 0 10px rgba(204, 255, 0, 0.3); }
|
| 675 |
.aspect-ratio-btn.active .preview { background: #000; }
|
| 676 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
@media (max-width: 600px) {
|
| 678 |
.form-grid, .style-grid { grid-template-columns: 1fr; }
|
| 679 |
.full-width { grid-column: span 1; }
|
|
@@ -859,6 +889,27 @@ textarea {
|
|
| 859 |
<textarea id="object_additional_prompt" placeholder="Например: добавить инфографику 'new collection', левитация предмета"></textarea>
|
| 860 |
</div>
|
| 861 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 862 |
</div>
|
| 863 |
|
| 864 |
<div class="btn-container">
|
|
@@ -874,68 +925,71 @@ textarea {
|
|
| 874 |
let currentMode = 'model';
|
| 875 |
const envKeyword = {{ keyword|tojson|safe }};
|
| 876 |
|
| 877 |
-
const
|
| 878 |
-
'studio': 'Студия (профи)',
|
| 879 |
-
'
|
| 880 |
-
'
|
| 881 |
-
'
|
| 882 |
-
'
|
| 883 |
-
'
|
| 884 |
-
'
|
| 885 |
-
'
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
'
|
| 894 |
-
'
|
| 895 |
-
'
|
| 896 |
-
'
|
| 897 |
-
'
|
| 898 |
-
'
|
| 899 |
-
'
|
| 900 |
-
'
|
| 901 |
-
'
|
| 902 |
-
'
|
| 903 |
-
'
|
| 904 |
-
'
|
| 905 |
-
'
|
| 906 |
-
'
|
| 907 |
-
'
|
| 908 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 909 |
};
|
| 910 |
|
| 911 |
-
const
|
| 912 |
-
'studio': '
|
| 913 |
-
'minimalism': '
|
| 914 |
-
'nature': '
|
| 915 |
-
'luxe': '
|
| 916 |
-
'dark': '
|
| 917 |
};
|
| 918 |
|
| 919 |
const femaleBodyTypes = {
|
| 920 |
-
'standard': 'Стандартное',
|
| 921 |
-
'
|
| 922 |
-
'
|
| 923 |
-
'slim_busty': 'Стройное с пышной грудью',
|
| 924 |
-
'athletic': 'Атлетичное',
|
| 925 |
-
'petite': 'Миниатюрное',
|
| 926 |
-
'hourglass': 'Песочные часы',
|
| 927 |
-
'fit_curvy': 'Спортивное (curvy)',
|
| 928 |
-
'bombshell': 'Гипер-curvy',
|
| 929 |
-
'curvy': 'Мягкое (curvy)',
|
| 930 |
-
'full_figured': 'Плюс-сайз'
|
| 931 |
};
|
| 932 |
|
| 933 |
const maleBodyTypes = {
|
| 934 |
-
'athletic': 'Атлетичное',
|
| 935 |
-
'lean and toned': 'Поджарое',
|
| 936 |
-
'muscular build': 'Мускулистое',
|
| 937 |
-
'broad build': 'Крупное',
|
| 938 |
-
'slim build': 'Худощавое'
|
| 939 |
};
|
| 940 |
|
| 941 |
function switchMode(mode) {
|
|
@@ -962,7 +1016,7 @@ function populateBodyTypes() {
|
|
| 962 |
}
|
| 963 |
}
|
| 964 |
|
| 965 |
-
function populateStyles(containerId, styles) {
|
| 966 |
const container = document.getElementById(containerId);
|
| 967 |
container.innerHTML = '';
|
| 968 |
let isFirst = true;
|
|
@@ -975,7 +1029,7 @@ function populateStyles(containerId, styles) {
|
|
| 975 |
isFirst = false;
|
| 976 |
}
|
| 977 |
btn.dataset.value = key;
|
| 978 |
-
btn.textContent =
|
| 979 |
container.appendChild(btn);
|
| 980 |
}
|
| 981 |
}
|
|
@@ -983,14 +1037,19 @@ function populateStyles(containerId, styles) {
|
|
| 983 |
function setupClickableSelectors() {
|
| 984 |
document.querySelectorAll('.style-grid, .aspect-ratio-grid').forEach(container => {
|
| 985 |
container.addEventListener('click', (e) => {
|
| 986 |
-
|
|
|
|
| 987 |
container.querySelectorAll('.style-btn, .aspect-ratio-btn').forEach(innerBtn => innerBtn.classList.remove('active'));
|
| 988 |
-
|
| 989 |
}
|
| 990 |
});
|
| 991 |
});
|
| 992 |
}
|
| 993 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 994 |
function getPrompt() {
|
| 995 |
let prompt = `**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**
|
| 996 |
**STRICT DIRECTIVE: YOU ARE AN OPTICAL CLONING AND TEXTURE TRANSFER ENGINE.**
|
|
@@ -1003,9 +1062,12 @@ function getPrompt() {
|
|
| 1003 |
`;
|
| 1004 |
let aspectRatio = '';
|
| 1005 |
let additionalPrompt = '';
|
|
|
|
|
|
|
| 1006 |
|
| 1007 |
if (currentMode === 'model') {
|
| 1008 |
-
|
|
|
|
| 1009 |
const gender = document.getElementById('gender').value;
|
| 1010 |
const age = document.getElementById('age').value;
|
| 1011 |
const nationality = document.getElementById('nationality').value;
|
|
@@ -1016,13 +1078,14 @@ function getPrompt() {
|
|
| 1016 |
additionalPrompt = document.getElementById('additional_prompt').value;
|
| 1017 |
aspectRatio = document.querySelector('#aspectRatioSelectorModel .aspect-ratio-btn.active').dataset.value;
|
| 1018 |
|
| 1019 |
-
prompt += `\n**STYLE & MOOD:** High-quality professional fashion photography,
|
| 1020 |
prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard average build. ${bodyType} body type.`;
|
| 1021 |
prompt += `\n\n**CLOTHING:** The model is wearing: ${clothingDetails}.`;
|
| 1022 |
prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
|
| 1023 |
|
| 1024 |
} else if (currentMode === 'children') {
|
| 1025 |
-
|
|
|
|
| 1026 |
const gender = document.getElementById('child_gender').value;
|
| 1027 |
const age = document.getElementById('child_age').value;
|
| 1028 |
const nationality = document.getElementById('child_nationality').value;
|
|
@@ -1032,26 +1095,48 @@ function getPrompt() {
|
|
| 1032 |
additionalPrompt = document.getElementById('child_additional_prompt').value;
|
| 1033 |
aspectRatio = document.querySelector('#aspectRatioSelectorChildren .aspect-ratio-btn.active').dataset.value;
|
| 1034 |
|
| 1035 |
-
prompt += `\n**STYLE & MOOD:** High-quality professional fashion photography,
|
| 1036 |
prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard infant/child physique.`;
|
| 1037 |
prompt += `\n\n**CLOTHING:** The child is wearing: ${clothingDetails}.`;
|
| 1038 |
prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
|
| 1039 |
|
| 1040 |
-
} else {
|
| 1041 |
prompt = `**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**\n**PRODUCT PHOTOGRAPHY ENGINE.**\nPreserve the exact texture, color, and silhouette of the provided garment images with 20,000,000% fidelity.\n`;
|
| 1042 |
-
|
|
|
|
| 1043 |
const objectName = document.getElementById('object_name').value || "the product";
|
| 1044 |
additionalPrompt = document.getElementById('object_additional_prompt').value;
|
| 1045 |
aspectRatio = document.querySelector('#aspectRatioSelectorObject .aspect-ratio-btn.active').dataset.value;
|
| 1046 |
|
| 1047 |
-
prompt += `\n**SCENE CONFIGURATION:**\n- Mode: Flat lay / Hanging shoot\n- Style:
|
| 1048 |
-
prompt += `\n-
|
| 1049 |
}
|
| 1050 |
|
| 1051 |
if (additionalPrompt) {
|
| 1052 |
prompt += `\n\n**ADDITIONAL ARTISTIC DIRECTIVES:** ${additionalPrompt}`;
|
| 1053 |
}
|
| 1054 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1055 |
return `${envKeyword}, ${prompt} ${aspectRatio}`;
|
| 1056 |
}
|
| 1057 |
|
|
@@ -1084,9 +1169,9 @@ async function processAndOpen() {
|
|
| 1084 |
}
|
| 1085 |
|
| 1086 |
document.addEventListener('DOMContentLoaded', () => {
|
| 1087 |
-
populateStyles('styleSelector',
|
| 1088 |
-
populateStyles('childStyleSelector',
|
| 1089 |
-
populateStyles('objectStyleSelector',
|
| 1090 |
populateBodyTypes();
|
| 1091 |
setupClickableSelectors();
|
| 1092 |
switchMode('model');
|
|
|
|
| 570 |
letter-spacing: 0.8px;
|
| 571 |
}
|
| 572 |
|
| 573 |
+
input[type="text"], select, textarea {
|
| 574 |
padding: 12px 14px;
|
| 575 |
border: 1px solid var(--border);
|
| 576 |
border-radius: 8px;
|
|
|
|
| 583 |
box-sizing: border-box;
|
| 584 |
}
|
| 585 |
|
| 586 |
+
select:focus, textarea:focus, input[type="text"]:focus {
|
| 587 |
border-color: var(--primary);
|
| 588 |
box-shadow: 0 0 10px rgba(204, 255, 0, 0.2);
|
| 589 |
}
|
|
|
|
| 674 |
.aspect-ratio-btn.active { background-color: var(--primary); color: #000; border-color: var(--primary); box-shadow: 0 0 10px rgba(204, 255, 0, 0.3); }
|
| 675 |
.aspect-ratio-btn.active .preview { background: #000; }
|
| 676 |
|
| 677 |
+
.options-grid {
|
| 678 |
+
display: flex;
|
| 679 |
+
flex-direction: column;
|
| 680 |
+
gap: 12px;
|
| 681 |
+
background-color: var(--input-bg);
|
| 682 |
+
padding: 15px;
|
| 683 |
+
border-radius: 12px;
|
| 684 |
+
border: 1px solid var(--border);
|
| 685 |
+
}
|
| 686 |
+
.option-item {
|
| 687 |
+
display: flex;
|
| 688 |
+
align-items: center;
|
| 689 |
+
gap: 10px;
|
| 690 |
+
}
|
| 691 |
+
.option-item input[type="checkbox"] {
|
| 692 |
+
width: 20px;
|
| 693 |
+
height: 20px;
|
| 694 |
+
accent-color: var(--primary);
|
| 695 |
+
cursor: pointer;
|
| 696 |
+
flex-shrink: 0;
|
| 697 |
+
}
|
| 698 |
+
.option-item label {
|
| 699 |
+
margin-bottom: 0;
|
| 700 |
+
color: var(--text-secondary);
|
| 701 |
+
cursor: pointer;
|
| 702 |
+
font-weight: 500;
|
| 703 |
+
text-transform: none;
|
| 704 |
+
letter-spacing: 0;
|
| 705 |
+
}
|
| 706 |
+
|
| 707 |
@media (max-width: 600px) {
|
| 708 |
.form-grid, .style-grid { grid-template-columns: 1fr; }
|
| 709 |
.full-width { grid-column: span 1; }
|
|
|
|
| 889 |
<textarea id="object_additional_prompt" placeholder="Например: добавить инфографику 'new collection', левитация предмета"></textarea>
|
| 890 |
</div>
|
| 891 |
</div>
|
| 892 |
+
|
| 893 |
+
<div class="form-group full-width">
|
| 894 |
+
<label>Детали и Вариации</label>
|
| 895 |
+
<div class="options-grid">
|
| 896 |
+
<div class="option-item">
|
| 897 |
+
<input type="checkbox" id="detail_collage">
|
| 898 |
+
<label for="detail_collage">Коллаж с увеличенными деталями (ткань, фурнитура)</label>
|
| 899 |
+
</div>
|
| 900 |
+
<div class="option-item">
|
| 901 |
+
<input type="checkbox" id="text_overlay_check" onchange="toggleTextOverlayInput(this.checked)">
|
| 902 |
+
<label for="text_overlay_check">Наложение текста</label>
|
| 903 |
+
</div>
|
| 904 |
+
<div id="text_overlay_input_container" style="display: none; margin-top: 10px; padding-left: 30px;">
|
| 905 |
+
<input type="text" id="text_overlay_input" placeholder="Текст через запятую, например: New Collection, 100% Cotton">
|
| 906 |
+
</div>
|
| 907 |
+
<div class="option-item">
|
| 908 |
+
<input type="checkbox" id="color_variants">
|
| 909 |
+
<label for="color_variants">Разные варианты/цвета (коллаж)</label>
|
| 910 |
+
</div>
|
| 911 |
+
</div>
|
| 912 |
+
</div>
|
| 913 |
</div>
|
| 914 |
|
| 915 |
<div class="btn-container">
|
|
|
|
| 925 |
let currentMode = 'model';
|
| 926 |
const envKeyword = {{ keyword|tojson|safe }};
|
| 927 |
|
| 928 |
+
const styleNames = {
|
| 929 |
+
'studio': 'Студия (профи)', 'street': 'Стрит-стайл', 'lookbook': 'Лукбук (минимализм)', 'minimalism': 'Экстрим минимализм',
|
| 930 |
+
'selfie': 'Селфи (гиперреализм)', 'creative': 'Креативная съемка', 'new_year': 'Новый Год', 'retro': 'Ретро (35мм пленка)',
|
| 931 |
+
'boho': 'Бохо (золотой час)', 'gothic': 'Готика', 'editorial': 'Эдиториал (глянец)', 'film_noir': 'Фильм-нуар (Ч/Б)',
|
| 932 |
+
'cottagecore': 'Коттеджкор', 'royalcore': 'Роскошь (дворец)', 'solarpunk': 'Соларпанк', 'skater': 'Скейтер',
|
| 933 |
+
'baroque': 'Барокко', 'japandi': 'Джапанди', 'coastal': 'Прибрежный стиль', 'cyberpunk': 'Киберпанк',
|
| 934 |
+
'fantasy': 'Фэнтези', '90s_grunge': 'Гранж 90-х', 'techwear': 'Techwear', 'avant_garde': 'Авангард',
|
| 935 |
+
'home_casual': 'Домашний уют', 'social_media_candid': 'Инстаграм-фото', 'backstage': 'Бэкстейдж', 'road_trip': 'Роуд-трип',
|
| 936 |
+
'rainy_day': 'Дождливый день', 'night_flash': 'Ночь (вспышка)', 'golden_hour_picnic': 'Пикник (золотой час)'
|
| 937 |
+
};
|
| 938 |
+
|
| 939 |
+
const objectStyleNames = {
|
| 940 |
+
'studio': 'Студия (профи)', 'minimalism': 'Минимализм', 'nature': 'На природе', 'luxe': 'Лакшери', 'dark': 'Мрачный стиль'
|
| 941 |
+
};
|
| 942 |
+
|
| 943 |
+
const stylePrompts = {
|
| 944 |
+
'studio': 'профессиональная студийная фотография с динамичным, сложным освещением на бесшовном, текстурированном фоне (не просто белом).',
|
| 945 |
+
'street': 'динамичная стрит-стайл фотография в оживленной, аутентичной городской среде (например, Токио, Нью-Йорк). Кадр живой и полный движения.',
|
| 946 |
+
'lookbook': 'чистый, минималистичный стиль лукбука, на текстурированном нейтральном фоне, таком как бетон, лен или мягкий серый. Фокус на силуэте одежды.',
|
| 947 |
+
'minimalism': 'фото в стиле экстремального минимализма, с акцентом на форму и негативное пространство. Архитектурный, чистый фон с интересными тенями.',
|
| 948 |
+
'selfie': 'гиперреалистичный стиль селфи, как будто снято на флагманский смартфон. Естественная, интимная перспектива.',
|
| 949 |
+
'creative': 'ультра-креативная, авангардная концептуальная съемка, подобранная под суть продукта. Используйте неожиданный реквизит, драматическое освещение и образное, сюрреалистическое окружение.',
|
| 950 |
+
'new_year': 'праздничная новогодняя тема с огнями боке, конфетти и торжественной атмосферой.',
|
| 951 |
+
'retro': 'ретро-стиль, снятый с эмуляцией 35-мм пленки. Зернистая текстура, винтажная цветокоррекция и ностальгическое настроение.',
|
| 952 |
+
'boho': 'стиль бохо-шик, снятый в золотой час в естественной, деревенской обстановке, например, в поле или на пляже.',
|
| 953 |
+
'gothic': 'мрачный и атмосферный готический стиль. Снято в драматической, исторической архитектуре с освещением в стиле кьяроскуро.',
|
| 954 |
+
'editorial': 'глянцевый журнальный эдиториал на ярком, разноцветном фоне. Включите отражающие поверхности или зеркала, чтобы показать продукт с разных ракурсов.',
|
| 955 |
+
'film_noir': 'классический стиль фильм-нуар. Высококонтрастное черно-белое изображение, драматические тени и таинственное, кинематографическое настроение.',
|
| 956 |
+
'cottagecore': 'романтизированная эстетика коттеджкор. Снято в загородной местности с деревенским, идиллическим и естественным ощущением. Подумайте о полевых цветах и винтажном реквизите.',
|
| 957 |
+
'royalcore': 'роскошная эстетика роялкор. Снято в роскошном, дворцовом интерьере с деталями в стиле барокко, богатыми тканями и царственной атмосферой.',
|
| 958 |
+
'solarpunk': 'оптимистичный стиль соларпанк, сочетающий природу с футуристическими технологиями в яркой, устойчивой среде.',
|
| 959 |
+
'skater': 'аутентичный скейтерский стиль, снятый в городском скейтпарке или на улице. Широкоугольный объектив, динамичные позы.',
|
| 960 |
+
'baroque': 'драматический художественный стиль барокко. Богатые детали, глубокие цвета и интенсивная игра света и тени, напоминающая классическую живопись.',
|
| 961 |
+
'japandi': 'безмятежная обстановка в стиле джапанди, смесь японского деревенского минимализма и скандинавской функциональности. Нейтральные тона, натуральные материалы, такие как светлое дерево и бамбук, чистые линии.',
|
| 962 |
+
'coastal': 'легкий и расслабленный прибрежный стиль. Снято на пляже или в светлом приморском доме. Естественный свет, мягкие цвета.',
|
| 963 |
+
'cyberpunk': 'залитая неоном обстановка в стиле киберпанк. Футуристические городские пейзажи, светящиеся вывески и высокотехнологичное, антиутопическое настроение.',
|
| 964 |
+
'fantasy': 'эпическая фэнтезийная обстановка. Заколдованные леса, древние руины или мифические пейзажи.',
|
| 965 |
+
'90s_grunge': 'эстетика гранжа 90-х. Сырой, неотполированный вид, снятый в городской или промышленной среде с мрачным, бунтарским настроением.',
|
| 966 |
+
'techwear': 'элегантный стиль techwear. Футуристическая, городская среда с акцентом на функциональную, современную одежду. Чистые линии, часто ночью.',
|
| 967 |
+
'avant_garde': 'экспериментальная, авангардная фотография. Нестандартная композиция, абстрактные элементы и акцент на художественном выражении.',
|
| 968 |
+
'home_casual': 'уютная и непринужденная домашняя обстановка. Мягкое, естественное освещение, расслабленные позы и комфортное, обжитое ощущение.',
|
| 969 |
+
'social_media_candid': 'непринужденное фото в стиле Instagram. Выглядит спонтанно и аутентично, часто с элементом лайфстайла.',
|
| 970 |
+
'backstage': 'атмосфера за кулисами модного показа. Суетливая энергия, случайные моменты, видно профессиональное осветительное оборудование.',
|
| 971 |
+
'road_trip': 'атмосфера приключенческого автопутешествия. Снято в винтажном автомобиле или на фоне живописной, открытой дороги.',
|
| 972 |
+
'rainy_day': 'мрачная эстетика дождливого дня. Отражения на мокром асфальте, зонты и уютная или драматическая атмосфера.',
|
| 973 |
+
'night_flash': 'энергичный ночной снимок с использованием прямой вспышки. Создает резкие тени, насыщенные цвета и сырое, тусовочное ощущение.',
|
| 974 |
+
'golden_hour_picnic': 'идиллический пикник в золотой час. Теплое, мягкое освещение, расслабленная атмосфера в парке или поле.'
|
| 975 |
};
|
| 976 |
|
| 977 |
+
const objectStylePrompts = {
|
| 978 |
+
'studio': 'профессиональная студийная предметная фотография с динамическим освещением на бесшовном, текстурированном фоне.',
|
| 979 |
+
'minimalism': 'экстремальный минимализм, фокусирующийся на форме продукта на чистом, архитектурном фоне с мягкими тенями.',
|
| 980 |
+
'nature': 'продукт, представленный в естественной среде, которая его дополняет (например, на мхе, камне или среди листьев).',
|
| 981 |
+
'luxe': 'роскошная, элитная обстановка с богатыми текстурами, такими как мрамор, шелк или темное дерево. Роскошное и изысканное настроение.',
|
| 982 |
+
'dark': 'мрачная и атмосфер��ая предметная фотография. Драматическое, низкоключевое освещение, которое подчеркивает ключевые особенности продукта на темном фоне.'
|
| 983 |
};
|
| 984 |
|
| 985 |
const femaleBodyTypes = {
|
| 986 |
+
'standard': 'Стандартное', 'very_slim': 'Очень стройное (модель)', 'slim': 'Стройное (натуральное)', 'slim_busty': 'Стройное с пышной грудью',
|
| 987 |
+
'athletic': 'Атлетичное', 'petite': 'Миниатюрное', 'hourglass': 'Песочные часы', 'fit_curvy': 'Спортивное (curvy)',
|
| 988 |
+
'bombshell': 'Гипер-curvy', 'curvy': 'Мягкое (curvy)', 'full_figured': 'Плюс-сайз'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 989 |
};
|
| 990 |
|
| 991 |
const maleBodyTypes = {
|
| 992 |
+
'athletic': 'Атлетичное', 'lean and toned': 'Поджарое', 'muscular build': 'Мускулистое', 'broad build': 'Крупное', 'slim build': 'Худощавое'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
};
|
| 994 |
|
| 995 |
function switchMode(mode) {
|
|
|
|
| 1016 |
}
|
| 1017 |
}
|
| 1018 |
|
| 1019 |
+
function populateStyles(containerId, styles, styleNames) {
|
| 1020 |
const container = document.getElementById(containerId);
|
| 1021 |
container.innerHTML = '';
|
| 1022 |
let isFirst = true;
|
|
|
|
| 1029 |
isFirst = false;
|
| 1030 |
}
|
| 1031 |
btn.dataset.value = key;
|
| 1032 |
+
btn.textContent = styleNames[key];
|
| 1033 |
container.appendChild(btn);
|
| 1034 |
}
|
| 1035 |
}
|
|
|
|
| 1037 |
function setupClickableSelectors() {
|
| 1038 |
document.querySelectorAll('.style-grid, .aspect-ratio-grid').forEach(container => {
|
| 1039 |
container.addEventListener('click', (e) => {
|
| 1040 |
+
const button = e.target.closest('.style-btn, .aspect-ratio-btn');
|
| 1041 |
+
if (button) {
|
| 1042 |
container.querySelectorAll('.style-btn, .aspect-ratio-btn').forEach(innerBtn => innerBtn.classList.remove('active'));
|
| 1043 |
+
button.classList.add('active');
|
| 1044 |
}
|
| 1045 |
});
|
| 1046 |
});
|
| 1047 |
}
|
| 1048 |
|
| 1049 |
+
function toggleTextOverlayInput(isChecked) {
|
| 1050 |
+
document.getElementById('text_overlay_input_container').style.display = isChecked ? 'block' : 'none';
|
| 1051 |
+
}
|
| 1052 |
+
|
| 1053 |
function getPrompt() {
|
| 1054 |
let prompt = `**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**
|
| 1055 |
**STRICT DIRECTIVE: YOU ARE AN OPTICAL CLONING AND TEXTURE TRANSFER ENGINE.**
|
|
|
|
| 1062 |
`;
|
| 1063 |
let aspectRatio = '';
|
| 1064 |
let additionalPrompt = '';
|
| 1065 |
+
let styleKey = '';
|
| 1066 |
+
let stylePrompt = '';
|
| 1067 |
|
| 1068 |
if (currentMode === 'model') {
|
| 1069 |
+
styleKey = document.querySelector('#styleSelector .style-btn.active').dataset.value;
|
| 1070 |
+
stylePrompt = stylePrompts[styleKey];
|
| 1071 |
const gender = document.getElementById('gender').value;
|
| 1072 |
const age = document.getElementById('age').value;
|
| 1073 |
const nationality = document.getElementById('nationality').value;
|
|
|
|
| 1078 |
additionalPrompt = document.getElementById('additional_prompt').value;
|
| 1079 |
aspectRatio = document.querySelector('#aspectRatioSelectorModel .aspect-ratio-btn.active').dataset.value;
|
| 1080 |
|
| 1081 |
+
prompt += `\n**STYLE & MOOD:** High-quality professional fashion photography, ${stylePrompt}`;
|
| 1082 |
prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard average build. ${bodyType} body type.`;
|
| 1083 |
prompt += `\n\n**CLOTHING:** The model is wearing: ${clothingDetails}.`;
|
| 1084 |
prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
|
| 1085 |
|
| 1086 |
} else if (currentMode === 'children') {
|
| 1087 |
+
styleKey = document.querySelector('#childStyleSelector .style-btn.active').dataset.value;
|
| 1088 |
+
stylePrompt = stylePrompts[styleKey];
|
| 1089 |
const gender = document.getElementById('child_gender').value;
|
| 1090 |
const age = document.getElementById('child_age').value;
|
| 1091 |
const nationality = document.getElementById('child_nationality').value;
|
|
|
|
| 1095 |
additionalPrompt = document.getElementById('child_additional_prompt').value;
|
| 1096 |
aspectRatio = document.querySelector('#aspectRatioSelectorChildren .aspect-ratio-btn.active').dataset.value;
|
| 1097 |
|
| 1098 |
+
prompt += `\n**STYLE & MOOD:** High-quality professional fashion photography, ${stylePrompt}`;
|
| 1099 |
prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard infant/child physique.`;
|
| 1100 |
prompt += `\n\n**CLOTHING:** The child is wearing: ${clothingDetails}.`;
|
| 1101 |
prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
|
| 1102 |
|
| 1103 |
+
} else {
|
| 1104 |
prompt = `**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**\n**PRODUCT PHOTOGRAPHY ENGINE.**\nPreserve the exact texture, color, and silhouette of the provided garment images with 20,000,000% fidelity.\n`;
|
| 1105 |
+
styleKey = document.querySelector('#objectStyleSelector .style-btn.active').dataset.value;
|
| 1106 |
+
stylePrompt = objectStylePrompts[styleKey];
|
| 1107 |
const objectName = document.getElementById('object_name').value || "the product";
|
| 1108 |
additionalPrompt = document.getElementById('object_additional_prompt').value;
|
| 1109 |
aspectRatio = document.querySelector('#aspectRatioSelectorObject .aspect-ratio-btn.active').dataset.value;
|
| 1110 |
|
| 1111 |
+
prompt += `\n**SCENE CONFIGURATION:**\n- Mode: Flat lay / Hanging shoot\n- Style: ${stylePrompt}`;
|
| 1112 |
+
prompt += `\n- Product: ${objectName}`;
|
| 1113 |
}
|
| 1114 |
|
| 1115 |
if (additionalPrompt) {
|
| 1116 |
prompt += `\n\n**ADDITIONAL ARTISTIC DIRECTIVES:** ${additionalPrompt}`;
|
| 1117 |
}
|
| 1118 |
|
| 1119 |
+
let finalDirectives = [];
|
| 1120 |
+
|
| 1121 |
+
if (document.getElementById('detail_collage').checked) {
|
| 1122 |
+
finalDirectives.push('**OUTPUT FORMAT: E-COMMERCE COLLAGE.** Создайте основное изображение, показывающее полный наряд, и 2-3 меньших, круглых вставных изображения, сфокусированных на гипердетализированных крупных планах текстуры ткани, молний, пуговиц и швов. Общая композиция должна быть чистой и профессиональной для маркетплейса.');
|
| 1123 |
+
}
|
| 1124 |
+
|
| 1125 |
+
if (document.getElementById('color_variants').checked) {
|
| 1126 |
+
finalDirectives.push('**OUTPUT FORMAT: MULTI-VARIANT COLLAGE.** Сгенерируйте коллаж, отображающий один и тот же предмет в нескольких разных цветах или вариантах. Это можно сделать, показав несколько моделей бок о бок в одном кадре или создав чистую сеточную композицию из разных снимков продукта.');
|
| 1127 |
+
}
|
| 1128 |
+
|
| 1129 |
+
if (document.getElementById('text_overlay_check').checked) {
|
| 1130 |
+
const textToOverlay = document.getElementById('text_overlay_input').value;
|
| 1131 |
+
if (textToOverlay) {
|
| 1132 |
+
finalDirectives.push(`**GRAPHIC OVERLAY:** Наложите следующие ключевые слова на изображение стильным, современным шрифтом с дополняющими иконками или минималистичными графическими элементами: "${textToOverlay}". Текст должен быть хорошо интегрирован в композицию и эстетически приятен.`);
|
| 1133 |
+
}
|
| 1134 |
+
}
|
| 1135 |
+
|
| 1136 |
+
if(finalDirectives.length > 0){
|
| 1137 |
+
prompt += `\n\n**FINAL OUTPUT DIRECTIVES:**\n- ${finalDirectives.join('\n- ')}`;
|
| 1138 |
+
}
|
| 1139 |
+
|
| 1140 |
return `${envKeyword}, ${prompt} ${aspectRatio}`;
|
| 1141 |
}
|
| 1142 |
|
|
|
|
| 1169 |
}
|
| 1170 |
|
| 1171 |
document.addEventListener('DOMContentLoaded', () => {
|
| 1172 |
+
populateStyles('styleSelector', stylePrompts, styleNames);
|
| 1173 |
+
populateStyles('childStyleSelector', stylePrompts, styleNames);
|
| 1174 |
+
populateStyles('objectStyleSelector', objectStylePrompts, objectStyleNames);
|
| 1175 |
populateBodyTypes();
|
| 1176 |
setupClickableSelectors();
|
| 1177 |
switchMode('model');
|