ヘルプデスクGPTの作り方と実践ガイド - 自動応答とFAQ管理

 今回はヘルプデスクのチャットボットのように自動で回答してくれるチャットボットをGPTsで作成してみました。自動応答だけだとよく見かけるチャットボットと大差ないので、FAQなどを自動でメンテナンスしてくれるFAQ管理機能も付けてみました。

実際作ってみると、これがちゃんとできてしまえばもうヘルプデスクに人要らないのでは?と思うくらい凄いと思いましたので参考になると幸いです。



ヘルプデスクGPTsの全体概要

まず、利用者側のチャットボットと管理者側のチャットボットとでIFを分けてみました。

全部をまとめようとするとGPTsを作るのが大変なので、それぞれ別にすることでシンプルにしようとしています。ヘルプデスクGPTの概要図は以下のようなイメージ図です。


全体概要

大抵のヘルプデスクなどでは、お問い合わせの一覧的なものがあるかと思いますので、QA一覧はそういった管理表を想定しています。

FAQ一覧はよくある質問などのFAQの一覧等を想定しています。

Googleスプレッドシートへの操作はチャットボット側から操作する際は、Google Apps Scriptを利用して操作します。

管理者側から操作する際もGoogle Apps Scriptを利用して操作しています。これは後程紹介しますが、ChatGPTのAIの能力を活かすためです。普通にスプレッドシートを開いてそのまま利用してもいいと思います。

今回はGPTsの構成の部分の知識にファイルをアップロードするのではなく、何故Googleスプレッドシートを使うのかと言うと、知識の部分は人の手でメンテナンスする必要があるからです。また、知識の部分にアップロードできるファイルの数にも上限があったりするようです。この2つの部分を効率化するためにも今回はGPTs内部ではなく、外部にデータを持たせることにしています。



GPTsの動作

では、早速に作ってみたGPTsの動作から見ていきましょう。今回はIT関係のヘルプデスクを想定してQAやFAQのサンプルデータを作成してます。


利用者側GPTsの動作

利用者が任意の質問をすると、FAQやこれまでのQAから回答を探して、回答してくれます。ここまでだとこれまでの古のチャットボットと変わらないじゃないかと思うかもしれませんが、GPTsはインターネット検索することができますので、FAQやQAに回答が無ければ、インターネット上の一般的な知識を利用しても回答をしてくれます。やっぱりChatGPT使うならChatGPT自体の能力も活用したいですよね!

以下のような感じで動きます。

まずはユーザが問い合わせるところからです。まずは以下のような感じで問い合わせせるとします。すると、スプレッドシートのQA一覧にお問い合わせ内容を記録するとともに、回答をFAQや過去のQAの履歴から検索します。今回はFAQにもQAにも回答が無かったので、ChatGPT側の知識でいくつか追加情報をユーザに求めてヒアリングしようとしています。今回はインターネット検索していないですが、たまにインターネット検索することもあります。

利用者側GPTs動作1

ちなみに、この時のFAQ一覧は以下の状態です。

FAQ一覧1


QA一覧は以下の状態です。No.12に今回のユーザの問い合わせ内容が記録されていますね。


利用者側GPTs動作2

では、言われたとおりに追加情報を伝えてみましょう。実はFAQにブラウザに関する情報を入れていたので、今回は聞いてくれなかったですが、ブラウザの情報も提供してみることにします。すると、FAQには具体的な回答は無いとは言うものの、Firefoxは動作保証がされていない旨の情報を提供してくれました!GPTさんやりますね!!

利用者側GPTs動作3

このチャットのタイミングでApps Scriptへ通信しようとしてますが、これはユーザから提供された内容を基に質問に追加情報を付加してQA一覧のお問い合わせ内容を更新する処理です。この処理後、スプレッドシートのNo.12のお問い合わせ内容は以下の通りFirefoxを利用している旨の情報が付加されています。こうやってユーザに自動でヒアリングしてくれてどんどん情報を付加していってくれるととっても便利ですよね!


利用者側GPTs動作4


では、解決したことにしてみましょう。すると以下のように今後のためにどうやって解決したのかを聞いてくれます。


そして、解決方法を教えてもらったらQA一覧へ回答内容を入力してくれます。解決後のQA一覧の内容は以下の状態です。

利用者側GPTs動作6

ここまで自動でやってくれると相当便利ではないでしょうか!私も探り探りできるのかな?と思ってやってみてましたが、かなりChatGPTが賢くてあっさりとやりたいところまで全てできてしまいました。

