LoginSignup
3
1

はじめに

Power Appsには、プロンプトからDataverseテーブルを作成するという非常にCoolな機能が追加されています。

image.png

サンプルデータを作成してくれることは、ありがたい・・・。
なんだかんだこういったサンプルデータを活用するシーンって多いなと感じています。

少なくとも自分で一から考えるのは大変です。

GPTを活用すればいいのでは?

もちろんChatGPTを使えば一発で解決する話です。
サイトにアクセスしてプロンプトを打てばOK!!

ChatGPTにアクセスして、プロンプトさえ渡せば解決するんです。
ただそれがもう手間。

表データの取り扱いは、Excelでなんだかんだ調整するシーンが多いため、この機能をExcelにも追加したい!

そこでGPT-4oAPIをたたく際に、JSON フォーマットを指定すれば、うまい具合にパースできるのでは🧐という仮説を立てたため、今回検証してみました🐟

この記事は2024.06.16時点の記事です。Copilot for Microsoft 365にありそうな機能ですが、使えない状況の個人利用を想定しています。
標準で配置されそうな機能ですが、もう今必要なもの!ということでアウトプットします!

Excelからのシナリオを考える

先日のQiitaの記事でも紹介させていただきましたが、Excelからデスクトップアプリブラウザ問わず、Power Automateを実行できます。

[ 自動化 ]タブの[ 作業の自動化 ]、[ このブック内のフロー ]から、Power Automateが起動できます。

ExcelからOffice Scripts経由で、Outlookの連絡先を追加する(with Graph API)

  1. Excelからサンプルデータが欲しいテーマを指定し
  2. Power Automateでプロンプトを作成、GPT-4oからサンプルデータであるJSONを取得
  3. Office ScriptsJSONを解析し、ブックに追加

上記のアプローチで進めてみましょう。

Excelの準備

前述のとおり[ 自動化 ]タブの[ 作業の自動化 ]、[ このブック内のフロー ]から、Power Automateが起動できます。

テンプレートをクリックし、Excelから呼び出すPower Automateフローの準備をします

  1. テンプレートのうちSend Bulk Emailsを選択、作成をクリック
    image.png
  2. このブック内のフローに追加された場合、Power Automateの画面でフローを編集できます
    image.png

Office Scriptsの解説は後述します

Power Automateの準備

前述で追加したPower Automateフローを全部消去します。

フローの流れ

  1. フローを手動でトリガーする - Excelの画面から作成したいデータのテーマを受け取る
  2. 作成 - JSON配列入力のスキーマをGPT-4oで作成するためのプロンプトを作成
  3. シークレットの取得[Azure Key Vault] - Azure Key Vaultに格納したOpenAIAPIキーを取得
  4. HTTP 要求GPT-4oAPIを使用し、サンプルデータのJSON Schemaを作成
  5. 作成 - サンプルデータを取得するためのプロンプトを作成
  6. HTTP 要求GPT-4oAPIを使用し、サンプルデータを作成
  7. Office ScriptsExcelにシートを追加し、サンプルデータを追加

GPT-4oのAPIを2回使用しています。
様々なデータのスキーマの定義もGPT-4oにやってもらおう!という思想の元です。
ここもできてしまうわけですから、GPT-4oはとんでもないなと思います。

1. フローを手動でトリガーする - Excelの画面から作成したいデータのテーマを受け取る

文字列の入力を追加するのみです。

image.png

2. 作成 - JSON配列入力のスキーマをGPT-4oで作成するためのプロンプトを作成

GPT-4oで利用するためのプロンプトです。

image.png

JSON Schema {\"type\":\"string\"}}と指定することにより、サンプルデータを作成するときのためのJSON Schemaがエスケープ文字込みの状態で、うまい具合に作られます。

JSONスキーマを定義するためのプロンプト
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "与えられたプロンプトに対して、ダミーデータをJSONで作成します。配列入力のスキーマを提供してください。"
    },
    {
      "role": "user",
      "content": "@{起動時に受け取るデータのテーマ}のダミーデータのスキーマを作成してください。 ## JSON Schema {\"type\":\"string\"}}"
    }
  ],
  "temperature": 0.8,
  "max_tokens": 2000,
  "response_format": {
    "type": "json_object"
  }
}

3. シークレットの取得 [Azure Key Vault] - Azure Key Vaultに格納したOpenAIAPIキーを取得

Azure Key Vaultの取得は以前からブログで複数回取り上げているため、割愛します

image.png

4. HTTP 要求GPT-4oAPIを使用し、サンプルデータのJSON Schemaを作成

私のQiita記事では最高に反響があった記事のアプローチと同様です。

image.png

■ HTTP

キー
URI https://api.openai.com/v1/chat/completions
Method POST

ヘッダー

キー
Content-Type application/json
Authorization Bearer @{outputs('シークレットの取得')?['body/value']}

Bodyは前述の(2)作成アクションで作成したJSON

body
@{outputs('Prompt')}

5. 作成 - サンプルデータを取得するためのプロンプトを作成

(4)でGPT-4oから取得したJSON Schemabody('CreateSchema')?['choices'][0]?['message']?['content']に格納されます。
CreateSchemaは私の設定したJSONスキーマを作成するためのアクション名です。

