main.py 14.9 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
    IMAGES_OPENAI_API_BASE_URL,
    IMAGES_OPENAI_API_KEY,
42
    IMAGE_GENERATION_MODEL,
43
44
    IMAGE_SIZE,
    IMAGE_STEPS,
45
    AppConfig,
Self Denial's avatar
Self Denial committed
46
)
Timothy J. Baek's avatar
Timothy J. Baek committed
47
48


49
50
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["IMAGES"])
Timothy J. Baek's avatar
Timothy J. Baek committed
51
52
53

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
54
55
56
57
58
59
60
61
62
63

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

64
app.state.config = AppConfig()
Timothy J. Baek's avatar
Timothy J. Baek committed
65

66
67
app.state.config.ENGINE = IMAGE_GENERATION_ENGINE
app.state.config.ENABLED = ENABLE_IMAGE_GENERATION
Timothy J. Baek's avatar
Timothy J. Baek committed
68

69
70
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
71

72
app.state.config.MODEL = IMAGE_GENERATION_MODEL
Timothy J. Baek's avatar
Timothy J. Baek committed
73

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

75
76
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
77

78
79
80

app.state.config.IMAGE_SIZE = IMAGE_SIZE
app.state.config.IMAGE_STEPS = IMAGE_STEPS
Timothy J. Baek's avatar
Timothy J. Baek committed
81
82


Timothy J. Baek's avatar
Timothy J. Baek committed
83
84
@app.get("/config")
async def get_config(request: Request, user=Depends(get_admin_user)):
85
    return {
86
87
        "engine": app.state.config.ENGINE,
        "enabled": app.state.config.ENABLED,
88
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
89
90


Timothy J. Baek's avatar
Timothy J. Baek committed
91
92
93
94
95
96
97
class ConfigUpdateForm(BaseModel):
    engine: str
    enabled: bool


@app.post("/config/update")
async def update_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)):
98
99
    app.state.config.ENGINE = form_data.engine
    app.state.config.ENABLED = form_data.enabled
100
    return {
101
102
        "engine": app.state.config.ENGINE,
        "enabled": app.state.config.ENABLED,
103
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
104
105


Timothy J. Baek's avatar
Timothy J. Baek committed
106
107
108
class EngineUrlUpdateForm(BaseModel):
    AUTOMATIC1111_BASE_URL: Optional[str] = None
    COMFYUI_BASE_URL: Optional[str] = None
Timothy J. Baek's avatar
Timothy J. Baek committed
109
110
111


@app.get("/url")
Timothy J. Baek's avatar
Timothy J. Baek committed
112
113
async def get_engine_url(user=Depends(get_admin_user)):
    return {
114
115
        "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
116
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
117
118
119


@app.post("/url/update")
Timothy J. Baek's avatar
Timothy J. Baek committed
120
121
async def update_engine_url(
    form_data: EngineUrlUpdateForm, user=Depends(get_admin_user)
Timothy J. Baek's avatar
Timothy J. Baek committed
122
):
Timothy J. Baek's avatar
Timothy J. Baek committed
123

Timothy J. Baek's avatar
Timothy J. Baek committed
124
    if form_data.AUTOMATIC1111_BASE_URL == None:
125
        app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
Timothy J. Baek's avatar
Timothy J. Baek committed
126
    else:
Timothy J. Baek's avatar
Timothy J. Baek committed
127
        url = form_data.AUTOMATIC1111_BASE_URL.strip("/")
Timothy J. Baek's avatar
Timothy J. Baek committed
128
129
        try:
            r = requests.head(url)
130
            app.state.config.AUTOMATIC1111_BASE_URL = url
Timothy J. Baek's avatar
Timothy J. Baek committed
131
132
        except Exception as e:
            raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
133

Timothy J. Baek's avatar
Timothy J. Baek committed
134
    if form_data.COMFYUI_BASE_URL == None:
135
        app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
Timothy J. Baek's avatar
Timothy J. Baek committed
136
137
    else:
        url = form_data.COMFYUI_BASE_URL.strip("/")
Timothy J. Baek's avatar
Timothy J. Baek committed
138
139
140

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

Timothy J. Baek's avatar
Timothy J. Baek committed
145
    return {
146
147
        "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
148
149
        "status": True,
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
150
151


152
153
class OpenAIConfigUpdateForm(BaseModel):
    url: str
Timothy J. Baek's avatar
Timothy J. Baek committed
154
155
156
    key: str


157
158
159
@app.get("/openai/config")
async def get_openai_config(user=Depends(get_admin_user)):
    return {
160
161
        "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL,
        "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY,
162
    }
Timothy J. Baek's avatar
Timothy J. Baek committed
163
164


165
166
167
@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
168
169
170
171
):
    if form_data.key == "":
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)

172
173
    app.state.config.OPENAI_API_BASE_URL = form_data.url
    app.state.config.OPENAI_API_KEY = form_data.key
174

Timothy J. Baek's avatar
Timothy J. Baek committed
175
176
    return {
        "status": True,
177
178
        "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
179
180
181
    }


Timothy J. Baek's avatar
Timothy J. Baek committed
182
183
184
185
186
187
class ImageSizeUpdateForm(BaseModel):
    size: str


@app.get("/size")
async def get_image_size(user=Depends(get_admin_user)):
188
    return {"IMAGE_SIZE": app.state.config.IMAGE_SIZE}
Timothy J. Baek's avatar
Timothy J. Baek committed
189
190
191
192
193
194
195
196


@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):
197
        app.state.config.IMAGE_SIZE = form_data.size
