STABLE_DIFFUSION/server.py

Python source for AI models in Docker containers, 97 lines. Raw file

from diffusers import StableDiffusionPipeline
import PIL.Image
import asyncio
import websockets
import json
import base64
import torch
import io

model = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4")
next_job_id = 1


class Messenger:
    def __init__(self, websocket):
        self.websocket = websocket

    async def progress(self, progress):
        payload = {
            "progress": progress
        }
        payload_serialized = json.dumps(payload)
        await self.websocket.send(payload_serialized)

    async def success(self, result):
        payload = {
            "type": "image",
            "success": result
        }
        payload_serialized = json.dumps(payload)
        await self.websocket.send(payload_serialized)
        await self.websocket.close()

    async def error(self, error):
        payload = {
            "error": error
        }
        payload_serialized = json.dumps(payload)
        await self.websocket.send(payload_serialized)
        await self.websocket.close()


def to_base64(image: PIL.Image.Image) -> str:
    with io.BytesIO() as output:
        image.save(output, format='PNG')
        contents = output.getvalue()
    img_str = base64.b64encode(contents).decode()
    return f"data:image/png;base64,{img_str}"


# Websocket handler function, this is executed everytime new user connects
async def handler(websocket):
    message = await websocket.recv()
    message_data = json.loads(message)
    messenger = Messenger(websocket)

    if message_data.get("started"):
        global next_job_id, model

        current_job_id: int = next_job_id
        next_job_id += 1
        print(f"Started worker with job id: {current_job_id}")
        await messenger.progress(0)

        # Get the prompt, and model from the message
        prompt: str = message_data.get("prompt")
        settings = message_data.get("settings")

        await messenger.progress(25)
        pipe = model.to(settings["device"])

        await messenger.progress(50)

        generated_images_arr: list = pipe(prompt).images

        encoded_images_arr: list = [to_base64(img) for _, img in enumerate(generated_images_arr)]

        print(f"Sequence complete for job id: {current_job_id}")
        await messenger.progress(100)

        # Send the result back to the client
        await messenger.success(encoded_images_arr)


if __name__ == "__main__":
    start_server = websockets.serve(handler, "0.0.0.0", 1337)
    asyncio.get_event_loop().run_until_complete(start_server)
    print("Server started...")

    try:
        asyncio.get_event_loop().run_forever()
    except KeyboardInterrupt:
        print("Keyboard Interrupt: Exiting server")
    except:
        print("Unknown error")
    finally:
        exit(1)