AppSheetとGoogle Apps Scriptで取材記事の草稿を自動作成する

今回はAppSheetとGoogle Apps Script(以下、GAS)を用いて、Googleスプレッドシートに格納されている情報を反映したGoogleドキュメントを作成しようと思います。

はじめに

Googleスプレッドシートに格納されている情報を反映したPDFの作成方法は知っていましたが、完成されているPDFではなく編集可能なGoogleドキュメントでも同じようなものを作成できないかと考えたのがこのブログを書くきっかけです。

ユースケースはたくさんは思いつかないですが、テレビ局ならではの「記者活用アプリ」などには使えるのでは?と思ったりしています。
取材現場に行った際の「取材メモ」のようなものをAppSheetとこの技術を合わせて使えば、現場にはいないデスクの者も更新されているドキュメントをリアルタイムで確認することができます。リアルタイムで確認することで、記者に対して「この質問もして!」と発注できたり、記者が記事を書く前にデスクの者が代わりに記事を書き、素早いオンエアにもつながるかもしれませんね!

しかし、本格的に弊社の記者に使用してもらおうと思っているわけではないので、この記事は「かるい読みもの」として読んでいただければと思います。

全体のアプリフロー

今回はAppSheetを用いて「記者活用アプリ(仮)」というものを作成していきます。

このアプリはものすごく単純に、「記者名」「取材場所」「取材日」「取材タイトル」「記者メールアドレス」「取材メモの有無」をフォームで答えるようにします。
もしも「取材メモの有無」の項目の回答が「あり」になっていた場合のみ、「取材メモ」のドキュメントが自動で作成され、そのリンクがアプリ上で確認でき、作成されたドキュメントにリダイレクトできるというような流れのアプリを想定しています。

アプリの細かい機能は、今回の記事の本題ではないため割愛させていただきます(かと言って、そんなに機能もりもりではないですが、、)。

ドキュメントのテンプレートの用意

今回のシステムには、ドキュメントを作成するための「テンプレートドキュメント」を用意する必要があります。
この後、GASで作成する新規ドキュメントはこのテンプレートドキュメントをコピーして作成します。
テンプレートドキュメントの中身は、スプレッドシートの情報を格納したい位置に対して「なんらかの文字列」を入力しておいてください(以下の画像を参考にしてください)。

この文字列に対して、スプレッドシートから得た情報を格納していきます。
今回スプレッドシートに格納している情報は以下のようなものを用意しています。

GoogleドキュメントをGASで作成する

ようやく今回の本題。
GASを用いて、スプレッドシートの情報が反映された新規ドキュメントを作成していきます。

まずテンプレートドキュメントのIDを取得します。

const  tempDocID = "**********";

GoogleドキュメントのIDは、URLの**********の部分(https://docs.google.com/document/d/**********/edit )

次に、テンプレートドキュメントをコピーして新規ドキュメントを作成します。
その後、新規ドキュメントを開いて、中身を編集します。

// テンプレートをコピーしてファイル名を設定する
const  docID = DriveApp.getFileById(tempDocID).makeCopy(`${data.name["取材タイトル"]} (${data.name["記者名"]})`).getId();
			
// コピーしたドキュメントのIDを取得して、開き中身を取得する
const  doc = DocumentApp.openById(docID);
// ドキュメントの本文を取得
const  body = doc.getBody();

// ドキュメント内の置換したい「文字列」を指定し、スプレッドシートの情報を渡す
body.replaceText("UniqueID", data.name["ユニークID"])
	.replaceText("Title", data.name["取材タイトル"])
	.replaceText("Date", formattedDate)
	.replaceText("Name", data.name["記者名"])
	.replaceText("Location", data.name["取材場所"]);

// 作成したドキュメントURLをスプレッドシートに書き込み
const  docUrl = `https://docs.google.com/document/d/${docID}/edit`;
// 作成したドキュメントのリンクを書き込み
sheet.getRange(row, sheet.getLastColumn()).setValue(docUrl);

実際に指定している文字列は「正規表現」を使用してください。

最後に、トリガーを適切に設定します。
今回はAppSheetと連携しているので、スプレッドシートの変更時にトリガーがかかるように設定しました。

全体のコード

以上に加え、文中で触れていなかった機能もすこし加えています。

/** 
 * スプレッドシートから特定の行に対応する質問と回答の情報を取得し、それらをオブジェクトとして返す関数。
 * @param {number} row - 取得する情報がある行番号。 
 * @param {object} sheet - 情報を取得するGoogleスプレッドシートのシートオブジェクト。 
 * @return {object} - `{name: object}`形式のオブジェクト。`name`キーには、さらに質問をキーとし、それに対応する回答を値とするオブジェクトが割り当てられている。
 */
function  getSpreadInfo(row, sheet) {
	const  que = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]; // 質問内容
	const  values = sheet.getRange(row, 1, 1, sheet.getLastColumn()).getValues()[0]; // 回答内容
	const  name = {}; // 質問と回答をマッピングするオブジェクト

	for (let  i = 0; i < values.length; i++) {
		name[que[i]] = values[i];
	} 
	return{name:name};
}  

