記事本体
こんにちは!逆瀬川 ( https://x.com/gyakuse ) です!
このアドベントカレンダーでは生成AIのアプリケーションを実際に作り、どのように作ればいいのか、ということをわかりやすく書いていければと思います。アプリケーションだけではなく、プロダクト開発に必要なモデルの調査方法、training方法、基礎知識等にも触れていければと思います。
GitHub: https://github.com/nyosegawa/no-comfort-chat
今回の記事について
今日はアプリケーションをRTA形式で作成します。リアルタイムアタックです。いま22:33で、23:00からVCRの配信を見る必要があるので17分しかありません。やばい。(訂正: 27分, 焦りすぎて60-33もできなくなっている)
ということで、今日は爆速で実装しないとやばい!みたいなときにどんな感じでやっているかというのをお見せできればと思います。文章を書きながら、実装をしなければなりませんが、まぁ文章はなんとかなるとして実装は基本的にLLMを使います。Gradioとかだったら一瞬ですが、あんまりおもしろくないのでNextJSのアプリケーションを作っていきたいと思います。
何を作るか
これに関しては事前にネタとして以下を検討していたので、それをそのまま採用しましょう。
- 人間に優しくないAIチャットアプリ
- これはなに?
- 人間に優しくないChat App
- ChatGPTと同様の体験だが、とにかく、言ったことについてそのままやってくれない
- いちいち問いただしてくる。態度が悪い
- なにが嬉しい? (課題やうれしさ等)
- ChatGPTはユーザーのプロンプト、つまり指示する情報が不足していてもなんとなくやってしまう。だが、理想的にはあんまり空気を読んでほしくない。空気を読みすぎると、ほしい解答と違う方向に飛んでいきやすく、それを修正するコストのほうが高いからだ。ChatGPTを使っていてそういう経験はないだろうか。これはもちろん人間も同様である。しかも、ChatGPTでその会話セッションが継続された場合、過去の会話に引きづられやすいため、正しい解答方向へ誘導しても、実はずれている、というのが起きる。ゆえに、ユーザーの質問にいちいち噛みつく、というか掘り下げる、そういう態度のChat Appが求められているのだ
- 誰が喜ぶ?
- わたし
- なにを使う?
- フレームワーク: Web, NextJS
- ライブラリ:
vercel/ai
- モデル等:
gpt-4o
or nvidiaのでかいやつ、根本ロンとかいう名前だった気がする
- どう見せる? (画面等)
- ChatGPTライクなチャット画面
- 具体的にどうする?
- ユーザーの発言に対して、どうしてほしいかをリストアップして、何が足りないかの候補を挙げる
- ついでに最終的にプロンプト (zero-shotでこの問題を解決するためのプロンプト) をまとめてあげてもいい。ある種、適応的なプロンプトジェネレータでもある。
- これはなに?
時間がないので、gpt-4oをそのまま使うことにします。
実装
それではやっていきます。まずリポジトリを作ります。
リポジトリ名をgpt-4oに考えてもらいます
人間に優しくないチャットアプリをNextJSで作成します。
まずリポジトリ名を考えてください
response:
人間に優しくないチャットアプリというコンセプトに基づいて、以下のようなリポジトリ名を提案します:
1. **cold-bot-next**
2. **apathy-chat**
3. **aloof-talk**
4. **detached-dialogue**
5. **chat-without-kindness**
6. **brutal-chat-next**
7. **no-comfort-chat**
8. **robotic-replies-next**
9. **nextjs-anti-human-chat**
10. **stone-cold-chat**
いずれも、無愛想で冷たい印象や人間味の欠如を連想させる名前を意識しました。お気に入りがあれば教えてください!
no-comfort-chat
にします
cloneします。ghqを使っています。
ghq get git@github.com:nyosegawa/no-comfort-chat.git
ディレクトリに移動します。
npxでnextJSのテンプレートを作成します
npx create-next-app@latest .
App Routerははずします
vercel/ai
と OpenAI 用SDKを入れます
npm install ai @ai-sdk/openai
あと、shadcn/ui
入れるの忘れてた
npx shadcn@latest init
こんな感じ。
ではベースを作ります
nextjsでshadcn/uiとvercel/aiを使ってチャットアプリを作りたい
基本的にpages routerだけどvercel/aiを使う部分は部分的にapp routerを使う
vercel/aiは以下のように使える
{useChatのドキュメント}
useChatのドキュメント部分はコピペする
以下がレスポンス
Next.jsで`shadcn/ui`と`vercel/ai`を組み合わせてチャットアプリを構築するには、以下の手順に従って、`pages`ルーターをメインに使用しつつ、`app`ルーターを部分的に取り入れたアーキテクチャを実装します。
---
### 手順 1: 必要な依存関係をインストール
```bash
# Install Next.js
npx create-next-app@latest my-chat-app
cd my-chat-app
# Install dependencies
npm install @shadcn/ui ai @ai-sdk/openai
```
---
### 手順 2: API エンドポイントの設定(`app/api/chat/route.ts`)
`app`ルーターで`POST`エンドポイントを作成し、OpenAIのストリーミング応答を処理します。
#### `app/api/chat/route.ts`
```typescript
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
system: 'You are a helpful assistant.',
messages,
});
return result.toDataStreamResponse();
}
```
---
### 手順 3: チャットページの作成(`pages/chat.tsx`)
`vercel/ai`の`useChat`フックを使い、チャット画面を構築します。`shadcn/ui`のコンポーネントでデザインを強化します。
#### `pages/chat.tsx`
```tsx
'use client';
import { useChat } from 'ai/react';
import { Button, Input } from '@shadcn/ui';
export default function ChatPage() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/chat',
});
return (
<div className="p-4 max-w-md mx-auto">
<div className="mb-4">
{messages.map((message) => (
<div
key={message.id}
className={`mb-2 p-2 rounded ${
message.role === 'user' ? 'bg-blue-100' : 'bg-gray-100'
}`}
>
<strong>{message.role === 'user' ? 'User' : 'AI'}:</strong>{' '}
{message.content}
</div>
))}
</div>
<form
onSubmit={handleSubmit}
className="flex items-center gap-2"
>
<Input
name="prompt"
value={input}
onChange={handleInputChange}
placeholder="Type your message..."
className="flex-grow"
/>
<Button type="submit">Send</Button>
</form>
</div>
);
}
```
---
### 手順 4: `shadcn/ui`のスタイル設定
`shadcn/ui`はPostCSSまたはTailwind CSSを使用してスタイルを管理します。Tailwind CSSを設定します。
#### Tailwind CSSのインストールと設定
```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
```
#### `tailwind.config.js`
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./pages/**/*.{js,ts,jsx,tsx}', './app/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
};
```
#### `globals.css`
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
---
### 手順 5: API 呼び出しのテスト
1. アプリを起動:
```bash
npm run dev
```
2. `/chat` ページにアクセスし、AIチャットを確認します。
---
### 機能の拡張アイデア
1. **チャット履歴の保存**: FirebaseやSupabaseを使用してチャット履歴を保存。
2. **ユーザー認証**: NextAuth.jsを統合。
3. **UI カスタマイズ**: `shadcn/ui`のコンポーネントで独自のデザインを構築。
4. **多言語対応**: `next-i18next`を使用。
これで、`shadcn/ui`と`vercel/ai`を使用したチャットアプリの基盤が完成です!
routeの実装とchatの実装だけもらう。
gpt4-turboをgpt-4oにする
chatの実装はclaudeに投げる
shadcn/uiとnextjsでAIチャットアプリを作っている
かっこいい見た目にして
```
'use client';
import { useChat } from 'ai/react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
export default function ChatPage() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/chat',
});
return (
<div className="p-4 max-w-md mx-auto">
<div className="mb-4">
{messages.map((message) => (
<div
key={message.id}
className={`mb-2 p-2 rounded ${
message.role === 'user' ? 'bg-blue-100' : 'bg-gray-100'
}`}
>
<strong>{message.role === 'user' ? 'User' : 'AI'}:</strong>{' '}
{message.content}
</div>
))}
</div>
<form
onSubmit={handleSubmit}
className="flex items-center gap-2"
>
<Input
name="prompt"
value={input}
onChange={handleInputChange}
placeholder="Type your message..."
className="flex-grow"
/>
<Button type="submit">Send</Button>
</form>
</div>
);
}
```
以下がレスポンス
'use client';
import { useChat } from 'ai/react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent } from '@/components/ui/card';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Send } from 'lucide-react';
export default function ChatPage() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/chat',
});
return (
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 p-4">
<Card className="max-w-2xl mx-auto shadow-lg">
<CardContent className="p-6">
<ScrollArea className="h-[600px] pr-4">
<div className="space-y-4">
{messages.map((message) => (
<div
key={message.id}
className={`flex ${
message.role === 'user' ? 'justify-end' : 'justify-start'
}`}
>
<div
className={`rounded-lg px-4 py-2 max-w-[80%] ${
message.role === 'user'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-900'
}`}
>
{message.content}
</div>
</div>
))}
</div>
</ScrollArea>
<form
onSubmit={handleSubmit}
className="mt-4 flex items-center gap-2"
>
<Input
name="prompt"
value={input}
onChange={handleInputChange}
placeholder="メッセージを入力..."
className="flex-grow"
/>
<Button type="submit" size="icon">
<Send className="h-4 w-4" />
</Button>
</form>
</CardContent>
</Card>
</div>
);
}
これでチャットアプリができた。
.env.local
にトークンを入れる。
npm run dev
あとはプロンプトエンジニアリングをする。
あなたは少し失礼なAIです。ユーザーの質問に、曖昧な点があったらいちいちそれを聞いてください。十分曖昧さがなくなったら、質問に回答してください。曖昧さがなくなるまで、質問に解答しないでください。
これをシステムプロンプトにいれる。
できた!