kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add SerpAPI as a tool
rodzic
bebbdfbd49
commit
0fa8b3a9b8
|
@ -8,7 +8,7 @@ import defaultKy from 'ky'
|
||||||
export type BaseResponse<P = Record<string | number | symbol, never>> = {
|
export type BaseResponse<P = Record<string | number | symbol, never>> = {
|
||||||
search_metadata: {
|
search_metadata: {
|
||||||
id: string
|
id: string
|
||||||
status: 'Queued' | 'Processing' | 'Success'
|
status: string | 'Queued' | 'Processing' | 'Success'
|
||||||
json_endpoint: string
|
json_endpoint: string
|
||||||
created_at: string
|
created_at: string
|
||||||
processed_at: string
|
processed_at: string
|
||||||
|
@ -24,9 +24,6 @@ export type BaseResponse<P = Record<string | number | symbol, never>> = {
|
||||||
pagination?: {
|
pagination?: {
|
||||||
next: string
|
next: string
|
||||||
}
|
}
|
||||||
next?: (
|
|
||||||
callback?: (json: BaseResponse<P>) => void
|
|
||||||
) => Promise<BaseResponse<P>>
|
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +330,7 @@ export type GoogleParameters = BaseParameters & {
|
||||||
* Parameter defines the maximum number of results to return. (e.g., `10` (default)
|
* Parameter defines the maximum number of results to return. (e.g., `10` (default)
|
||||||
* returns 10 results, `40` returns 40 results, and `100` returns 100 results).
|
* returns 10 results, `40` returns 40 results, and `100` returns 100 results).
|
||||||
*/
|
*/
|
||||||
num?: string
|
num?: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page Number (images)
|
* Page Number (images)
|
||||||
|
@ -345,8 +342,270 @@ export type GoogleParameters = BaseParameters & {
|
||||||
ijn?: string
|
ijn?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SearchResult extends BaseResponse<GoogleParameters> {
|
||||||
|
search_metadata: SearchMetadata
|
||||||
|
search_parameters: SearchParameters
|
||||||
|
search_information: SearchInformation
|
||||||
|
local_map?: LocalMap
|
||||||
|
local_results?: LocalResults
|
||||||
|
answer_box?: AnswerBox
|
||||||
|
knowledge_graph?: KnowledgeGraph
|
||||||
|
inline_images?: InlineImage[]
|
||||||
|
inline_people_also_search_for?: InlinePeopleAlsoSearchFor[]
|
||||||
|
related_questions?: SearchResultRelatedQuestion[]
|
||||||
|
organic_results: OrganicResult[]
|
||||||
|
related_searches?: RelatedSearch[]
|
||||||
|
pagination: Pagination
|
||||||
|
serpapi_pagination: Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnswerBox {
|
||||||
|
type: string
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
displayed_link: string
|
||||||
|
snippet: string
|
||||||
|
snippet_highlighted_words: string[]
|
||||||
|
images: string[]
|
||||||
|
about_this_result: AboutThisResult
|
||||||
|
about_page_link: string
|
||||||
|
cached_page_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InlineImage {
|
||||||
|
link: string
|
||||||
|
source: string
|
||||||
|
thumbnail: string
|
||||||
|
original: string
|
||||||
|
source_name: string
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InlinePeopleAlsoSearchFor {
|
||||||
|
title: string
|
||||||
|
items: SearchItem[]
|
||||||
|
see_more_link: string
|
||||||
|
see_more_serpapi_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchItem {
|
||||||
|
name: string
|
||||||
|
image: string
|
||||||
|
link: string
|
||||||
|
serpapi_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KnowledgeGraph {
|
||||||
|
type: string
|
||||||
|
kgmid: string
|
||||||
|
knowledge_graph_search_link: string
|
||||||
|
serpapi_knowledge_graph_search_link: string
|
||||||
|
header_images: HeaderImage[]
|
||||||
|
description: string
|
||||||
|
source: Source
|
||||||
|
buttons: Button[]
|
||||||
|
people_also_search_for: SearchItem[]
|
||||||
|
people_also_search_for_link: string
|
||||||
|
people_also_search_for_stick: string
|
||||||
|
list: { [key: string]: string[] }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Button {
|
||||||
|
text: string
|
||||||
|
subtitle: string
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
displayed_link: string
|
||||||
|
snippet?: string
|
||||||
|
snippet_highlighted_words?: string[]
|
||||||
|
answer?: string
|
||||||
|
thumbnail: string
|
||||||
|
search_link: string
|
||||||
|
serpapi_search_link: string
|
||||||
|
date?: string
|
||||||
|
list?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeaderImage {
|
||||||
|
image: string
|
||||||
|
source: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Source {
|
||||||
|
name: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalMap {
|
||||||
|
link: string
|
||||||
|
image: string
|
||||||
|
gps_coordinates: LocalMapGpsCoordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalMapGpsCoordinates {
|
||||||
|
latitude: number
|
||||||
|
longitude: number
|
||||||
|
altitude: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalResults {
|
||||||
|
places: Place[]
|
||||||
|
more_locations_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Place {
|
||||||
|
position: number
|
||||||
|
title: string
|
||||||
|
rating?: number
|
||||||
|
reviews_original?: string
|
||||||
|
reviews?: number
|
||||||
|
place_id: string
|
||||||
|
place_id_search: string
|
||||||
|
lsig: string
|
||||||
|
thumbnail: string
|
||||||
|
gps_coordinates: PlaceGpsCoordinates
|
||||||
|
service_options: ServiceOptions
|
||||||
|
address?: string
|
||||||
|
type?: string
|
||||||
|
hours?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlaceGpsCoordinates {
|
||||||
|
latitude: number
|
||||||
|
longitude: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceOptions {
|
||||||
|
dine_in?: boolean
|
||||||
|
takeout: boolean
|
||||||
|
no_delivery?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrganicResult {
|
||||||
|
position: number
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
displayed_link: string
|
||||||
|
thumbnail?: string
|
||||||
|
favicon?: string
|
||||||
|
snippet: string
|
||||||
|
snippet_highlighted_words: string[]
|
||||||
|
sitelinks?: Sitelinks
|
||||||
|
rich_snippet?: RichSnippet
|
||||||
|
about_this_result: AboutThisResult
|
||||||
|
cached_page_link: string
|
||||||
|
related_pages_link?: string
|
||||||
|
source: string
|
||||||
|
related_results?: RelatedResult[]
|
||||||
|
date?: string
|
||||||
|
related_questions?: OrganicResultRelatedQuestion[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AboutThisResult {
|
||||||
|
keywords: string[]
|
||||||
|
languages: string[]
|
||||||
|
regions: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrganicResultRelatedQuestion {
|
||||||
|
question: string
|
||||||
|
snippet: string
|
||||||
|
snippet_links: SnippetLink[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SnippetLink {
|
||||||
|
text: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelatedResult {
|
||||||
|
position: number
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
displayed_link: string
|
||||||
|
snippet: string
|
||||||
|
snippet_highlighted_words: string[]
|
||||||
|
about_this_result: AboutThisResult
|
||||||
|
cached_page_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RichSnippet {
|
||||||
|
bottom: Bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Bottom {
|
||||||
|
extensions?: string[]
|
||||||
|
questions?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Sitelinks {
|
||||||
|
inline: Inline[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Inline {
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Pagination {
|
||||||
|
current: number
|
||||||
|
next: string
|
||||||
|
other_pages: { [key: string]: string }
|
||||||
|
next_link?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchResultRelatedQuestion {
|
||||||
|
question: string
|
||||||
|
snippet: string
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
displayed_link: string
|
||||||
|
thumbnail: string
|
||||||
|
next_page_token: string
|
||||||
|
serpapi_link: string
|
||||||
|
date?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelatedSearch {
|
||||||
|
query: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchInformation {
|
||||||
|
organic_results_state: string
|
||||||
|
query_displayed: string
|
||||||
|
total_results: number
|
||||||
|
time_taken_displayed: number
|
||||||
|
menu_items: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MenuItem {
|
||||||
|
position: number
|
||||||
|
title: string
|
||||||
|
link: string
|
||||||
|
serpapi_link?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchMetadata {
|
||||||
|
id: string
|
||||||
|
status: string
|
||||||
|
json_endpoint: string
|
||||||
|
created_at: string
|
||||||
|
processed_at: string
|
||||||
|
google_url: string
|
||||||
|
raw_html_file: string
|
||||||
|
total_time_taken: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchParameters {
|
||||||
|
engine: string
|
||||||
|
q: string
|
||||||
|
google_domain: string
|
||||||
|
device?: 'desktop' | 'tablet' | 'mobile'
|
||||||
|
}
|
||||||
|
|
||||||
export type SerpAPIParams = Omit<GoogleParameters, 'q'>
|
export type SerpAPIParams = Omit<GoogleParameters, 'q'>
|
||||||
export type SerpAPISearchResponse = BaseResponse<GoogleParameters>
|
export type SerpAPISearchResponse = SearchResult
|
||||||
|
|
||||||
export interface SerpAPIClientOptions extends Partial<SerpAPIParams> {
|
export interface SerpAPIClientOptions extends Partial<SerpAPIParams> {
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
|
@ -387,9 +646,14 @@ export class SerpAPIClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async search(queryOrOpts: string | { query: string }) {
|
async search(queryOrOpts: string | GoogleParameters) {
|
||||||
const query =
|
const defaultGoogleParams: Partial<GoogleParameters> = {
|
||||||
typeof queryOrOpts === 'string' ? queryOrOpts : queryOrOpts.query
|
num: 10
|
||||||
|
}
|
||||||
|
const options: GoogleParameters =
|
||||||
|
typeof queryOrOpts === 'string'
|
||||||
|
? { ...defaultGoogleParams, q: queryOrOpts }
|
||||||
|
: queryOrOpts
|
||||||
const { timeout, ...rest } = this.params
|
const { timeout, ...rest } = this.params
|
||||||
|
|
||||||
return this.api
|
return this.api
|
||||||
|
@ -398,7 +662,7 @@ export class SerpAPIClient {
|
||||||
...rest,
|
...rest,
|
||||||
engine: 'google',
|
engine: 'google',
|
||||||
api_key: this.apiKey,
|
api_key: this.apiKey,
|
||||||
q: query
|
...(options as any) // TODO
|
||||||
},
|
},
|
||||||
timeout
|
timeout
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,12 +7,11 @@ import { BaseTask } from '@/task'
|
||||||
export const CalculatorInputSchema = z.object({
|
export const CalculatorInputSchema = z.object({
|
||||||
expression: z.string().describe('mathematical expression to evaluate')
|
expression: z.string().describe('mathematical expression to evaluate')
|
||||||
})
|
})
|
||||||
|
export type CalculatorInput = z.infer<typeof CalculatorInputSchema>
|
||||||
|
|
||||||
export const CalculatorOutputSchema = z
|
export const CalculatorOutputSchema = z
|
||||||
.number()
|
.number()
|
||||||
.describe('result of calculating the expression')
|
.describe('result of calculating the expression')
|
||||||
|
|
||||||
export type CalculatorInput = z.infer<typeof CalculatorInputSchema>
|
|
||||||
|
|
||||||
export type CalculatorOutput = z.infer<typeof CalculatorOutputSchema>
|
export type CalculatorOutput = z.infer<typeof CalculatorOutputSchema>
|
||||||
|
|
||||||
export class CalculatorTool extends BaseTask<
|
export class CalculatorTool extends BaseTask<
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { SerpAPIClient } from '@/services/serpapi'
|
||||||
|
|
||||||
import { ky } from '../_utils'
|
import { ky } from '../_utils'
|
||||||
|
|
||||||
test('SerpAPIClient.search', async (t) => {
|
test('SerpAPIClient.search - coffee', async (t) => {
|
||||||
if (!process.env.SERPAPI_API_KEY) {
|
if (!process.env.SERPAPI_API_KEY) {
|
||||||
return t.pass()
|
return t.pass()
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,21 @@ test('SerpAPIClient.search', async (t) => {
|
||||||
const client = new SerpAPIClient({ ky })
|
const client = new SerpAPIClient({ ky })
|
||||||
|
|
||||||
const result = await client.search('coffee')
|
const result = await client.search('coffee')
|
||||||
// console.log(result)
|
// console.log(JSON.stringify(result, null, 2))
|
||||||
t.truthy(result)
|
t.truthy(result.organic_results)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('SerpAPIClient.search - answer box', async (t) => {
|
||||||
|
if (!process.env.SERPAPI_API_KEY) {
|
||||||
|
return t.pass()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.timeout(2 * 60 * 1000)
|
||||||
|
const client = new SerpAPIClient({ ky })
|
||||||
|
|
||||||
|
const result = await client.search(
|
||||||
|
'how many planets are there in the milky way?'
|
||||||
|
)
|
||||||
|
// console.log(JSON.stringify(result, null, 2))
|
||||||
|
t.truthy(result.answer_box)
|
||||||
})
|
})
|
||||||
|
|
Ładowanie…
Reference in New Issue