From df90b7829c3092e16f560fa6ba889179c3823dae Mon Sep 17 00:00:00 2001 From: sauravniraula Date: Sat, 26 Jul 2025 02:13:54 +0545 Subject: [PATCH] fix(fastapi+nextjs): provides default height and width if not available, provides presentation json in sse complete response in outlines --- .../api/v1/ppt/endpoints/presentation.py | 21 ++++++++++++------- servers/fastapi/models/sse_response.py | 9 ++++++++ servers/fastapi/utils/error_handling.py | 1 + servers/nextjs/app/api/export-as-pdf/route.ts | 2 +- .../api/presentation_to_pptx_model/route.ts | 7 ++----- 5 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 servers/fastapi/utils/error_handling.py diff --git a/servers/fastapi/api/v1/ppt/endpoints/presentation.py b/servers/fastapi/api/v1/ppt/endpoints/presentation.py index 9c24ca3d..7d8439a8 100644 --- a/servers/fastapi/api/v1/ppt/endpoints/presentation.py +++ b/servers/fastapi/api/v1/ppt/endpoints/presentation.py @@ -8,7 +8,10 @@ from fastapi import APIRouter, Body, HTTPException from fastapi.responses import StreamingResponse from sqlalchemy import delete from sqlmodel import select -from models.presentation_outline_model import PresentationOutlineModel, SlideOutlineModel +from models.presentation_outline_model import ( + PresentationOutlineModel, + SlideOutlineModel, +) from models.pptx_models import PptxPresentationModel from models.presentation_layout import PresentationLayoutModel from models.presentation_structure_model import PresentationStructureModel @@ -304,8 +307,11 @@ async def create_pptx(pptx_model: Annotated[PptxPresentationModel, Body()]): return pptx_path + @PRESENTATION_ROUTER.post("/generate") -async def generate_presentation_api(data: Annotated[GeneratePresentationRequest, Body()]): +async def generate_presentation_api( + data: Annotated[GeneratePresentationRequest, Body()], +): presentation_id = str(uuid.uuid4()) print("**" * 40) print(f"Generating presentation with ID: {presentation_id}") @@ -341,7 +347,7 @@ async def generate_presentation_api(data: Annotated[GeneratePresentationRequest, presentation_content_json = json.loads(presentation_content_text) presentation_content = PresentationOutlineModel(**presentation_content_json) - outlines = presentation_content.slides[:data.n_slides] + outlines = presentation_content.slides[: data.n_slides] total_outlines = len(outlines) print("-" * 40) @@ -441,7 +447,10 @@ async def generate_presentation_api(data: Annotated[GeneratePresentationRequest, if response.status != 200: error_text = await response.text() print(f"Failed to get PPTX model: {error_text}") - raise HTTPException(status_code=500, detail="Failed to convert presentation to PPTX model") + raise HTTPException( + status_code=500, + detail="Failed to convert presentation to PPTX model", + ) pptx_model_data = await response.json() print(f"Received PPTX model data: {json.dumps(pptx_model_data, indent=2)}") @@ -453,9 +462,7 @@ async def generate_presentation_api(data: Annotated[GeneratePresentationRequest, await pptx_creator.create_ppt() export_directory = get_exports_directory() - pptx_path = os.path.join( - export_directory, f"{presentation_content.title}.pptx" - ) + pptx_path = os.path.join(export_directory, f"{presentation_content.title}.pptx") pptx_creator.save(pptx_path) presentation_and_path = PresentationAndPath( diff --git a/servers/fastapi/models/sse_response.py b/servers/fastapi/models/sse_response.py index 290c93ab..18dc9a47 100644 --- a/servers/fastapi/models/sse_response.py +++ b/servers/fastapi/models/sse_response.py @@ -20,6 +20,15 @@ class SSEStatusResponse(BaseModel): ).to_string() +class SSEErrorResponse(BaseModel): + detail: str + + def to_string(self): + return SSEResponse( + event="response", data=json.dumps({"type": "error", "detail": self.detail}) + ).to_string() + + class SSECompleteResponse(BaseModel): key: str value: object diff --git a/servers/fastapi/utils/error_handling.py b/servers/fastapi/utils/error_handling.py new file mode 100644 index 00000000..f87e8426 --- /dev/null +++ b/servers/fastapi/utils/error_handling.py @@ -0,0 +1 @@ +# async def format_exc(e: Exception): diff --git a/servers/nextjs/app/api/export-as-pdf/route.ts b/servers/nextjs/app/api/export-as-pdf/route.ts index 8ca388cc..afc5e378 100644 --- a/servers/nextjs/app/api/export-as-pdf/route.ts +++ b/servers/nextjs/app/api/export-as-pdf/route.ts @@ -22,7 +22,7 @@ export async function POST(req: NextRequest) { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 720 }); - await page.goto(`http://localhost/pdf-maker?id=${id}`, { waitUntil: 'networkidle0', timeout: 80000 }); + await page.goto(`http://localhost/pdf-maker?id=${id}`, { waitUntil: 'networkidle0', timeout: 180000 }); await page.waitForFunction('() => document.readyState === "complete"') diff --git a/servers/nextjs/app/api/presentation_to_pptx_model/route.ts b/servers/nextjs/app/api/presentation_to_pptx_model/route.ts index 19693e5c..7b624ecb 100644 --- a/servers/nextjs/app/api/presentation_to_pptx_model/route.ts +++ b/servers/nextjs/app/api/presentation_to_pptx_model/route.ts @@ -77,10 +77,7 @@ async function getBrowserAndPage(id: string): Promise<[Browser, Page]> { await page.setViewport({ width: 1280, height: 720, deviceScaleFactor: 1 }); await page.goto(`http://localhost/pdf-maker?id=${id}`, { waitUntil: "networkidle0", - timeout: 60000, - }); - page.on('console', (msg) => { - console.log('console', msg.text()); + timeout: 180000, }); return [browser, page]; } @@ -182,7 +179,7 @@ const convertSvgToPng = async (element_attibutes: ElementAttributes) => { const svgBuffer = Buffer.from(svgHtml); const pngBuffer = await sharp(svgBuffer) - .resize(element_attibutes.position?.width, element_attibutes.position?.height) + .resize(element_attibutes.position?.width ?? 10, element_attibutes.position?.height ?? 10) .toFormat('png') .toBuffer(); return pngBuffer;