image.png

こちらを活用して、あらためてプロンプトを作成!!

プロンプト
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "与えられたプロンプトに対して、ダミーデータを提供してください。日本の情報をベースに作成してください。"
    },
    {
      "role": "user",
      "content": "JSON配列入力形式で@{outputs('InputData')}のダミーデータを作成してください。配列のキー値はvaluesで統一してください。 ## JSON Schema {\"type\":\"array\",\"items\":@{body('CreateSchema')?['choices'][0]?['message']?['content']}]}}"
    }
  ],
  "temperature": 0.8,
  "max_tokens": 2000,
  "response_format": {
    "type": "json_object"
  }
}

6. HTTP 要求GPT-4oAPIを使用し、サンプルデータを作成

(4)と一緒ですね。

image.png

■ HTTP

キー
URI https://api.openai.com/v1/chat/completions
Method POST

ヘッダー

キー
Content-Type application/json
Authorization Bearer @{outputs('シークレットの取得')?['body/value']}

Bodyは前述の(2)作成アクションで作成したJSON

body
@{outputs('CreateDataPrompt')}

このアクションの戻り値body('HTTP-CreateDummyData')?['choices'][0]?['message']?['content']Office Scriptsに渡して完了です。

image.png

Office Scripts

まずは手っ取り早くコードを載せてしまいます。
GPT様様で作成しています。

Office Scripts
function main(workbook: ExcelScript.Workbook, jsonInput: string) {
  // ネストされたオブジェクトをフラット化するヘルパー関数
  function flattenObject(obj: Record<string, unknown>): Record<string, string | number> {
    const toReturn: Record<string, string | number> = {};

    for (const key in obj) {
      // プロトタイプチェーン上のプロパティは無視
      if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;

      const value = obj[key];

      // プロパティがオブジェクトの場合,フラット化
      if (typeof value === 'object' && value !== null) {
        const flatObject = flattenObject(value as Record<string, unknown>);
        for (const nestedKey in flatObject) {
          if (!Object.prototype.hasOwnProperty.call(flatObject, nestedKey)) continue;

          // ネストされたプロパティを結合して新しいキーを作成
          toReturn[`${key}.${nestedKey}`] = flatObject[nestedKey];
        }
      } else {
        // プロパティがオブジェクトでない場合、追加
        toReturn[key] = value as string | number;
      }
    }
    return toReturn;
  }

  // 新しいシート名を生成するヘルパー関数
  function generateUniqueSheetName(baseName: string, workbook: ExcelScript.Workbook): string {
    let newSheetName = baseName;
    let counter = 1;
    while (workbook.getWorksheet(newSheetName)) {
      newSheetName = `${baseName} (${counter})`;
      counter++;
    }
    return newSheetName;
  }

  try {
    // 1. JSON文字列をオブジェクトに変換
    const parsedJson = JSON.parse(jsonInput) as { values: Record<string, unknown>[] };
    // 配列のキーはプロンプトで`values`に固定
    const data = parsedJson.values;

    if (!Array.isArray(data) || data.length === 0) {
      throw new Error("Invalid or empty data array");
    }

    // 2. 新しいシート名を生成し、追加
    const newSheetName = generateUniqueSheetName("Parsed Data", workbook);
    const newSheet = workbook.addWorksheet(newSheetName);

    // 3-1. 最初のデータオブジェクトをフラット化して、ヘッダー行を設定
    const headers = Object.keys(flattenObject(data[0]));
    newSheet.getRangeByIndexes(0, 0, 1, headers.length).setValues([headers]);

    // 4. 各データオブジェクトをフラット化してシートに設定
    const values = data.map(item => {
      const flattenedItem = flattenObject(item);
      return headers.map(header => flattenedItem[header]);
    });
    newSheet.getRangeByIndexes(1, 0, values.length, headers.length).setValues(values);

  } catch (error) {
    console.log("Error processing JSON input: ", error.message);
    const errorSheetName = generateUniqueSheetName("Error", workbook);
    const errorSheet = workbook.addWorksheet(errorSheetName);
    errorSheet.getRange("A1").setValue(`Error processing JSON input: ${error.message}`);
  }
}
  1. 受け取ったJSONを配列に変換
  2. シート名重複時対策に、シート追加の関数を追加
  3. 二次元配列に固定化するためのフラット化の関数を実行
  4. 新しいシートにサンプルデータを作成

上記のことを実施しています。

スクリプトの中でもparsedJson.valuesは、GPTが二次元配列のキーをvaluesに設定してくれなければ上手くいきません。

const data = parsedJson.values;

実際の挙動は・・・!

このアクションはWeb 用 Excelではないと、コンフリクトを起こし、失敗します。
実験するときはWeb 用 Excel でやりましょう。

フローを実行すると、プロンプトの入力画面がでます。

image.png

人事と打って、実行します。

image.png

おお!次は営業活動

image.png

経費精算

image.png

製品

image.png

なんだかんだ上手くいくものですね。
エラーも想定外に発生しません。

image.png

やっぱりGPT-4oは凄すぎる!!

今回も読んでくださり、ありがとうございました。🐟✨

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1