File size: 13,645 Bytes
6e887ea
 
51fc11d
4d02c23
6e887ea
461aeae
51fc11d
461aeae
 
4d02c23
5838efa
461aeae
4d02c23
 
 
 
 
461aeae
4d02c23
a9a44ea
461aeae
84b5f6c
 
461aeae
4d02c23
 
84b5f6c
461aeae
4d02c23
 
461aeae
4d02c23
461aeae
 
4d02c23
84b5f6c
461aeae
84b5f6c
461aeae
 
4d02c23
84b5f6c
4d02c23
 
84b5f6c
4d02c23
84b5f6c
 
 
 
461aeae
84b5f6c
 
461aeae
4d02c23
461aeae
4d02c23
461aeae
 
4d02c23
461aeae
 
 
 
 
 
4d02c23
461aeae
4d02c23
461aeae
 
 
4d02c23
461aeae
4d02c23
461aeae
4d02c23
461aeae
 
 
 
 
a9a44ea
 
461aeae
4d02c23
84b5f6c
461aeae
4d02c23
 
 
461aeae
 
 
4d02c23
9d4c47a
461aeae
5838efa
4d02c23
5838efa
461aeae
 
5838efa
4d02c23
461aeae
4d02c23
461aeae
 
6e887ea
eb284a9
461aeae
4d02c23
 
461aeae
 
 
4d02c23
461aeae
4d02c23
eb284a9
461aeae
 
4d02c23
eb284a9
461aeae
 
 
4d02c23
461aeae
eb284a9
5838efa
4d02c23
461aeae
3f1040a
461aeae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb284a9
461aeae
 
58f4530
461aeae
 
 
 
 
 
 
 
 
 
58f4530
4d02c23
461aeae
 
 
 
 
 
4d02c23
461aeae
4d02c23
 
 
 
3f1040a
4d02c23
461aeae
84b5f6c
4d02c23
3f1040a
4d02c23
 
84b5f6c
461aeae
 
4d02c23
461aeae
eb284a9
461aeae
 
 
 
eb284a9
4d02c23
84b5f6c
4d02c23
9d4c47a
461aeae
 
 
 
84b5f6c
9d4c47a
461aeae
 
 
 
a9a44ea
3f1040a
4d02c23
5838efa
461aeae
 
4d02c23
461aeae
4d02c23
461aeae
 
4d02c23
 
461aeae
4d02c23
461aeae
4d02c23
 
 
 
 
 
 
 
 
461aeae
4d02c23
 
a9a44ea
4d02c23
461aeae
a9a44ea
4d02c23
461aeae
4d02c23
461aeae
4d02c23
461aeae
84b5f6c
a9a44ea
461aeae
4d02c23
 
 
 
 
 
461aeae
4d02c23
461aeae
4d02c23
 
 
9d4c47a
461aeae
4d02c23
461aeae
 
 
4d02c23
9d4c47a
4d02c23
461aeae
4d02c23
 
461aeae
 
 
 
 
4d02c23
 
 
461aeae
4d02c23
9d4c47a
84b5f6c
4d02c23
461aeae
 
 
 
 
 
 
 
4d02c23
461aeae
 
 
 
 
2c12be3
461aeae
 
4d02c23
461aeae
 
 
4d02c23
461aeae
 
 
 
 
6e887ea
461aeae
6e887ea
461aeae
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import gradio as gr
import torch
import time
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline

print("🚀 ЗАГРУЖАЮ ОПТИМИЗИРОВАННУЮ СИСТЕМУ...")

# ================== ИСПОЛЬЗУЕМ ТОЛЬКО TINYLLAMA ==================
# Она быстрая, уже работает, занимает мало памяти
MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"

# Глобальные переменные для кэша
_tokenizer = None
_model = None
_translator = None

def load_system():
    """Загружаем только одну модель - TinyLlama"""
    global _tokenizer, _model, _translator
    
    print("📦 Загружаю TinyLlama (самая быстрая для CPU)...")
    
    try:
        # Токенизатор
        _tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
        _tokenizer.pad_token = _tokenizer.eos_token
        
        # Модель с оптимизациями для CPU
        _model = AutoModelForCausalLM.from_pretrained(
            MODEL_NAME,
            torch_dtype=torch.float32,  # Используем float32 для CPU
            device_map="auto",
            low_cpu_mem_usage=True,
            offload_folder="./offload"  # Выгружаем на диск если не хватает RAM
        )
        
        print("✅ TinyLlama загружена и оптимизирована для CPU!")
        
        # Переводчик
        print("🌐 Загружаю переводчик...")
        _translator = pipeline(
            "translation_ru_to_en", 
            model="Helsinki-NLP/opus-mt-ru-en",
            device="cpu"
        )
        print("✅ Переводчик готов!")
        
        return True
        
    except Exception as e:
        print(f"❌ Ошибка загрузки: {e}")
        return False

