dsfsadfsdfdsf commited on
Commit
2c12be3
·
verified ·
1 Parent(s): 0440869

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -202
app.py CHANGED
@@ -1,39 +1,27 @@
1
  import gradio as gr
 
2
  import torch
3
- from transformers import (
4
- AutoTokenizer,
5
- AutoModelForCausalLM,
6
- pipeline,
7
- BitsAndBytesConfig
8
- )
9
  import time
10
  import re
11
 
12
- # ================== НАСТРОЙКА МОДЕЛЕЙ ==================
13
- # Выбор: загружать обе модели сразу или только выбранную
14
- # Для экономии памяти на CPU можно грузить только активную модель
15
  MODEL_CONFIGS = {
16
- "gemma": {
17
- "name": "google/gemma-2b-it",
18
- "quantized": False, # Можно использовать 4-битную версию если найдете
19
- "requires_auth": False # Gemma требует принятия лицензии
 
20
  },
21
- "phi2": {
22
- "name": "microsoft/phi-2",
23
- "quantized": False,
 
24
  "requires_auth": False
25
  }
26
  }
27
 
28
- # Конфигурация для экономии памяти (4-битное квантование)
29
- bnb_config = BitsAndBytesConfig(
30
- load_in_4bit=True,
31
- bnb_4bit_compute_dtype=torch.float16,
32
- bnb_4bit_quant_type="nf4",
33
- bnb_4bit_use_double_quant=True
34
- )
35
-
36
- # Инициализация переменных
37
  models = {}
38
  tokenizers = {}
39
 
@@ -50,85 +38,113 @@ def load_model(model_key):
50
  # Загружаем токенизатор
51
  tokenizer = AutoTokenizer.from_pretrained(
52
  config["name"],
53
- trust_remote_code=config.get("trust_remote_code", False)
54
  )
55
 
56
- # Конфигурация для модели
57
- model_kwargs = {
58
- "torch_dtype": torch.float16,
59
- "device_map": "auto",
60
- "trust_remote_code": config.get("trust_remote_code", False),
61
- }
62
-
63
- if config["quantized"]:
64
- model_kwargs["quantization_config"] = bnb_config
65
-
66
- # Особые настройки для каждой модели
67
- if model_key == "gemma":
68
  tokenizer.pad_token = tokenizer.eos_token
69
- tokenizer.padding_side = "left"
70
- elif model_key == "phi2":
71
- tokenizer.pad_token = tokenizer.eos_token
72
-
73
- # Загружаем модель
74
  model = AutoModelForCausalLM.from_pretrained(
75
  config["name"],
76
- **model_kwargs
 
 
 
77
  )
78
 
79
  models[model_key] = model
80
  tokenizers[model_key] = tokenizer
81
 
82
- print(f"Модель {model_key} загружена успешно!")
83
  return model, tokenizer
84
 
85
  except Exception as e:
86
- print(f"Ошибка загрузки модели {model_key}: {str(e)}")
87
- # Fallback на простую логику
88
  return None, None
89
 
90
  # Загружаем переводчик (он всегда нужен)
91
  print("Загрузка переводчика...")