回答を自動で記録してくれるということは、同様の質問が別のユーザから来たとしても次回は回答できてしまうということです!

では、別のユーザが問い合わせしてきたとして、新しいチャットを開いて似たような問い合わせをしてみましょう。

利用者側GPTs動作7
はい、もうGPT先生天才過ぎます。次からすぐ回答してくれるようになりました。これはヘルプデスクの回答精度がみるみる上がっていきそうですね!

こちらの問い合わせも上手に回答してくれたので、解決したことにしましょう。

利用者側GPTs動作8

「ありがとうございました。」などの不要な言葉が入っていると、ChatGPT側で判断して、以下のように不要なワードは削除してQA一覧に記録してくれます。賢いですね。

利用者側GPTs動作9


利用者側のGPTsの動作は以上です。ここまででかなりChatGPTの凄さを体感しましたが、本当に恐ろしく凄いのはここからです。では、次は管理者側のGPTsの動作を見ていきましょう!



管理者側GPTsの動作

管理者側のGPTsの機能としては、FAQ一覧のメンテナンス機能と未回答一覧の取得機能を作ってみました。

人間がやるには非常に面倒なFAQのメンテナンスですが、GPT先生はそんな簡単にやってしまうのでしょうか!?やってみましょう。

まずは、更新前のFAQ一覧は先ほどと同様に以下の通りです。


このFAQ一覧を先ほどのQA一覧の内容を基に更新をかけます。チャットはおまじないのように「FAQメンテナンス」と唱えればいいだけにしました。「FAQメンテナンス」と伝えるとFAQ一覧が以下のような感じに更新されます。凄い!!!!

管理者側GPTs動作2

このFAQ一覧のメンテナンスですが、QA一覧にあってFAQ一覧に足りない分を補っているだけかと思ったら大間違い。GPTs側に追加で指示を記述したのですが、個別対応となるような問い合わせは除外するように指定してます。そのため、FAQにあるべきではないシステム復旧依頼のような問い合わせについては、FAQに追加されてません。けっこう何度もこのメンテナンス処理をしてみましたが、復旧依頼の問い合わせについては、一度も追加されたケースは見かけませんでした。

もちろんChatGPT側で判断していい具合に更新をかけるので、毎回若干更新内容は異なります。ここは上手く指示するなり人間のチェックで補正をかけるなりで対応が必要なところでしょう。

しかし、FAQ更新のドラフトがこんなに簡単に出来上がり、かつ利用者側のチャットボットに即時反映されるのであれば、今までの手間は何だったんだというくらいに圧倒的に楽になるのではないでしょうか!

ただ、こちらのFAQメンテナンスボットですが、なぜかユーザへの回答では以下のようにエラーと返してしまいます。私の実装が若干不足しているだけだと思いますが、メインとなるスプレッドシートの更新まできちんと意図した通りできているので、時間ももったいないしここで諦めました。

管理者側GPTs動作1


また、おまけで管理者っぽく未回答の状況を確認できる機能の方も作ってます。こちらは「未回答一覧取得」と唱えると動作してくれます。


こうして全体の状況などを参照できると管理者としてはやりやすいかと思います。これができればChatGPTと一緒に回答を検討して回答案を作成したりできるようになると思うので、いろいろ活用の幅が広がりそうですよね。



利用者側GPTsの作り方

では本題のGPTsの作り方を説明します。利用者側のGPTsの構成(GPTの設定)は以下の通りです。

利用者側GPTs構成1
利用者側GPTs構成2


