Download app.py from Amaro2a/flakeai: direct link, hf CLI and curl.
- Browser
- Download file 4.09 kB
-
https://huggingface.co/spaces/Amaro2a/flakeai/resolve/main/app.py
- Command line
-
hf download hf://spaces/Amaro2a/flakeai/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Amaro2a/flakeai/resolve/main/app.py
4.09 kB
| import torch | |
| import logging | |
| import io | |
| from pathlib import Path | |
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| from starlette.responses import StreamingResponse | |
| from diffusers import StableDiffusionPipeline | |
| from peft import PeftModel | |
| from fastapi.middleware.cors import CORSMiddleware | |
| # ================================== | |
| # Setup: App, Logging, Constants | |
| # ================================== | |
| app = FastAPI( | |
| title="Stable Diffusion LoRA Inference API", | |
| description="The Flake API to generate images using a Stable Diffusion model fine-tuned with LoRA.", | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], # Or specify your frontend's URL | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(levelname)s - %(message)s", | |
| ) | |
| # Constants for model paths | |
| BASE_MODEL_ID = "runwayml/stable-diffusion-v1-5" | |
| LORA_UNET_PATH = "./lora_unet" | |
| LORA_TEXT_ENCODER_PATH = "./lora_text" | |
| # Global variable to hold the pipeline | |
| pipe = None | |
| # ================================== | |
| # Pydantic Models for API | |
| # ================================== | |
| class ImageRequest(BaseModel): | |
| """Request model for image generation.""" | |
| prompt: str | |
| num_steps: int = 30 | |
| guidance_scale: float = 7.5 | |
| # ================================== | |
| # Model Loading & Application Events | |
| # ================================== | |
| def load_model(): | |
| """ | |
| Load the model and adapters once when the application starts. | |
| This is efficient as the model stays in memory. | |
| """ | |
| global pipe | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| torch_dtype = torch.float16 if device == "cuda" else torch.float32 | |
| logging.info(f"Using device: {device}") | |
| # Load the base pipeline | |
| logging.info(f"Loading base model: {BASE_MODEL_ID}") | |
| pipe = StableDiffusionPipeline.from_pretrained( | |
| BASE_MODEL_ID, | |
| torch_dtype=torch_dtype, | |
| safety_checker=None, | |
| ) | |
| # Load and fuse the LoRA adapters | |
| try: | |
| logging.info(f"Loading and attaching UNet LoRA from: {LORA_UNET_PATH}") | |
| pipe.unet = PeftModel.from_pretrained(pipe.unet, LORA_UNET_PATH) | |
| logging.info(f"Loading and attaching Text Encoder LoRA from: {LORA_TEXT_ENCODER_PATH}") | |
| pipe.text_encoder = PeftModel.from_pretrained(pipe.text_encoder, LORA_TEXT_ENCODER_PATH) | |
| except Exception as e: | |
| logging.error(f"Fatal: Could not load LoRA adapters. Server will not work. Error: {e}") | |
| # In a real scenario, you might want the app to fail startup if models don't load. | |
| raise RuntimeError(f"Failed to load LoRA adapters: {e}") from e | |
| pipe.to(device) | |
| logging.info("Model and LoRA adapters loaded successfully.") | |
| # ================================== | |
| # API Endpoints | |
| # ================================== | |
| def read_root(): | |
| """Root endpoint to check if the API is running.""" | |
| return {"status": "API is running", "docs_url": "/docs"} | |
| async def generate_image_endpoint(request: ImageRequest): | |
| """ | |
| Endpoint to generate an image. | |
| Receives a POST request with a JSON body containing the prompt. | |
| Returns the generated image as a PNG file. | |
| """ | |
| if pipe is None: | |
| raise HTTPException(status_code=503, detail="Model is not loaded or failed to load.") | |
| try: | |
| logging.info(f"Generating image for prompt: '{request.prompt}'") | |
| image = pipe( | |
| prompt=request.prompt, | |
| num_inference_steps=request.num_steps, | |
| guidance_scale=request.guidance_scale, | |
| ).images[0] | |
| # Save image to an in-memory buffer | |
| buffer = io.BytesIO() | |
| image.save(buffer, format="PNG") | |
| buffer.seek(0) | |
| # Return the image as a streaming response | |
| return StreamingResponse(buffer, media_type="image/png") | |
| except Exception as e: | |
| logging.error(f"Error during image generation: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) |