"lightx2v/common/vscode:/vscode.git/clone" did not exist on "1b5d336d23e02cc50414cf9d8e22243fb181d5f6"
main.py 15.7 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
import re
Timothy J. Baek's avatar
Timothy J. Baek committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
from fastapi import (
    FastAPI,
    Request,
    Depends,
    HTTPException,
    status,
    UploadFile,
    File,
    Form,
)
from fastapi.middleware.cors import CORSMiddleware
from faster_whisper import WhisperModel

from constants import ERROR_MESSAGES
from utils.utils import (
    get_current_user,
    get_admin_user,
)
Timothy J. Baek's avatar
Timothy J. Baek committed
21
22

from apps.images.utils.comfyui import ImageGenerationPayload, comfyui_generate_image
Timothy J. Baek's avatar
Timothy J. Baek committed
23
24
25
from utils.misc import calculate_sha256
from typing import Optional
from pydantic import BaseModel
Timothy J. Baek's avatar
Timothy J. Baek committed
26
from pathlib import Path
27
import mimetypes
Timothy J. Baek's avatar
Timothy J. Baek committed
28
29
30
import uuid
import base64
import json
31
import logging
Timothy J. Baek's avatar
Timothy J. Baek committed
32

Self Denial's avatar
Self Denial committed
33
34
35
from config import (
    SRC_LOG_LEVELS,
    CACHE_DIR,
36
    IMAGE_GENERATION_ENGINE,
Self Denial's avatar
Self Denial committed
37
    ENABLE_IMAGE_GENERATION,
Self Denial's avatar
Self Denial committed
38
39
    AUTOMATIC1111_BASE_URL,
    COMFYUI_BASE_URL,
40
41
42
43
    COMFYUI_CFG_SCALE,
    COMFYUI_SAMPLER,
    COMFYUI_SCHEDULER,
    COMFYUI_SD3,
44
45
    IMAGES_OPENAI_API_BASE_URL,
    IMAGES_OPENAI_API_KEY,
46
    IMAGE_GENERATION_MODEL,
47
48
    IMAGE_SIZE,
    IMAGE_STEPS,
49
    AppConfig,
Self Denial's avatar
Self Denial committed
50
)
Timothy J. Baek's avatar
Timothy J. Baek committed
51
52


53
54
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["IMAGES"])
Timothy J. Baek's avatar
Timothy J. Baek committed
55
56
57

IMAGE_CACHE_DIR = Path(CACHE_DIR).joinpath("./image/generations/")
IMAGE_CACHE_DIR.mkdir(parents=True, exist_ok=True)
Timothy J. Baek's avatar
Timothy J. Baek committed
58
59
60
61
62
63
64
65
66
67

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

68
app.state.config = AppConfig()
Timothy J. Baek's avatar
Timothy J. Baek committed
69

70
71
app.state.config.ENGINE = IMAGE_GENERATION_ENGINE
app.state.config.ENABLED = ENABLE_IMAGE_GENERATION
Timothy J. Baek's avatar
Timothy J. Baek committed
72

73
74
app.state.config.OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL
app.state.config.OPENAI_API_KEY = IMAGES_OPENAI_API_KEY
Timothy J. Baek's avatar
Timothy J. Baek committed
75

76
app.state.config.MODEL = IMAGE_GENERATION_MODEL
Timothy J. Baek's avatar
Timothy J. Baek committed
77

Timothy J. Baek's avatar
Timothy J. Baek committed
78

79
80
app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
Timothy J. Baek's avatar
Timothy J. Baek committed
81

82
83
84

app.state.config.IMAGE_SIZE = IMAGE_SIZE
app.state.config.IMAGE_STEPS = IMAGE_STEPS
85
86
87
88
app.state.config.COMFYUI_CFG_SCALE = COMFYUI_CFG_SCALE
app.state.config.COMFYUI_SAMPLER = COMFYUI_SAMPLER
app.state.config.COMFYUI_SCHEDULER = COMFYUI_SCHEDULER
app.state.config.COMFYUI_SD3 = COMFYUI_SD3
Timothy J. Baek's avatar
Timothy J. Baek committed
89
90


Timothy J. Baek's avatar
Timothy J. Baek committed
91
92
@app.get("/config")
async def get_config(request: Request, user=Depends(get_admin_user)):
93
    return {
94
95
        "engine": app.state.config.ENGINE,
        "enabled": app.state.config.ENABLED,
96
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
97
98


Timothy J. Baek's avatar
Timothy J. Baek committed
99
100
101
102
103
104
105
class ConfigUpdateForm(BaseModel):
    engine: str
    enabled: bool


@app.post("/config/update")
async def update_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)):
106
107
    app.state.config.ENGINE = form_data.engine
    app.state.config.ENABLED = form_data.enabled
