diff --git a/src/config.ts b/src/config.ts index 86bd26d..0174350 100644 --- a/src/config.ts +++ b/src/config.ts @@ -14,6 +14,7 @@ type Config = { mecabDic?: string; memoryDir?: string; earthQuakeMonitorPort?: number; + openAiApiKey?: string; }; const config = require('../config.json'); diff --git a/src/constants/ENDPOINTS.ts b/src/constants/ENDPOINTS.ts new file mode 100644 index 0000000..85ef559 --- /dev/null +++ b/src/constants/ENDPOINTS.ts @@ -0,0 +1,5 @@ +const ENDPOINTS = { + OPEN_AI: 'https://api.openai.com/v1', +} as const; + +export default ENDPOINTS; diff --git a/src/constants/GPT3_MODELS.ts b/src/constants/GPT3_MODELS.ts new file mode 100644 index 0000000..3a4f274 --- /dev/null +++ b/src/constants/GPT3_MODELS.ts @@ -0,0 +1,11 @@ +/** + * @see https://beta.openai.com/docs/models/overview + */ +const GPT3_MODELS = { + davinci: 'text-davinci-003', + curie: 'text-curie-001', + babbage: 'text-babbage-001', + ada: 'text-ada-001', +}; + +export default GPT3_MODELS; diff --git a/src/index.ts b/src/index.ts index 96ef87e..e2bf4fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,6 +39,7 @@ import Earthquake from './modules/earthquake'; import DicModule from './modules/dic'; import MenuModule from './modules/menu'; import GetColorModule from './modules/color'; +import ChatGPT from './modules/chatGPT'; console.log(' __ ____ _____ ___ '); console.log(' /__\\ (_ _)( _ )/ __)'); @@ -72,6 +73,7 @@ promiseRetry((retry) => { new 藍(account, [ new CoreModule(), new ReminderModule(), + new ChatGPT(), new SummonCat(), new EmojiModule(), new EmojiReactModule(), diff --git a/src/modules/chatGPT/index.ts b/src/modules/chatGPT/index.ts new file mode 100644 index 0000000..058ef2c --- /dev/null +++ b/src/modules/chatGPT/index.ts @@ -0,0 +1,29 @@ +import autobind from 'autobind-decorator'; +import Module from '@/module'; +import Message from '@/message'; +import fetchChatGPT from '@/utils/fetchChatGPT'; + +class ChatGPT extends Module { + public readonly name = 'ChatGPT'; + + @autobind + public install() { + return { + mentionHook: this.mentionHook, + }; + } + + @autobind + private async mentionHook(msg: Message) { + if (msg.text && (msg.text.includes('ChatGPT'))) { + // msg.textから"ChatGPT "を削除 + const prompt = msg.text.replace('ChatGPT ', ''); + msg.reply(await fetchChatGPT({prompt})); + return true; + } else { + return false; + } + } +} + +export default ChatGPT; diff --git a/src/utils/fetchChatGPT.ts b/src/utils/fetchChatGPT.ts new file mode 100644 index 0000000..b15cf05 --- /dev/null +++ b/src/utils/fetchChatGPT.ts @@ -0,0 +1,42 @@ +import {isNil} from 'lodash'; +import ENDPOINTS from '@/constants/ENDPOINTS.js'; +import GPT3_MODELS from '@/constants/GPT3_MODELS.js'; +import config from '@/config'; + +const COMPLETION_ENDPOINT = `${ENDPOINTS.OPEN_AI}/completions`; + +// 0~1 +const TEMPERATURE = 0.9; +// 2048 or 4000 +const MAX_TOKENS = 4000; + +/** + * @see https://beta.openai.com/docs/api-reference/completions/create + */ +async function fetchChatGPT({prompt}: {prompt: string}): Promise { + if (isNil(config.openAiApiKey)) { + return '利用する準備ができていないようです...?'; + } + const options = { + model: GPT3_MODELS.davinci, + max_tokens: MAX_TOKENS, + temperature: TEMPERATURE, + prompt, + }; + + const response = await fetch(COMPLETION_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${config.openAiApiKey}`, + }, + body: JSON.stringify(options), + }); + + const results = await response.json(); + // results.choicesの中からランダムに返す + const randomIndex = Math.floor(Math.random() * results.choices.length); + return results.choices[randomIndex].text; +} + +export default fetchChatGPT;