指示の内容

  1. 以下の入力パターンに応じて回答するボットです。
  2. #対応パターン1
  3. 以下の回答段取りでユーザへ回答してください。
  4. ##回答段取り
  5. 1.ユーザから問い合わせがあったら、ユーザの質問内容をスプレッドシートに追加してください。
  6. 2.以下の「回答検索段取り」で回答を取得してください。
  7. 3.回答を見つけたら'回答更新'のリクエストをスプレッドシートへ送信してください。
  8. 4.ユーザへ回答してください。「回答検索段取り」で回答を取得し、質問にマッチする回答案が無い場合は、スプレッドシートに追加した結果の氏名、カテゴリ、お問い合わせ内容、回答希望日を回答の上、ユーザに少々お時間を頂くように連絡してください。また、他に提供可能な情報が無いかいくつか選択肢を提示してヒアリングを行ってください。
  9. 5.ユーザが情報提供してくれた場合には、ヒアリング内容を基に'質問更新'を実施してスプレッドシートに提供された情報を付加して問い合わせ内容を更新してください。
  10. ##回答検索段取り
  11. 1.スプレッドシートのFAQ一覧から、回答案を取得してください。
  12. 2.FAQ一覧内に質問にマッチする回答案が無い場合は、スプレッドシートのQA一覧を検索し、最も近い回答案を取得してください。
  13. 3.QA一覧内に質問にマッチする回答案が無い場合は、ウェブ参照にてインターネットを検索し、最も近い回答案を取得してください。
  14. #対応パターン2
  15. ユーザから別の回答案、もしくは別の調査項目が欲しい旨の要望があった場合は、以下の「追加対応手順」に従い対応してください。
  16. ##追加対応手順
  17. 1.ヒアリング内容を基に'質問更新'を実施してスプレッドシートに追加した問い合わせ内容を更新してください。
  18. 2.ヒアリングを行って質問へマッチする回答案が見つかった場合は回答案をスプレッドシートへ'回答更新'します。
  19. 3.回答更新後、更新した回答案をユーザへ回答をしてください。
  20. #対応パターン3
  21. 対応パターン1の対応後、別の質問をされたら、再度対応パターン1の通りに対応してくしてください。
  22. #対応パターン4
  23. ユーザが問題を自己解決した場合は、以下の「解決方法確認手順」に従い対応してください。
  24. ##解決方法確認手順
  25. 1.ユーザにどうのようにしたら解決したかを確認する。今後のサービス向上のために必要である旨を添えてください。
  26. 2.ユーザに確認した解決方法を'回答更新'を実行することで、回答を更新する。

ChatGPTへの指示は、パターンの考え方や手順のみとし、それぞれの手順の詳細等は考え方だけを指示することで、ChatGPTに考えさせます。いろいろな詳細事項を考えるところが一番面倒なところなので、その一番面倒な部分をAIに考えさせるように作りこむことで全体を設計します。


利用者側GPTsのActionのスキーマは以下の通りです。

  1. {
  2.   "openapi": "3.1.0",
  3.   "info": {
  4.     "title": "スプレッドシートデータの検索・更新・追加",
  5.     "description": "ユーザの問い合わせの状況に応じてスプレッドシートデータの追加・回答更新・取得・質問更新を行います。",
  6.     "version": "v1.0.0"
  7.   },
  8.   "servers": [
  9.     {
  10.       "url": "https://script.google.com"
  11.     }
  12.   ],
  13.   "paths": {
  14.     "/macros/s/AKfycbwSacdMPMciSGO0J85mPwJ43j-9iamODzPGQyWkYaB7T9_QipCPi-eRFm_SP8KYenVB/exec": {
  15.       "get": {
  16.         "description": "ユーザから問い合わせがあった場合は、問い合わせ内容の'追加'のリクエストを送信します。回答案を取得する場合は、'取得'のリクエストを送信します。ユーザへの回答後に回答をスプレッドシートへ更新する場合は、'回答更新'のリクエストを送信します。質問の更新をする場合は、'質問更新'のリクエストを送信します。",
  17.         "operationId": "operation sheet",
  18.         "parameters": [
  19.           {
  20.             "name": "action",
  21.             "in": "query",
  22.             "description": "'追加' or '取得' or '回答更新' or '質問更新'",
  23.             "required": true,
  24.             "schema": {
  25.               "type": "string"
  26.             }
  27.           },
  28.           {
  29.             "name": "sheet",
  30.             "in": "query",
  31.             "description": "回答案を取得するシート名で、'FAQ' or 'QA'",
  32.             "required": true,
  33.             "schema": {
  34.               "type": "string"
  35.             }
  36.           },
  37.           {
  38.             "name": "timestamp",
  39.             "in": "query",
  40.             "description": "タイムスタンプがこのスプレッドシートのIDの代わりになります。'追加'時は空文字を送信します。タイムスタンプの形式は、'yyyy/MM/dd hh:mm:ss'で、ユーザが入力した時のJSTです。'取得'、'回答更新'、'質問更新'時は最初に質問を追加した時にgoogle apps scriptから返却されたレスポンスのタイムスタンプを送信します。",
  41.             "required": true,
  42.             "schema": {
  43.               "type": "string"
  44.             }
  45.           },
  46.           {
  47.             "name": "name",
  48.             "in": "query",
  49.             "description": "氏名",
  50.             "required": true,
  51.             "schema": {
  52.               "type": "string"
  53.             }
  54.           },
  55.           {
  56.             "name": "category",
  57.             "in": "query",
  58.             "description": "主にシステム名になるカテゴリです。",
  59.             "required": true,
  60.             "schema": {
  61.               "type": "string"
  62.             }
  63.           },
  64.           {
  65.             "name": "content",
  66.             "in": "query",
  67.             "description": "お問い合わせ内容。対応パターン2の場合は、最初の質問内容にユーザからヒアリングした内容を付加して値をお問い合わせ内容をセットします。",
  68.             "required": true,
  69.             "schema": {
  70.               "type": "string"
  71.             }
  72.           },
  73.           {
  74.             "name": "deadline",
  75.             "in": "query",
  76.             "description": "回答希望日。フォーマットは、'yyyy/MM/dd'",
  77.             "required": true,
  78.             "schema": {
  79.               "type": "string"
  80.             }
  81.           },
  82.           {
  83.             "name": "answer",
  84.             "in": "query",
  85.             "description": "ユーザへ回答した内容",
  86.             "required": true,
  87.             "schema": {
  88.               "type": "string"
  89.             }
  90.           }
  91.         ],
  92.         "deprecated": false
  93.       }
  94.     }
  95.   },
  96.   "components": {
  97.     "schemas": {
  98.       "NameResponse": {
  99.         "type": "object",
  100.         "properties": {
  101.           "name": {
  102.             "type": "string"
  103.           },
  104.           "category": {
  105.             "type": "string"
  106.           },
  107.           "content": {
  108.             "type": "string"
  109.           },
  110.           "deadline": {
  111.             "type": "string"
  112.           },
  113.           "answer": {
  114.             "type": "string"
  115.           },
  116.           "QAdata": {
  117.             "type": "string"
  118.           }
  119.         }
  120.       }
  121.     }
  122.   }
  123. }

