Files
ALwrity/backend/api/onboarding_utils/website_automation_service.py
ajaysi b3cc83ed6e fix: resolve onboarding session not found warnings and frontend build OOM
- Use canonical Clerk user id (clerk_user_id) across all onboarding entrypoints to ensure consistent OnboardingSession.user_id lookup
- Fix API key persistence in api_key_manager.py to use correct APIKey model columns (session_id, provider, key)
- Increase Node heap for frontend build to 8GB and add build:nomap script to disable sourcemaps and reduce memory usage
- Update onboarding endpoints (endpoints_core.py, onboarding_control_service.py, step_management_service.py) to prefer clerk_user_id over id
- Fix frontend workflowStore.ts TypeScript error by returning WorkflowError instance
- Add website_automation_service.py for onboarding automation
2026-03-09 13:36:34 +05:30

251 lines
8.5 KiB
Python

"""Website Automation Service for API layer - orchestrates website creation."""
from typing import Dict, Any, Optional
from loguru import logger
import os
import tempfile
import json
from fastapi import HTTPException
# Import the actual automation service
from services.onboarding.website_automation_service import WebsiteAutomationService as CoreAutomationService
class WebsiteAutomationService:
"""API layer service for website automation operations."""
def __init__(self):
logger.info("🔄 Initializing WebsiteAutomationService (API layer)...")
self.core_service = CoreAutomationService()
async def generate_preview_site(
self,
user_id: str,
site_brief: Dict[str, Any],
css: str
) -> Dict[str, Any]:
"""Generate a preview site for the user."""
try:
logger.info(f"Generating preview site for user {user_id}")
# For preview, we'll create a temporary HTML file
# In production, this could be hosted on a preview server
preview_html = self._generate_preview_html(site_brief, css)
# Save to temporary file (in production, use proper hosting)
preview_url = f"/preview/{user_id}/index.html"
return {
"preview_url": preview_url,
"preview_root": f"/preview/{user_id}",
"preview_files": ["index.html", "custom.css"],
"preview_html": preview_html
}
except Exception as e:
logger.error(f"Failed to generate preview site: {str(e)}")
raise HTTPException(status_code=500, detail=f"Preview generation failed: {str(e)}")
def _generate_preview_html(self, site_brief: Dict[str, Any], css: str) -> str:
"""Generate HTML preview from site brief and CSS."""
try:
site_data = site_brief.get("site_brief", {})
business_name = site_data.get("business_name", "Your Business")
tagline = site_data.get("tagline", "Your tagline here")
# Get content plan
content_plan = site_brief.get("content_plan", {})
required_pages = content_plan.get("required_pages", [])
# Generate HTML
html = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{business_name}</title>
<style>
{css}
/* Additional preview styles */
.preview-banner {{
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 2rem;
text-align: center;
margin-bottom: 2rem;
}}
.preview-banner h1 {{
margin: 0;
font-size: 2.5rem;
}}
.preview-banner p {{
margin: 0.5rem 0 0 0;
font-size: 1.2rem;
opacity: 0.9;
}}
.preview-content {{
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
}}
.preview-section {{
margin-bottom: 3rem;
}}
.preview-grid {{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}}
.preview-card {{
background: var(--color-surface, #f8fafc);
padding: 1.5rem;
border-radius: var(--border-radius-medium, 0.5rem);
box-shadow: var(--shadow-small, 0 1px 2px 0 rgb(0 0 0 / 0.05));
}}
.preview-watermark {{
position: fixed;
bottom: 1rem;
right: 1rem;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
font-size: 0.875rem;
z-index: 1000;
}}
</style>
</head>
<body>
<div class="preview-banner">
<h1>{business_name}</h1>
<p>{tagline}</p>
<div class="preview-watermark">ALwrity Preview</div>
</div>
<div class="preview-content">
{self._generate_page_content(required_pages)}
</div>
<script>
// Basic interactions for preview
document.addEventListener('DOMContentLoaded', function() {{
console.log('ALwrity website preview loaded');
}});
</script>
</body>
</html>"""
return html
except Exception as e:
logger.error(f"Failed to generate preview HTML: {str(e)}")
return f"<html><body><h1>Preview Error</h1><p>{str(e)}</p></body></html>"
def _generate_page_content(self, required_pages: list) -> str:
"""Generate HTML content for pages."""
if not required_pages:
return """
<div class="preview-section">
<h2>Welcome to Your Website</h2>
<p>This is a preview of your new website. The content will be generated based on your business information.</p>
<div class="preview-grid">
<div class="preview-card">
<h3>About Us</h3>
<p>Learn more about your business and what makes you unique.</p>
</div>
<div class="preview-card">
<h3>Services</h3>
<p>Discover the services and products you offer to your customers.</p>
</div>
<div class="preview-card">
<h3>Contact</h3>
<p>Get in touch with you through various contact methods.</p>
</div>
</div>
</div>
"""
content_parts = []
for page in required_pages:
page_name = page.get("page", "page").title()
goal = page.get("goal", "")
key_points = page.get("key_points", [])
cta = page.get("cta", "Get Started")
page_html = f"""
<div class="preview-section">
<h2>{page_name}</h2>
<p>{goal}</p>
"""
if key_points:
page_html += "<div class='preview-grid'>"
for point in key_points:
page_html += f"""
<div class="preview-card">
<p>{point}</p>
</div>
"""
page_html += "</div>"
if cta:
page_html += f"""
<div style="margin-top: 2rem;">
<button class="btn btn-primary">{cta}</button>
</div>
"""
page_html += "</div>"
content_parts.append(page_html)
return "".join(content_parts)
async def generate_website(
self,
user_id: str,
business_info: Dict[str, Any],
niche: str,
site_brief: Optional[Dict[str, Any]] = None,
css: Optional[str] = None
) -> Dict[str, str]:
"""Generate and deploy a full website."""
try:
logger.info(f"Generating website for user {user_id}")
# Use the core automation service
result = await self.core_service.generate_website(
user_id=user_id,
business_info=business_info,
niche=niche,
site_brief=site_brief,
css=css
)
return result
except Exception as e:
logger.error(f"Failed to generate website: {str(e)}")
raise HTTPException(status_code=500, detail=f"Website generation failed: {str(e)}")
def get_deployment_status(self, user_id: str) -> Dict[str, Any]:
"""Get the status of website deployment."""
try:
# This would typically check the deployment status
# For now, return a placeholder
return {
"status": "pending",
"message": "Deployment status checking not yet implemented"
}
except Exception as e:
logger.error(f"Failed to get deployment status: {str(e)}")
return {
"status": "error",
"message": str(e)
}
# Singleton instance
website_automation_service = WebsiteAutomationService()