feat: add bing web search service

Travis Fischer 2023-06-12 18:50:47 -07:00
rodzic acbcb654eb
commit ab5321b641
5 zmienionych plików z 312 dodań i 8 usunięć

Wyświetl plik

@ -1,14 +1,9 @@
export * from './agentic'
export * from './task'
export * from './llms'
export * from './errors'
export * from './tokenizer'
export * from './human-feedback'
export * from './services/metaphor'
export * from './services/serpapi'
export * from './services/novu'
export * from './tools/calculator'
export * from './tools/metaphor'
export * from './tools/novu'
export * from './llms'
export * from './services'
export * from './tools'

Wyświetl plik

@ -0,0 +1,282 @@
import ky from 'ky'
export const BING_BASE_URL = 'https://api.bing.microsoft.com'
export interface BingWebSearchQuery {
q: string
mkt?: string
offset?: number
count?: number
safeSearch?: 'Off' | 'Moderate' | 'Strict'
textDecorations?: boolean
textFormat?: 'Raw' | 'HTML'
}
// export type BingWebSearchInput = z.infer<typeof BingWebSearchInputSchema>
export interface BingWebSearchResponse {
_type: string
entities: Entities
images: Images
places: Places
queryContext: QueryContext
rankingResponse: RankingResponse
relatedSearches: RelatedSearches
videos: Videos
webPages: WebPages
}
interface Entities {
value: EntitiesValue[]
}
interface EntitiesValue {
bingId: string
contractualRules: PurpleContractualRule[]
description: string
entityPresentationInfo: EntityPresentationInfo
id: string
image: Image
name: string
webSearchUrl: string
}
interface PurpleContractualRule {
_type: string
license?: DeepLink
licenseNotice?: string
mustBeCloseToContent: boolean
targetPropertyName: string
text?: string
url?: string
}
interface DeepLink {
name: string
url: string
}
interface EntityPresentationInfo {
entityScenario: string
entityTypeHints: string[]
}
interface Image {
height: number
hostPageUrl: string
name: string
provider: Provider[]
sourceHeight: number
sourceWidth: number
thumbnailUrl: string
width: number
}
interface Provider {
_type: string
url: string
}
interface Images {
id: string
isFamilyFriendly: boolean
readLink: string
value: ImagesValue[]
webSearchUrl: string
}
interface ImagesValue {
contentSize: string
contentUrl: string
encodingFormat: string
height: number
hostPageDisplayUrl: string
hostPageUrl: string
name: string
thumbnail: Thumbnail
thumbnailUrl: string
webSearchUrl: string
width: number
}
interface Thumbnail {
height: number
width: number
}
interface Places {
value: PlacesValue[]
}
interface PlacesValue {
_type: string
address: Address
entityPresentationInfo: EntityPresentationInfo
id: string
name: string
telephone: string
url: string
webSearchUrl: string
}
interface Address {
addressCountry: string
addressLocality: string
addressRegion: string
neighborhood: string
postalCode: string
}
interface QueryContext {
askUserForLocation: boolean
originalQuery: string
}
interface RankingResponse {
mainline: Mainline
sidebar: Mainline
}
interface Mainline {
items: Item[]
}
interface Item {
answerType: string
resultIndex?: number
value?: ItemValue
}
interface ItemValue {
id: string
}
interface RelatedSearches {
id: string
value: RelatedSearchesValue[]
}
interface RelatedSearchesValue {
displayText: string
text: string
webSearchUrl: string
}
interface Videos {
id: string
isFamilyFriendly: boolean
readLink: string
scenario: string
value: VideosValue[]
webSearchUrl: string
}
interface VideosValue {
allowHttpsEmbed: boolean
allowMobileEmbed: boolean
contentUrl: string
creator: Creator
datePublished: Date
description: string
duration: string
embedHtml: string
encodingFormat: EncodingFormat
height: number
hostPageDisplayUrl: string
hostPageUrl: string
isAccessibleForFree: boolean
isSuperfresh: boolean
motionThumbnailUrl: string
name: string
publisher: Creator[]
thumbnail: Thumbnail
thumbnailUrl: string
viewCount: number
webSearchUrl: string
width: number
}
interface Creator {
name: string
}
enum EncodingFormat {
Mp4 = 'mp4'
}
interface WebPages {
totalEstimatedMatches: number
value: WebPagesValue[]
webSearchUrl: string
}
interface WebPagesValue {
dateLastCrawled: Date
deepLinks?: DeepLink[]
displayUrl: string
id: string
isFamilyFriendly: boolean
isNavigational: boolean
language: string
name: string
snippet: string
thumbnailUrl?: string
url: string
contractualRules?: FluffyContractualRule[]
}
interface FluffyContractualRule {
_type: string
license: DeepLink
licenseNotice: string
mustBeCloseToContent: boolean
targetPropertyIndex: number
targetPropertyName: string
}
export class BingWebSearchClient {
apiKey: string
baseUrl: string
constructor({
apiKey = process.env.BING_API_KEY,
baseUrl = BING_BASE_URL
}: {
apiKey?: string
baseUrl?: string
} = {}) {
if (!apiKey) {
throw new Error(`Error BingWebSearchClient missing required "apiKey"`)
}
this.apiKey = apiKey
this.baseUrl = baseUrl
}
async search(queryOrOpts: string | BingWebSearchQuery) {
const defaultQuery: Partial<BingWebSearchQuery> = {
mkt: 'en-US'
}
const searchParams =
typeof queryOrOpts === 'string'
? {
...defaultQuery,
q: queryOrOpts
}
: {
...defaultQuery,
...queryOrOpts
}
console.log(searchParams)
return ky
.get(`${this.baseUrl}/v7.0/search`, {
headers: {
'Ocp-Apim-Subscription-Key': this.apiKey
},
searchParams
})
.json<BingWebSearchResponse>()
}
}

Wyświetl plik

@ -0,0 +1,6 @@
export * from './bing-web-search'
export * from './metaphor'
export * from './novu'
export * from './serpapi'
export * from './slack'
export * from './twilio-conversation'

Wyświetl plik

@ -0,0 +1,3 @@
export * from './calculator'
export * from './metaphor'
export * from './novu'

18
test/bing.test.ts vendored 100644
Wyświetl plik

@ -0,0 +1,18 @@
import test from 'ava'
import { BingWebSearchClient } from '@/services'
import './_utils'
test('BingWebSearchClient.search', async (t) => {
if (!process.env.BING_API_KEY) {
return t.pass()
}
t.timeout(2 * 60 * 1000)
const client = new BingWebSearchClient()
const result = await client.search('coffee')
// console.log(result)
t.truthy(result?.webPages)
})