kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/643/head^2
rodzic
a5bf1736a9
commit
1a90a1e129
|
@ -29,7 +29,8 @@ async function main() {
|
||||||
|
|
||||||
const wikipedia = new WikipediaClient()
|
const wikipedia = new WikipediaClient()
|
||||||
const res = await wikipedia.getPageSummary({
|
const res = await wikipedia.getPageSummary({
|
||||||
title: 'Naruto_(TV_series)'
|
// title: 'Naruto_(TV_series)'
|
||||||
|
title: 'SpaceX'
|
||||||
})
|
})
|
||||||
console.log(JSON.stringify(res, null, 2))
|
console.log(JSON.stringify(res, null, 2))
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import type * as types from './types.ts'
|
import type * as types from './types.ts'
|
||||||
import { AIFunctionsProvider } from './fns.js'
|
import { AIFunctionsProvider } from './fns.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of AI functions intended to make it easier to work with large sets of
|
||||||
|
* AI functions across different clients.
|
||||||
|
*
|
||||||
|
* This class mimics a built-in `Set<AIFunction>`, but with additional utility
|
||||||
|
* methods like `pick`, `omit`, and `map`.
|
||||||
|
*/
|
||||||
export class AIFunctionSet implements Iterable<types.AIFunction> {
|
export class AIFunctionSet implements Iterable<types.AIFunction> {
|
||||||
protected readonly _map: Map<string, types.AIFunction>
|
protected readonly _map: Map<string, types.AIFunction>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { AIFunctionSet } from './ai-function-set.js'
|
||||||
import { createAIFunction } from './create-ai-function.js'
|
import { createAIFunction } from './create-ai-function.js'
|
||||||
import { assert } from './utils.js'
|
import { assert } from './utils.js'
|
||||||
|
|
||||||
export interface Invocable {
|
export interface PrivateAIFunctionMetadata {
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
inputSchema: z.AnyZodObject
|
inputSchema: z.AnyZodObject
|
||||||
|
@ -21,7 +21,8 @@ export abstract class AIFunctionsProvider {
|
||||||
if (!this._functions) {
|
if (!this._functions) {
|
||||||
const metadata = this.constructor[Symbol.metadata]
|
const metadata = this.constructor[Symbol.metadata]
|
||||||
assert(metadata)
|
assert(metadata)
|
||||||
const invocables = (metadata?.invocables as Invocable[]) ?? []
|
const invocables =
|
||||||
|
(metadata?.invocables as PrivateAIFunctionMetadata[]) ?? []
|
||||||
// console.log({ metadata, invocables })
|
// console.log({ metadata, invocables })
|
||||||
|
|
||||||
const aiFunctions = invocables.map((invocable) => {
|
const aiFunctions = invocables.map((invocable) => {
|
||||||
|
@ -71,7 +72,7 @@ export function aiFunction<
|
||||||
if (!context.metadata.invocables) {
|
if (!context.metadata.invocables) {
|
||||||
context.metadata.invocables = []
|
context.metadata.invocables = []
|
||||||
}
|
}
|
||||||
;(context.metadata.invocables as Invocable[]).push({
|
;(context.metadata.invocables as PrivateAIFunctionMetadata[]).push({
|
||||||
name: name ?? methodName,
|
name: name ?? methodName,
|
||||||
description,
|
description,
|
||||||
inputSchema,
|
inputSchema,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import defaultKy, { type KyInstance } from 'ky'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
|
||||||
import { aiFunction, AIFunctionsProvider } from '../fns.js'
|
import { aiFunction, AIFunctionsProvider } from '../fns.js'
|
||||||
import { assert, getEnv } from '../utils.js'
|
import { assert, getEnv, omit } from '../utils.js'
|
||||||
|
|
||||||
export namespace serper {
|
export namespace serper {
|
||||||
export const BASE_URL = 'https://google.serper.dev'
|
export const BASE_URL = 'https://google.serper.dev'
|
||||||
|
@ -13,10 +13,25 @@ export namespace serper {
|
||||||
gl: z.string().default('us').optional(),
|
gl: z.string().default('us').optional(),
|
||||||
hl: z.string().default('en').optional(),
|
hl: z.string().default('en').optional(),
|
||||||
page: z.number().int().positive().default(1).optional(),
|
page: z.number().int().positive().default(1).optional(),
|
||||||
num: z.number().int().positive().default(10).optional()
|
num: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.positive()
|
||||||
|
.default(10)
|
||||||
|
.optional()
|
||||||
|
.describe('number of results to return')
|
||||||
})
|
})
|
||||||
export type SearchParams = z.infer<typeof SearchParamsSchema>
|
export type SearchParams = z.infer<typeof SearchParamsSchema>
|
||||||
|
|
||||||
|
export const GeneralSearchSchema = SearchParamsSchema.extend({
|
||||||
|
type: z
|
||||||
|
.enum(['search', 'images', 'videos', 'places', 'news', 'shopping'])
|
||||||
|
.default('search')
|
||||||
|
.optional()
|
||||||
|
.describe('Type of Google search to perform')
|
||||||
|
})
|
||||||
|
export type GeneralSearchParams = z.infer<typeof GeneralSearchSchema>
|
||||||
|
|
||||||
export interface SearchResponse {
|
export interface SearchResponse {
|
||||||
searchParameters: SearchParameters & { type: 'search' }
|
searchParameters: SearchParameters & { type: 'search' }
|
||||||
organic: Organic[]
|
organic: Organic[]
|
||||||
|
@ -233,12 +248,19 @@ export class SerperClient extends AIFunctionsProvider {
|
||||||
name: 'serper_google_search',
|
name: 'serper_google_search',
|
||||||
description:
|
description:
|
||||||
'Uses Google Search 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.',
|
'Uses Google Search 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: serper.SearchParamsSchema.pick({
|
inputSchema: serper.GeneralSearchSchema.pick({
|
||||||
q: true
|
q: true,
|
||||||
|
num: true,
|
||||||
|
type: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
async search(queryOrOpts: string | serper.SearchParams) {
|
async search(queryOrOpts: string | serper.GeneralSearchParams) {
|
||||||
return this._fetch<serper.SearchResponse>('search', queryOrOpts)
|
const searchType =
|
||||||
|
typeof queryOrOpts === 'string' ? 'search' : queryOrOpts.type || 'search'
|
||||||
|
return this._fetch<serper.SearchResponse>(
|
||||||
|
searchType,
|
||||||
|
typeof queryOrOpts === 'string' ? queryOrOpts : omit(queryOrOpts, 'type')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchImages(queryOrOpts: string | serper.SearchParams) {
|
async searchImages(queryOrOpts: string | serper.SearchParams) {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import defaultKy, { type KyInstance } from 'ky'
|
import defaultKy, { type KyInstance } from 'ky'
|
||||||
import pThrottle from 'p-throttle'
|
import pThrottle from 'p-throttle'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
import { aiFunction, AIFunctionsProvider } from '../fns.js'
|
||||||
import { assert, getEnv, throttleKy } from '../utils.js'
|
import { assert, getEnv, throttleKy } from '../utils.js'
|
||||||
|
|
||||||
export namespace wikipedia {
|
export namespace wikipedia {
|
||||||
// Only allow 200 requests per second
|
// Only allow 200 requests per second by default.
|
||||||
export const throttle = pThrottle({
|
export const throttle = pThrottle({
|
||||||
limit: 200,
|
limit: 200,
|
||||||
interval: 1000
|
interval: 1000
|
||||||
|
@ -94,7 +96,7 @@ export namespace wikipedia {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WikipediaClient {
|
export class WikipediaClient extends AIFunctionsProvider {
|
||||||
readonly apiBaseUrl: string
|
readonly apiBaseUrl: string
|
||||||
readonly apiUserAgent: string
|
readonly apiUserAgent: string
|
||||||
readonly ky: KyInstance
|
readonly ky: KyInstance
|
||||||
|
@ -114,6 +116,7 @@ export class WikipediaClient {
|
||||||
} = {}) {
|
} = {}) {
|
||||||
assert(apiBaseUrl, 'WikipediaClient missing required "apiBaseUrl"')
|
assert(apiBaseUrl, 'WikipediaClient missing required "apiBaseUrl"')
|
||||||
assert(apiUserAgent, 'WikipediaClient missing required "apiUserAgent"')
|
assert(apiUserAgent, 'WikipediaClient missing required "apiUserAgent"')
|
||||||
|
super()
|
||||||
|
|
||||||
this.apiBaseUrl = apiBaseUrl
|
this.apiBaseUrl = apiBaseUrl
|
||||||
this.apiUserAgent = apiUserAgent
|
this.apiUserAgent = apiUserAgent
|
||||||
|
@ -127,6 +130,13 @@ export class WikipediaClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@aiFunction({
|
||||||
|
name: 'wikipedia_search',
|
||||||
|
description: 'Searches Wikipedia for pages matching the given query.',
|
||||||
|
inputSchema: z.object({
|
||||||
|
query: z.string().describe('Search query')
|
||||||
|
})
|
||||||
|
})
|
||||||
async search({ query, ...opts }: wikipedia.SearchOptions) {
|
async search({ query, ...opts }: wikipedia.SearchOptions) {
|
||||||
return (
|
return (
|
||||||
// https://www.mediawiki.org/wiki/API:REST_API
|
// https://www.mediawiki.org/wiki/API:REST_API
|
||||||
|
@ -138,12 +148,26 @@ export class WikipediaClient {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@aiFunction({
|
||||||
|
name: 'wikipedia_get_page_summary',
|
||||||
|
description: 'Gets a summary of the given Wikipedia page.',
|
||||||
|
inputSchema: z.object({
|
||||||
|
title: z.string().describe('Wikipedia page title'),
|
||||||
|
acceptLanguage: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default('en-us')
|
||||||
|
.describe('Locale code for the language to use.')
|
||||||
|
})
|
||||||
|
})
|
||||||
async getPageSummary({
|
async getPageSummary({
|
||||||
title,
|
title,
|
||||||
acceptLanguage = 'en-us',
|
acceptLanguage = 'en-us',
|
||||||
redirect = true,
|
redirect = true,
|
||||||
...opts
|
...opts
|
||||||
}: wikipedia.PageSummaryOptions) {
|
}: wikipedia.PageSummaryOptions) {
|
||||||
|
title = title.trim().replaceAll(' ', '_')
|
||||||
|
|
||||||
// https://en.wikipedia.org/api/rest_v1/
|
// https://en.wikipedia.org/api/rest_v1/
|
||||||
return this.ky
|
return this.ky
|
||||||
.get(`page/summary/${title}`, {
|
.get(`page/summary/${title}`, {
|
||||||
|
|
Ładowanie…
Reference in New Issue