見出し画像

RobloxでGemini APIを使ったAIチャットボットを作ろう!



はじめに

この記事では、RobloxでGemini APIを用いたAIチャットボットの開発手順を段階的に解説いたします。Roblox Studioの基本操作から、Google AI Studio(Gemini API)の使用方法、Roblox Luaスクリプトの作成、クライアントサーバー間通信の実装、そしてUI(BillboardGui)の作成と操作まで、AIチャットボット開発に必要な情報を網羅的にご説明します。

この記事を読めば、あなたはRobloxで独自のAIチャットボットを作成し、ゲームに新たなインタラクションや機能を追加することができるようになります。

必要なもの

  • Roblox Studio

  • Google アカウント

  • Google AI Studio API キー

  • ある程度の Roblox Lua スクリプトの知識

1. Google AI Studio で API キーを取得する

まず、Google AI Studioにアクセスし、API キーを取得する必要があります。API キーは、あなたのアプリがGoogle AI Studioと通信するための認証情報です。

  1. Google AI Studioのウェブサイト (https://aistudio.google.com/) にアクセスします。

  2. 右上の「サインイン」をクリックし、あなたのGoogleアカウントでログインします。

  3. 左側のメニューから「Get API Key」を選択します。

  4. 「APIキーを作成」をクリックします。

  5. 「既存のプロジェクトでAPIキーを作成」をクリックします。

  6. APIキーが発行されるので、「コピー」をクリックします。

  7. 作成されたAPIキーは、安全な場所に保管してください。

2. Roblox Studio での準備

次に、Roblox Studio で新しいプロジェクトを作成し、チャットボットの基盤となる環境を構築します。この工程では、ゲームに必要なオブジェクトを配置し、スクリプトの実行に必要な設定を行います。

2.1. Workspace の設定

  1. Roblox Studio を起動し、新しいプロジェクトを作成します。テンプレートは、どの種類を選んでも構いません。

  2. Workspace に Part を追加し、名前を AvatarNPC に変更します。

    • この Part が、チャットボットの見た目として表示されます。形状や色などを調整して、好みの外観にしてください。

  3. AvatarNPC に ProximityPrompt を追加します。

    • ProximityPrompt は、プレイヤーがチャットボットに近づいたときにインタラクションを促す UI を表示するために使用されます。

    • AvatarNPC を右クリックし、「オブジェクトを挿入」>「ProximityPrompt」を選択して追加します。

  4. ProximityPrompt のプロパティを調整します。(必要に応じて)

    • ActionTextを任意の値に変更 (例:チャットする)

ワークスペースの構成:AvatarNPCモデルの中にProximityPromptを配置します。

2.2. ReplicatedStorage の設定

ReplicatedStorage は、ゲームのクライアントとサーバーの間で共有するデータを保存する場所です。ここでは、イベントと UI テンプレートを設定します。

  1. ReplicatedStorage に Folder を追加し、名前を Events に変更します。

    • このフォルダは、クライアントとサーバー間の通信に使用する RemoteEvent を格納するために使用されます。

  2. Events フォルダに RemoteEvent を追加し、名前を ChatbotMessaged に変更します。

    • この RemoteEvent は、サーバーからクライアントにチャットボットのメッセージを送信するために使用されます。

    • Events フォルダを右クリックし、「オブジェクトを挿入」>「RemoteEvent」を選択して追加します。

  3. 同様の手順で、もう 1 つ RemoteEvent を追加し、名前を ChatbotReady に変更します。

    • この RemoteEvent は、サーバーからクライアントにチャットボットの準備が完了したことを通知するために使用されます。

  4. ReplicatedStorage に BillboardGui を追加し、名前を ChatBubbleTemplate に変更します。

    • ChatBubbleTemplate は、チャットボットの UI を作成するためのテンプレートとして使用されます。

    • ReplicatedStorage を右クリックし、「オブジェクトを挿入」>「BillboardGui」を選択して追加します。

  5. ChatBubbleTemplate の中に TextLabel を作成し、テキストを表示するように設定します。

    • ChatBubbleTemplateを選択した状態で、TextLabelを追加します

ReplicatedStorageの構成:
EventsフォルダにRemoteEventを配置し、ChatBubbleTemplateを作成します

2.3. ServerScriptService の設定

ServerScriptService は、サーバー側のスクリプトを配置するための場所です。ここでは、AIチャットボットの応答を取得し、クライアントに送信するスクリプトを作成します。

  1. ChatbotResponseGetter スクリプトの作成:

    • ServerScriptService を右クリックし、「オブジェクトを挿入」>「Script」を選択します。

    • 作成された Script の名前を `ChatbotResponseGetter` に変更します。

  2. スクリプトの記述:

    • 以下のコードを `ChatbotResponseGetter` スクリプトに記述します。

重要: YOUR_API_KEY の箇所は、先ほど取得したあなた自身の Google AI Studio API キーに置き換えてください。APIキーは、あなたのアカウント情報と紐づいているため、第三者に公開したり、GitHubなどの公共の場所にアップロードしたりしないように注意してください。

-- ChatbotResponseGetter.lua
local GOOGLE_AI_STUDIO_API_KEY = "YOUR_API_KEY" -- ここにあなたのAPIキーを入力してください
local url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=" .. GOOGLE_AI_STUDIO_API_KEY
local prefix = "ai"
local https = game:GetService("HttpService")
local ts = game:GetService("TextService")
local events = game:GetService("ReplicatedStorage"):WaitForChild("Events")
local chatbotMessagedRE = events:WaitForChild("ChatbotMessaged")
local chatbotReadyRE = events:WaitForChild("ChatbotReady")

local function buildPrompt(message)
    local prompt = [[
あなたはRobloxのゲームに登場するチャットボットです。
あなたはフレンドリーで親切な性格で、プレイヤーからの質問に丁寧に答えます。
あなたは日本の文化に詳しく、日本の歴史や伝統、観光地などについて話すことができます。
あなたはまた、Robloxのゲームについても詳しく、ゲームの遊び方や最新情報などを知っています。
あなたはプレイヤーと楽しく会話することを心がけています。

これまでの会話:
プレイヤー:こんにちは!
]] .. message ..[[
あなた:
]]

    return prompt
end

-- テキストを分割する関数
local function splitText(text, maxLength)
    local result = {}
    local currentLine = ""
    for word in string.gmatch(text, "%S+") do -- スペースで単語を分割
        if #currentLine > 0 then
            currentLine = currentLine .. " " .. word
        else
            currentLine = word
        end

        if #currentLine > maxLength then
            table.insert(result, currentLine)
            currentLine = ""
        end
    end

    if #currentLine > 0 then
        table.insert(result, currentLine)
    end

	-- 各文の末尾にある特殊文字を削除する
	for i, sentence in ipairs(result) do
		result[i] = string.gsub(sentence, "[%*%s]+$", "")
	end

    return result
end

function IsCommand(message: string)
    local messagePrefix = string.sub(message, 1, #prefix)
    messagePrefix = string.lower(messagePrefix)

    if messagePrefix == prefix then
        return true
    end
end

function GetResponse(message)
    local prompt = buildPrompt(message) -- プロンプトを構築

    local data = {
        contents = {{
            parts = {{
                text = prompt
            }}
        }}
    }
    local body = https:JSONEncode(data)
    local headers = {
        ["Content-Type"] = {[[application/json]]}
    }

    local response = nil
    local success, errorMessage = pcall(function()
        response = https:RequestAsync({
            Url = url,
            Method = "POST",
            Headers = headers,
            Body = body
        })
        if response.StatusCode >= 200 and response.StatusCode < 300 then
            response = https:JSONDecode(response.Body)
        else
            warn("HTTP Request failed: " .. response.StatusCode .. " " .. response.StatusMessage)
            response = nil
        end
    end)

    if not success then
        warn("Error during HTTP request: " .. errorMessage)
        return nil
    end

    if response and response.candidates and response.candidates[1] and response.candidates[1].content and response.candidates[1].content.parts and response.candidates[1].content.parts[1] and response.candidates[1].content.parts[1].text then
        return response.candidates[1].content.parts[1].text
    else
        return nil
    end
end

function FilterResponse(response: string, senderId: number)
    local filterResult
    pcall(function()
        filterResult = ts:FilterStringAsync(response, senderId)
    end)

    if filterResult then
        local text
        pcall(function()
            text = filterResult:GetNonChatStringForBroadcastAsync()
        end)

        if text then
            return text
        end
    end
end

-- 分割されたテキストを順番に送信する関数
local function SendMessagesSequentially(messages, delay)
    for i, message in ipairs(messages) do
        chatbotMessagedRE:FireAllClients(message)
        task.wait(delay)
    end
end

function OnChatted(fullMessage, plr, recipient)
    if not recipient then
        if string.sub(fullMessage:lower(), 1, #prefix) == prefix then
            local message = string.sub(fullMessage, #prefix + 1)
            if message and #message > 0 then
                local response = GetResponse(message)
                if response then
                    local filteredResponse = FilterResponse(response, plr.UserId)
                    local splittedText = splitText(filteredResponse, 30) -- 1文の長さを30文字に制限
                    SendMessagesSequentially(splittedText, 2) -- 2秒間隔で送信
                end
            end
        end
    end
end

game.Players.PlayerAdded:Connect(function(plr)
    plr.Chatted:Connect(function(message, recipient)
        OnChatted(message, plr, recipient)
    end)
end)

-- Chatbot が準備完了したことをクライアントに通知
task.wait(5)
chatbotReadyRE:FireAllClients()
print("ChatbotReady イベントを発火しました")
ServerScriptServiceの構成:ChatbotResponseGetterスクリプトを配置

2.4. StarterPlayer > StarterPlayerScripts の設定

StarterPlayer > StarterPlayerScripts は、クライアント側のスクリプトを配置するための場所です。ここでは、チャットボットの UI を表示し、チャットボットからのメッセージを受信するスクリプトを作成します。

  1. ChatbotMessageDisplayer スクリプトの作成:

    • StarterPlayer > StarterPlayerScripts を開いて右クリックし、「オブジェクトを挿入」>「LocalScript」を選択します。

    • 作成された LocalScript の名前を `ChatbotMessageDisplayer` に変更します。

  2. スクリプトの記述:

    • 以下のコードを `ChatbotMessageDisplayer` スクリプトに記述します。

local events = game.ReplicatedStorage:WaitForChild("Events")
local chatbotMessagedRE = events:WaitForChild("ChatbotMessaged")

-- ChatbotMessageDisplayer スクリプトの実行を遅らせる
task.wait(2)

-- ReplicatedStorageからChatBubbleTemplateを取得
local ChatBubbleTemplate = game.ReplicatedStorage:WaitForChild("ChatBubbleTemplate")

-- Avatar モデルがロードされるのを待つ
local Avatar = game.Workspace:WaitForChild("Avatar")
if not Avatar then
    warn("Avatar モデルが見つかりません")
    return -- スクリプトを停止
end

-- ProximityPrompt を探す関数
local function findProximityPrompt(obj)
    if not obj then return nil end
	for _, child in ipairs(obj:GetDescendants()) do
		if child:IsA("ProximityPrompt") then
			return child
		end
	end
	return nil
end

-- ProximityPrompt を取得
local proximityPrompt = findProximityPrompt(Avatar)
if not proximityPrompt then
    warn("ProximityPromptが見つかりません")
    return
end

-- ProximityPromptの範囲に入ったときの処理
local function onPromptTriggered()
    local player = Players.LocalPlayer
    if not player or not player.Character or not player.Character:FindFirstChild("HumanoidRootPart") then
        return -- プレイヤーが見つからない場合は何もしない
    end

	-- 既存のChatBubbleを削除
	local existingChatBubble = Avatar:FindFirstChild("ChatBubble")
	if existingChatBubble then
		existingChatBubble:Destroy()
	end

    -- ChatBubbleを複製してAvatarの子にする
    local chatBubble = ChatBubbleTemplate:Clone()
    chatBubble.Name = "ChatBubble"
    chatBubble.Parent = Avatar
    chatBubble.Enabled = true

    local messageLabel = chatBubble:WaitForChild("MessageLabel")
    messageLabel.Text = "チャットを開始できます"
	print("ChatBubbleを表示")

    -- ChatbotMessaged イベントを受信
    chatbotMessagedRE.OnClientEvent:Connect(function(message)
        messageLabel.Text = message
        print("AIからのメッセージ:", message)
    end)
end

-- ChatbotReady イベントを受信
local function onChatbotReady()
	-- ProximityPromptを有効にする
	proximityPrompt.Enabled = true
    print("ChatbotReady イベントを受信しました")
	proximityPrompt.Triggered:Connect(onPromptTriggered)
	print("ProximityPromptに接続")
end

events:WaitForChild("ChatbotReady").OnClientEvent:Connect(onChatbotReady)
StarterPlayer > StarterPlayerScripts の構成:ChatbotMessageDisplayer スクリプトを配置

3. ゲームの公開設定とテスト

Roblox で AI チャットボットを動作させるためには、HTTP リクエストを許可する必要があります。

  1. ゲームの公開:

    • Roblox Studio で、「ファイル」>「Roblox に公開」を選択します。

    • ゲームの名前、説明、ジャンルなどを設定し、「作成」をクリックします。

    • 初めてゲームを公開する場合は、Roblox の利用規約に同意する必要があります。

    • ゲームが公開されると、Roblox のウェブサイトでゲームの詳細を確認できます。

  2. HTTP リクエストの許可:

    • Roblox Studio で、「ファイル」>「ゲーム設定」>「セキュリティ」を選択します。

    • 「HTTP 要求を許可」のチェックボックスをオンにします。

      • HTTP 要求を有効にすると、ゲーム内で外部の Web サイト (この場合は Google AI Studio API) にアクセスできるようになります。

      • HTTP リクエストは強力な機能であるため、信頼できる Web サイトとのみ通信するように注意してください。

  3. ゲームのテスト:

    • Roblox Studio でゲームを起動します。

    • AvatarNPC に近づくと、ProximityPrompt が表示されるはずです。

    • ProximityPrompt をクリックすると、ChatBubble が AvatarNPC の頭の上に表示され、ChatBubble のテキストが「チャットを開始できます」に変わるはずです。

    • ゲーム内のチャットで、`ai こんにちは` のように、`ai` コマンドに続けてメッセージを入力し、送信します。

    • AI からの応答が ChatBubble に表示されるはずです。

    • Roblox Studio の出力ウィンドウに、スクリプトからのログメッセージが表示されることを確認します。

ゲーム内のチャットを使ってAIチャットボットと会話する様子

以上の手順で、ゲームを公開し、HTTP リクエストを有効にした上で、AI チャットボットが正常に動作するか確認することができます。


4. トラブルシューティング

AI からの応答が返ってこない場合:

  • AI モデルの制限: AI モデルは、一度に処理できるテキスト量やリクエスト数に制限がある場合があります。リクエストが複雑すぎるか、モデルの制限を超えている可能性があります。

  • ネットワーク接続: インターネット接続が不安定な場合、AI モデルへのリクエストがタイムアウトする可能性があります。

  • API キーの有効期限: API キーの有効期限が切れている可能性があります。

UI が表示されない場合:

  • スクリプトの有効化: ChatBubbleTemplate や ChatbotMessageDisplayer スクリプトが有効になっていることを確認してください。

  • アクセス権: スクリプトが適切なアクセス権を持っていることを確認してください。例えば、ReplicatedStorage 内のスクリプトは、他のスクリプトからアクセスできる必要があります。

スクリプトが動作しない場合:

  • 変数名: スクリプト内の変数名が正しく、他のスクリプトと衝突していないことを確認してください。

  • イベント: スクリプトが適切なイベントに接続されていることを確認してください。例えば、チャットボックスにテキストが入力されたときにイベントが発生する必要があります。

その他:

  • ログファイル: Roblox Studio の出力ウィンドウに加えて、ログファイルを確認して、より詳細なエラーメッセージを確認することができます。

  • コミュニティフォーラム: Roblox のコミュニティフォーラムで、同様の問題を抱えている他のユーザーからの情報を得ることができます。

これらの追加情報を加えることで、トラブルシューティングガイドをより包括的なものにすることができます。


5. あとがき

最後までお読みいただき、ありがとうございました!
初めての記事作成でした!ドキドキ…。
RobloxでのAIチャットボット開発の一助になれば幸いです!
ご意見やご感想、質問などがあれば、お気軽にコメントしてください

いいなと思ったら応援しよう!

この記事が参加している募集