【GAS】DeepLAPIを使って英文ブログを翻訳する(後半)

f:id:twixoreo:20210524235505p:plain
サムネイル

▼前回のおさらい
azumikan.hatenablog.com

いよいよGASで差分をとって、
ブログの英文をDeepLで翻訳します。

今回のスクリプトの流れ

1.スプレッドシートで更新を検知したらブログの文章を取り込む

2.雑に1000文字ずつに区切って、バンバンAPIになげる

3.返ってきた日本語を配列に格納して成形

4.日本語をメールに流す

1.スプレッドシートで更新を検知したらブログの文章を取り込む

英語のブログ…MSの公式のブログを今回はとってくるのですが、
RSSからIMPORTFEED関数を使って
文章まで一気にとってきます。


▼取り方はこんな感じ。
更新があった際にGASを動かすようにします。
azumikan.hatenablog.com

トリガーは日次で発火します。

2.雑に1000文字ずつに区切って、バンバンAPIになげる

API利用で注意すること
APIの一度のリクエストは30kbまでなので、たくさん投げすぎるとエラーで翻訳できません。
②DeepLには一文ずつも投げられますが、一文ずつの場合1リクエストで50文まで。
urlfetchappを使うのですが、連続でアクセスしすぎると、たまに止まるらしい。(ドキュメント記載なし)


最初一文ずつ投げないのかと行けないと思ったら雑に改行コードつきでも長文を投げられることが判明。
しかし、一気にAPIに放り込んで全部訳そうとしたら、キャパオーバーなのか死んだので
1000文字ずつくらいに区切るといい感じになります。
区切る際は良い感じの区切り部分(句読点、改行、感嘆符など)で区切るとさらにいい感じです。
ちなみに↓のコードはリクエストのエラー処理していない処理ですが、そこは許して…。

3.返ってきた日本語を配列に格納して成形

リクエストのレスポンスはJSON形式なので、JSONの中身を取り出して配列に格納します。

4.日本語をメールに流す

完成!
そしてDeepLから返ってきた日本語、長文は途中で文書が抜けたり、ダブったり
日本語はそれっぽいけど内容が怪しかったりもする…。
ので、完璧なに和訳ではないですが、ざっくり概要把握にはいいかも。

ところどころハードコーディングですが、
完成したコードがこちら:

// シートの新旧で更新を比較
// トリガーに設定するのはこの関数
// C1にFALSEの件数を反映させます。
function copySheet() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
 
  const sheet_new = ss.getSheetByName('new'); 
  const sheet_old = ss.getSheetByName('old'); 
 
  const lastRow = sheet_new.getLastRow(); 
  const lastColumn = sheet_new.getLastColumn(); 
 
  const copyValue = sheet_new.getRange(1,1,lastRow,lastColumn).getValues(); 
  sheet_old.getRange(1,1,lastRow,lastColumn).setValues(copyValue); 

  const data =  sheet_old.getDataRange().getValues();

// C1がFALSEだったら更新通知
  if (data[0][2] > 0){
    console.log("FALSEがあります");
    sendMail(data);
  }

}

// メールを送るスクリプト
// 引数はシートのセル情報
function sendMail(dt) {

  const strTo = "example@example.com";
  const strSubject = "【自動送信】英語のブログに更新がありました";
// シートからとってきたブログURLやら文書やらを格納※ハードコーディングですみません
  const text = dt[5][5];
  const translation = splitTxt(text);
  const strBody = 
    "▼ブログURL:" + dt[5][3] + "\n"
    + "▼DeepL翻訳:" + "https://www.deepl.com/ja/translator"+ "\n"
    + "▼記事名:" + dt[5][1] + "\n" 
    +  translation;

  /* メールを送信 */
  GmailApp.sendEmail(
    strTo,
    strSubject,
    strBody
  ); 
}


// 英文を分割してAPIに送り出すところまでの関数
function splitTxt(str){

// パラグラフをセンテンスに分割
const array = str.replace(/(\.+|\:|\!|\?)(\"*|\'*|\)*|}*|]*)(\s|\n|\r|\r\n)/gm, "$1$2|").split("|");
// APIに投げる文字列を入れる配列
let apiArr = [];
let countArr = [];
let text = '';

for(let i = 0; i <= array.length; i++){
        // 1000字までは配列に格納
    if(text.length < 1000){
        text = text + array[i];
    }else{
        // 1000字超えたら
        apiArr.push(text);
        countArr.push(i);
        text = '';
    }
}
    text = '';
    // console.log(count[0]);
    // console.log(count.length);

for(let i = countArr[countArr.length-1]; i <= array.length; i++){
    text = text + array[i];
}
    apiArr.push(text);
    return DeepLTool(apiArr);

}


// APIに送り出して日本語にする関数
// 引数はブログの英語本文
function DeepLTool(transArr) {

  console.log(transArr);
  const DeepLURL = 'https://api-free.deepl.com/v2/translate?auth_key=';
  const authkey = 'APIのトークン';
  let transresult = [];
  let fetchUrl = '';
  let response = '';
  let results  = '';

  for (const element of transArr) {
    // 必要に応じて設定変えるともっとましなのかもしれない…
    fetchUrl = DeepLURL + authkey + '&text=' + encodeURI(element) +'&target_lang=ja&source_lang=en&preserve_formatting=1';
    response = UrlFetchApp.fetch(fetchUrl);
    results = JSON.parse(response.getContentText());
    transresult.push(transJSON(results));
  }

  return transresult.join('');
  // return transJSON(results);
}

// 受け取ったJSONをテキスト化
function transJSON(JSONdt){
  let results  = JSON.parse(JSON.stringify(JSONdt));
  let trans = results.translations[0].text;
  return trans
}