こちらは、APIのパラメータ値でApps Script側で処理を分岐をさせるので、それぞれのパラメータの役割をきちんと教える必要があります。ここは確実に間違えないように具体的な値を指示する必要があります。

また、データ型も間違えるとApps Script側でエラーになるので、データフォーマットも具体的に指定します。ChatGPTへの指示も、何をする部分なのかに応じて指示の抽象度を変えて指示していくことがコツになると思っています。


Actionには一番最初の全体概要に示した通り、google Apps Scriptを使っています。Apps Scriptの利用者側のコードは以下の通りです。

QABot.gs

  1. function doGet(e) {
  2.   var action = e.parameter.action;
  3.   if (action == '追加') {
  4.     return addAction(e);
  5.   } else if (action == '取得') {
  6.     return getData(e);
  7.   } else if (action == '回答更新') {
  8.     return updateAnswer(e);
  9.   } else if (action == '質問更新') {
  10.     return updateQuestion(e);
  11.   } else {
  12.     return ContentService.createTextOutput(
  13.       JSON.stringify({ "error": "Invalid Action." })
  14.     ).setMimeType(ContentService.MimeType.JSON);
  15.   }
  16. }
  17. function addAction(e) {
  18.   // リクエストからパラメータを取得
  19.   var addtimestamp = Utilities.formatDate( new Date(), 'Asia/Tokyo', 'yyyy/MM/dd hh:mm:ss');
  20.   var addname = e.parameter.name;
  21.   var addcategory = e.parameter.category;
  22.   var addcontent = e.parameter.content;
  23.   var adddeadline = e.parameter.deadline;
  24.   // スプレッドシートデータの取得
  25.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName('QA');
  26.   var lastRow = sheet.getLastRow();
  27.   if (lastRow > 1) { // データがある場合
  28.     var lastIdCell = sheet.getRange(lastRow, 1).getValue(); // 最後の行のIDを取得
  29.     lastId = parseInt(lastIdCell, 10);
  30.   }
  31.   sheet.appendRow([addtimestamp, addname, addcategory, addcontent, adddeadline]);
  32.   return ContentService.createTextOutput(
  33.     JSON.stringify({ "timestamp": addtimestamp, "name": addname, "category": addcategory, "content": addcontent, "deadline": adddeadline, "answer": "", "QAdata": "" })
  34.   ).setMimeType(ContentService.MimeType.JSON);
  35. }
  36. function getData(e) {
  37.   // リクエストからパラメータを取得
  38.   var targetsheet = e.parameter.sheet;
  39.   // スプレッドシートの準備
  40.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName(targetsheet);
  41.   var data = sheet.getDataRange().getValues();
  42.   // スプレッドシートのデータを返却
  43.   return ContentService.createTextOutput(
  44.     JSON.stringify({ "timestamp": "", "name": "", "category": "", "content": "", "deadline": "", "answer": "", "QAdata": data })
  45.   ).setMimeType(ContentService.MimeType.JSON);
  46. }
  47. function updateAnswer(e) {
  48.   // リクエストからパラメータを取得
  49.   var searchtimestamp = e.parameter.timestamp;
  50.   var updateanswer = e.parameter.answer;
  51.   // スプレッドシートデータの取得
  52.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName('QA');
  53.   var data = sheet.getDataRange().getValues();
  54.   // スプレッドシートを検索
  55.   for (var i = 1; i < data.length; i++) { // 2行目から開始
  56.     if (Utilities.formatDate(data[i][0], "JST", "yyyy/MM/dd HH:mm:ss") === searchtimestamp.toString()) {
  57.       sheet.getRange(i + 1, 6).setValue(updateanswer);
  58.       var responseanswer = sheet.getRange(i + 1, 6).getValues();
  59.       // 見つかった場合、JSONとして返す
  60.       return ContentService.createTextOutput(
  61.         JSON.stringify({ "timestamp": "", "name": "", "category": "", "content": "", "deadline": "", "answer": responseanswer, "QAdata": "" })
  62.       ).setMimeType(ContentService.MimeType.JSON);
  63.     }
  64.   }
  65.   
  66.   // 一致するデータが見つからない場合
  67.   return ContentService.createTextOutput(
  68.     JSON.stringify({ "error": "回答を記録する対象の質問が見つかりませんでした。" })
  69.   ).setMimeType(ContentService.MimeType.JSON);
  70. }
  71. function updateQuestion(e) {
  72.   // リクエストからパラメータを取得
  73.   var searchtimestamp = e.parameter.timestamp;
  74.   var updatecontent = e.parameter.content;
  75.   // スプレッドシートデータの取得
  76.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName('QA');
  77.   var data = sheet.getDataRange().getValues();
  78.   // スプレッドシートを検索
  79.   for (var i = 1; i < data.length; i++) { // 2行目から開始
  80.     if (Utilities.formatDate(data[i][0], "JST", "yyyy/MM/dd HH:mm:ss") === searchtimestamp.toString()) {
  81.       sheet.getRange(i + 1, 4).setValue(updatecontent);
  82.       var responseContent = sheet.getRange(i + 1, 4).getValues();
  83.       // 見つかった場合、JSONとして返す
  84.       return ContentService.createTextOutput(
  85.         JSON.stringify({ "timestamp": "", "name": "", "category": "", "content": responseContent, "deadline": "", "answer": "", "QAdata": "" })
  86.       ).setMimeType(ContentService.MimeType.JSON);
  87.     }
  88.   }
  89.   
  90.   // 一致するデータが見つからない場合
  91.   return ContentService.createTextOutput(
  92.     JSON.stringify({ "error": "更新対象の質問が見つかりませんでした。" })
  93.   ).setMimeType(ContentService.MimeType.JSON);
  94. }


