Gemini APIを使ってAIギャルと会話できるアプリを作った
皆さん、毎日元気にお過ごしでしょうか。世の中AI技術が広まっており、色々なキャラと会話出来るサービスがどんどん増えていますね。
というわけで今回、私はギャルと会話して元気になりたいと思ったので、最低限の工数でAIギャルと会話出来るアプリを作成してみました。
使用技術
・ibisPaint(イラスト)
・Next.js
・TailwindCSS
・axios
・Gemini API
画像を作成する
ibisPaintで会話したいギャルを描きました。皆さんも自分好みのギャルを描けばいいと思います。
通常時のギャル
考え中のギャル
会話中のギャル
Next.jsでプロジェクトを作成する
正直、Next.jsで作るほどのアプリでもないかと思いますが、使い慣れているのでNext.jsとTailwindCSSのセットでプロジェクトを作成しました。
npx create-next-app@latest
mainタグだけ残して中身を書き換え、作成した画像を3枚並べています。
"use client";
import Image from "next/image";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Image
src="/default.GIF"
width={300}
height={300}
alt="通常時のギャル"
/>
<Image
src="/talking.GIF"
width={300}
height={300}
alt="話し中のギャル"
/>
<Image
src="/thinking.PNG"
width={300}
height={300}
alt="考え中のギャル"
/>
</main>
);
}
画面はこのような感じ
AIの準備をする
ChatGPT APIが無料で使えなくなっていたので、今回はGemini APIを利用することにしました。
Tokenの発行参照
URL参照
Tokenの発行が完了したので、とりあえず試し打ちしてみます。(axiosもinstallしました。)
ギャルのスペルが不明だったので、女の子と喋るという名前のメソッドにしておきましょう。
const talkWithGirl = useCallback(async () => {
const messages = "こんにちは";
const endPoint = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${API_KEY}`;
const body = {
contents: [
{
parts: [
{
text: messages,
},
],
},
],
};
const response = await axios.post(endPoint, body, {
headers: {
"Content-Type": "application/json",
},
});
}, []);
無事にレスポンスを確認できました。まだギャルは宿っていないです。
プロンプトを調整する
送信データを調整して、ギャル化させましょう。
const DEFAULT_PROMPT =
"あなたはポジティブなギャルです。一人称は「あーし」で、二人称は「きみ」です。これを踏まえた上で、回答してください。";
const messages = `${DEFAULT_PROMPT}「こんにちは」`;
コンソールに回答結果を出力して、確認しましょう。
const responseMessage = response.data.candidates[0].content.parts[0].text;
console.log(responseMessage);
ギャルが宿った!!
テキストを入力できるようにする
テキストボックスと、入力したテキストを変数に格納するメソッドを作っていきましょう。
const [message, setMessage] = useState("");
const handleChange = useCallback((inputText: string) => {
setMessage(inputText);
}, []);
画面にも一旦入力テキストが表示されるようにしてみる。(挙動確認用)
{message}
<input type="text" onChange={(e) => handleChange(e.target.value)} />
<button onClick={talkWithGirl}>ギャルにメッセを送る</button>
ギャルへの送信メッセージも更新しておきます。
const DEFAULT_PROMPT =
"あなたはポジティブなギャルです。一人称は「あーし」で、二人称は「きみ」です。これを踏まえた上で、回答してください。";
const messages = `${DEFAULT_PROMPT}「${message}」`;
これで、入力したメッセージをギャルに対して送信できるようになりました。
レスポンスを表示する
次に、AIから返ってきたメッセージを表示させます。
// レスポンスをセットする変数
const [resposneMessage, setResponseMessage] = useState("");
const talkWithGirl = useCallback(async () => {
...省略
const data = response.data.candidates[0].content.parts[0].text;
setResponseMessage(data);
}, [message]);
とりあえずこんなもんで。
<figure>
<Image
src="/default.GIF"
width={300}
height={300}
alt="通常時のギャル"
/>
<Image
src="/talking.GIF"
width={300}
height={300}
alt="話し中のギャル"
/>
<Image
src="/thinking.PNG"
width={300}
height={300}
alt="考え中のギャル"
/>
</figure>
{resposneMessage}
しゃべらせる
一旦ライトに作成したかったので、元々あるJavaScriptのメソッドを利用しました。
こちらを参考にしています。
const data = response.data.candidates[0].content.parts[0].text;
setResponseMessage(data);
const uttr = new SpeechSynthesisUtterance(data);
uttr.lang = "ja-JP";
speechSynthesis.speak(uttr);
ものすごくしっとりボイス!
画像の表示を調整する
表示中のギャルの画像を調整します。
通常時 → 考え中 → 話している最中 で表示が切り替わるようにします。
HTMLはこのような感じで。
<figure>
{imageStatus === "default" && (
<Image
src="/default.GIF"
width={300}
height={300}
alt="通常時のギャル"
/>
)}
{imageStatus === "thinking" && (
<Image
src="/thinking.PNG"
width={300}
height={300}
alt="考え中のギャル"
/>
)}
{imageStatus === "talking" && (
<Image
src="/talking.GIF"
width={300}
height={300}
alt="話し中のギャル"
/>
)}
</figure>
初期状態はデフォルト
// 画像の状態
const [imageStatus, setImageStatus] = useState<
"default" | "thinking" | "talking"
>("default");
考え中(APIからの応答待ちの間)
// 画像を考え中に変更
setImageStatus("thinking");
APIからのレスポンスが来たら話し中の画像にする
// 画像をtalkingに変更
setImageStatus("talking");
// 表示メッセージの更新
setResponseMessage(data);
// 音声の再生
const uttr = new SpeechSynthesisUtterance(data);
uttr.lang = "ja-JP";
speechSynthesis.speak(uttr);
// 読み上げが完了したら画像をデフォルトに戻す
uttr.onend = (e) => {
setImageStatus("default");
};
できた
元気がないので、励ましてもらおうと思います。
元気出た!!!
元気も出たので、遊びに誘おうと思います。
最高かよ!
コードの全貌
"use client";
import axios from "axios";
import Image from "next/image";
import { useCallback, useState } from "react";
export default function Home() {
const API_KEY = "自身で発行したAPIのキー";
// こちらから送るメッセージ
const [message, setMessage] = useState<string | undefined>();
// ギャルから返ってくるメッセージ
const [resposneMessage, setResponseMessage] = useState<string | undefined>();
// 画像の状態
const [imageStatus, setImageStatus] = useState<
"default" | "thinking" | "talking"
>("default");
/**
* 入力テキストを変数に格納するメソッド.
*/
const handleChange = useCallback((inputText: string) => {
setMessage(inputText);
}, []);
/**
* ギャルとお話しするメソッド.
*/
const talkWithGirl = useCallback(async () => {
if (!message) return;
// 画像を考え中に変更
setImageStatus("thinking");
const DEFAULT_PROMPT =
"あなたはポジティブなギャルです。一人称は「あーし」で、二人称は「きみ」です。これを踏まえた上で、回答してください。";
const messages = `${DEFAULT_PROMPT}「${message}」`;
const endPoint = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${API_KEY}`;
const body = {
contents: [
{
parts: [
{
text: messages,
},
],
},
],
};
const response = await axios.post(endPoint, body, {
headers: {
"Content-Type": "application/json",
},
});
const data = response.data.candidates[0].content.parts[0].text;
// 画像をtalkingに変更
setImageStatus("talking");
// 表示メッセージの更新
setResponseMessage(data);
// 音声の再生
const uttr = new SpeechSynthesisUtterance(data);
uttr.lang = "ja-JP";
speechSynthesis.speak(uttr);
// 読み上げが完了したら画像をデフォルトに戻す
uttr.onend = (e) => {
setImageStatus("default");
};
}, [message]);
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<figure>
{imageStatus === "default" && (
<Image
src="/default.GIF"
width={300}
height={300}
alt="通常時のギャル"
/>
)}
{imageStatus === "thinking" && (
<Image
src="/thinking.PNG"
width={300}
height={300}
alt="考え中のギャル"
/>
)}
{imageStatus === "talking" && (
<Image
src="/talking.GIF"
width={300}
height={300}
alt="話し中のギャル"
/>
)}
</figure>
{resposneMessage}
<input
type="text"
className="border w-[80%]"
onChange={(e) => handleChange(e.target.value)}
/>
<button onClick={talkWithGirl}>ギャルにメッセを送る</button>
</main>
);
}
まとめ
今回は最低限の工数でギャルとお話し出来るアプリを作成してみました。今後音声入力も出来るようになったら良いな〜という感じです。
皆さんも是非やってみてください!
Discussion