mirror of
https://github.com/invoke-ai/InvokeAI
synced 2026-04-02 04:55:04 +02:00
* Implements rudimentary api * Fixes blocking in API * Adds UI to monorepo > src/frontend/ * Updates frontend/README * Reverts conda env name to `ldm` * Fixes environment yamls * CORS config for testing * Fixes LogViewer position * API WID * Adds actions to image viewer * Increases vite chunkSizeWarningLimit to 1500 * Implements init image * Implements state persistence in localStorage * Improve progress data handling * Final build * Fixes mimetypes error on windows * Adds error logging * Fixes bugged img2img strength component * Adds sourcemaps to dev build * Fixes missing key * Changes connection status indicator to text * Adds ability to serve other hosts than localhost * Adding Flask API server * Removes source maps from config * Fixes prop transfer * Add missing packages and add CORS support * Adding API doc * Remove defaults from openapi doc * Adds basic error handling for server config query * Mostly working socket.io implementation. * Fixes bug preventing mask upload * Fixes bug with sampler name not written to metadata * UI Overhaul, numerous fixes Co-authored-by: Kyle Schouviller <kyle0654@hotmail.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654)
|
|
|
|
import json
|
|
import string
|
|
from copy import deepcopy
|
|
from datetime import datetime, timezone
|
|
from enum import Enum
|
|
|
|
class DreamRequest():
|
|
prompt: string
|
|
initimg: string
|
|
strength: float
|
|
iterations: int
|
|
steps: int
|
|
width: int
|
|
height: int
|
|
fit = None
|
|
cfgscale: float
|
|
sampler_name: string
|
|
gfpgan_strength: float
|
|
upscale_level: int
|
|
upscale_strength: float
|
|
upscale: None
|
|
progress_images = None
|
|
seed: int
|
|
time: int
|
|
|
|
# TODO: use something else for state tracking
|
|
images_generated: int = 0
|
|
images_upscaled: int = 0
|
|
|
|
def id(self, seed = None, upscaled = False) -> str:
|
|
return f"{self.time}.{seed or self.seed}{'.u' if upscaled else ''}"
|
|
|
|
# TODO: handle this more cleanly (probably by splitting this into a Job and Result class)
|
|
# TODO: Set iterations to 1 or remove it from the dream result? And just keep it on the job?
|
|
def clone_without_image(self, seed = None):
|
|
data = deepcopy(self)
|
|
data.initimg = None
|
|
if seed:
|
|
data.seed = seed
|
|
|
|
return data
|
|
|
|
def to_json(self, seed: int = None):
|
|
copy = self.clone_without_image(seed)
|
|
return json.dumps(copy.__dict__)
|
|
|
|
@staticmethod
|
|
def from_json(j, newTime: bool = False):
|
|
d = DreamRequest()
|
|
d.prompt = j.get('prompt')
|
|
d.initimg = j.get('initimg')
|
|
d.strength = float(j.get('strength'))
|
|
d.iterations = int(j.get('iterations'))
|
|
d.steps = int(j.get('steps'))
|
|
d.width = int(j.get('width'))
|
|
d.height = int(j.get('height'))
|
|
d.fit = 'fit' in j
|
|
d.seamless = 'seamless' in j
|
|
d.cfgscale = float(j.get('cfgscale'))
|
|
d.sampler_name = j.get('sampler')
|
|
d.variation_amount = float(j.get('variation_amount'))
|
|
d.with_variations = j.get('with_variations')
|
|
d.gfpgan_strength = float(j.get('gfpgan_strength'))
|
|
d.upscale_level = j.get('upscale_level')
|
|
d.upscale_strength = j.get('upscale_strength')
|
|
d.upscale = [int(d.upscale_level),float(d.upscale_strength)] if d.upscale_level != '' else None
|
|
d.progress_images = 'progress_images' in j
|
|
d.seed = int(j.get('seed'))
|
|
d.time = int(datetime.now(timezone.utc).timestamp()) if newTime else int(j.get('time'))
|
|
return d
|
|
|
|
|
|
class ProgressType(Enum):
|
|
GENERATION = 1
|
|
UPSCALING_STARTED = 2
|
|
UPSCALING_DONE = 3
|
|
|
|
class Signal():
|
|
event: str
|
|
data = None
|
|
room: str = None
|
|
broadcast: bool = False
|
|
|
|
def __init__(self, event: str, data, room: str = None, broadcast: bool = False):
|
|
self.event = event
|
|
self.data = data
|
|
self.room = room
|
|
self.broadcast = broadcast
|
|
|
|
@staticmethod
|
|
def image_progress(jobId: str, dreamId: str, step: int, totalSteps: int, progressType: ProgressType = ProgressType.GENERATION, hasProgressImage: bool = False):
|
|
return Signal('dream_progress', {
|
|
'jobId': jobId,
|
|
'dreamId': dreamId,
|
|
'step': step,
|
|
'totalSteps': totalSteps,
|
|
'hasProgressImage': hasProgressImage,
|
|
'progressType': progressType.name
|
|
}, room=jobId, broadcast=True)
|
|
|
|
# TODO: use a result id or something? Like a sub-job
|
|
@staticmethod
|
|
def image_result(jobId: str, dreamId: str, dreamRequest: DreamRequest):
|
|
return Signal('dream_result', {
|
|
'jobId': jobId,
|
|
'dreamId': dreamId,
|
|
'dreamRequest': dreamRequest.__dict__
|
|
}, room=jobId, broadcast=True)
|
|
|
|
@staticmethod
|
|
def job_started(jobId: str):
|
|
return Signal('job_started', {
|
|
'jobId': jobId
|
|
}, room=jobId, broadcast=True)
|
|
|
|
@staticmethod
|
|
def job_done(jobId: str):
|
|
return Signal('job_done', {
|
|
'jobId': jobId
|
|
}, room=jobId, broadcast=True)
|
|
|
|
@staticmethod
|
|
def job_canceled(jobId: str):
|
|
return Signal('job_canceled', {
|
|
'jobId': jobId
|
|
}, room=jobId, broadcast=True)
|