📲

AppSheet × GASでJANコードから商品情報を自動取得:外部API連携(楽天API)、AIによる入力調整(Gemini)

2024/12/19に公開

概要

この記事では、AppSheetApps Script、および外部API(楽天APIやGoogle AI StudioのAPI)を組み合わせ、JANコードの入力をトリガーに商品情報を自動取得し、Googleスプレッドシートへ反映する手法を紹介します。

最終的なゴールは以下の通りです:

  • スマホでAppSheetアプリからJANコードをスキャン・入力
  • AppSheetがそのデータ追加をトリガーにAutomationを発火
  • Automationが**「Call a script」**でApps Scriptの関数を実行
  • Apps Scriptが楽天APIから商品情報を取得
  • Google AI StudioのAPIで商品名を簡潔化(例: 長い商品名を短く要約)し、単品価格を計算
  • スプレッドシートに結果が自動反映され、AppSheet側に即時同期

この仕組みにより、ユーザーがシートを手動で編集しなくても、自動的に最新の情報が整備されます。

完成版

背景と課題

従来のアプローチ
onEditonChangeトリガーは、ユーザーがスプレッドシートを直接編集したときにのみ発火します。しかし、AppSheet経由で追加されたデータはユーザー編集とみなされないことが多く、自動処理が期待通り動作しないことがあります。

解決策
AppSheetのAutomationで「Call a script」を使用すると、レコード追加時などのイベントで任意のApps Script関数を呼び出せます。これにより、AppSheet操作をトリガーにApps Scriptコードが起動し、外部APIコール→シート更新が可能になります。

準備物

  • Googleアカウント(Apps Script・AppSheet利用可)
  • 楽天APIキー楽天デベロッパーズより取得)
  • Google AI Studio APIキー
    (Google AI Studio でGeminiのAPIを有効化し、APIキーを取得)
  • AppSheet:JANコード入力用フォーム+Productsシートをデータソースに。

全体構成図

AppSheet App (JANコードスキャン)
        |
        v
  AppSheet Automation (When a record is added)
        |
        v
   Call a script task
        |
        v
    Apps Script (processLastRow())
        |---(UrlFetchApp)---> 楽天API
        |
        |---(UrlFetchApp)---> Google AI Studio API
        |
        ---> スプレッドシート更新

手順詳細

1. スプレッドシートの用意

  • Productsシート作成
  • カラム例:
    A列: JANコード
    B列: 商品名
    C列: メーカー
    D列: 価格
    E列: 単品価格

2. Apps Scriptのスタンドアロンプロジェクト作成

  1. Driveから「新規」→「その他」→「Google Apps Script」で新規プロジェクト作成。
  2. SPREADSHEET_IDYOUR_RAKUTEN_APP_IDYOUR_AI_STUDIO_API_KEYに適宜値を入れる。
const SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID';
const AI_STUDIO_API_KEY = 'YOUR_AI_STUDIO_API_KEY'; // Google AI Studio用APIキー

// 楽天API呼び出し
function getProductInfoFromRakuten(janCode) {
  const applicationId = 'YOUR_RAKUTEN_APP_ID';
  const baseUrl = 'https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706';
  
  janCode = janCode.toString().replace(/^'/, '');
  const params = {
    'applicationId': applicationId,
    'format': 'json',
    'keyword': janCode
  };

  const query = Object.keys(params).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`).join('&');
  const url = `${baseUrl}?${query}`;
  
  const response = UrlFetchApp.fetch(url);
  const data = JSON.parse(response.getContentText());

  if (data && data.Items && data.Items.length > 0) {
    const item = data.Items[0].Item;
    return {
      name: item.itemName || '',
      maker: item.shopName || '',
      price: item.itemPrice || ''
    };
  }
  return null;
}

// 数量抽出&単品価格計算
function calculateUnitPrice(productInfo) {
  const qtyMatch = productInfo.name.match(/(\d+)(|)/);
  let quantity = 1;
  if (qtyMatch) quantity = parseInt(qtyMatch[1], 10);
  productInfo.unitPrice = (quantity > 1) ? Math.round(productInfo.price / quantity) : productInfo.price;
  return productInfo;
}

// Google AI Studio APIを使って商品名を簡潔化
function getSimplifiedProductName(productInfo) {
  // 簡易的な例:Promptを渡して簡略名を生成
  const prompt = `商品名: ${productInfo.name}\nこの商品名を短く、わかりやすく表現してください。価格は${productInfo.price}円です。`;
  
  const url = `https://generativelanguage.googleapis.com/v1beta/models/text-bison-001:generateText?key=${AI_STUDIO_API_KEY}`;
  const payload = {
    prompt: {
      text: prompt
    }
  };
  
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };
  
  const response = UrlFetchApp.fetch(url, options);
  const result = JSON.parse(response.getContentText());
  
  if (result && result.candidates && result.candidates.length > 0) {
    // candidates[0].output に生成テキストがある想定
    const simplifiedName = result.candidates[0].output.trim();
    return { name: simplifiedName };
  }
  return null;
}

