perf(fastapi): uses async sql engine

This commit is contained in:
sauravniraula 2025-07-29 17:19:31 +05:45
parent 007208f616
commit 9cb7d9f432
No known key found for this signature in database
GPG key ID: 60FCC1B5A5E83326
17 changed files with 206 additions and 210 deletions

View file

@ -6,10 +6,7 @@ RUN apt-get update && apt-get install -y \
npm \
nginx \
curl \
redis-server \
default-libmysqlclient-dev \
build-essential \
pkg-config
redis-server
# Create a working directory
WORKDIR /app

View file

@ -6,10 +6,7 @@ RUN apt-get update && apt-get install -y \
npm \
nginx \
curl \
redis-server \
default-libmysqlclient-dev \
build-essential \
pkg-config
redis-server
# Change working directory
WORKDIR /app

View file

@ -2,11 +2,12 @@ from contextlib import asynccontextmanager
import os
from fastapi import FastAPI
from sqlmodel import SQLModel
from services import SQL_ENGINE
from services.database import create_db_and_tables
from utils.get_env import get_app_data_directory_env
from utils.model_availability import check_llm_and_image_provider_api_or_model_availability
from utils.model_availability import (
check_llm_and_image_provider_api_or_model_availability,
)
@asynccontextmanager
@ -14,9 +15,9 @@ async def app_lifespan(_: FastAPI):
"""
Lifespan context manager for FastAPI application.
Initializes the application data directory and checks LLM model availability.
"""
os.makedirs(get_app_data_directory_env(), exist_ok=True)
SQLModel.metadata.create_all(SQL_ENGINE)
await create_db_and_tables()
await check_llm_and_image_provider_api_or_model_availability()
yield

View file

@ -1,10 +1,11 @@
from typing import List
from fastapi import APIRouter
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from models.image_prompt import ImagePrompt
from models.sql.image_asset import ImageAsset
from services.database import get_sql_session
from services.database import get_async_session
from services.image_generation_service import ImageGenerationService
from utils.asset_directory_utils import get_images_directory
@ -12,7 +13,9 @@ IMAGES_ROUTER = APIRouter(prefix="/images", tags=["Images"])
@IMAGES_ROUTER.get("/generate")
async def generate_image(prompt: str):
async def generate_image(
prompt: str, sql_session: AsyncSession = Depends(get_async_session)
):
images_directory = get_images_directory()
image_prompt = ImagePrompt(prompt=prompt)
image_generation_service = ImageGenerationService(images_directory)
@ -21,21 +24,18 @@ async def generate_image(prompt: str):
if not isinstance(image, ImageAsset):
return image
with get_sql_session() as sql_session:
sql_session.add(image)
sql_session.commit()
image_path = image.path
sql_session.add(image)
await sql_session.commit()
return image_path
return image.path
@IMAGES_ROUTER.get("/generated", response_model=List[ImageAsset])
async def get_generated_images():
async def get_generated_images(sql_session: AsyncSession = Depends(get_async_session)):
try:
with get_sql_session() as sql_session:
images = sql_session.exec(
select(ImageAsset).order_by(ImageAsset.created_at.desc())
).all()
images = await sql_session.scalars(
select(ImageAsset).order_by(ImageAsset.created_at.desc())
)
return images
except Exception as e:
return {"error": f"Failed to retrieve generated images: {str(e)}"}

View file

