kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/643/head^2
rodzic
89f8246a3a
commit
17f3912654
|
@ -2,6 +2,9 @@ export * from './clearbit-client.js'
|
|||
export * from './dexa-client.js'
|
||||
export * from './diffbot-client.js'
|
||||
export * from './exa-client.js'
|
||||
export * from './people-data-labs-client.js'
|
||||
export * from './perigon-client.js'
|
||||
export * from './predict-leads-client.js'
|
||||
export * from './proxycurl-client.js'
|
||||
export * from './scraper-client.js'
|
||||
export * from './serpapi-client.js'
|
||||
|
|
|
@ -0,0 +1,525 @@
|
|||
import defaultKy, { type KyInstance } from 'ky'
|
||||
import pThrottle from 'p-throttle'
|
||||
|
||||
import { assert, getEnv, throttleKy } from '../utils.js'
|
||||
|
||||
const peopleDataLabsAPIThrottle = pThrottle({
|
||||
limit: 20,
|
||||
interval: 60 * 1000,
|
||||
strict: true
|
||||
})
|
||||
|
||||
export namespace peopledatalabs {
|
||||
export const BASE_URL = 'https://api.peopledatalabs.com/v5/'
|
||||
|
||||
export const JobTitleLevels = [
|
||||
'cxo',
|
||||
'director',
|
||||
'entry',
|
||||
'manager',
|
||||
'owner',
|
||||
'partner',
|
||||
'senior',
|
||||
'training',
|
||||
'unpaid',
|
||||
'vp'
|
||||
]
|
||||
|
||||
export const JobTitleRoles = [
|
||||
'customer_service',
|
||||
'design',
|
||||
'education',
|
||||
'engineering',
|
||||
'finance',
|
||||
'health',
|
||||
'human_resources',
|
||||
'legal',
|
||||
'marketing',
|
||||
'media',
|
||||
'operations',
|
||||
'public_relations',
|
||||
'real_estate',
|
||||
'sales',
|
||||
'trades'
|
||||
]
|
||||
|
||||
// TODO configure this type to make pdl_id or name or profile or ticker or website required.
|
||||
// Only one is required
|
||||
export interface CompanyLookupOptions {
|
||||
pdl_id?: string
|
||||
name?: string
|
||||
profile?: string
|
||||
ticker?: string
|
||||
website?: string
|
||||
location?: string[]
|
||||
locality?: string
|
||||
region?: string
|
||||
country?: string
|
||||
street_address?: string
|
||||
postal_code?: string
|
||||
data_include?: string
|
||||
pretty?: boolean
|
||||
}
|
||||
|
||||
export interface Naics {
|
||||
naics_code: string
|
||||
sector: string
|
||||
sub_sector: string
|
||||
industry_group: string
|
||||
naics_industry: string | null
|
||||
national_industry: string | null
|
||||
}
|
||||
|
||||
export interface Sic {
|
||||
sic_code: string
|
||||
major_group: string
|
||||
industry_group: string
|
||||
industry_sector: string | null
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
name: string
|
||||
locality: string
|
||||
region: string
|
||||
metro: string
|
||||
country: string
|
||||
continent: string
|
||||
street_address: string
|
||||
address_line_2: string | null
|
||||
postal_code: string
|
||||
geo: string
|
||||
}
|
||||
|
||||
export interface EmployeeCountByCountry {
|
||||
[country: string]: number
|
||||
}
|
||||
|
||||
export interface CompanyLookupResponse {
|
||||
status: number
|
||||
name: string
|
||||
display_name: string
|
||||
size: string
|
||||
employee_count: number
|
||||
id: string
|
||||
founded: number
|
||||
industry: string
|
||||
naics: Naics[]
|
||||
sic: Sic[]
|
||||
location: Location
|
||||
linkedin_id: string
|
||||
linkedin_url: string
|
||||
facebook_url: string
|
||||
twitter_url: string
|
||||
profiles: string[]
|
||||
website: string
|
||||
ticker: string
|
||||
gics_sector: string | null
|
||||
mic_exchange: string | null
|
||||
type: string
|
||||
summary: string
|
||||
tags: string[]
|
||||
headline: string
|
||||
alternative_names: string[]
|
||||
alternative_domains: string[]
|
||||
affiliated_profiles: string[]
|
||||
employee_count_by_country: EmployeeCountByCountry
|
||||
likelihood: number
|
||||
}
|
||||
|
||||
export interface CompanySearchOptions {
|
||||
limit?: number
|
||||
query: {
|
||||
website?: string
|
||||
tags?: string
|
||||
industry?: string
|
||||
'location.country'?: string
|
||||
'location.metro'?: string
|
||||
summary?: string
|
||||
size?: string[]
|
||||
affiliated_profiles?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type CompanySearchOptionsQueryKeys =
|
||||
keyof CompanySearchOptions['query']
|
||||
|
||||
export interface CompanySearchResponse {
|
||||
status: number
|
||||
data: {
|
||||
name: string
|
||||
display_name: string
|
||||
size: string
|
||||
employee_count: number
|
||||
id: string
|
||||
founded: number
|
||||
industry: string
|
||||
naics: Naics[]
|
||||
sic: Sic[]
|
||||
location: Location
|
||||
linkedin_id: string
|
||||
linkedin_url: string
|
||||
facebook_url: string
|
||||
twitter_url: string
|
||||
profiles: string[]
|
||||
website: string
|
||||
ticker: string
|
||||
gics_sector: string | null
|
||||
mic_exchange: string | null
|
||||
type: string
|
||||
summary: string
|
||||
tags: string[]
|
||||
headline: string
|
||||
alternative_names: string[]
|
||||
alternative_domains: string[]
|
||||
affiliated_profiles: string[]
|
||||
employee_count_by_country: EmployeeCountByCountry
|
||||
}[]
|
||||
scroll_token: string
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface PersonSearchOptions {
|
||||
limit?: number
|
||||
query: {
|
||||
first_name?: string
|
||||
full_name?: string
|
||||
last_name?: string
|
||||
job_company_website?: string
|
||||
job_title_role?: string
|
||||
/**
|
||||
* The docs says this property should be an array of strings.
|
||||
* But when sending the array a 404 error is returned.
|
||||
* See: https://docs.peopledatalabs.com/docs/fields#job_title_levels
|
||||
*/
|
||||
job_title_levels?: string
|
||||
job_company_name?: string
|
||||
job_company_location_country?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type PersonSearchOptionsQueryKeys = keyof PersonSearchOptions['query']
|
||||
|
||||
// Person response
|
||||
export interface SearchPersonApiResponse {
|
||||
id: string
|
||||
full_name: string
|
||||
first_name: string
|
||||
middle_initial: null | string
|
||||
middle_name: null | string
|
||||
last_initial: string
|
||||
last_name: string
|
||||
gender: string
|
||||
birth_year: null | number
|
||||
birth_date: null | string
|
||||
linkedin_url: string
|
||||
linkedin_username: string
|
||||
linkedin_id: string
|
||||
facebook_url: null | string
|
||||
facebook_username: null | string
|
||||
facebook_id: null | string
|
||||
twitter_url: string
|
||||
twitter_username: string
|
||||
github_url: null | string
|
||||
github_username: null | string
|
||||
work_email: string
|
||||
personal_emails: string[]
|
||||
recommended_personal_email: null | string
|
||||
mobile_phone: null | string
|
||||
industry: null | string
|
||||
job_title: string
|
||||
job_title_role: null | string
|
||||
job_title_sub_role: null | string
|
||||
job_title_levels: string[]
|
||||
job_onet_code: string
|
||||
job_onet_major_group: string
|
||||
job_onet_minor_group: string
|
||||
job_onet_broad_occupation: string
|
||||
job_onet_specific_occupation: string
|
||||
job_onet_specific_occupation_detail: string
|
||||
job_company_id: string
|
||||
job_company_name: string
|
||||
job_company_website: string
|
||||
job_company_size: string
|
||||
job_company_founded: number
|
||||
job_company_industry: string
|
||||
job_company_linkedin_url: string
|
||||
job_company_linkedin_id: string
|
||||
job_company_facebook_url: string
|
||||
job_company_twitter_url: string
|
||||
job_company_type: string
|
||||
job_company_ticker: null | string
|
||||
job_company_location_name: string
|
||||
job_company_location_locality: string
|
||||
job_company_location_metro: string
|
||||
job_company_location_region: string
|
||||
job_company_location_geo: string
|
||||
job_company_location_street_address: string
|
||||
job_company_location_address_line_2: string
|
||||
job_company_location_postal_code: string
|
||||
job_company_location_country: string
|
||||
job_company_location_continent: string
|
||||
job_last_updated: string
|
||||
job_start_date: string
|
||||
job_summary: null | string
|
||||
location_name: null | string
|
||||
location_locality: null | string
|
||||
location_metro: null | string
|
||||
location_region: null | string
|
||||
location_country: null | string
|
||||
location_continent: null | string
|
||||
location_street_address: null | string
|
||||
location_address_line_2: null | string
|
||||
location_postal_code: null | string
|
||||
location_geo: null | string
|
||||
location_last_updated: null | string
|
||||
linkedin_connections: number
|
||||
facebook_friends: null | string
|
||||
inferred_salary: string
|
||||
inferred_years_experience: number
|
||||
summary: null | string
|
||||
phone_numbers: string[]
|
||||
phones: string[]
|
||||
emails: Email[]
|
||||
interests: string[]
|
||||
skills: string[]
|
||||
location_names: string[]
|
||||
regions: string[]
|
||||
countries: string[]
|
||||
street_addresses: string[]
|
||||
experience: Experience[]
|
||||
education: Education[]
|
||||
profiles: Profile[]
|
||||
name_aliases: string[]
|
||||
possible_emails: PossibleEmail[]
|
||||
possible_profiles: PossibleProfile[]
|
||||
possible_phones: PossiblePhone[]
|
||||
possible_street_addresses: string[]
|
||||
possible_location_names: string[]
|
||||
possible_birth_dates: string[]
|
||||
job_history: JobHistory[]
|
||||
certifications: string[]
|
||||
languages: string[]
|
||||
first_seen: string
|
||||
num_sources: number
|
||||
num_records: number
|
||||
version_status: VersionStatus
|
||||
}
|
||||
|
||||
export interface Email {
|
||||
address: string
|
||||
type: null | string
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
num_sources: number
|
||||
}
|
||||
|
||||
export interface Experience {
|
||||
company: Company
|
||||
start_date: null | string
|
||||
end_date: null | string
|
||||
title: Title
|
||||
location_names: string[]
|
||||
is_primary: boolean
|
||||
summary: null | string
|
||||
num_sources: number
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
}
|
||||
|
||||
export interface Company {
|
||||
name: string
|
||||
size: string
|
||||
id: string
|
||||
founded: number
|
||||
industry: string
|
||||
location: Location
|
||||
linkedin_url: string
|
||||
linkedin_id: string
|
||||
facebook_url: null | string
|
||||
twitter_url: string
|
||||
website: string
|
||||
ticker: null | string
|
||||
type: string
|
||||
raw: string[]
|
||||
fuzzy_match: boolean
|
||||
}
|
||||
|
||||
export interface Title {
|
||||
name: string
|
||||
raw: string[]
|
||||
role: null | string
|
||||
sub_role: null | string
|
||||
levels: string[]
|
||||
}
|
||||
|
||||
export interface Education {
|
||||
school: School
|
||||
degrees: string[]
|
||||
start_date: string
|
||||
end_date: string
|
||||
majors: string[]
|
||||
minors: string[]
|
||||
gpa: null | string
|
||||
raw: string[]
|
||||
summary: null | string
|
||||
}
|
||||
|
||||
export interface School {
|
||||
name: string
|
||||
type: string
|
||||
id: string
|
||||
location: Location
|
||||
linkedin_url: string
|
||||
facebook_url: string
|
||||
twitter_url: string
|
||||
linkedin_id: string
|
||||
website: string
|
||||
domain: string
|
||||
raw: string[]
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
network: string
|
||||
id: null | string
|
||||
url: string
|
||||
username: string
|
||||
num_sources: number
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
}
|
||||
|
||||
export interface PossibleEmail {
|
||||
address: string
|
||||
type: null | string
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
num_sources: number
|
||||
}
|
||||
|
||||
export interface PossibleProfile {
|
||||
network: string
|
||||
id: null | string
|
||||
url: string
|
||||
username: null | string
|
||||
num_sources: number
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
}
|
||||
|
||||
export interface PossiblePhone {
|
||||
number: string
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
num_sources: number
|
||||
}
|
||||
|
||||
export interface VersionStatus {
|
||||
status: string
|
||||
contains: string[]
|
||||
previous_version: string
|
||||
current_version: string
|
||||
}
|
||||
|
||||
export interface JobHistory {
|
||||
company_id: string
|
||||
company_name: string
|
||||
title: string
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
num_sources: number
|
||||
}
|
||||
}
|
||||
|
||||
export class PeopleDataLabsClient {
|
||||
readonly ky: KyInstance
|
||||
readonly apiKey: string
|
||||
readonly apiBaseUrl: string
|
||||
|
||||
constructor({
|
||||
apiKey = getEnv('PEOPLE_DATA_LABS_API_KEY'),
|
||||
apiBaseUrl = peopledatalabs.BASE_URL,
|
||||
timeoutMs = 30_000,
|
||||
throttle = true,
|
||||
ky = defaultKy
|
||||
}: {
|
||||
apiKey?: string
|
||||
apiBaseUrl?: string
|
||||
timeoutMs?: number
|
||||
throttle?: boolean
|
||||
ky?: KyInstance
|
||||
} = {}) {
|
||||
assert(apiKey, 'PeopleDataLabsClient missing required "apiKey"')
|
||||
|
||||
this.apiKey = apiKey
|
||||
this.apiBaseUrl = apiBaseUrl
|
||||
|
||||
const throttledKy = throttle
|
||||
? throttleKy(ky, peopleDataLabsAPIThrottle)
|
||||
: ky
|
||||
|
||||
this.ky = throttledKy.extend({
|
||||
prefixUrl: apiBaseUrl,
|
||||
timeout: timeoutMs,
|
||||
headers: {
|
||||
'X-Api-Key': `${this.apiKey}`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async companyLookup(options: peopledatalabs.CompanySearchOptions) {
|
||||
const terms = options.query
|
||||
const termsQuery = []
|
||||
|
||||
for (const term of Object.keys(
|
||||
terms
|
||||
) as peopledatalabs.CompanySearchOptionsQueryKeys[]) {
|
||||
termsQuery.push({ term: { [term]: terms[term] } })
|
||||
}
|
||||
|
||||
return this.ky
|
||||
.get('company/search', {
|
||||
searchParams: {
|
||||
size: options.limit || 1,
|
||||
query: JSON.stringify({
|
||||
bool: {
|
||||
must: termsQuery
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.json<peopledatalabs.CompanySearchResponse>()
|
||||
}
|
||||
|
||||
async companyProfile(options: peopledatalabs.CompanyLookupOptions) {
|
||||
return this.ky
|
||||
.get('company/enrich', {
|
||||
// @ts-expect-error location is a string[] and searchparams shows a TS error heres
|
||||
searchParams: { ...options }
|
||||
})
|
||||
.json<peopledatalabs.CompanyLookupResponse>()
|
||||
}
|
||||
|
||||
async personSearch(options: peopledatalabs.PersonSearchOptions) {
|
||||
const terms = options.query
|
||||
const termsQuery = []
|
||||
|
||||
for (const term of Object.keys(
|
||||
terms
|
||||
) as peopledatalabs.PersonSearchOptionsQueryKeys[]) {
|
||||
termsQuery.push({ term: { [term]: terms[term] } })
|
||||
}
|
||||
|
||||
return this.ky
|
||||
.get('person/search', {
|
||||
searchParams: {
|
||||
size: options.limit || 10,
|
||||
query: JSON.stringify({
|
||||
bool: {
|
||||
must: termsQuery
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.json<peopledatalabs.SearchPersonApiResponse>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
import defaultKy, { type KyInstance } from 'ky'
|
||||
import pThrottle from 'p-throttle'
|
||||
|
||||
import { assert, getEnv, throttleKy } from '../utils.js'
|
||||
|
||||
const perigonAPIThrottle = pThrottle({
|
||||
limit: 20,
|
||||
interval: 60 * 1000,
|
||||
strict: true
|
||||
})
|
||||
|
||||
export namespace perigon {
|
||||
export type ArticleLabel =
|
||||
| 'Opinion'
|
||||
| 'Non-news'
|
||||
| 'Paid News'
|
||||
| 'Fact Check'
|
||||
| 'Pop Culture'
|
||||
| 'Roundup'
|
||||
| 'Press Release'
|
||||
|
||||
export type Categories =
|
||||
| 'Politics'
|
||||
| 'Tech'
|
||||
| 'Sports'
|
||||
| 'Business'
|
||||
| 'Finance'
|
||||
| 'Entertainment'
|
||||
| 'Health'
|
||||
| 'Weather'
|
||||
| 'Lifestyle'
|
||||
| 'Auto'
|
||||
| 'Science'
|
||||
| 'Travel'
|
||||
| 'Environment'
|
||||
| 'World'
|
||||
| 'General'
|
||||
| 'none'
|
||||
|
||||
export type ArticlesOptions = {
|
||||
q: string
|
||||
title?: string
|
||||
desc?: string
|
||||
content?: string
|
||||
url?: string
|
||||
from?: string | Date
|
||||
to?: string | Date
|
||||
addDateFrom?: string | Date
|
||||
addDateTo?: string | Date
|
||||
refreshDateFrom?: string | Date
|
||||
refreshDateTo?: string | Date
|
||||
articleId?: string
|
||||
clusterId?: string
|
||||
medium?: 'article' | 'video'
|
||||
source?: string
|
||||
sourceGroup?:
|
||||
| 'top10'
|
||||
| 'top100'
|
||||
| 'top500English'
|
||||
| 'top25crypto'
|
||||
| 'top25finance'
|
||||
| 'top50tech'
|
||||
| 'top100sports'
|
||||
| 'top100leftUS'
|
||||
| 'top100rightUS'
|
||||
| 'top100centerUS'
|
||||
excludeSource?: string
|
||||
paywall?: boolean
|
||||
country?: string
|
||||
language?: string
|
||||
label?: ArticleLabel
|
||||
excludeLabel?: ArticleLabel | 'Low Content'
|
||||
byline?: string
|
||||
topic?: string
|
||||
category?: Categories
|
||||
journalistId?: string
|
||||
state?: string
|
||||
city?: string
|
||||
area?: string
|
||||
location?: string
|
||||
sortBy?: 'date' | 'relevance' | 'addDate' | 'pubDate' | 'refreshDate'
|
||||
relevance?: number
|
||||
size?: number
|
||||
showReprints?: boolean
|
||||
showNumResults?: boolean
|
||||
type?: 'all' | 'local' | 'world'
|
||||
linkTo?: string
|
||||
reprintGroupId?: string
|
||||
personWikidataId?: string[]
|
||||
personName?: string[]
|
||||
companyId?: string[]
|
||||
companyName?: string
|
||||
companyDomain?: string[]
|
||||
companySymbol?: string[]
|
||||
maxDistance?: number
|
||||
lat?: number
|
||||
lon?: number
|
||||
searchTranslation?: boolean
|
||||
}
|
||||
|
||||
export type ArticlesResponse = {
|
||||
status: number
|
||||
numResults: number
|
||||
articles: {
|
||||
url: string
|
||||
authorsByline: string
|
||||
articleId: string
|
||||
clusterId: string
|
||||
source: {
|
||||
domain: string
|
||||
}
|
||||
imageUrl: string
|
||||
country: string
|
||||
language: string
|
||||
pubDate: string
|
||||
addDate: string
|
||||
refreshDate: string
|
||||
score: number
|
||||
title: string
|
||||
description: string
|
||||
content: string
|
||||
medium: string
|
||||
links: string[]
|
||||
labels: string[]
|
||||
matchedAuthors: string[]
|
||||
claim: string
|
||||
verdict: string
|
||||
keywords: {
|
||||
name: string
|
||||
weight: number
|
||||
}[]
|
||||
topics: {
|
||||
name: string
|
||||
}[]
|
||||
categories: {
|
||||
name: string
|
||||
}[]
|
||||
entities: {
|
||||
data: string
|
||||
type: string
|
||||
mentions: number
|
||||
}[]
|
||||
sentiment: {
|
||||
positive: number
|
||||
negative: number
|
||||
neutral: number
|
||||
}
|
||||
summary: string
|
||||
translation: string
|
||||
locations: string[]
|
||||
reprint: boolean
|
||||
reprintGroupId: string
|
||||
places: null
|
||||
}[]
|
||||
}
|
||||
|
||||
export type StoriesOptions = {
|
||||
clusterId?: string
|
||||
topic?: string
|
||||
category?: Categories
|
||||
name?: string
|
||||
nameExists?: boolean
|
||||
from?: string
|
||||
to?: string
|
||||
initializedFrom?: string
|
||||
initializedTo?: string
|
||||
updatedFrom?: string
|
||||
updatedTo?: string
|
||||
minClusterSize?: number
|
||||
maxClusterSize?: number
|
||||
state?: string
|
||||
city?: string
|
||||
area?: string
|
||||
page?: number
|
||||
size?: number
|
||||
sortBy?: 'count' | 'createdAt' | 'updatedAt'
|
||||
showNumResults?: boolean
|
||||
}
|
||||
|
||||
export type StoriesResponse = {
|
||||
status: number
|
||||
numResults: number
|
||||
results: Array<{
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
initializedAt: string
|
||||
id: string
|
||||
name: string
|
||||
summary: string
|
||||
summaryReferences: Array<any>
|
||||
keyPoints: Array<{
|
||||
point: string
|
||||
references: Array<string>
|
||||
}>
|
||||
sentiment: {
|
||||
positive: number
|
||||
negative: number
|
||||
neutral: number
|
||||
}
|
||||
uniqueCount: number
|
||||
reprintCount: number
|
||||
totalCount: number
|
||||
countries: Array<{
|
||||
name: string
|
||||
count: number
|
||||
}>
|
||||
topCountries: Array<string>
|
||||
topics: Array<{
|
||||
name: string
|
||||
count: number
|
||||
}>
|
||||
topTopics: Array<{ name: string }>
|
||||
categories: Array<{
|
||||
name: string
|
||||
count: number
|
||||
}>
|
||||
topCategories: Array<{ name: string }>
|
||||
people: Array<{ wikidataId: string; name: string; count: number }>
|
||||
topPeople: Array<{ wikidataId: string; name: string }>
|
||||
companies: Array<{
|
||||
id: string
|
||||
name: string
|
||||
domains: Array<string>
|
||||
symbols: Array<string>
|
||||
count: number
|
||||
}>
|
||||
topCompanies: Array<{
|
||||
id: string
|
||||
name: string
|
||||
domains: Array<string>
|
||||
symbols: Array<string>
|
||||
}>
|
||||
locations: Array<{
|
||||
state: string
|
||||
city?: string
|
||||
area?: string
|
||||
county?: string
|
||||
count: number
|
||||
}>
|
||||
topLocations: Array<{
|
||||
state: string
|
||||
city?: string
|
||||
area?: string
|
||||
county?: string
|
||||
}>
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export class PerigonClient {
|
||||
readonly ky: KyInstance
|
||||
readonly apiKey: string
|
||||
readonly _maxPageSize = 10
|
||||
|
||||
constructor({
|
||||
apiKey = getEnv('PERIGON_API_KEY'),
|
||||
timeoutMs = 30_000,
|
||||
throttle = true,
|
||||
ky = defaultKy
|
||||
}: {
|
||||
apiKey?: string
|
||||
apiBaseUrl?: string
|
||||
throttle?: boolean
|
||||
timeoutMs?: number
|
||||
ky?: KyInstance
|
||||
} = {}) {
|
||||
assert(apiKey, 'Error perigon client missing required "apiKey"')
|
||||
|
||||
this.apiKey = apiKey
|
||||
|
||||
const throttledKy = throttle ? throttleKy(ky, perigonAPIThrottle) : ky
|
||||
|
||||
this.ky = throttledKy.extend({
|
||||
prefixUrl: 'https://api.goperigon.com/v1/',
|
||||
timeout: timeoutMs
|
||||
})
|
||||
}
|
||||
|
||||
async articles(options: perigon.ArticlesOptions) {
|
||||
return this.ky
|
||||
.get('all', {
|
||||
// @ts-expect-error there are multiple query params that array of strings
|
||||
// and KY SearchParamsOption shows a TS error for those types
|
||||
searchParams: {
|
||||
apiKey: this.apiKey,
|
||||
...options,
|
||||
size: Math.min(this._maxPageSize, options.size || this._maxPageSize)
|
||||
}
|
||||
})
|
||||
.json<perigon.ArticlesResponse>()
|
||||
}
|
||||
|
||||
async stories(options: perigon.StoriesOptions) {
|
||||
return this.ky
|
||||
.get('stories/all', {
|
||||
searchParams: {
|
||||
apiKey: this.apiKey,
|
||||
...options,
|
||||
size: Math.min(this._maxPageSize, options.size || this._maxPageSize)
|
||||
}
|
||||
})
|
||||
.json<perigon.StoriesResponse>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,478 @@
|
|||
import defaultKy, { type KyInstance } from 'ky'
|
||||
import pThrottle from 'p-throttle'
|
||||
|
||||
import type { DeepNullable } from '../types.js'
|
||||
import { assert, getEnv, throttleKy } from '../utils.js'
|
||||
|
||||
const predictionLeadsAPIThrottle = pThrottle({
|
||||
limit: 20,
|
||||
interval: 60 * 1000,
|
||||
strict: true
|
||||
})
|
||||
|
||||
export namespace predictleads {
|
||||
export type Meta = DeepNullable<{
|
||||
count: number
|
||||
message?: string | null
|
||||
message_type?: string
|
||||
}>
|
||||
|
||||
export type GenericSuccessResponse = {
|
||||
success: {
|
||||
type: string
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
export type FollowedCompaniesResponse = {
|
||||
data: DeepNullable<
|
||||
Array<{
|
||||
domain: string
|
||||
custom_company_identifier: string | null
|
||||
}>
|
||||
>
|
||||
meta: Meta
|
||||
}
|
||||
|
||||
export type Relationship = Record<
|
||||
string,
|
||||
{
|
||||
data: {
|
||||
id: string
|
||||
type: string
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
export type AdditionalData = {
|
||||
relationships: {
|
||||
companies: [string, string]
|
||||
}
|
||||
date: string
|
||||
location: string
|
||||
location_data: {
|
||||
region?: string
|
||||
continent?: string
|
||||
country?: string
|
||||
state?: string
|
||||
zip_code?: string
|
||||
city?: string
|
||||
fuzzy_match?: boolean
|
||||
}
|
||||
contact?: string
|
||||
job_title?: string
|
||||
product?: string
|
||||
product_tags?: string[]
|
||||
amount?: number
|
||||
recognition?: string
|
||||
assets?: string
|
||||
asset_tags?: string[]
|
||||
headcount?: number
|
||||
award?: string
|
||||
financing_type?: string
|
||||
financing_type_tags?: string[]
|
||||
funding_round?: string
|
||||
division?: string
|
||||
conference?: string
|
||||
vulnerability?: string
|
||||
planning?: boolean
|
||||
article_title?: string
|
||||
article_sentence?: string
|
||||
article_body?: string
|
||||
article_source?: string
|
||||
article_published_at?: string
|
||||
article_image_url?: string
|
||||
}
|
||||
|
||||
export type Event = {
|
||||
id: string
|
||||
type: string
|
||||
attributes: {
|
||||
categories: string[]
|
||||
title: string
|
||||
url: string
|
||||
found_at: string
|
||||
additional_data: AdditionalData
|
||||
domain: string
|
||||
location: string
|
||||
location_data: {
|
||||
state: string
|
||||
country: string
|
||||
}
|
||||
company_name: string
|
||||
friendly_company_name: string
|
||||
ticker: null
|
||||
meta_title: string
|
||||
meta_description: string
|
||||
published_at: string
|
||||
post_type: string
|
||||
post_url: string
|
||||
company_domain: string
|
||||
fuzzy_match: boolean
|
||||
}
|
||||
relationships: Relationship
|
||||
}
|
||||
|
||||
export type Response = DeepNullable<{
|
||||
data: Event[]
|
||||
included: Relationship
|
||||
meta: Meta
|
||||
}>
|
||||
|
||||
export type JobOpeningData = {
|
||||
id: string
|
||||
type: string
|
||||
attributes: {
|
||||
title: string
|
||||
url: string
|
||||
description: string
|
||||
salary: string
|
||||
salary_data: {
|
||||
salary_low: number
|
||||
salary_high: number
|
||||
salary_currency: string
|
||||
salary_low_usd: number
|
||||
salary_high_usd: number
|
||||
salary_time_unit: string
|
||||
}
|
||||
job_opening_closed: boolean
|
||||
location: string
|
||||
contract_types: string[]
|
||||
first_seen_at: string
|
||||
last_seen_at: string
|
||||
last_processed_at: string
|
||||
categories: string[]
|
||||
onet_code: string
|
||||
additional_data: {
|
||||
job_title_seniority: string
|
||||
tags: string[]
|
||||
location_data: {
|
||||
country: string
|
||||
city: string
|
||||
fuzzy_match: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
relationships: {
|
||||
company: {
|
||||
data: {
|
||||
id: string
|
||||
type: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type CompanyData = {
|
||||
id: string
|
||||
type: string
|
||||
attributes: {
|
||||
domain: string
|
||||
company_name: string
|
||||
ticker: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export type JobOpeningResponse = DeepNullable<{
|
||||
data: JobOpeningData[]
|
||||
included: CompanyData[]
|
||||
meta: {
|
||||
count: number
|
||||
}
|
||||
}>
|
||||
|
||||
export type JobOpeningByIdResponse = Omit<JobOpeningResponse, 'meta'>
|
||||
}
|
||||
|
||||
export class PredictLeadsClient {
|
||||
readonly ky: KyInstance
|
||||
readonly apiKey: string
|
||||
readonly apiToken: string
|
||||
readonly _maxPageSize = 100
|
||||
|
||||
constructor({
|
||||
apiKey = getEnv('PREDICT_LEADS_API_KEY'),
|
||||
apiToken = getEnv('PREDICT_LEADS_API_TOKEN'),
|
||||
timeoutMs = 30_000,
|
||||
throttle = true,
|
||||
ky = defaultKy
|
||||
}: {
|
||||
apiKey?: string
|
||||
apiToken?: string
|
||||
apiBaseUrl?: string
|
||||
timeoutMs?: number
|
||||
throttle?: boolean
|
||||
ky?: KyInstance
|
||||
} = {}) {
|
||||
assert(apiKey, 'PredictLeadsClient missing required "apiKey"')
|
||||
assert(apiToken, 'PredictLeadsClient missing required "apiToken"')
|
||||
|
||||
this.apiKey = apiKey
|
||||
this.apiToken = apiToken
|
||||
|
||||
const throttledKy = throttle
|
||||
? throttleKy(ky, predictionLeadsAPIThrottle)
|
||||
: ky
|
||||
|
||||
this.ky = throttledKy.extend({
|
||||
timeout: timeoutMs,
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
'X-Api-Token': apiToken
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async followCompany(domain: string, customCompanyIdentifier?: string) {
|
||||
return this.ky
|
||||
.post(
|
||||
`https://predictleads.com/api/v2/companies/${domain}/follow`,
|
||||
customCompanyIdentifier
|
||||
? {
|
||||
json: { customCompanyIdentifier }
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
.json<predictleads.GenericSuccessResponse>()
|
||||
}
|
||||
|
||||
async getFollowingCompanies(limit: number = this._maxPageSize) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/followings`, {
|
||||
searchParams: { limit }
|
||||
})
|
||||
.json<predictleads.FollowedCompaniesResponse>()
|
||||
}
|
||||
|
||||
async unfollowCompany(domain: string, customCompanyIdentifier?: string) {
|
||||
return this.ky
|
||||
.post(
|
||||
`https://predictleads.com/api/v2/companies/${domain}/unfollow`,
|
||||
customCompanyIdentifier
|
||||
? {
|
||||
json: { customCompanyIdentifier }
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
.json<predictleads.GenericSuccessResponse>()
|
||||
}
|
||||
|
||||
async events(
|
||||
domain: string,
|
||||
params: {
|
||||
categories?: string
|
||||
found_at_from?: string
|
||||
found_at_until?: string
|
||||
page?: number
|
||||
limit?: string
|
||||
with_news_article_bodies?: boolean
|
||||
} = {}
|
||||
) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}/events`, {
|
||||
searchParams: { page: 1, ...params }
|
||||
})
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async eventById(id: string) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/events/${id}`)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async financingEvents(domain: string) {
|
||||
return this.ky
|
||||
.get(
|
||||
`https://predictleads.com/api/v2/companies/${domain}/financing_events`
|
||||
)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async jobOpenings(
|
||||
domain: string,
|
||||
params: {
|
||||
categories?: string
|
||||
with_job_descriptions?: boolean
|
||||
active_only?: boolean
|
||||
not_closed?: boolean
|
||||
limit?: string
|
||||
} = {}
|
||||
) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}/job_openings`, {
|
||||
searchParams: params
|
||||
})
|
||||
.json<predictleads.JobOpeningResponse>()
|
||||
}
|
||||
|
||||
async jobOpeningById(id: string) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/job_openings/${id}`)
|
||||
.json<predictleads.JobOpeningByIdResponse>()
|
||||
}
|
||||
|
||||
async technologies(
|
||||
domain: string,
|
||||
params: {
|
||||
categories: string
|
||||
limit?: string
|
||||
}
|
||||
) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}/technologies`, {
|
||||
searchParams: params
|
||||
})
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async connections(
|
||||
domain: string,
|
||||
params?: {
|
||||
categories: string
|
||||
limit?: string
|
||||
}
|
||||
) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}/connections`, {
|
||||
searchParams: params
|
||||
})
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async websiteEvolution(
|
||||
domain: string,
|
||||
{ limit = 100 }: { limit?: number } = {}
|
||||
) {
|
||||
return this.ky
|
||||
.get(
|
||||
`https://predictleads.com/api/v2/companies/${domain}/website_evolution`,
|
||||
{
|
||||
searchParams: { limit }
|
||||
}
|
||||
)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async githubRepositories(
|
||||
domain: string,
|
||||
{ limit = 100 }: { limit?: number } = {}
|
||||
) {
|
||||
return this.ky
|
||||
.get(
|
||||
`https://predictleads.com/api/v2/companies/${domain}/github_repositories`,
|
||||
{
|
||||
searchParams: { limit }
|
||||
}
|
||||
)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async products(
|
||||
domain: string,
|
||||
params?: {
|
||||
sources: string
|
||||
limit?: number
|
||||
}
|
||||
) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}/products`, {
|
||||
searchParams: params
|
||||
})
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async company(domain: string) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/companies/${domain}`)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async discoverStartupJobs(params?: {
|
||||
post_datetime_from?: string
|
||||
post_datetime_until?: string
|
||||
min_score?: string
|
||||
limit?: string
|
||||
}) {
|
||||
return this.ky
|
||||
.get(
|
||||
`https://predictleads.com/api/v2/discover/startup_platform/jobs_hn`,
|
||||
{
|
||||
searchParams: params
|
||||
}
|
||||
)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
async discoverStartupShow(params?: {
|
||||
post_datetime_from?: string
|
||||
post_datetime_until?: string
|
||||
min_score?: string
|
||||
limit?: string
|
||||
}) {
|
||||
return this.ky
|
||||
.get(
|
||||
`https://predictleads.com/api/v2/discover/startup_platform/show_hn`,
|
||||
{
|
||||
searchParams: params
|
||||
}
|
||||
)
|
||||
.json<predictleads.Response>()
|
||||
}
|
||||
|
||||
/*
|
||||
TODO this returns 500 error, even using the curl example from docs.
|
||||
Also for this reason I couldn't test the other segments endpoints
|
||||
curl -X POST "https://predictleads.com/api/v2/segments"
|
||||
-d '{"technologies":"Salesforce", "job_categories":"sales"}'
|
||||
-H "Content-Type: application/json" \
|
||||
-H 'X-Api-Key: <key>' \
|
||||
-H 'X-Api-Token: <token>'
|
||||
*/
|
||||
async createSegment(params: {
|
||||
webhook_url?: string
|
||||
locations?: string
|
||||
headquarters_locations?: string
|
||||
job_categories?: string
|
||||
technologies?: string
|
||||
found_at_from?: string
|
||||
found_at_until?: string
|
||||
active?: string
|
||||
limit?: string
|
||||
}) {
|
||||
return this.ky
|
||||
.post(`https://predictleads.com/api/v2/segments`, {
|
||||
json: params
|
||||
})
|
||||
.json<any>()
|
||||
}
|
||||
|
||||
async updateSegment(params: {
|
||||
id: string
|
||||
webhook_url: string
|
||||
active: string
|
||||
}) {
|
||||
return this.ky
|
||||
.put(
|
||||
`https://predictleads.com/api/v2/discover/startup_platform/show_hn`,
|
||||
{
|
||||
json: params
|
||||
}
|
||||
)
|
||||
.json<any>()
|
||||
}
|
||||
|
||||
async showSegment(id: string) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/segments/${id}`)
|
||||
.json<any>()
|
||||
}
|
||||
|
||||
async showAllSegment(limit = 100) {
|
||||
return this.ky
|
||||
.get(`https://predictleads.com/api/v2/segments`, {
|
||||
searchParams: { limit }
|
||||
})
|
||||
.json<any>()
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue