Download app.py from aexyb/xAI: direct link, hf CLI and curl.
- Browser
- Download file 14.9 kB
-
https://huggingface.co/spaces/aexyb/xAI/resolve/main/app.py
- Command line
-
hf download hf://spaces/aexyb/xAI/app.py
-
curl -L -o app.py https://huggingface.co/spaces/aexyb/xAI/resolve/main/app.py
14.9 kB
| """ | |
| FLUX.2-klein-4B GGUF โ CPU-only Inference Space | |
| ็กฌไปถ๏ผๆ GPU ยท CPU ยท 18 GB RAM | |
| """ | |
| import os | |
| import sys | |
| import json | |
| import torch | |
| import numpy as np | |
| from huggingface_hub import login, hf_hub_download, list_repo_files | |
| # โโ ็ฏๅข้ ็ฝฎ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| os.environ["TOKENIZERS_PARALLELISM"] = "false" | |
| torch.set_num_threads(os.cpu_count() or 4) | |
| GGUF_REPO = "unsloth/FLUX-2-klein-4B-GGUF" | |
| TOKEN = os.environ.get("HF_TOKEN", "") | |
| # โโ ่ฎค่ฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ") | |
| print("โ FLUX.2-klein-4B GGUF โ CPU Inference โ") | |
| print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ") | |
| if TOKEN: | |
| login(token=TOKEN, add_to_git_credential=False) | |
| print(" โ HF_TOKEN authenticated") | |
| else: | |
| print(" โ HF_TOKEN not set!") | |
| print(" โ Go to Space Settings โ Repository Secrets โ Add HF_TOKEN") | |
| print(" โ Get token: https://huggingface.co/settings/tokens") | |
| print(" โ Also accept model license on the model page first!\n") | |
| print(f" Model : {GGUF_REPO}") | |
| print(f" Threads : {torch.get_num_threads()}") | |
| print(f" PyTorch : {torch.__version__}") | |
| # โโ ๅ ่ฝฝๆจกๅ๏ผๅ้็ญ็ฅ๏ผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| from diffusers import FluxPipeline, FluxTransformer2DModel | |
| pipe = None | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Strategy A๏ผ็ดๆฅๅ ่ฝฝ๏ผdiffusers ๅ็ GGUF ๆฏๆ๏ผ | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| if pipe is None: | |
| try: | |
| print("\n[A] Trying direct diffusers loading...") | |
| pipe = FluxPipeline.from_pretrained( | |
| GGUF_REPO, | |
| torch_dtype=torch.float32, | |
| token=TOKEN or None, | |
| ) | |
| pipe.to("cpu") | |
| print("[A] โ Direct loading succeeded!\n") | |
| except Exception as e: | |
| print(f"[A] โ Failed: {e}\n") | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| # Strategy B๏ผๆๅจ่งฃๆ GGUF โ ๆณจๅ ฅ transformer | |
| # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| if pipe is None: | |
| try: | |
| print("[B] Manual GGUF loading...") | |
| from gguf import GGUFReader | |
| # 1) ๅๅบไปๅบๆไปถ๏ผๆพๅฐ .gguf | |
| print(" Listing repo files...") | |
| repo_files = list_repo_files(GGUF_REPO, token=TOKEN or None) | |
| gguf_candidates = [f for f in repo_files if f.endswith(".gguf")] | |
| if not gguf_candidates: | |
| raise FileNotFoundError("No .gguf file found in repo") | |
| # ไผๅ ้ Q4_K_M๏ผ็ฒพๅบฆไธ้ๅบฆๅนณ่กก๏ผ๏ผๆฒกๆๅ้็ฌฌไธไธช | |
| preferred = [f for f in gguf_candidates if "Q4_K_M" in f.upper()] | |
| gguf_fname = preferred[0] if preferred else gguf_candidates[0] | |
| print(f" Selected: {gguf_fname}") | |
| # 2) ไธ่ฝฝ GGUF ๆไปถ | |
| print(" Downloading GGUF file...") | |
| gguf_path = hf_hub_download( | |
| GGUF_REPO, gguf_fname, token=TOKEN or None | |
| ) | |
| print(f" Saved to: {gguf_path}") | |
| # 3) ่ฏปๅ GGUF ๅผ ้ | |
| print(" Reading GGUF tensors...") | |
| reader = GGUFReader(gguf_path) | |
| gguf_sd = {} | |
| for tensor in reader.tensors: | |
| name = tensor.name | |
| if isinstance(name, bytes): | |
| name = name.decode("utf-8") | |
| data = np.array(tensor.data, dtype=np.float32) | |
| data = data.reshape(tensor.shape).copy() | |
| gguf_sd[name] = torch.from_numpy(data) | |
| print(f" Loaded {len(gguf_sd)} tensors") | |
| sample_keys = list(gguf_sd.keys())[:5] | |
| print(f" Sample keys: {sample_keys}") | |
| # 4) ไธ่ฝฝ transformer config | |
| print(" Loading transformer config...") | |
| config_path = hf_hub_download( | |
| GGUF_REPO, "transformer/config.json", token=TOKEN or None | |
| ) | |
| with open(config_path, "r") as f: | |
| tf_config = json.load(f) | |
| # 5) ๅๅปบ็ฉบ transformer ๅนถๅ ่ฝฝ GGUF ๆ้ | |
| print(" Building transformer and loading weights...") | |
| transformer = FluxTransformer2DModel.from_config(tf_config) | |
| # ๅฐ่ฏๅค็ง key ๆ ๅฐ | |
| loaded_ok = False | |
| # B1: ็ดๆฅๆ ๅฐ | |
| try: | |
| info = transformer.load_state_dict(gguf_sd, strict=False) | |
| missing = [k for k in info.missing_keys if "bias" not in k.lower()] | |
| if len(missing) < 5: | |
| loaded_ok = True | |
| print(f" B1 โ Direct mapping (missing={len(missing)})") | |
| except Exception: | |
| pass | |
| # B2: ๅ "transformer." ๅ็ผ | |
| if not loaded_ok: | |
| try: | |
| mapped = {"transformer." + k: v for k, v in gguf_sd.items()} | |
| info = transformer.load_state_dict(mapped, strict=False) | |
| missing = [k for k in info.missing_keys if "bias" not in k.lower()] | |
| if len(missing) < 5: | |
| loaded_ok = True | |
| print(f" B2 โ Prefix mapping (missing={len(missing)})") | |
| except Exception: | |
| pass | |
| # B3: ๅปๆๅทฒๆๅ็ผๅๆ ๅฐ | |
| if not loaded_ok: | |
| try: | |
| mapped = {} | |
| for k, v in gguf_sd.items(): | |
| new_key = k | |
| for prefix in ["transformer.", "model."]: | |
| if k.startswith(prefix): | |
| new_key = k[len(prefix):] | |
| break | |
| mapped[new_key] = v | |
| info = transformer.load_state_dict(mapped, strict=False) | |
| missing = [k for k in info.missing_keys if "bias" not in k.lower()] | |
| if len(missing) < 5: | |
| loaded_ok = True | |
| print(f" B3 โ Strip-prefix mapping (missing={len(missing)})") | |
| except Exception: | |
| pass | |
| if not loaded_ok: | |
| # ๆๅฐ่ฏๆญไฟกๆฏๅธฎๅฉ่ฐ่ฏ | |
| model_keys = set(transformer.state_dict().keys()) | |
| gguf_keys = set(gguf_sd.keys()) | |
| print(f"\n โโ Key mismatch diagnostics โโ") | |
| print(f" Model expects {len(model_keys)} keys") | |
| print(f" GGUF has {len(gguf_keys)} keys") | |
| print(f" Model key sample : {list(model_keys)[:3]}") | |
| print(f" GGUF key sample : {list(gguf_keys)[:3]}") | |
| raise RuntimeError("Could not map GGUF keys to model keys") | |
| # 6) ๆๅปบๅฎๆด pipeline๏ผไผ ๅ ฅ transformer ่ทณ่ฟ็ฃ็ๅ ่ฝฝ๏ผ | |
| print(" Building full pipeline...") | |
| pipe = FluxPipeline.from_pretrained( | |
| GGUF_REPO, | |
| transformer=transformer, | |
| torch_dtype=torch.float32, | |
| token=TOKEN or None, | |
| ) | |
| pipe.to("cpu") | |
| print("[B] โ Manual GGUF loading succeeded!\n") | |
| except Exception as e: | |
| print(f"[B] โ Failed: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| print() | |
| # โโ ๆ็ปๆฃๆฅ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| if pipe is None: | |
| print("=" * 58) | |
| print("FATAL: Could not load model.") | |
| print("") | |
| print("Please check:") | |
| print(" 1. HF_TOKEN is set as a Space secret") | |
| print(" 2. You have accepted the model license at:") | |
| print(f" https://huggingface.co/{GGUF_REPO}") | |
| print("=" * 58) | |
| sys.exit(1) | |
| print("โ Model ready for inference!\n") | |
| # โโ ๆจ็ๅฝๆฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| def generate( | |
| prompt: str, | |
| negative_prompt: str, | |
| width: int, | |
| height: int, | |
| steps: int, | |
| guidance: float, | |
| seed: int, | |
| progress=gr.Progress(track_tqdm=True), | |
| ): | |
| if not prompt.strip(): | |
| raise gr.Error("่ฏท่พๅ ฅๆ็คบ่ฏ") | |
| seed = seed if seed >= 0 else int(time.time() * 1000) % (2**32) | |
| generator = torch.Generator("cpu").manual_seed(seed) | |
| t0 = time.time() | |
| result = pipe( | |
| prompt=prompt, | |
| negative_prompt=negative_prompt if negative_prompt.strip() else None, | |
| width=width, | |
| height=height, | |
| num_inference_steps=steps, | |
| guidance_scale=guidance, | |
| generator=generator, | |
| ) | |
| dt = time.time() - t0 | |
| return result.images[0], seed, f"ๅฎๆ ยท ่ๆถ {dt:.1f}s ยท seed {seed}" | |
| # โโ ็้ขๆ ทๅผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| CSS = """ | |
| :root{--bg:#0a0a0f;--card:#13131a;--border:#23233a;--fg:#e4e4ec;--muted:#6b6b80;--accent:#7c5cfc;--glow:rgba(124,92,252,.25)} | |
| .gradio-container{background:var(--bg)!important;color:var(--fg)!important;max-width:1080px!important;padding-top:1rem!important} | |
| .gr-block,.gr-panel{background:var(--card)!important;border:1px solid var(--border)!important;border-radius:14px!important} | |
| .gr-input,textarea.gr-textbox,input[type=number].gr-number{background:#0e0e16!important;border:1px solid var(--border)!important;color:var(--fg)!important;border-radius:10px!important;font-size:.92rem!important} | |
| textarea.gr-textbox{resize:vertical!important} | |
| .gr-label{color:var(--muted)!important;font-size:.78rem!important;text-transform:uppercase!important;letter-spacing:.06em!important;font-weight:600!important} | |
| .gr-button-primary{background:linear-gradient(135deg,#7c5cfc,#a78bfa)!important;border:none!important;font-weight:700!important;font-size:1rem!important;border-radius:10px!important;padding:.7rem 1.5rem!important;box-shadow:0 4px 24px var(--glow)!important;transition:all .2s ease!important} | |
| .gr-button-primary:hover{transform:translateY(-1px)!important;box-shadow:0 6px 32px var(--glow)!important;filter:brightness(1.1)!important} | |
| .gr-slider input[type=range]{accent-color:var(--accent)!important} | |
| .gr-image{border-radius:12px!important;overflow:hidden!important} | |
| footer{display:none!important} | |
| ::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#333;border-radius:3px} | |
| .warn-bar{background:linear-gradient(90deg,#1c1a2e,#1a1428);border:1px solid #2e2848;border-radius:10px;padding:.7rem 1rem;margin-bottom:1.2rem;font-size:.82rem;color:#a0a0b8;line-height:1.5} | |
| .warn-bar strong{color:#c4b5fd} | |
| .info-bar{background:#0e0e16;border:1px solid var(--border);border-radius:8px;padding:.5rem .8rem;font-size:.82rem;color:var(--muted);font-family:'SF Mono','Fira Code',monospace} | |
| """ | |
| import time | |
| import gradio as gr | |
| with gr.Blocks(title="FLUX.2-klein-4B GGUF", css=CSS, theme=gr.themes.Soft(primary_hue="violet")) as demo: | |
| gr.HTML(""" | |
| <div style="text-align:center;padding:2rem 0 .6rem"> | |
| <h1 style="font-size:2.4rem;font-weight:800;letter-spacing:-.03em; | |
| background:linear-gradient(135deg,#7c5cfc 0%,#c084fc 50%,#f0abfc 100%); | |
| -webkit-background-clip:text;-webkit-text-fill-color:transparent; | |
| margin:0;line-height:1.2">FLUX.2-klein-4B</h1> | |
| <p style="color:#555;font-size:.88rem;margin-top:.5rem;font-weight:500; | |
| letter-spacing:.08em;text-transform:uppercase"> | |
| GGUF Quantized ยท CPU Inference ยท 4B Parameters</p> | |
| </div>""") | |
| gr.HTML(""" | |
| <div class="warn-bar"> | |
| ⚠ ็บฏ CPU ๆจ็๏ผ้ๅบฆ่พๆ ขใๅปบ่ฎฎ <strong>512ร512</strong> ไปฅไธ + | |
| <strong>8~12 ๆญฅ</strong>ใ้ฆๆฌก็ๆๅ JIT ็ผ่ฏๆดๆ ข๏ผๅ็ปญๅ ้ใ | |
| ่ถ ๆถ่ฏท้ไฝๅ่พจ็ๆๆญฅๆฐใ | |
| </div>""") | |
| with gr.Row(equal_height=False): | |
| with gr.Column(scale=3): | |
| prompt = gr.Textbox(label="Prompt", placeholder="A cyberpunk city at night with neon signs reflecting in rain-soaked streets...", lines=3) | |
| negative_prompt = gr.Textbox(label="Negative Prompt", placeholder="blurry, low quality, distorted...", lines=1) | |
| with gr.Row(): | |
| w = gr.Slider(256, 768, value=512, step=64, label="Width") | |
| h = gr.Slider(256, 768, value=512, step=64, label="Height") | |
| with gr.Row(): | |
| steps = gr.Slider(4, 30, value=10, step=1, label="Steps") | |
| guidance = gr.Slider(1.0, 10.0, value=3.5, step=0.5, label="Guidance Scale") | |
| seed = gr.Number(label="Seed๏ผ-1 ้ๆบ๏ผ", value=-1, precision=0) | |
| btn = gr.Button("โฆ Generate", variant="primary", size="lg") | |
| gr.Examples(examples=[ | |
| ["A serene Japanese garden with cherry blossoms over a stone bridge, koi pond, golden hour, 4K", ""], | |
| ["Futuristic space station interior, holographic star maps, bioluminescent plants, cinematic wide shot", ""], | |
| ["Oil painting of a cozy wooden cabin in snowy mountains, warm light from windows, impressionist style", ""], | |
| ["Macro photograph of a dewdrop on a spider web at sunrise, prismatic light, shallow depth of field", ""], | |
| ["Whimsical treehouse library at twilight, floating books with glowing pages, fairy tale atmosphere", "blurry"], | |
| ["Underwater coral reef city, bioluminescent architecture, tropical fish, volumetric god rays", ""], | |
| ], inputs=[prompt, negative_prompt], label="Quick Examples") | |
| with gr.Column(scale=4): | |
| output_img = gr.Image(label="Output", show_label=False, height=540) | |
| info_text = gr.Textbox(label="Status", interactive=False, max_lines=1, elem_classes="info-bar", value="Ready") | |
| btn.click(fn=generate, inputs=[prompt, negative_prompt, w, h, steps, guidance, seed], outputs=[output_img, seed, info_text]) | |
| prompt.submit(fn=generate, inputs=[prompt, negative_prompt, w, h, steps, guidance, seed], outputs=[output_img, seed, info_text]) | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |