Spaces:
Running
Running
| import os | |
| import shutil | |
| import torch | |
| import gradio as gr | |
| from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline | |
| from huggingface_hub import hf_hub_download, HfApi | |
| def convert_and_push(source_repo, file_name, model_type, target_repo, hf_token): | |
| # 檢查 Token 是否為空 | |
| if not hf_token: | |
| return "❌ 錯誤:請輸入具有寫入權限的 Hugging Face Token!" | |
| # 定義暫存目錄,轉換完會刪除 | |
| output_dir = "temp_diffusers_model" | |
| api = HfApi() | |
| try: | |
| # --- 第一步:從雲端下載檔案 --- | |
| gr.Info(f"正在從 {source_repo} 下載 {file_name}...") | |
| # hf_hub_download 會把檔案抓到 Space 的快取暫存區 | |
| local_ckpt_path = hf_hub_download( | |
| repo_id=source_repo.strip(), | |
| filename=file_name.strip() | |
| ) | |
| # --- 第二步:判斷模型版本並選擇對應的轉換引擎 --- | |
| # SD 1.5/2.1 與 SDXL 的結構不同,所以必須切換類別 | |
| if model_type == "SDXL": | |
| gr.Info("偵測到 SDXL,使用 StableDiffusionXLPipeline 轉換...") | |
| pipeline_class = StableDiffusionXLPipeline | |
| else: | |
| gr.Info("使用 StableDiffusionPipeline 轉換 (SD1.5/2.1)...") | |
| pipeline_class = StableDiffusionPipeline | |
| # --- 第三步:執行核心轉換 --- | |
| # from_single_file 是一個強大的方法,能把單一 .safetensors 拆解成 Diffusers 資料夾結構 | |
| # load_safety_checker=False: 關閉安全檢查器以節省 VRAM/RAM | |
| # torch_dtype=torch.float32: 在免費 CPU Space 建議用 float32,最穩定 | |
| pipe = pipeline_class.from_single_file( | |
| local_ckpt_path, | |
| load_safety_checker=False, | |
| torch_dtype=torch.float32 | |
| ) | |
| # 將轉換好的各個子元件(unet, vae, tokenizer 等)存入暫存資料夾 | |
| pipe.save_pretrained(output_dir) | |
| # --- 第四步:推送到你的 Hugging Face 倉庫 --- | |
| gr.Info(f"正在推送到目標倉庫: {target_repo}...") | |
| # 1. 自動建立目標倉庫 (如果已經存在則會忽略) | |
| api.create_repo( | |
| repo_id=target_repo.strip(), | |
| token=hf_token, | |
| exist_ok=True, | |
| repo_type="model" | |
| ) | |
| # 2. 將整個資料夾上傳,這會自動完成 Diffusers 的標準檔案佈局 | |
| api.upload_folder( | |
| folder_path=output_dir, | |
| repo_id=target_repo.strip(), | |
| token=hf_token, | |
| repo_type="model" | |
| ) | |
| # --- 第五步:清理暫存,釋放硬碟空間 --- | |
| shutil.rmtree(output_dir) | |
| return f"✅ 成功完成!\n模型已轉換並推送到:https://huggingface.co{target_repo}" | |
| except Exception as e: | |
| # 發生錯誤時也嘗試清理暫存,避免硬碟爆掉 | |
| if os.path.exists(output_dir): | |
| shutil.rmtree(output_dir) | |
| return f"❌ 出錯了:{str(e)}" | |
| # --- Gradio UI 排版 --- | |
| with gr.Blocks(theme=gr.themes.Soft(), title="SD 轉 Diffusers 工具") as demo: | |
| gr.Markdown("# 🚀 SD to Diffusers 雲端自動推送工具") | |
| gr.Markdown("本工具能將單一檔案模型 (.safetensors) 直接轉換為 Diffusers 格式並推送到你的個人 Repo。") | |
| with gr.Row(): | |
| # 左邊區塊:來源模型資訊 | |
| with gr.Column(): | |
| gr.Markdown("### 📥 1. 來源模型 (Source)") | |
| src_repo = gr.Textbox(label="來源 Repo ID", placeholder="作者/倉庫名稱") | |
| src_file = gr.Textbox(label="來源檔案名稱", placeholder="包含副檔名,如 model.safetensors") | |
| m_type = gr.Radio(["SD1.5 / SD2.1", "SDXL"], label="模型版本", value="SD1.5 / SD2.1") | |
| # 右邊區塊:目標位置與金鑰 | |
| with gr.Column(): | |
| gr.Markdown("### 📤 2. 目標設定 (Target)") | |
| tgt_repo = gr.Textbox(label="你的目標 Repo ID", placeholder="你的名稱/新倉庫名稱") | |
| hf_token = gr.Textbox(label="Hugging Face Write Token", placeholder="需有 Write 權限的 Token", type="password") | |
| # 執行按鈕 | |
| run_btn = gr.Button("🔥 開始轉換並推送", variant="primary") | |
| # 狀態回饋 | |
| status_output = gr.Textbox(label="執行進度與狀態", lines=5) | |
| # 綁定按鈕動作 | |
| run_btn.click( | |
| fn=convert_and_push, | |
| inputs=[src_repo, src_file, m_type, tgt_repo, hf_token], | |
| outputs=status_output | |
| ) | |
| demo.launch() | |