feat: content generation UI, test script, and API docs
This commit is contained in:
172
src/pages/admin/content-generator.astro
Normal file
172
src/pages/admin/content-generator.astro
Normal file
@@ -0,0 +1,172 @@
|
||||
---
|
||||
import AdminLayout from '../../../layouts/AdminLayout.astro';
|
||||
import PageHeader from '../../../components/admin/PageHeader.astro';
|
||||
---
|
||||
|
||||
<AdminLayout title="Content Generator">
|
||||
<div class="space-y-8">
|
||||
<PageHeader
|
||||
icon="🎯"
|
||||
title="Content Generation Engine"
|
||||
description="Submit JSON blueprints to generate full 2000-word articles with spintax"
|
||||
/>
|
||||
|
||||
<!-- Campaign Input -->
|
||||
<div class="bg-titanium border border-edge-normal rounded-xl p-8">
|
||||
<h2 class="text-2xl font-bold text-gold-500 mb-6">📝 Submit Campaign Blueprint</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
||||
Campaign Name (Optional)
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="campaignName"
|
||||
class="w-full bg-obsidian border border-edge-subtle rounded-lg px-4 py-3 text-white focus:border-gold-500 focus:outline-none"
|
||||
placeholder="e.g., Solar California Campaign"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">
|
||||
JSON Blueprint
|
||||
</label>
|
||||
<textarea
|
||||
id="blueprintJson"
|
||||
rows="16"
|
||||
class="w-full bg-obsidian border border-edge-subtle rounded-lg px-4 py-3 text-white font-mono text-sm focus:border-gold-500 focus:outline-none"
|
||||
placeholder='Paste your JSON blueprint here...'
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-4">
|
||||
<button
|
||||
id="createCampaign"
|
||||
class="px-6 py-3 bg-gold-500 hover:bg-gold-600 text-obsidian font-semibold rounded-lg transition-all"
|
||||
>
|
||||
Create Campaign
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="loadExample"
|
||||
class="px-6 py-3 bg-gray-700 hover:bg-gray-600 text-white font-semibold rounded-lg transition-all"
|
||||
>
|
||||
Load Example
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Active Campaigns -->
|
||||
<div class="bg-titanium border border-edge-normal rounded-xl p-8">
|
||||
<h2 class="text-2xl font-bold text-gold-500 mb-6">⚡ Active Campaigns</h2>
|
||||
<div id="campaignsList" class="space-y-4">
|
||||
<p class="text-gray-400">No campaigns yet. Create one above.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generated Content Stats -->
|
||||
<div class="bg-titanium border border-edge-normal rounded-xl p-8">
|
||||
<h2 class="text-2xl font-bold text-gold-500 mb-6">📊 Generation Stats</h2>
|
||||
<div id="statsContainer" class="grid grid-cols-4 gap-4">
|
||||
<div class="bg-obsidian rounded-lg p-4 border border-edge-subtle">
|
||||
<div class="text-sm text-gray-400 mb-1">Total Campaigns</div>
|
||||
<div id="statCampaigns" class="text-3xl font-bold text-gold-500">0</div>
|
||||
</div>
|
||||
<div class="bg-obsidian rounded-lg p-4 border border-edge-subtle">
|
||||
<div class="text-sm text-gray-400 mb-1">Posts Created</div>
|
||||
<div id="statPosts" class="text-3xl font-bold text-blue-400">0</div>
|
||||
</div>
|
||||
<div class="bg-obsidian rounded-lg p-4 border border-edge-subtle">
|
||||
<div class="text-sm text-gray-400 mb-1">Blocks Used</div>
|
||||
<div id="statBlocks" class="text-3xl font-bold text-green-400">0</div>
|
||||
</div>
|
||||
<div class="bg-obsidian rounded-lg p-4 border border-edge-subtle">
|
||||
<div class="text-sm text-gray-400 mb-1">Variations</div>
|
||||
<div id="statVariations" class="text-3xl font-bold text-purple-400">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
|
||||
<script>
|
||||
const exampleBlueprint = {
|
||||
"asset_name": "{{CITY}} Solar Revenue Accelerator",
|
||||
"deployment_target": "High-Value Residential Solar Funnel",
|
||||
"variables": {
|
||||
"STATE": "California",
|
||||
"COUNTY": "San Diego County|Orange County",
|
||||
"CITY": "San Diego|Irvine|Anaheim",
|
||||
"LANDMARK": "Del Mar Heights|Saddleback Peak|Balboa Island",
|
||||
"AVATAR_A": "Solar CEO",
|
||||
"AVATAR_B": "Lead Installer",
|
||||
"AVATAR_C": "Sales Manager"
|
||||
},
|
||||
"content": {
|
||||
"url_path": "{{CITY}}.solarinstall.com/revenue-engine",
|
||||
"meta_description": "{Stop|Eliminate} lead waste. We install conversion infrastructure for Solar CEOs in {{CITY}}.",
|
||||
"body": [
|
||||
{
|
||||
"block_type": "Hero (1)",
|
||||
"content": "<h1>Why {{CITY}} Solar Firms {Lose|Burn} $4K Per Job</h1><p>{The Data is clear|The reality is harsh}: If you operate in {{CITY}}, you are paying for the highest CPL in {the industry|your sector}.</p>"
|
||||
},
|
||||
{
|
||||
"block_type": "Agitation (2)",
|
||||
"content": "<h2>{{AVATAR_A}}s: Friction is Rejection in the {{STATE}} Market</h2><p>In the {luxury|high-demand} market of {{CITY}}, **friction is rejection**.</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('loadExample')?.addEventListener('click', () => {
|
||||
const textarea = document.getElementById('blueprintJson') as HTMLTextAreaElement;
|
||||
if (textarea) {
|
||||
textarea.value = JSON.stringify(exampleBlueprint, null, 2);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('createCampaign')?.addEventListener('click', async () => {
|
||||
const nameInput = document.getElementById('campaignName') as HTMLInputElement;
|
||||
const jsonInput = document.getElementById('blueprintJson') as HTMLTextAreaElement;
|
||||
|
||||
try {
|
||||
const blueprint = JSON.parse(jsonInput.value);
|
||||
const name = nameInput.value || undefined;
|
||||
|
||||
const response = await fetch('/api/god/campaigns/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-God-Token': localStorage.getItem('god_token') || ''
|
||||
},
|
||||
body: JSON.stringify({ name, blueprint })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
alert(`✅ Campaign created! ID: ${result.campaignId}`);
|
||||
jsonInput.value = '';
|
||||
nameInput.value = '';
|
||||
loadCampaigns();
|
||||
} else {
|
||||
alert(`❌ Error: ${result.error}`);
|
||||
}
|
||||
} catch (err: any) {
|
||||
alert(`❌ Invalid JSON: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
async function loadCampaigns() {
|
||||
// This would fetch from an API - for now just placeholder
|
||||
const list = document.getElementById('campaignsList');
|
||||
if (list) {
|
||||
list.innerHTML = '<p class="text-gray-400">Loading campaigns...</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Load stats on page load
|
||||
loadCampaigns();
|
||||
</script>
|
||||
Reference in New Issue
Block a user