First_agent / app.py
Naveen671's picture
fix some z index error (#2)
86523fe verified
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
import datetime
import requests
import pytz
import yaml
import base64
import io
from PIL import Image
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI
# Enhanced design-to-code tool
@tool
def design_to_code_generator(design_prompt: str, image_path: str = None) -> str:
"""A tool that generates HTML, CSS, and JavaScript code based on a design description or image.
Args:
design_prompt: A detailed description of the desired web design/interface
image_path: Optional path to an image file for visual reference
"""
# Base HTML template with modern styling capabilities
html_template = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{title}</title>
<style>
{css_content}
</style>
</head>
<body>
{html_content}
<script>
{js_content}
</script>
</body>
</html>"""
# Analyze the design prompt to determine components and styling
components = analyze_design_prompt(design_prompt)
# Generate CSS based on design requirements
css_content = generate_css_from_prompt(design_prompt, components)
# Generate HTML structure
html_content = generate_html_structure(design_prompt, components)
# Generate JavaScript for interactivity
js_content = generate_javascript_features(design_prompt, components)
# Determine page title from prompt
title = extract_title_from_prompt(design_prompt)
# Combine everything
final_code = html_template.format(
title=title,
css_content=css_content,
html_content=html_content,
js_content=js_content
)
return f"Generated HTML/CSS/JS code:\n\n```html\n{final_code}\n```"
def analyze_design_prompt(prompt: str) -> dict:
"""Analyze the design prompt to identify components and features needed."""
prompt_lower = prompt.lower()
components = {
'has_header': any(word in prompt_lower for word in ['header', 'navigation', 'nav', 'menu']),
'has_hero': any(word in prompt_lower for word in ['hero', 'banner', 'main section', 'landing']),
'has_cards': any(word in prompt_lower for word in ['card', 'cards', 'grid', 'boxes']),
'has_form': any(word in prompt_lower for word in ['form', 'input', 'contact', 'signup', 'login']),
'has_footer': any(word in prompt_lower for word in ['footer', 'bottom']),
'has_sidebar': any(word in prompt_lower for word in ['sidebar', 'aside', 'side panel']),
'has_gallery': any(word in prompt_lower for word in ['gallery', 'images', 'photos', 'portfolio']),
'has_animation': any(word in prompt_lower for word in ['animate', 'animation', 'hover', 'interactive']),
'color_scheme': extract_colors_from_prompt(prompt),
'layout_type': determine_layout_type(prompt),
'style_theme': determine_style_theme(prompt)
}
return components
def extract_colors_from_prompt(prompt: str) -> list:
"""Extract color preferences from the prompt."""
colors = []
color_words = ['blue', 'red', 'green', 'purple', 'orange', 'yellow', 'pink', 'black', 'white', 'gray', 'dark', 'light']
for color in color_words:
if color in prompt.lower():
colors.append(color)
return colors if colors else ['blue', 'white'] # Default colors
def determine_layout_type(prompt: str) -> str:
"""Determine the layout type based on the prompt."""
prompt_lower = prompt.lower()
if any(word in prompt_lower for word in ['dashboard', 'admin', 'panel']):
return 'dashboard'
elif any(word in prompt_lower for word in ['landing', 'homepage', 'marketing']):
return 'landing'
elif any(word in prompt_lower for word in ['blog', 'article', 'post']):
return 'blog'
elif any(word in prompt_lower for word in ['portfolio', 'gallery', 'showcase']):
return 'portfolio'
else:
return 'general'
def determine_style_theme(prompt: str) -> str:
"""Determine the visual style theme."""
prompt_lower = prompt.lower()
if any(word in prompt_lower for word in ['modern', 'clean', 'minimal']):
return 'modern'
elif any(word in prompt_lower for word in ['dark', 'night', 'black']):
return 'dark'
elif any(word in prompt_lower for word in ['colorful', 'vibrant', 'bright']):
return 'colorful'
elif any(word in prompt_lower for word in ['professional', 'corporate', 'business']):
return 'professional'
else:
return 'modern'
def fix_zindex_conflicts(css_content: str) -> str:
"""Fix common z-index conflicts in generated CSS."""
# Define z-index hierarchy for common components
zindex_hierarchy = {
'modal': 9999,
'modal-overlay': 9998,
'dropdown': 200,
'tooltip': 300,
'header': 1000,
'nav': 1001,
'sticky': 100,
'card-hover': 13,
'card': 12,
'form': 10,
'content': 1,
'background': -1
}
# Add z-index management comment
fixed_css = """
/* Z-Index Management System */
/* Modal: 9999, Dropdowns: 200-299, Headers: 1000-1099, Content: 1-99, Background: -1 */
""" + css_content
return fixed_css
def generate_css_from_prompt(prompt: str, components: dict) -> str:
"""Generate CSS based on the design requirements."""
# Base styles
css = """
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
color: #333;
}
"""
# Add theme-specific styles
if components['style_theme'] == 'dark':
css += """
body {
background-color: #1a1a1a;
color: #ffffff;
}
"""
elif components['style_theme'] == 'colorful':
css += """
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
}
"""
# Add component-specific styles with proper z-index management
if components['has_header']:
css += """
.header {
background-color: #2c3e50;
color: white;
padding: 1rem 0;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.nav {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
position: relative;
z-index: 1001;
}
.nav ul {
display: flex;
list-style: none;
gap: 2rem;
}
.nav a {
color: white;
text-decoration: none;
transition: color 0.3s;
position: relative;
z-index: 1002;
}
.nav a:hover {
color: #3498db;
}
"""
if components['has_hero']:
css += """
.hero {
background: linear-gradient(135deg, #3498db, #2c3e50);
color: white;
text-align: center;
padding: 8rem 2rem;
position: relative;
z-index: 1;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
z-index: -1;
}
.hero-content {
position: relative;
z-index: 2;
max-width: 800px;
margin: 0 auto;
}
.hero h1 {
font-size: 3rem;
margin-bottom: 1rem;
position: relative;
z-index: 3;
}
.hero p {
font-size: 1.2rem;
margin-bottom: 2rem;
position: relative;
z-index: 3;
}
.btn {
display: inline-block;
background-color: #e74c3c;
color: white;
padding: 1rem 2rem;
text-decoration: none;
border-radius: 5px;
transition: all 0.3s;
position: relative;
z-index: 3;
border: none;
cursor: pointer;
}
.btn:hover {
background-color: #c0392b;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(231, 76, 60, 0.3);
}
"""
if components['has_cards']:
css += """
.cards-section {
padding: 4rem 2rem;
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 10;
}
.cards-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-top: 2rem;
position: relative;
z-index: 11;
}
.card {
background: white;
border-radius: 10px;
padding: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
position: relative;
z-index: 12;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent, rgba(52, 152, 219, 0.1), transparent);
opacity: 0;
transition: opacity 0.3s;
z-index: -1;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
z-index: 13;
}
.card:hover::before {
opacity: 1;
}
.card h3 {
position: relative;
z-index: 2;
margin-bottom: 1rem;
}
.card p {
position: relative;
z-index: 2;
}
"""
if components['has_form']:
css += """
.form-section {
padding: 4rem 2rem;
background-color: #f8f9fa;
position: relative;
z-index: 5;
}
.form-container {
max-width: 600px;
margin: 0 auto;
background: white;
padding: 2rem;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
z-index: 6;
}
.form-group {
margin-bottom: 1.5rem;
position: relative;
z-index: 7;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
position: relative;
z-index: 8;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 1rem;
position: relative;
z-index: 8;
background: white;
transition: all 0.3s;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
z-index: 9;
}
.form-group input:focus + .focus-indicator,
.form-group textarea:focus + .focus-indicator {
opacity: 1;
transform: scaleX(1);
}
"""
if components['has_footer']:
css += """
.footer {
background-color: #2c3e50;
color: white;
text-align: center;
padding: 2rem 0;
margin-top: 4rem;
position: relative;
z-index: 100;
}
.footer p {
position: relative;
z-index: 101;
}
"""
# Add animations if requested with proper z-index
if components['has_animation']:
css += """
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInFromLeft {
from {
opacity: 0;
transform: translateX(-50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.animate-on-scroll {
animation: fadeInUp 0.6s ease-out forwards;
}
.animate-slide {
animation: slideInFromLeft 0.8s ease-out forwards;
}
/* Ensure animated elements don't interfere with z-index */
.animate-on-scroll,
.animate-slide {
position: relative;
z-index: auto;
}
"""
# Add modal and overlay styles with high z-index
css += """
/* Modal and overlay z-index management */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: none;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 2rem;
border-radius: 10px;
z-index: 9999;
max-width: 90vw;
max-height: 90vh;
overflow: auto;
}
/* Dropdown menus */
.dropdown {
position: relative;
z-index: 200;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
background: white;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 201;
min-width: 200px;
display: none;
}
.dropdown:hover .dropdown-menu {
display: block;
}
/* Tooltips */
.tooltip {
position: relative;
z-index: 300;
}
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 0.5rem;
border-radius: 4px;
font-size: 0.875rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
z-index: 301;
}
.tooltip:hover::after {
opacity: 1;
}
/* Responsive z-index adjustments */
@media (max-width: 768px) {
.header {
z-index: 1100;
}
.nav {
z-index: 1101;
}
.mobile-menu {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(44, 62, 80, 0.95);
z-index: 1200;
display: none;
}
.mobile-menu.active {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
}
"""
# Fix z-index conflicts and return optimized CSS
return fix_zindex_conflicts(css)
def generate_html_structure(prompt: str, components: dict) -> str:
"""Generate HTML structure based on components."""
html = ""
# Header
if components['has_header']:
html += """
<header class="header">
<nav class="nav">
<div class="logo">
<h2>Your Brand</h2>
</div>
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
"""
# Hero section
if components['has_hero']:
html += """
<section class="hero" id="home">
<div class="hero-content">
<h1>Welcome to Our Amazing Service</h1>
<p>Transform your ideas into reality with our cutting-edge solutions</p>
<a href="#contact" class="btn">Get Started</a>
</div>
</section>
"""
# Cards section
if components['has_cards']:
html += """
<section class="cards-section" id="services">
<div class="container">
<h2 style="text-align: center; margin-bottom: 2rem;">Our Services</h2>
<div class="cards-grid">
<div class="card">
<h3>Service One</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.</p>
</div>
<div class="card">
<h3>Service Two</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.</p>
</div>
<div class="card">
<h3>Service Three</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.</p>
</div>
</div>
</div>
</section>
"""
# Form section
if components['has_form']:
html += """
<section class="form-section" id="contact">
<div class="form-container">
<h2 style="text-align: center; margin-bottom: 2rem;">Contact Us</h2>
<form id="contactForm">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<button type="submit" class="btn" style="width: 100%;">Send Message</button>
</form>
</div>
</section>
"""
# Footer
if components['has_footer']:
html += """
<footer class="footer">
<div class="container">
<p>&copy; 2024 Your Company. All rights reserved.</p>
</div>
</footer>
"""
return html
def generate_javascript_features(prompt: str, components: dict) -> str:
"""Generate JavaScript for interactivity."""
js = """
// Smooth scrolling for navigation links
document.addEventListener('DOMContentLoaded', function() {
const links = document.querySelectorAll('a[href^="#"]');
links.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
"""
# Add form handling if form exists
if components['has_form']:
js += """
// Form submission handling
const contactForm = document.getElementById('contactForm');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this);
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
// Simple validation
if (name && email && message) {
alert('Thank you for your message! We will get back to you soon.');
this.reset();
} else {
alert('Please fill in all fields.');
}
});
}
"""
# Add scroll animations if requested
if components['has_animation']:
js += """
// Scroll animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-on-scroll');
}
});
}, observerOptions);
// Observe cards and other elements
const animatedElements = document.querySelectorAll('.card, .hero-content');
animatedElements.forEach(el => observer.observe(el));
"""
js += """
});
"""
return js
def extract_title_from_prompt(prompt: str) -> str:
"""Extract a suitable title from the design prompt."""
prompt_lower = prompt.lower()
if 'dashboard' in prompt_lower:
return 'Dashboard'
elif 'portfolio' in prompt_lower:
return 'Portfolio'
elif 'landing' in prompt_lower or 'homepage' in prompt_lower:
return 'Welcome'
elif 'blog' in prompt_lower:
return 'Blog'
elif 'contact' in prompt_lower:
return 'Contact Us'
else:
return 'My Website'
@tool
def get_current_time_in_timezone(timezone: str) -> str:
"""A tool that fetches the current local time in a specified timezone.
Args:
timezone: A string representing a valid timezone (e.g., 'America/New_York').
"""
try:
# Create timezone object
tz = pytz.timezone(timezone)
# Get current time in that timezone
local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
return f"The current local time in {timezone} is: {local_time}"
except Exception as e:
return f"Error fetching time for timezone '{timezone}': {str(e)}"
@tool
def image_analyzer_for_design(image_path: str, analysis_type: str = "design") -> str:
"""Analyze an uploaded image to extract design elements and generate code suggestions.
Args:
image_path: Path to the image file
analysis_type: Type of analysis to perform ('design', 'layout', 'colors')
"""
try:
# This is a placeholder for image analysis
# In a real implementation, you would use computer vision or AI models
return f"Image analysis for {image_path}: Detected modern layout with clean design elements. Suggested color scheme: blue and white. Layout appears to be a landing page with header, hero section, and cards."
except Exception as e:
return f"Error analyzing image: {str(e)}"
final_answer = FinalAnswerTool()
# Model configuration
model = HfApiModel(
max_tokens=2096,
temperature=0.5,
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
custom_role_conversions=None,
)
# Load additional tools
try:
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
except:
print("Image generation tool not available")
image_generation_tool = None
# Load prompts
with open("prompts.yaml", 'r') as stream:
prompt_templates = yaml.safe_load(stream)
# Create agent with enhanced tools
tools = [
final_answer,
design_to_code_generator,
get_current_time_in_timezone,
image_analyzer_for_design,
]
# Add image generation tool if available
if image_generation_tool:
tools.append(image_generation_tool)
agent = CodeAgent(
model=model,
tools=tools,
max_steps=6,
verbosity_level=1,
grammar=None,
planning_interval=None,
name="DesignToCodeAgent", # Fixed: removed spaces and hyphens
description="An AI agent that converts design descriptions and images into functional HTML, CSS, and JavaScript code.",
prompt_templates=prompt_templates
)
# Launch the Gradio interface
GradioUI(agent).launch()