feat: add AI Instruction Enhancer and improve comprehensive data export

This commit is contained in:
Gemini AI
2025-12-29 16:13:12 +04:00
Unverified
parent e6424f2b10
commit 10eb12648d
2 changed files with 108 additions and 88 deletions

View File

@@ -50,6 +50,7 @@ export default function GoogleAdsGenerator() {
const [expandedSections, setExpandedSections] = useState<string[]>(["keywords"]); const [expandedSections, setExpandedSections] = useState<string[]>(["keywords"]);
const [isMagicThinking, setIsMagicThinking] = useState(false); const [isMagicThinking, setIsMagicThinking] = useState(false);
const [isEnhancing, setIsEnhancing] = useState(false);
const [progressMessage, setProgressMessage] = useState(""); const [progressMessage, setProgressMessage] = useState("");
const [progressIndex, setProgressIndex] = useState(0); const [progressIndex, setProgressIndex] = useState(0);
@@ -296,6 +297,32 @@ export default function GoogleAdsGenerator() {
} }
}; };
const handleEnhanceInstructions = async () => {
if (!specialInstructions.trim()) return;
setIsEnhancing(true);
setError(null);
try {
const result = await modelAdapter.enhancePrompt(
specialInstructions,
selectedProvider,
selectedModel
);
if (result.success && result.data) {
setSpecialInstructions(result.data);
} else {
setError(result.error || "Failed to enhance instructions");
}
} catch (err) {
console.error("[GoogleAdsGenerator] Enhancement error:", err);
setError(err instanceof Error ? err.message : "Instruction enhancement failed");
} finally {
setIsEnhancing(false);
}
};
const handleCopy = async () => { const handleCopy = async () => {
const content = googleAdsResult?.rawContent || magicWandResult?.rawContent; const content = googleAdsResult?.rawContent || magicWandResult?.rawContent;
if (content) { if (content) {
@@ -1017,7 +1044,23 @@ export default function GoogleAdsGenerator() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-xs lg:text-sm font-medium">{t.specialInstructions}</label> <div className="flex items-center justify-between">
<label className="text-xs lg:text-sm font-medium">{t.specialInstructions}</label>
<Button
variant="ghost"
size="sm"
className="h-6 px-2 text-[10px] font-black uppercase tracking-widest text-indigo-600 hover:text-indigo-700 hover:bg-indigo-50 gap-1.5 transition-all"
onClick={handleEnhanceInstructions}
disabled={isEnhancing || !specialInstructions.trim()}
>
{isEnhancing ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : (
<Wand2 className="h-3 w-3" />
)}
AI Instructions enhancer
</Button>
</div>
<Textarea <Textarea
placeholder={t.specialInstructionsPlaceholder} placeholder={t.specialInstructionsPlaceholder}
value={specialInstructions} value={specialInstructions}

View File

@@ -19,151 +19,128 @@ export const generateGoogleAdsCSV = (googleAds?: any, magic?: any): string => {
if (googleAds) { if (googleAds) {
rows.push(["GOOGLE ADS STRATEGY REPORT"]); rows.push(["GOOGLE ADS STRATEGY REPORT"]);
rows.push(["Generated at", new Date().toLocaleString()]); rows.push(["Generated at", new Date().toLocaleString()]);
rows.push(["Website", googleAds.websiteUrl || 'N/A']);
rows.push([]); rows.push([]);
const kw = googleAds.keywords; const kw = googleAds.keywords;
if (kw) { if (kw) {
rows.push(["--- KEYWORD RESEARCH ---"]); rows.push(["KEYWORD RESEARCH"]);
rows.push(["Type", "Keyword", "CPC"]); rows.push(["Type", "Keyword", "CPC"]);
if (Array.isArray(kw.primary)) kw.primary.forEach((k: any) => rows.push(["Primary", k.keyword, k.cpc || 'N/A'])); if (Array.isArray(kw.primary)) kw.primary.forEach((k: any) => rows.push(["Primary", String(k?.keyword || ''), String(k?.cpc || '')]));
if (Array.isArray(kw.longTail)) kw.longTail.forEach((k: any) => rows.push(["Long-tail", k.keyword, k.cpc || 'N/A'])); if (Array.isArray(kw.longTail)) kw.longTail.forEach((k: any) => rows.push(["Long-tail", String(k?.keyword || ''), String(k?.cpc || '')]));
if (Array.isArray(kw.negative)) kw.negative.forEach((k: any) => rows.push(["Negative", k.keyword, k.cpc || 'N/A'])); if (Array.isArray(kw.negative)) kw.negative.forEach((k: any) => rows.push(["Negative", String(k?.keyword || ''), String(k?.cpc || '')]));
rows.push([]); rows.push([]);
} }
const ads = googleAds.adCopies; const ads = googleAds.adCopies;
if (Array.isArray(ads)) { if (Array.isArray(ads)) {
rows.push(["--- AD COPY VARIATIONS ---"]); rows.push(["AD COPIES"]);
rows.push(["Variation", "Headlines", "Descriptions", "CTA"]); rows.push(["Variation", "Headlines", "Descriptions", "CTA"]);
ads.forEach((ad: any, i: number) => { ads.forEach((ad: any, i: number) => {
const hl = Array.isArray(ad.headlines) ? ad.headlines.join(' | ') : ''; const hl = Array.isArray(ad.headlines) ? ad.headlines.join(' | ') : '';
const ds = Array.isArray(ad.descriptions) ? ad.descriptions.join(' | ') : ''; const ds = Array.isArray(ad.descriptions) ? ad.descriptions.join(' | ') : '';
rows.push([`Variation ${i + 1}`, hl, ds, ad.callToAction || '']); rows.push([`Var ${i + 1}`, hl, ds, String(ad?.callToAction || '')]);
}); });
rows.push([]); rows.push([]);
} }
const camps = googleAds.campaigns; const camps = googleAds.campaigns;
if (Array.isArray(camps)) { if (Array.isArray(camps)) {
rows.push(["--- CAMPAIGN STRUCTURE ---"]); rows.push(["CAMPAIGN STRUCTURE"]);
rows.push(["Name", "Type", "Daily Budget", "Locations", "Schedule"]); rows.push(["Name", "Type", "Budget", "Locations", "Schedule"]);
camps.forEach((c: any) => { camps.forEach((c: any) => {
const targeting = c.targeting; const t = c.targeting;
const locs = (targeting && Array.isArray(targeting.locations)) ? targeting.locations.join('; ') : 'All'; const locs = (t && Array.isArray(t.locations)) ? t.locations.join('; ') : 'All';
const sched = (targeting && Array.isArray(targeting.schedule)) ? targeting.schedule.join('; ') : 'All'; const sched = (t && Array.isArray(t.schedule)) ? t.schedule.join('; ') : 'All';
rows.push([ rows.push([String(c.name || ''), String(c.type || ''), `${c?.budget?.daily || 0} ${c?.budget?.currency || ''}`, locs, sched]);
c.name || 'Campaign',
c.type || 'Search',
`${c.budget?.daily || 0} ${c.budget?.currency || 'USD'}`,
locs,
sched
]);
}); });
rows.push([]); rows.push([]);
} }
const impl = googleAds.implementation;
if (impl) {
rows.push(["IMPLEMENTATION"]);
if (Array.isArray(impl.setupSteps)) impl.setupSteps.forEach((s: any) => rows.push(["Setup", String(s)]));
if (Array.isArray(impl.qualityScoreTips)) impl.qualityScoreTips.forEach((s: any) => rows.push(["QS Tip", String(s)]));
rows.push([]);
}
} }
if (magic) { if (magic) {
rows.push(["--- MARKET INTELLIGENCE ---"]); rows.push(["MARKET INTELLIGENCE"]);
const ma = magic.marketAnalysis; const ma = magic.marketAnalysis;
if (ma) { if (ma) {
rows.push(["Growth Rate", ma.growthRate || 'N/A']); rows.push(["Size", String(ma.industrySize || '')]);
const comps = ma.topCompetitors; rows.push(["Growth", String(ma.growthRate || '')]);
rows.push(["Top Competitors", Array.isArray(comps) ? comps.join('; ') : 'N/A']); rows.push(["Trends", Array.isArray(ma.marketTrends) ? ma.marketTrends.join('; ') : '']);
const trends = ma.marketTrends; rows.push(["Competitors", Array.isArray(ma.topCompetitors) ? ma.topCompetitors.join('; ') : '']);
rows.push(["Market Trends", Array.isArray(trends) ? trends.join('; ') : 'N/A']); rows.push([]);
} }
const rationale = magic.rationale;
if (rationale) { const strats = magic.strategies;
rows.push(["Strategy Rationale", rationale]); if (Array.isArray(strats)) {
rows.push(["STRATEGIES"]);
strats.forEach((s: any) => {
rows.push(["Direction", String(s.direction || '')]);
rows.push(["Target", String(s.targetAudience || '')]);
rows.push(["Rationale", String(s.rationale || '')]);
rows.push(["ROI", String(s.expectedROI || '')]);
rows.push([]);
});
} }
} }
return rows.map(row => row.map(cell => `"${String(cell || '').replace(/"/g, '""')}"`).join(",")).join("\n"); return rows.map(r => r.map(c => `"${String(c || '').replace(/"/g, '""')}"`).join(",")).join("\n");
}; };
export const generateGoogleAdsHTML = (googleAds?: any, magic?: any): string => { export const generateGoogleAdsHTML = (googleAds?: any, magic?: any): string => {
const parts: string[] = []; const parts: string[] = [];
parts.push(`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Ads Report</title>`); parts.push(`<!DOCTYPE html><html><head><title>Report</title><style>
parts.push(`<style> body { font-family: sans-serif; background: #0f172a; color: #e2e8f0; padding: 40px; }
:root { --bg: #0f172a; --card: #1e293b; --text: #e2e8f0; --accent: #6366f1; } .section { background: #1e293b; border-radius: 12px; padding: 24px; margin-bottom: 24px; border: 1px solid rgba(255,255,255,0.1); }
body { font-family: system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; padding: 40px; margin: 0; } h1 { color: #818cf8; }
.container { max-width: 1000px; margin: 0 auto; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.section { background: var(--card); border-radius: 16px; padding: 32px; margin-bottom: 32px; border: 1px solid rgba(255,255,255,0.1); } .card { background: rgba(0,0,0,0.2); padding: 16px; border-radius: 8px; }
h1 { font-size: 2.5rem; background: linear-gradient(to right, #818cf8, #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin: 0 0 1rem 0; } </style></head><body>`);
h2 { font-size: 1.25rem; color: #818cf8; margin-top: 0; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 12px; }
.tag { display: inline-block; background: rgba(99,102,241,0.15); border: 1px solid rgba(99,102,241,0.3); color: #c3dafe; padding: 6px 14px; border-radius: 99px; font-size: 0.85rem; margin: 0 8px 8px 0; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.card { background: rgba(0,0,0,0.2); padding: 20px; border-radius: 12px; border: 1px solid rgba(255,255,255,0.05); }
.metric { font-size: 1.5rem; font-weight: 700; color: #4ade80; }
.label { font-size: 0.75rem; text-transform: uppercase; color: #94a3b8; font-weight: 600; }
</style></head><body><div class="container">`);
parts.push(`<h1>Google Ads Strategy Report</h1><p style="color:#94a3b8; margin-bottom: 40px">Generated on ${new Date().toLocaleDateString()}</p>`); parts.push(`<h1>Marketing Strategy</h1>`);
if (googleAds) { if (googleAds) {
parts.push(`<div class="section"><h2>🎯 Keyword Intelligence</h2>`); parts.push(`<div class="section"><h2>Keywords</h2>`);
const kw = googleAds.keywords; const kw = googleAds.keywords;
if (kw) { if (kw && Array.isArray(kw.primary)) {
const primary = kw.primary; parts.push(`<h3>Primary</h3>`);
if (Array.isArray(primary)) { kw.primary.forEach((k: any) => parts.push(`<span>${k.keyword}</span> `));
parts.push(`<div style="margin-bottom:20px"><div class="label">Primary Keywords</div>`);
primary.forEach((k: any) => parts.push(`<span class="tag">${k.keyword} <small>(${k.cpc || 'N/A'})</small></span>`));
parts.push(`</div>`);
}
const longTail = kw.longTail;
if (Array.isArray(longTail)) {
parts.push(`<div style="margin-bottom:20px"><div class="label">Long-tail Opportunities</div>`);
longTail.forEach((k: any) => parts.push(`<span class="tag">${k.keyword}</span>`));
parts.push(`</div>`);
}
} }
parts.push(`</div>`); parts.push(`</div>`);
const ads = googleAds.adCopies; const ads = googleAds.adCopies;
if (Array.isArray(ads)) { if (Array.isArray(ads)) {
parts.push(`<div class="section"><h2>✍️ Ad Copy Variations</h2><div class="grid">`); parts.push(`<div class="section"><h2>Ads</h2><div class="grid">`);
ads.forEach((ad: any, i: number) => { ads.forEach((ad: any) => {
parts.push(`<div class="card"><div class="label">Variation ${i + 1}</div>`); parts.push(`<div class="card"><b>${(ad.headlines || [])[0] || ''}</b><p>${(ad.descriptions || [])[0] || ''}</p></div>`);
const headlines = ad.headlines;
if (Array.isArray(headlines)) headlines.forEach(h => parts.push(`<div style="font-weight:700; color:#f1f5f9; margin-top:4px">${h}</div>`));
const descriptions = ad.descriptions;
if (Array.isArray(descriptions)) descriptions.forEach(d => parts.push(`<div style="margin-top:12px; font-size:0.9rem; color:#cbd5e1">${d}</div>`));
if (ad.callToAction) parts.push(`<div style="margin-top:16px; font-weight:700; color:#818cf8">${ad.callToAction}</div>`);
parts.push(`</div>`);
});
parts.push(`</div></div>`);
}
const camps = googleAds.campaigns;
if (Array.isArray(camps)) {
parts.push(`<div class="section"><h2>🏗️ Campaign Architecture</h2><div class="grid">`);
camps.forEach((c: any) => {
parts.push(`<div class="card"><b>${c.name || 'Campaign'}</b><br><small>${c.type || 'Search'}</small>`);
parts.push(`<div style="margin-top:10px; color:#4ade80; font-weight:bold">${c.budget?.daily || 0} ${c.budget?.currency || 'USD'}/day</div></div>`);
}); });
parts.push(`</div></div>`); parts.push(`</div></div>`);
} }
} }
if (magic) { if (magic) {
parts.push(`<div class="section"><h2>🧠 Market Intelligence</h2>`); parts.push(`<div class="section"><h2>Market</h2>`);
const ma = magic.marketAnalysis; const ma = magic.marketAnalysis;
if (ma) { if (ma) {
parts.push(`<p><b>Market Growth:</b> ${ma.growthRate || 'Stable'}</p>`); parts.push(`<p>Size: ${ma.industrySize || 'N/A'}</p>`);
const comps = ma.topCompetitors; parts.push(`<p>Growth: ${ma.growthRate || 'N/A'}</p>`);
if (Array.isArray(comps)) {
parts.push(`<div class="label">Key Competitors</div>`);
comps.forEach(c => parts.push(`<div style="margin:4px 0">${c}</div>`));
}
} }
const rationale = magic.rationale; const strats = magic.strategies;
if (rationale) { if (Array.isArray(strats)) {
parts.push(`<div style="margin-top:20px"><b>Strategy:</b><p>${rationale}</p></div>`); parts.push(`<h2>Strategies</h2>`);
strats.forEach((s: any) => {
parts.push(`<div class="card"><h3>${s.direction}</h3><p>${s.rationale}</p></div>`);
});
} }
parts.push(`</div>`); parts.push(`</div>`);
} }
parts.push(`</div></body></html>`); parts.push(`</body></html>`);
return parts.join(''); return parts.join('');
}; };