自分専用ChatGPTを構築してみた
自分専用ChatGPTを構築してみた
たまたま見つけた
を利用したら、ChatGPTっぽいUIが比較的簡単に構築できそうだったので、リポジトリをForkしつつ、自分専用ChatGPTを構築してみました。
本記事は簡単な開発ログです。
できたものはこちら:
ChatGPTライクなUIを構築する
基本的に https://github.com/mckaywrigley/chatbot-ui のREADMEに従えば簡単に環境構築ができます。Next.js + TypeScriptで構築されていて、必要なライブラリや環境変数のセットをするだけでシュッと動きました。
今回は後にログイン必須で使えるようにすることを想定しているので、リポジトリをForkして開発をしていきます。
Auth0の導入 (インフラ編)
まず初めに、Next.jsのフロントエンドにAuth0認証機能を導入する際、以下の選択肢がありました。
こちらの記事を参考にしたのと、自分自身 auth0-reactを使った経験があったので今回は auth0-react を採用していきます。
Auth0の構築自体はこちらを参考にすればすぐできるのですが、念の為コマンドラインでAuth0にデプロイできるようにしていきます。auth0-deploy-cliを使えば実現できることは知っていたので、そちらも導入します。
新たにauth0というディレクトリを作り、そこにAuth0用のpackage.json
を作成しておきます。
{
"private": true,
"devDependencies": {
"auth0-deploy-cli": "^7.17.1"
},
"scripts": {
"a0deploy": "npx a0deploy deploy -c config.json -i tenant.yaml",
"export": "npx a0deploy export"
}
}
そしてAuth0のダッシュボード側でMachine to Machineのdeploy専用アプリを作っておき、auth0/config.json
に以下の情報をセットしておきます。
{
"AUTH0_DOMAIN": "xxx",
"AUTH0_CLIENT_ID": "xxx",
"AUTH0_CLIENT_SECRET": "xxx"
}
あとは 初回のみ npm run export
をして、tenant.yaml
を取得し、あとはそれを使って、npm run a0deploy
でAuth0へのdeployができるようになります。新たに今回のNext.jsアプリ用にAuth0側にSPAのアプリケーション環境を構築し、開発環境、本番環境用の許可するcallback URL、logout URL、web origins URLなどを登録しておきます (詳しくはGitHubの tenant.yaml
を見てみてください)。
Auth0の導入 (フロントエンド編)
.env.local
に新たに
NEXT_PUBLIC_AUTH0_DOMAIN=''
NEXT_PUBLIC_AUTH0_CLIENT_ID=''
を追加し、pages/_app.tsx
に Auth0Provider
を絡めていきます。
function App({ Component, pageProps }: AppProps<{}>) {
const onRedirectCallback = (appState?: AppState) => {
// Use Next.js's Router.replace method to replace the url
Router.replace(appState?.returnTo || '/');
};
return (
<Auth0Provider
domain={process.env["NEXT_PUBLIC_AUTH0_DOMAIN"] || ""}
clientId={process.env["NEXT_PUBLIC_AUTH0_CLIENT_ID"] || ""}
authorizationParams={{
redirect_uri:
typeof window !== 'undefined' ? window.location.origin : undefined,
}}
onRedirectCallback={onRedirectCallback}
>
<div className={inter.className}>
<Toaster />
<Component {...pageProps} />
</div>
</Auth0Provider>
);
}
export default appWithTranslation(App);
あとは pages/index.tsx
側で
// Auth --------------------------------------------
const { isAuthenticated, loginWithRedirect } = useAuth0();
return (
<>
<Head>
<title>Chatbot UI</title>
<meta name="description" content="ChatGPT but better." />
<meta
name="viewport"
content="height=device-height ,width=device-width, initial-scale=1, user-scalable=no"
/>
<link rel="icon" href="/favicon.ico" />
</Head>
{isAuthenticated && selectedConversation && (
<main
className={`flex h-screen w-screen flex-col text-sm text-white dark:text-white ${lightMode}`}
>
...
}
{!isAuthenticated && (
<div className='flex justify-center h-screen w-screen items-center'>
<button type="button" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800" onClick={() => loginWithRedirect()}>Login</button>
</div>
)}
みたいなノリで、Userの認証有無によって分岐してやればやりたいことは実現できました。
認証Userの情報やログアウトボタンもせっかくなのでつけたかったので、components/Chatbar/ChatbarSettings.tsx
を少し改良。
export const ChatbarSettings: FC<Props> = ({
lightMode,
apiKey,
conversationsCount,
onToggleLightMode,
onApiKeyChange,
onClearConversations,
onExportConversations,
onImportConversations,
}) => {
const { t } = useTranslation('sidebar');
const { logout, user } = useAuth0();
return (
<div className="flex flex-col items-center space-y-1 border-t border-white/20 pt-1 text-sm">
{user && (
<SidebarButton
text={user.nickname || user.name || 'Anonymus'}
icon={<IconUser size={18} />}
onClick={() => void(0)}
/>
)}
...
<SidebarButton
text="Logout"
icon={<IconLogout size={18} />}
onClick={() => logout()}
/>
...
</div>
);
};
Vercelでデプロイ
これはVercelへの登録さえ終わっていれば、必要なAuth0やOpenAI API keyなどを環境変数にセットしておくだけでめちゃめちゃ簡単にデプロイできるので割愛。
まとめ
Next.jsアプリケーションにAuth0を導入するだけで簡単にやりたいことが実現できました。
特にFork元の https://github.com/mckaywrigley/chatbot-ui の実装が神で pages/api/chat.ts
あたりの実装はOpenAIのtiktokenなどをこう使うのか、だったりstreamの扱いをどう実装しているか、などが垣間見えてめっちゃ勉強になります。
私はまだOn waitlistなのですが、API経由でGPT-4が開放されればさらに精度も期待できそうです。
Discussion