feat: add bing web search

pull/643/head^2
Travis Fischer 2024-06-05 20:41:27 -05:00
rodzic bc12a880a2
commit 963204728c
21 zmienionych plików z 371 dodań i 57 usunięć

Wyświetl plik

@ -16,7 +16,8 @@ import restoreCursor from 'restore-cursor'
// createTwitterV2Client,
// TwitterClient
// } from '../src/services/twitter/index.js'
import { MidjourneyClient } from '../src/index.js'
// import { MidjourneyClient } from '../src/index.js'
import { BingClient } from '../src/index.js'
/**
* Scratch pad for testing.
@ -98,10 +99,16 @@ async function main() {
// })
// console.log(res)
const midjourney = new MidjourneyClient()
const res = await midjourney.imagine(
'tiny lil baby kittens playing with an inquisitive AI robot, kawaii, anime'
)
// const midjourney = new MidjourneyClient()
// const res = await midjourney.imagine(
// 'tiny lil baby kittens playing with an inquisitive AI robot, kawaii, anime'
// )
// console.log(JSON.stringify(res, null, 2))
const bing = new BingClient()
const res = await bing.search({
q: 'world cup 2024 freestyle wrestling news'
})
console.log(JSON.stringify(res, null, 2))
}

Wyświetl plik

@ -123,6 +123,7 @@ The SDK-specific imports are all isolated to keep the main `@agentic/stdlib` as
## Services
- bing
- clearbit
- dexa
- diffbot

Wyświetl plik

@ -0,0 +1,305 @@
import defaultKy, { type KyInstance } from 'ky'
import { z } from 'zod'
import { aiFunction, AIFunctionsProvider } from '../fns.js'
import { assert, getEnv, omit } from '../utils.js'
export namespace bing {
export const API_BASE_URL = 'https://api.bing.microsoft.com'
export interface SearchQuery {
q: string
mkt?: string
offset?: number
count?: number
safeSearch?: 'Off' | 'Moderate' | 'Strict'
textDecorations?: boolean
textFormat?: 'Raw' | 'HTML'
}
export interface SearchResponse {
_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 BingClient extends AIFunctionsProvider {
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('BING_API_KEY'),
apiBaseUrl = bing.API_BASE_URL,
ky = defaultKy
}: {
apiKey?: string
apiBaseUrl?: string
ky?: KyInstance
} = {}) {
assert(
apiKey,
'BingClient missing required "apiKey" (defaults to "BING_API_KEY")'
)
super()
this.apiKey = apiKey
this.apiBaseUrl = apiBaseUrl
this.ky = ky.extend({
prefixUrl: this.apiBaseUrl
})
}
@aiFunction({
name: 'bing_web_search',
description:
'Searches the web using the Bing search engine to return the most relevant web pages for a given query. Can also be used to find up-to-date news and information about many topics.',
inputSchema: z.object({
q: z.string().describe('search query')
})
})
async search(queryOrOpts: string | bing.SearchQuery) {
const defaultQuery: Partial<bing.SearchQuery> = {
mkt: 'en-US'
}
const searchParams =
typeof queryOrOpts === 'string'
? {
...defaultQuery,
q: queryOrOpts
}
: {
...defaultQuery,
...queryOrOpts
}
// console.log(searchParams)
const res = await this.ky
.get('v7.0/search', {
headers: {
'Ocp-Apim-Subscription-Key': this.apiKey
},
searchParams
})
.json<bing.SearchResponse>()
return omit(res, 'rankingResponse')
}
}

Wyświetl plik

@ -361,9 +361,9 @@ export namespace clearbit {
}
export class ClearbitClient {
readonly ky: KyInstance
readonly apiKey: string
readonly _maxPageSize = 100
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly _maxPageSize = 100
static readonly PersonRoles = [
'communications',

Wyświetl plik

@ -13,9 +13,9 @@ export namespace dexa {
}
export class DexaClient extends AIFunctionsProvider {
readonly apiKey: string
readonly apiBaseUrl: string
readonly ky: KyInstance
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('DEXA_API_KEY'),

Wyświetl plik

@ -660,12 +660,12 @@ export namespace diffbot {
}
export class DiffbotClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly kyKnowledgeGraph: KyInstance
protected readonly ky: KyInstance
protected readonly kyKnowledgeGraph: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
readonly apiKnowledgeGraphBaseUrl: string
protected readonly apiKey: string
protected readonly apiBaseUrl: string
protected readonly apiKnowledgeGraphBaseUrl: string
constructor({
apiKey = getEnv('DIFFBOT_API_KEY'),

Wyświetl plik

@ -164,9 +164,9 @@ export namespace exa {
}
export class ExaClient extends AIFunctionsProvider {
readonly apiKey: string
readonly apiBaseUrl: string
readonly ky: KyInstance
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('EXA_API_KEY'),

Wyświetl plik

@ -88,9 +88,9 @@ export namespace firecrawl {
* @see https://github.com/mendableai/firecrawl
*/
export class FirecrawlClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('FIRECRAWL_API_KEY'),