管理者側GPTsの作り方

管理者側のGPTsの構成は以下の通りです。

管理者側GPTs構成1
管理者側GPTs構成2


指示の内容

  1. 以下の入力パターンに応じて対応するボットです。
  2. #対応パターン1
  3. 「FAQメンテナンス」とユーザが指示したら、以下の「メンテナンス段取り」でFAQデータをメンテナンスします。
  4. ##「メンテナンス段取り」
  5. 1.FAQ一覧を取得します。取得した内容は表示不要です。
  6. 2.QA一覧を取得します。取得した内容は表示不要です。
  7. 3.「FAQ一覧の更新の考え方」に基づいてFAQ一覧を更新し、'FAQ更新'処理を実行する。FAQのデータ形式は変更しない。FAQの更新内容はユーザへ確認及び表示せずに'FAQ更新'処理を実行します。
  8. ###FAQ一覧の更新の考え方
  9. 1.FAQ一覧に掲載されておらず、QA一覧にて頻出の質問は追加する。
  10. 2.FAQ一覧に掲載されている回答よりも、もっと良い回答がQA一覧にあれば、FAQの回答をその回答に更新する。
  11. 3.個別の質問・対応内容と考えられるQAについては掲載しない。
  12. #対応パターン2
  13. 「未回答一覧取得」とユーザが指示したら、QA一覧を取得し、未回答分の質問を出力します。
  14. 未回答件数が10件未満の場合は、すべての質問の一覧を出力します。
  15. 未回答件数が10件以上ある場合は、未回答の件数を出力し、任意の10件の質問の一覧を出力します。

