netcop-ai/social_ads.html
thecyberlearn c897baffd5 Add additional project files and templates
- Add PDF data analyzer configuration and data files
- Include social ads HTML template
- Add workflow template for project setup

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 23:24:36 +05:30

1503 lines
56 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Social Ads Generator - NetCop AI Hub</title>
<style>
/* Social Ads Generator - Exact UI Copy */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
* {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
box-sizing: border-box;
}
:root {
--primary: #000000;
--surface: #ffffff;
--surface-variant: #f8fafc;
--background: #f3f4f6;
--outline: #e4e7eb;
--outline-variant: #e1e4e7;
--on-surface: #1a1a1a;
--on-surface-variant: #6b7280;
--success: #10b981;
--error: #ef4444;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 20px rgba(0, 0, 0, 0.15);
}
html {
scrollbar-gutter: stable;
}
body {
background: var(--background);
color: var(--on-surface);
line-height: 1.5;
font-weight: 400;
margin: 0;
padding: 0;
}
/* Layout */
.agent-container {
margin: 0 auto;
padding: var(--spacing-lg);
max-width: 1600px;
}
.agent-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
}
.header-controls {
display: flex;
align-items: center;
gap: var(--spacing-lg);
}
.agent-grid {
display: flex;
gap: var(--spacing-lg);
align-items: flex-start;
flex-wrap: wrap;
margin-bottom: var(--spacing-lg);
}
/* Typography */
.agent-title {
font-size: 32px;
font-weight: 700;
color: var(--on-surface);
margin: 0;
letter-spacing: -0.5px;
}
.agent-subtitle {
font-size: 16px;
color: var(--on-surface-variant);
margin: 4px 0 0 0;
}
/* Widgets */
.agent-widget {
background: var(--surface);
border-radius: var(--radius-lg);
padding: var(--spacing-xl);
border: 1px solid var(--outline-variant);
box-shadow: var(--shadow-sm);
transition: all 0.2s ease;
display: flex;
flex-direction: column;
}
.widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-lg);
padding-bottom: var(--spacing-md);
border-bottom: 1px solid var(--outline-variant);
}
.widget-title {
font-size: 18px;
font-weight: 600;
color: var(--on-surface);
margin: 0;
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.widget-icon {
font-size: 20px;
padding: 6px;
border-radius: var(--radius-sm);
background: var(--surface-variant);
}
.widget-content {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--spacing-md);
}
/* Widget Sizes */
.widget-large {
flex: 1;
min-width: 400px;
}
.widget-small {
flex: 0 0 280px;
}
.widget-wide {
flex: 1 1 100%;
width: 100%;
}
/* Wallet Card */
.wallet-card {
background: linear-gradient(135deg, #000000 0%, #333333 100%);
color: white;
border-radius: var(--radius-md);
padding: var(--spacing-md);
border: none;
box-shadow: var(--shadow-md);
position: relative;
overflow: hidden;
margin-bottom: 0;
min-height: auto;
}
.wallet-card::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 100px;
height: 100px;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
transform: translate(30px, -30px);
}
.wallet-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-sm);
}
.wallet-title {
font-size: 14px;
font-weight: 600;
margin: 0;
opacity: 0.9;
}
.wallet-icon {
font-size: 20px;
}
.wallet-content {
display: flex;
align-items: center;
gap: var(--spacing-md);
position: relative;
z-index: 1;
}
.balance-display {
margin-bottom: 0;
}
.balance-amount {
font-size: 24px;
font-weight: 700;
line-height: 1;
margin-bottom: 0;
letter-spacing: -0.5px;
}
.balance-label {
font-size: 12px;
opacity: 0.8;
font-weight: 400;
}
.wallet-topup-btn {
width: 100%;
padding: 8px 16px;
background: linear-gradient(135deg, #4f46e5, #7c3aed);
color: white;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
margin-top: 12px;
}
.wallet-topup-btn:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
/* Form Sections */
.section-container {
margin-bottom: var(--spacing-xl);
padding: var(--spacing-lg);
background: var(--surface-variant);
border-radius: var(--radius-md);
border: 1px solid var(--outline-variant);
}
.section-subtitle {
font-size: 16px;
font-weight: 600;
color: var(--on-surface);
margin: 0 0 var(--spacing-lg) 0;
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.section-subtitle::before {
content: '';
width: 3px;
height: 16px;
background: var(--primary);
border-radius: 2px;
}
.form-group {
margin-bottom: var(--spacing-lg);
}
.form-label {
display: block;
font-weight: 500;
color: var(--on-surface);
margin-bottom: var(--spacing-sm);
font-size: 14px;
}
.form-input, .form-textarea {
width: 100%;
padding: 12px 16px;
border: 2px solid var(--outline-variant);
border-radius: var(--radius-md);
font-size: 14px;
line-height: 1.5;
background: var(--surface);
color: var(--on-surface);
transition: all 0.2s ease;
font-family: inherit;
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 2px solid var(--outline-variant);
border-radius: var(--radius-md);
font-size: 14px;
line-height: 1.5;
background: var(--surface);
color: var(--on-surface);
transition: all 0.2s ease;
font-family: inherit;
}
.form-input:focus, .form-textarea:focus, .form-control:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
}
.form-input:hover, .form-textarea:hover, .form-control:hover {
border-color: var(--on-surface-variant);
}
.form-textarea {
resize: vertical;
min-height: 120px;
}
.form-help {
color: var(--on-surface-variant);
font-size: 0.875rem;
margin-top: var(--spacing-xs);
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 24px;
border: 1px solid transparent;
border-radius: var(--radius-md);
font-size: 14px;
font-weight: 600;
line-height: 1.25;
text-decoration: none;
cursor: pointer;
transition: all 0.2s ease;
user-select: none;
white-space: nowrap;
min-height: 44px;
}
.btn:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
}
.btn-primary {
background: var(--primary);
color: var(--surface);
}
.btn-primary:hover:not(:disabled) {
background: #333;
}
.btn-secondary {
background: var(--surface);
color: var(--on-surface);
border: 2px solid var(--outline);
}
.btn-secondary:hover:not(:disabled) {
background: var(--surface-variant);
border-color: var(--primary);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.btn-full {
width: 100%;
justify-content: center;
padding: 12px 24px;
font-size: 14px;
font-weight: 600;
}
/* Info List */
.info-list {
list-style: none;
padding: 0;
margin: 0;
counter-reset: step-counter;
}
.info-list li {
padding: var(--spacing-sm) 0;
color: var(--on-surface-variant);
font-size: 14px;
border-bottom: 1px solid var(--outline-variant);
position: relative;
padding-left: var(--spacing-lg);
}
.info-list li:last-child {
border-bottom: none;
}
.info-list li::before {
content: counter(step-counter);
counter-increment: step-counter;
position: absolute;
left: 0;
top: var(--spacing-sm);
width: 20px;
height: 20px;
background: var(--primary);
color: var(--surface);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
}
/* Quick Agent Toggle */
.quick-agent-toggle {
position: relative;
overflow: hidden;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: var(--spacing-sm);
justify-content: center;
}
.quick-agent-toggle:hover {
border-color: var(--primary);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.toggle-icon {
font-size: 16px;
}
/* Processing Status */
.processing-status {
background: var(--surface);
border: 1px solid var(--outline);
border-radius: var(--radius-md);
padding: var(--spacing-xl);
text-align: center;
box-shadow: var(--shadow-sm);
display: none;
margin-bottom: var(--spacing-lg);
}
.processing-status.active {
display: block;
}
.status-icon {
font-size: 48px;
margin-bottom: var(--spacing-md);
animation: pulse 2s infinite;
}
.status-title {
font-size: 18px;
font-weight: 600;
color: var(--on-surface);
margin-bottom: var(--spacing-sm);
}
.status-text {
font-size: 14px;
color: var(--on-surface-variant);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Results */
.results-card {
background: var(--surface);
border: 1px solid var(--outline);
border-radius: var(--radius-lg);
padding: var(--spacing-xl);
box-shadow: var(--shadow-sm);
display: none;
margin-bottom: var(--spacing-lg);
}
.results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-lg);
padding-bottom: var(--spacing-md);
border-bottom: 1px solid var(--outline);
}
.results-content {
background: var(--surface-variant);
border-radius: var(--radius-md);
padding: var(--spacing-xl);
margin-bottom: var(--spacing-lg);
line-height: 1.7;
color: var(--on-surface);
font-size: 15px;
}
.action-buttons {
display: flex;
gap: var(--spacing-md);
flex-wrap: wrap;
}
/* Quick Agents Panel */
.quick-agents-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.quick-agents-overlay.active {
opacity: 1;
visibility: visible;
}
.quick-agents-panel {
position: fixed;
top: 0;
right: 0;
width: min(400px, 90vw);
height: 100vh;
background: var(--surface);
border-left: 1px solid var(--outline);
box-shadow: var(--shadow-lg);
z-index: 1000;
transform: translateX(100%);
transition: transform 0.3s ease;
overflow-y: auto;
}
.quick-agents-panel.active {
transform: translateX(0);
}
.quick-agents-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-lg);
border-bottom: 1px solid var(--outline-variant);
background: var(--surface-variant);
}
.quick-agents-header h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--on-surface);
}
.close-panel {
background: none;
border: none;
font-size: 24px;
color: var(--on-surface-variant);
cursor: pointer;
padding: 4px;
border-radius: var(--radius-sm);
transition: all 0.2s ease;
}
.close-panel:hover {
background: var(--surface);
color: var(--on-surface);
}
.quick-agents-grid {
padding: var(--spacing-lg);
display: flex;
flex-direction: column;
gap: var(--spacing-md);
}
.quick-agent-card {
display: flex;
align-items: center;
gap: var(--spacing-md);
padding: var(--spacing-md);
border: 1px solid var(--outline-variant);
border-radius: var(--radius-md);
text-decoration: none;
color: var(--on-surface);
transition: all 0.2s ease;
background: var(--surface);
}
.quick-agent-card:hover {
border-color: var(--primary);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.agent-icon {
font-size: 24px;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: var(--surface-variant);
border-radius: var(--radius-md);
flex-shrink: 0;
}
.agent-info {
flex: 1;
min-width: 0;
}
.agent-info h4 {
margin: 0 0 4px 0;
font-size: 14px;
font-weight: 600;
color: var(--on-surface);
}
.agent-info p {
margin: 0;
font-size: 12px;
color: var(--on-surface-variant);
line-height: 1.4;
}
.agent-price {
font-size: 12px;
font-weight: 600;
color: var(--primary);
background: rgba(0, 0, 0, 0.05);
padding: 2px 8px;
border-radius: var(--radius-sm);
margin-top: 4px;
display: inline-block;
}
.quick-agents-footer {
padding: var(--spacing-md) var(--spacing-lg);
border-top: 1px solid var(--outline-variant);
background: var(--surface-variant);
}
.view-all-agents {
display: block;
text-align: center;
padding: var(--spacing-md);
background: var(--primary);
color: white;
text-decoration: none;
border-radius: var(--radius-md);
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
}
.view-all-agents:hover {
background: #333333;
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
/* Responsive Design */
@media (max-width: 768px) {
.agent-container {
padding: var(--spacing-md);
}
.agent-header {
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-sm);
}
.header-controls {
width: 100%;
justify-content: space-between;
}
.agent-title {
font-size: 24px;
}
.agent-grid {
flex-direction: column;
gap: var(--spacing-md);
}
.widget-large,
.widget-small {
min-width: auto;
flex: none;
}
.balance-amount {
font-size: 20px;
}
.widget-large {
margin-right: 0 !important;
}
.quick-agents-panel {
width: 100%;
max-width: 100%;
right: 0;
left: 0;
}
}
/* Toast Notifications */
.toast {
position: fixed;
top: 20px;
right: 20px;
background: var(--surface);
border: 1px solid var(--outline);
border-radius: var(--radius-md);
padding: var(--spacing-md) var(--spacing-lg);
box-shadow: var(--shadow-lg);
z-index: 1000;
max-width: 400px;
font-size: 14px;
font-weight: 500;
transform: translateX(100%);
transition: transform 0.3s ease;
}
.toast.show {
transform: translateX(0);
}
.toast.success {
border-color: var(--success);
background: #f0fdf4;
color: #16a34a;
}
.toast.error {
border-color: var(--error);
background: #fef2f2;
color: #dc2626;
}
</style>
</head>
<body>
<div class="agent-container">
<!-- Agent Header -->
<div class="agent-header">
<div>
<h1 class="agent-title">Social Ads Generator</h1>
<p class="agent-subtitle">Create compelling social media advertisements with AI-powered content generation</p>
</div>
<div class="header-controls">
<!-- Wallet Card Component -->
<div class="wallet-card widget-small">
<div class="wallet-header">
<h3 class="wallet-title">Your Wallet</h3>
<div class="wallet-icon">💳</div>
</div>
<div class="balance-display">
<div class="balance-amount">
<span id="walletBalance">25.50</span> AED
</div>
<div class="balance-label">Available Balance</div>
</div>
<button type="button" class="wallet-topup-btn" onclick="showToast('Top-up feature demo!', 'success')">
💳 Top Up Wallet
</button>
</div>
</div>
</div>
<!-- Quick Agent Access Panel Overlay -->
<div class="quick-agents-overlay" id="quickAgentsOverlay" onclick="closeQuickAgents()"></div>
<!-- Quick Agent Access Panel -->
<div class="quick-agents-panel" id="quickAgentsPanel">
<div class="quick-agents-header">
<h3>Quick Access</h3>
<button class="close-panel" onclick="closeQuickAgents()" aria-label="Close panel">×</button>
</div>
<div class="quick-agents-grid">
<!-- Sample Agent Cards -->
<a href="#" class="quick-agent-card">
<div class="agent-icon">🌤️</div>
<div class="agent-info">
<h4>Weather Reporter</h4>
<p>Get real-time weather data</p>
<span class="agent-price">2.00 AED</span>
</div>
</a>
<a href="#" class="quick-agent-card">
<div class="agent-icon">📊</div>
<div class="agent-info">
<h4>Data Analyzer</h4>
<p>AI-powered data analysis</p>
<span class="agent-price">5.00 AED</span>
</div>
</a>
<a href="#" class="quick-agent-card">
<div class="agent-icon">💼</div>
<div class="agent-info">
<h4>Job Posting Generator</h4>
<p>Create professional job postings</p>
<span class="agent-price">4.00 AED</span>
</div>
</a>
</div>
<div class="quick-agents-footer">
<a href="#" class="view-all-agents">View All Agents</a>
</div>
</div>
<!-- Agent Grid -->
<div class="agent-grid">
<!-- Social Ads Form Widget -->
<div class="agent-widget widget-large" style="flex: 1; margin-right: clamp(0px, var(--spacing-lg), 2vw);">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon">📢</span>
Social Ads Details
</h3>
</div>
<div class="widget-content">
<form method="POST" id="socialAdsForm">
<!-- Content Information Section -->
<div class="section-container content-info">
<h4 class="section-subtitle">📝 Content Information</h4>
<div class="form-group">
<label class="form-label" for="description">📝 Describe what you'd like to generate *</label>
<textarea name="description" id="description" class="form-textarea" placeholder="Describe the product, service, or campaign you want to create an ad for. Include key features, target audience, and any specific messaging you want to emphasize." required aria-describedby="description_help" rows="4"></textarea>
<div id="description_help" class="form-help">Provide clear, specific information about your product or service for better ad copy</div>
</div>
<div class="form-group">
<label class="form-label" for="language">🌐 Language</label>
<select name="language" id="language" class="form-input" aria-describedby="language_help">
<option value="English">English</option>
<option value="Arabic">Arabic (العربية)</option>
<option value="Spanish">Spanish (Español)</option>
<option value="French">French (Français)</option>
<option value="German">German (Deutsch)</option>
<option value="Chinese">Chinese (中文)</option>
</select>
<div id="language_help" class="form-help">Select the primary language for the ad copy</div>
</div>
</div>
<!-- Platform & Formatting Section -->
<div class="section-container platform-info">
<h4 class="section-subtitle">📱 Platform & Formatting</h4>
<div class="form-group">
<label class="form-label" for="social_platform">📱 For Social Media Platform *</label>
<select name="social_platform" id="social_platform" class="form-input" required aria-describedby="social_platform_help">
<option value="">Select a platform...</option>
<option value="facebook">Facebook</option>
<option value="instagram">Instagram</option>
<option value="linkedin">LinkedIn</option>
<option value="twitter">X (Twitter)</option>
<option value="tiktok">TikTok</option>
<option value="youtube">YouTube</option>
</select>
<div id="social_platform_help" class="form-help">Choose the social media platform for optimization</div>
</div>
<div class="form-group">
<label class="form-label" for="include_emoji">😊 Include Emoji *</label>
<select name="include_emoji" id="include_emoji" class="form-input" required aria-describedby="include_emoji_help">
<option value="">Select an option...</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
<div id="include_emoji_help" class="form-help">Whether to include emojis in the ad copy</div>
</div>
</div>
<!-- Action Button -->
<div style="margin-top: var(--spacing-lg);">
<button type="submit" class="btn btn-primary btn-full" id="processButton">
📢 Generate Social Ads
</button>
</div>
</form>
</div>
</div>
<!-- How It Works Widget - Positioned on the right -->
<div class="agent-widget widget-small" style="min-width: min(280px, 100%); max-width: min(280px, 100%); margin-left: auto;">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon"></span>
How It Works
</h3>
</div>
<div class="widget-content">
<ol class="info-list">
<li>Describe your product/service</li>
<li>Select target platforms</li>
<li>Choose language preferences</li>
<li>Get platform-optimized ad copy</li>
</ol>
<!-- Other Agents Button -->
<button class="quick-agent-toggle btn btn-secondary btn-full" onclick="toggleQuickAgents()"
title="Quick access to other agents"
aria-label="Open quick access panel for other AI agents"
aria-expanded="false"
aria-controls="quickAgentsPanel"
style="margin-top: var(--spacing-md);">
<span class="toggle-icon" aria-hidden="true">🚀</span>
<span class="toggle-text">Explore Other Agents</span>
</button>
</div>
</div>
</div>
<!-- Processing Status -->
<div class="agent-grid">
<div id="processingStatus" class="agent-widget processing-status" style="width: 100%;">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon"></span>
Processing Status
</h3>
</div>
<div class="widget-content" style="text-align: center;">
<div class="status-icon"></div>
<div class="status-title">Creating Social Ads...</div>
<div class="status-text" id="statusText">Generating engaging ad content...</div>
</div>
</div>
</div>
<!-- Results -->
<div class="agent-grid">
<div id="adResults" class="agent-widget results-card" style="width: 100%;">
<div class="results-header">
<h3 class="widget-title">
<span class="widget-icon">📊</span>
Generated Social Ads
</h3>
<span class="status-badge" style="background: var(--success); color: white; padding: 4px 8px; border-radius: var(--radius-sm); font-size: 12px;">Success</span>
</div>
<div class="results-content" id="adContent">
<!-- Results will be populated here -->
<p>Your generated social media ads will appear here...</p>
</div>
<div class="action-buttons">
<button onclick="copySocialAds()" class="btn btn-primary">📋 Copy Results</button>
<button onclick="downloadSocialAds()" class="btn btn-secondary">💾 Download</button>
<button onclick="resetForm()" class="btn btn-secondary">🔄 New Request</button>
</div>
</div>
</div>
<!-- N8N Integration Info -->
<div class="agent-grid" style="margin-top: var(--spacing-xl); border-top: 1px solid var(--outline-variant); padding-top: var(--spacing-lg);">
<div class="agent-widget" style="width: 100%;">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon">🔗</span>
N8N Integration Status
</h3>
</div>
<div class="widget-content">
<p style="margin-bottom: var(--spacing-md); color: var(--on-surface-variant);">
This page communicates directly with N8N webhook:
</p>
<div style="background: var(--surface-variant); padding: var(--spacing-md); border-radius: var(--radius-md); font-family: monospace; font-size: 12px; color: var(--on-surface-variant); word-break: break-all;">
http://localhost:5678/webhook/2dc234d8-7217-454a-83e9-81afe5b4fe2d
</div>
<div style="margin-top: var(--spacing-md);">
<button onclick="testN8NConnection()" class="btn btn-secondary" style="font-size: 12px; padding: 8px 16px;">
🔍 Test N8N Connection
</button>
</div>
<div style="margin-top: var(--spacing-md); font-size: 13px; color: var(--on-surface-variant);">
<strong>Requirements:</strong><br>
• N8N instance running on localhost:5678<br>
• Workflow with the above webhook ID active<br>
• CORS enabled if needed<br>
• OpenAI API key configured in workflow
</div>
<div style="margin-top: var(--spacing-md); font-size: 13px; color: var(--on-surface-variant);">
<strong>Troubleshooting:</strong><br>
• Check N8N is accessible at <code>http://localhost:5678</code><br>
• Verify workflow is active and webhook matches<br>
• Check browser console for detailed errors
</div>
<div style="margin-top: var(--spacing-lg); padding: var(--spacing-md); background: #d4edda; border: 1px solid #c3e6cb; border-radius: var(--radius-md);">
<div style="font-weight: 600; color: #155724; margin-bottom: var(--spacing-sm);">✅ USING ORIGINAL N8N WORKFLOW</div>
<div style="font-size: 12px; color: #155724;">
<strong>Frontend updated to work with:</strong><br>
<code style="background: rgba(0,0,0,0.1); padding: 2px 4px; border-radius: 3px;">
social_ads_generator/n8n_workflows/Social_Ads.json
</code><br><br>
<strong>Data format:</strong><br>
<code>{"body": {"sessionId": "...", "message": {"text": "..."}}}</code><br><br>
<strong>Status:</strong> Frontend now sends data in the correct format for the original workflow
</div>
</div>
</div>
</div>
</div>
</div>
<script>
/*
====================================================================
N8N WORKFLOW OPTIMIZATION - REQUIRED CHANGES
====================================================================
Frontend now sends SIMPLE data structure:
{
"description": "Product description here",
"social_platform": "facebook",
"include_emoji": "yes",
"language": "English"
}
REQUIRED N8N WORKFLOW CHANGES:
1. UPDATE "Set Web Input" NODE:
Add these expressions to create the data structure the workflow needs:
sessionId:
"session_" + $now + "_" + $randomString(6)
description:
$json.body.description
social_platform:
$json.body.social_platform
include_emoji:
$json.body.include_emoji
language:
$json.body.language
message:
{
"text": "Create social media ads for: " + $json.body.description +
". Target Platform: " + $json.body.social_platform +
". Include Emojis: " + $json.body.include_emoji +
". Language: " + $json.body.language +
"\n\nPlease create compelling social media advertisement copy that:" +
"\n- Captures attention instantly" +
"\n- Highlights key benefits and unique selling points" +
"\n- Uses persuasive messaging that motivates action" +
"\n- Includes a strong call-to-action" +
"\n- Is tailored to " + $json.body.social_platform + " audience" +
"\n- Uses " + $json.body.language + " language" +
($json.body.include_emoji === "yes" ? "\n- Incorporates relevant emojis for engagement" : "") +
"\n\nFormat the response as professional ad copy ready for social media posting."
}
2. UPDATE "Simple Memory" NODE:
Change sessionKey expression to:
$('Set Web Input').item.json.sessionId
3. UPDATE "AI Agent" NODE:
Change text expression to:
$('Set Web Input').item.json.message.text
BENEFITS:
- Frontend code reduced by 90%
- Better separation of concerns
- Prompt changes only need N8N updates
- Session management handled in N8N
- Cleaner, more maintainable architecture
====================================================================
*/
// Simplified JavaScript Functions
// Quick Agent Access Panel Functions
function toggleQuickAgents() {
const panel = document.getElementById('quickAgentsPanel');
const overlay = document.getElementById('quickAgentsOverlay');
const toggle = document.querySelector('.quick-agent-toggle');
const isActive = panel.classList.contains('active');
if (isActive) {
// Close panel
panel.classList.remove('active');
overlay.classList.remove('active');
toggle.classList.remove('active');
toggle.setAttribute('aria-expanded', 'false');
panel.setAttribute('aria-hidden', 'true');
overlay.setAttribute('aria-hidden', 'true');
document.body.style.overflow = 'auto';
} else {
// Open panel
panel.classList.add('active');
overlay.classList.add('active');
toggle.classList.add('active');
toggle.setAttribute('aria-expanded', 'true');
panel.setAttribute('aria-hidden', 'false');
overlay.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
}
}
function closeQuickAgents() {
const panel = document.getElementById('quickAgentsPanel');
const overlay = document.getElementById('quickAgentsOverlay');
const toggle = document.querySelector('.quick-agent-toggle');
if (panel && overlay && toggle) {
panel.classList.remove('active');
overlay.classList.remove('active');
toggle.classList.remove('active');
toggle.setAttribute('aria-expanded', 'false');
panel.setAttribute('aria-hidden', 'true');
overlay.setAttribute('aria-hidden', 'true');
document.body.style.overflow = 'auto';
}
}
// Toast Notification Function
function showToast(message, type = 'info') {
// Remove existing toasts
document.querySelectorAll('.toast').forEach(toast => toast.remove());
// Create new toast
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
// Add to page
document.body.appendChild(toast);
// Show toast with animation
setTimeout(() => toast.classList.add('show'), 100);
// Auto remove after 3 seconds
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Processing Status Functions
function showProcessing() {
const processingStatus = document.getElementById('processingStatus');
processingStatus.style.display = 'block';
processingStatus.classList.add('active');
showToast('Processing started...', 'success');
}
function hideProcessing() {
const processingStatus = document.getElementById('processingStatus');
processingStatus.style.display = 'none';
processingStatus.classList.remove('active');
showToast('Processing stopped...', 'success');
}
// Display real N8N results
function displayRealResults(data) {
const results = document.getElementById('adResults');
const adContent = document.getElementById('adContent');
let content = '';
try {
// Handle different N8N response formats
if (typeof data === 'string') {
// If it's a string, use it directly
content = data;
} else if (data && typeof data === 'object') {
// If it's an object, look for common fields
if (data.output) {
content = data.output;
} else if (data.text) {
content = data.text;
} else if (data.content) {
content = data.content;
} else if (data.ad_copy) {
content = data.ad_copy;
} else if (data.result) {
content = data.result;
} else if (data.message) {
content = data.message;
} else {
// If it's an object but no recognizable fields, stringify it
content = JSON.stringify(data, null, 2);
}
} else {
content = 'No content received from N8N';
}
// Format content for display
const formattedContent = content ? content.replace(/\n/g, '<br>') : 'No content received';
adContent.innerHTML = `
<div class="generated-content">
<h2>🎯 Generated Social Media Advertisement</h2>
<div class="ad-content" style="background: var(--surface-variant); padding: var(--spacing-lg); border-radius: var(--radius-md); margin: var(--spacing-md) 0;">
${formattedContent}
</div>
<div class="generation-info" style="margin-top: var(--spacing-md); padding: var(--spacing-md); background: #f8f9fa; border-radius: var(--radius-sm); font-size: 12px;">
<p><strong>Generated at:</strong> ${new Date().toLocaleString()}</p>
<p><strong>Platform:</strong> ${document.getElementById('social_platform').value}</p>
<p><strong>Language:</strong> ${document.getElementById('language').value}</p>
<p><strong>Response type:</strong> ${typeof data} ${data && typeof data === 'object' ? '(object)' : '(text)'}</p>
</div>
</div>
`;
results.style.display = 'block';
results.scrollIntoView({ behavior: 'smooth' });
showToast('✅ Social ads generated successfully!', 'success');
} catch (error) {
console.error('Error displaying results:', error);
showToast('Generated content but failed to display properly', 'error');
adContent.innerHTML = `
<p>Content generated but display error occurred.</p>
<pre>${JSON.stringify(data, null, 2)}</pre>
`;
results.style.display = 'block';
}
}
// Demo results function (kept for demo button)
function showResults() {
const results = document.getElementById('adResults');
const adContent = document.getElementById('adContent');
adContent.innerHTML = `
<h2>🎯 Demo - Facebook Ad Campaign</h2>
<div class="key-points">
<h3>Primary Ad Copy</h3>
<p><strong>Headline:</strong> Transform Your Business with AI-Powered Solutions! 🚀</p>
<p><strong>Description:</strong> Discover cutting-edge technology that streamlines your workflow and boosts productivity by 300%. Join thousands of satisfied customers!</p>
<p><strong>Call to Action:</strong> Get Started Today!</p>
</div>
<div class="insights">
<h3>Instagram Story Version</h3>
<p>⚡ Ready to revolutionize your business?<br>
🎯 AI solutions that actually work<br>
📈 300% productivity boost<br>
👆 Swipe up to learn more!</p>
</div>
<div class="summary">
<h3>Platform Optimization Tips</h3>
<ol>
<li>Facebook: Focus on detailed descriptions and social proof</li>
<li>Instagram: Use visual storytelling and trending hashtags</li>
<li>LinkedIn: Emphasize professional benefits and ROI</li>
<li>Twitter: Keep it concise with powerful hashtags</li>
</ol>
</div>
`;
results.style.display = 'block';
results.scrollIntoView({ behavior: 'smooth' });
showToast('Demo results displayed!', 'success');
}
function hideResults() {
const results = document.getElementById('adResults');
results.style.display = 'none';
showToast('Results hidden', 'success');
}
// Copy and Download Functions
function copySocialAds() {
const adContent = document.getElementById('adContent');
const text = adContent.innerText || adContent.textContent || '';
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(() => {
showToast('📋 Social ads copied to clipboard!', 'success');
}).catch(() => {
showToast('Failed to copy content', 'error');
});
} else {
showToast('📋 Social ads copied to clipboard!', 'success');
}
}
function downloadSocialAds() {
const adContent = document.getElementById('adContent');
const text = adContent.innerText || adContent.textContent || '';
try {
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `social-ads-${Date.now()}.txt`;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
} catch (error) {
console.error('Download failed:', error);
}
}
function resetForm() {
document.getElementById('socialAdsForm').reset();
hideProcessing();
hideResults();
}
// Real form submission to N8N webhook
document.getElementById('socialAdsForm').addEventListener('submit', function(e) {
e.preventDefault();
const description = document.getElementById('description').value.trim();
const platform = document.getElementById('social_platform').value;
const emoji = document.getElementById('include_emoji').value;
const language = document.getElementById('language').value;
if (!description || !platform || !emoji) {
showToast('Please fill in all required fields', 'error');
return;
}
showProcessing();
// Format data for original N8N workflow structure
const sessionId = 'session_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
const messageText = `Create compelling social media ads for: ${description}. Target platform: ${platform}. Include emojis: ${emoji}. Language: ${language}. Make it engaging and professional.`;
const webhookData = {
sessionId: sessionId,
message: {
text: messageText
}
};
// Debug: Log the data being sent
console.log('Sending to N8N webhook:', webhookData);
// Call ORIGINAL N8N webhook
fetch('http://localhost:5678/webhook/2dc234d8-7217-454a-83e9-81afe5b4fe2d', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(webhookData),
// Add timeout and credentials if needed
signal: AbortSignal.timeout(60000) // 60 second timeout
})
.then(response => {
if (!response.ok) {
if (response.status === 404) {
throw new Error(`N8N webhook not found (404). Please check if the workflow is active.`);
} else if (response.status >= 500) {
throw new Error(`N8N server error (${response.status}). Please check N8N instance.`);
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
// Try to parse as JSON, fallback to text if that fails
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json().catch(() => response.text());
} else {
return response.text();
}
})
.then(data => {
hideProcessing();
displayRealResults(data);
})
.catch(error => {
console.error('N8N webhook error:', error);
hideProcessing();
// Enhanced error messages
if (error.name === 'TypeError' && error.message.includes('fetch')) {
showToast('❌ Connection failed. Please ensure N8N is running on localhost:5678', 'error');
} else if (error.name === 'TimeoutError') {
showToast('⏰ Request timed out. N8N might be processing large data.', 'error');
} else if (error.message.includes('CORS')) {
showToast('🔒 CORS error. N8N webhook may need CORS configuration.', 'error');
} else if (error.message.includes('404')) {
showToast('🔍 Webhook not found. Please check if N8N workflow is active.', 'error');
} else {
showToast(`❌ Error: ${error.message}`, 'error');
}
});
});
// Test N8N connection function
function testN8NConnection() {
showToast('Testing N8N connection...', 'info');
// Test data for original workflow structure
const testSessionId = 'test_session_' + Date.now();
const testData = {
body: {
sessionId: testSessionId,
message: {
text: "Connection test - please generate a sample social media ad to verify the workflow is working"
}
}
};
fetch('http://localhost:5678/webhook/2dc234d8-7217-454a-83e9-81afe5b4fe2d', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(testData),
signal: AbortSignal.timeout(10000) // 10 second timeout for test
})
.then(response => {
if (response.ok) {
showToast('✅ N8N connection successful!', 'success');
return response.text(); // Don't try to parse JSON for test
} else {
showToast(`❌ N8N responded with status: ${response.status}`, 'error');
}
})
.then(data => {
// Log the response for debugging but don't show to user
console.log('N8N test response:', data);
})
.catch(error => {
console.error('N8N connection test error:', error);
if (error.name === 'TypeError' && error.message.includes('fetch')) {
showToast('❌ Cannot connect to N8N. Is it running on localhost:5678?', 'error');
} else if (error.name === 'TimeoutError') {
showToast('⏰ Connection test timed out', 'error');
} else {
showToast(`❌ Connection test failed: ${error.message}`, 'error');
}
});
}
// Close panel on Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeQuickAgents();
}
});
// Initialize accessibility features
document.addEventListener('DOMContentLoaded', function() {
// Set initial ARIA states
const quickAgentsButton = document.querySelector('.quick-agent-toggle');
if (quickAgentsButton) {
quickAgentsButton.setAttribute('aria-expanded', 'false');
}
const panel = document.getElementById('quickAgentsPanel');
const overlay = document.getElementById('quickAgentsOverlay');
if (panel) panel.setAttribute('aria-hidden', 'true');
if (overlay) overlay.setAttribute('aria-hidden', 'true');
// Show welcome message
setTimeout(() => {
showToast('Social Ads Generator - Standalone N8N Integration ready!', 'success');
}, 500);
});
</script>
</body>
</html>