chatGPTでノーコードプログラミング③実践してみる
はじめに
第1回、第2回とプログラミングを始める前の大枠を埋めてきました。今回はいよいよ目的である、「①Slackに投稿があったら、②スプレッドシートに取り込み、③chatGPTに送信し、④回答をスプレッドシートに保存、⑤回答をメールで送信、⑥回答をSlackに投稿、⑦(おまけ)chatGPTをキャラbot化する」プログラムに挑戦しましょう。なお、第1回でも言いましたが、単純にSlackとchatGPTを連携させるだけならアプリが用意されているようなのでそちらで検索してください。これはchatGPTでコードを生成してもらう練習です。
前提として、コード中のURLやAPI-KEYは自分の環境に合わせて入力してください。(chatGPTのエンドポイントは別です)
①~②投稿を取り込む
すでに出来上がったものがこちらにございます!
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('◯◯◯◯◯'); // ←シート名を入力する
var token = 'XXXXXXXXXXXXXXXX' // ← Outgoing Webhook のトークンを入力する
// Googleスプレッドシートにデータを追加する処理
if (token == e.parameter.token){
var datetime = new Date();
var date = (datetime.getFullYear() + '/' + ('0' + (datetime.getMonth() + 1)).slice(-2) + '/' + ('0' + datetime.getDate()).slice(-2))
var time = (('0' + datetime.getHours()).slice(-2) + ':' + ('0' + datetime.getMinutes()).slice(-2));
var username = e.parameter.user_name;
var text = e.parameter.text;
array = [date,time,username,text];
sheet.appendRow(array);
}
return
}
?chatGPTは?となると思いますが、すでに出来上がったものがgoogle等で見つかるならそちらのほうがうまくいく可能性は高いです。説明も丁寧なので。
もちろんchatGPTに「google apps scriptで、slackのoutgoingwebhookから送られたデータを受け取り、スプレッドシートに入力するコードを生成してください」とお願いすれば、
function doPost(e) {
var postData = e.postData.contents; // Slackからのデータを受け取り
// Slackからのデータをパース
var data = JSON.parse(postData);
// スプレッドシートを取得(スプレッドシートのIDを指定)
var ss = SpreadsheetApp.openById('YOUR_SPREADSHEET_ID');
// 対象のシートを取得(シート名を指定)
var sheet = ss.getSheetByName('Sheet1');
// Slackからのデータをスプレッドシートに書き込み
sheet.appendRow([new Date(), data.user_name, data.text]);
// レスポンスを返す(任意)
return ContentService.createTextOutput("データを受け取りました。");
}
と、コードがかえってきます。こちらでも方法は少し違っても結果はほぼ同じです。(23.10.18追記:こちらのコードでは動かないようです。slackからのデータはJSONではなく、URLencodeという形式で届いているようです。)しかし、最初のコードには、「受け取ったトークンで、データの送信元が自分のAPIかどうか判定する」コードが入っています。これは悪意あるPOSTリクエストをはじくためでしょうか?chatGPTにそう追加でお願いすれば入ったコードが得られますが、もう出来たものがあるなら利用させていただきましょう。ここまでがうまくいかない方(といっても結構難しいです)は私の過去記事も参考にしてください。
③chatGPTに送信
さあ、ここからが生成AIの力の見せどころです。
「google apps scriptで、chatGPTのAPIにデータを送信するコードを生成してください」
function sendToChatGPT() {
// ChatGPT APIエンドポイントとAPIキーを設定
var apiUrl = "https://api.openai.com/v1/engines/davinci/completions";
var apiKey = "YOUR_API_KEY"; // ChatGPTのAPIキーをここに入力
// リクエストデータを作成
var requestData = {
prompt: "Translate the following English text to French: 'Hello, world.'",
max_tokens: 50 // 応答の最大トークン数
};
// HTTPリクエストのオプションを設定
var options = {
method: "POST",
headers: {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
},
payload: JSON.stringify(requestData)
};
// HTTPリクエストを送信
var response = UrlFetchApp.fetch(apiUrl, options);
// レスポンスを解析
var responseData = JSON.parse(response.getContentText());
// ChatGPTからの応答を取得
var chatResponse = responseData.choices[0].text;
// ChatGPTからの応答をログに出力
Logger.log("ChatGPTの応答: " + chatResponse);
// 必要に応じて、ChatGPTからの応答を別の処理に使用できます。
}
出てきました!動きます!けど、何か変ですね?
こういう時にまず疑わしいのはAPIの仕様変更です。反応は意味不明ですが、とりあえず実行はエラーがなく終了しているからです。
よくよく調べてみると、APIエンドポイントのバージョンが古いようでした。
なのでchatGPTに「上のコードのエンドポイントをhttps://api.openai.com/v1/chat/completionsに変更して全体を修正してください」とお願いしてみます。
function sendToChatGPT() {
// ChatGPT APIエンドポイントとAPIキーを設定
var apiUrl = "https://api.openai.com/v1/chat/completions";
var apiKey = "YOUR_API_KEY"; // ChatGPTのAPIキーをここに入力
// リクエストデータを作成
var requestData = {
model: "gpt-3.5-turbo", // 使用するChatGPTモデル
messages: [
{
role: "system",
content: "You are a helpful assistant."
},
{
role: "user",
content: "Translate the following English text to French: 'Hello, world.'"
}
],
};
// HTTPリクエストのオプションを設定
var options = {
method: "POST",
headers: {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
},
payload: JSON.stringify(requestData)
};
// HTTPリクエストを送信
var response = UrlFetchApp.fetch(apiUrl, options);
// レスポンスを解析
var responseData = JSON.parse(response.getContentText());
// ChatGPTからの応答を取得
var chatResponse = responseData.choices[0].message.content;
// ChatGPTからの応答をログに出力
Logger.log("ChatGPTの応答: " + chatResponse);
// 必要に応じて、ChatGPTからの応答を別の処理に使用できます。
}
これを実行すると
動きました!検索の手間はありましたが、途中の、JSONだとかUrlFetchAppだとか何もわからなくてもGASとchatGPTを連携させることが出来ました。
(しかし2023年の変更になぜchatGPTは対応できるのでしょう?)
最後に、これを関数として利用したいので、
「上のコードを、変数questionを引数として受け取りchatGPTの応答を戻り値として返すコードにしてください」
とお願いしてみましょう。
function getChatGPTResponse(question) {
// ChatGPT APIエンドポイントとAPIキーを設定
var apiUrl = "https://api.openai.com/v1/chat/completions";
var apiKey = "YOUR_API_KEY"; // ChatGPTのAPIキーをここに入力
// リクエストデータを作成
var requestData = {
model: "gpt-3.5-turbo", // 使用するChatGPTモデル
messages: [
{
role: "system",
content: "You are a helpful assistant."
},
{
role: "user",
content: question
}
],
};
// HTTPリクエストのオプションを設定
var options = {
method: "POST",
headers: {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
},
payload: JSON.stringify(requestData)
};
// HTTPリクエストを送信
var response = UrlFetchApp.fetch(apiUrl, options);
// レスポンスを解析
var responseData = JSON.parse(response.getContentText());
// ChatGPTからの応答を取得
var chatResponse = responseData.choices[0].message.content;
// ChatGPTからの応答を返す
return chatResponse;
}
// 使用例:
var question = "Translate the following English text to French: 'Hello, world.'";
var response = getChatGPTResponse(question);
Logger.log("ChatGPTの応答: " + response);
使用例までつけてくれました。コピペする時は使用例は消しましょう。
④スプレッドシートに記入する
ではここで、chatGPTへ質問する関数と組み合わせて、回答をスプレッドシートに記入してみましょう。最初のコードを以下のようにします。
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('◯◯◯◯◯'); // ←シート名を入力する
var token = 'XXXXXXXXXXXXXXXX' // ← Outgoing Webhook のトークンを入力する
// Googleスプレッドシートにデータを追加する処理
if (token == e.parameter.token){
var datetime = new Date();
var date = (datetime.getFullYear() + '/' + ('0' + (datetime.getMonth() + 1)).slice(-2) + '/' + ('0' + datetime.getDate()).slice(-2))
var time = (('0' + datetime.getHours()).slice(-2) + ':' + ('0' + datetime.getMinutes()).slice(-2));
var username = e.parameter.user_name;
var text = e.parameter.text;
var answer = getChatGPTResponse(text);//追加 引数としてSlackからきたtextを渡して、その戻り値が変数answerに保存される
array = [date,time,username,text,answer];//ここにanswerも入れてもらうと楽
sheet.appendRow(array);
}
return
}
//追加したい関数を下に並べていく
function getChatGPTResponse(question) {
略
}
関数、変数の使い方は都度chatGPTに聞いても教えてくれますが、覚えてしまったほうが早いと思います。
関数の(question)と呼び出す時の(text)は一致している必要はありません。
入れ物であるtextの中身を関数に渡し、関数側ではquestionという入れ物に入れるという解釈で、中身は変わっていません。
⑤回答をメールで送信する
どんどん聞いていきましょう。
「google apps scriptで、引数を本文としてメールを送信するコードを生成してください」
function sendEmailWithBody(body) {
// メールの受信者、件名、本文を設定
var recipient = "recipient@example.com"; // 受信者のメールアドレスを指定
var subject = "メールの件名"; // 送信するメールの件名
var message = body; // 引数として受け取った本文
// メールを送信
MailApp.sendEmail({
to: recipient,
subject: subject,
body: message
});
}
これはもうこれでOKです。
戻り値がない関数の場合は、doPostのvar answer~以降好きな行で、
sendEmailWithBody(answer);
と記入してください。
⑥回答をSlackへ送信
このままいけるでしょうか?
「google apps scriptで、引数を本文としてincomingwebhookへデータを送信するコードを生成してください」
何故incomingが出てくるのか?というのは、前提知識としてSlackとのデータのやり取りにはAPIが必要で、事前に「Slack API 投稿」等で調べた結果とします。過去記事①も参考にしてみてください。
(outgoing単体で返事を返す方法もあるはずなのですが、現状うまくいかないのでまた別でチャレンジします。)
function sendToIncomingWebhook(body) {
// Incoming WebhookのURLを設定
var webhookUrl = "https://hooks.slack.com/services/your-webhook-url"; // Incoming WebhookのURLを指定
// リクエストデータを作成
var payload = {
text: body // 引数として受け取った本文
};
// HTTPリクエストのオプションを設定
var options = {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload)
};
// HTTPリクエストを送信
var response = UrlFetchApp.fetch(webhookUrl, options);
// 応答を取得(通常は無視)
var responseData = response.getContentText();
}
いけますね!あとはこれをくっつけましょう。
function doPost(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('◯◯◯◯◯'); // ←シート名を入力する
var token = 'XXXXXXXXXXXXXXXX' // ← Outgoing Webhook のトークンを入力する
// Googleスプレッドシートにデータを追加する処理
if (token == e.parameter.token){
var datetime = new Date();
var date = (datetime.getFullYear() + '/' + ('0' + (datetime.getMonth() + 1)).slice(-2) + '/' + ('0' + datetime.getDate()).slice(-2))
var time = (('0' + datetime.getHours()).slice(-2) + ':' + ('0' + datetime.getMinutes()).slice(-2));
var username = e.parameter.user_name;
var text = e.parameter.text;
var answer = getChatGPTResponse(text);//追加 引数としてSlackからきたtextを渡して、その戻り値が変数answerに保存される
array = [date,time,username,text,answer];//ここにanswerも入れてもらうと楽
sheet.appendRow(array);
sendEmailWithBody(answer);//メール送信
sendToIncomingWebhook(answer);//slackへ送信
}
return
}
//追加したい関数を下に並べていく
function getChatGPTResponse(question) {
略
}
function sendEmailWithBody(body) {
略
}
function sendToIncomingWebhook(body) {
略
}
骨組み完成です!
骨組みとしたのは、これはまだ投稿すべてに反応してしまう状態だからです。特定のキーワードに反応させる手っ取り早い方法は、Slack側のoutgoingwebhookの設定でキーワードを設定してしまうことです。
ただ、それだとキーワードを変更したくなった時に手間なので、
var keyword = "キーワード";
var keylength = keyword.length
if (text.indexOf(keyword) === 0) {
text = text.substring(keylength+1);
var answer
略
sendToIncomingWebhook(answer);
}
とコード内で分岐させると、キーワードが変えやすくなります。もちろんchatGPTに聞きました。
⑦おまけ キャラbotにする
こちらを参考に、この記事でいうgetChatGPTResponse関数内のrole:systemへ色んなプロンプトを与えましょう。ちなみに私は癒されたいのでかわいい牛botを作りました。
"messages": [
{
"role": "system",
"content": "あなたは牛です。チャットにおいて語頭に「モ~。」とつけてください。すべてのチャットにおいて100文字程度で返信してください。\
食べ物の話題では肉食は拒否してください。癒し系の口調でしゃべってください。"
},
{
"role": "user",
"content": question
}
おわりに
いかがでしたでしょうか。つたない説明でしたが、生成AIでプログラミングを始めるにあたって、必要なこと、コツ等をお話させていただきました。
思ったよりも大変だったところもあれば、コード生成に入るとすんなりいく部分もあったと思います。デジタルファーストキャンプでは明日からまた違うテーマになりますが、私はこのテーマが好きなのでこそこそ続けようと思います。