@ -1,21 +1,23 @@
import asyncio
import json
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from models.presentation_outline_model import PresentationOutlineModel
from models.sql.presentation import PresentationModel
from models.sse_response import SSECompleteResponse, SSEResponse, SSEStatusResponse
from services.database import get_sql_session
from services.database import get_async_session
from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
OUTLINES_ROUTER = APIRouter(prefix="/outlines", tags=["Outlines"])
@OUTLINES_ROUTER.get("/stream")
async def stream_outlines(presentation_id: str):
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, presentation_id)
async def stream_outlines(
presentation_id: str, sql_session: AsyncSession = Depends(get_async_session)
):
presentation = await sql_session.get(PresentationModel, presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
@ -54,10 +56,8 @@ async def stream_outlines(presentation_id: str):
]
presentation.notes = presentation_content.notes
with get_sql_session() as sql_session:
sql_session.add(presentation)
sql_session.commit()
sql_session.refresh(presentation)
sql_session.add(presentation)
await sql_session.commit()
yield SSECompleteResponse(
key="presentation", value=presentation.model_dump(mode="json")

View file

@ -3,11 +3,10 @@ import json
import os
import random
from typing import Annotated, List, Literal, Optional
import uuid
from annotated_types import Len
from fastapi import APIRouter, Body, File, HTTPException, UploadFile
from fastapi import APIRouter, Body, Depends, File, HTTPException, UploadFile
from fastapi.responses import StreamingResponse
from sqlalchemy import delete
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from constants.documents import UPLOAD_ACCEPTED_FILE_TYPES
from models.presentation_and_path import PresentationPathAndEditPath
@ -29,7 +28,7 @@ from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
from models.sql.slide import SlideModel
from models.sse_response import SSECompleteResponse, SSEResponse
from services import TEMP_FILE_SERVICE
from services.database import get_sql_session
from services.database import get_async_session
from services.documents_loader import DocumentsLoader
from models.sql.presentation import PresentationModel
from services.pptx_presentation_creator import PptxPresentationCreator
@ -49,57 +48,60 @@ PRESENTATION_ROUTER = APIRouter(prefix="/presentation", tags=["Presentation"])
@PRESENTATION_ROUTER.get("", response_model=PresentationWithSlides)
def get_presentation(id: str):
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, id)
if not presentation:
raise HTTPException(404, "Presentation not found")
slides = sql_session.exec(
async def get_presentation(
id: str, sql_session: AsyncSession = Depends(get_async_session)
):
presentation = await sql_session.get(PresentationModel, id)
if not presentation:
raise HTTPException(404, "Presentation not found")
slides = await sql_session.scalars(
select(SlideModel)
.where(SlideModel.presentation == id)
.order_by(SlideModel.index)
)
return PresentationWithSlides(
**presentation.model_dump(),
slides=slides,
)
@PRESENTATION_ROUTER.delete("", status_code=204)
async def delete_presentation(
id: str, sql_session: AsyncSession = Depends(get_async_session)
):
presentation = await sql_session.get(PresentationModel, id)
if not presentation:
raise HTTPException(404, "Presentation not found")
await sql_session.execute(delete(SlideModel).where(SlideModel.presentation == id))
await sql_session.delete(presentation)
await sql_session.commit()
@PRESENTATION_ROUTER.get("/all", response_model=List[PresentationWithSlides])
async def get_all_presentations(sql_session: AsyncSession = Depends(get_async_session)):
presentations_with_slides = []
presentations = await sql_session.scalars(
select(PresentationModel).where(PresentationModel.layout != "null")
)
async def inner(presentation: PresentationModel, sql_session: AsyncSession):
slides = await sql_session.scalars(
select(SlideModel)
.where(SlideModel.presentation == id)
.order_by(SlideModel.index)
.where(SlideModel.presentation == presentation.id)
.where(SlideModel.index == 0)
)
if not slides:
return None
return PresentationWithSlides(
**presentation.model_dump(),
slides=slides,
)
@PRESENTATION_ROUTER.delete("", status_code=204)
def delete_presentation(id: str):
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, id)
if not presentation:
raise HTTPException(404, "Presentation not found")
slides = sql_session.exec(
select(SlideModel).where(SlideModel.presentation == id)
).all()
for slide in slides:
sql_session.delete(slide)
sql_session.delete(presentation)
sql_session.commit()
@PRESENTATION_ROUTER.get("/all", response_model=List[PresentationWithSlides])
def get_all_presentations():
with get_sql_session() as sql_session:
presentations_with_slides = []
presentations = sql_session.exec(select(PresentationModel))
for presentation in presentations:
slides = sql_session.exec(
select(SlideModel)
.where(SlideModel.presentation == presentation.id)
.where(SlideModel.index == 0)
).all()
if not slides:
continue
presentations_with_slides.append(
PresentationWithSlides(
**presentation.model_dump(),
slides=slides,
)
)
return presentations_with_slides
tasks = [inner(p, sql_session) for p in presentations]
results = await asyncio.gather(*tasks)
presentations_with_slides = [r for r in results if r is not None]
return presentations_with_slides
@PRESENTATION_ROUTER.post("/create", response_model=PresentationModel)
@ -108,8 +110,9 @@ async def create_presentation(
n_slides: Annotated[int, Body()],
language: Annotated[str, Body()],
file_paths: Annotated[Optional[List[str]], Body()] = None,
sql_session: AsyncSession = Depends(get_async_session),
):
presentation_id = str(uuid.uuid4())
presentation_id = get_random_uuid()
summary = None
if file_paths:
@ -127,10 +130,8 @@ async def create_presentation(
summary=summary,
)
with get_sql_session() as sql_session:
sql_session.add(presentation)
sql_session.commit()
sql_session.refresh(presentation)
sql_session.add(presentation)
await sql_session.commit()
return presentation
@ -141,12 +142,14 @@ async def prepare_presentation(
outlines: Annotated[List[SlideOutlineModel], Body()],
layout: Annotated[PresentationLayoutModel, Body()],
title: Annotated[Optional[str], Body()] = None,
sql_session: AsyncSession = Depends(get_async_session),
):
if not outlines:
raise HTTPException(status_code=400, detail="Outlines are required")
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, presentation_id)
presentation = await sql_session.get(PresentationModel, presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
total_slide_layouts = len(layout.slides)
total_outlines = len(outlines)
@ -170,34 +173,33 @@ async def prepare_presentation(
if presentation_structure.slides[index] >= total_slide_layouts:
presentation_structure.slides[index] = random_slide_index
with get_sql_session() as sql_session:
sql_session.add(presentation)
presentation.outlines = [each.model_dump() for each in outlines]
presentation.title = title or presentation.title
presentation.set_layout(layout)
presentation.set_structure(presentation_structure)
sql_session.commit()
sql_session.refresh(presentation)
sql_session.add(presentation)
presentation.outlines = [each.model_dump() for each in outlines]
presentation.title = title or presentation.title
presentation.set_layout(layout)
presentation.set_structure(presentation_structure)
await sql_session.commit()
return presentation
@PRESENTATION_ROUTER.get("/stream", response_model=PresentationWithSlides)
async def stream_presentation(presentation_id: str):
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
if not presentation.structure:
raise HTTPException(
status_code=400,
detail="Presentation not prepared for stream",
)
if not presentation.outlines:
raise HTTPException(
status_code=400,
detail="Outlines can not be empty",
)
async def stream_presentation(
presentation_id: str, sql_session: AsyncSession = Depends(get_async_session)
):
presentation = await sql_session.get(PresentationModel, presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
if not presentation.structure:
raise HTTPException(
status_code=400,
detail="Presentation not prepared for stream",
)
if not presentation.outlines:
raise HTTPException(
status_code=400,
detail="Outlines can not be empty",
)
image_generation_service = ImageGenerationService(get_images_directory())
icon_finder_service = IconFinderService()
@ -254,14 +256,10 @@ async def stream_presentation(presentation_id: str):
for assets_list in generated_assets_lists:
generated_assets.extend(assets_list)
with get_sql_session() as sql_session:
sql_session.add(presentation)
sql_session.add_all(slides)
sql_session.add_all(generated_assets)
sql_session.commit()
sql_session.refresh(presentation)
for each_slide in slides:
sql_session.refresh(each_slide)
sql_session.add(presentation)
sql_session.add_all(slides)
sql_session.add_all(generated_assets)
await sql_session.commit()
response = PresentationWithSlides(
**presentation.model_dump(),
@ -277,25 +275,22 @@ async def stream_presentation(presentation_id: str):
@PRESENTATION_ROUTER.put("/update", response_model=PresentationWithSlides)
def update_presentation(
async def update_presentation(
presentation_with_slides: Annotated[PresentationWithSlides, Body()],
sql_session: AsyncSession = Depends(get_async_session),
):
updated_presentation = presentation_with_slides.to_presentation_model()
updated_slides = presentation_with_slides.slides
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, updated_presentation.id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
presentation.sqlmodel_update(updated_presentation)
presentation = await sql_session.get(PresentationModel, updated_presentation.id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
presentation.sqlmodel_update(updated_presentation)
sql_session.exec(
delete(SlideModel).where(SlideModel.presentation == updated_presentation.id)
)
sql_session.add_all(updated_slides)
sql_session.commit()
sql_session.refresh(presentation)
for slide in updated_slides:
sql_session.refresh(slide)
await sql_session.execute(
delete(SlideModel).where(SlideModel.presentation == updated_presentation.id)
)
sql_session.add_all(updated_slides)
await sql_session.commit()
return PresentationWithSlides(
**presentation.model_dump(),
@ -304,7 +299,9 @@ def update_presentation(
@PRESENTATION_ROUTER.post("/export/pptx", response_model=str)
async def create_pptx(pptx_model: Annotated[PptxPresentationModel, Body()]):
async def create_pptx(
pptx_model: Annotated[PptxPresentationModel, Body()],
):
temp_dir = TEMP_FILE_SERVICE.create_temp_dir()
pptx_creator = PptxPresentationCreator(pptx_model, temp_dir)
@ -327,6 +324,7 @@ async def generate_presentation_api(
layout: Annotated[str, Body()] = "general",
files: Annotated[Optional[List[UploadFile]], File()] = None,
export_as: Annotated[Literal["pptx", "pdf"], Body()] = "pptx",
sql_session: AsyncSession = Depends(get_async_session),
):
validate_files(files, True, True, 50, UPLOAD_ACCEPTED_FILE_TYPES)
@ -369,12 +367,12 @@ async def generate_presentation_api(
print(f"Generated {total_outlines} outlines for the presentation")
# 4. Parse Layouts
layout = await get_layout_by_name(layout)
total_slide_layouts = len(layout.slides)
layout_model = await get_layout_by_name(layout)
total_slide_layouts = len(layout_model.slides)
# 5. Generate Structure
if layout.ordered:
presentation_structure = layout.to_presentation_structure()
if layout_model.ordered:
presentation_structure = layout_model.to_presentation_structure()
else:
presentation_structure: PresentationStructureModel = (
await generate_presentation_structure(
@ -383,7 +381,7 @@ async def generate_presentation_api(
slides=outlines,
notes=presentation_content.notes,
),
presentation_layout=layout,
presentation_layout=layout_model,
)
)
@ -406,7 +404,7 @@ async def generate_presentation_api(
summary=summary,
outlines=[each.model_dump() for each in outlines],
notes=presentation_content.notes,
layout=layout.model_dump(),
layout=layout_model.model_dump(),
structure=presentation_structure.model_dump(),
)
@ -418,14 +416,14 @@ async def generate_presentation_api(
slides: List[SlideModel] = []
slide_contents: List[dict] = []
for i, slide_layout_index in enumerate(presentation_structure.slides):
slide_layout = layout.slides[slide_layout_index]
slide_layout = layout_model.slides[slide_layout_index]
print(f"Generating content for slide {i} with layout {slide_layout.id}")
slide_content = await get_slide_content_from_type_and_outline(
slide_layout, outlines[i]
)
slide = SlideModel(
presentation=presentation_id,
layout_group=layout.name,
layout_group=layout_model.name,
layout=slide_layout.id,
index=i,
content=slide_content,
@ -444,11 +442,10 @@ async def generate_presentation_api(
generated_assets.extend(assets_list)
# 8. Save PresentationModel and Slides
with get_sql_session() as sql_session:
sql_session.add(presentation)
sql_session.add_all(slides)
sql_session.add_all(generated_assets)
sql_session.commit()
sql_session.add(presentation)
sql_session.add_all(slides)
sql_session.add_all(generated_assets)
await sql_session.commit()
# 9. Export
presentation_and_path = await export_presentation(
@ -464,14 +461,14 @@ async def generate_presentation_api(
@PRESENTATION_ROUTER.post("/from-template", response_model=PresentationPathAndEditPath)
async def from_template(
data: Annotated[GetPresentationUsingTemplateRequest, Body()],
sql_session: AsyncSession = Depends(get_async_session),
):
with get_sql_session() as sql_session:
presentation = sql_session.get(PresentationModel, data.presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
slides = sql_session.exec(
select(SlideModel).where(SlideModel.presentation == data.presentation_id)
).all()
presentation = await sql_session.get(PresentationModel, data.presentation_id)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
slides = await sql_session.scalars(
select(SlideModel).where(SlideModel.presentation == data.presentation_id)
)
new_presentation = presentation.get_new_presentation()
new_slides = []
@ -485,11 +482,9 @@ async def from_template(
each_slide.get_new_slide(new_presentation.id, updated_content)
)
with get_sql_session() as sql_session:
sql_session.add(new_presentation)
sql_session.add_all(new_slides)
sql_session.commit()
sql_session.refresh(new_presentation)
sql_session.add(new_presentation)
sql_session.add_all(new_slides)
await sql_session.commit()
presentation_and_path = await export_presentation(
new_presentation.id, new_presentation.title, data.export_as

View file

@ -1,9 +1,10 @@
from typing import Annotated, Optional
from fastapi import APIRouter, Body, HTTPException
from fastapi import APIRouter, Body, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from models.sql.presentation import PresentationModel
from models.sql.slide import SlideModel
from services.database import get_sql_session
from services.database import get_async_session
from services.icon_finder_service import IconFinderService
from services.image_generation_service import ImageGenerationService
from utils.asset_directory_utils import get_images_directory
@ -18,15 +19,17 @@ SLIDE_ROUTER = APIRouter(prefix="/slide", tags=["Slide"])
@SLIDE_ROUTER.post("/edit")
async def edit_slide(id: Annotated[str, Body()], prompt: Annotated[str, Body()]):
with get_sql_session() as sql_session:
slide = sql_session.get(SlideModel, id)
if not slide:
raise HTTPException(status_code=404, detail="Slide not found")
presentation = sql_session.get(PresentationModel, slide.presentation)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
async def edit_slide(
id: Annotated[str, Body()],
prompt: Annotated[str, Body()],
sql_session: AsyncSession = Depends(get_async_session),
):
slide = await sql_session.get(SlideModel, id)
if not slide:
raise HTTPException(status_code=404, detail="Slide not found")
presentation = await sql_session.get(PresentationModel, slide.presentation)
if not presentation:
raise HTTPException(status_code=404, detail="Presentation not found")
presentation_layout = presentation.get_layout()
@ -51,13 +54,11 @@ async def edit_slide(id: Annotated[str, Body()], prompt: Annotated[str, Body()])
# Always assign a new unique id to the slide
slide.id = get_random_uuid()
with get_sql_session() as sql_session:
sql_session.add(slide)
slide.content = edited_slide_content
slide.layout = slide_layout.id
sql_session.add_all(new_assets)
sql_session.commit()
sql_session.refresh(slide)
sql_session.add(slide)
slide.content = edited_slide_content
slide.layout = slide_layout.id
sql_session.add_all(new_assets)
await sql_session.commit()
return slide
@ -67,11 +68,11 @@ async def edit_slide_html(
id: Annotated[str, Body()],
prompt: Annotated[str, Body()],
html: Annotated[Optional[str], Body()] = None,
sql_session: AsyncSession = Depends(get_async_session),
):
with get_sql_session() as sql_session:
slide = sql_session.get(SlideModel, id)
if not slide:
raise HTTPException(status_code=404, detail="Slide not found")
slide = await sql_session.get(SlideModel, id)
if not slide:
raise HTTPException(status_code=404, detail="Slide not found")
html_to_edit = html or slide.html_content
if not html_to_edit:
@ -83,10 +84,8 @@ async def edit_slide_html(
# This is to ensure that the nextjs can track slide updates
slide.id = get_random_uuid()
with get_sql_session() as sql_session:
sql_session.add(slide)
slide.html_content = edited_slide_html
sql_session.commit()
sql_session.refresh(slide)
sql_session.add(slide)
slide.html_content = edited_slide_html
await sql_session.commit()
return slide

View file

@ -21,7 +21,7 @@ class PresentationWithSlides(BaseModel):
summary: Optional[str]
created_at: datetime
updated_at: datetime
layout: PresentationLayoutModel
layout: Optional[PresentationLayoutModel]
structure: Optional[PresentationStructureModel]
slides: List[SlideModel]

View file

@ -1,6 +1,5 @@
from datetime import datetime
from typing import List, Optional
import uuid
from sqlalchemy import JSON, Column, DateTime
from sqlmodel import SQLModel, Field

View file

@ -1,5 +1,4 @@
from typing import Optional
import uuid
from sqlmodel import SQLModel, Field, Column, JSON
from utils.randomizers import get_random_uuid

View file

@ -1,9 +1,12 @@
aiohappyeyeballs==2.6.1
aiohttp==3.12.14
aiomysql==0.2.0
aiosignal==1.4.0
aiosqlite==0.21.0
annotated-types==0.7.0
anyio==4.9.0
async-timeout==5.0.1
asyncpg==0.30.0
attrs==25.3.0
backoff==2.2.1
bcrypt==4.3.0
@ -90,6 +93,7 @@ pycparser==2.22
pydantic==2.11.7
pydantic_core==2.33.2
Pygments==2.19.2
PyMySQL==1.1.1
pypdfium2==4.30.1
PyPika==0.48.9
pyproject_hooks==1.2.0

View file

@ -1,8 +1,6 @@
from services.redis_service import RedisService
from services.temp_file_service import TempFileService
from services.database import sql_engine
TEMP_FILE_SERVICE = TempFileService()
SQL_ENGINE = sql_engine
REDIS_SERVICE = RedisService()

View file

@ -1,25 +1,32 @@
from contextlib import contextmanager
from collections.abc import AsyncGenerator
import os
from sqlalchemy import create_engine
from sqlmodel import Session
from sqlalchemy.ext.asyncio import (
AsyncEngine,
create_async_engine,
async_sessionmaker,
AsyncSession,
)
from sqlmodel import SQLModel
from utils.get_env import get_app_data_directory_env, get_database_url_env
database_url = get_database_url_env() or "sqlite:///" + os.path.join(
database_url = get_database_url_env() or "sqlite+aiosqlite:///" + os.path.join(
get_app_data_directory_env() or "/tmp/presenton", "fastapi.db"
)
connect_args = {}
if "sqlite" in database_url:
connect_args["check_same_thread"] = False
sql_engine = create_engine(database_url, connect_args=connect_args)
sql_engine: AsyncEngine = create_async_engine(database_url, connect_args=connect_args)
async_session_maker = async_sessionmaker(sql_engine, expire_on_commit=False)
@contextmanager
def get_sql_session():
session = Session(sql_engine)
try:
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
yield session
finally:
session.close()
async def create_db_and_tables():
async with sql_engine.begin() as conn:
await conn.run_sync(SQLModel.metadata.create_all)

View file

@ -1,6 +1,5 @@
import asyncio
import os
import uuid
import aiohttp
from google import genai
from google.genai.types import GenerateContentConfig
@ -16,6 +15,7 @@ from utils.image_provider import (
is_gemini_flash_selected,
is_dalle3_selected,
)
from utils.randomizers import get_random_uuid
class ImageGenerationService:
@ -104,7 +104,7 @@ class ImageGenerationService:
if part.text is not None:
print(part.text)
elif part.inline_data is not None:
image_path = os.path.join(output_directory, f"{str(uuid.uuid4())}.jpg")
image_path = os.path.join(output_directory, f"{get_random_uuid()}.jpg")
with open(image_path, "wb") as f:
f.write(part.inline_data.data)

View file

@ -1,6 +1,5 @@
import os
from typing import List, Optional
import uuid
from lxml import etree
from pptx import Presentation
@ -41,6 +40,7 @@ from utils.image_utils import (
round_image_corners,
set_image_opacity,
)
from utils.randomizers import get_random_uuid
BLANK_SLIDE_LAYOUT = 6
@ -210,7 +210,7 @@ class PptxPresentationCreator:
image = invert_image(image)
if picture_model.opacity:
image = set_image_opacity(image, picture_model.opacity)
image_path = os.path.join(self._temp_dir, f"{str(uuid.uuid4())}.png")
image_path = os.path.join(self._temp_dir, f"{get_random_uuid()}.png")
image.save(image_path)
margined_position = self.get_margined_position(

View file

@ -1,8 +1,8 @@
import os
import uuid
from typing import Optional, Union
from utils.get_env import get_temp_directory_env
from utils.randomizers import get_random_uuid
class TempFileService:
@ -14,7 +14,7 @@ class TempFileService:
os.makedirs(self.base_dir, exist_ok=True)
def create_dir_in_dir(self, base_dir: str, dir_name: Optional[str] = None) -> str:
temp_dir = os.path.join(base_dir, dir_name if dir_name else str(uuid.uuid4()))
temp_dir = os.path.join(base_dir, dir_name if dir_name else get_random_uuid())
os.makedirs(temp_dir, exist_ok=True)
return temp_dir