kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add weather api service
rodzic
19cb765db1
commit
64afe1d441
|
@ -8,6 +8,7 @@ import { isValidTaskIdentifier } from '@/utils'
|
||||||
|
|
||||||
// TODO: this needs work + testing
|
// TODO: this needs work + testing
|
||||||
// TODO: move to isolated module
|
// TODO: move to isolated module
|
||||||
|
// TODO compare with https://gist.github.com/rileytomasek/4811b5fdd9c82c4730c191317ea76411
|
||||||
export async function getNumTokensForChatMessages({
|
export async function getNumTokensForChatMessages({
|
||||||
messages,
|
messages,
|
||||||
model,
|
model,
|
||||||
|
|
|
@ -5,3 +5,4 @@ export * from './novu'
|
||||||
export * from './serpapi'
|
export * from './serpapi'
|
||||||
export * from './slack'
|
export * from './slack'
|
||||||
export * from './twilio-conversation'
|
export * from './twilio-conversation'
|
||||||
|
export * from './weather'
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import defaultKy from 'ky'
|
||||||
|
|
||||||
|
export const WEATHER_API_BASE_URL = 'http://api.weatherapi.com/v1'
|
||||||
|
|
||||||
|
interface CurrentWeatherResponse {
|
||||||
|
current: CurrentWeather
|
||||||
|
location: WeatherLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CurrentWeather {
|
||||||
|
cloud: number
|
||||||
|
condition: WeatherCondition
|
||||||
|
feelslike_c: number
|
||||||
|
feelslike_f: number
|
||||||
|
gust_kph: number
|
||||||
|
gust_mph: number
|
||||||
|
humidity: number
|
||||||
|
is_day: number
|
||||||
|
last_updated: string
|
||||||
|
last_updated_epoch: number
|
||||||
|
precip_in: number
|
||||||
|
precip_mm: number
|
||||||
|
pressure_in: number
|
||||||
|
pressure_mb: number
|
||||||
|
temp_c: number
|
||||||
|
temp_f: number
|
||||||
|
uv: number
|
||||||
|
vis_km: number
|
||||||
|
vis_miles: number
|
||||||
|
wind_degree: number
|
||||||
|
wind_dir: string
|
||||||
|
wind_kph: number
|
||||||
|
wind_mph: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeatherCondition {
|
||||||
|
code: number
|
||||||
|
icon: string
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeatherLocation {
|
||||||
|
country: string
|
||||||
|
lat: number
|
||||||
|
localtime: string
|
||||||
|
localtime_epoch: number
|
||||||
|
lon: number
|
||||||
|
name: string
|
||||||
|
region: string
|
||||||
|
tz_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeatherIPInfoResponse {
|
||||||
|
ip: string
|
||||||
|
type: string
|
||||||
|
continent_code: string
|
||||||
|
continent_name: string
|
||||||
|
country_code: string
|
||||||
|
country_name: string
|
||||||
|
is_eu: string
|
||||||
|
geoname_id: number
|
||||||
|
city: string
|
||||||
|
region: string
|
||||||
|
lat: number
|
||||||
|
lon: number
|
||||||
|
tz_id: string
|
||||||
|
localtime_epoch: number
|
||||||
|
localtime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WeatherClient {
|
||||||
|
api: typeof defaultKy
|
||||||
|
|
||||||
|
apiKey: string
|
||||||
|
apiBaseUrl: string
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
apiKey = process.env.WEATHER_API_KEY,
|
||||||
|
apiBaseUrl = WEATHER_API_BASE_URL,
|
||||||
|
ky = defaultKy
|
||||||
|
}: {
|
||||||
|
apiKey?: string
|
||||||
|
apiBaseUrl?: string
|
||||||
|
ky?: typeof defaultKy
|
||||||
|
} = {}) {
|
||||||
|
if (!apiKey) {
|
||||||
|
throw new Error(`Error WeatherClient missing required "apiKey"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.apiKey = apiKey
|
||||||
|
this.apiBaseUrl = apiBaseUrl
|
||||||
|
|
||||||
|
this.api = ky.extend({ prefixUrl: apiBaseUrl })
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentWeather(queryOrOptions: string | { q: string }) {
|
||||||
|
const options =
|
||||||
|
typeof queryOrOptions === 'string'
|
||||||
|
? { q: queryOrOptions }
|
||||||
|
: queryOrOptions
|
||||||
|
|
||||||
|
return this.api
|
||||||
|
.get('current.json', {
|
||||||
|
searchParams: {
|
||||||
|
key: this.apiKey,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.json<CurrentWeatherResponse>()
|
||||||
|
}
|
||||||
|
|
||||||
|
async ipInfo(ipOrOptions: string | { q: string }) {
|
||||||
|
const options =
|
||||||
|
typeof ipOrOptions === 'string' ? { q: ipOrOptions } : ipOrOptions
|
||||||
|
|
||||||
|
return this.api
|
||||||
|
.get('ip.json', {
|
||||||
|
searchParams: {
|
||||||
|
key: this.apiKey,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.json<WeatherIPInfoResponse>()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import test from 'ava'
|
||||||
|
|
||||||
|
import { WeatherClient } from '@/services'
|
||||||
|
|
||||||
|
import { ky } from '../_utils'
|
||||||
|
|
||||||
|
test('WeatherClient.getCurrentWeather', async (t) => {
|
||||||
|
if (!process.env.WEATHER_API_KEY) {
|
||||||
|
return t.pass()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.timeout(2 * 60 * 1000)
|
||||||
|
const client = new WeatherClient({ ky })
|
||||||
|
|
||||||
|
const result = await client.getCurrentWeather('Seattle')
|
||||||
|
// console.log(result)
|
||||||
|
t.truthy(result.current)
|
||||||
|
t.truthy(result.location)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('WeatherClient.ipInfo', async (t) => {
|
||||||
|
if (!process.env.WEATHER_API_KEY) {
|
||||||
|
return t.pass()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.timeout(2 * 60 * 1000)
|
||||||
|
const client = new WeatherClient({ ky })
|
||||||
|
|
||||||
|
const res = await client.ipInfo('52.119.125.215')
|
||||||
|
t.truthy(res.ip)
|
||||||
|
t.truthy(res.city)
|
||||||
|
t.truthy(res.lat)
|
||||||
|
t.truthy(res.lon)
|
||||||
|
})
|
Ładowanie…
Reference in New Issue