From fccd04172a07f7401788ac70484ed56c412772a0 Mon Sep 17 00:00:00 2001 From: sauravniraula Date: Tue, 5 Aug 2025 20:48:38 +0545 Subject: [PATCH] fix(fastapi): fix issue where all tables were created in both DBs --- .../app_mcp/services/state_machine/context.py | 1 - .../app_mcp/wrapper/generate_outline.py | 26 ++++++++----------- .../wrapper/presentation_generation.py | 22 +++++++--------- servers/fastapi/services/database.py | 24 +++++++++++++++-- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/servers/fastapi/app_mcp/services/state_machine/context.py b/servers/fastapi/app_mcp/services/state_machine/context.py index 1fe2398a..c3b6dd43 100644 --- a/servers/fastapi/app_mcp/services/state_machine/context.py +++ b/servers/fastapi/app_mcp/services/state_machine/context.py @@ -5,7 +5,6 @@ from dataclasses import dataclass class StateContext: """Context data that travels with the state machine""" presentation_id: Optional[str] = None - summary: Optional[str] = None title: Optional[str] = None outlines: Optional[list] = None layout: Optional[str] = None diff --git a/servers/fastapi/app_mcp/wrapper/generate_outline.py b/servers/fastapi/app_mcp/wrapper/generate_outline.py index 28b8200f..0c2d88a7 100644 --- a/servers/fastapi/app_mcp/wrapper/generate_outline.py +++ b/servers/fastapi/app_mcp/wrapper/generate_outline.py @@ -8,12 +8,10 @@ from services.documents_loader import DocumentsLoader from services.score_based_chunker import ScoreBasedChunker from utils.validators import validate_files from fastapi import UploadFile, File -from models.sse_response import SSEResponse from constants.documents import UPLOAD_ACCEPTED_FILE_TYPES import asyncio - async def generate_outline( prompt: str, n_slides: int = 8, @@ -66,26 +64,24 @@ async def generate_outline( presentation_outlines_text += chunk presentation_outlines_json = json.loads(presentation_outlines_text) - presentation_outlines = PresentationOutlineModel( - **presentation_outlines_json - ) + presentation_outlines = PresentationOutlineModel(**presentation_outlines_json) # Truncate slides to n_slides presentation_outlines.slides = presentation_outlines.slides[:n_slides] - # Compose title from first slide (if available) - title = "" - if presentation_outlines.slides and hasattr(presentation_outlines.slides[0], '__str__'): - title = str(presentation_outlines.slides[0])[:50] - title = title.replace("#", "").replace("/", "").replace("\\", "").replace("\n", "") - elif presentation_outlines.slides: - title = str(presentation_outlines.slides[0])[:50] + # Compose title from first slide + title = ( + presentation_outlines.slides[0][:50] + .replace("#", "") + .replace("/", "") + .replace("\\", "") + .replace("\n", "") + ) # Prepare outlines list - outlines = [slide.model_dump() for slide in presentation_outlines.slides] + outlines = presentation_outlines.model_dump(mode="json") return { - "title": getattr(presentation_outlines, 'title', title), + "title": title, "outlines": outlines, - "notes": getattr(presentation_outlines, 'notes', []), } diff --git a/servers/fastapi/app_mcp/wrapper/presentation_generation.py b/servers/fastapi/app_mcp/wrapper/presentation_generation.py index 45d47717..a82aa64f 100644 --- a/servers/fastapi/app_mcp/wrapper/presentation_generation.py +++ b/servers/fastapi/app_mcp/wrapper/presentation_generation.py @@ -1,13 +1,16 @@ import random from typing import List, Dict, Any, Optional -from models.presentation_outline_model import SlideOutlineModel from models.presentation_layout import PresentationLayoutModel from models.presentation_structure_model import PresentationStructureModel from models.sql.presentation import PresentationModel from models.sql.slide import SlideModel from utils.get_layout_by_name import get_layout_by_name -from utils.llm_calls.generate_presentation_structure import generate_presentation_structure -from utils.llm_calls.generate_slide_content import get_slide_content_from_type_and_outline +from utils.llm_calls.generate_presentation_structure import ( + generate_presentation_structure, +) +from utils.llm_calls.generate_slide_content import ( + get_slide_content_from_type_and_outline, +) from services.image_generation_service import ImageGenerationService from services.icon_finder_service import IconFinderService from utils.asset_directory_utils import get_images_directory @@ -15,15 +18,13 @@ from utils.process_slides import process_slide_and_fetch_assets from models.presentation_outline_model import PresentationOutlineModel from utils.randomizers import get_random_uuid import asyncio -from services.database import get_async_session from sqlalchemy.ext.asyncio import AsyncSession # Standalone function for workflow orchestrator async def process_post_outline_workflow( title: str, - outlines: List[Dict[str, Any]], - notes: Optional[str]=[], + outlines: List[str], layout: str = "general", language: str = "English", prompt: str = "", @@ -44,9 +45,7 @@ async def process_post_outline_workflow( presentation_structure: PresentationStructureModel = ( await generate_presentation_structure( presentation_outline=PresentationOutlineModel( - title=title, slides=outlines, - notes=notes, ), presentation_layout=layout_model, ) @@ -69,7 +68,6 @@ async def process_post_outline_workflow( language=language, outlines=outlines, prompt=prompt, - notes=notes, layout=layout_model.model_dump(), structure=presentation_structure.model_dump(), ) @@ -83,7 +81,7 @@ async def process_post_outline_workflow( for i, slide_layout_index in enumerate(presentation_structure.slides): slide_layout = layout_model.slides[slide_layout_index] slide_content = await get_slide_content_from_type_and_outline( - slide_layout, SlideOutlineModel(**outlines[i]), language + slide_layout, outlines[i], language ) slide = SlideModel( presentation=presentation_id, @@ -107,6 +105,7 @@ async def process_post_outline_workflow( # 5. Save PresentationModel and Slides if sql_session is None: from services.database import get_async_session + async for session in get_async_session(): session.add(presentation) session.add_all(slides) @@ -118,11 +117,10 @@ async def process_post_outline_workflow( sql_session.add_all(generated_assets) await sql_session.commit() - # 6. Ask user if they want to export and in which format return { "presentation_id": presentation_id, "title": title, "message": "Presentation is ready. Would you like to export? (pdf or pptx)", - "export_options": ["pdf", "pptx"] + "export_options": ["pdf", "pptx"], } diff --git a/servers/fastapi/services/database.py b/servers/fastapi/services/database.py index 3f419bcf..a46f6471 100644 --- a/servers/fastapi/services/database.py +++ b/servers/fastapi/services/database.py @@ -8,6 +8,11 @@ from sqlalchemy.ext.asyncio import ( ) from sqlmodel import SQLModel +from models.sql.image_asset import ImageAsset +from models.sql.key_value import KeyValueSqlModel +from models.sql.ollama_pull_status import OllamaPullStatus +from models.sql.presentation import PresentationModel +from models.sql.slide import SlideModel from utils.get_env import get_app_data_directory_env, get_database_url_env @@ -55,7 +60,22 @@ async def get_container_db_async_session() -> AsyncGenerator[AsyncSession, None] # Create Database and Tables async def create_db_and_tables(): async with sql_engine.begin() as conn: - await conn.run_sync(SQLModel.metadata.create_all) + await conn.run_sync( + lambda sync_conn: SQLModel.metadata.create_all( + sync_conn, + tables=[ + PresentationModel.__table__, + SlideModel.__table__, + KeyValueSqlModel.__table__, + ImageAsset.__table__, + ], + ) + ) async with container_db_engine.begin() as conn: - await conn.run_sync(SQLModel.metadata.create_all) + await conn.run_sync( + lambda sync_conn: SQLModel.metadata.create_all( + sync_conn, + tables=[OllamaPullStatus.__table__], + ) + )