top of page

GAS × Gemini で手書き帳票をAI-OCR ― スプレッドシートに自動入力する

  • 6月22日
  • 読了時間: 7分

2026年6月17日(水)、高知県の「IoP技術者コミュニティ」第4回定例会を、オンライン(Teams)と弊社高知オフィスのハイブリッドで開催しました。PROMPT-XはIoP技術者コミュニティの事務局を務めています。テーマは「GAS(Google Apps Script) × AI で営農記録をデジタル化」。コミュニティ会員でもある井上石灰工業株式会社の今田潔氏を講師に迎え、参加者全員が手元でコードを動かすハンズオン形式で行いました。


この記事では、当日のハンズオンから「手書きの記録表をGASとGeminiでスプレッドシートに自動入力する」実装を、動くコードとともに紹介します。Googleアカウントさえあれば追加費用ゼロで試せます。


地方拠点から全国レベルの開発に挑戦してみたい方は、記事末尾の採用情報もご覧ください。


まず、GASからGeminiに質問してみる


業務効率化に役立てられるAIツールは多く存在します。たとえば昨年のIoP技術者講座で取り上げたDifyやn8nなどがあります。AIベンダーも、コーディング支援や業務自動化を担うエージェント型ツールとして Anthropic が Claude Code / Claude Cowork、OpenAI が Codex を提供するなど、選択肢が増えています。


そのような中で、これまで業務のなかで使い慣れ親しんできた GAS(Google Apps Script)でも AI を活用できるというのが井上石灰工業さまが昨年の IoP 技術者コミュニティ アイデアソンで発表されたアイデアでした。


GASは、Googleアカウントがあれば無料で使えるサーバーレスの実行環境です。`UrlFetchApp`で外部APIを叩けるので、Gemini APIもそのまま呼べます。APIキーはGoogle AI Studioで発行し、コードに直書きせず`PropertiesService`(スクリプトプロパティ)に保存します。



まずGeminiに文章を渡してみる


まず最小形として「プロンプト(文章)を渡す → 答えが返る」というところを確認しました。


const GEMINI_MODEL = 'gemini-3.1-flash-lite';
const prompt = '高知県のIoPについて教えてください';

// 実行用:メニューの ▶ から run を選ぶと、ログに答えが出力される
function run() {
  Logger.log(askGemini(prompt));
}

function askGemini(prompt) {
  // APIキーはコードに直書きせず、スクリプトプロパティから読む
  const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  const url = 'https://generativelanguage.googleapis.com/v1beta/models/'
    + GEMINI_MODEL + ':generateContent';

  const res = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    headers: { 'x-goog-api-key': apiKey },
    payload: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] }),
    muteHttpExceptions: true
  });
  return JSON.parse(res.getContentText()).candidates[0].content.parts[0].text;
}


モデルには、安価・高速な軽量モデル「gemini-3.1-flash-lite」を指定しています。無料枠も充実しているので、受講者も気兼ねなく何度も試せます。昨年の講座ではOpenAIの「gpt-5-nano」を使いましたが、同じ低価格帯のモデルでも、知識量の充実やハルシネーションの減少といったAIモデルの進化を実感できました。


手書きの記録を画像で読ませる(Gemini OCR)


次に「文章 + 画像」を渡して、手書きの記録表を読み取らせます。ポイントは、画像処理もすべてGAS側で完結させていることです。写真はGoogleドライブに置くだけでよく、`DriveApp`で読み込んで`Utilities.base64Encode`し、`inline_data`としてプロンプトと一緒に`parts`へ入れて渡します。画像を別途アップロード(Files API)する手順が要らず、1回のリクエストにまとめて送れるので構成がシンプルです。




// 実行用:Googleドライブの画像ファイルIDを指定して読み取る
function runImage() {
  const fileId = 'ここにGoogleドライブの画像ファイルIDを入れる';
  Logger.log(readImage(fileId, 'この表を読み取って、内容をテキストで教えてください'));
}

function readImage(fileId, prompt) {
  const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  const blob = DriveApp.getFileById(fileId).getBlob();   // ドライブの画像を読む
  const url = 'https://generativelanguage.googleapis.com/v1beta/models/'
    + GEMINI_MODEL + ':generateContent';

  const res = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    headers: { 'x-goog-api-key': apiKey },
    payload: JSON.stringify({ contents: [{ parts: [
      { text: prompt },                                  // 質問(プロンプト)
      { inline_data: { mime_type: blob.getContentType(),
                       data: Utilities.base64Encode(blob.getBytes()) } }  // 画像
    ] }] }),
    muteHttpExceptions: true
  });
  return JSON.parse(res.getContentText()).candidates[0].content.parts[0].text;
}

これで手書きの表を読み取って文章で返してくれます。ただし、返ってくるのは「表っぽいテキスト」のみ。あとで集計やグラフ化をしたいなら、これでは足りません。


スプレッドシートにAIの結果を「使える列」で書き込む(responseSchema)


AI×スプレッドシートを実用的に使いたいなら、Geminiの構造化出力(`responseSchema`)が役に立ちます。「ほしい列の形」を指定すると、その形のJSONだけを返してくれます。あとは`setValues`で「1行=1レコード」に展開すれば、そのまま合計・平均・グラフ化できる“使えるデータ”になります。


// 実行用:画像ファイルIDと書き込み先スプレッドシートIDを指定
function runToSheet() {
  const fileId  = 'ここにGoogleドライブの画像ファイルIDを入れる';
  const sheetId = 'ここに書き込み先スプレッドシートのIDを入れる';
  readImageToSheet(fileId, sheetId);
}

