api.py 5.7 KB
Newer Older
1
import uvicorn
B
Bruno Seoane 已提交
2
from gradio.processing_utils import encode_pil_to_base64, decode_base64_to_file, decode_base64_to_image
B
Bruno Seoane 已提交
3
from fastapi import APIRouter, HTTPException
4
import modules.shared as shared
5
from modules.api.models import *
6 7
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
from modules.sd_samplers import all_samplers
B
Bruno Seoane 已提交
8 9 10 11 12 13
from modules.extras import run_extras

def upscaler_to_index(name: str):
    try:
        return [x.name.lower() for x in shared.sd_upscalers].index(name.lower())
    except:
B
Bruno Seoane 已提交
14
        raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be on of these: {' , '.join([x.name for x in sd_upscalers])}")
15

A
arcticfaded 已提交
16
sampler_to_index = lambda name: next(filter(lambda row: name.lower() == row[1].name.lower(), enumerate(all_samplers)), None)
A
arcticfaded 已提交
17

B
Bruno Seoane 已提交
18 19 20 21 22 23 24 25
def setUpscalers(req: dict):
    reqDict = vars(req)
    reqDict['extras_upscaler_1'] = upscaler_to_index(req.upscaler_1)
    reqDict['extras_upscaler_2'] = upscaler_to_index(req.upscaler_2)
    reqDict.pop('upscaler_1')
    reqDict.pop('upscaler_2')
    return reqDict

26
class Api:
A
arcticfaded 已提交
27
    def __init__(self, app, queue_lock):
28
        self.router = APIRouter()
A
arcticfaded 已提交
29 30
        self.app = app
        self.queue_lock = queue_lock
B
Bruno Seoane 已提交
31
        self.app.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=TextToImageResponse)
32
        self.app.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse)
B
Bruno Seoane 已提交
33
        self.app.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse)
34
        self.app.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse)
B
Bruno Seoane 已提交
35
        self.app.add_api_route("/sdapi/v1/extra-folder-images", self.extras_folder_processing_api, methods=["POST"], response_model=ExtrasBatchImagesResponse)
S
Stephen 已提交
36

37
    def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
A
arcticfaded 已提交
38 39 40 41 42
        sampler_index = sampler_to_index(txt2imgreq.sampler_index)
        
        if sampler_index is None:
            raise HTTPException(status_code=404, detail="Sampler not found") 
        
A
arcticfaded 已提交
43 44
        populate = txt2imgreq.copy(update={ # Override __init__ params
            "sd_model": shared.sd_model, 
A
arcticfaded 已提交
45
            "sampler_index": sampler_index[0],
A
arcticfaded 已提交
46 47
            "do_not_save_samples": True,
            "do_not_save_grid": True
A
arcticfaded 已提交
48 49 50 51
            }
        )
        p = StableDiffusionProcessingTxt2Img(**vars(populate))
        # Override object param
A
arcticfaded 已提交
52 53
        with self.queue_lock:
            processed = process_images(p)
54
        
B
Bruno Seoane 已提交
55
        b64images = list(map(encode_pil_to_base64, processed.images))
56
        
57
        return TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.info)
58

59 60 61 62 63 64 65 66 67 68 69
    def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
        sampler_index = sampler_to_index(img2imgreq.sampler_index)
        
        if sampler_index is None:
            raise HTTPException(status_code=404, detail="Sampler not found") 


        init_images = img2imgreq.init_images
        if init_images is None:
            raise HTTPException(status_code=404, detail="Init image not found") 

S
Stephen 已提交
70 71
        mask = img2imgreq.mask
        if mask:
B
Bruno Seoane 已提交
72
            mask = decode_base64_to_image(mask)
S
Stephen 已提交
73

74 75 76 77 78
        
        populate = img2imgreq.copy(update={ # Override __init__ params
            "sd_model": shared.sd_model, 
            "sampler_index": sampler_index[0],
            "do_not_save_samples": True,
S
Stephen 已提交
79 80
            "do_not_save_grid": True, 
            "mask": mask
81 82 83 84 85 86
            }
        )
        p = StableDiffusionProcessingImg2Img(**vars(populate))

        imgs = []
        for img in init_images:
B
Bruno Seoane 已提交
87
            img = decode_base64_to_image(img)
88 89 90 91 92 93 94
            imgs = [img] * p.batch_size

        p.init_images = imgs
        # Override object param
        with self.queue_lock:
            processed = process_images(p)
        
B
Bruno Seoane 已提交
95
        b64images = list(map(encode_pil_to_base64, processed.images))
96
       
97
        return ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.info)
98

B
Bruno Seoane 已提交
99
    def extras_single_image_api(self, req: ExtrasSingleImageRequest):
B
Bruno Seoane 已提交
100
        reqDict = setUpscalers(req)
B
Bruno Seoane 已提交
101

B
Bruno Seoane 已提交
102
        reqDict['image'] = decode_base64_to_image(reqDict['image'])
B
Bruno Seoane 已提交
103 104

        with self.queue_lock:
B
Bruno Seoane 已提交
105
            result = run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", **reqDict)
B
Bruno Seoane 已提交
106

B
Bruno Seoane 已提交
107
        return ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1])
108 109

    def extras_batch_images_api(self, req: ExtrasBatchImagesRequest):
B
Bruno Seoane 已提交
110
        reqDict = setUpscalers(req)
111

B
Bruno Seoane 已提交
112 113 114 115 116 117
        def prepareFiles(file):
            file = decode_base64_to_file(file.data, file_path=file.name)
            file.orig_name = file.name
            return file

        reqDict['image_folder'] = list(map(prepareFiles, reqDict['imageList']))
118 119 120
        reqDict.pop('imageList')

        with self.queue_lock:
B
Bruno Seoane 已提交
121
            result = run_extras(extras_mode=1, image="", input_dir="", output_dir="", **reqDict)
122

B
Bruno Seoane 已提交
123
        return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1])
124
    
B
Bruno Seoane 已提交
125 126 127 128 129 130
    def extras_folder_processing_api(self, req:ExtrasFoldersRequest):
        reqDict = setUpscalers(req)

        with self.queue_lock:
            result = run_extras(extras_mode=2, image=None, image_folder=None, **reqDict)

B
Bruno Seoane 已提交
131
        return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1])
132

A
arcticfaded 已提交
133
    def pnginfoapi(self):
134 135 136
        raise NotImplementedError

    def launch(self, server_name, port):
A
arcticfaded 已提交
137 138
        self.app.include_router(self.router)
        uvicorn.run(self.app, host=server_name, port=port)