108
    return {
109
110
        "engine": app.state.config.ENGINE,
        "enabled": app.state.config.ENABLED,
111
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
112
113


Timothy J. Baek's avatar
Timothy J. Baek committed
114
115
116
class EngineUrlUpdateForm(BaseModel):
    AUTOMATIC1111_BASE_URL: Optional[str] = None
    COMFYUI_BASE_URL: Optional[str] = None
Timothy J. Baek's avatar
Timothy J. Baek committed
117
118
119


@app.get("/url")
Timothy J. Baek's avatar
Timothy J. Baek committed
120
121
async def get_engine_url(user=Depends(get_admin_user)):
    return {
122
123
        "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
        "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
Timothy J. Baek's avatar
Timothy J. Baek committed
124
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
125
126
127


@app.post("/url/update")
Timothy J. Baek's avatar
Timothy J. Baek committed
128
129
async def update_engine_url(
    form_data: EngineUrlUpdateForm, user=Depends(get_admin_user)
Timothy J. Baek's avatar
Timothy J. Baek committed
130
):
Timothy J. Baek's avatar
Timothy J. Baek committed
131

Timothy J. Baek's avatar
Timothy J. Baek committed
132
    if form_data.AUTOMATIC1111_BASE_URL == None:
133
        app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
Timothy J. Baek's avatar
Timothy J. Baek committed
134
    else:
Timothy J. Baek's avatar
Timothy J. Baek committed
135
        url = form_data.AUTOMATIC1111_BASE_URL.strip("/")
Timothy J. Baek's avatar
Timothy J. Baek committed
136
137
        try:
            r = requests.head(url)
138
            app.state.config.AUTOMATIC1111_BASE_URL = url
Timothy J. Baek's avatar
Timothy J. Baek committed
139
140
        except Exception as e:
            raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
141

Timothy J. Baek's avatar
Timothy J. Baek committed
142
    if form_data.COMFYUI_BASE_URL == None:
143
        app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
Timothy J. Baek's avatar
Timothy J. Baek committed
144
145
    else:
        url = form_data.COMFYUI_BASE_URL.strip("/")
Timothy J. Baek's avatar
Timothy J. Baek committed
146
147
148

        try:
            r = requests.head(url)
149
            app.state.config.COMFYUI_BASE_URL = url
Timothy J. Baek's avatar
Timothy J. Baek committed
150
151
        except Exception as e:
            raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
152

Timothy J. Baek's avatar
Timothy J. Baek committed
153
    return {
154
155
        "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
        "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
Timothy J. Baek's avatar
Timothy J. Baek committed
156
157
        "status": True,
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
158
159


160
161
class OpenAIConfigUpdateForm(BaseModel):
    url: str
Timothy J. Baek's avatar
Timothy J. Baek committed
162
163
164
    key: str


165
166
167
@app.get("/openai/config")
async def get_openai_config(user=Depends(get_admin_user)):
    return {
168
169
        "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL,
        "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY,
170
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
171
172


173
174
175
@app.post("/openai/config/update")
async def update_openai_config(
    form_data: OpenAIConfigUpdateForm, user=Depends(get_admin_user)
Timothy J. Baek's avatar
Timothy J. Baek committed
176
177
178
179
):
    if form_data.key == "":
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)

180
181
    app.state.config.OPENAI_API_BASE_URL = form_data.url
    app.state.config.OPENAI_API_KEY = form_data.key
182

Timothy J. Baek's avatar
Timothy J. Baek committed
183
184
    return {
        "status": True,
185
186
        "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL,
        "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY,
Timothy J. Baek's avatar
Timothy J. Baek committed
187
188
189
    }


Timothy J. Baek's avatar
Timothy J. Baek committed
190
191
192
193
194
195
class ImageSizeUpdateForm(BaseModel):
    size: str


@app.get("/size")
async def get_image_size(user=Depends(get_admin_user)):
196
    return {"IMAGE_SIZE": app.state.config.IMAGE_SIZE}
Timothy J. Baek's avatar
Timothy J. Baek committed
197
198
199
200
201
202
203
204


@app.post("/size/update")
async def update_image_size(
    form_data: ImageSizeUpdateForm, user=Depends(get_admin_user)
):
    pattern = r"^\d+x\d+$"  # Regular expression pattern
    if re.match(pattern, form_data.size):
205
        app.state.config.IMAGE_SIZE = form_data.size
Timothy J. Baek's avatar
Timothy J. Baek committed
206
        return {
207
            "IMAGE_SIZE": app.state.config.IMAGE_SIZE,
Timothy J. Baek's avatar
Timothy J. Baek committed
208
209
210
211
212
213
214
            "status": True,
        }
    else:
        raise HTTPException(
            status_code=400,
            detail=ERROR_MESSAGES.INCORRECT_FORMAT("  (e.g., 512x512)."),
        )
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
215

216
217
218
219
220
221
222

class ImageStepsUpdateForm(BaseModel):
    steps: int


@app.get("/steps")
async def get_image_size(user=Depends(get_admin_user)):
223
    return {"IMAGE_STEPS": app.state.config.IMAGE_STEPS}
224
225
226
227
228
229
230


@app.post("/steps/update")
async def update_image_size(
    form_data: ImageStepsUpdateForm, user=Depends(get_admin_user)
):
    if form_data.steps >= 0:
231
        app.state.config.IMAGE_STEPS = form_data.steps
232
        return {
233
            "IMAGE_STEPS": app.state.config.IMAGE_STEPS,
234
235
236
237
238
239
240
            "status": True,
        }
    else:
        raise HTTPException(
            status_code=400,
            detail=ERROR_MESSAGES.INCORRECT_FORMAT("  (e.g., 50)."),
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
241
242


Timothy J. Baek's avatar
Timothy J. Baek committed
243
244
245
@app.get("/models")
def get_models(user=Depends(get_current_user)):
    try:
246
        if app.state.config.ENGINE == "openai":
Timothy J. Baek's avatar
Timothy J. Baek committed
247
248
249
250
            return [
                {"id": "dall-e-2", "name": "DALL·E 2"},
                {"id": "dall-e-3", "name": "DALL·E 3"},
            ]
251
        elif app.state.config.ENGINE == "comfyui":
Timothy J. Baek's avatar
Timothy J. Baek committed
252

253
            r = requests.get(url=f"{app.state.config.COMFYUI_BASE_URL}/object_info")
Timothy J. Baek's avatar
Timothy J. Baek committed
254
255
256
257
258
259
260
261
262
            info = r.json()

            return list(
                map(
                    lambda model: {"id": model, "name": model},
                    info["CheckpointLoaderSimple"]["input"]["required"]["ckpt_name"][0],
                )
            )

Timothy J. Baek's avatar
Timothy J. Baek committed
263
264
        else:
            r = requests.get(
265
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models"
Timothy J. Baek's avatar
Timothy J. Baek committed
266
267
268
269
270
271
272
273
            )
            models = r.json()
            return list(
                map(
                    lambda model: {"id": model["title"], "name": model["model_name"]},
                    models,
                )
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
274
    except Exception as e:
275
        app.state.config.ENABLED = False
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
276
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
277
278
279
280
281


@app.get("/models/default")
async def get_default_model(user=Depends(get_admin_user)):
    try:
282
        if app.state.config.ENGINE == "openai":
283
284
            return {
                "model": (
285
                    app.state.config.MODEL if app.state.config.MODEL else "dall-e-2"
286
287
                )
            }
288
289
        elif app.state.config.ENGINE == "comfyui":
            return {"model": (app.state.config.MODEL if app.state.config.MODEL else "")}
Timothy J. Baek's avatar
Timothy J. Baek committed
290
        else:
291
292
293
            r = requests.get(
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
294
295
            options = r.json()
            return {"model": options["sd_model_checkpoint"]}
Timothy J. Baek's avatar
Timothy J. Baek committed
296
    except Exception as e:
297
        app.state.config.ENABLED = False
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
298
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
299
300
301
302
303
304
305


class UpdateModelForm(BaseModel):
    model: str


def set_model_handler(model: str):
306
307
308
    if app.state.config.ENGINE in ["openai", "comfyui"]:
        app.state.config.MODEL = model
        return app.state.config.MODEL
Timothy J. Baek's avatar
Timothy J. Baek committed
309
    else:
310
311
312
        r = requests.get(
            url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
313
314
315
316
317
        options = r.json()

        if model != options["sd_model_checkpoint"]:
            options["sd_model_checkpoint"] = model
            r = requests.post(
318
319
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
                json=options,
Timothy J. Baek's avatar
Timothy J. Baek committed
320
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
321

Timothy J. Baek's avatar
Timothy J. Baek committed
322
        return options
Timothy J. Baek's avatar
Timothy J. Baek committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336


@app.post("/models/default/update")
def update_default_model(
    form_data: UpdateModelForm,
    user=Depends(get_current_user),
):
    return set_model_handler(form_data.model)


class GenerateImageForm(BaseModel):
    model: Optional[str] = None
    prompt: str
    n: int = 1
Timothy J. Baek's avatar
Timothy J. Baek committed
337
    size: Optional[str] = None
Timothy J. Baek's avatar
Timothy J. Baek committed
338
339
340
    negative_prompt: Optional[str] = None


Timothy J. Baek's avatar
Timothy J. Baek committed
341
342
def save_b64_image(b64_str):
    try:
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
343
        image_id = str(uuid.uuid4())
Timothy J. Baek's avatar
Timothy J. Baek committed
344

Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
345
346
347
        if "," in b64_str:
            header, encoded = b64_str.split(",", 1)
            mime_type = header.split(";")[0]
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
348

Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
            img_data = base64.b64decode(encoded)
            image_format = mimetypes.guess_extension(mime_type)

            image_filename = f"{image_id}{image_format}"
            file_path = IMAGE_CACHE_DIR / f"{image_filename}"
            with open(file_path, "wb") as f:
                f.write(img_data)
            return image_filename
        else:
            image_filename = f"{image_id}.png"
            file_path = IMAGE_CACHE_DIR.joinpath(image_filename)

            img_data = base64.b64decode(b64_str)

            # Write the image data to a file
            with open(file_path, "wb") as f:
                f.write(img_data)
            return image_filename
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
367

Timothy J. Baek's avatar
Timothy J. Baek committed
368
    except Exception as e:
369
        log.exception(f"Error saving image: {e}")
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
370
        return None
Timothy J. Baek's avatar
Timothy J. Baek committed
371
372


Timothy J. Baek's avatar
Timothy J. Baek committed
373
374
375
376
377
def save_url_image(url):
    image_id = str(uuid.uuid4())
    try:
        r = requests.get(url)
        r.raise_for_status()
378
379
380
381
        if r.headers["content-type"].split("/")[0] == "image":

            mime_type = r.headers["content-type"]
            image_format = mimetypes.guess_extension(mime_type)
Timothy J. Baek's avatar
Timothy J. Baek committed
382

383
384
385
            if not image_format:
                raise ValueError("Could not determine image type from MIME type")

Timothy J. Baek's avatar
Timothy J. Baek committed
386
387
388
            image_filename = f"{image_id}{image_format}"

            file_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}")
389
390
391
            with open(file_path, "wb") as image_file:
                for chunk in r.iter_content(chunk_size=8192):
                    image_file.write(chunk)
Timothy J. Baek's avatar
Timothy J. Baek committed
392
            return image_filename
393
394
        else:
            log.error(f"Url does not point to an image.")
Timothy J. Baek's avatar
Timothy J. Baek committed
395
            return None
Timothy J. Baek's avatar
Timothy J. Baek committed
396
397

    except Exception as e:
398
        log.exception(f"Error saving image: {e}")
Timothy J. Baek's avatar
Timothy J. Baek committed
399
        return None
Timothy J. Baek's avatar
Timothy J. Baek committed
400
401


Timothy J. Baek's avatar
Timothy J. Baek committed
402
403
404
405
406
407
@app.post("/generations")
def generate_image(
    form_data: GenerateImageForm,
    user=Depends(get_current_user),
):

408
    width, height = tuple(map(int, app.state.config.IMAGE_SIZE.split("x")))
Timothy J. Baek's avatar
Timothy J. Baek committed
409

Timothy J. Baek's avatar
Timothy J. Baek committed
410
    r = None
411
    try:
412
        if app.state.config.ENGINE == "openai":
413

Timothy J. Baek's avatar
Timothy J. Baek committed
414
            headers = {}
415
            headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEY}"
Timothy J. Baek's avatar
Timothy J. Baek committed
416
            headers["Content-Type"] = "application/json"
417

Timothy J. Baek's avatar
Timothy J. Baek committed
418
            data = {
419
420
421
422
423
                "model": (
                    app.state.config.MODEL
                    if app.state.config.MODEL != ""
                    else "dall-e-2"
                ),
Timothy J. Baek's avatar
Timothy J. Baek committed
424
425
                "prompt": form_data.prompt,
                "n": form_data.n,
426
                "size": (
427
                    form_data.size if form_data.size else app.state.config.IMAGE_SIZE
428
                ),
Timothy J. Baek's avatar
Timothy J. Baek committed
429
430
                "response_format": "b64_json",
            }
431

Timothy J. Baek's avatar
Timothy J. Baek committed
432
            r = requests.post(
433
                url=f"{app.state.config.OPENAI_API_BASE_URL}/images/generations",
Timothy J. Baek's avatar
Timothy J. Baek committed
434
435
436
                json=data,
                headers=headers,
            )
437

Timothy J. Baek's avatar
Timothy J. Baek committed
438
439
            r.raise_for_status()
            res = r.json()
Timothy J. Baek's avatar
Timothy J. Baek committed
440

Timothy J. Baek's avatar
Timothy J. Baek committed
441
442
443
            images = []

            for image in res["data"]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
444
445
                image_filename = save_b64_image(image["b64_json"])
                images.append({"url": f"/cache/image/generations/{image_filename}"})
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
446
                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
Timothy J. Baek's avatar
Timothy J. Baek committed
447
448
449
450
451
452

                with open(file_body_path, "w") as f:
                    json.dump(data, f)

            return images

453
        elif app.state.config.ENGINE == "comfyui":
Timothy J. Baek's avatar
Timothy J. Baek committed
454
455
456
457
458
459
460
461

            data = {
                "prompt": form_data.prompt,
                "width": width,
                "height": height,
                "n": form_data.n,
            }

462
463
            if app.state.config.IMAGE_STEPS is not None:
                data["steps"] = app.state.config.IMAGE_STEPS
Timothy J. Baek's avatar
Timothy J. Baek committed
464

465
            if form_data.negative_prompt is not None:
Timothy J. Baek's avatar
Timothy J. Baek committed
466
467
                data["negative_prompt"] = form_data.negative_prompt

468
469
470
471
472
473
474
475
476
477
478
479
            if app.state.config.COMFYUI_CFG_SCALE:
                data["cfg_scale"] = app.state.config.COMFYUI_CFG_SCALE

            if app.state.config.COMFYUI_SAMPLER is not None:
                data["sampler"] = app.state.config.COMFYUI_SAMPLER

            if app.state.config.COMFYUI_SCHEDULER is not None:
                data["scheduler"] = app.state.config.COMFYUI_SCHEDULER

            if app.state.config.COMFYUI_SD3 is not None:
                data["sd3"] = app.state.config.COMFYUI_SD3

Timothy J. Baek's avatar
Timothy J. Baek committed
480
481
482
            data = ImageGenerationPayload(**data)

            res = comfyui_generate_image(
483
                app.state.config.MODEL,
Timothy J. Baek's avatar
Timothy J. Baek committed
484
485
                data,
                user.id,
486
                app.state.config.COMFYUI_BASE_URL,
Timothy J. Baek's avatar
Timothy J. Baek committed
487
            )
488
            log.debug(f"res: {res}")
Timothy J. Baek's avatar
Timothy J. Baek committed
489
490
491
492

            images = []

            for image in res["data"]:
Timothy J. Baek's avatar
Timothy J. Baek committed
493
494
495
                image_filename = save_url_image(image["url"])
                images.append({"url": f"/cache/image/generations/{image_filename}"})
                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
Timothy J. Baek's avatar
Timothy J. Baek committed
496
497
498
499

                with open(file_body_path, "w") as f:
                    json.dump(data.model_dump(exclude_none=True), f)

500
            log.debug(f"images: {images}")
Timothy J. Baek's avatar
Timothy J. Baek committed
501
            return images
Timothy J. Baek's avatar
Timothy J. Baek committed
502
503
504
505
506
507
508
509
510
511
512
        else:
            if form_data.model:
                set_model_handler(form_data.model)

            data = {
                "prompt": form_data.prompt,
                "batch_size": form_data.n,
                "width": width,
                "height": height,
            }

513
514
            if app.state.config.IMAGE_STEPS is not None:
                data["steps"] = app.state.config.IMAGE_STEPS
Timothy J. Baek's avatar
Timothy J. Baek committed
515

516
            if form_data.negative_prompt is not None:
Timothy J. Baek's avatar
Timothy J. Baek committed
517
518
519
                data["negative_prompt"] = form_data.negative_prompt

            r = requests.post(
520
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img",
Timothy J. Baek's avatar
Timothy J. Baek committed
521
522
523
524
525
                json=data,
            )

            res = r.json()

526
            log.debug(f"res: {res}")
Timothy J. Baek's avatar
Timothy J. Baek committed
527
528
529
530

            images = []

            for image in res["images"]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
531
532
                image_filename = save_b64_image(image)
                images.append({"url": f"/cache/image/generations/{image_filename}"})
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
533
                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
Timothy J. Baek's avatar
Timothy J. Baek committed
534
535
536
537
538

                with open(file_body_path, "w") as f:
                    json.dump({**data, "info": res["info"]}, f)

            return images
539
540

    except Exception as e:
541
542
543
544
545
546
547
        error = e

        if r != None:
            data = r.json()
            if "error" in data:
                error = data["error"]["message"]
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(error))