function readImageToSheet(fileId, sheetId) {
  const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  const url = 'https://generativelanguage.googleapis.com/v1beta/models/'
    + GEMINI_MODEL + ':generateContent';

  // 画像を inline_data で渡す(readImage と同じやり方)
  const blob = DriveApp.getFileById(fileId).getBlob();
  const imagePart = { inline_data: {
    mime_type: blob.getContentType(),
    data: Utilities.base64Encode(blob.getBytes())
  } };

  // ほしい「列の形」を指定する(Gemini はこの形の JSON だけを返す)
  const schema = {
    type: 'ARRAY',
    items: {
      type: 'OBJECT',
      properties: {
        '日':       { type: 'INTEGER' },
        '天気':     { type: 'STRING'  },
        '給液差分量': { type: 'INTEGER' },
        '排液率':   { type: 'INTEGER' }
      }
    }
  };

  const prompt = 'この給液・排液記録表を、各行を1レコードとして読み取ってください';
  const res = UrlFetchApp.fetch(url, {
    method: 'post', contentType: 'application/json',
    headers: { 'x-goog-api-key': apiKey },
    payload: JSON.stringify({
      contents: [{ parts: [ { text: prompt }, imagePart ] }],
      generationConfig: {                       // ← 構造化出力のキモ
        responseMimeType: 'application/json',   //   「JSON で返して」
        responseSchema: schema                  //   「この列の形で」
      }
    }),
    muteHttpExceptions: true
  });

  // 応答の中身は JSON 文字列なので、もう一度 parse して配列に戻す
  const rows = JSON.parse(
    JSON.parse(res.getContentText()).candidates[0].content.parts[0].text
  );

  // シートに「ヘッダ + 全データ行」を一気に書き込む → そのまま集計できる
  const headers = ['日', '天気', '給液差分量', '排液率'];
  const values  = [headers].concat(rows.map(r => headers.map(h => r[h])));
  SpreadsheetApp.openById(sheetId).getSheets()[0]
    .getRange(1, 1, values.length, headers.length).setValues(values);
}


紙の手書き記録 → 写真 → 構造化データ(表)まで、GASだけで一気通貫です。あとはこの関数を時間トリガーで回せば「撮ってフォルダに入れる → 自動で表になりシートに溜まる」まで全自動にできます。


プロンプトとモデルのコツ


  • 最新のモデルは、以前ほど細かくプロンプトを作り込まなくても読み取れる。指示を凝りすぎなくてよい方向に変わってきている。

  • 「CSVにして」「Excelにそのままコピペできるように」と出力フォーマットを指定すると、そのまま使える結果が返る(構造化出力はその発展形)。


「かつては高いモデルで複雑なプロンプトを書かなければ読み取れなかった資料も、安いモデルでシンプルなプロンプトで、現場の手書き帳票がここまで読めるようになった」。AIによる帳票の電子化が、特別な投資なしに現場の手で始められる時代になってきたことを、参加者全員で確かめられた回になりました。井上石灰工業さまがアイデアソンで提案されたGASの活用は、こうした現場主導のAI活用に有効だということを実感しました。


講座をふりかえって


ハンズオンの後の意見交換では、各社それぞれの応用アイデアが次々と出ました。「電話などの接客応対メモなど様々なデータに使えそう。もっとちょっとしたメモのような用途にも」「AIのいいところが見えた。手書きのものを読ませるところに手応えがあった」。「小さく始められるものがいい。スクリプトが長くなりすぎると本末転倒で、簡単であること自体が価値」という声もいただきました。


講師の今田氏は「GASはIT系じゃなくてもとっつきやすい。外注ではなく内製に挑戦した」と語るように、現場主導こそが最も効果的なAI導入のあり方です。書籍やオンライン記事には残りにくい試行錯誤の過程や、実際に動くコードを、地域のエンジニアや企業が直接交換できる実践的な場は、高知で実務に携わる私たちにとっても貴重です。PROMPT-Xは引き続き本コミュニティの事務局として、高知県の施設園芸産業のデジタル化・スマート化を支えていきます。


手を動かしてAI活用を学ぶ ― Technovation Workshop


今回のように「実際にコードを動かしながら学ぶ」スタイルで、最先端のテクノロジーをビジネスの現場で活かすスキルを身につけられる体験型講座として、PROMPT-XはTechnovation Workshopを提供しています。「IoTとAI」「画像とAI」「データとAI」の3つのハンズオンプログラムで構成され、今回の記事で扱った画像のAI読み取りや時系列データの活用なども、基礎から体系立てて学べます。エンジニアの方はもちろん、ビジネスの現場で課題解決にAIを役立てたい方にもおすすめです。


PROMPT-Xでは仲間を募集しています


PROMPT-Xは東京・鹿児島・高知に拠点を置いています。お客さまの現場に入り込み、業務課題に対して生成AIを含む最新技術をどう活かすかを一緒に考え、実装まで伴走するエンジニアを募集しています。地方拠点から全国の先進企業・自治体と直接取引を行い、上流設計から実装まで一気通貫で手がける環境です。今回のような「現場の人が自分で小さく作れる」を後押しする活動に興味がある方を歓迎します。


PROMPT-Xで働くことに興味がある方は、採用情報ページをご覧ください。鹿児島での募集はジョブアンテナ鹿児島もあわせてご覧いただけます。


関連リンク





 
 
 

コメント


bottom of page