# ================== ПРАВИЛЬНЫЕ ПРОМТ-ШАБЛОНЫ ==================
def get_enhancement_prompt(user_input: str) -> str:
    """Создаем ПРАВИЛЬНЫЙ промт для улучшения, а не для рассказа"""
    return f"""<|system|>
Ты помощник для создания промтов к AI-генератору изображений Dreamlike Photoreal 2.0.
ТВОЯ ЗАДАЧА: Взять короткое описание и добавить КОНКРЕТНЫЕ детали для фотореалистичной генерации.

ДОБАВЬ:
1. Описание внешности (если есть персонаж)
2. Детали окружения
3. Освещение и время суток
4. Атмосферу и настроение
5. Стиль изображения

НЕ пиши рассказ, НЕ добавляй сюжет. Только описание для генератора изображений.

Примеры правильных улучшений:
• "девушка в лесу" → "Молодая девушка с рыжими волосами в белом платье стоит в магическом лесу на закате, золотые лучи солнца пробиваются сквозь листву, атмосферное освещение, фотореалистично, детализированно"
• "город ночью" → "Футуристический город ночью с неоновыми вывесками, мокрые улицы отражают свет, киберпанк стиль, детализированная архитектура, фотореалистично"</s>
<|user|>
Улучши это описание для генерации фотореалистичного изображения: "{user_input}"</s>
<|assistant|>
Улучшенное описание:"""

# ================== БЫСТРАЯ ГЕНЕРАЦИЯ ==================
def enhance_prompt_fast(user_input: str) -> str:
    """Быстро улучшаем промт с TinyLlama"""
    if _model is None or _tokenizer is None:
        return user_input + " [система не загружена]"
    
    try:
        # Создаем правильный промт
        system_prompt = get_enhancement_prompt(user_input)
        
        # Токенизация (ограничиваем длину)
        inputs = _tokenizer(
            system_prompt,
            return_tensors="pt",
            max_length=256,
            truncation=True,
            padding=True
        )
        
        # Быстрая генерация с оптимизированными параметрами
        with torch.no_grad():
            outputs = _model.generate(
                **inputs,
                max_new_tokens=120,  # Не больше 120 новых токенов
                temperature=0.8,
                do_sample=True,
                top_p=0.9,
                repetition_penalty=1.1,
                pad_token_id=_tokenizer.eos_token_id,
                eos_token_id=_tokenizer.eos_token_id,
                no_repeat_ngram_size=3  # Избегаем повторений
            )
        
        # Декодируем
        response = _tokenizer.decode(outputs[0], skip_special_tokens=True)
        
        # Извлекаем только улучшенную часть
        if "Улучшенное описание:" in response:
            enhanced = response.split("Улучшенное описание:")[-1].strip()
        else:
            # Fallback: удаляем системный промт
            enhanced = response.replace(system_prompt, "").strip()
        
        # Очищаем от метаданных
        for marker in ["<|endoftext|>", "</s>", "<|assistant|>", "<|user|>", "<|system|>"]:
            enhanced = enhanced.split(marker)[0].strip()
        
        # Если результат слишком короткий, добавляем базовые улучшения
        if len(enhanced.split()) < 5:
            enhanced = f"{user_input}, фотореалистично, высокое качество, детализированно, красивое освещение"
        
        return enhanced[:400]  # Ограничиваем длину
        
    except Exception as e:
        print(f"Ошибка генерации: {e}")
        return f"{user_input}, фотореалистично, высокое качество, детализированно"

def generate_negative_prompt_smart(english_prompt: str) -> str:
    """Умный негативный промт"""
    base = [
        "blurry", "ugly", "deformed", "bad anatomy",
        "bad proportions", "extra limbs", "mutated hands",
        "poorly drawn hands", "text", "watermark", "signature",
        "worst quality", "low quality", "jpeg artifacts"
    ]
    
    prompt_lower = english_prompt.lower()
    
    # Добавляем контекстные исключения
    if any(word in prompt_lower for word in ["realistic", "photoreal", "photo"]):
        base.extend(["cartoon", "anime", "painting", "drawing", "illustration", "3d render"])
    
    if any(word in prompt_lower for word in ["bright", "light", "sun"]):
        base.extend(["dark", "dull", "underexposed", "gloomy"])
    
    if any(word in prompt_lower for word in ["portrait", "face", "person"]):
        base.extend(["asymmetric eyes", "cloned face", "malformed limbs"])
    
    # Убираем дубликаты
    unique = []
    for term in base:
        if term not in unique:
            unique.append(term)
    
    return ", ".join(unique)

