diff --git a/servers/fastapi/api/v1/ppt/endpoints/presentation.py b/servers/fastapi/api/v1/ppt/endpoints/presentation.py index c244709..2bcf9a8 100644 --- a/servers/fastapi/api/v1/ppt/endpoints/presentation.py +++ b/servers/fastapi/api/v1/ppt/endpoints/presentation.py @@ -454,6 +454,12 @@ async def inner(): asyncio.create_task(process_slide_and_fetch_assets(image_generation_service, slide)) ) + if i > 0: + yield SSEResponse( + event="response", + data=json.dumps({"type": "chunk", "chunk": ","}), + ).to_string() + yield SSEResponse( event="response", data=json.dumps({"type": "chunk", "chunk": slide.model_dump_json()}), diff --git a/servers/fastapi/test_layout_gen.py b/servers/fastapi/test_layout_gen.py new file mode 100644 index 0000000..1f992e0 --- /dev/null +++ b/servers/fastapi/test_layout_gen.py @@ -0,0 +1,60 @@ +"""Quick test of the layout generation pipeline.""" +import asyncio +import sys +import os +import traceback + +# Ensure the package is on the path +sys.path.insert(0, os.path.dirname(__file__)) + +from models.presentation_outline_model import SlideOutlineModel +from utils.llm_calls.generate_slide_layouts import ( + categorize_outlines, + generate_layout_tsx, + generate_all_layouts, + LAYOUT_TYPES, +) + +OUTLINES = [ + SlideOutlineModel(content="Title: Benefits of Renewable Energy - An overview of why renewable energy matters"), + SlideOutlineModel(content="Solar Power: Cost savings, environmental benefits, and growing adoption worldwide"), + SlideOutlineModel(content="Wind Energy: Offshore and onshore wind farms generating clean electricity"), +] + +async def test_categorize(): + print("=== Testing categorize_outlines ===") + try: + result = await categorize_outlines(OUTLINES, "Benefits of Renewable Energy") + print(f"Result: {result}") + return result + except Exception as e: + print(f"ERROR: {e}") + traceback.print_exc() + return None + +async def test_generate_tsx(): + print("\n=== Testing generate_layout_tsx ===") + try: + tsx = await generate_layout_tsx( + LAYOUT_TYPES[0], # title-intro + "Benefits of Renewable Energy", + "Title: Benefits of Renewable Energy", + ) + print(f"Generated TSX ({len(tsx)} chars):") + print(tsx[:500]) + return tsx + except Exception as e: + print(f"ERROR: {e}") + traceback.print_exc() + return None + +async def main(): + cat_result = await test_categorize() + tsx_result = await test_generate_tsx() + + if cat_result and tsx_result: + print("\n=== Both tests passed ===") + else: + print("\n=== Some tests FAILED ===") + +asyncio.run(main()) diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/StreamingProgressBar.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/StreamingProgressBar.tsx new file mode 100644 index 0000000..9804523 --- /dev/null +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/StreamingProgressBar.tsx @@ -0,0 +1,57 @@ +"use client"; +import React, { useEffect, useState } from "react"; + +interface StreamingProgressBarProps { + streamed: number; + total: number; +} + +const StreamingProgressBar: React.FC = ({ + streamed, + total, +}) => { + const [visible, setVisible] = useState(false); + + useEffect(() => { + // Slight delay so it fades in gracefully + const t = setTimeout(() => setVisible(true), 50); + return () => clearTimeout(t); + }, []); + + const pct = total > 0 ? Math.round((streamed / total) * 100) : 0; + + return ( +
+
+
+
+ {/* Pulsing dot */} + + + + + + Generating presentation… + +
+ + {streamed}/{total} slides + +
+ +
+
+
+
+
+ ); +}; + +export default StreamingProgressBar; diff --git a/servers/nextjs/app/presentation-templates/general/BulletIconsOnlySlideLayout.tsx b/servers/nextjs/app/presentation-templates/general/BulletIconsOnlySlideLayout.tsx index 9fa1844..852924c 100644 --- a/servers/nextjs/app/presentation-templates/general/BulletIconsOnlySlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/general/BulletIconsOnlySlideLayout.tsx @@ -146,13 +146,15 @@ const BulletIconsOnlySlideLayout: React.FC = ({ > {/* Icon */}
- + {bullet.icon?.__icon_url__ && ( + + )}
{/* Content */} diff --git a/servers/nextjs/app/presentation-templates/general/BulletWithIconsSlideLayout.tsx b/servers/nextjs/app/presentation-templates/general/BulletWithIconsSlideLayout.tsx index 0b1ecce..490c527 100644 --- a/servers/nextjs/app/presentation-templates/general/BulletWithIconsSlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/general/BulletWithIconsSlideLayout.tsx @@ -147,13 +147,15 @@ const BulletWithIconsSlideLayout: React.FC = ({
{/* Icon */}
- + {bullet.icon?.__icon_url__ && ( + + )}
{/* Content */} diff --git a/servers/nextjs/app/presentation-templates/general/ChartWithBulletsSlideLayout.tsx b/servers/nextjs/app/presentation-templates/general/ChartWithBulletsSlideLayout.tsx index 2cb680c..137f061 100644 --- a/servers/nextjs/app/presentation-templates/general/ChartWithBulletsSlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/general/ChartWithBulletsSlideLayout.tsx @@ -321,13 +321,15 @@ const ChartWithBulletsSlideLayout: React.FC = {/* Icon and Title */}
- + {bullet.icon?.__icon_url__ && ( + + )}

{bullet.title} diff --git a/servers/nextjs/app/presentation-templates/neo-general/BulletIconsOnlySlideLayout.tsx b/servers/nextjs/app/presentation-templates/neo-general/BulletIconsOnlySlideLayout.tsx index 3229801..e215924 100644 --- a/servers/nextjs/app/presentation-templates/neo-general/BulletIconsOnlySlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/neo-general/BulletIconsOnlySlideLayout.tsx @@ -154,13 +154,15 @@ const BulletIconsOnlySlideLayout: React.FC = ({ > {/* Icon */}
- + {bullet.icon?.__icon_url__ && ( + + )}
{/* Content */} diff --git a/servers/nextjs/app/presentation-templates/neo-general/BulletWithIconsSlideLayout.tsx b/servers/nextjs/app/presentation-templates/neo-general/BulletWithIconsSlideLayout.tsx index 561cea0..17e8488 100644 --- a/servers/nextjs/app/presentation-templates/neo-general/BulletWithIconsSlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/neo-general/BulletWithIconsSlideLayout.tsx @@ -154,13 +154,15 @@ const BulletWithIconsSlideLayout: React.FC = ({
{/* Icon */}
- + {bullet.icon?.__icon_url__ && ( + + )}
{/* Content */} diff --git a/servers/nextjs/app/presentation-templates/neo-general/ChartWithBulletsSlideLayout.tsx b/servers/nextjs/app/presentation-templates/neo-general/ChartWithBulletsSlideLayout.tsx index 203c715..1572a3d 100644 --- a/servers/nextjs/app/presentation-templates/neo-general/ChartWithBulletsSlideLayout.tsx +++ b/servers/nextjs/app/presentation-templates/neo-general/ChartWithBulletsSlideLayout.tsx @@ -553,13 +553,15 @@ const ChartWithBulletsSlideLayout: React.FC = {/* Icon and Title */}
- + {bullet.icon?.__icon_url__ && ( + + )}

{bullet.title} diff --git a/servers/nextjs/app/presentation-templates/swift/BulletsWithIconsTitleDescription.tsx b/servers/nextjs/app/presentation-templates/swift/BulletsWithIconsTitleDescription.tsx index bcafb1e..b8d28c0 100644 --- a/servers/nextjs/app/presentation-templates/swift/BulletsWithIconsTitleDescription.tsx +++ b/servers/nextjs/app/presentation-templates/swift/BulletsWithIconsTitleDescription.tsx @@ -209,13 +209,15 @@ const InfographicFourIcons: React.FC = ({ data }) => { style={{ backgroundColor: 'var(--primary-color, #BFF4FF)' }} > {/* Icon */} - + {item.icon?.__icon_url__ && ( + + )}

diff --git a/servers/nextjs/app/presentation-templates/swift/IconBulletListDescription.tsx b/servers/nextjs/app/presentation-templates/swift/IconBulletListDescription.tsx index e696b32..9f06384 100644 --- a/servers/nextjs/app/presentation-templates/swift/IconBulletListDescription.tsx +++ b/servers/nextjs/app/presentation-templates/swift/IconBulletListDescription.tsx @@ -171,13 +171,15 @@ const FeatureCards: React.FC = ({ data: slideData }) => {
- + {f.icon?.__icon_url__ && ( + + )}
{f.title}

{f.body}

diff --git a/servers/nextjs/app/presentation-templates/swift/Timeline.tsx b/servers/nextjs/app/presentation-templates/swift/Timeline.tsx index 40a175b..a6957cb 100644 --- a/servers/nextjs/app/presentation-templates/swift/Timeline.tsx +++ b/servers/nextjs/app/presentation-templates/swift/Timeline.tsx @@ -148,7 +148,9 @@ const Timeline: React.FC = ({ data: slideData }) => { style={{ backgroundColor: 'var(--card-color, #FFFFFF)' }} >
- {it.icon.__icon_query__} + {it.icon?.__icon_url__ && ( + {it.icon.__icon_query__} + )}
{it.heading}

{it.body}