mirror of https://github.com/kortix-ai/suna.git
rem styles from tool
This commit is contained in:
parent
67cbf529dd
commit
d4179c7832
|
@ -6,13 +6,12 @@ import json
|
|||
import os
|
||||
from datetime import datetime
|
||||
import re
|
||||
from .presentation_styles_config import get_style_config, get_all_styles
|
||||
|
||||
class SandboxPresentationTool(SandboxToolsBase):
|
||||
"""
|
||||
Per-slide HTML presentation tool for creating professional presentations.
|
||||
Each slide is managed individually with 1920x1080 dimensions.
|
||||
Supports iterative slide creation, editing, and presentation assembly.
|
||||
Per-slide HTML presentation tool for creating presentation slides.
|
||||
Each slide is created as a basic HTML document without predefined CSS styling.
|
||||
Users can include their own CSS styling inline or in style tags as needed.
|
||||
"""
|
||||
|
||||
def __init__(self, project_id: str, thread_manager: ThreadManager):
|
||||
|
@ -20,6 +19,7 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
self.workspace_path = "/workspace"
|
||||
self.presentations_dir = "presentations"
|
||||
|
||||
|
||||
async def _ensure_presentations_dir(self):
|
||||
"""Ensure the presentations directory exists"""
|
||||
full_path = f"{self.workspace_path}/{self.presentations_dir}"
|
||||
|
@ -42,15 +42,9 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
"""Convert presentation name to safe filename"""
|
||||
return "".join(c for c in name if c.isalnum() or c in "-_").lower()
|
||||
|
||||
def _get_style_config(self, style_name: str) -> Dict:
|
||||
"""Get style configuration for a given style name"""
|
||||
return get_style_config(style_name)
|
||||
|
||||
def _create_slide_html(self, slide_content: str, slide_number: int, total_slides: int, presentation_title: str, style: str = "default") -> str:
|
||||
"""Create a complete HTML document for a single slide with proper 1920x1080 dimensions"""
|
||||
|
||||
# Get style configuration
|
||||
style_config = self._get_style_config(style)
|
||||
def _create_slide_html(self, slide_content: str, slide_number: int, total_slides: int, presentation_title: str) -> str:
|
||||
"""Create a basic HTML document without predefined CSS"""
|
||||
|
||||
html_template = f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
@ -58,146 +52,12 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{presentation_title} - Slide {slide_number}</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<link href="{style_config['font_import']}" rel="stylesheet">
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1"></script>
|
||||
<style>
|
||||
/* Base styling and 1920x1080 slide container */
|
||||
* {{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}}
|
||||
|
||||
body {{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: {style_config['font_family']};
|
||||
color: {style_config['text_color']};
|
||||
}}
|
||||
|
||||
.slide-container {{
|
||||
/* CRITICAL: Standard presentation dimensions */
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
position: relative;
|
||||
background: {style_config['background']};
|
||||
color: {style_config['text_color']};
|
||||
overflow: hidden;
|
||||
|
||||
/* Auto-scale to fit viewport while maintaining aspect ratio */
|
||||
transform-origin: center center;
|
||||
transform: scale(min(100vw / 1920px, 100vh / 1080px));
|
||||
}}
|
||||
|
||||
/* Slide number indicator */
|
||||
.slide-number {{
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
font-size: 18px;
|
||||
color: {style_config['text_color']};
|
||||
opacity: 0.7;
|
||||
font-weight: 500;
|
||||
z-index: 1000;
|
||||
}}
|
||||
|
||||
/* Common presentation elements with style theming */
|
||||
.slide-title {{
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30px;
|
||||
color: {style_config['primary_color']};
|
||||
}}
|
||||
|
||||
.slide-subtitle {{
|
||||
font-size: 32px;
|
||||
margin-bottom: 40px;
|
||||
color: {style_config['text_color']};
|
||||
}}
|
||||
|
||||
.slide-content {{
|
||||
font-size: 24px;
|
||||
line-height: 1.6;
|
||||
color: {style_config['text_color']};
|
||||
}}
|
||||
|
||||
.accent-bar {{
|
||||
width: 100px;
|
||||
height: 4px;
|
||||
background-color: {style_config['accent_color']};
|
||||
margin: 20px 0;
|
||||
}}
|
||||
|
||||
/* Primary color elements */
|
||||
.primary-color {{
|
||||
color: {style_config['primary_color']};
|
||||
}}
|
||||
|
||||
.primary-bg {{
|
||||
background-color: {style_config['primary_color']};
|
||||
}}
|
||||
|
||||
/* Accent color elements */
|
||||
.accent-color {{
|
||||
color: {style_config['accent_color']};
|
||||
}}
|
||||
|
||||
.accent-bg {{
|
||||
background-color: {style_config['accent_color']};
|
||||
}}
|
||||
|
||||
/* Style-aware text color */
|
||||
.text-color {{
|
||||
color: {style_config['text_color']};
|
||||
}}
|
||||
|
||||
/* Responsive images */
|
||||
img {{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
|
||||
/* List styling */
|
||||
ul, ol {{
|
||||
margin: 20px 0;
|
||||
padding-left: 30px;
|
||||
}}
|
||||
|
||||
li {{
|
||||
margin: 10px 0;
|
||||
font-size: 20px;
|
||||
line-height: 1.5;
|
||||
color: {style_config['text_color']};
|
||||
}}
|
||||
|
||||
/* Style-specific enhancements */
|
||||
.card {{
|
||||
background: {'rgba(255, 255, 255, 0.1)' if 'gradient' in style_config['background'] or style_config['background'].startswith('#1') or style_config['background'].startswith('#0') else 'rgba(0, 0, 0, 0.05)'};
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
backdrop-filter: blur(10px);
|
||||
}}
|
||||
|
||||
.highlight {{
|
||||
background: {style_config['accent_color']};
|
||||
color: {'#FFFFFF' if style_config['accent_color'].startswith('#') else style_config['text_color']};
|
||||
padding: 4px 12px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slide-container">
|
||||
{slide_content}
|
||||
<div class="slide-number">{slide_number}{f" / {total_slides}" if total_slides > 0 else ""}</div>
|
||||
</div>
|
||||
{slide_content}
|
||||
</body>
|
||||
</html>"""
|
||||
return html_template
|
||||
|
@ -229,7 +89,7 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
"type": "function",
|
||||
"function": {
|
||||
"name": "create_slide",
|
||||
"description": "Create or update a single slide in a presentation. Each slide is saved as a standalone HTML file with 1920x1080 dimensions (16:9 aspect ratio). Perfect for iterative slide creation and editing. Use 'presentation_styles' tool first to see available styles.",
|
||||
"description": "Create or update a single slide in a presentation. Each slide is saved as a standalone HTML file with 1920x1080 dimensions (16:9 aspect ratio). Perfect for iterative slide creation and editing.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -246,18 +106,13 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
"description": "Title of this specific slide (for reference and navigation)"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "HTML content for the slide body. Should include all styling within the content. The content will be placed inside a 1920x1080 slide container with CSS frameworks (Tailwind, FontAwesome, D3, Chart.js) available. Use professional styling with good typography, spacing, and visual hierarchy. You can use style-aware CSS classes: .primary-color, .primary-bg, .accent-color, .accent-bg, .text-color, .card, .highlight"
|
||||
},
|
||||
"type": "string",
|
||||
"description": "Complete HTML content including inline CSS or <style> blocks. Design for 1920x1080 resolution. Include all necessary styling as no external CSS frameworks are automatically loaded."
|
||||
},
|
||||
"presentation_title": {
|
||||
"type": "string",
|
||||
"description": "Main title of the presentation (used in HTML title and navigation)",
|
||||
"default": "Presentation"
|
||||
},
|
||||
"style": {
|
||||
"type": "string",
|
||||
"description": "Visual style theme for the slide. Use 'presentation_styles' tool to see all available options. Examples: 'velvet', 'glacier', 'ember', 'sage', 'obsidian', 'coral', 'platinum', 'aurora', 'midnight', 'citrus', or 'default'",
|
||||
"default": "default"
|
||||
}
|
||||
},
|
||||
"required": ["presentation_name", "slide_number", "slide_title", "content"]
|
||||
|
@ -265,36 +120,69 @@ class SandboxPresentationTool(SandboxToolsBase):
|
|||
}
|
||||
})
|
||||
@usage_example('''
|
||||
Create individual slides for a presentation about "Modern Web Development":
|
||||
Create clean, professional presentation slides:
|
||||
|
||||
<function_calls>
|
||||
<invoke name="create_slide">
|
||||
<parameter name="presentation_name">modern_web_development</parameter>
|
||||
<parameter name="slide_number">1</parameter>
|
||||
<parameter name="slide_title">Title Slide</parameter>
|
||||
<parameter name="presentation_title">Modern Web Development Trends 2024</parameter>
|
||||
<parameter name="content"><div style='background: linear-gradient(135deg, #005A9C 0%, #FF6B00 100%); height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; color: white; padding: 80px;'><h1 style='font-size: 72px; font-weight: bold; margin-bottom: 30px;'>Modern Web Development</h1><div style='width: 150px; height: 6px; background: white; margin: 30px auto;'></div><h2 style='font-size: 36px; margin-bottom: 40px; opacity: 0.9;'>Trends & Technologies 2024</h2><p style='font-size: 24px; opacity: 0.8;'>Building Tomorrow's Web Today</p></div></parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
# Example 1: Simple Title Slide
|
||||
<function_calls>
|
||||
<invoke name="create_slide">
|
||||
<parameter name="presentation_name">product_launch_2024</parameter>
|
||||
<parameter name="slide_number">1</parameter>
|
||||
<parameter name="slide_title">Product Launch Title</parameter>
|
||||
<parameter name="presentation_title">Product Launch 2024</parameter>
|
||||
<parameter name="content">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
.slide-container {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'Arial', sans-serif;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 64px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 30px;
|
||||
color: #2563eb;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 28px;
|
||||
margin-bottom: 40px;
|
||||
color: #666666;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.accent-line {
|
||||
width: 100px;
|
||||
height: 4px;
|
||||
background: #2563eb;
|
||||
margin: 30px auto;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Then create the next slide:
|
||||
|
||||
<function_calls>
|
||||
<invoke name="create_slide">
|
||||
<parameter name="presentation_name">modern_web_development</parameter>
|
||||
<parameter name="slide_number">2</parameter>
|
||||
<parameter name="slide_title">Frontend Frameworks</parameter>
|
||||
<parameter name="presentation_title">Modern Web Development Trends 2024</parameter>
|
||||
<parameter name="content"><div style='display: flex; height: 100%; padding: 0;'><div style='width: 60%; padding: 80px; display: flex; flex-direction: column; justify-content: center;'><h1 style='font-size: 48px; font-weight: bold; color: #005A9C; margin-bottom: 20px;'>Frontend Frameworks</h1><div style='width: 100px; height: 4px; background: #FF6B00; margin-bottom: 40px;'></div><div style='font-size: 22px; line-height: 1.8;'><div style='margin-bottom: 25px; display: flex; align-items: center;'><i class='fab fa-react' style='color: #61DAFB; font-size: 28px; margin-right: 15px;'></i><div><strong>React</strong> - Component-based UI library</div></div><div style='margin-bottom: 25px; display: flex; align-items: center;'><i class='fab fa-vuejs' style='color: #4FC08D; font-size: 28px; margin-right: 15px;'></i><div><strong>Vue.js</strong> - Progressive framework</div></div></div></div><div style='width: 40%; background: #f8f9fa; display: flex; align-items: center; justify-content: center; padding: 40px;'><div style='text-align: center;'><div style='font-size: 64px; margin-bottom: 30px;'>📱</div><h3 style='font-size: 28px; color: #005A9C;'>Modern Tools</h3></div></div></div></parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
|
||||
This approach allows you to:
|
||||
- Create slides one at a time
|
||||
- Edit existing slides by using the same slide number
|
||||
- Build presentations iteratively
|
||||
- Mix and match different slide designs
|
||||
- Each slide is a standalone HTML file with full styling
|
||||
<div class="slide-container">
|
||||
<div class="content">
|
||||
<h1 class="main-title">Product Launch 2024</h1>
|
||||
<div class="accent-line"></div>
|
||||
<p class="subtitle">Introducing our latest innovation</p>
|
||||
</div>
|
||||
</div>
|
||||
</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def create_slide(
|
||||
self,
|
||||
|
@ -302,8 +190,7 @@ This approach allows you to:
|
|||
slide_number: int,
|
||||
slide_title: str,
|
||||
content: str,
|
||||
presentation_title: str = "Presentation",
|
||||
style: str = "default"
|
||||
presentation_title: str = "Presentation"
|
||||
) -> ToolResult:
|
||||
"""Create or update a single slide in a presentation"""
|
||||
try:
|
||||
|
@ -337,8 +224,7 @@ This approach allows you to:
|
|||
slide_content=content,
|
||||
slide_number=slide_number,
|
||||
total_slides=0, # Will be updated when regenerating navigation
|
||||
presentation_title=presentation_title,
|
||||
style=style
|
||||
presentation_title=presentation_title
|
||||
)
|
||||
|
||||
# Save slide file
|
||||
|
@ -355,7 +241,6 @@ This approach allows you to:
|
|||
"filename": slide_filename,
|
||||
"file_path": f"{self.presentations_dir}/{safe_name}/{slide_filename}",
|
||||
"preview_url": f"/workspace/{self.presentations_dir}/{safe_name}/{slide_filename}",
|
||||
"style": style,
|
||||
"created_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
|
@ -363,16 +248,15 @@ This approach allows you to:
|
|||
await self._save_presentation_metadata(presentation_path, metadata)
|
||||
|
||||
return self.success_response({
|
||||
"message": f"Slide {slide_number} '{slide_title}' created/updated successfully with '{style}' style",
|
||||
"message": f"Slide {slide_number} '{slide_title}' created/updated successfully",
|
||||
"presentation_name": presentation_name,
|
||||
"presentation_path": f"{self.presentations_dir}/{safe_name}",
|
||||
"slide_number": slide_number,
|
||||
"slide_title": slide_title,
|
||||
"slide_file": f"{self.presentations_dir}/{safe_name}/{slide_filename}",
|
||||
"preview_url": f"/workspace/{self.presentations_dir}/{safe_name}/{slide_filename}",
|
||||
"style": style,
|
||||
"total_slides": len(metadata["slides"]),
|
||||
"note": "Slide saved as standalone HTML file with 1920x1080 dimensions"
|
||||
"note": "Professional slide created with custom styling - designed for 1920x1080 resolution"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
|
@ -513,31 +397,6 @@ This approach allows you to:
|
|||
|
||||
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "presentation_styles",
|
||||
"description": "Get available presentation styles with their descriptions and visual characteristics. Use this to show users different style options before creating slides.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
}
|
||||
})
|
||||
async def presentation_styles(self) -> ToolResult:
|
||||
"""Get available presentation styles with descriptions and examples"""
|
||||
try:
|
||||
styles = get_all_styles()
|
||||
|
||||
return self.success_response({
|
||||
"message": f"Found {len(styles)} presentation styles available",
|
||||
"styles": styles,
|
||||
"usage_tip": "Choose a style and use it with the 'style' parameter in create_slide"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return self.fail_response(f"Failed to get presentation styles: {str(e)}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
|
|
Loading…
Reference in New Issue