diff --git a/servers/fastapi/api/v1/ppt/endpoints/presentation.py b/servers/fastapi/api/v1/ppt/endpoints/presentation.py index 118d67f7..8d91cf6e 100644 --- a/servers/fastapi/api/v1/ppt/endpoints/presentation.py +++ b/servers/fastapi/api/v1/ppt/endpoints/presentation.py @@ -10,7 +10,7 @@ from models.presentation_layout import PresentationLayoutModel from models.presentation_structure_model import PresentationStructureModel from models.presentation_with_slides import PresentationWithSlides from models.sql.slide import SlideModel -from models.sse_response import SSECompleteResponse, SSEResponse +from models.sse_response import SSECompleteResponse, SSEResponse, SSEStatusResponse from services import TEMP_FILE_SERVICE from services.database import get_sql_session from services.documents_loader import DocumentsLoader @@ -140,6 +140,7 @@ async def stream_presentation(presentation_id: str): slide_content = await get_slide_content_from_type_and_outline( slide_layout, outline.slides[i] ) + print(slide_content) slide = SlideModel( presentation=presentation_id, layout=slide_layout.id, @@ -150,6 +151,7 @@ async def stream_presentation(presentation_id: str): event="response", data=json.dumps({"type": "chunk", "chunk": slide.model_dump_json()}), ).to_string() + yield SSEResponse( event="response", data=json.dumps({"type": "chunk", "chunk": " ] }"}), diff --git a/servers/fastapi/get_test_schema.py b/servers/fastapi/get_test_schema.py index 6ec34f83..6ba97937 100644 --- a/servers/fastapi/get_test_schema.py +++ b/servers/fastapi/get_test_schema.py @@ -16,54 +16,43 @@ class ContactInfoModel(BaseModel): # First Slide Layout class FirstSlideModel(BaseModel): title: str = Field( - "Welcome to Our Presentation", min_length=3, max_length=100, description="Main title of the presentation", ) subtitle: Optional[str] = Field( - None, min_length=10, max_length=200, description="Optional subtitle or tagline" + min_length=10, max_length=200, description="Optional subtitle or tagline" ) author: Optional[str] = Field( - "John Doe", min_length=2, max_length=100, description="Author or presenter name", ) - date: Optional[str] = Field(None, description="Presentation date") + date: Optional[str] = Field(description="Presentation date") company: Optional[str] = Field( - "Company Name", min_length=2, max_length=100, description="Company or organization name", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) # Bullet Point Slide Layout class BulletPointSlideModel(BaseModel): title: str = Field( - "Key Points", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) - icon: Optional[str] = Field(None, description="Icon to display in the slide") + icon: Optional[str] = Field(description="Icon to display in the slide") bulletPoints: List[str] = Field( - [ - "First key point that highlights important information", - "Second bullet point with valuable insights", - "Third point demonstrating clear benefits", - "Fourth item showcasing key features", - ], min_length=2, max_length=8, description="List of bullet points (2-8 items)", @@ -73,35 +62,30 @@ class BulletPointSlideModel(BaseModel): # Image Slide Layout class ImageSlideModel(BaseModel): title: str = Field( - "Image Showcase", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - "Subtitle for the slide", min_length=3, max_length=150, description="Optional subtitle or description", ) image: HttpUrl = Field( - "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&h=600&fit=crop", description="Main image URL", ) imageCaption: Optional[str] = Field( - "Image caption", min_length=5, max_length=200, description="Optional image caption or description", ) content: Optional[str] = Field( - None, min_length=10, max_length=600, description="Optional supporting content text", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -116,10 +100,9 @@ class StatisticItemModel(BaseModel): min_length=3, max_length=100, description="Description of the statistic" ) trend: Optional[str] = Field( - None, description="Trend direction indicator", pattern="^(up|down|neutral)$" + description="Trend direction indicator", pattern="^(up|down|neutral)$" ) context: Optional[str] = Field( - None, min_length=5, max_length=200, description="Additional context or time period", @@ -128,88 +111,56 @@ class StatisticItemModel(BaseModel): class StatisticsSlideModel(BaseModel): title: str = Field( - "Key Statistics", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) statistics: List[StatisticItemModel] = Field( - [ - StatisticItemModel( - value="250%", - label="Revenue Growth", - trend="up", - context="Year over year increase", - ), - StatisticItemModel( - value="50M+", - label="Active Users", - trend="up", - context="Global user base", - ), - StatisticItemModel( - value="99.9%", - label="Uptime", - trend="neutral", - context="Service reliability", - ), - StatisticItemModel( - value="24/7", - label="Support", - trend="neutral", - context="Customer service", - ), - ], min_length=2, max_length=6, description="List of statistics (2-6 items)", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) # Quote Slide Layout class QuoteSlideModel(BaseModel): title: str = Field( - "Testimonials", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) quote: str = Field( - "This solution has transformed our business operations and exceeded all expectations.", min_length=10, max_length=500, description="The main quote or testimonial", ) author: str = Field( - "John Smith", min_length=2, max_length=100, description="Quote author name", ) authorTitle: Optional[str] = Field( - None, min_length=2, max_length=100, description="Author job title or position" + min_length=2, max_length=100, description="Author job title or position" ) company: Optional[str] = Field( - None, min_length=2, max_length=100, description="Author company or organization" + min_length=2, max_length=100, description="Author company or organization" ) - authorImage: Optional[HttpUrl] = Field(None, description="URL to author photo") + authorImage: Optional[HttpUrl] = Field(description="URL to author photo") backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -223,7 +174,6 @@ class TimelineItemModel(BaseModel): min_length=10, max_length=300, description="Event description" ) status: str = Field( - "upcoming", description="Timeline item status", pattern="^(completed|current|upcoming)$", ) @@ -231,50 +181,22 @@ class TimelineItemModel(BaseModel): class TimelineSlideModel(BaseModel): title: str = Field( - "Project Timeline", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) timelineItems: List[TimelineItemModel] = Field( - [ - TimelineItemModel( - date="Q1 2024", - title="Project Initiation", - description="Project planning, team assembly, and initial requirements gathering", - status="completed", - ), - TimelineItemModel( - date="Q2 2024", - title="Development Phase", - description="Core development work, prototype creation, and testing implementation", - status="current", - ), - TimelineItemModel( - date="Q3 2024", - title="Testing & QA", - description="Comprehensive testing, quality assurance, and user acceptance testing", - status="upcoming", - ), - TimelineItemModel( - date="Q4 2024", - title="Launch & Deployment", - description="Final deployment, go-live activities, and post-launch monitoring", - status="upcoming", - ), - ], min_length=2, max_length=6, description="Timeline events (2-6 items)", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -282,63 +204,34 @@ class TimelineSlideModel(BaseModel): class TeamMemberModel(BaseModel): name: str = Field(min_length=2, max_length=100, description="Team member name") title: str = Field(min_length=2, max_length=100, description="Job title or role") - image: Optional[HttpUrl] = Field(None, description="URL to team member photo") + image: Optional[HttpUrl] = Field(description="URL to team member photo") bio: Optional[str] = Field( - None, min_length=10, max_length=300, description="Brief biography or description", ) - email: Optional[EmailStr] = Field(None, description="Contact email") - linkedin: Optional[HttpUrl] = Field(None, description="LinkedIn profile URL") + email: Optional[EmailStr] = Field(description="Contact email") + linkedin: Optional[HttpUrl] = Field(description="LinkedIn profile URL") class TeamSlideModel(BaseModel): title: str = Field( - "Meet Our Team", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or team description", ) teamMembers: List[TeamMemberModel] = Field( - [ - TeamMemberModel( - name="Sarah Johnson", - title="Chief Executive Officer", - image="https://images.unsplash.com/photo-1494790108755-2616b612b786?w=300&h=300&fit=crop&crop=face", - bio="Strategic leader with 15+ years experience driving innovation and growth in technology companies.", - email="sarah@company.com", - linkedin="https://linkedin.com/in/sarahjohnson", - ), - TeamMemberModel( - name="Michael Chen", - title="Chief Technology Officer", - image="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=300&h=300&fit=crop&crop=face", - bio="Technology visionary specializing in scalable architecture and emerging technologies.", - email="michael@company.com", - linkedin="https://linkedin.com/in/michaelchen", - ), - TeamMemberModel( - name="Emma Rodriguez", - title="Head of Design", - image="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=300&h=300&fit=crop&crop=face", - bio="Creative director passionate about user-centered design and innovative digital experiences.", - email="emma@company.com", - linkedin="https://linkedin.com/in/emmarodriguez", - ), - ], min_length=1, max_length=6, description="Team members (1-6 people)", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -353,46 +246,22 @@ class ProcessStepModel(BaseModel): class ProcessSlideModel(BaseModel): title: str = Field( - "Our Process", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) processSteps: List[ProcessStepModel] = Field( - [ - ProcessStepModel( - step=1, - title="Discovery", - description="Understanding requirements and gathering initial insights", - ), - ProcessStepModel( - step=2, - title="Planning", - description="Strategic planning and roadmap development", - ), - ProcessStepModel( - step=3, - title="Implementation", - description="Executing the plan with precision and quality", - ), - ProcessStepModel( - step=4, - title="Delivery", - description="Final delivery and ongoing support", - ), - ], min_length=2, max_length=6, description="Process steps (2-6 items)", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -404,97 +273,75 @@ class ColumnContentModel(BaseModel): class TwoColumnSlideModel(BaseModel): title: str = Field( - "Two Column Layout", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) leftColumn: ColumnContentModel = Field( - ColumnContentModel( - title="Left Column", - content="Content for the left column goes here. This can include detailed information, explanations, or supporting details.", - ), description="Left column content", ) rightColumn: ColumnContentModel = Field( - ColumnContentModel( - title="Right Column", - content="Content for the right column goes here. This can include additional information, comparisons, or contrasting details.", - ), description="Right column content", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) # Conclusion Slide Layout class ConclusionSlideModel(BaseModel): title: str = Field( - "Conclusion", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) keyTakeaways: List[str] = Field( - [ - "Successfully achieved our primary objectives", - "Demonstrated significant value and impact", - "Established clear next steps for continued success", - "Built strong foundation for future growth", - ], min_length=2, max_length=6, description="Key takeaways or summary points (2-6 items)", ) callToAction: Optional[str] = Field( - None, min_length=5, max_length=150, description="Optional call to action or next steps", ) contactInfo: Optional[ContactInfoModel] = Field( - None, description="Optional contact information" + description="Optional contact information" ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) # Content Slide Layout class ContentSlideModel(BaseModel): title: str = Field( - "Slide Title", min_length=3, max_length=100, description="Title of the slide", ) subtitle: Optional[str] = Field( - None, min_length=3, max_length=150, description="Optional subtitle or description", ) content: str = Field( - "Your slide content goes here. This is where you can add detailed information, explanations, or any other text content that supports your presentation.", min_length=10, max_length=1000, description="Main content text", ) backgroundImage: Optional[HttpUrl] = Field( - None, description="URL to background image for the slide" + description="URL to background image for the slide" ) @@ -560,6 +407,6 @@ presentation_layout = PresentationLayoutModel( ], ) -# print(presentation_layout.model_dump_json()) +print(presentation_layout.model_dump_json()) -print(PresentationOutlineModel.model_json_schema()) +# print(PresentationOutlineModel.model_json_schema()) diff --git a/servers/fastapi/utils/llm_calls/generate_slide_content.py b/servers/fastapi/utils/llm_calls/generate_slide_content.py index a5afded2..cb91211c 100644 --- a/servers/fastapi/utils/llm_calls/generate_slide_content.py +++ b/servers/fastapi/utils/llm_calls/generate_slide_content.py @@ -72,15 +72,14 @@ async def get_slide_content_from_type_and_outline( return json.loads(response.choices[0].message.content) else: client = get_google_llm_client() - user_prompt = get_user_prompt(outline.title, outline.body) response = await asyncio.to_thread( client.models.generate_content, model=model, - contents=[user_prompt], + contents=[get_user_prompt(outline.title, outline.body)], config=GenerateContentConfig( system_instruction=system_prompt, response_mime_type="application/json", response_json_schema=slide_layout.json_schema, ), ) - return response.model_dump(mode="json") + return response.text