# app.py (ไฟล์นี้จะถูกอัปโหลดไปยัง Hugging Face Space) import gradio as gr from PIL import Image import torch from diffusers import DiffusionPipeline import transformers # จำเป็นสำหรับ diffusers import accelerate # จำเป็นสำหรับ diffusers # --- ตรวจสอบและตั้งค่า Device --- # Hugging Face Spaces มักจะตั้งค่า CUDA_VISIBLE_DEVICES ให้ถูกต้องแล้ว # แต่โค้ดนี้ก็ยังใช้ได้ดี if torch.cuda.is_available(): device = "cuda" # ใช้ float16 เพื่อประหยัด VRAM บน GPU # สำหรับ SDXL แนะนำให้ใช้ variant="fp16" ด้วย torch_dtype = torch.float16 print(f"ใช้ GPU: {torch.cuda.get_device_name(0)}") else: device = "cpu" # CPU ไม่รองรับ float16 โดยตรงสำหรับบาง operations torch_dtype = torch.float32 print("ไม่พบ GPU, จะใช้ CPU (อาจช้ามากสำหรับ Stable Diffusion)") # --- โหลดโมเดล Stable Diffusion --- # โหลดโมเดลนอกฟังก์ชัน generate เพื่อให้โหลดเพียงครั้งเดียวเมื่อแอปเริ่มทำงาน model_id = "stabilityai/stable-diffusion-xl-base-1.0" pipe = None # กำหนดค่าเริ่มต้นเป็น None try: print(f"กำลังโหลดโมเดล: {model_id}") pipe = DiffusionPipeline.from_pretrained( model_id, torch_dtype=torch_dtype, use_safetensors=True, # ใช้ variant fp16 ถ้ามี GPU เพื่อลดขนาดโมเดลและ VRAM variant="fp16" if device == "cuda" else None ) pipe = pipe.to(device) print(f"โหลดโมเดล {model_id} สำเร็จ และย้ายไปที่ {device}") # --- Optimizations สำหรับ GPU --- if device == "cuda": # เปิดใช้งาน memory efficient attention ด้วย xformers (ถ้าติดตั้ง) # ช่วยลด VRAM ได้มาก try: import xformers.ops pipe.enable_xformers_memory_efficient_attention() print("เปิดใช้งาน xformers memory efficient attention") except ImportError: print("xformers ไม่ได้ติดตั้งหรือไม่พร้อมใช้งาน, ไม่สามารถเปิดใช้งาน memory efficient attention ได้") except Exception as e: print(f"เกิดข้อผิดพลาดในการเปิดใช้งาน xformers: {e}") # Optional: เปิดใช้งาน attention slicing (อาจช่วยลด VRAM ได้อีก แต่ช้าลงเล็กน้อย) # pipe.enable_attention_slicing() # print("เปิดใช้งาน attention slicing") # Optional: เปิดใช้งาน sequential CPU offload (ลด VRAM ได้มาก แต่ช้าลงมาก) # pipe.enable_sequential_cpu_offload() # print("เปิดใช้งาน sequential CPU offload") except Exception as e: print(f"เกิดข้อผิดพลาดในการโหลดโมเดล: {e}") print("อาจเกิดจาก VRAM ไม่เพียงพอ หรือการเชื่อมต่ออินเทอร์เน็ตมีปัญหา") pipe = None # ตั้งค่า pipe เป็น None หากโหลดไม่สำเร็จ # --- ฟังก์ชันสร้างภาพสำหรับ Gradio --- def generate_image_for_gradio(prompt: str): # ตรวจสอบว่าโมเดลโหลดสำเร็จหรือไม่ if pipe is None: error_message = "โมเดล Stable Diffusion ยังไม่ได้โหลด หรือเกิดข้อผิดพลาดในการโหลด" print(error_message) # ส่งคืนภาพ placeholder หรือข้อความแสดงข้อผิดพลาด # สร้างภาพสีแดงพร้อมข้อความแสดงข้อผิดพลาด img = Image.new('RGB', (256, 256), color = (255, 0, 0)) from PIL import ImageDraw, ImageFont draw = ImageDraw.Draw(img) try: # ลองโหลดฟอนต์มาตรฐาน font = ImageFont.load_default() except: font = None # ใช้ค่าเริ่มต้นถ้าโหลดฟอนต์ไม่ได้ text_to_display = "Error: Model not loaded" if font: # ใช้ textbbox สำหรับ PIL เวอร์ชันใหม่ try: bbox = draw.textbbox((0, 0), text_to_display, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] except: # Fallback สำหรับ PIL เวอร์ชันเก่า text_width, text_height = draw.textsize(text_to_display, font) text_x = (256 - text_width) // 2 text_y = (256 - text_height) // 2 draw.text((text_x, text_y), text_to_display, fill=(255,255,255), font=font) else: draw.text((10, 10), text_to_display, fill=(255,255,255)) return img # ส่งคืนภาพแสดงข้อผิดพลาด print(f"\nกำลังสร้างภาพสำหรับ Prompt: \"{prompt}\"") print(f"Device: {device}") # กำหนดค่าพารามิเตอร์การสร้างภาพ # ค่าเหล่านี้ปรับได้ตามต้องการ แต่ค่าเริ่มต้นนี้เหมาะสำหรับ Free GPU num_inference_steps = 25 # จำนวนขั้นตอน (20-50) guidance_scale = 7.0 # ความเข้มข้นของ prompt (5-15) # ลดขนาดภาพลงเพื่อประหยัด VRAM height = 768 width = 768 # Negative prompt เพื่อควบคุมสิ่งที่ไม่ต้องการ negative_prompt = "blurry, low quality, cartoon, watermark, text, ugly, deformed, extra limbs, missing limbs" try: # เรียก pipeline เพื่อสร้างภาพ image = pipe( prompt=prompt, negative_prompt=negative_prompt, num_inference_steps=num_inference_steps, guidance_scale=guidance_scale, height=height, width=width ).images[0] # .images จะคืนค่าเป็น list, เราต้องการภาพแรก print("สร้างภาพสำเร็จ!") return image except torch.cuda.OutOfMemoryError: oom_message = "เกิดข้อผิดพลาด: VRAM ไม่เพียงพอ ลองลดขนาดภาพ หรือใช้โมเดลที่เล็กกว่า" print(oom_message) # ส่งคืนภาพสีส้มพร้อมข้อความแสดง VRAM Error img = Image.new('RGB', (256, 256), color = (255, 165, 0)) from PIL import ImageDraw, ImageFont draw = ImageDraw.Draw(img) try: font = ImageFont.load_default() except: font = None text_to_display = "Error: Out of VRAM" if font: try: bbox = draw.textbbox((0, 0), text_to_display, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] except: text_width, text_height = draw.textsize(text_to_display, font) text_x = (256 - text_width) // 2 text_y = (256 - text_height) // 2 draw.text((text_x, text_y), text_to_display, fill=(0,0,0), font=font) else: draw.text((10, 10), text_to_display, fill=(0,0,0)) return img except Exception as e: print(f"เกิดข้อผิดพลาดในการสร้างภาพ: {e}") # ส่งคืนภาพสีแดงพร้อมข้อความแสดงข้อผิดพลาดทั่วไป img = Image.new('RGB', (256, 256), color = (255, 0, 0)) from PIL import ImageDraw, ImageFont draw = ImageDraw.Draw(img) try: font = ImageFont.load_default() except: font = None # แสดงข้อความ error บางส่วน text_to_display = "Error: " + str(e)[:50] + "..." if font: try: bbox = draw.textbbox((0, 0), text_to_display, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] except: text_width, text_height = draw.textsize(text_to_display, font) text_x = (256 - text_width) // 2 text_y = (256 - text_height) // 2 draw.text((text_x, text_y), text_to_display, fill=(255,255,255), font=font) else: draw.text((10, 10), text_to_display, fill=(255,255,255)) return img # --- สร้าง Gradio Interface --- iface = gr.Interface( fn=generate_image_for_gradio, inputs=gr.Textbox(lines=2, placeholder="Enter your prompt here...", label="Prompt"), outputs=gr.Image(type="pil", label="Generated Image"), title="Stable Diffusion XL Text-to-Image (Hugging Face Free GPU Demo)", description="Generate images using Stable Diffusion XL 1.0 on a free Hugging Face GPU Space. May be slow or fail due to resource limits like VRAM.", examples=[ ["A cute cat wearing a hat, cinematic lighting"], ["A beautiful sunset over mountains, digital art"], ["An epic fantasy landscape, highly detailed, trending on artstation"] ] ) # --- รัน Interface (สำหรับทดสอบ local หรือเมื่อ deploy บน Hugging Face Spaces) --- if __name__ == "__main__": # บน Hugging Face Spaces ไม่ต้องใส่ share=True # ถ้าทดสอบ local และต้องการ share ให้ใส่ share=True iface.launch()