// メイン処理関数
function processLastRow() {
  const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheet = ss.getSheetByName('Products');
  if (!sheet) return "No sheet found";

  const lastRow = sheet.getLastRow();
  if (lastRow > 1) {
    const janCode = sheet.getRange(lastRow, 1).getValue();
    if (janCode) {
      let productInfo = getProductInfoFromRakuten(janCode);
      if (productInfo) {
        productInfo = calculateUnitPrice(productInfo);
        const simplified = getSimplifiedProductName(productInfo);
        if (simplified) productInfo.name = simplified.name;

        sheet.getRange(lastRow, 2).setValue(productInfo.name);
        sheet.getRange(lastRow, 3).setValue(productInfo.maker);
        sheet.getRange(lastRow, 4).setValue(productInfo.price);
        sheet.getRange(lastRow, 5).setValue(productInfo.unitPrice);
        return "Product info updated in row: " + lastRow;
      } else {
        sheet.getRange(lastRow, 2).setValue('不明');
        sheet.getRange(lastRow, 3).setValue('不明');
        sheet.getRange(lastRow, 4).setValue('不明');
        sheet.getRange(lastRow, 5).setValue('不明');
        return "No product info found for JAN code: " + janCode;
      }
    }
  }
  return "No action taken";
}

以下は、AppSheetでAutomationを設定する際の詳細な手順と、JANコードスキャンを有効にする方法、およびスプレッドシート(データベース)とのリンク方法をより具体的に解説した内容です。

3. AppSheetでのAutomation設定(詳細版)

前提条件

  • データベース(スプレッドシート)の準備
    すでにGoogleスプレッドシート上にProductsシートを作成し、JANコード, 商品名, メーカー, 価格, 単品価格などの列がある状態を想定します。
  • AppSheetアプリの作成・データリンク
    AppSheetアプリを新規に作成する際、「Start with your data」から作成したProductsシートを選択することで、AppSheetは自動的にこのシートをデータソースとして利用します。

スキャナ機能の有効化

  1. カラム設定の確認
    AppSheetエディタでData > Columnsタブを開き、Productsテーブルを選択します。
    JANコード列を見つけ、Column TypeをTextNumberに設定します。

  2. Scannableオプションの有効化
    JANコードカラムの設定画面で「Scannable」(バーコードスキャン対応)オプションを有効にします。これにより、スマホアプリ上でこのカラムを編集する際、カメラアイコンが表示され、バーコードスキャンが可能になります。

  3. 入力フォームの確認
    UX > Viewsタブで、Productsテーブルに対する「Form」ビューを確認します。
    このフォームでJANコードフィールドをタップするとカメラアイコンが現れ、スマホのカメラを使用してJANコードをスキャンできます。
    ユーザーはスマホでAppSheetアプリを開き、「Add」ボタンなどから新規レコード追加フォームに進むと、JANコードをスキャン入力可能になります。

