見出し画像

アドベントカレンダー2023 #17 GASのソースコード整理と機能向上

ソースコードの整理

今日は、Google Apps Script(GAS)のサービス関連のソースコードを整理しました。変更は2点で、1点目は、スプレッドシートに新たな設定シートを追加しました。これにより、設定値を外部で管理し、効率的な運用が可能になります。2点目は、OpenAI APIのセキュリティを強化するために、リクエスト時に特定の単語を隠語に置換する処理を加えました。

パラメータ管理のクラス作成

スプレッドシートに新たな設定シートを設けた理由は、エリア集計やサービス集計、OpenAI API実行などで設定が増えてきたことが要因です。重複するような定数の整理や幾つかの変数を外部設定としています。ソース内の定数を最小限に抑え、変更も容易な仕組みとなりました。さらに、設定シートの処理を効率化するため、専用クラスを作成し、各種パラメータを集中管理しています。

連想配列の形式で設定をするシンプルな構造

OpenAI APIのセキュリティ強化

OpenAI APIの使用に際して、秘匿性を高める工夫を行いました。APIを使用してデータを処理する際に、そのデータの安全性とプライバシーを確保するための処置です。データをOpenAIに送信する前に、それを暗号化することで、データが第三者によって読み取られるリスクを減らすことができます。具体的には、リクエスト時に特定の単語を隠語に置換し、レスポンスでの隠語を再び特定の単語に戻す処理を実装しました。これらの置換処理と辞書をスプレッドシートに設定することで、セキュリティを強化しています。

リクエスト前に変換

上段:リクエスト暗号化前 下段:暗号化後

リクエスト前に、特定の単語が隠語に変換されるようにしています。
OpenAI APIからのレスポンスを、同様に隠語から単語に変換しています。

上段:レスポンス暗号化 下段:復号後
変換処理用の辞書設定

パラメータ管理のクラスと変換処理のソース

暗号化と複合には、変換単語辞書を使用している単純なものです。変更の方向性を渡すことで暗号化と複合の処理を行う仕組み(replaceWords関数)になっています。

class SpreadsheetManager {
  constructor() {
    this.grId = '(スプレッドシートのID)';
    this.grParamSheet = '設定';
    this.grLogSheet = 'LOG_DATA';
    this.grReplaceSheet = 'REP_DATA';
  }

  getSheetAppID() {
    return this.grId;
  }

  getSheetApp() {
    const ss = SpreadsheetApp.openById(this.grId);
    if (!ss) {
      Logger.log("指定されたファイルが見つかりませんでした。");
      return null;
    }
    return ss;
  }

  getParamSheet() {
    const ss = this.getSheetApp();
    if (!ss) return null;
    const sheet = ss.getSheetByName(this.grParamSheet);
    if (!sheet) {
      Logger.log("指定されたシートが見つかりませんでした。");
      return null;
    }
    return sheet;
  }

  getLogSheet() {
    const ss = this.getSheetApp();
    if (!ss) return null;
    const sheet = ss.getSheetByName(this.grLogSheet);
    if (!sheet) {
      Logger.log("指定されたシートが見つかりませんでした。");
      return null;
    }
    return sheet;
  }

  createKeyValuePairs() {
    const sheet = this.getParamSheet();
    if (!sheet) return null;
    var range = sheet.getRange("A:B");
    var values = range.getValues();
    var keyValuePairs = {};
    for (var i = 0; i < values.length; i++) {
      var key = values[i][0];
      var value = values[i][1];
      keyValuePairs[key] = value;
    }
    return keyValuePairs;
  }

  getValue(key) {
    var keyValuePairs = this.createKeyValuePairs();
    return keyValuePairs[key] || 'Key not found';
  }  

  getReplaceSheet() {
    const ss = this.getSheetApp();
    if (!ss) return null;
    const sheet = ss.getSheetByName(this.grReplaceSheet);
    if (!sheet) {
      Logger.log("指定されたシートが見つかりませんでした。");
      return null;
    }
    return sheet;
  }

  replaceWords(text, direction) {
    const sheet = this.getReplaceSheet();
    if (!sheet) return text;
    var range = sheet.getRange("A:B");
    var values = range.getValues();
    var replacedText = text;
    for (var i = 0; i < values.length; i++) {
      var from = values[i][direction === 1 ? 0 : 1];
      var to = values[i][direction === 1 ? 1 : 0];
      var escapedFrom = from.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
      replacedText = replacedText.replace(new RegExp(escapedFrom, 'g'), to);
    }
    return replacedText;
  }  
}

// 以下に続くスクリプトの部分は、省略しています。

まとめ

今日は、サービス側の処理を整理することができた。DialogFlowとの連携前に、全体を通して動作確認も取れたので、この後の作業がスムーズに進むと思う。全体と通じて複雑な処理ではないので、残りの時間で完成まで進めたい。


この記事が気に入ったらサポートをしてみませんか?