Spaces:
Sleeping
Sleeping
File size: 10,462 Bytes
a4a766c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | # api/webhooks.py
import uuid
import asyncio
import logging
from datetime import datetime
from fastapi import APIRouter, HTTPException, BackgroundTasks
from fastapi.responses import JSONResponse
from models.campaign import CampaignWebhook, CampaignData, CampaignOrchestrationState
from agents.orchestrator import CampaignOrchestrator
from services.voice import VoiceService
from config.settings import settings
logger = logging.getLogger(__name__)
webhook_router = APIRouter()
# Initialize orchestrator and voice service
orchestrator = CampaignOrchestrator()
voice_service = VoiceService()
@webhook_router.post("/campaign-created")
async def handle_campaign_created(
campaign_webhook: CampaignWebhook,
background_tasks: BackgroundTasks
):
"""
π― MAIN WEBHOOK ENDPOINT - Triggered when campaign is created
This kicks off the entire AI workflow:
Campaign β Discovery β ElevenLabs Calls β Results
"""
try:
# Generate unique task ID for tracking
task_id = str(uuid.uuid4())
logger.info(f"π Campaign webhook received: {campaign_webhook.product_name}")
# Convert webhook data to internal campaign format
campaign_data = CampaignData(
id=campaign_webhook.campaign_id,
product_name=campaign_webhook.product_name,
brand_name=campaign_webhook.brand_name,
product_description=campaign_webhook.product_description,
target_audience=campaign_webhook.target_audience,
campaign_goal=campaign_webhook.campaign_goal,
product_niche=campaign_webhook.product_niche,
total_budget=campaign_webhook.total_budget,
campaign_code=f"CAMP-{campaign_webhook.campaign_id[:8].upper()}"
)
# Initialize orchestration state
orchestration_state = CampaignOrchestrationState(
campaign_id=campaign_data.id,
campaign_data=campaign_data,
current_stage="webhook_received"
)
# Store in global state for monitoring
from main import active_campaigns
active_campaigns[task_id] = orchestration_state
# π₯ START THE AI WORKFLOW IN BACKGROUND
background_tasks.add_task(
orchestrator.orchestrate_campaign,
orchestration_state,
task_id
)
return JSONResponse(
status_code=202,
content={
"message": "π― AI campaign workflow started",
"task_id": task_id,
"campaign_id": campaign_data.id,
"brand_name": campaign_data.brand_name,
"product_name": campaign_data.product_name,
"estimated_duration_minutes": 5,
"monitor_url": f"/api/monitor/campaign/{task_id}",
"status": "started",
"next_steps": [
"Discovery phase: Finding matching creators",
"Negotiation phase: ElevenLabs phone calls",
"Results phase: Contract generation"
]
}
)
except Exception as e:
logger.error(f"β Webhook processing failed: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to start campaign workflow: {str(e)}"
)
@webhook_router.post("/test-campaign")
async def create_test_campaign(background_tasks: BackgroundTasks):
"""
π§ͺ Create a test campaign for demo purposes
This endpoint creates a realistic fitness campaign for testing
"""
test_campaign = CampaignWebhook(
campaign_id=str(uuid.uuid4()),
product_name="FitPro Protein Powder",
brand_name="FitLife Nutrition",
product_description="Premium whey protein powder for muscle building and recovery, perfect for fitness enthusiasts and athletes looking to maximize their workout results",
target_audience="Fitness enthusiasts, gym-goers, and athletes aged 18-35 who are serious about their workout routine and nutrition goals",
campaign_goal="Increase brand awareness and drive sales in the fitness community through authentic creator partnerships",
product_niche="fitness",
total_budget=15000.0
)
logger.info("π§ͺ Test campaign created for demo")
return await handle_campaign_created(test_campaign, background_tasks)
@webhook_router.post("/test-tech-campaign")
async def create_test_tech_campaign(background_tasks: BackgroundTasks):
"""π§ͺ Create a tech campaign for testing different niches"""
test_campaign = CampaignWebhook(
campaign_id=str(uuid.uuid4()),
product_name="TechPro Wireless Earbuds",
brand_name="AudioMax",
product_description="High-quality wireless earbuds with noise cancellation and superior sound quality for tech enthusiasts",
target_audience="Tech enthusiasts, gamers, and professionals aged 20-40",
campaign_goal="Launch new product and establish market presence",
product_niche="tech",
total_budget=12000.0
)
return await handle_campaign_created(test_campaign, background_tasks)
@webhook_router.get("/test-elevenlabs")
async def test_elevenlabs_setup():
"""
π§ͺ Test ElevenLabs credentials and setup
"""
try:
# Test credentials
result = await voice_service.test_credentials()
return JSONResponse(
status_code=200 if result["status"] == "success" else 400,
content={
"elevenlabs_status": result,
"setup_instructions": {
"step_1": "Get API key from https://elevenlabs.io/app/settings/api-keys",
"step_2": "Create agent at https://elevenlabs.io/app/conversational-ai",
"step_3": "Set up phone number integration",
"step_4": "Add credentials to .env file",
"required_env_vars": [
"ELEVENLABS_API_KEY=sk_your_key_here",
"ELEVENLABS_AGENT_ID=your_agent_id_here",
"ELEVENLABS_PHONE_NUMBER_ID=your_phone_id_here"
]
},
"current_settings": {
"api_key_set": bool(settings.elevenlabs_api_key),
"agent_id_set": bool(settings.elevenlabs_agent_id),
"phone_number_id_set": bool(settings.elevenlabs_phone_number_id),
"mock_mode": voice_service.use_mock
}
}
)
except Exception as e:
logger.error(f"β ElevenLabs test failed: {e}")
return JSONResponse(
status_code=500,
content={
"error": str(e),
"message": "ElevenLabs test failed - check your setup"
}
)
@webhook_router.post("/test-call")
async def test_single_call():
"""
π§ͺ Test a single ElevenLabs call (for debugging)
"""
try:
# Mock creator profile for testing
test_creator = {
"id": "test_creator",
"name": "TestCreator",
"niche": "fitness",
"followers": 100000,
"engagement_rate": 5.2,
"average_views": 50000,
"location": "India",
"languages": ["English"],
"typical_rate": 3000
}
test_campaign_brief = """
Brand: TestBrand
Product: Test Product
Description: This is a test campaign to verify ElevenLabs integration
Target Audience: Test audience
Goal: Test the calling system
"""
# β
FIXED: Use your actual phone number (India)
# FROM: +1 320 383 8447 (Twilio US number)
# TO: +918806859890 (Your Indian number)
test_phone = "+918806859890" # Your actual phone number
logger.info(f"π§ͺ Initiating test call")
logger.info(f" FROM: +1 320 383 8447 (Twilio US)")
logger.info(f" TO: {test_phone} (Your phone)")
# Initiate call
call_result = await voice_service.initiate_negotiation_call(
creator_phone=test_phone,
creator_profile=test_creator,
campaign_brief=test_campaign_brief,
price_range="2000-4000"
)
return JSONResponse(
status_code=200,
content={
"test_call_result": call_result,
"message": f"Test call initiated! Check your phone {test_phone}",
"call_flow": {
"from_number": "+1 320 383 8447 (Twilio US)",
"to_number": test_phone,
"expected": "Your phone should ring in a few seconds"
},
"troubleshooting": {
"if_no_ring": "Check Twilio console logs",
"if_call_fails": "Verify ElevenLabs agent configuration",
"international_calls": "Ensure Twilio account can make international calls to India"
}
}
)
except Exception as e:
logger.error(f"β Test call failed: {e}")
return JSONResponse(
status_code=500,
content={
"error": str(e),
"message": "Test call failed"
}
)
@webhook_router.get("/status")
async def webhook_status():
"""π Get webhook service status"""
return {
"service": "InfluencerFlow Webhook Handler",
"status": "healthy",
"version": "2.0.0",
"endpoints": {
"campaign_created": "/api/webhook/campaign-created",
"test_campaign": "/api/webhook/test-campaign",
"test_tech_campaign": "/api/webhook/test-tech-campaign",
"test_elevenlabs": "/api/webhook/test-elevenlabs",
"test_call": "/api/webhook/test-call"
},
"capabilities": [
"Campaign workflow orchestration",
"ElevenLabs phone call integration",
"Real-time progress monitoring",
"Multi-niche creator matching"
],
"integrations": {
"groq_ai": bool(settings.groq_api_key),
"elevenlabs": bool(settings.elevenlabs_api_key),
"mock_mode": voice_service.use_mock
}
} |