データベース(スプレッドシート)へのリンク確認

  • AppSheetはデータソースとしてGoogle Sheetsを利用するため、Productsシートに新規レコード(JANコード)を追加すると、自動的にGoogleスプレッドシート側にも行が追加・変更されます。
  • スマホでJANコードをスキャン→保存すると、数秒以内にスプレッドシートが更新されるので、後述のAutomationがそのイベントをトリガーとして発火します。

Automationの設定手順

  1. AppSheetエディタでAutomationを開く
    AppSheetエディタで上部メニューからAutomationタブを選択します。
    Automationは「Event(トリガー条件)」と「Process(処理フロー)」の2つを定義する必要があります。

  2. イベント定義(When a new row is added)
    Productsテーブルに新規行が追加されたことを検知するイベントを作成します。

    • 「Event」→「+ New Event」をクリックし、イベントタイプにData: adds onlyを選択します。
    • For TableProductsを選択します。
      これでProductsシートに新規行(JANコード記入行)が追加されると、このイベントが発火します。
  3. プロセス定義(スクリプト呼び出し)
    イベントが発火した際に実行する処理(Process)を定義します。

    • 「Process」→「+ New Process」をクリックし、任意の名称(Update Product Info Processなど)を付けます。
    • プロセス内で「+ Step」をクリックしてタスクを追加します。
    • タスクのタイプ一覧から「Call a script」を選択。
  4. Call a scriptの設定
    「Call a script」タスクで、先ほど作成したスタンドアロンApps Scriptプロジェクトの関数を呼び出します。

    • 「Script Project ID」欄に、Apps ScriptプロジェクトのIDを入力します。
      (Apps Scriptエディタで「プロジェクトの設定」からIDを取得できます)
    • 「Script Function Name」欄にはprocessLastRow(先ほど定義したメイン処理関数名)を入力します。
    • Saveをクリックして保存します。
  5. 権限の承認
    初回実行時や保存時、AppSheetがApps Scriptを呼び出すための権限付与要求が表示される場合があります。
    その場合は「Allow」や「Authorize」などのボタンをクリックし、Apps ScriptプロジェクトとAppSheetアプリ間の接続を許可します。

この設定で何が起きるか

  • ユーザーがスマホのAppSheetアプリで「Add」ボタンを押し、新規フォームでJANコードをスキャン→保存します。
  • AppSheetは即時にProductsシートへ新規レコードを追加します。
  • When a new row is added to Productsイベントが発火し、定義したプロセスが走ります。
  • プロセス内の「Call a script」タスクによってprocessLastRow関数が実行されます。
  • processLastRow関数は楽天APIやGoogle AI Studio APIを呼び出し、商品情報を取得・簡略化してスプレッドシートへ書き込む処理を行います。
  • 更新が終わると、AppSheet側でも同期が行われ、ユーザーはスマホアプリ上で詳細情報(簡潔化した商品名、メーカー、価格、単品価格)をすぐに確認できます。

まとめ

このように、スキャナ機能はJANコード列のScannable設定で実現し、データベースとしてのスプレッドシートはAppSheet作成時に選択したProductsシートを自動的にリンクしています。Automationで「When a new row is added」イベントと「Call a script」タスクを組み合わせることで、AppSheet経由のデータ追加をトリガーにApps Script関数を呼び出し、自動処理と外部API連携を実現できます。

4. テスト

  • AppSheetからJANコードを入力後、保存。
  • スプレッドシートを確認すると、商品名・メーカー・価格・単品価格が反映。
  • AI Studioによる簡易的な短縮商品名が表示されるはずです。

参考資料

まとめ

本記事では、JANコードの入力からAppSheet経由でApps Scriptを実行し、楽天API→AI Studio API→シート更新といった流れを実現しました。onEditに頼らず、AppSheetの「Call a script」を用いることで、ユーザー操作(AppSheet上のデータ入力)をトリガーとして外部API連携が自動的に行えます。
Google AI Studio APIを利用して商品名を簡潔化することで、長い商品名を見やすくし、また数量解析による単品価格計算で価格情報をより実用的な形に整えることができます。

Discussion