Spaces:
Running on Zero
Running on Zero
File size: 6,068 Bytes
c46a5da 62122bd c46a5da 62122bd c46a5da 60b63d0 c46a5da 60b63d0 c46a5da | 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 | import spaces
import torch
import gradio as gr
import random
from PIL import Image
from diffusers import Flux2KleinPipeline
# ββ Configuration βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
BASE_MODEL = "black-forest-labs/FLUX.2-klein-9B"
LORA_REPO = "paom/texture2albedo-v2"
WEIGHT_NAME = "pytorch_lora_weights.safetensors"
DEFAULT_PROMPT = (
"Unlit flat-shaded albedo map. Remove all shadows, reflections, highlights, "
"and specularity. Maintain absolute pixel-per-pixel structural identity, shape, "
"and spatial alignment with the original image, displaying only raw base color."
)
MAX_SEED = 2**31 - 1
# ββ Model load at module scope βββββββββββββββββββββββββββββββββββββββββββββββ
print("Loading FLUX.2-klein-9B base pipeline...")
pipe = Flux2KleinPipeline.from_pretrained(
BASE_MODEL,
torch_dtype=torch.bfloat16,
)
pipe.to("cuda")
print("Loading LoRA weights...")
pipe.load_lora_weights(
LORA_REPO,
weight_name=WEIGHT_NAME,
adapter_name="albedo",
)
# Model card loads the LoRA adapter and runs it unfused (default adapter
# weight = 1.0); do NOT fuse, to match the documented inference recipe.
print("Pipeline ready.")
# ββ Inference ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
@spaces.GPU(duration=90)
def generate_albedo(
input_image,
prompt,
num_inference_steps,
guidance_scale,
seed,
randomize_seed,
progress=gr.Progress(track_tqdm=True),
):
if input_image is None:
raise gr.Error("Please upload a texture or photo first.")
if not prompt or not prompt.strip():
prompt = DEFAULT_PROMPT
orig_width, orig_height = input_image.size
# Resize to 1024x1024 for the model
processed_input = input_image.resize((1024, 1024))
if randomize_seed:
seed = random.randint(0, MAX_SEED)
# Model card seeds with torch.manual_seed(seed), i.e. a CPU generator.
# A CUDA generator produces a different noise sequence for the same seed,
# so match the documented recipe to keep outputs consistent with the card.
generator = torch.manual_seed(seed)
with torch.inference_mode():
output_image = pipe(
prompt=prompt,
image=processed_input,
guidance_scale=guidance_scale,
num_inference_steps=int(num_inference_steps),
generator=generator,
).images[0]
# Resize back to original dimensions
albedo_map = output_image.resize((orig_width, orig_height))
return albedo_map, seed
# ββ UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
with gr.Blocks(title="Texture to Albedo β FLUX.2 Klein") as demo:
gr.Markdown(
"""
# Texture β Albedo Studio
Extract clean, flat, shadowless **albedo maps** from textures and photos using
[paom/texture2albedo-v2](https://huggingface.co/paom/texture2albedo-v2) on
[FLUX.2-klein-9B](https://huggingface.co/black-forest-labs/FLUX.2-klein-9B).
Perfect for 3D/PBR material pipelines.
"""
)
with gr.Row(equal_height=True):
with gr.Column(scale=1):
input_img = gr.Image(label="Input Texture / Photo", type="pil")
prompt_box = gr.Textbox(
label="Prompt",
value=DEFAULT_PROMPT,
lines=3,
placeholder="Describe what you want the albedo map to look like...",
)
with gr.Accordion("Advanced Parameters", open=False):
inference_steps = gr.Slider(
minimum=1, maximum=12, value=4, step=1,
label="Inference Steps",
)
guidance = gr.Slider(
minimum=0.0, maximum=4.0, value=1.0, step=0.1,
label="Guidance Scale",
)
seed_input = gr.Slider(
minimum=0, maximum=MAX_SEED, value=0, step=1,
label="Seed",
)
randomize_seed = gr.Checkbox(
label="Randomize seed", value=True,
)
submit_btn = gr.Button("Generate Albedo Map", variant="primary", size="lg")
with gr.Column(scale=1):
albedo_out = gr.Image(label="Clean Albedo Map", type="pil")
used_seed = gr.Number(label="Seed used", precision=0, interactive=False)
gr.Examples(
# The model-card example images are before/after composites
# (left half = original texture, right half = albedo output).
# Only the left "before" half is fed to the model as the example input.
examples=[
["example_1_left.jpg", DEFAULT_PROMPT, 4, 1.0, 0, True],
["example_2_left.jpg", DEFAULT_PROMPT, 4, 1.0, 0, True],
["example_3_left.jpg", DEFAULT_PROMPT, 4, 1.0, 0, True],
],
inputs=[input_img, prompt_box, inference_steps, guidance, seed_input, randomize_seed],
outputs=[albedo_out, used_seed],
fn=generate_albedo,
cache_examples=True,
cache_mode="lazy",
)
submit_btn.click(
fn=generate_albedo,
inputs=[input_img, prompt_box, inference_steps, guidance, seed_input, randomize_seed],
outputs=[albedo_out, used_seed],
)
prompt_box.submit(
fn=generate_albedo,
inputs=[input_img, prompt_box, inference_steps, guidance, seed_input, randomize_seed],
outputs=[albedo_out, used_seed],
)
if __name__ == "__main__":
demo.launch(theme=gr.themes.Citrus(), show_error=True) |