Wyświetl plik

@ -1,3 +1,4 @@
export * from './bing-client.js'
export * from './clearbit-client.js'
export * from './dexa-client.js'
export * from './diffbot-client.js'

Wyświetl plik

@ -44,9 +44,9 @@ export namespace midjourney {
* @see https://www.imagineapi.dev
*/
export class MidjourneyClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('MIDJOURNEY_IMAGINE_API_KEY'),

Wyświetl plik

@ -450,9 +450,9 @@ export namespace peopledatalabs {
* @see https://www.peopledatalabs.com
*/
export class PeopleDataLabsClient {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('PEOPLE_DATA_LABS_API_KEY'),

Wyświetl plik

@ -626,8 +626,8 @@ export namespace perigon {
* @see https://www.goperigon.com/products/news-api
*/
export class PerigonClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
protected readonly ky: KyInstance
protected readonly apiKey: string
constructor({
apiKey = getEnv('PERIGON_API_KEY'),

Wyświetl plik

@ -476,9 +476,9 @@ export namespace predictleads {
}
export class PredictLeadsClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiToken: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiToken: string
constructor({
apiKey = getEnv('PREDICT_LEADS_API_KEY'),

Wyświetl plik

@ -2011,9 +2011,9 @@ export namespace proxycurl {
}
export class ProxycurlClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('PROXYCURL_API_KEY'),

Wyświetl plik

@ -40,8 +40,8 @@ export namespace scraper {
* proxies and JavaScript rendering if needed.
*/
export class ScraperClient extends AIFunctionsProvider {
readonly apiBaseUrl: string
readonly ky: KyInstance
protected readonly ky: KyInstance
protected readonly apiBaseUrl: string
constructor({
apiBaseUrl = getEnv('SCRAPER_API_BASE_URL'),

Wyświetl plik

@ -262,8 +262,8 @@ export namespace searxng {
* See [perplexica](https://github.com/ItzCrazyKns/Perplexica/blob/master/docker-compose.yaml) for an example.
*/
export class SearxngClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiBaseUrl: string
constructor({
apiBaseUrl = getEnv('SEARXNG_API_BASE_URL'),

Wyświetl plik

@ -634,10 +634,10 @@ export namespace serpapi {
* @see https://serpapi.com/search-api
*/
export class SerpAPIClient extends AIFunctionsProvider {
protected ky: KyInstance
protected apiKey: string
protected apiBaseUrl: string
protected params: serpapi.ClientParams
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
protected readonly params: serpapi.ClientParams
constructor({
apiKey = getEnv('SERPAPI_API_KEY') ?? getEnv('SERP_API_KEY'),

Wyświetl plik

@ -210,10 +210,10 @@ export namespace serper {
* @see https://serper.dev
*/
export class SerperClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
readonly params: serper.ClientParams
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
protected readonly params: serper.ClientParams
constructor({
apiKey = getEnv('SERPER_API_KEY'),

Wyświetl plik

@ -75,9 +75,9 @@ export namespace weatherapi {
}
export class WeatherClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly apiKey: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly apiKey: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('WEATHER_API_KEY'),

Wyświetl plik

@ -97,9 +97,9 @@ export namespace wikipedia {
}
export class WikipediaClient extends AIFunctionsProvider {
readonly apiBaseUrl: string
readonly apiUserAgent: string
readonly ky: KyInstance
protected readonly ky: KyInstance
protected readonly apiBaseUrl: string
protected readonly apiUserAgent: string
constructor({
apiBaseUrl = getEnv('WIKIPEDIA_API_BASE_URL') ??

Wyświetl plik

@ -29,9 +29,9 @@ export namespace wolfram {
* @see https://products.wolframalpha.com/llm-api/documentation
*/
export class WolframClient extends AIFunctionsProvider {
readonly ky: KyInstance
readonly appId: string
readonly apiBaseUrl: string
protected readonly ky: KyInstance
protected readonly appId: string
protected readonly apiBaseUrl: string
constructor({
appId = getEnv('WOLFRAM_APP_ID'),