Google Gemini で執筆支援
概要
Google の生成 AI「Gemini」を活用した V8 マクロのサンプルです。
テキストを選択した状態でマクロを実行すると、Gemini が文章作成をサポートします。
注意事項
- Mery Ver 3.7.8 以上で動作します。
- Google AI Studio で Gemini API キーを取得してください。
- Gemini API の特性上、送信した文字列が AI の学習に利用される可能性があります。機密情報やプライバシーに関わる内容は送信しないでください。
- 本マクロを登録することで、選択したテキストが Google Gemini に送信され処理されることに同意したものとみなします。データの取り扱いについては、Google Gemini の利用規約およびプライバシーポリシーを必ずご確認ください。
- 2025年6月21日時点で無料の Gemini API を使用しています。ただし、将来の仕様変更や設定ミスにより費用が発生しても、作者は責任を負いません。
使い方
- 環境変数の設定
- コマンド プロンプトで以下のコマンドを実行し、環境変数を設定してください。
setx GEMINI_API_KEY "***************************************"
- 設定後、Mery または Windows の再起動が必要な場合があります。
- マクロの実行
- テキストを選択し、マクロを実行するとポップアップ メニューが表示されます。
- [やわらかく書き換えて] や [要約して] など、相談したい項目を選択すると、Gemini API に送信され、結果が出力されます。
ソースコード (AskGemini.js)
#language = "V8"
#title = "Gemini で執筆支援"
#tooltip = "選択範囲を Google Gemini に相談します。"
/*
1. 環境変数の設定
マクロを使用する前に、コマンド プロンプトで以下の環境変数を設定してください。
setx GOOGLE_API_KEY "***************************************"
2. データ利用についての同意
マクロを登録することにより、文書内のテキスト データが Google Gemini に送信され、処理されることに同意したものとみなします。データの取り扱いやプライバシーに関する詳細は、Google Gemini の利用規約およびプライバシーポリシーをご確認ください。
https://support.google.com/gemini?p=privacy_help
*/
// [出力] 0: 選択範囲の後, 1: 新規文書, 2: アウトプット バー
const output = 0;
async function callGemini(apiKey, promptText) {
try {
const response = await fetch("https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=" + apiKey, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"contents": [{
"role": "user",
"parts": [{
"text": promptText
}],
}],
}),
});
if (!response.ok) {
alert(await response.text());
Quit();
}
const responseObj = await response.json();
if (!responseObj.candidates || responseObj.candidates.length === 0) {
alert("candidates が見つかりませんでした。");
Quit();
}
return responseObj.candidates[0].content.parts[0].text;
} catch (error) {
alert(error.message);
Quit();
}
}
async function main() {
const prefix = "次の文章を";
const rewrite = "書き換え";
const rewrites = [
"やわらかく書き換えて",
"フォーマルに書き換えて",
"エモーショナルに書き換えて",
"わかりやすく書き換えて",
"簡潔に書き換えて",
"バズるように書き換えて"
];
const actions = [
"要約して",
"3 行にまとめて",
"SNS の投稿用にまとめて",
"文末のまとめを書いて",
"-",
"もっと読まれるようにして",
"間違いを見つけて",
"反対意見を書いて",
"炎上しないように確認して"
];
const translate = "翻訳";
const translates = [
"日本語に翻訳して",
"英語に翻訳して",
"中国語に翻訳して",
"韓国語に翻訳して"
];
const ask = "くわしく相談...";
const send = "そのまま送信";
const apiKey = shell.getEnv("GEMINI_API_KEY");
if (!apiKey) {
alert("API キーが設定されていません。");
return;
}
let sel = document.selection;
let text = sel.Text;
if (text.length === 0) {
alert("テキストが選択されていません。");
return;
}
const menu = CreatePopupMenu();
const submenu = CreatePopupMenu();
const submenu2 = CreatePopupMenu();
const askCommandId = 1001;
const sendCommandId = 1002;
let commandId = 0;
for (let i = 0; i < rewrites.length; ++i) {
submenu.Add(rewrites[i], ++commandId);
}
menu.AddPopup(rewrite, submenu);
menu.Add("", 0, meMenuSeparator);
for (let i = 0; i < actions.length; ++i) {
if (actions[i] === "-") {
menu.Add("", 0, meMenuSeparator);
} else {
menu.Add(actions[i], ++commandId);
}
}
menu.Add("", 0, meMenuSeparator);
for (let i = 0; i < translates.length; ++i) {
submenu2.Add(translates[i], ++commandId);
}
menu.AddPopup(translate, submenu2);
menu.Add("", 0, meMenuSeparator);
menu.Add(ask, askCommandId);
menu.Add("", 0, meMenuSeparator);
menu.Add(send, sendCommandId);
const result = menu.Track(mePosMouse);
if (result !== 0) {
let promptText = "";
if (result === askCommandId) {
promptText = prompt("Gemini に相談(&A)", "校正してください。", mePromptMultiline).substring(0, 65530);
if (promptText.length === 0) {
return;
}
} else if (result !== sendCommandId) {
promptText = menu.GetText(result);
}
if (promptText.length !== 0 || text.length !== 0) {
if (promptText.length === 0) {
promptText = text;
} else if (text.length !== 0) {
promptText = prefix + promptText + ":\n" + text;
}
shell.KeepRunning = true;
status = "Gemini に相談しています...";
try {
const response = await callGemini(apiKey, promptText);
switch (output) {
case 1:
editor.NewFile();
editor.ActiveDocument.write(response);
break;
case 2:
outputBar.writeln(response);
outputBar.Visible = true;
break;
default:
BeginUndoGroup();
try {
sel.CharRight();
sel.EndOfLine(false, mePosLogical);
sel.NewLine();
sel.Text = "\n---\n\n" + response.trim() + "\n\n---\n";
} finally {
EndUndoGroup();
}
break;
}
} catch (error) {
console.log("Gemini API エラー: ", error);
} finally {
status = "";
shell.KeepRunning = false;
}
}
}
}
main();
カスタマイズ
- ソースコードの最初の部分で、output の値を変更することで、Gemini の結果をどこに出力するかを選択できます。
// [出力] 0: 選択範囲の後, 1: 新規文書, 2: アウトプット バー
const output = 0;
- Gemini へのアクションは、ソースコードの中ほどで actions などの定数に定義されています。文字列を変更または追加することで、お好みのアクションを定義できます。
const actions = [
"要約して",
"3 行にまとめて",
"SNS の投稿用にまとめて",
"文末のまとめを書いて",
"-",
"もっと読まれるようにして",
"間違いを見つけて",
"反対意見を書いて",
"炎上しないように確認して"
];
スペシャルサンクス
本マクロは、yuko さんが作成された「Google Gemini に相談」マクロにインスパイアされ、Mery のあまり使われていないと思われる V8 マクロ機能を使って実装したサンプルです。yuko さんの素晴らしいアイデアに感謝し、このマクロをお届けします。
スポンサーリンク