一番メインとなるFAQ一覧の更新のやり方については、考え方のレベルまでを指示します。具体的にきちんと指示するのであれば、それは通常のプログラム等にて処理すればよいことになります。あくまでAIにやってほしいことは、抽象的な内容から具体的な操作に落とし込む面倒なところをやってほしいので、その面倒な部分をChatGPTに考えさせます。


管理者側GPTsのActionのスキーマは以下の通りです。

  1. {
  2.   "openapi": "3.1.0",
  3.   "info": {
  4.     "title": "QA管理者用機能",
  5.     "description": "FAQもしくはQAの'取得'、'FAQ更新'、'未回答一覧取得'を行う",
  6.     "version": "v1.0.0"
  7.   },
  8.   "servers": [
  9.     {
  10.       "url": "https://script.google.com"
  11.     }
  12.   ],
  13.   "paths": {
  14.     "/macros/s/AKfycbwSacdMPMciSGO0J85mPwJ43j-9iamODzPGQyWkYaB7T9_QipCPi-eRFm_SP8KYenVB/exec": {
  15.       "post": {
  16.         "description": "FAQかQAの一覧取得の場合は、'取得'のリクエストを送信します。FAQ一覧を更新する場合は、'FAQ更新'のリクエストを送信します。未回答一覧を取得する場合は、'未回答一覧取得'のリクエストを送信します。",
  17.         "operationId": "operation sheet",
  18.         "parameters": [
  19.           {
  20.             "name": "action",
  21.             "in": "query",
  22.             "description": "'取得' or 'FAQ更新' or '未回答一覧取得'",
  23.             "required": true,
  24.             "schema": {
  25.               "type": "string"
  26.             }
  27.           },
  28.           {
  29.             "name": "sheet",
  30.             "in": "query",
  31.             "description": "FAQ一覧を取得する場合は、'FAQ'をセットし、QA一覧を取得する場合は'QA'をセットする。",
  32.             "required": true,
  33.             "schema": {
  34.               "type": "string"
  35.             }
  36.           },
  37.           {
  38.             "name": "faqdata",
  39.             "in": "query",
  40.             "description": "FAQ一覧を更新するための更新後のFAQ一覧の文字列型の配列データをセットする。セットするFAQデータのサンプルは、次のフォーマットで、各要素全て文字列です。#フォーマット:[[\"a\",\"b\",\"c\",\"d\"],[\"e\",\"f\",\"g\",\"h\"]]。ヘッダ行は削除する。",
  41.             "required": false,
  42.             "schema": {
  43.               "type": "string"
  44.             }
  45.           }
  46.         ],
  47.         "deprecated": false
  48.       }
  49.     }
  50.   },
  51.   "components": {
  52.     "schemas": {
  53.       "NameResponse": {
  54.         "type": "object",
  55.         "properties": {
  56.           "responsedata": {
  57.             "type": "string"
  58.           }
  59.         }
  60.       }
  61.     }
  62.   }
  63. }

こちらは、APIのパラメータで分岐をさせるので、それぞれのパラメータの役割をきちんと教える必要があります。特に、今回のApps Scriptは文字列で分岐する設計になっているので、ここは確実に間違えないように具体的な値を指示する必要があります。


Apps Scriptの管理者側のコードは以下の通りです。