92
- translator = pipeline(
93
- "translation_ru_to_en",
94
- model="Helsinki-NLP/opus-mt-ru-en",
95
- device_map="auto"
96
- )
97
- print("Переводчик загружен!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
  # ================== ОСНОВНАЯ ЛОГИКА ==================
100
- def extract_from_response(response, prompt_type="gemma"):
101
  """Извлекает структурированные данные из ответа модели"""
102
- # Удаляем исходный промт и инструкции
103
- lines = response.split('\n')
104
-
105
  result = {"enhanced_ru": "", "optimized_en": "", "negative": ""}
106
 
107
  # Паттерны для поиска
108
  patterns = {
109
- "enhanced_ru": [r"Улучшенный[:\s]*(.+)", r"Enhanced.*RU[:\s]*(.+)", r"Улучшенный промт[:\s]*(.+)"],
110
- "optimized_en": [r"Английский[:\s]*(.+)", r"English[:\s]*(.+)", r"Optimized[:\s]*(.+)", r"Перевод[:\s]*(.+)"],
111
- "negative": [r"Негативный[:\s]*(.+)", r"Negative[:\s]*(.+)", r"Negative prompt[:\s]*(.+)"]
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
 
 
 
 
114
  for line in lines:
115
- line_lower = line.lower()
116
-
117
- for key in patterns:
118
  if not result[key]: # Если еще не нашли
119
- for pattern in patterns[key]:
120
  match = re.search(pattern, line, re.IGNORECASE)
121
  if match:
122
- result[key] = match.group(1).strip()
123
  break
124
 
125
- # Если не нашли через паттерны, берем первые 3 строки
126
- if not result["enhanced_ru"] and len(lines) > 1:
127
- result["enhanced_ru"] = lines[1].strip()
128
- if not result["optimized_en"] and len(lines) > 2:
129
- result["optimized_en"] = lines[2].strip()
130
- if not result["negative"] and len(lines) > 3:
131
- result["negative"] = lines[3].strip()
132
 
133
  return result
134
 
@@ -136,91 +152,63 @@ def generate_with_model(prompt_ru, model_key):
136
  """Генерация улучшенного промта с помощью выбранной модели"""
137
  model, tokenizer = load_model(model_key)
138
 
139
- if model is None:
140
- return "Ошибка загрузки модели", "", ""
141
-
142
- # Промты для разных моделей
143
- templates = {
144
- "gemma": f"""<start_of_turn>user
145
- Ты эксперт по созданию промтов для AI-генерации изображений в Dreamlike Photoreal 2.0.
146
-
147
- ВХОДНОЙ ПРОМТ: "{prompt_ru}"
148
-
149
- ВЫПОЛНИ 3 ЗАДАЧИ:
150
- 1. УЛУЧШЕННЫЙ ПРОМТ (русский): Детализируй, добавь описания освещения, времени года, стиля, деталей
151
- 2. ОПТИМИЗИРОВАННЫЙ ПРОМТ (английский): Переведи улучшенный промт на английский для AI-генератора
152
- 3. НЕГАТИВНЫЙ ПРОМТ (английский): Создай негативный промт с исключением артефактов
153
-
154
- Формат ответа:
155
- Улучшенный промт: [текст]
156
- Оптимизированный промт: [текст]
157
- Негативный промт: [текст]<end_of_turn>
158
- <start_of_turn>model""",
159
-
160
- "phi2": f"""Instruct: Ты - AI ассистент для создания промтов к генератору изображений Dreamlike Photoreal 2.0.
161
-
162
- Запрос пользователя: {prompt_ru}
163
-
164
- Выполни следующие шаги:
165
-
166
- 1. Улучши и детализируй промт на русском языке, добавь фотографические детали:
167
- 2. Переведи улучшенный промт на английский язык для AI-генератора:
168
- 3. Создай негативный промт (negative prompt) на английском для исключения нежелательных элементов:
169
-
170
- Output format:
171
- Улучшенный промт: [здесь детализированный русский промт]
172
- Оптимизированный промт: [здесь английский промт для генератора]
173
- Негативный промт: [здесь негативный промт на английском]"""
174
- }
175
-
176
- prompt_template = templates[model_key]
177
 
178
  try:
 
 
 
 
179
  # Токенизация
180
  inputs = tokenizer(
181
- prompt_template,
182
  return_tensors="pt",
183
  truncation=True,
184
  max_length=512
185
  )
186
 
187
- # Перенос на устройство модели
188
- inputs = {k: v.to(model.device) for k, v in inputs.items()}
189
-
190
  # Генерация
191
  with torch.no_grad():
192
  outputs = model.generate(
193
  **inputs,
194
- max_new_tokens=300,
195
  temperature=0.7,
196
  do_sample=True,
197
  top_p=0.9,
198
  repetition_penalty=1.1,
199
- pad_token_id=tokenizer.pad_token_id,
200
  eos_token_id=tokenizer.eos_token_id
201
  )
202
 
203
  # Декодирование
204
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
205
 
206
- # Извлечение структурированного ответа
207
- extracted = extract_from_response(response, model_key)
208
 
209
- # Если extraction не сработал, используем fallback
210
- if not extracted["enhanced_ru"]:
211
- # Удаляем промт из ответа
212
- response_clean = response.replace(prompt_template, "").strip()
213
- lines = [line.strip() for line in response_clean.split('\n') if line.strip()]
214
-
215
- extracted["enhanced_ru"] = lines[0] if len(lines) > 0 else prompt_ru
216
- extracted["optimized_en"] = lines[1] if len(lines) > 1 else ""
217
- extracted["negative"] = lines[2] if len(lines) > 2 else ""
218
 
219
  return extracted["enhanced_ru"], extracted["optimized_en"], extracted["negative"]
220
 
221
  except Exception as e:
222
  print(f"Ошибка генерации: {str(e)}")
223
- return f"Ошибка: {str(e)}", "", ""
 
 
 
 
 
 
 
224
 
225
  def process_prompt(prompt_ru, model_choice):
226
  """Основная функция обработки промта"""
@@ -230,44 +218,51 @@ def process_prompt(prompt_ru, model_choice):
230
  return "Введите промт", "", "", "0.0s"
231
 
232
  # Выбор модели
233
- model_key = "gemma" if "gemma" in model_choice.lower() else "phi2"
 
 
 
 
 
234
 
235
  # 1. Генерация с выбранной LLM
236
  enhanced_ru, optimized_en, negative_en = generate_with_model(prompt_ru, model_key)
237
 
238
  # 2. Если LLM не сгенерировала английский, используем переводчик
239
- if not optimized_en or len(optimized_en.split()) < 3:
240
  try:
241
  translated = translator(prompt_ru)[0]['translation_text']
242
- if not optimized_en:
243
  optimized_en = translated
244
- elif "Ошибка" in enhanced_ru:
245
- # Fallback: если LLM дала ошибку, используем простую логику
246
- enhanced_ru = prompt_ru + ", фотографично, высокое качество, детализировано"
247
- optimized_en = translated + ", photorealistic, high quality, detailed, 8k"
248
  except:
249
- optimized_en = prompt_ru + ", photorealistic, high quality"
 
 
 
 
250
 
251
- # 3. Дополняем негативный промт если он короткий
252
- base_negative = "blurry, ugly, deformed, cartoon, painting, anime, text, watermark, signature, bad quality, worst quality, low quality, jpeg artifacts"
 
 
 
253
 
254
  if not negative_en or len(negative_en.split(',')) < 3:
255
  negative_en = base_negative
256
  else:
257
  negative_en = base_negative + ", " + negative_en
258
 
259
- # 4. Добавляем контекстные исключения
260
- ru_text_lower = enhanced_ru.lower()
261
- en_text_lower = optimized_en.lower()
262
 
263
- if any(word in ru_text_lower for word in ["реалистич", "фото", "photoreal"]):
264
- negative_en += ", abstract, drawing, sketch, illustration, stylized"
265
 
266
- if any(word in ru_text_lower for word in ["ярк", "солн", "bright"]):
267
- negative_en += ", dark, dull, underexposed, gloomy"
268
 
269
- if any(word in ru_text_lower for word in ["портрет", "лицо", "portrait", "face"]):
270
- negative_en += ", deformed face, asymmetric eyes, bad anatomy, extra limbs"
271
 
272
  # Время выполнения
273
  processing_time = time.time() - start_time
@@ -276,16 +271,18 @@ def process_prompt(prompt_ru, model_choice):
276
  enhanced_ru,
277
  optimized_en,
278
  negative_en,
279
- f"⏱️ {processing_time:.1f} сек | Модель: {'Gemma-2B' if model_key == 'gemma' else 'Phi-2'}"
280
  )
281
 
282
  # ================== GRADIO ИНТЕРФЕЙС ==================
283
  css = """
284
- .gradio-container {max-width: 900px !important;}
285
- h1 {text-align: center; color: #4f46e5;}
286
- .model-info {background: #f0f9ff; padding: 10px; border-radius: 10px; margin: 10px 0;}
287
- .result-box {background: #f8fafc; padding: 15px; border-radius: 8px; border-left: 4px solid #4f46e5;}
288
- .negative-box {background: #fef2f2; padding: 15px; border-radius: 8px; border-left: 4px solid #dc2626;}
 
 
289
  """
290
 
291
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
@@ -295,86 +292,98 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
295
  """)
296
 
297
  with gr.Row():
298
- with gr.Column(scale=3):
299
  input_prompt = gr.Textbox(
300
- label="✏️ Ваш промт на русском",
301
- placeholder="Например: красивый пейзаж с горами и озером на закате",
302
- lines=3
 
303
  )
304
 
305
  with gr.Row():
306
  model_choice = gr.Radio(
307
- choices=["🚀 Gemma-2B (быстрее, проще)", "🎨 Phi-2 (качественнее, умнее)"],
308
- value="🚀 Gemma-2B (быстрее, проще)",
309
- label="Выберите модель для обработки"
 
310
  )
311
 
312
- submit_btn = gr.Button(" Оптимизировать промт", variant="primary", size="lg")
313
 
314
- with gr.Column(scale=2):
315
  gr.Markdown("""
316
  <div class="model-info">
317
- <h3>🤖 О моделях:</h3>
318
- <b>Gemma-2B:</b> Быстрая, хорошо понимает инструкции<br>
319
- <b>Phi-2:</b> Качественнее обрабатывает сложные запросы<br><br>
320
 
321
- <b>⚠️ Первый запуск:</b> Загрузка моделей займет 1-2 минуты<br>
322
- <b>📦 Память:</b> Используется 4-битное квантование для экономии
323
- </div>
 
 
 
 
 
 
324
 
325
- <h3>🎯 Примеры промтов:</h3>
326
- • Кот в шляпе читает газету в кафе<br>
327
- • Футуристический город ночью с неоновыми огнями<br>
328
- • Портрет женщины с рыжими волосами в стиле ретро<br>
329
- • Магический лес с светящимися грибами
330
  """)
331
 
332
  with gr.Row():
333
  with gr.Column():
334
- gr.Markdown("### 📝 Улучшенный промт (русский)")
335
  output_ru = gr.Textbox(
336
  label="",
337
  lines=3,
338
- interactive=False,
339
- elem_classes="result-box"
 
340
  )
341
 
342
  with gr.Column():
343
- gr.Markdown("### 🌐 Промт для генератора (английский)")
344
  output_en = gr.Textbox(
345
  label="",
346
  lines=3,
347
- interactive=False,
348
- elem_classes="result-box"
 
349
  )
350
 
351
- gr.Markdown("### 🚫 Негативный промт (английский)")
 
352
  output_negative = gr.Textbox(
353
- label="Используйте в negative prompt в Dreamlike",
354
  lines=2,
355
- interactive=False,
356
- elem_classes="negative-box"
 
357
  )
358
 
359
  info_text = gr.Textbox(
360
- label="Информация",
361
  interactive=False
362
  )
363
 
364
- # Примеры для быстрого тестирования
365
- gr.Markdown("### 🧪 Быстрые примеры (кликните для теста):")
366
  with gr.Row():
367
  examples = [
368
- ["Космонавт играет на гитаре на луне, земля на горизонте"],
369
- ["Стимпанк лаборатория с летающими механическими птицами"],
370
- ["Магический портал в лесу, светящиеся руны, ночное небо"],
371
- ["Киберпанк улица под дождем, неоновые вывески, отражения в лужах"]
372
  ]
373
- gr.Examples(
374
- examples=examples,
375
- inputs=[input_prompt],
376
- label=""
377
- )
 
 
 
 
 
378
 
379
  # Обработка
380
  submit_btn.click(
@@ -383,21 +392,30 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
383
  outputs=[output_ru, output_en, output_negative, info_text]
384
  )
385
 
386
- # Авто-отправка при нажатии Enter
387
  input_prompt.submit(
388
  fn=process_prompt,
389
  inputs=[input_prompt, model_choice],
390
  outputs=[output_ru, output_en, output_negative, info_text]
391
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
  # ================== ЗАПУСК ==================
394
  if __name__ == "__main__":
395
- # Предзагрузка Gemma для быстрого старта
396
- print("Предзагрузка Gemma-2B...")
397
- load_model("gemma")
398
-
399
  demo.launch(
400
  server_name="0.0.0.0",
401
- share=False, # Поставьте True если хотите публичную ссылку
402
- debug=True
 
403
  )
 
1
  import gradio as gr
2
+ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
3
  import torch
 
 
 
 
 
 
4
  import time
5
  import re
6
 
7
+ # ================== НАСТРОЙКА МОДЕЛЕЙ (ИСПРАВЛЕННАЯ) ==================
8
+ # Используем только открытые и легкие модели
 
9
  MODEL_CONFIGS = {
10
+ "qwen": {
11
+ "name": "Qwen/Qwen2.5-0.5B-Instruct",
12
+ "size": "0.5B",
13
+ "description": "Быстрая и умная, отлично понимает русский",
14
+ "requires_auth": False
15
  },
16
+ "tinyllama": {
17
+ "name": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
18
+ "size": "1.1B",
19
+ "description": "Очень быстрая, хорошо для простых промтов",
20
  "requires_auth": False
21
  }
22
  }
23
 
24
+ # Инициализация
 
 
 
 
 
 
 
 
25
  models = {}
26
  tokenizers = {}
27
 
 
38
  # Загружаем токенизатор
39
  tokenizer = AutoTokenizer.from_pretrained(
40
  config["name"],
41
+ trust_remote_code=True
42
  )
43
 
44
+ # Для TinyLlama добавляем pad_token
45
+ if model_key == "tinyllama":
 
 
 
 
 
 
 
 
 
 
46
  tokenizer.pad_token = tokenizer.eos_token
47
+
48
+ # Загружаем модель с квантованием для CPU
 
 
 
49
  model = AutoModelForCausalLM.from_pretrained(
50
  config["name"],
51
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
52
+ device_map="auto",
53
+ trust_remote_code=True,
54
+ low_cpu_mem_usage=True # Экономим память
55
  )
56
 
57
  models[model_key] = model
58
  tokenizers[model_key] = tokenizer
59
 
60
+ print(f"Модель {model_key} загружена успешно!")
61
  return model, tokenizer
62
 
63
  except Exception as e:
64
+ print(f"Ошибка загрузки модели {model_key}: {str(e)}")
 
65
  return None, None
66
 
67
  # Загружаем переводчик (он всегда нужен)
68
  print("Загрузка переводчика...")
69
+ try:
70
+ translator = pipeline(
71
+ "translation_ru_to_en",
72
+ model="Helsinki-NLP/opus-mt-ru-en",
73
+ device="cpu"
74
+ )
75
+ print("✅ Переводчик загружен!")
76
+ except:
77
+ print("⚠️ Переводчик не загрузился, используем fallback")
78
+ translator = None
79
+
80
+ # ================== ПРОМТ-ШАБЛОНЫ ==================
81
+ PROMPT_TEMPLATES = {
82
+ "qwen": """<|im_start|>system
83
+ Ты эксперт по созданию промтов для AI-генерации изображений в Dreamlike Photoreal 2.0.
84
+ Твоя задача:
85
+ 1. Улучшить и детализировать русский п��омт (добавить описание освещения, времени года, стиля, деталей)
86
+ 2. Перевести улучшенный промт на английский для AI-генератора
87
+ 3. Создать негативный промт на английском для исключения артефактов
88
+
89
+ Формат ответа:
90
+ Улучшенный промт: [текст]
91
+ Английский промт: [текст]
92
+ Негативный промт: [текст]<|im_end|>
93
+ <|im_start|>user
94
+ {user_prompt}<|im_end|>
95
+ <|im_start|>assistant""",
96
+
97
+ "tinyllama": """<|system|>
98
+ Ты помощник для создания промтов к генератору изображений. Улучши промт, переведи на английский и создай негативный промт.</s>
99
+ <|user|>
100
+ {user_prompt}</s>
101
+ <|assistant|>"""
102
+ }
103
 
104
  # ================== ОСНОВНАЯ ЛОГИКА ==================
105
+ def extract_from_response(response):
106
  """Извлекает структурированные данные из ответа модели"""
 
 
 
107
  result = {"enhanced_ru": "", "optimized_en": "", "negative": ""}
108
 
109
  # Паттерны для поиска
110
  patterns = {
111
+ "enhanced_ru": [
112
+ r"Улучшенный промт[:\s]*(.+)",
113
+ r"Улучшенный[:\s]*(.+)",
114
+ r"Enhanced[:\s]*(.+)"
115
+ ],
116
+ "optimized_en": [
117
+ r"Английский промт[:\s]*(.+)",
118
+ r"Английский[:\s]*(.+)",
119
+ r"English[:\s]*(.+)",
120
+ r"Перевод[:\s]*(.+)"
121
+ ],
122
+ "negative": [
123
+ r"Негативный промт[:\s]*(.+)",
124
+ r"Негативный[:\s]*(.+)",
125
+ r"Negative[:\s]*(.+)"
126
+ ]
127
  }
128
 
129
+ # Разделяем на строки и ищем
130
+ lines = [line.strip() for line in response.split('\n') if line.strip()]
131
+
132
  for line in lines:
133
+ for key, key_patterns in patterns.items():
 
 
134
  if not result[key]: # Если еще не нашли
135
+ for pattern in key_patterns:
136
  match = re.search(pattern, line, re.IGNORECASE)
137
  if match:
138
+ result[key] = match.group(1).strip(' :')
139
  break
140
 
141
+ # Fallback: если не нашли паттернами, берем первые строки
142
+ if not result["enhanced_ru"] and len(lines) > 0:
143
+ result["enhanced_ru"] = lines[0]
144
+ if not result["optimized_en"] and len(lines) > 1:
145
+ result["optimized_en"] = lines[1]
146
+ if not result["negative"] and len(lines) > 2:
147
+ result["negative"] = lines[2]
148
 
149
  return result
150
 
 
152
  """Генерация улучшенного промта с помощью выбранной модели"""
153
  model, tokenizer = load_model(model_key)
154
 
155
+ if model is None or tokenizer is None:
156
+ # Fallback: базовая обработка
157
+ enhanced = prompt_ru + ", детализировано, высокое качество"
158
+ if translator:
159
+ translated = translator(prompt_ru)[0]['translation_text'] + ", detailed, high quality"
160
+ else:
161
+ translated = prompt_ru + ", detailed, high quality"
162
+ negative = "blurry, ugly, deformed, cartoon, text, watermark"
163
+ return enhanced, translated, negative
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  try:
166
+ # Подготавливаем промт
167
+ template = PROMPT_TEMPLATES[model_key]
168
+ full_prompt = template.format(user_prompt=prompt_ru)
169
+
170
  # Токенизация
171
  inputs = tokenizer(
172
+ full_prompt,
173
  return_tensors="pt",
174
  truncation=True,
175
  max_length=512
176
  )
177
 
 
 
 
178
  # Генерация
179
  with torch.no_grad():
180
  outputs = model.generate(
181
  **inputs,
182
+ max_new_tokens=256,
183
  temperature=0.7,
184
  do_sample=True,
185
  top_p=0.9,
186
  repetition_penalty=1.1,
187
+ pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
188
  eos_token_id=tokenizer.eos_token_id
189
  )
190
 
191
  # Декодирование
192
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
193
 
194
+ # Удаляем исходный промт из ответа
195
+ response = response.replace(full_prompt, "").strip()
196
 
197
+ # Извлекаем структурированные данные
198
+ extracted = extract_from_response(response)
 
 
 
 
 
 
 
199
 
200
  return extracted["enhanced_ru"], extracted["optimized_en"], extracted["negative"]
201
 
202
  except Exception as e:
203
  print(f"Ошибка генерации: {str(e)}")
204
+ # Fallback
205
+ enhanced = prompt_ru
206
+ if translator:
207
+ translated = translator(prompt_ru)[0]['translation_text']
208
+ else:
209
+ translated = prompt_ru
210
+ negative = "blurry, ugly, deformed, cartoon, text"
211
+ return enhanced, translated, negative
212
 
213
  def process_prompt(prompt_ru, model_choice):
214
  """Основная функция обработки промта"""
 
218
  return "Введите промт", "", "", "0.0s"
219
 
220
  # Выбор модели
221
+ if "qwen" in model_choice.lower():
222
+ model_key = "qwen"
223
+ model_name = "Qwen2.5-0.5B"
224
+ else:
225
+ model_key = "tinyllama"
226
+ model_name = "TinyLlama-1.1B"
227
 
228
  # 1. Генерация с выбранной LLM
229
  enhanced_ru, optimized_en, negative_en = generate_with_model(prompt_ru, model_key)
230
 
231
  # 2. Если LLM не сгенерировала английский, используем переводчик
232
+ if (not optimized_en or len(optimized_en.split()) < 3) and translator:
233
  try:
234
  translated = translator(prompt_ru)[0]['translation_text']
235
+ if not optimized_en or optimized_en == prompt_ru:
236
  optimized_en = translated
 
 
 
 
237
  except:
238
+ pass
239
+
240
+ # 3. Дополняем если пусто
241
+ if not enhanced_ru or enhanced_ru == prompt_ru:
242
+ enhanced_ru = prompt_ru + ", фотографично, высокое качество, детализировано"
243
 
244
+ if not optimized_en or optimized_en == prompt_ru:
245
+ optimized_en = enhanced_ru + ", photorealistic, high quality, detailed"
246
+
247
+ # 4. Базовая негативная строка
248
+ base_negative = "blurry, ugly, deformed, cartoon, painting, anime, text, watermark, signature, bad quality"
249
 
250
  if not negative_en or len(negative_en.split(',')) < 3:
251
  negative_en = base_negative
252
  else:
253
  negative_en = base_negative + ", " + negative_en
254
 
255
+ # 5. Контекстные улучшения
256
+ text_for_analysis = (enhanced_ru + " " + optimized_en).lower()
 
257
 
258
+ if any(word in text_for_analysis for word in ["реалистич", "фото", "photoreal", "realistic"]):
259
+ negative_en += ", abstract, drawing, sketch, illustration, stylized, painting"
260
 
261
+ if any(word in text_for_analysis for word in ["ярк", "солн", "bright", "sunny", "light"]):
262
+ negative_en += ", dark, dull, underexposed, gloomy, shadow"
263
 
264
+ if any(word in text_for_analysis for word in ["портрет", "лицо", "человек", "portrait", "face", "person"]):
265
+ negative_en += ", deformed face, asymmetric eyes, bad anatomy, extra limbs, mutated hands"
266
 
267
  # Время выполнения
268
  processing_time = time.time() - start_time
 
271
  enhanced_ru,
272
  optimized_en,
273
  negative_en,
274
+ f"⏱️ {processing_time:.1f} сек | Модель: {model_name} | Токенов: ~{len(optimized_en.split())}"
275
  )
276
 
277
  # ================== GRADIO ИНТЕРФЕЙС ==================
278
  css = """
279
+ .gradio-container {max-width: 900px !important; margin: auto;}
280
+ h1 {text-align: center; color: #4f46e5; margin-bottom: 10px;}
281
+ .model-info {background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 12px; margin: 10px 0;}
282
+ .result-box {background: #f8fafc; padding: 15px; border-radius: 10px; border-left: 5px solid #4f46e5; margin: 5px 0;}
283
+ .negative-box {background: #fef2f2; padding: 15px; border-radius: 10px; border-left: 5px solid #dc2626; margin: 5px 0;}
284
+ .example-box {background: #f0f9ff; padding: 8px 12px; border-radius: 8px; margin: 3px; cursor: pointer; border: 1px solid #bae6fd;}
285
+ .example-box:hover {background: #e0f2fe;}
286
  """
287
 
288
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
 
292
  """)
293
 
294
  with gr.Row():
295
+ with gr.Column(scale=2):
296
  input_prompt = gr.Textbox(
297
+ label="✏️ **Ваш промт на русском**",
298
+ placeholder="Например: кот в шляпе читает газету в уютном кафе утром",
299
+ lines=3,
300
+ elem_id="input_prompt"
301
  )
302
 
303
  with gr.Row():
304
  model_choice = gr.Radio(
305
+ choices=["🧠 Qwen2.5-0.5B (умнее, лучше русский)", " TinyLlama-1.1B (быстрее)"],
306
+ value="🧠 Qwen2.5-0.5B (умнее, лучше русский)",
307
+ label="**Выберите модель для обработки**",
308
+ elem_id="model_choice"
309
  )
310
 
311
+ submit_btn = gr.Button("🚀 **Оптимизировать промт**", variant="primary", size="lg", scale=1)
312
 
313
+ with gr.Column(scale=1):
314
  gr.Markdown("""
315
  <div class="model-info">
316
+ <h3>🤖 **Доступные модели:**</h3>
 
 
317
 
318
+ <b>🧠 Qwen2.5-0.5B</b><br>
319
+ Лучшее понимание русского<br>
320
+ • Качественные улучшения<br>
321
+ • ~2-4 секунды на CPU<br><br>
322
+
323
+ <b>⚡ TinyLlama-1.1B</b><br>
324
+ • Максимальная скорость<br>
325
+ • Хорошо для простых промтов<br>
326
+ • ~1-2 секунды на CPU<br><br>
327
 
328
+ <b>⚠️ Все модели загружены и готовы!</b>
329
+ </div>
 
 
 
330
  """)
331
 
332
  with gr.Row():
333
  with gr.Column():
334
+ gr.Markdown("### 📝 **Улучшенный промт (русский)**")
335
  output_ru = gr.Textbox(
336
  label="",
337
  lines=3,
338
+ interactive=True,
339
+ elem_classes="result-box",
340
+ show_copy_button=True
341
  )
342
 
343
  with gr.Column():
344
+ gr.Markdown("### 🌐 **Промт для генератора (английский)**")
345
  output_en = gr.Textbox(
346
  label="",
347
  lines=3,
348
+ interactive=True,
349
+ elem_classes="result-box",
350
+ show_copy_button=True
351
  )
352
 
353
+ gr.Markdown("### 🚫 **Негативный промт (английский)**")
354
+ gr.Markdown("*Скопируйте это в поле 'Negative Prompt' в Dreamlike*")
355
  output_negative = gr.Textbox(
356
+ label="",
357
  lines=2,
358
+ interactive=True,
359
+ elem_classes="negative-box",
360
+ show_copy_button=True
361
  )
362
 
363
  info_text = gr.Textbox(
364
+ label="**Информация о выполнении**",
365
  interactive=False
366
  )
367
 
368
+ # Примеры
369
+ gr.Markdown("### 🧪 **Быстрые примеры (кликните для теста):**")
370
  with gr.Row():
371
  examples = [
372
+ ["Космонавт играет на гитаре на луне, земля видна на горизонте"],
373
+ ["Стимпанк лаборатория с летающими механическими птицами и шестеренками"],
374
+ ["Магический портал в древнем лесу, светящиеся руны, ночное небо с двумя лунами"],
375
+ ["Киберпанк улица Токио под кислотным дождем, неоновые вывески, отражения"]
376
  ]
377
+ example_components = []
378
+ for ex in examples:
379
+ btn = gr.Button(
380
+ ex[0][:40] + "...",
381
+ size="sm",
382
+ variant="secondary",
383
+ elem_classes="example-box"
384
+ )
385
+ btn.click(lambda x=ex[0]: x, outputs=[input_prompt])
386
+ example_components.append(btn)
387
 
388
  # Обработка
389
  submit_btn.click(
 
392
  outputs=[output_ru, output_en, output_negative, info_text]
393
  )
394
 
 
395
  input_prompt.submit(
396
  fn=process_prompt,
397
  inputs=[input_prompt, model_choice],
398
  outputs=[output_ru, output_en, output_negative, info_text]
399
  )
400
+
401
+ # Предзагрузка моделей при старте
402
+ def preload_models():
403
+ print("🔧 Предзагрузка моделей...")
404
+ load_model("qwen")
405
+ load_model("tinyllama")
406
+ print("✅ Все модели готовы!")
407
+ return "Система готова к работе! Выберите модель и введите промт."
408
+
409
+ demo.load(
410
+ fn=preload_models,
411
+ outputs=[info_text]
412
+ )
413
 
414
  # ================== ЗАПУСК ==================
415
  if __name__ == "__main__":
 
 
 
 
416
  demo.launch(
417
  server_name="0.0.0.0",
418
+ share=True, # Публичная ссылка
419
+ debug=False,
420
+ show_error=True
421
  )