Kgshop commited on
Commit
9fd0766
·
verified ·
1 Parent(s): f3b281b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -149
app.py CHANGED
@@ -21,8 +21,9 @@ app = Flask(__name__)
21
  app.secret_key = 'your_unique_secret_key_gippo_312_shop_54321_no_login_synkris'
22
  DATA_FILE = 'data.json'
23
  DATA_FILE_TEMP = 'data.json.tmp'
 
24
 
25
- SYNC_FILES = [DATA_FILE]
26
 
27
  REPO_ID = "Kgshop/synkristest"
28
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
@@ -33,6 +34,77 @@ DOWNLOAD_DELAY = 5
33
 
34
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWNLOAD_DELAY):
37
  if not HF_TOKEN_READ and not HF_TOKEN_WRITE:
38
  return False
@@ -65,6 +137,8 @@ def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWN
65
  if file_name == DATA_FILE:
66
  with open(file_name, 'w', encoding='utf-8') as f:
67
  json.dump({}, f)
 
 
68
  except Exception:
69
  pass
70
  success = True
@@ -758,20 +832,20 @@ textarea {
758
  <div class="form-group">
759
  <label for="shotType">Ракурс/План</label>
760
  <select id="shotType">
761
- <option value="Full body shot">В полный рост</option>
762
- <option value="Medium shot, waist up">По пояс</option>
763
- <option value="Cowboy shot, mid-thigh up">"Ковбойский" план</option>
764
- <option value="Portrait shot">Портрет</option>
765
  </select>
766
  </div>
767
  <div class="form-group">
768
  <label for="pose">Поза</label>
769
  <select id="pose">
770
- <option value="standing confidently">Стоит уверенно</option>
771
- <option value="walking towards camera">Идет на камеру</option>
772
- <option value="sitting relaxed">Сидит расслабленно</option>
773
- <option value="leaning against a wall">Оперевшись о стену</option>
774
- <option value="dynamic high fashion editorial pose" selected>Динамичная поза</option>
775
  </select>
776
  </div>
777
  <div class="form-group full-width">
@@ -801,17 +875,17 @@ textarea {
801
  <div class="form-group">
802
  <label for="child_gender">Пол</label>
803
  <select id="child_gender">
804
- <option value="female">Девочка</option>
805
- <option value="male">Мальчик</option>
806
  </select>
807
  </div>
808
  <div class="form-group">
809
  <label for="child_age">Возраст</label>
810
  <select id="child_age">
811
- <option value="infant">0-12 месяцев</option>
812
- <option value="preschooler">1-4 года</option>
813
- <option value="schoolchild">5-12 лет</option>
814
- <option value="teenager">13-17 лет</option>
815
  </select>
816
  </div>
817
  <div class="form-group">
@@ -825,18 +899,19 @@ textarea {
825
  <div class="form-group">
826
  <label for="child_shotType">Ракурс/План</label>
827
  <select id="child_shotType">
828
- <option value="Full body shot">В полный рост</option>
829
- <option value="Medium shot, waist up">По пояс</option>
830
- <option value="Portrait shot">Портрет</option>
831
  </select>
832
  </div>
833
  <div class="form-group full-width">
834
  <label for="child_pose">Поза/Действие</label>
835
  <select id="child_pose">
836
- <option value="running in a field">Бежит по полю</option>
837
- <option value="playing with toys">Играет с игрушками</option>
838
- <option value="sitting and reading a book">Сидит с книгой</option>
839
- <option value="posing for a school photo">Позирует для фото</option>
 
840
  </select>
841
  </div>
842
  <div class="form-group full-width">
@@ -921,113 +996,36 @@ textarea {
921
  <script>
922
  let currentMode = 'model';
923
  const envKeyword = {{ keyword|tojson|safe }};
 
924
 
925
  const flagshipStyles = {
926
- 'studio': 'Студия (профи)',
927
- 'street': 'Стрит-стайл',
928
- 'lookbook': 'Лукбук (минимализм)',
929
- 'minimalism': 'Экстрим минимализм',
930
- 'selfie': 'Селфи (гиперреализм)',
931
- 'creative': 'Креативная съемка',
932
- 'new_year': 'Новый Год',
933
- 'retro': 'Ретро (35мм пленка)',
934
- 'boho': 'Бохо (золотой час)',
935
- 'gothic': 'Готика',
936
- 'editorial': 'Эдиториал (глянец)',
937
- 'film_noir': 'Фильм-нуар (Ч/Б)',
938
- 'cottagecore': 'Коттеджкор',
939
- 'royalcore': 'Роскошь (дворец)',
940
- 'solarpunk': 'Соларпанк',
941
- 'skater': 'Скейтер',
942
- 'baroque': 'Барокко',
943
- 'japandi': 'Джапанди',
944
- 'coastal': 'Прибрежный стиль',
945
- 'cyberpunk': 'Киберпанк',
946
- 'fantasy': 'Фэнтези',
947
- '90s_grunge': 'Гранж 90-х',
948
- 'techwear': 'Techwear',
949
- 'avant_garde': 'Авангард',
950
- 'home_casual': 'Домашний уют',
951
- 'social_media_candid': 'Инстаграм-фото',
952
- 'backstage': 'Бэкстейдж',
953
- 'road_trip': 'Роуд-трип',
954
- 'rainy_day': 'Дождливый день',
955
- 'night_flash': 'Ночь (вспышка)',
956
- 'golden_hour_picnic': 'Пикник (золотой час)'
957
- };
958
-
959
- const flagshipStylePrompts = {
960
- 'studio': 'Профессиональная студийная съемка с идеальным освещением на циклораме нейтрального цвета (серый, бежевый).',
961
- 'street': 'Динамичная уличная фотография в оживленном мегаполисе (например, Токио, Нью-Йорк), естественное городское освещение, эффект движения.',
962
- 'lookbook': 'Минималистичная лукбук-съемка на простом, текстурном фоне (например, бетон, цветной бумажный фон), мягкий рассеянный свет.',
963
- 'minimalism': 'Экстремальный минимализм. Объект съемки на фоне архитектуры из грубого бетона или гипса с одной драматичной тенью.',
964
- 'selfie': 'Гиперреалистичное селфи, снятое на смартфон в интересной локации (например, в з��ркале лифта, в кафе), с естественными отражениями и бликами.',
965
- 'creative': 'Максимально креативная и художественная концептуальная съемка. Фон, реквизит и свет подбираются индивидуально, чтобы наилучшим образом раскрыть суть товара.',
966
- 'new_year': 'Атмосферная новогодняя съемка с боке от гирлянд, бенгальскими огнями, на фоне украшенной елки или заснеженного пейзажа.',
967
- 'retro': 'Стилизация под ретро-фото, снятое на 35-мм пленку. Характерное зерно, теплые цвета, легкие потертости, атмосфера 70-х или 80-х.',
968
- 'boho': 'Стиль бохо, снятый в "золотой час" на природе. Мягкий, теплый свет, полевые цветы, натуральные ткани, расслабленная атмосфера.',
969
- 'gothic': 'Готическая атмосфера, съемка в старинном здании с арками, витражами. Приглушенный свет, драматичные тени, таинственное настроение.',
970
- 'editorial': 'Глянцевая журнальная съемка (эдиториал) на ярком, цветном фоне. В кадре присутствуют зеркала, отражающие модель и товар с разных ракурсов.',
971
- 'film_noir': 'Черно-белая стилизация под фильм-нуар. Высокий контраст, драматичные тени, атмосфера старого Голливуда, эффект дождя или дымки.',
972
- 'cottagecore': 'Эстетика коттеджкор. Съемка в деревенском доме или в саду, уютная идиллическая атмосфера, натуральные материалы, полевые цветы.',
973
- 'royalcore': 'Эстетика роскоши и королевского стиля. Интерьеры дворца, лепнина, бархат, позолота, величественная и аристократичная атмосфера.',
974
- 'solarpunk': 'Оптимистичное будущее в стиле соларпанк. Футуристическая архитектура, интегрированная с природой, много света и зелени.',
975
- 'skater': 'Скейтерская эстетика. Съемка в скейт-парке или на городских улицах, динамичные позы, широкие углы, энергия и молодость.',
976
- 'baroque': 'Стиль барокко. Пышные декорации, изобилие деталей, драматический свет, как на картинах Караваджо, глубокие насыщенные цвета.',
977
- 'japandi': 'Стиль "Джапанди": сочетание японского минимализма и скандинавской функциональности. Светлое дерево, нейтральные тона, чистые линии, натуральные текстуры.',
978
- 'coastal': 'Прибрежный стиль. Съемка на берегу моря или океана, светлые тона, натуральные материалы (лен, хлопок), легкий бриз, расслабленное настроение.',
979
- 'cyberpunk': 'Киберпанк. Неоновые огни ночного города, футуристические элементы, высокая детализация, атмосфера технологичного будущего.',
980
- 'fantasy': 'Фэнтезийная съемка в сказочном лесу или в руинах замка. Волшебная атмосфера, необычное освещение, элементы мистики.',
981
- '90s_grunge': 'Гранж 90-х. Урбанистические пейзажи, заброшенные здания, приглушенные цвета, небрежный стиль, бунтарский дух.',
982
- 'techwear': 'Функциональная одежда в стиле Techwear. Городская среда, футуристическая архитектура, акцент на деталях и материалах одежды.',
983
- 'avant_garde': 'Авангардная съемка с необычными формами, смелыми цветовыми решениями и нестандартной композицией. Экспериментальный и художественный подход.',
984
- 'home_casual': 'Уютная домашняя съемка. Мягкий естественный свет из окна, комфортная обстановка, пледы, книги, атмосфера отдыха.',
985
- 'social_media_candid': 'Живое, "случайное" фото в стиле Instagram. Естественные позы, съемка в кафе, на прогулке, создается ощущение подсмотренного момента.',
986
- 'backstage': 'Атмосфера бэкстейджа модного показа. Подготовка моделей, стойки с одеждой, приглушенный свет, суета и творческий беспорядок.',
987
- 'road_trip': 'Эстетика дорожного путешествия. Съемка у машины на фоне заката, пустынные пейзажи, ощущение свободы и приключений.',
988
- 'rainy_day': 'Съемка в дождливый день. Отражения в лужах, блики от мокрого асфальта, зонты, меланхоличное и романтичное настроение.',
989
- 'night_flash': 'Ночная съемка с жесткой вспышкой "в лоб". Высокий контраст, пересвеченные детали, эффект моментального снимка, клубная атмосфера.',
990
- 'golden_hour_picnic': 'Пикник в "золотой час". Теплый, мягкий свет заката, красивая сервировка на пледе, фрукты, расслабленная и романтичная атмосфера.'
991
  };
992
 
993
-
994
  const objectStyles = {
995
- 'studio': 'Студия (профи)',
996
- 'minimalism': 'Минимализм',
997
- 'nature': 'На природе',
998
- 'luxe': 'Лакшери',
999
- 'dark': 'Мрачный стиль'
1000
- };
1001
-
1002
- const objectStylePrompts = {
1003
- 'studio': 'Профессиональная предметная съемка в студии на бесшовном фоне нейтрального цвета, с идеальной схемой света, подчеркивающей форму и текстуру.',
1004
- 'minimalism': 'Минималистичная композиция на текстурном фоне (бетон, мрамор, песок) с одной жесткой тенью, создающей графичность.',
1005
- 'nature': 'Предмет расположен в естественной природной среде, которая дополняет его (например, на мху в лесу, на камнях у воды, среди цветов).',
1006
- 'luxe': 'Лакшери-съемка на фоне шелка, бархата или темного мрамора. Приглушенный свет, золотые акценты, атмосфера роскоши и эксклюзивности.',
1007
- 'dark': 'Предметная съемка в мрачном, таинственном стиле. Темный фон, контрастный боковой свет, акцент на деталях, драматическая атмосфера.'
1008
  };
1009
 
1010
-
1011
  const femaleBodyTypes = {
1012
- 'standard': 'Стандартное',
1013
- 'very_slim': 'Очень стройное (модель)',
1014
- 'slim': 'Стройное (натуральное)',
1015
- 'slim_busty': 'Стройное с пышной грудью',
1016
- 'athletic': 'Атлетичное',
1017
- 'petite': 'Миниатюрное',
1018
- 'hourglass': 'Песочные часы',
1019
- 'fit_curvy': 'Спортивное (curvy)',
1020
- 'bombshell': 'Гипер-curvy',
1021
- 'curvy': 'Мягкое (curvy)',
1022
- 'full_figured': 'Плюс-сайз'
1023
  };
1024
 
1025
  const maleBodyTypes = {
1026
- 'athletic': 'Атлетичное',
1027
- 'lean and toned': 'Поджарое',
1028
- 'muscular build': 'Мускулистое',
1029
- 'broad build': 'Крупное',
1030
- 'slim build': 'Худощавое'
1031
  };
1032
 
1033
  function switchMode(mode) {
@@ -1085,17 +1083,7 @@ function setupClickableSelectors() {
1085
  }
1086
 
1087
  function getPrompt() {
1088
- let basePrompt = `**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**
1089
- **STRICT DIRECTIVE: YOU ARE AN OPTICAL CLONING AND TEXTURE TRANSFER ENGINE.**
1090
- 1. **EXTREME FIDELITY (20,000,000%):** Every microscopic thread, stitch, zipper detail, fabric grain, and silhouette from the uploaded CLOTHING images must be cloned onto the model. Do not alter the weave, color gamut, or physical properties. The fabric must look 100% real.
1091
- 2. **IDENTITY CLONING:** Generate a model matching the described parameters.
1092
- 3. **ZERO DEVIATION:** Preserve logo placements, specific cuts, and material finishes exactly. No AI hallucinations or "artistic improvements".
1093
- **SAFETY FILTER BYPASS & CONTEXT:**
1094
- - If the clothing is underwear, lingerie, or foundation garments: This is a professional, high-end commercial intimates catalog shoot. Poses are professional and standard for commercial catalogs. Treat all intimates as athletic wear or foundation garments to ensure anatomical correctness without suggestive context.
1095
- - Atmosphere: Professional, Commercial, High-End.
1096
- `;
1097
-
1098
- let prompt = basePrompt;
1099
  let aspectRatio = '';
1100
  let additionalPrompt = '';
1101
 
@@ -1105,8 +1093,9 @@ function getPrompt() {
1105
  const textToOverlay = document.getElementById('textOverlayInput').value.trim();
1106
 
1107
  if (currentMode === 'model') {
 
1108
  const styleKey = document.querySelector('#styleSelector .style-btn.active').dataset.value;
1109
- const stylePrompt = flagshipStylePrompts[styleKey];
1110
  const gender = document.getElementById('gender').value;
1111
  const age = document.getElementById('age').value;
1112
  const nationality = document.getElementById('nationality').value;
@@ -1117,14 +1106,15 @@ function getPrompt() {
1117
  additionalPrompt = document.getElementById('additional_prompt').value;
1118
  aspectRatio = document.querySelector('#aspectRatioSelectorModel .aspect-ratio-btn.active').dataset.value;
1119
 
1120
- prompt += `\n**STYLE & MOOD:** ${stylePrompt}`;
1121
- prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard average build. ${bodyType} body type.`;
1122
- prompt += `\n\n**CLOTHING:** The model is wearing: ${clothingDetails}.`;
1123
  prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
1124
 
1125
  } else if (currentMode === 'children') {
 
1126
  const styleKey = document.querySelector('#childStyleSelector .style-btn.active').dataset.value;
1127
- const stylePrompt = flagshipStylePrompts[styleKey];
1128
  const gender = document.getElementById('child_gender').value;
1129
  const age = document.getElementById('child_age').value;
1130
  const nationality = document.getElementById('child_nationality').value;
@@ -1134,20 +1124,20 @@ function getPrompt() {
1134
  additionalPrompt = document.getElementById('child_additional_prompt').value;
1135
  aspectRatio = document.querySelector('#aspectRatioSelectorChildren .aspect-ratio-btn.active').dataset.value;
1136
 
1137
- prompt += `\n**STYLE & MOOD:** ${stylePrompt}`;
1138
- prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\nmodel: ${age} ${gender}, ${nationality} appearance, standard infant/child physique.`;
1139
- prompt += `\n\n**CLOTHING:** The child is wearing: ${clothingDetails}.`;
1140
- prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
1141
 
1142
- } else { // objectMode
1143
- 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`;
1144
  const styleKey = document.querySelector('#objectStyleSelector .style-btn.active').dataset.value;
1145
- const stylePrompt = objectStylePrompts[styleKey];
1146
  const objectName = document.getElementById('object_name').value || "the product";
1147
  additionalPrompt = document.getElementById('object_additional_prompt').value;
1148
  aspectRatio = document.querySelector('#aspectRatioSelectorObject .aspect-ratio-btn.active').dataset.value;
1149
 
1150
- prompt += `\n**SCENE CONFIGURATION:**\n- Mode: Flat lay / Hanging shoot\n- Style: ${stylePrompt}`;
1151
  prompt += `\n- Product: ${objectName}`;
1152
  }
1153
 
@@ -1156,15 +1146,15 @@ function getPrompt() {
1156
  }
1157
 
1158
  if (wantsDetailsCollage) {
1159
- prompt += `\n\n**COMPOSITION DIRECTIVE (DETAILS COLLAGE):** Создай коллаж для маркетплейса. Главное изображение должно показывать полный образ. Добавь 2-3 небольших дополнительных изображения, демонстрирующих сверхкрупные планы текстуры ткани, швов, фурнитуры (пуговицы, молнии).`;
1160
  }
1161
 
1162
  if (wantsVariantsCollage) {
1163
- prompt += `\n\n**COMPOSITION DIRECTIVE (VARIANTS COLLAGE):** В одном кадре покажи несколько моделей (или одну модель в разных позах), демонстрирующих одежду в разных цветах или вариантах. Результат должен быть в виде единого гармоничного коллажа.`;
1164
  }
1165
 
1166
  if (wantsTextOverlay && textToOverlay) {
1167
- prompt += `\n\n**GRAPHIC OVERLAY:** Добавь следующий текст: "${textToOverlay}". Интегрируй его в изображение, используя стильную, современную типографику. Можно использовать минималистичные иконки, дополняющие текст и общую эстетику. Текст должен быть читаемым, но художественно расположенным.`;
1168
  }
1169
 
1170
  return `${envKeyword}, ${prompt} ${aspectRatio}`;
@@ -1365,6 +1355,7 @@ def serve_env(env_id):
1365
 
1366
  keyword = env_data.get("keyword", "")
1367
  env_type = env_data.get("type", "closed")
 
1368
 
1369
  current_log = {
1370
  "time": datetime.utcnow().isoformat(),
@@ -1384,7 +1375,7 @@ def serve_env(env_id):
1384
  save_data(data)
1385
 
1386
  if env_type == 'open':
1387
- return render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword)
1388
 
1389
  stored_token = env_data.get("device_token")
1390
  user_token = request.cookies.get(f'access_token_{env_id}')
@@ -1413,18 +1404,19 @@ def serve_env(env_id):
1413
  </body>
1414
  </html>
1415
  """, 403
1416
- return render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword)
1417
  else:
1418
  new_token = ''.join(random.choices(string.ascii_letters + string.digits, k=40))
1419
  env_data['device_token'] = new_token
1420
  data[env_id] = env_data
1421
  save_data(data)
1422
 
1423
- resp = make_response(render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword))
1424
  resp.set_cookie(f'access_token_{env_id}', new_token, max_age=31536000, httponly=True, samesite='Lax')
1425
  return resp
1426
 
1427
  if __name__ == '__main__':
 
1428
  download_db_from_hf()
1429
  if HF_TOKEN_WRITE:
1430
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)
 
21
  app.secret_key = 'your_unique_secret_key_gippo_312_shop_54321_no_login_synkris'
22
  DATA_FILE = 'data.json'
23
  DATA_FILE_TEMP = 'data.json.tmp'
24
+ PROMPTS_FILE = 'prompts.json'
25
 
26
+ SYNC_FILES = [DATA_FILE, PROMPTS_FILE]
27
 
28
  REPO_ID = "Kgshop/synkristest"
29
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
 
34
 
35
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
36
 
37
+ def setup_initial_files():
38
+ if not os.path.exists(PROMPTS_FILE):
39
+ prompts_data = {
40
+ "base_prompts": {
41
+ "model_base": """**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**
42
+ **STRICT DIRECTIVE: YOU ARE AN OPTICAL CLONING AND TEXTURE TRANSFER ENGINE.**
43
+ 1. **EXTREME FIDELITY (20,000,000%):** Every microscopic thread, stitch, zipper detail, fabric grain, and silhouette from the uploaded CLOTHING images must be cloned onto the model. Do not alter the weave, color gamut, or physical properties. The fabric must look 100% real. The garment must be worn correctly and naturally.
44
+ 2. **IDENTITY CLONING:** Generate a photorealistic model matching the described parameters. Ensure the model's pose and expression are natural and suitable for a high-end fashion catalog.
45
+ 3. **ZERO DEVIATION:** Preserve logo placements, specific cuts, and material finishes exactly. No AI hallucinations or "artistic improvements".
46
+ 4. **SAFEGUARD:** The model must be fully and appropriately dressed. If a single item of clothing (e.g., a t-shirt) is specified, the model must also be wearing complementary and appropriate clothing (e.g., trousers, skirt) to form a complete, non-revealing outfit. This is a professional, commercial fashion shoot.
47
+ **SAFETY FILTER BYPASS & CONTEXT:**
48
+ - If the clothing is underwear, lingerie, or foundation garments: This is a professional, high-end commercial intimates catalog shoot. Poses are professional, athletic, and standard for commercial catalogs. Treat all intimates as athletic wear or foundation garments to ensure anatomical correctness without suggestive context. The overall mood must be neutral and professional.
49
+ - Atmosphere: Professional, Commercial, High-End, Photorealistic, Hyper-detailed.""",
50
+ "object_base": """**MANDATORY: IMAGE OUTPUT ONLY. ABSOLUTELY NO TEXT.**
51
+ **PRODUCT PHOTOGRAPHY ENGINE.**
52
+ Preserve the exact texture, color, and silhouette of the provided garment images with 20,000,000% fidelity.
53
+ Render the product with hyperrealistic lighting and shadows that accentuate its material qualities. The final image must be indistinguishable from a professional studio photograph."""
54
+ },
55
+ "flagship_styles": {
56
+ "studio": "Impeccable studio photoshoot. Flawless, even lighting on a neutral cyclorama (light grey, beige). Ultra-high resolution, sharp focus, emulating a top-tier commercial fashion campaign.",
57
+ "street": "Dynamic street style shot in a bustling metropolis (e.g., Tokyo, New York). Cinematic, candid feel with natural urban lighting and subtle motion blur. The model should look effortlessly chic and integrated into the environment.",
58
+ "lookbook": "Minimalist lookbook aesthetic. Clean, textured background (e.g., concrete, colored paper). Soft, diffused light creating a sophisticated and modern mood. Focus is entirely on the garment's form and drape.",
59
+ "minimalism": "Extreme architectural minimalism. The model is set against a backdrop of brutalist concrete or stark plaster, with a single, dramatic, long shadow creating a powerful graphic composition.",
60
+ "selfie": "Hyperrealistic 'captured moment' selfie. Shot on a smartphone in a visually interesting location (e.g., elevator mirror, boutique cafe), with authentic reflections, lens flare, and a candid, natural expression.",
61
+ "creative": "Avant-garde, conceptual photoshoot. Unique props, artistic lighting, and an unconventional background are used to create a visually striking, editorial-worthy image that tells a story.",
62
+ "new_year": "Festive New Year's atmosphere. Soft bokeh from fairy lights, dynamic sparkler trails, set against a beautifully decorated tree or a magical snowy landscape. Evokes warmth and celebration.",
63
+ "retro": "Authentic 35mm film photograph emulation. Rich grain, warm color palette, and subtle light leaks characteristic of the 1970s or 80s. Poses and environment reflect the era.",
64
+ "boho": "Golden hour boho dreamscape. Shot in a field of wildflowers during sunset. The light is warm, soft, and glowing, highlighting natural textures and creating a serene, free-spirited vibe.",
65
+ "gothic": "Moody, gothic romance. Set in ancient, atmospheric architecture like a cathedral or castle ruins. Low-key lighting, deep shadows, and a sense of mystery and drama.",
66
+ "editorial": "High-fashion glossy magazine editorial. Bold, saturated colored background. Clever use of mirrors to create compelling reflections and fragmented views of the model and outfit.",
67
+ "film_noir": "Cinematic black and white film noir. High contrast, dramatic 'chiaroscuro' lighting, with long shadows and a sense of suspense. May incorporate atmospheric elements like rain or fog.",
68
+ "cottagecore": "Idyllic cottagecore aesthetic. A cozy, rustic setting in a country house or lush garden. Natural light, organic textures, and a feeling of wholesome, romanticized rural life.",
69
+ "royalcore": "Opulent royalcore aesthetic. Set in a lavish palace interior with ornate details, velvet curtains, and gilded furniture. The lighting is grand and dramatic, creating an air of aristocracy.",
70
+ "solarpunk": "Optimistic solarpunk future. Sleek, futuristic architecture seamlessly integrated with lush greenery. Bright, clean light fills the scene, suggesting a harmonious, tech-advanced society.",
71
+ "skater": "Energetic skater aesthetic. Wide-angle, dynamic shot in a skate park or on urban streets. Captures movement and a raw, youthful, counter-culture energy.",
72
+ "baroque": "Dramatic Baroque painting style. Ornate, detailed setting with rich fabrics. Lighting is high-contrast and theatrical, reminiscent of a Caravaggio masterpiece, creating deep, intense colors.",
73
+ "japandi": "Serene Japandi style. A fusion of Japanese minimalism and Scandinavian functionality. Clean lines, neutral tones, natural wood, and a focus on tranquility and uncluttered space.",
74
+ "coastal": "Relaxed coastal grandmother style. Bright, airy setting by the sea. A palette of whites, beiges, and soft blues. Natural materials and a feeling of effortless seaside elegance.",
75
+ "cyberpunk": "Gritty, neon-drenched cyberpunk cityscape. High-tech, futuristic elements, with reflections from neon signs on wet streets. A cool color palette and a sense of urban dystopia.",
76
+ "fantasy": "Enchanting fantasy world. A magical forest, ancient ruins, or ethereal landscape. The lighting is mystical and otherworldly, creating a dreamlike, narrative-driven image.",
77
+ "90s_grunge": "Raw 90s grunge aesthetic. Urban decay, abandoned locations, with a desaturated color palette. A feeling of angst, rebellion, and effortless, non-conformist style.",
78
+ "techwear": "Sleek, functional Techwear style. Set against futuristic, urban architecture. The lighting is clean and sharp, highlighting the technical details, fabrics, and functionality of the garments.",
79
+ "avant_garde": "Experimental avant-garde fashion. Abstract shapes, bold color clashes, and unconventional compositions. A highly artistic and conceptual approach that challenges traditional aesthetics.",
80
+ "home_casual": "Cozy, authentic home setting. Soft, natural light streaming through a window. A relaxed, intimate atmosphere with books, plants, and comfortable furnishings.",
81
+ "social_media_candid": "Candid, 'Instagrammable' moment. Shot in a trendy cafe or during a walk. Looks spontaneous and natural, as if capturing a real moment in time.",
82
+ "backstage": "Hectic, atmospheric backstage of a fashion show. Racks of clothes, makeup stations, and focused energy. The lighting is functional but chaotic, creating a 'behind-the-scenes' narrative.",
83
+ "road_trip": "Cinematic American road trip aesthetic. The model is near a vintage car against a vast, open landscape at sunset. A sense of freedom, adventure, and nostalgia.",
84
+ "rainy_day": "Romantic, melancholic rainy day scene. Reflections on wet pavement, droplets on windows, and the soft, diffused light of an overcast sky. A cozy and introspective mood.",
85
+ "night_flash": "Edgy, direct-flash night photography. High contrast, saturated colors, and sharp shadows. Creates a raw, spontaneous, 'paparazzi' or party-snapshot feel.",
86
+ "golden_hour_picnic": "Idyllic golden hour picnic. Warm, glowing sunset light filters through trees. A beautifully styled picnic scene with a relaxed, romantic, and joyful atmosphere."
87
+ },
88
+ "object_styles": {
89
+ "studio": "Professional product photography on a seamless, neutral background. Perfect, multi-point lighting that eliminates harsh shadows and reveals every detail of the product's texture and form.",
90
+ "minimalism": "Minimalist composition on a textured surface like concrete, marble, or fine sand. A single, crisp, hard light source creates a graphic, artistic shadow, emphasizing the product's silhouette.",
91
+ "nature": "The product is artfully placed in a complementary natural environment. E.g., on mossy rocks in a forest, beside a clear stream, or nestled among flowers. The lighting is natural and enhances the organic feel.",
92
+ "luxe": "Luxury still life. The product is arranged on a rich, tactile surface like silk, velvet, or dark marble. The lighting is low-key and sophisticated, with soft highlights that suggest opulence and exclusivity.",
93
+ "dark": "Moody and dramatic 'dark academia' style. The product is set against a dark, textured background. A single, directional light source carves the product out of the shadows, creating a mysterious and intense atmosphere."
94
+ }
95
+ }
96
+ with open(PROMPTS_FILE, 'w', encoding='utf-8') as f:
97
+ json.dump(prompts_data, f, ensure_ascii=False, indent=4)
98
+
99
+ def load_prompts():
100
+ if not os.path.exists(PROMPTS_FILE):
101
+ setup_initial_files()
102
+ try:
103
+ with open(PROMPTS_FILE, 'r', encoding='utf-8') as f:
104
+ return json.load(f)
105
+ except (FileNotFoundError, json.JSONDecodeError):
106
+ return {}
107
+
108
  def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWNLOAD_DELAY):
109
  if not HF_TOKEN_READ and not HF_TOKEN_WRITE:
110
  return False
 
137
  if file_name == DATA_FILE:
138
  with open(file_name, 'w', encoding='utf-8') as f:
139
  json.dump({}, f)
140
+ elif file_name == PROMPTS_FILE:
141
+ setup_initial_files()
142
  except Exception:
143
  pass
144
  success = True
 
832
  <div class="form-group">
833
  <label for="shotType">Ракурс/План</label>
834
  <select id="shotType">
835
+ <option value="Full body shot, dynamic angle">В полный рост, динамичный ракурс</option>
836
+ <option value="Medium shot, waist up, candid">По пояс, естественный</option>
837
+ <option value="Cowboy shot, mid-thigh up, fashion editorial style">"Ковбойский" план, журнальный</option>
838
+ <option value="Expressive portrait shot, detailed">Портрет, выразительный</option>
839
  </select>
840
  </div>
841
  <div class="form-group">
842
  <label for="pose">Поза</label>
843
  <select id="pose">
844
+ <option value="standing confidently, looking at camera">Стоит уверенно, взгляд в камеру</option>
845
+ <option value="dynamic walking pose, slight motion blur">Динамичная походка, легкое размытие</option>
846
+ <option value="sitting relaxed on a modern chair">Сидит расслабленно на стуле</option>
847
+ <option value="leaning casually against a textured wall">Небрежно оперевшись о стену</option>
848
+ <option value="dynamic high fashion editorial pose, unconventional">Динамичная, нестандартная фэшн-поза</option>
849
  </select>
850
  </div>
851
  <div class="form-group full-width">
 
875
  <div class="form-group">
876
  <label for="child_gender">Пол</label>
877
  <select id="child_gender">
878
+ <option value="girl">Девочка</option>
879
+ <option value="boy">Мальчик</option>
880
  </select>
881
  </div>
882
  <div class="form-group">
883
  <label for="child_age">Возраст</label>
884
  <select id="child_age">
885
+ <option value="infant (6-12 months old)">6-12 месяцев</option>
886
+ <option value="toddler (2-4 years old)">2-4 года</option>
887
+ <option value="child (5-8 years old)">5-8 лет</option>
888
+ <option value="pre-teen (9-12 years old)">9-12 лет</option>
889
  </select>
890
  </div>
891
  <div class="form-group">
 
899
  <div class="form-group">
900
  <label for="child_shotType">Ракурс/План</label>
901
  <select id="child_shotType">
902
+ <option value="Full body shot, playful angle">В полный рост</option>
903
+ <option value="Medium shot, capturing emotion">По пояс</option>
904
+ <option value="Close-up portrait, happy expression">Портрет</option>
905
  </select>
906
  </div>
907
  <div class="form-group full-width">
908
  <label for="child_pose">Поза/Действие</label>
909
  <select id="child_pose">
910
+ <option value="running joyfully in a field">Бежит по полю</option>
911
+ <option value="playing enthusiastically with wooden toys on the floor">Играет с игрушками</option>
912
+ <option value="sitting and curiously looking at a picture book">Сидит с книгой</option>
913
+ <option value="posing for a candid school photo, smiling naturally">Позирует для фото</option>
914
+ <option value="laughing and jumping on a bed">Прыгает на кровати</option>
915
  </select>
916
  </div>
917
  <div class="form-group full-width">
 
996
  <script>
997
  let currentMode = 'model';
998
  const envKeyword = {{ keyword|tojson|safe }};
999
+ const promptsData = {{ prompts_data|tojson|safe }};
1000
 
1001
  const flagshipStyles = {
1002
+ 'studio': 'Студия (профи)', 'street': 'Стрит-стайл', 'lookbook': 'Лукбук (минимализм)',
1003
+ 'minimalism': 'Экстрим минимализм', 'selfie': 'Селфи (гиперреализм)', 'creative': 'Креативная съемка',
1004
+ 'new_year': 'Новый Год', 'retro': 'Ретро (35мм пленка)', 'boho': 'Бохо (золотой час)',
1005
+ 'gothic': 'Готика', 'editorial': 'Эдиториал (глянец)', 'film_noir': 'Фильм-нуар (Ч/Б)',
1006
+ 'cottagecore': 'Коттеджкор', 'royalcore': 'Роскошь (дворец)', 'solarpunk': 'Соларпанк',
1007
+ 'skater': 'Скейтер', 'baroque': 'Барокко', 'japandi': 'Джапанди', 'coastal': 'Прибрежный стиль',
1008
+ 'cyberpunk': 'Киберпанк', 'fantasy': 'Фэнтези', '90s_grunge': 'Гранж 90-х',
1009
+ 'techwear': 'Techwear', 'avant_garde': 'Авангард', 'home_casual': 'Домашний уют',
1010
+ 'social_media_candid': 'Инстаграм-фото', 'backstage': 'Бэкстейдж', 'road_trip': 'Роуд-трип',
1011
+ 'rainy_day': 'Дождливый день', 'night_flash': 'Ночь (вспышка)', 'golden_hour_picnic': 'Пикник (золотой час)'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  };
1013
 
 
1014
  const objectStyles = {
1015
+ 'studio': 'Студия (профи)', 'minimalism': 'Минимализм', 'nature': 'На природе',
1016
+ 'luxe': 'Лакшери', 'dark': 'Мрачный стиль'
 
 
 
 
 
 
 
 
 
 
 
1017
  };
1018
 
 
1019
  const femaleBodyTypes = {
1020
+ 'standard': 'Станд��ртное', 'very_slim': 'Очень стройное (модель)', 'slim': 'Стройное (натуральное)',
1021
+ 'slim_busty': 'Стройное с пышной грудью', 'athletic': 'Атлетичное', 'petite': 'Миниатюрное',
1022
+ 'hourglass': 'Песочные часы', 'fit_curvy': 'Спортивное (curvy)', 'bombshell': 'Гипер-curvy',
1023
+ 'curvy': 'Мягкое (curvy)', 'full_figured': 'Плюс-сайз'
 
 
 
 
 
 
 
1024
  };
1025
 
1026
  const maleBodyTypes = {
1027
+ 'athletic': 'Атлетичное', 'lean and toned': 'Поджарое', 'muscular build': 'Мускулистое',
1028
+ 'broad build': 'Крупное', 'slim build': 'Худощавое'
 
 
 
1029
  };
1030
 
1031
  function switchMode(mode) {
 
1083
  }
1084
 
1085
  function getPrompt() {
1086
+ let prompt = "";
 
 
 
 
 
 
 
 
 
 
1087
  let aspectRatio = '';
1088
  let additionalPrompt = '';
1089
 
 
1093
  const textToOverlay = document.getElementById('textOverlayInput').value.trim();
1094
 
1095
  if (currentMode === 'model') {
1096
+ prompt = promptsData.base_prompts.model_base;
1097
  const styleKey = document.querySelector('#styleSelector .style-btn.active').dataset.value;
1098
+ const stylePrompt = promptsData.flagship_styles[styleKey];
1099
  const gender = document.getElementById('gender').value;
1100
  const age = document.getElementById('age').value;
1101
  const nationality = document.getElementById('nationality').value;
 
1106
  additionalPrompt = document.getElementById('additional_prompt').value;
1107
  aspectRatio = document.querySelector('#aspectRatioSelectorModel .aspect-ratio-btn.active').dataset.value;
1108
 
1109
+ prompt += `\n\n**STYLE & MOOD:** ${stylePrompt}`;
1110
+ prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\n- model: ${age} ${gender}, ${nationality} appearance, with a realistic, ${bodyType} body type.`;
1111
+ prompt += `\n\n**CLOTHING:** The model is wearing: ${clothingDetails}. If this is a single item like a top, they are also wearing appropriate bottoms (e.g. jeans, trousers). If it's bottoms, they wear a simple, neutral top. The full outfit is stylish and complete.`;
1112
  prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Pose: ${pose}`;
1113
 
1114
  } else if (currentMode === 'children') {
1115
+ prompt = promptsData.base_prompts.model_base;
1116
  const styleKey = document.querySelector('#childStyleSelector .style-btn.active').dataset.value;
1117
+ const stylePrompt = promptsData.flagship_styles[styleKey];
1118
  const gender = document.getElementById('child_gender').value;
1119
  const age = document.getElementById('child_age').value;
1120
  const nationality = document.getElementById('child_nationality').value;
 
1124
  additionalPrompt = document.getElementById('child_additional_prompt').value;
1125
  aspectRatio = document.querySelector('#aspectRatioSelectorChildren .aspect-ratio-btn.active').dataset.value;
1126
 
1127
+ prompt += `\n\n**STYLE & MOOD:** ${stylePrompt} The scene should be cheerful, safe, and age-appropriate.`;
1128
+ prompt += `\n\n**MODEL(S) SPECIFICATIONS:**\n- model: A happy and natural-looking ${age} ${gender}, ${nationality} appearance.`;
1129
+ prompt += `\n\n**CLOTHING:** The child is wearing: ${clothingDetails}. The child is fully dressed in a complete, practical, and age-appropriate outfit.`;
1130
+ prompt += `\n\n**POSE & COMPOSITION:**\n- Perspective: ${shotType}\n- Camera Angle: Straight-on\n- Action: ${pose}`;
1131
 
1132
+ } else {
1133
+ prompt = promptsData.base_prompts.object_base;
1134
  const styleKey = document.querySelector('#objectStyleSelector .style-btn.active').dataset.value;
1135
+ const stylePrompt = promptsData.object_styles[styleKey];
1136
  const objectName = document.getElementById('object_name').value || "the product";
1137
  additionalPrompt = document.getElementById('object_additional_prompt').value;
1138
  aspectRatio = document.querySelector('#aspectRatioSelectorObject .aspect-ratio-btn.active').dataset.value;
1139
 
1140
+ prompt += `\n\n**SCENE CONFIGURATION:**\n- Mode: Flat lay / Hanging shoot\n- Style: ${stylePrompt}`;
1141
  prompt += `\n- Product: ${objectName}`;
1142
  }
1143
 
 
1146
  }
1147
 
1148
  if (wantsDetailsCollage) {
1149
+ prompt += `\n\n**COMPOSITION DIRECTIVE (DETAILS COLLAGE):** Create a marketplace-ready collage. The main image features the full look. Add 2-3 smaller inset images showcasing ultra-close-up shots of fabric texture, seams, and hardware (buttons, zippers).`;
1150
  }
1151
 
1152
  if (wantsVariantsCollage) {
1153
+ prompt += `\n\n**COMPOSITION DIRECTIVE (VARIANTS COLLAGE):** In a single, cohesive frame, display multiple models (or one model in different poses) showcasing the garment in various colors or styles. The result must be a harmonious and balanced collage.`;
1154
  }
1155
 
1156
  if (wantsTextOverlay && textToOverlay) {
1157
+ prompt += `\n\n**GRAPHIC OVERLAY:** Add the following text: "${textToOverlay}". Integrate it stylishly using modern, clean typography. The text should be legible but artistically placed to complement the image, not dominate it. Minimalist icons that enhance the text are permissible.`;
1158
  }
1159
 
1160
  return `${envKeyword}, ${prompt} ${aspectRatio}`;
 
1355
 
1356
  keyword = env_data.get("keyword", "")
1357
  env_type = env_data.get("type", "closed")
1358
+ prompts_data = load_prompts()
1359
 
1360
  current_log = {
1361
  "time": datetime.utcnow().isoformat(),
 
1375
  save_data(data)
1376
 
1377
  if env_type == 'open':
1378
+ return render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword, prompts_data=prompts_data)
1379
 
1380
  stored_token = env_data.get("device_token")
1381
  user_token = request.cookies.get(f'access_token_{env_id}')
 
1404
  </body>
1405
  </html>
1406
  """, 403
1407
+ return render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword, prompts_data=prompts_data)
1408
  else:
1409
  new_token = ''.join(random.choices(string.ascii_letters + string.digits, k=40))
1410
  env_data['device_token'] = new_token
1411
  data[env_id] = env_data
1412
  save_data(data)
1413
 
1414
+ resp = make_response(render_template_string(SYNKRIS_LOOK_TEMPLATE, keyword=keyword, prompts_data=prompts_data))
1415
  resp.set_cookie(f'access_token_{env_id}', new_token, max_age=31536000, httponly=True, samesite='Lax')
1416
  return resp
1417
 
1418
  if __name__ == '__main__':
1419
+ setup_initial_files()
1420
  download_db_from_hf()
1421
  if HF_TOKEN_WRITE:
1422
  backup_thread = threading.Thread(target=periodic_backup, daemon=True)