diff --git a/backend/core/prompts/samples/presentation_agent_image.md b/backend/core/prompts/samples/presentation_agent_image.md index 996071e7..68651eaa 100644 --- a/backend/core/prompts/samples/presentation_agent_image.md +++ b/backend/core/prompts/samples/presentation_agent_image.md @@ -16,7 +16,7 @@ Follow this simplified, four-step workflow for every presentation. **DO NOT SKIP 1. **Understand the User’s Needs**: Ask the user about the presentation’s **audience, context, and goals**. 2. **Gather Information**: Use `web_search` and `web_scape` to research the topic thoroughly. 3. **Create a Content Outline**: Develop a structured outline that maps out the content for each slide. Focus on one main idea per slide. Also decide if a slide need any images or not, if yes what all. images will it need based on content. -4. **Search Images**: Use `image_search` to batch search all images that are required, set num_results based on the number of images needed. +4. **Search Images**: Use `image_search` to batch search all images that are required. **IMPORTANT**: Search for only 2 images per topic (set `num_results=2`) to avoid confusion and keep results focused. 5. **Download Images**: Use `wget` command to batch download all images in `presentations/images` folder. ### **Phase 2: Theme Definition** 🎨 @@ -50,14 +50,18 @@ For each slide in your outline, you will perform the following steps: 1. **Create the Slide**: Create the slide using the `create_slide` tool. All styling MUST be derived from the **Theme Object** defined in Phase 2. Use relative path like `../images/[name]` to link images. -2. **Validate Slide Dimensions**: After creating each slide, you MUST use the `validate_slide` tool to verify that the slide height does not exceed 1080px. This tool will: - * Check for explicit height values exceeding 1080px - * Analyze content density and layout - * Provide warnings and recommendations if issues are detected +2. **Validate Slide Dimensions**: After creating each slide, you MUST use the `validate_slide` tool to verify that the slide height does not exceed 1080px. The validation is simple pass/fail: + * **Pass**: Content height ≤ 1080px + * **Fail**: Content height > 1080px - If validation fails or warnings are raised, revise the slide to reduce content or adjust spacing before proceeding to the next slide. + If validation fails, you must edit the slide to reduce content or adjust spacing before proceeding to the next slide. -3. **Enforce Theme Consistency**: Ensure that every slide uses the *exact same* colors and fonts from the **Theme Object**. Do not introduce new styles or deviate from the established theme. +3. **Edit Slides When Needed**: When you need to modify existing slides (e.g., after validation failures or to update content), use the appropriate file editing tools: + * **`edit_file`** (PREFERRED): AI-powered editing tool for quick, precise edits. Specify only the lines you want to change using `// ... existing code ...` for unchanged sections. This is the fastest and most efficient option. + * **`str_replace`**: For simple exact text replacements (titles, colors, specific strings). Only use when `edit_file` is not suitable and the string appears exactly once. + * **`full_file_rewrite`**: Complete file rewrite. Use as last resort when other tools fail or when replacing entire slide content. + +4. **Enforce Theme Consistency**: Ensure that every slide uses the *exact same* colors and fonts from the **Theme Object**. Do not introduce new styles or deviate from the established theme. ### **Phase 4: Final Presentation** 🎯 diff --git a/backend/core/tools/sb_presentation_tool.py b/backend/core/tools/sb_presentation_tool.py index 7386fc88..651cc0a1 100644 --- a/backend/core/tools/sb_presentation_tool.py +++ b/backend/core/tools/sb_presentation_tool.py @@ -493,29 +493,21 @@ async def measure_slide_height(): # Wait for page to load await page.wait_for_load_state('networkidle') - # Measure the actual content height + # Measure the actual rendered height of the content dimensions = await page.evaluate(""" () => {{ - const body = document.body; - const html = document.documentElement; + // Get the actual bounding box height of the body content + const bodyRect = document.body.getBoundingClientRect(); + const actualHeight = Math.ceil(bodyRect.height); - // Get the actual scroll height (total content height) - const scrollHeight = Math.max( - body.scrollHeight, body.offsetHeight, - html.clientHeight, html.scrollHeight, html.offsetHeight - ); - - // Get viewport height const viewportHeight = window.innerHeight; - - // Check if content overflows - const overflows = scrollHeight > 1080; + const overflows = actualHeight > 1080; return {{ - scrollHeight: scrollHeight, + scrollHeight: actualHeight, viewportHeight: viewportHeight, overflows: overflows, - excessHeight: scrollHeight - 1080 + excessHeight: Math.max(0, actualHeight - 1080) }}; }} """) @@ -559,46 +551,25 @@ print(json.dumps(result)) pass return self.fail_response(f"Failed to measure slide dimensions: {str(e)}") - # Analyze results + # Analyze results - simple pass/fail + validation_passed = not dimensions["overflows"] + validation_results = { + "presentation_name": presentation_name, + "presentation_path": presentation_path, "slide_number": slide_number, "slide_title": slide_info["title"], "actual_content_height": dimensions["scrollHeight"], "target_height": 1080, - "excess_height": dimensions["excessHeight"], - "validation_passed": not dimensions["overflows"], - "warnings": [], - "errors": [], - "recommendations": [] + "validation_passed": validation_passed } - # Add errors or success messages based on actual measurements - if dimensions["overflows"]: - validation_results["validation_passed"] = False - validation_results["errors"].append( - f"Content height ({dimensions['scrollHeight']}px) exceeds the 1080px limit by {dimensions['excessHeight']}px" - ) - validation_results["recommendations"].append( - f"Reduce content or spacing by at least {dimensions['excessHeight']}px to fit within 1080px height" - ) - - # Provide warnings for slides close to the limit - elif dimensions["scrollHeight"] > 1000: - margin = 1080 - dimensions["scrollHeight"] - validation_results["warnings"].append( - f"Content height ({dimensions['scrollHeight']}px) is close to the 1080px limit (only {margin}px margin remaining)" - ) - validation_results["recommendations"].append( - "Consider reducing content slightly to ensure comfortable fit across different browsers" - ) - - # Summary message - if validation_results["validation_passed"] and not validation_results["warnings"]: - validation_results["message"] = f"✓ Slide {slide_number} '{slide_info['title']}' validation passed. Content height: {dimensions['scrollHeight']}px (within 1080px limit)" - elif validation_results["validation_passed"] and validation_results["warnings"]: - validation_results["message"] = f"⚠ Slide {slide_number} '{slide_info['title']}' validation passed with {len(validation_results['warnings'])} warning(s)" + # Add pass/fail message + if validation_passed: + validation_results["message"] = f"✓ Slide {slide_number} '{slide_info['title']}' validation passed. Content height: {dimensions['scrollHeight']}px" else: - validation_results["message"] = f"✗ Slide {slide_number} '{slide_info['title']}' validation failed. Content height: {dimensions['scrollHeight']}px exceeds 1080px by {dimensions['excessHeight']}px" + validation_results["message"] = f"✗ Slide {slide_number} '{slide_info['title']}' validation failed. Content height: {dimensions['scrollHeight']}px exceeds 1080px limit by {dimensions['excessHeight']}px" + validation_results["excess_height"] = dimensions["excessHeight"] return self.success_response(validation_results) diff --git a/frontend/src/components/agents/tools/tool-groups-comprehensive.ts b/frontend/src/components/agents/tools/tool-groups-comprehensive.ts index 9cad1167..a68e5acc 100644 --- a/frontend/src/components/agents/tools/tool-groups-comprehensive.ts +++ b/frontend/src/components/agents/tools/tool-groups-comprehensive.ts @@ -484,6 +484,12 @@ export const TOOL_GROUPS: Record = { description: 'Delete entire presentations', enabled: true, }, + { + name: 'validate_slide', + displayName: 'Validate Slide', + description: 'Validate slide dimensions and content height', + enabled: true, + } ], }, diff --git a/frontend/src/components/thread/tool-views/wrapper/ToolViewRegistry.tsx b/frontend/src/components/thread/tool-views/wrapper/ToolViewRegistry.tsx index a988c8bb..0bb233f2 100644 --- a/frontend/src/components/thread/tool-views/wrapper/ToolViewRegistry.tsx +++ b/frontend/src/components/thread/tool-views/wrapper/ToolViewRegistry.tsx @@ -136,6 +136,7 @@ const defaultRegistry: ToolViewRegistryType = { 'list-presentations': ListPresentationsToolView, 'delete-slide': DeleteSlideToolView, 'delete-presentation': DeletePresentationToolView, + 'validate-slide': PresentationViewer, // 'presentation-styles': PresentationStylesToolView, 'present-presentation': PresentPresentationToolView, @@ -263,6 +264,7 @@ export function ToolView({ name = 'default', assistantContent, toolContent, ...p 'list-slides', 'delete-slide', 'delete-presentation', + 'validate-slide', // 'presentation-styles', 'present-presentation', ]