184 lines
5.5 KiB
TypeScript
184 lines
5.5 KiB
TypeScript
import { WorkflowBase, WorkflowContext, WorkflowResult } from './workflow-base';
|
|
import { WorkflowType } from '@prisma/client';
|
|
import { FacebookAdsExpert } from '../integrations/claude/skills/facebook-ads-expert';
|
|
import { GoogleAdsExpert } from '../integrations/claude/skills/google-ads-expert';
|
|
import { FacebookAdsAPI } from '../integrations/ads/facebook-ads';
|
|
import { GoogleAdsAPI } from '../integrations/ads/google-ads';
|
|
import { log } from '../monitoring/logger';
|
|
import { integrations } from '../utils/config';
|
|
|
|
export class PaidAdsWorkflow extends WorkflowBase {
|
|
protected type: WorkflowType = 'PAID_ADS';
|
|
private fbExpert: FacebookAdsExpert;
|
|
private googleExpert: GoogleAdsExpert;
|
|
private fbAds: FacebookAdsAPI;
|
|
private googleAds: GoogleAdsAPI;
|
|
|
|
constructor(db: any, alerts: any) {
|
|
super(db, alerts);
|
|
this.fbExpert = new FacebookAdsExpert();
|
|
this.googleExpert = new GoogleAdsExpert();
|
|
this.fbAds = new FacebookAdsAPI();
|
|
this.googleAds = new GoogleAdsAPI();
|
|
}
|
|
|
|
protected async execute(context: WorkflowContext): Promise<WorkflowResult> {
|
|
const business = await this.getBusiness(context.businessId);
|
|
|
|
log.info('Starting paid ads campaigns', { businessId: context.businessId });
|
|
|
|
const results: any = {
|
|
facebook: null,
|
|
google: null,
|
|
};
|
|
|
|
try {
|
|
// Step 1: Create Facebook Ads campaign
|
|
if (integrations.hasFacebookAds()) {
|
|
results.facebook = await this.createFacebookCampaign(business);
|
|
log.info('Facebook campaign created', { businessId: context.businessId });
|
|
} else {
|
|
log.warn('Facebook Ads not configured - skipping', {
|
|
businessId: context.businessId,
|
|
});
|
|
}
|
|
|
|
// Step 2: Create Google Ads campaign
|
|
if (integrations.hasGoogleAds()) {
|
|
results.google = await this.createGoogleCampaign(business);
|
|
log.info('Google Ads campaign created', { businessId: context.businessId });
|
|
} else {
|
|
log.warn('Google Ads not configured - skipping', {
|
|
businessId: context.businessId,
|
|
});
|
|
}
|
|
|
|
// Step 3: Update business status
|
|
await this.db.business.update({
|
|
where: { id: context.businessId },
|
|
data: {
|
|
adsActive: true,
|
|
status: 'RUNNING_ADS',
|
|
},
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: results,
|
|
};
|
|
} catch (error) {
|
|
log.error('Paid ads workflow failed', error, { businessId: context.businessId });
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
|
|
private async createFacebookCampaign(business: any): Promise<any> {
|
|
try {
|
|
// Get campaign strategy from Claude
|
|
const strategy = await this.fbExpert.generateCampaignStrategy({
|
|
businessName: business.name,
|
|
businessIdea: business.idea,
|
|
budget: business.budget || 500,
|
|
targetAudience: business.targetAudience || 'general',
|
|
goal: 'CONVERSIONS',
|
|
});
|
|
|
|
// Create campaign via Facebook Ads API
|
|
const campaign = await this.fbAds.createCampaign({
|
|
name: `${business.name} - Conversions`,
|
|
objective: 'CONVERSIONS',
|
|
budget: business.budget || 500,
|
|
targeting: {
|
|
age_min: 25,
|
|
age_max: 65,
|
|
interests: [],
|
|
},
|
|
});
|
|
|
|
// Save campaign to database
|
|
await this.db.campaign.create({
|
|
data: {
|
|
businessId: business.id,
|
|
platform: 'FACEBOOK',
|
|
campaignId: campaign.id,
|
|
name: campaign.name,
|
|
budget: business.budget || 500,
|
|
dailyBudget: (business.budget || 500) / 30,
|
|
active: true,
|
|
targeting: campaign.targeting || {},
|
|
},
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
campaignId: campaign.id,
|
|
strategy: strategy.output,
|
|
};
|
|
} catch (error) {
|
|
log.error('Facebook campaign creation failed', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
|
|
private async createGoogleCampaign(business: any): Promise<any> {
|
|
try {
|
|
// Get campaign strategy from Claude
|
|
const strategy = await this.googleExpert.generateCampaignStrategy({
|
|
businessName: business.name,
|
|
businessIdea: business.idea,
|
|
budget: business.budget || 500,
|
|
targetKeywords: this.extractKeywords(business.idea),
|
|
campaignType: 'SEARCH',
|
|
});
|
|
|
|
// Create campaign via Google Ads API
|
|
const campaign = await this.googleAds.createCampaign({
|
|
name: `${business.name} - Search`,
|
|
type: 'SEARCH',
|
|
budget: business.budget || 500,
|
|
keywords: this.extractKeywords(business.idea),
|
|
});
|
|
|
|
// Save campaign to database
|
|
await this.db.campaign.create({
|
|
data: {
|
|
businessId: business.id,
|
|
platform: 'GOOGLE',
|
|
campaignId: campaign.id,
|
|
name: campaign.name,
|
|
budget: business.budget || 500,
|
|
dailyBudget: (business.budget || 500) / 30,
|
|
active: true,
|
|
},
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
campaignId: campaign.id,
|
|
strategy: strategy.output,
|
|
};
|
|
} catch (error) {
|
|
log.error('Google Ads campaign creation failed', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
|
|
private extractKeywords(text: string): string[] {
|
|
return text
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9\s]/g, '')
|
|
.split(/\s+/)
|
|
.filter((w) => w.length > 3)
|
|
.slice(0, 20);
|
|
}
|
|
}
|