Spaces:
Running on Zero
Running on Zero
multimodalart HF Staff
Align inference with model card: remove fuse_lora, use CPU seed generator
62122bd verified | 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 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| 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) |