/** 
 * Googleドキュメントを作成し、スプレッドシートに関連情報を記録する関数。
 */
function  makeDocs(){
	const  sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // アクティブなシートを取得
	const  row = sheet.getLastRow();
	const  data = getSpreadInfo(row, sheet);
	const  tempDocID = "**********"; // テンプレートドキュメントのID
	
	const  formattedDate = Utilities.formatDate(data.name["取材日"], "JST", "yyyy/mm/dd(E)");

	if (data.name["記者メモの有無"] === "あり" && data.name["記者メモURL"] === "") {
		// テンプレートをコピーしてファイル名を設定する
		const  docID = DriveApp.getFileById(tempDocID).makeCopy(`${data.name["取材タイトル"]} (${data.name["記者名"]})`).getId();
			
		// コピーしたドキュメントのIDを取得して、開き中身を取得する
		const  doc = DocumentApp.openById(docID);
		// ドキュメントの本文を取得
		const  body = doc.getBody();

		// ドキュメント内の置換したい「文字列」を指定し、スプレッドシートの情報を渡す
		body.replaceText("UniqueID", data.name["ユニークID"])
			.replaceText("Title", data.name["取材タイトル"])
			.replaceText("Date", formattedDate)
			.replaceText("Name", data.name["記者名"])
			.replaceText("Location", data.name["取材場所"]);

		// 作成したドキュメントURLをスプレッドシートに書き込み
		const  docUrl = `https://docs.google.com/document/d/${docID}/edit`;
		// 作成したドキュメントのリンクを書き込み
		sheet.getRange(row, sheet.getLastColumn()).setValue(docUrl);
	}	
}

getSpreadInfo関数は補足にもある通り、スプレッドシートの情報を取得してきてる関数です。
MakeDocs関数のif文では、記者メモが「あり」と回答してまだドキュメントが作成されていない時にコードが走るようにしています。

また、中間のconst formattedDate = Utilities.formatDate(data.name["取材日"], "JST", "yyyy/mm/dd(E)");の部分ですが、スプレッドシート内に日付として情報が格納されている時、このような変換を行わないと「Fri March 01 2024 (Japan Standard Time)」と表記されてしまいます。
全く問題はないのですが、見慣れない形なので見慣れた「2024/03/01(Fri)」という表記に変換しているだけです。

実際に使ってみる

それでは、今までのコードがきちんと動作しているかを確認しみます。

  1. AppSheetからフォームに回答する

  2. フォームの回答がスプレッドシートに格納される

  3. これをトリガーに先ほどのGASが実行される

  4. 新規ドキュメントが作成される
    ー 無事、テンプレートドキュメントに戻づいて、スプレッドシートの情報が反映したドキュメントが作成されています。

  5. AppSheetアプリから新規ドキュメントに移動できる
    - 新規ドキュメントのURLをスプレッドシートに格納したことで、AppSheetからもリダイレクトできるようになっています。

更新されたスプレッドシートは以下。

設計通りの流れで新規ドキュメントが作成されましたね。
GASの実行時間はテンプレートドキュメントをコピーして、編集しているため5~10秒ほどかかりました。

新規ドキュメントを権限設定を正しく行った「共有ドライブ」に作成することで、はじめに述べていた「記者活用アプリ(仮)」 として使用できそうですね。

おわりに

Google Workspace(以下、GWS)はそれぞれのシステムをうまく結合することで、便利なアプリを簡単に作成することができますね。今回のこのアプリもアイデア出しから完成まで1日かからずに済みました。
複数のシステムを結合するときは、権限認証がめんどくさいことになりがちですが、GWS内なら認証もめんどくさくないところが大好きです。

簡単なアプリで自分(とその少しまわり)の業務が効率化する。これがDX推進の第一歩であると思っています!

Next Post Previous Post