def process_pipeline(user_input: str):
    """Полный пайплайн обработки"""
    start_time = time.time()
    
    if not user_input.strip():
        return "Введите промт", "", "", "⏳ Введите промт"
    
    print(f"⚡ Обработка: {user_input}")
    
    # 1. Улучшаем промт (максимум 5 секунд)
    gen_start = time.time()
    enhanced_ru = enhance_prompt_fast(user_input)
    gen_time = time.time() - gen_start
    
    # 2. Переводим
    trans_start = time.time()
    try:
        if _translator:
            translated = _translator(enhanced_ru[:300])[0]['translation_text']
        else:
            translated = enhanced_ru
    except:
        translated = enhanced_ru
    trans_time = time.time() - trans_start
    
    # 3. Улучшаем английский для Dreamlike
    dreamlike_keywords = ", photorealistic, high quality, detailed, 8K, professional photography"
    if "photorealistic" not in translated.lower():
        translated += dreamlike_keywords
    
    # 4. Негативный промт
    negative_start = time.time()
    negative_en = generate_negative_prompt_smart(translated)
    negative_time = time.time() - negative_start
    
    # 5. Статистика
    total_time = time.time() - start_time
    
    info = f"""
    ⚡ БЫСТРАЯ ОБРАБОТКА:
    • Генерация: {gen_time:.1f} сек
    • Перевод: {trans_time:.1f} сек
    • Негативный промт: {negative_time:.1f} сек
    • Всего: {total_time:.1f} сек
    
    📊 СТАТИСТИКА:
    • Модель: TinyLlama-1.1B (оптимизирована для CPU)
    • Длина промта: {len(translated.split())} слов
    • Статус: ✅ Готово к использованию в Dreamlike
    """
    
    return enhanced_ru, translated, negative_en, info.strip()

# ================== ПРОСТОЙ ИНТЕРФЕЙС ==================
with gr.Blocks(title="AI Улучшитель промтов для Dreamlike", theme=gr.themes.Soft()) as demo:
    
    # Заголовок
    gr.Markdown("""
    # 🚀 УЛЬТРА-БЫСТРЫЙ AI УЛУЧШИТЕЛЬ ПРОМТОВ
    ### Оптимизирован для CPU • TinyLlama • Мгновенная обработка
    """)
    
    # Статус загрузки
    status = gr.Textbox(
        label="🔄 Статус системы",
        value="Загружаю систему...",
        interactive=False
    )
    
    # Основной интерфейс
    with gr.Column(visible=False) as main_ui:
        # Ввод
        input_prompt = gr.Textbox(
            label="🎯 Введите промт на русском",
            placeholder="Пример: девушка в магическом лесу на закате",
            lines=2
        )
        
        # Кнопка
        process_btn = gr.Button("⚡ УЛУЧШИТЬ ПРОМТ", variant="primary", size="lg")
        
        # Результаты
        gr.Markdown("### 📝 УЛУЧШЕННЫЙ ПРОМТ (русский)")
        output_ru = gr.Textbox(
            label="",
            lines=3,
            interactive=True
        )
        
        gr.Markdown("### 🌐 ДЛЯ DREAMLIKE (английский)")
        with gr.Row():
            output_en = gr.Textbox(
                label="🎨 Основной промт",
                lines=3,
                interactive=True
            )
            
            output_neg = gr.Textbox(
                label="🚫 Negative Prompt",
                lines=3,
                interactive=True
            )
        
        # Информация
        output_info = gr.Textbox(
            label="📊 СТАТИСТИКА",
            lines=4,
            interactive=False
        )
        
        # Примеры
        gr.Markdown("### 🧪 БЫСТРЫЕ ПРИМЕРЫ")
        examples = gr.Examples(
            examples=[
                ["девушка в магическом лесу на закате"],
                ["киберпанк улица ночью с неоновыми вывесками"],
                ["космонавт играет на гитаре на луне"],
                ["кошка в шляпе читает газету в кафе"],
                ["дракон на вершине горы"]
            ],
            inputs=[input_prompt],
            outputs=[output_ru, output_en, output_neg, output_info],
            fn=process_pipeline,
            label="Кликните для теста:"
        )
        
        # Обработчики
        def process_and_update(prompt):
            return process_pipeline(prompt)
        
        process_btn.click(
            fn=process_and_update,
            inputs=[input_prompt],
            outputs=[output_ru, output_en, output_neg, output_info]
        )
        
        input_prompt.submit(
            fn=process_and_update,
            inputs=[input_prompt],
            outputs=[output_ru, output_en, output_neg, output_info]
        )
    
    # Функция инициализации
    def initialize_system():
        if load_system():
            return "✅ СИСТЕМА ГОТОВА! TinyLlama загружена и оптимизирована.\n⚡ Введите промт и нажмите кнопку.", gr.update(visible=True)
        else:
            return "❌ Ошибка загрузки. Попробуйте перезапустить Space.", gr.update(visible=False)
    
    # Загружаем при старте
    demo.load(
        fn=initialize_system,
        outputs=[status, main_ui]
    )

# ================== ЗАПУСК ==================
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860
    )