QAmaintenance.gs

  1. function doPost(e) {
  2.   var action = e.parameter.action;
  3.   if (action == '取得') {
  4.     return getDataForMaintenance(e);
  5.   } else if (action == 'FAQ更新') {
  6.     return updateFaq(e);
  7.   } else if (action == '未回答一覧取得') {
  8.     return getUnAnsweredData(e);
  9.   } else {
  10.     return ContentService.createTextOutput(
  11.       JSON.stringify({ "error": "Invalid Action." })
  12.     ).setMimeType(ContentService.MimeType.JSON);
  13.   }
  14. }
  15. function getDataForMaintenance(e) {
  16.   // リクエストからパラメータを取得
  17.   var targetsheet = e.parameter.sheet;
  18.   // スプレッドシートデータの取得
  19.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName(targetsheet);
  20.   var data = sheet.getDataRange().getValues();
  21.   // スプレッドシートのデータを返却
  22.   return ContentService.createTextOutput(
  23.     JSON.stringify({"responsedata": data })
  24.   ).setMimeType(ContentService.MimeType.JSON);
  25. }
  26. function updateFaq(e) {
  27.   // リクエストからパラメータを取得
  28.   var faqStringData = e.parameter.faqdata;
  29.   var faqArray = JSON.parse(faqStringData);
  30.   // スプレッドシートの準備
  31.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName('FAQ');
  32.   // 既存のデータを取得
  33.   var existingData = sheet.getDataRange().getValues();
  34.   // Noをキーにしてデータをマップに変換
  35.   var dataMap = {};
  36.   for (var i = 0; i < faqArray.length; i++) {
  37.     dataMap[faqArray[i][0]] = faqArray[i];
  38.   }
  39.   // 既存データを更新
  40.   for (var j = 0; j < existingData.length; j++) {
  41.     var no = existingData[j][0];
  42.     if (dataMap[no]) {
  43.       existingData[j] = dataMap[no];
  44.       delete dataMap[no]; // 更新済みのデータは削除
  45.     }
  46.   }
  47.   // 新しいデータを追加
  48.   for (var key in dataMap) {
  49.     existingData.push(dataMap[key]);
  50.   }
  51.   // 更新したデータをスプレッドシートに反映
  52.   sheet.getRange(1, 1, existingData.length, 4).setValues(existingData);
  53.   return ContentService.createTextOutput(
  54.     JSON.stringify({"responsedata": "FAQ一覧のメンテナンスが完了しました。" })
  55.   ).setMimeType(ContentService.MimeType.JSON);
  56. }
  57. function getUnAnsweredData(e) {
  58.   // スプレッドシートデータの取得
  59.   var sheet = SpreadsheetApp.openById('{スプレッドシートID}').getSheetByName('QA');
  60.   var data = sheet.getDataRange().getValues();
  61.   // 未回答のデータを格納する配列
  62.   var unansweredFAQs = [];
  63.   
  64.   // 未回答のデータを抽出
  65.   for (var i = 0; i < data.length; i++) {
  66.     var row = data[i];
  67.     if (row[5] === "") { // 回答列が空の場合
  68.       unansweredFAQs.push(row);
  69.     }
  70.   }
  71.   // スプレッドシートのデータを返却
  72.   return ContentService.createTextOutput(
  73.     JSON.stringify({"responsedata": unansweredFAQs })
  74.   ).setMimeType(ContentService.MimeType.JSON);
  75. }


※利用者側のApps Scriptは管理者側のApps Scriptと同一プロジェクトにしてます。そのため、こちらはPostメソッドでリクエストを受けるAPIになっておりますが、単なるPostの実験ですので、気にしないでください。



まとめ

やれるかな~と思って実際作ってみると、思った以上にChatGPTが賢く、これはさらに活用の幅が広がるなと思いました。チャットなどでやり取りできる仕事などはどんどんAIに置き換えられていきそうな感じですね。

作成にあたってのコツも私なりにいくつか記載してみましたので、参考となりましたら幸いです。

ポイントとしては、以下の通りと考えます。

  • 考え方だけを指示するだけでChatGPTは概ね上手く考えて動いてくれる。
  • AIにどこの部分をを考えてほしいのかを明確にして設計する。

また何か面白そうな使い方を思いついたら記事を書きたいと思いますので、次回お会いしましょう。

今回の記事については、一回くらいはGPTsを作ったことがある人向けの内容になっていると思いますので、そもそもGPTsってどう作るんだっけ?という人は、以下のサイトなどを参考に一度ご自身のGPTを作成してみてください。


参考サイト






保険料控除証明書XMLをマイナポータルで取得できるようにしてみた(保険料控除証明書電子化対応)

そろそろ年末調整の時期となりますが、皆さん準備は済んでいるでしょうか? 年末調整では保険料控除証明書が必要ですが、電子化対応がかなり進んでいますので、昨年度e-Taxで確定申告した経験を活かして今回はマイナポータルでの保険料控除証明書XML取得の方法についてまとめてみました。皆さ...