Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package integrations.telex.salesagent.lead.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PeopleLeadDto {
private String fullName;
private String headline;
private String location;
private String profileURL;
private String username;
}

Original file line number Diff line number Diff line change
@@ -1,8 +1,31 @@
package integrations.telex.salesagent.lead.dto;

import integrations.telex.salesagent.lead.service.LocationMappingService;
import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class PeopleSearchRequest {
private String url;
private String keyword;
private String location;

private transient LocationMappingService locationMappingService;

public String buildLinkedInSearchUrl() {
StringBuilder urlBuilder = new StringBuilder("https://www.linkedin.com/search/results/people/?");

if (location != null && !location.isEmpty()) {
String geoUrn = locationMappingService.getGeoUrnForLocation(location);
if (geoUrn != null) {
urlBuilder.append("geoUrn=%5B%22").append(geoUrn).append("%22%5D&");
} else {
// Handle case where location is not found in the mapping
System.out.println("Location not found in mapping: " + location);
}
}

urlBuilder.append("origin=FACETED_SEARCH");
return urlBuilder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package integrations.telex.salesagent.lead.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import integrations.telex.salesagent.lead.dto.PeopleLeadDto;
import integrations.telex.salesagent.lead.dto.PeopleSearchRequest;
import integrations.telex.salesagent.lead.dto.RapidLeadDto;
import integrations.telex.salesagent.telex.service.TelexClient;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -16,6 +17,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
Expand All @@ -34,65 +36,94 @@ public class LeadPeopleResearchService {
private final ObjectMapper objectMapper;
private final TelexClient telexClient;

public List<RapidLeadDto> queryLeads(String channelID, PeopleSearchRequest request) {
public List<PeopleLeadDto> queryLeads(String channelID, PeopleSearchRequest request) {
try {
// Prepare headers
HttpHeaders headers = new HttpHeaders();
headers.set("X-RapidAPI-Key", rapidApiKey);
headers.set("X-RapidAPI-Host", rapidApiHost);
headers.setContentType(MediaType.APPLICATION_JSON);

// Build the request body (LinkedIn search URL)
Map<String, String> payload = new HashMap<>();
payload.put("url", request.getUrl());

HttpEntity<Map<String, String>> entity = new HttpEntity<>(payload, headers);

// Call RapidAPI
log.info("Searching for people with URL: {}", request.getUrl());
ResponseEntity<String> response = restTemplate.exchange(
rapidApiUrl, HttpMethod.POST, entity, String.class
);

// Process the response
if (response.getStatusCode().is2xxSuccessful()) {
List<RapidLeadDto> leads = formatPeopleResponse(response.getBody());

if (leads.isEmpty()) {
String report = "🔍 No LinkedIn profiles found for the given search URL.";
telexClient.sendInstruction(channelID, report);
} else {
for (RapidLeadDto lead : leads) {
telexClient.processTelexPayload(channelID, lead);
}
}
return leads;
} else {
log.error("API Error: {}", response.getStatusCode());
return new ArrayList<>();
// Build URL with location filter
String searchUrl = request.buildLinkedInSearchUrl();
log.info("Constructed LinkedIn search URL: {}", searchUrl);

// Make API call
List<PeopleLeadDto> leads = fetchLeadsFromApi(searchUrl);

// Apply keyword filtering
if (request.getKeyword() != null && !request.getKeyword().isEmpty()) {
leads = filterByKeyword(leads, request.getKeyword());
log.info("Filtered {} leads by keyword: {}", leads.size(), request.getKeyword());
}

// Process results
processResults(channelID, leads);

return leads;

} catch (Exception e) {
log.error("Error calling RapidAPI: {}", e.getMessage(), e);
}
return new ArrayList<>();
}

private List<PeopleLeadDto> filterByKeyword(List<PeopleLeadDto> leads, String keyword) {
String lowerKeyword = keyword.toLowerCase();
return leads.stream()
.filter(lead ->
(lead.getHeadline() != null &&
lead.getHeadline().toLowerCase().contains(lowerKeyword)) ||
(lead.getFullName() != null &&
lead.getFullName().toLowerCase().contains(lowerKeyword)))
.collect(Collectors.toList());
}

private void processResults(String channelID, List<PeopleLeadDto> leads) throws JsonProcessingException {
if (leads.isEmpty()) {
telexClient.sendInstruction(channelID, "🔍 No matching profiles found.");
} else {
leads.forEach(lead -> {
try {
telexClient.processTelexPayload(channelID, lead);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
}
}

private List<PeopleLeadDto> fetchLeadsFromApi(String searchUrl) {
HttpHeaders headers = new HttpHeaders();
headers.set("X-RapidAPI-Key", rapidApiKey);
headers.set("X-RapidAPI-Host", rapidApiHost);
headers.setContentType(MediaType.APPLICATION_JSON);

Map<String, String> payload = new HashMap<>();
payload.put("url", searchUrl);

HttpEntity<Map<String, String>> entity = new HttpEntity<>(payload, headers);

ResponseEntity<String> response = restTemplate.exchange(
rapidApiUrl, HttpMethod.POST, entity, String.class
);

if (!response.getStatusCode().is2xxSuccessful()) {
log.error("API request failed with status: {}", response.getStatusCode());
return new ArrayList<>();
}

return formatPeopleResponse(response.getBody());
}

// Parse API response into Lead objects
private List<RapidLeadDto> formatPeopleResponse(String responseBody) {
List<RapidLeadDto> leads = new ArrayList<>();
private List<PeopleLeadDto> formatPeopleResponse(String responseBody) {
List<PeopleLeadDto> leads = new ArrayList<>();
try {
JsonNode root = objectMapper.readTree(responseBody);
JsonNode items = root.path("data").path("items");

if (items.isArray()) {
for (JsonNode item : items) {
RapidLeadDto lead = new RapidLeadDto(
null,
PeopleLeadDto lead = new PeopleLeadDto(
item.path("fullName").asText(),
item.path("headline").asText(),
item.path("location").asText(),
item.path("profileURL").asText(),
String.format("%s | %s",
item.path("headline").asText(),
item.path("location").asText())
item.path("username").asText()
);
leads.add(lead);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package integrations.telex.salesagent.lead.service;

import org.springframework.stereotype.Service;

import java.util.Map;

import static java.util.Map.entry;

@Service
public class LocationMappingService {
private static final Map<String, String> LOCATION_TO_GEOURN = Map.of(
"lagos", "104197452",
"atlanta", "103644278",
"new york", "100288700",
"abuja", "101711968",
"port harcourt", "114378074",
"london", "90009496",
"kaduna", "103668447"
);

public String getGeoUrnForLocation(String locationName) {
if (locationName == null) return null;
return LOCATION_TO_GEOURN.get(locationName.toLowerCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public List<RapidLeadDto> queryLeads(String channelID,CompanySearchRequest reque

// Forward each lead to Telex
for (RapidLeadDto lead : newLeads) {
telexClient.processTelexPayload(channelID, lead);
//telexClient.processTelexPayload(channelID, lead);
log.info("Lead sent to Telex: {}", lead.getName());
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import integrations.telex.salesagent.config.AppConfig;
import integrations.telex.salesagent.lead.dto.PeopleLeadDto;
import integrations.telex.salesagent.lead.dto.RapidLeadDto;
import integrations.telex.salesagent.lead.model.Lead;
import integrations.telex.salesagent.lead.service.LeadPeopleResearchService;
import integrations.telex.salesagent.telex.util.FormatTelexMessage;
import integrations.telex.salesagent.user.dto.request.TelexPayload;
import lombok.RequiredArgsConstructor;
Expand All @@ -20,6 +22,7 @@ public class TelexClient {
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private final FormatTelexMessage formatTelexMessage;
private final LeadPeopleResearchService leadPeopleResearchService;

public void sendToTelexChannel(String channelID, String message) {
try {
Expand All @@ -32,7 +35,15 @@ public void sendToTelexChannel(String channelID, String message) {
}
}

public void processTelexPayload(String channelID, RapidLeadDto lead) throws JsonProcessingException {
// public void processTelexPayload(String channelID, RapidLeadDto lead) throws JsonProcessingException {
// String message = formatTelexMessage.formatNewLeadMessage(lead) + "\n\nSales Agent Bot";
//
// TelexPayload telexPayload = new TelexPayload("New Lead Alert", "Sales Agent", "success", message);
//
// sendToTelexChannel(channelID, objectMapper.writeValueAsString(telexPayload));
// }

public void processTelexPayload(String channelID, PeopleLeadDto lead) throws JsonProcessingException {
String message = formatTelexMessage.formatNewLeadMessage(lead) + "\n\nSales Agent Bot";

TelexPayload telexPayload = new TelexPayload("New Lead Alert", "Sales Agent", "success", message);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package integrations.telex.salesagent.telex.util;

import integrations.telex.salesagent.lead.dto.PeopleLeadDto;
import integrations.telex.salesagent.lead.dto.RapidLeadDto;
import org.springframework.stereotype.Component;

Expand All @@ -15,12 +16,32 @@ public class FormatTelexMessage {
Lead Company Summary : %s
""";

public String formatNewLeadMessage(RapidLeadDto data) {
return String.format(NEW_LEAD,
data.getId(),
data.getName(),
data.getLinkedinUrl(),
data.getTagline()
private static final String NEW_LEAD_PEOPLE = """
New lead has been found:

Lead Name: %s
Lead Headline: %s
Lead Location: %s
Lead Profile URL: %s
Lead Username: %s
""";

// public String formatNewLeadMessage(RapidLeadDto data) {
// return String.format(NEW_LEAD,
// data.getId(),
// data.getName(),
// data.getLinkedinUrl(),
// data.getTagline()
// );
// }

public String formatNewLeadMessage(PeopleLeadDto data) {
return String.format(NEW_LEAD_PEOPLE,
data.getFullName(),
data.getHeadline(),
data.getLocation(),
data.getProfileURL(),
data.getUsername()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
@Getter
@Setter
public class LeadDetails {
// private String businessType;
// private String locations;
// private String companySizes;
private String businessType;
private String locations;
private String companySizes;
private String location;
private String keyword;
}
Loading