本コードをサイトに転載したり、改変して配布することを禁止します。本コードが原因で起こったトラブル等は一切責任を持ちません。必要に応じて使用前にコードの動作確認を行った上、自己責任でお使いください。
本コードの保守メンテナンス等は一切行いませんので、あらかじめご了承ください。本コードは突然非公開にする場合があります。
エラーが出て動作しない人は以下をご確認ください(同じページ内の該当箇所にジャンプ)。 エラーが出た時の対処法
2023/3/6 Ver1.0.0を公開
本コードの使い方は以下の動画で解説しています。
1.以下のコードを全てコピーしてGoogle DocsのApps Scriptに貼り付けてください。
//**本コードをサイトに転載したり、改変して配布することを禁止します。
//本コードが原因で起こったトラブル等は一切責任を持ちません。
//必要に応じて使用前にコードの動作確認を行った上、自己責任でお使いください。
//解説ページ:<https://merilinc.notion.site/9356ec5fc73f46188a77b759e8d6710b>
//上記のコメントも削除せずに、そのまま貼り付けてください。**
const OPENAI_API_KEY = "Open AIのAPIキーを設定してください。";
const OPENAI_MODEL = "gpt-3.5-turbo";
const IMAGE_SIZE = '512x512'; // 画像サイズ:512x512、1024x1024
const MAX_INPUT_LENGTH = 2048; // 入力文字数の上限
// メニューを作成する
function onOpen() {
DocumentApp.getUi().createMenu("ウェブ職TV")
.addItem("KWからタイトル案を考える", "generateTitles")
.addItem("KWから記事構成案を考える", "generateIdeas")
.addItem("構成から下書きを作成する", "blogwriting")
.addItem("選択部分の詳細を書く", "detailwriting")
.addItem("選択部分を簡潔に書く", "simplewriting")
.addItem("選択部分の誤字脱字を修正する", "correctSentence")
.addItem("選択部分を別の文章に書き直す", "rewrite")
.addItem("画像を生成する(英語推奨)", "generateImage")
.addToUi();
}
function generateText(prompt) {
const requestBody = {
"model": OPENAI_MODEL,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0,
"max_tokens": MAX_INPUT_LENGTH,
};
const requestOptions = {
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer "+OPENAI_API_KEY
},
"payload": JSON.stringify(requestBody),
"muteHttpExceptions" : true,
}
try {
const response = UrlFetchApp.fetch("<https://api.openai.com/v1/chat/completions>", requestOptions);
const responseText = response.getContentText();
const json = JSON.parse(responseText);
const generatedText = json.choices[0].message.content;
return generatedText.toString();
} catch(e) {
throw new Error(`テキスト生成に失敗しました。`+e);
}
}
function getSelectedText(colorChange=false) {
const selection = DocumentApp.getActiveDocument().getSelection();
let selectedText = '';
if (!selection) {
throw new Error('テキストが選択されていません。');
}
const elements = selection.getRangeElements();
for (let i = 0; i < elements.length; i++) {
const element = elements[i].getElement();
if (element.editAsText) {
const text = element.asText().getText();
const startIndex = elements[i].getStartOffset();
const endIndex = elements[i].getEndOffsetInclusive();
selectedText += text.substring(startIndex, endIndex + 1);
if (colorChange) {
element.asText().setForegroundColor(startIndex, endIndex, '#D80000');
}
}
}
if (selectedText.length > MAX_INPUT_LENGTH) {
throw new Error('選択したテキストが'+MAX_INPUT_LENGTH+'文字を超えています。');
}
return selectedText;
}
//選択テキスト直後にテキスト挿入
function insertTextAfterSelection(insertText) {
const selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
const elements = selection.getRangeElements();
for (let i = 0; i < elements.length; i++) {
const element = elements[i].getElement();
const text = element.asText();
const startIndex = elements[i].getStartOffset();
const endIndex = elements[i].getEndOffsetInclusive();
element.asText().setForegroundColor(startIndex, endIndex, '#0711bf');
text.insertText(endIndex+1, "\\n\\n" + insertText.replace(/^[\\n\\r]+|[\\n\\r]+$/g, ''));
}
}
}
function insertImageAfterSelection(image) {
const selection = DocumentApp.getActiveDocument().getSelection();
if (!selection) return;
const elements = selection.getRangeElements();
const parent = elements[elements.length - 1].getElement().getParent();
const index = parent.getChildIndex(elements[elements.length - 1].getElement());
parent.insertInlineImage(index + 1, image);
return;
}
function inputPrompt() {
var response = DocumentApp.getUi().prompt(
'キーワード設定',
'キーワードを入力してください',
DocumentApp.getUi().ButtonSet.OK_CANCEL
);
if (response.getSelectedButton() == DocumentApp.getUi().Button.OK) {
if( !response.getResponseText() ){
throw new Error('キーワードが入力されていません。');
}
return response.getResponseText();
} else {
return false;
}
}
// 選択したテキストをもとにタイトル案を考える
function generateTitles() {
const inputKeyword = inputPrompt();
if( inputKeyword ){
const prompt = "キーワード「" + inputKeyword + "」でGoogle検索したユーザーのクリック率が高くなる記事タイトル案を10個考えて。タイトルには具体的な数字、記事を読むメリットなどを含めること。";
DocumentApp.getActiveDocument().getBody().appendParagraph("キーワード:"+inputKeyword+""+generateText(prompt)+"\\n\\n");
}
}
// 選択したテキストをもとに記事構成案を考える
function generateIdeas() {
const inputKeyword = inputPrompt();
if( inputKeyword ){
const prompt = "キーワード「" + inputKeyword + "」でGoogle検索したユーザーが知りたいことを深掘りして、再検索キーワードの検索意図も含めて、ユーザーの全ての検索意図を満たす専門的な記事構成を考えて。H2見出し、H3見出しをそれぞれ分けて考えること。再検索キーワードは回答に書かないでください。";
DocumentApp.getActiveDocument().getBody().appendParagraph("キーワード:"+inputKeyword+"\\n"+generateText(prompt)+"\\n\\n");
}
}
// 選択したテキストをもとにブログ記事を書く
function blogwriting() {
const prompt = getSelectedText() + "\\n\\n上記の構成をもとに本文を書いて。H2見出しは##、H3見出しは###を文頭につけること";
DocumentApp.getActiveDocument().getBody().appendParagraph(generateText(prompt));
}
// 選択したテキストをもとに詳細を書く
function detailwriting() {
const prompt = getSelectedText() + "\\n\\nこの文章をもとに、さらに詳しく専門的な文章を書いて。必要があればH4見出しを追加してもOK。H4見出しは####を文頭につけること。「そして」「また」のような順接や並列の接続詞はなるべく使わないこと。文章の前後の改行を含めないこと。";
insertTextAfterSelection(generateText(prompt));
getSelectedText(true);
}
// 選択したテキストを簡潔に書く
function simplewriting() {
const prompt = getSelectedText() + "\\n\\nこの文章を短く簡潔にまとめ直して。";
insertTextAfterSelection(generateText(prompt));
getSelectedText(true);
}
// 選択したテキストを修正して
function correctSentence() {
const prompt = getSelectedText() + "\\n\\nこの文章の誤字脱字やおかしなところを修正して。";
insertTextAfterSelection(generateText(prompt));
getSelectedText(true);
}
// 選択したテキストを書き直して。
function rewrite() {
const prompt = getSelectedText() + "\\n\\nこの文章を別の文章に書き直して。";
insertTextAfterSelection(generateText(prompt));
getSelectedText(true);
}
// 選択したテキストをもとに画像を生成する
function generateImage() {
const apiUrl = '<https://api.openai.com/v1/images/generations>';
const prompt = "「"+getSelectedText()+"」を英語に翻訳してから実行して。No text should be placed within the image.";
let headers = {
'Authorization':'Bearer '+ OPENAI_API_KEY,
'Content-type': 'application/json',
'X-Slack-No-Retry': 1
};
let options = {
'muteHttpExceptions' : true,
'headers': headers,
'method': 'POST',
'payload': JSON.stringify({
'n': 1,
'size' : IMAGE_SIZE,
'prompt': prompt})
};
const response = JSON.parse(UrlFetchApp.fetch(apiUrl, options).getContentText());
const image = UrlFetchApp.fetch(response.data[0].url).getAs('image/png');
insertImageAfterSelection(image);
}
以下をクリックするとコードを貼り付けるエディタが開きます。
以下に最初に書いてあるコードを削除して、コピペしてください。
2.コードの一番上のAPIキーにOpen AIで取得したAPIキーを貼り付ける
APIキーの取得はこちら:https://platform.openai.com/account/api-keys