挨拶
最近は、「Dify入門シリーズ」の検証+執筆にいそしんでいる龍ちゃんです。応用的ステップとして、GASで本格運用する業務アプリの開発などもやっていました。こちらの業務アプリでは、DifyのAPIを叩くわけでなく、Azure OpenAI Service(AOAI)のREST APIで生成AIを実行しています。
今回は、参照用のサンプルコードとして「プロパティサービスを活用してアクセスキーなどを保護しつつ、APIのリクエストを作成するスクリプト」を書いておきます。
検証に使用したモデルのバージョンとAPIのバージョンは以下になります。
項目 | バージョン |
---|---|
モデル | GPT-4o-mini |
AOAI APIバージョン | 2024-10-21 |
サンプルコード:スクリプトプロパティでアクセスキーを取得
AOAIのモデルのデプロイ等は、終わっていると仮定して進めていきます。REST APIのアクセスには、以下の情報が必要になります。必要な情報はこちらを参考に取得してください。
コンテンツ | 説明 |
---|---|
エンドポイント | Azure Portal上で確認するエンドポイント |
キー | Azure Portal上で確認するアクセスキー |
モデル名 | モデルをデプロイした際に設定したデプロイ名 |
APIバージョン | MS Learn上で参照して最新のGAリリースの情報を取得 |
こちらの情報を取得して、スクリプトプロパティとして保存しておきます。スクリプトプロパティの登録などはこちらを参考にしてください。以下のパラメータで保存しています。
コンテンツ | スクリプトプロパティ |
---|---|
エンドポイント | AOAI_API_URL |
キー | AOAI_API_KEY |
モデル名 | AOAI_API_MODEL |
APIバージョン | AOAI_API_VERSION |
上記のパラメータで保存することで、以下のスクリプトがそのまま使うことができます。
const apiEndpoint = PropertiesService.getScriptProperties().getProperty("AOAI_API_URL");
const modelName = PropertiesService.getScriptProperties().getProperty("AOAI_API_MODEL");
const apiVersion = PropertiesService.getScriptProperties().getProperty("AOAI_API_VERSION");
const apiKey = PropertiesService.getScriptProperties().getProperty("AOAI_API_KEY");
const apiUrl = `${apiEndpoint}/openai/deployments/${modelName}/chat/completions?api-version=${apiVersion}`;
サンプルコード:AOAIへの単発リクエスト(fetch)
AOAIへの単発のチャットリクエストを送信するサンプルとなります。fetch:公式リファレンス情報はこちらです。
// AOAIへの単発リクエスト
function testRequestToAOAI() {
const apiEndpoint = PropertiesService.getScriptProperties().getProperty("AOAI_API_URL");
const modelName = PropertiesService.getScriptProperties().getProperty("AOAI_API_MODEL");
const apiVersion = PropertiesService.getScriptProperties().getProperty("AOAI_API_VERSION");
const apiKey = PropertiesService.getScriptProperties().getProperty("AOAI_API_KEY");
const apiUrl = `${apiEndpoint}/openai/deployments/${modelName}/chat/completions?api-version=${apiVersion}`;
const payload = {
messages: [
{
role: "system",
content: `あなたは先生でユーザーは小学生です。優しく教えてください。` //システムプロンプト
}, {
role: "user",
content: "先生!トイレ~" //ユーザープロンプト
}
]
}
const option = {
method: 'post',
headers: {
"Content-Type": "application/json",
"api-key": apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
}
const response = UrlFetchApp.fetch(apiUrl, option)
const responsJson = JSON.parse(response.getContentText());
try {
const res = responsJson.choices[0].message.content.trim();
Logger.log(res)
} catch (e) {
if(responsJson.error) Logger.log(responsJson.error.message) // リクエストでエラーレスポンスが返答されている可能性
Logger.log(e.message)
}
}
注目してほしい点としては、muteHttpExceptions
です。こちらは、リクエスト時にエラーが発生した場合は、responseにエラーオブジェクトを詰めて処理を継続させます。もしエラーの場合では、生成AIのレスポンス取得部分が落ちてしまうので、try~catchで捕捉しています。
catchで捕捉されるエラーは、jsonオブジェクトへアクセスできない等のエラーになるため、responseJsonを検証してエラーを取得しています。

Errorを継承したカスタムエラーを作成する方法もありますが、厳密なエラーハンドリングが求められないのであればこれぐらいの軽量でよいと思います。
サンプルコード:AOAIへの並列リクエスト(fetchAll)
fetchAllを活用して並列でAOAIへのリクエストを送信するサンプルとなります。fetchAll:公式リファレンスの情報はこちらです。
// AOAIへのリクエスト作成
function createRequestToAOAI(text) {
const apiEndpoint = PropertiesService.getScriptProperties().getProperty("AOAI_API_URL");
const modelName = PropertiesService.getScriptProperties().getProperty("AOAI_API_MODEL");
const apiVersion = PropertiesService.getScriptProperties().getProperty("AOAI_API_VERSION");
const apiKey = PropertiesService.getScriptProperties().getProperty("AOAI_API_KEY");
const apiUrl = `${apiEndpoint}/openai/deployments/${modelName}/chat/completions?api-version=${apiVersion}`;
const payload = {
messages: [
{
role: "system",
content: `あなたは先生でユーザーは小学生です。優しく教えてください。` //システムプロンプト
}, {
role: "user",
content: text
}
]
}
const request = {
url: apiUrl,
method: 'post',
headers: {
"Content-Type": "application/json",
"api-key": apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
}
return request
}
function testRequestsToAOAI(){
const children = ["先生トイレ!","`右`の漢字の書き順がわかりません", "1+1は?"]
const requests = children.map((value) => createRequestToAOAI(value))
const reponses = UrlFetchApp.fetchAll(requests)
reponses.forEach((response, index) => {
const responsJson = JSON.parse(response.getContentText());
try {
const res = responsJson.choices[0].message.content.trim();
Logger.log(`${children[index]}:${res}`)
} catch (e) {
Logger.log(responsJson)
Logger.log(e)
}
})
}
こちらは、事前にリクエストを作成する関数を使用してリクエスト配列を生成し、そちらの内容をfetchAll
で送信しています。単発のリクエストとは異なり、request
オブジェクト内にurl
が含まれているのが特徴です。
終わり
今回は、GASでAOAIのREST APIを実行するサンプルコードを紹介しました。並列実行を含めたリクエストの作成方法と、エラーハンドリングの実装について解説しています。参考にしていただければ幸いです。