Timothy J. Baek's avatar
Timothy J. Baek committed
198
        return {
199
            "IMAGE_SIZE": app.state.config.IMAGE_SIZE,
Timothy J. Baek's avatar
Timothy J. Baek committed
200
201
202
203
204
205
206
            "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
207

208
209
210
211
212
213
214

class ImageStepsUpdateForm(BaseModel):
    steps: int


@app.get("/steps")
async def get_image_size(user=Depends(get_admin_user)):
215
    return {"IMAGE_STEPS": app.state.config.IMAGE_STEPS}
216
217
218
219
220
221
222


@app.post("/steps/update")
async def update_image_size(
    form_data: ImageStepsUpdateForm, user=Depends(get_admin_user)
):
    if form_data.steps >= 0:
223
        app.state.config.IMAGE_STEPS = form_data.steps
224
        return {
225
            "IMAGE_STEPS": app.state.config.IMAGE_STEPS,
226
227
228
229
230
231
232
            "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
233
234


Timothy J. Baek's avatar
Timothy J. Baek committed
235
236
237
@app.get("/models")
def get_models(user=Depends(get_current_user)):
    try:
238
        if app.state.config.ENGINE == "openai":
Timothy J. Baek's avatar
Timothy J. Baek committed
239
240
241
242
            return [
                {"id": "dall-e-2", "name": "DALL·E 2"},
                {"id": "dall-e-3", "name": "DALL·E 3"},
            ]
243
        elif app.state.config.ENGINE == "comfyui":
Timothy J. Baek's avatar
Timothy J. Baek committed
244

245
            r = requests.get(url=f"{app.state.config.COMFYUI_BASE_URL}/object_info")
Timothy J. Baek's avatar
Timothy J. Baek committed
246
247
248
249
250
251
252
253
254
            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
255
256
        else:
            r = requests.get(
257
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models"
Timothy J. Baek's avatar
Timothy J. Baek committed
258
259
260
261
262
263
264
265
            )
            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
266
    except Exception as e:
267
        app.state.config.ENABLED = False
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
268
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
269
270
271
272
273


@app.get("/models/default")
async def get_default_model(user=Depends(get_admin_user)):
    try:
274
        if app.state.config.ENGINE == "openai":
275
276
            return {
                "model": (
277
                    app.state.config.MODEL if app.state.config.MODEL else "dall-e-2"
278
279
                )
            }
280
281
        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
282
        else:
283
284
285
            r = requests.get(
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
286
287
            options = r.json()
            return {"model": options["sd_model_checkpoint"]}
Timothy J. Baek's avatar
Timothy J. Baek committed
288
    except Exception as e:
289
        app.state.config.ENABLED = False
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
290
        raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
Timothy J. Baek's avatar
Timothy J. Baek committed
291
292
293
294
295
296
297


class UpdateModelForm(BaseModel):
    model: str


def set_model_handler(model: str):
298
299
300
    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
301
    else:
302
303
304
        r = requests.get(
            url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
305
306
307
308
309
        options = r.json()

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

Timothy J. Baek's avatar
Timothy J. Baek committed
314
        return options
Timothy J. Baek's avatar
Timothy J. Baek committed
315
316
317
318
319
320
321
322
323
324
325
326
327
328


@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
329
    size: Optional[str] = None
Timothy J. Baek's avatar
Timothy J. Baek committed
330
331
332
    negative_prompt: Optional[str] = None


Timothy J. Baek's avatar
Timothy J. Baek committed
333
334
def save_b64_image(b64_str):
    try:
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
335
        image_id = str(uuid.uuid4())
Timothy J. Baek's avatar
Timothy J. Baek committed
336

Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
337
338
339
        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
340

Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
            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
359

Timothy J. Baek's avatar
Timothy J. Baek committed
360
    except Exception as e:
361
        log.exception(f"Error saving image: {e}")
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
362
        return None
Timothy J. Baek's avatar
Timothy J. Baek committed
363
364


Timothy J. Baek's avatar
Timothy J. Baek committed
365
366
367
368
369
def save_url_image(url):
    image_id = str(uuid.uuid4())
    try:
        r = requests.get(url)
        r.raise_for_status()
370
371
372
373
        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
374

375
376
377
            if not image_format:
                raise ValueError("Could not determine image type from MIME type")

Timothy J. Baek's avatar
Timothy J. Baek committed
378
379
380
            image_filename = f"{image_id}{image_format}"

            file_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}")
381
382
383
            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
384
            return image_filename
385
386
        else:
            log.error(f"Url does not point to an image.")
Timothy J. Baek's avatar
Timothy J. Baek committed
387
            return None
Timothy J. Baek's avatar
Timothy J. Baek committed
388
389

    except Exception as e:
390
        log.exception(f"Error saving image: {e}")
Timothy J. Baek's avatar
Timothy J. Baek committed
391
        return None
Timothy J. Baek's avatar
Timothy J. Baek committed
392
393


Timothy J. Baek's avatar
Timothy J. Baek committed
394
395
396
397
398
399
@app.post("/generations")
def generate_image(
    form_data: GenerateImageForm,
    user=Depends(get_current_user),
):

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

Timothy J. Baek's avatar
Timothy J. Baek committed
402
    r = None
403
    try:
404
        if app.state.config.ENGINE == "openai":
405

Timothy J. Baek's avatar
Timothy J. Baek committed
406
            headers = {}
407
            headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEY}"
Timothy J. Baek's avatar
Timothy J. Baek committed
408
            headers["Content-Type"] = "application/json"
409

Timothy J. Baek's avatar
Timothy J. Baek committed
410
            data = {
411
412
413
414
415
                "model": (
                    app.state.config.MODEL
                    if app.state.config.MODEL != ""
                    else "dall-e-2"
                ),
Timothy J. Baek's avatar
Timothy J. Baek committed
416
417
                "prompt": form_data.prompt,
                "n": form_data.n,
418
                "size": (
419
                    form_data.size if form_data.size else app.state.config.IMAGE_SIZE
420
                ),
Timothy J. Baek's avatar
Timothy J. Baek committed
421
422
                "response_format": "b64_json",
            }
423

Timothy J. Baek's avatar
Timothy J. Baek committed
424
            r = requests.post(
425
                url=f"{app.state.config.OPENAI_API_BASE_URL}/images/generations",
Timothy J. Baek's avatar
Timothy J. Baek committed
426
427
428
                json=data,
                headers=headers,
            )
429

Timothy J. Baek's avatar
Timothy J. Baek committed
430
431
            r.raise_for_status()
            res = r.json()
Timothy J. Baek's avatar
Timothy J. Baek committed
432

Timothy J. Baek's avatar
Timothy J. Baek committed
433
434
435
            images = []

            for image in res["data"]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
436
437
                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
438
                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
Timothy J. Baek's avatar
Timothy J. Baek committed
439
440
441
442
443
444

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

            return images

445
        elif app.state.config.ENGINE == "comfyui":
Timothy J. Baek's avatar
Timothy J. Baek committed
446
447
448
449
450
451
452
453

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

454
455
            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
456

457
            if form_data.negative_prompt is not None:
Timothy J. Baek's avatar
Timothy J. Baek committed
458
459
460
461
462
                data["negative_prompt"] = form_data.negative_prompt

            data = ImageGenerationPayload(**data)

            res = comfyui_generate_image(
463
                app.state.config.MODEL,
Timothy J. Baek's avatar
Timothy J. Baek committed
464
465
                data,
                user.id,
466
                app.state.config.COMFYUI_BASE_URL,
Timothy J. Baek's avatar
Timothy J. Baek committed
467
            )
468
            log.debug(f"res: {res}")
Timothy J. Baek's avatar
Timothy J. Baek committed
469
470
471
472

            images = []

            for image in res["data"]:
Timothy J. Baek's avatar
Timothy J. Baek committed
473
474
475
                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
476
477
478
479

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

480
            log.debug(f"images: {images}")
Timothy J. Baek's avatar
Timothy J. Baek committed
481
            return images
Timothy J. Baek's avatar
Timothy J. Baek committed
482
483
484
485
486
487
488
489
490
491
492
        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,
            }

493
494
            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
495

496
            if form_data.negative_prompt is not None:
Timothy J. Baek's avatar
Timothy J. Baek committed
497
498
499
                data["negative_prompt"] = form_data.negative_prompt

            r = requests.post(
500
                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img",
Timothy J. Baek's avatar
Timothy J. Baek committed
501
502
503
504
505
                json=data,
            )

            res = r.json()

506
            log.debug(f"res: {res}")
Timothy J. Baek's avatar
Timothy J. Baek committed
507
508
509
510

            images = []

            for image in res["images"]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
511
512
                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
513
                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
Timothy J. Baek's avatar
Timothy J. Baek committed
514
515
516
517
518

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

            return images
519
520

    except Exception as e:
521
522
523
524
525
526
527
        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))