近年、人工知能技術の進化に伴い、多くの人々が日常生活やビジネスシーンでAIを活用するようになりました。今回は、GPTs(Generative Pre-trained Transformers)、GAS(Google Apps Script)、そしてGemini Proを組み合わせて、LINE上で動作するLLM(Large Language Model)Bot「幻(げん)」を作成する方法を紹介します。
デモ動画
GPTsとGASのオウム返しBotを進化させる
初めに、GPTsとGASを使用したシンプルなオウム返しBotの基本的な構造から始めます。このBotは、ユーザーからのメッセージを受け取り、そのメッセージをそのまま返すという単純な機能を持っています。しかし、この基本的な機能をGemini Proの力を借りて、より高度な対話能力を持つBotへと進化させることが可能です。
GPTsとGASのコード解説
GASを用いた開発では、主にGoogle Apps Scriptを使用しています。以下に示すコードブロックは、LINE Botの基本的な設定や、スプレッドシートへのログ記録、Gemini APIへのリクエストを行うための関数などを含んでいます。
// LINE Bot設定
const LINE_CONFIG = {
token: PropertiesService.getScriptProperties().getProperty("LINE_TOKEN"),
url: 'https://api.line.me/v2/bot/message/reply'
};
// スプレッドシート設定
const SPREADSHEET_CONFIG = {
id: 'YYYYYYYYYYYYYYYYYYYYYYYYYYY',
systemSheetName: "SYSTEM",
messageSheetName: "message"
};
// メッセージを処理
function processMessage(message) {
if (!message) {
return { error: "Invalid request. Please provide a message." };
}
const responseMessage = getGeminiApiResponse(message);
logMessageToSheet(new Date(), message, responseMessage);
return { echo: responseMessage };
}
このコードは、LINEから受け取ったメッセージをGemini APIに送信し、得られたレスポンスをユーザーに返信する処理を行います。また、通信の履歴をスプレッドシートに保存する機能も備えています。
LINE Bot設定
// LINE Bot設定
const LINE_CONFIG = {
token: PropertiesService.getScriptProperties().getProperty("LINE_TOKEN"),
url: 'https://api.line.me/v2/bot/message/reply'
};
この部分では、LINE BotのアクセストークンとAPIのエンドポイントURLを設定しています。PropertiesService.getScriptProperties().getProperty("LINE_TOKEN")
は、スクリプトのプロパティに保存されたLINE_TOKEN
を取得しています。これにより、LINE Platformとの認証を可能にします。
スプレッドシート設定
// スプレッドシート設定
const SPREADSHEET_CONFIG = {
id: 'YYYYYYYYYYYYYYYYYYYYYYYYYYY',
systemSheetName: "SYSTEM",
messageSheetName: "message"
};
ここでは、使用するスプレッドシートのIDと、システム情報およびメッセージログを保存するためのシート名を設定しています。
システムプロンプトを取得
// システムプロンプトを取得
function getSystemPrompt() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SPREADSHEET_CONFIG.systemSheetName);
return sheet.getRange("A2").getValue();
}
getSystemPrompt
関数では、設定したスプレッドシートのSYSTEM
シートから、特定のセル(A2
)の値を取得します。この値は、後続の処理でGemini APIへのリクエストに使用されるプロンプトとして機能します。
メッセージを処理
// メッセージを処理
function processMessage(message) {
if (!message) {
return { error: "Invalid request. Please provide a message." };
}
const responseMessage = getGeminiApiResponse(message);
logMessageToSheet(new Date(), message, responseMessage);
return { echo: responseMessage };
}
processMessage
関数は、受け取ったメッセージを処理し、それに対する応答を生成します。メッセージが無効な場合はエラーを返し、有効な場合はGemini APIを通じて応答を取得し、それをログに記録した後、応答を返します。
スプレッドシートにメッセージを記録
// スプレッドシートにメッセージを記録
function logMessageToSheet(timestamp, message, response) {
const ss = SpreadsheetApp.openById(SPREADSHEET_CONFIG.id);
const sheet = ss.getSheetByName(SPREADSHEET_CONFIG.messageSheetName);
sheet.appendRow([timestamp, message, response]);
}
この関数は、処理されたメッセージとその応答をスプレッドシートに記録します。これにより、Botの対話履歴を追跡できます。
doGet関数の改善版
// doGet関数の改善版
function doGet(e) {
const response = processMessage(e.parameter.message);
return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}
doGet
関数は、HTTP GETリクエストを処理し、クエリパラメータとして受け取ったメッセージをprocessMessage
関数に渡して処理します。その結果をJSON形式で返します。
Gemini APIへのリクエストを行い、レスポンスを返す関数
// Gemini APIへのリクエストを行い、レスポンスを返す関数
function getGeminiApiResponse(prompt = 'あなたができることは何ですか?') {
// 省略...
}
getGeminiApiResponse
関数では、Gemini APIに対してHTTP POSTリクエストを行い、受け取ったプロンプトに基づいた応答を取得します。この関数の内部で、APIキーの取得、APIエンドポイントの設定、リクエストの送信、およびレスポンスの処理が行われます。
このコードは、Google Apps Scriptを使ってLINE Botを構築し、Gemini APIを介して動的な応答を生成するプロセスを示しています。LINEからのメッセージを受け取り、それに基づいてGemini APIにリクエストを送信し、得られた応答をユーザーに返す仕組みを構築しています。
全体コード
// LINE Bot設定
const LINE_CONFIG = {
token: PropertiesService.getScriptProperties().getProperty("LINE_TOKEN"),
url: 'https://api.line.me/v2/bot/message/reply'
};
// スプレッドシート設定
const SPREADSHEET_CONFIG = {
id: 'YYYYYYYYYYYYYYYYYYYYYYYYYYY',
systemSheetName: "SYSTEM",
messageSheetName: "message"
};
// システムプロンプトを取得
function getSystemPrompt() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SPREADSHEET_CONFIG.systemSheetName);
return sheet.getRange("A2").getValue();
}
// メッセージを処理
function processMessage(message) {
if (!message) {
return { error: "Invalid request. Please provide a message." };
}
const responseMessage = getGeminiApiResponse(message);
logMessageToSheet(new Date(), message, responseMessage);
return { echo: responseMessage };
}
// スプレッドシートにメッセージを記録
function logMessageToSheet(timestamp, message, response) {
const ss = SpreadsheetApp.openById(SPREADSHEET_CONFIG.id);
const sheet = ss.getSheetByName(SPREADSHEET_CONFIG.messageSheetName);
sheet.appendRow([timestamp, message, response]);
}
// doGet関数の改善版
function doGet(e) {
const response = processMessage(e.parameter.message);
return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}
// Gemini APIへのリクエストを行い、レスポンスを返す関数
function getGeminiApiResponse(prompt = 'あなたができることは何ですか?') {
// スクリプトプロパティからAPIキーを取得
const apiKey = PropertiesService.getScriptProperties().getProperty('APIKEY');
// Gemini APIのエンドポイントURL
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${apiKey}`;
const systemPrompt = getSystemPrompt(); // 修正: getSystemPrompt関数を呼び出してSYSTEM_PROMPTの値を動的に取得
prompt = `${systemPrompt}\n${prompt}`;
// Gemini APIリクエストに必要なペイロード
const payload = {
"contents": [
{"role": "user","parts": { "text": prompt }}
],
};
// HTTPリクエストのオプション設定
const options = {
'payload': JSON.stringify(payload),
'method' : 'POST',
'muteHttpExceptions': true,
'contentType': 'application/json'
};
// Gemini APIにリクエストを送信し、レスポンスを取得
try {
const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
const response = JSON.parse(responseText);
// レスポンスからテキストを抽出
const { content: { parts: [{ text }] } } = response.candidates[0];
console.log(text);
return text;
} catch (error) {
console.error('APIリクエストでエラーが発生しました: ', error);
return '少々お待ちください。';
}
}
このシステムの利点
このBotシステムの最大の利点は、GPTs の Instructionsがほぼ空であるため、プロンプトインジェクション攻撃に対して強いという点です。プロンプトインジェクション攻撃は、不正な入力を介してシステムに意図しない命令を実行させる攻撃手法の一つですが、このBotはそのような攻撃に対して耐性を持っています。
GPTs のSchema
GPTs を活用したAPIの構築には、OpenAPIスペックが使用されます。以下は、LINE Botが受け取ったメッセージをエコーバックする機能を持つAPIのOpenAPI 3.0仕様の一部です。
openapi: 3.0.0
info:
title: Echo Message API
description: Echoes back the received message
version: v1.0.0
servers:
- url: https://script.google.com
paths:
/macros/s/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/exec:
get:
operationId: echoMessage
summary: Echoes back the received message
description: Receives a message as a query parameter and echoes it back
parameters:
- name: message
in: query
description: The message to echo back
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
echo:
type: string
OpenAPIバージョン
openapi: 3.0.0
この行では、使用しているOpenAPIスペックのバージョンを宣言しています。ここでは3.0.0
が使用されています。
API情報
info:
title: Echo Message API
description: Echoes back the received message
version: v1.0.0
title
: APIの名前を指定します。description
: APIの簡単な説明を記述します。version
: APIのバージョンを指定します。
サーバ情報
servers:
- url: https://script.google.com
APIがホストされているサーバのURLを指定します。この例では、Google Apps ScriptでデプロイされたウェブアプリケーションのURLが使用されています。
パスと操作
paths:
/macros/s/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/exec:
get:
operationId: echoMessage
summary: Echoes back the received message
description: Receives a message as a query parameter and echoes it back
paths
: APIが提供するエンドポイントのパスを定義します。get
: HTTPメソッドを指定します。この場合はGET
メソッドです。operationId
: この操作を一意に識別するためのIDです。これは、コード生成ツールで使用されることがあります。summary
: 操作の簡単な説明を提供します。description
: 操作の詳細な説明を提供します。
パラメータ
parameters:
- name: message
in: query
description: The message to echo back
required: true
schema:
type: string
parameters
: エンドポイントが受け取るパラメータを定義します。name
: パラメータの名前です。in
: パラメータがどこにあるかを指定します。この場合、クエリパラメータとして指定されています。description
: パラメータの説明です。required
: このパラメータが必須かどうかを指定します。schema
: パラメータの型を定義します。ここではstring
型が使用されています。
レスポンス
responses:
"200":
description: Success
content:
application/json:
schema:
type: object
properties:
echo:
type: string
"400":
description: Invalid request. Please provide a message.
responses
: APIが返す可能性のあるレスポンスを定義します。"200"
: HTTPステータスコードを指定します。ここでは、成功時に200 OK
を返します。description
: レスポンスの説明です。content
: レスポンスボディの内容を定義します。この例では、application/json
タイプのオブジェクトを返し、そのオブジェクトにはecho
プロパティが含まれています。"400"
: エラーレスポンスを定義します。無効なリクエストが行われた場合、400 Bad Request
を返します。
まとめ
GPTs、GAS、Gemini Proを組み合わせることで、高度な対話機能を持つBotを簡単に作成できます。この記事で紹介したBot「幻(げん)」は、その一例に過ぎません。皆さんもこの仕組みを応用して、様々な用途に合わせたBotを作成してみてはいかがでしょうか。
コメント