fix: pivot to pure A2A only, remove social scraper
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 7s
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 7s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { fetchRecentNostrLeads } from '@/lib/social-scraper/nostr-scraper';
|
||||
import { ANPDiscoveryNode } from '@/lib/a2a-broadcasters/dht-discovery';
|
||||
import { GoogleGenerativeAI } from '@google/generative-ai';
|
||||
import axios from 'axios';
|
||||
|
||||
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');
|
||||
|
||||
@@ -11,59 +12,76 @@ export async function GET(request: Request) {
|
||||
return new NextResponse('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
console.log("[Lead Gen] Starting Autonomous Social Scraper...");
|
||||
console.log("[A2A Lead Gen] Starting Pure A2A Agent Discovery...");
|
||||
|
||||
try {
|
||||
// 1. Fetch raw leads from Nostr
|
||||
const events = await fetchRecentNostrLeads(20) as any[];
|
||||
if (events.length === 0) {
|
||||
return NextResponse.json({ status: "No new events found" });
|
||||
// 1. Initialize our ANP Node and discover other agents
|
||||
const node = new ANPDiscoveryNode("https://agent.wooo.work/.well-known/agent-card.json");
|
||||
await node.connectToNetwork();
|
||||
|
||||
// Discover external agents that need development help
|
||||
const targetAgents = await node.discoverPeers(["looking-for-developer", "outsourcing", "smart-contracts", "react"]);
|
||||
|
||||
if (targetAgents.length === 0) {
|
||||
return NextResponse.json({ status: "No target agents found in DHT." });
|
||||
}
|
||||
|
||||
// 2. Filter and Analyze intents using Gemini
|
||||
console.log(`[A2A Lead Gen] Discovered ${targetAgents.length} potential agents. Analyzing their Agent Cards...`);
|
||||
const leads = [];
|
||||
|
||||
// 2. Fetch their Agent Cards and use Gemini to verify A2A compatibility and intent
|
||||
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
|
||||
|
||||
const analysisPrompt = `
|
||||
You are an AI Lead Generation Agent.
|
||||
Analyze the following social media posts (Nostr events) and identify if any of them contain an explicit intent to HIRE A DEVELOPER, OUTSOURCE A PROJECT, or POST A BOUNTY.
|
||||
|
||||
Events:
|
||||
${JSON.stringify(events.map(e => ({ id: e.id, content: e.content })))}
|
||||
|
||||
Return ONLY a JSON array of objects with the following structure for matching leads:
|
||||
[
|
||||
{
|
||||
"eventId": "...",
|
||||
"intentScore": 0.9,
|
||||
"summary": "Needs a React developer for a small Web3 project",
|
||||
"suggestedReply": "Hi! Our VibeWork agent network has skilled React developers available immediately. Check out agent.wooo.work to post your bounty automatically!"
|
||||
|
||||
for (const agent of targetAgents) {
|
||||
try {
|
||||
const { data: agentCard } = await axios.get(agent.agentCardUrl);
|
||||
|
||||
const analysisPrompt = `
|
||||
You are an A2A (Agent-to-Agent) Negotiator.
|
||||
Analyze this Agent Card from another AI. Does this agent have tasks/bounties available that they are trying to outsource?
|
||||
|
||||
Agent Card:
|
||||
${JSON.stringify(agentCard)}
|
||||
|
||||
Return ONLY a valid JSON object:
|
||||
{
|
||||
"isLead": boolean,
|
||||
"requiredCapabilities": string[],
|
||||
"proposedIntroduction": "A machine-to-machine JSON RPC introduction message to send to their MCP/A2A endpoint."
|
||||
}
|
||||
`;
|
||||
|
||||
const result = await model.generateContent(analysisPrompt);
|
||||
const responseText = result.response.text();
|
||||
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
|
||||
|
||||
if (jsonMatch) {
|
||||
const analysis = JSON.parse(jsonMatch[0]);
|
||||
if (analysis.isLead) {
|
||||
leads.push({
|
||||
nodeId: agent.nodeId,
|
||||
agentCardUrl: agent.agentCardUrl,
|
||||
capabilities: analysis.requiredCapabilities,
|
||||
introduction: analysis.proposedIntroduction
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
If no events match, return an empty array [].
|
||||
`;
|
||||
} catch (err) {
|
||||
console.warn(`[A2A Lead Gen] Failed to fetch or analyze Agent Card for ${agent.nodeId}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[Lead Gen] Analyzing intents via Gemini...");
|
||||
const result = await model.generateContent(analysisPrompt);
|
||||
const responseText = result.response.text();
|
||||
|
||||
// Extract JSON from response
|
||||
const jsonMatch = responseText.match(/\[[\s\S]*\]/);
|
||||
const leads = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
|
||||
console.log(`[A2A Lead Gen] Found ${leads.length} pure A2A leads.`);
|
||||
|
||||
console.log(`[Lead Gen] Found ${leads.length} high-intent leads.`);
|
||||
|
||||
// 3. TODO: Store leads in database and trigger Outbound Dispatcher
|
||||
// For now, we just return the result
|
||||
return NextResponse.json({
|
||||
status: "Success",
|
||||
eventsAnalyzed: events.length,
|
||||
leadsIdentified: leads.length,
|
||||
agentsDiscovered: targetAgents.length,
|
||||
pureA2ALeads: leads.length,
|
||||
leads: leads
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("[Lead Gen] Error:", error);
|
||||
console.error("[A2A Lead Gen] Error:", error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { Relay } from 'nostr-tools';
|
||||
|
||||
export async function fetchRecentNostrLeads(limit: number = 20) {
|
||||
console.log(`[Nostr Scraper] Fetching recent leads from Nostr...`);
|
||||
try {
|
||||
const relay = await Relay.connect('wss://relay.damus.io');
|
||||
console.log(`[Nostr Scraper] Connected to relay`);
|
||||
|
||||
// In Nostr, search queries are supported by NIP-50 enabled relays.
|
||||
// Damus supports basic search via 'search' filter if enabled, otherwise we just fetch recent notes.
|
||||
// We'll use search filter. If the relay doesn't support it, it ignores it and returns recent events.
|
||||
const events: any[] = [];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const sub = relay.subscribe([
|
||||
{
|
||||
kinds: [1],
|
||||
search: "need developer hire freelance bounty looking for",
|
||||
limit: limit
|
||||
}
|
||||
], {
|
||||
onevent(event) {
|
||||
events.push(event);
|
||||
},
|
||||
oneose() {
|
||||
console.log(`[Nostr Scraper] Received ${events.length} events from Nostr.`);
|
||||
sub.close();
|
||||
relay.close();
|
||||
resolve(events);
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback timeout in case the relay doesn't send EOSE
|
||||
setTimeout(() => {
|
||||
sub.close();
|
||||
relay.close();
|
||||
resolve(events);
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("[Nostr Scraper] Error fetching leads:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user