Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,97 +2,89 @@ import gradio as gr
|
|
| 2 |
from huggingface_hub import InferenceClient
|
| 3 |
from PIL import Image
|
| 4 |
import os
|
| 5 |
-
import
|
| 6 |
|
| 7 |
-
#
|
| 8 |
hf_token = os.getenv("HF_TOKEN")
|
| 9 |
-
# Используем мощную модель SDXL
|
| 10 |
client = InferenceClient("stabilityai/stable-diffusion-xl-base-1.0", token=hf_token)
|
| 11 |
|
| 12 |
-
def
|
| 13 |
-
|
| 14 |
-
if not hf_token:
|
| 15 |
-
return None
|
| 16 |
|
| 17 |
-
#
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
try:
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
-
# Раз
|
| 26 |
res_map = {"16x16": 16, "32x32": 32, "64x64": 64, "128x128": 128, "512x512": 512}
|
| 27 |
size = res_map[resolution]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
|
| 30 |
-
image = image.resize((size, size), Image.Resampling.NEAREST)
|
| 31 |
-
else:
|
| 32 |
-
image = image.resize((size, size), Image.Resampling.LANCZOS)
|
| 33 |
-
|
| 34 |
-
return image
|
| 35 |
except Exception as e:
|
| 36 |
print(f"Error: {e}")
|
| 37 |
-
return None
|
| 38 |
|
| 39 |
-
def
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
return err
|
| 45 |
-
return img
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
block = generate_core(f"block of {prompt} texture", resolution, pixelate)
|
| 50 |
-
item = generate_core(f"item icon of {prompt} sword or tool", resolution, pixelate)
|
| 51 |
-
|
| 52 |
-
if block is None: block = Image.new('RGB', (512, 512), color=(20, 20, 20))
|
| 53 |
-
if item is None: item = Image.new('RGB', (512, 512), color=(20, 20, 20))
|
| 54 |
-
|
| 55 |
-
return block, item
|
| 56 |
-
|
| 57 |
-
# Красивый темный интерфейс
|
| 58 |
-
css = """
|
| 59 |
-
.gradio-container { background-color: #0a0a0a !important; color: #d8b4fe !important; }
|
| 60 |
-
.btn-primary { background: linear-gradient(to right, #7c3aed, #db2777) !important; border: none !important; }
|
| 61 |
-
footer { display: none !important; }
|
| 62 |
-
"""
|
| 63 |
|
| 64 |
with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
|
| 65 |
-
gr.Markdown("#
|
| 66 |
|
| 67 |
-
if not hf_token:
|
| 68 |
-
gr.HTML("<div style='background: red; padding: 10px; color: white;'>⚠️ ОШИБКА: HF_TOKEN не найден! Добавьте его в Settings -> Secrets</div>")
|
| 69 |
-
|
| 70 |
with gr.Tabs():
|
| 71 |
with gr.TabItem("Одиночная текстура"):
|
| 72 |
with gr.Row():
|
| 73 |
with gr.Column():
|
| 74 |
-
p_in = gr.Textbox(label="Описание
|
| 75 |
-
|
|
|
|
|
|
|
| 76 |
px_in = gr.Checkbox(label="Pixel Art Mode", value=True)
|
| 77 |
-
|
|
|
|
| 78 |
with gr.Column():
|
| 79 |
-
|
| 80 |
-
gr.
|
| 81 |
|
| 82 |
-
with gr.TabItem("📦 Г
|
| 83 |
-
gr.Markdown("Создает одновременно текстуру блока и иконку предмета в едином стиле.")
|
| 84 |
with gr.Row():
|
| 85 |
with gr.Column():
|
| 86 |
-
|
| 87 |
-
s_res = gr.Dropdown(["16x16", "32x32", "64x64", "128x128", "512x512"], value="128x128", label="Разрешение")
|
| 88 |
-
s_px = gr.Checkbox(label="Pixel Art Mode", value=True)
|
| 89 |
btn_s = gr.Button("⚒️ СОЗДАТЬ СЕТ", variant="primary")
|
| 90 |
with gr.Column():
|
| 91 |
with gr.Row():
|
| 92 |
-
|
| 93 |
-
|
|
|
|
| 94 |
|
| 95 |
-
btn_p.click(
|
| 96 |
-
btn_s.click(forge_set, [
|
| 97 |
|
| 98 |
demo.launch()
|
|
|
|
| 2 |
from huggingface_hub import InferenceClient
|
| 3 |
from PIL import Image
|
| 4 |
import os
|
| 5 |
+
import random
|
| 6 |
|
| 7 |
+
# Настройка клиента
|
| 8 |
hf_token = os.getenv("HF_TOKEN")
|
|
|
|
| 9 |
client = InferenceClient("stabilityai/stable-diffusion-xl-base-1.0", token=hf_token)
|
| 10 |
|
| 11 |
+
def forge_texture(prompt, resolution, pixelate, style, seed):
|
| 12 |
+
if not hf_token: return None, None
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
# Улучшение промпта в зависимости от стиля
|
| 15 |
+
styles = {
|
| 16 |
+
"Cursed 🔮": "dark occult aesthetic, purple and black glow, twisted textures, cursed energy",
|
| 17 |
+
"Classic ⛏️": "minecraft vanilla style, flat colors, blocky look, simplistic",
|
| 18 |
+
"HD Realism ✨": "highly detailed, 8k, realistic material, sharp shadows"
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
# Если seed -1, выбираем случайный
|
| 22 |
+
used_seed = random.randint(0, 1000000) if seed == -1 else seed
|
| 23 |
+
|
| 24 |
+
full_prompt = f"minecraft 2d texture, {prompt}, {styles[style]}, flat game asset, white background"
|
| 25 |
+
neg_prompt = "lowres, text, error, cropped, worst quality, low quality, 3d render, perspective, messy"
|
| 26 |
|
| 27 |
try:
|
| 28 |
+
image = client.text_to_image(
|
| 29 |
+
full_prompt,
|
| 30 |
+
negative_prompt=neg_prompt,
|
| 31 |
+
guidance_scale=8.0,
|
| 32 |
+
seed=used_seed
|
| 33 |
+
)
|
| 34 |
|
| 35 |
+
# Ресайз
|
| 36 |
res_map = {"16x16": 16, "32x32": 32, "64x64": 64, "128x128": 128, "512x512": 512}
|
| 37 |
size = res_map[resolution]
|
| 38 |
+
image = image.resize((size, size), Image.Resampling.NEAREST if pixelate else Image.Resampling.LANCZOS)
|
| 39 |
+
|
| 40 |
+
# Сохраняем как PNG
|
| 41 |
+
file_name = f"texture_{random.randint(1000, 9999)}.png"
|
| 42 |
+
image.save(file_name, "PNG")
|
| 43 |
|
| 44 |
+
return image, file_name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
except Exception as e:
|
| 46 |
print(f"Error: {e}")
|
| 47 |
+
return None, None
|
| 48 |
|
| 49 |
+
def forge_set(prompt, resolution, pixelate, style):
|
| 50 |
+
# Генератор для сета (блок + предмет)
|
| 51 |
+
block_img, block_file = forge_texture(f"block of {prompt}", resolution, pixelate, style, -1)
|
| 52 |
+
item_img, item_file = forge_texture(f"item {prompt} ingot or tool", resolution, pixelate, style, -1)
|
| 53 |
+
return block_img, block_file, item_img, item_file
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
# UI
|
| 56 |
+
css = ".gradio-container {background: #050505; color: #a78bfa;} .main-btn {background: linear-gradient(90deg, #4c1d95, #7c3aed) !important;}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
|
| 59 |
+
gr.Markdown("# 🔮 The Cursed: Texture Forge v4.0")
|
| 60 |
|
|
|
|
|
|
|
|
|
|
| 61 |
with gr.Tabs():
|
| 62 |
with gr.TabItem("Одиночная текстура"):
|
| 63 |
with gr.Row():
|
| 64 |
with gr.Column():
|
| 65 |
+
p_in = gr.Textbox(label="Описание", placeholder="dark obsidian with eyes")
|
| 66 |
+
with gr.Row():
|
| 67 |
+
r_in = gr.Dropdown(["16x16", "32x32", "64x64", "128x128", "512x512"], value="128x128", label="Разрешение")
|
| 68 |
+
s_in = gr.Dropdown(["Cursed 🔮", "Classic ⛏️", "HD Realism ✨"], value="Cursed 🔮", label="Стиль")
|
| 69 |
px_in = gr.Checkbox(label="Pixel Art Mode", value=True)
|
| 70 |
+
seed_in = gr.Number(label="Seed (-1 для случайного)", value=-1)
|
| 71 |
+
btn_p = gr.Button("🔥 ВЫКОВАТЬ", variant="primary", elem_classes="main-btn")
|
| 72 |
with gr.Column():
|
| 73 |
+
out_img = gr.Image(label="Предпросмотр", type="pil")
|
| 74 |
+
out_file = gr.File(label="Скачать .PNG для Minecraft")
|
| 75 |
|
| 76 |
+
with gr.TabItem("📦 Генерация сета"):
|
|
|
|
| 77 |
with gr.Row():
|
| 78 |
with gr.Column():
|
| 79 |
+
set_p = gr.Textbox(label="Тема сета", placeholder="void crystal")
|
|
|
|
|
|
|
| 80 |
btn_s = gr.Button("⚒️ СОЗДАТЬ СЕТ", variant="primary")
|
| 81 |
with gr.Column():
|
| 82 |
with gr.Row():
|
| 83 |
+
out_b = gr.Image(label="Блок"); out_i = gr.Image(label="Предмет")
|
| 84 |
+
with gr.Row():
|
| 85 |
+
out_b_f = gr.File(label="PNG Блока"); out_i_f = gr.File(label="PNG Предмета")
|
| 86 |
|
| 87 |
+
btn_p.click(forge_texture, [p_in, r_in, px_in, s_in, seed_in], [out_img, out_file])
|
| 88 |
+
btn_s.click(forge_set, [set_p, r_in, px_in, s_in], [out_b, out_b_f, out_i, out_i_f])
|
| 89 |
|
| 90 |
demo.launch()
|