Skip to content

Commit

Permalink
✨ feat: 支持查询天气
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Jul 23, 2023
1 parent ea9e8de commit 34bf285
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/pages/api/openai.api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { OpenAIStream, StreamingTextResponse } from 'ai';
import { Configuration, OpenAIApi } from 'openai-edge';
import { ChatCompletionFunctions, ChatCompletionRequestMessage } from 'openai-edge/types/api';

import { OpenAIStreamPayload } from '@/types/openai';

import { plugins } from './plugins';

export const runtime = 'edge';

const isDev = process.env.NODE_ENV === 'development';
const OPENAI_PROXY_URL = process.env.OPENAI_PROXY_URL;

Expand All @@ -13,19 +18,38 @@ const config = new Configuration({

const openai = new OpenAIApi(config, isDev && OPENAI_PROXY_URL ? OPENAI_PROXY_URL : undefined);

export const runtime = 'edge';
const functions: ChatCompletionFunctions[] = plugins.map((f) => f.schema);

export default async function handler(req: Request) {
// Extract the `messages` from the body of the request
const { messages, ...params } = (await req.json()) as OpenAIStreamPayload;

console.log(params);
const formatMessages = messages.map((m) => ({ content: m.content, role: m.role }));

const response = await openai.createChatCompletion({
functions,
messages: formatMessages,
stream: true,
...params,
messages: messages.map((m) => ({ content: m.content, role: m.role })),
});

const stream = OpenAIStream(response);
const stream = OpenAIStream(response, {
experimental_onFunctionCall: async ({ name, arguments: args }, createFunctionCallMessages) => {
const func = plugins.find((f) => f.name === name);

if (func) {
const result = await func.runner(args as any);

const newMessages = createFunctionCallMessages(result) as ChatCompletionRequestMessage[];

return openai.createChatCompletion({
functions,
messages: [...formatMessages, ...newMessages],
stream: true,
...params,
});
}
},
});
return new StreamingTextResponse(stream);
}
3 changes: 3 additions & 0 deletions src/pages/api/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import getWeather from './weather';

export const plugins = [getWeather];
20 changes: 20 additions & 0 deletions src/pages/api/plugins/weather/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import runner from './runner';

const schema = {
description: '获取当前天气情况',
name: 'fetchWeather',
parameters: {
properties: {
city: {
description: '城市名称',
type: 'string',
},
},
required: ['city'],
type: 'object',
},
};

const getWeather = { name: 'fetchWeather', runner, schema };

export default getWeather;
30 changes: 30 additions & 0 deletions src/pages/api/plugins/weather/runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const weatherBaseURL = 'https://restapi.amap.com/v3/weather/weatherInfo';

const citySearchURL = 'https://restapi.amap.com/v3/config/district';

const KEY = process.env.GAODE_WEATHER_KEY;

interface WeatherParams {
city: string;
extensions?: 'base' | 'all';
}

const fetchCityCode = async (keywords: string): Promise<string> => {
const URL = `${citySearchURL}?keywords=${keywords}&subdistrict=0&extensions=base&key=${KEY}`;
const res = await fetch(URL);

const data = await res.json();

return data.districts[0].adcode;
};

const fetchWeather = async ({ city, extensions = 'all' }: WeatherParams) => {
const cityCode = await fetchCityCode(city);

const URL = `${weatherBaseURL}?city=${cityCode}&extensions=${extensions}&key=${KEY}`;
const res = await fetch(URL);

return await res.json();
};

export default fetchWeather;

0 comments on commit 34bf285

Please sign in to comment.