1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GASとZoom apiを使ってZoom AI Companionを取得してみた

Last updated at Posted at 2024-10-07

業務でzoom apiを使って要約を取得したのでポイントをまとめます。

実装したいこと

  • 本日分のZoom AI Companion(要約)を取得して要約文をSlackに投げる。

そのために以下のことを実装しました。

  • meeting uuidの取得
  • meeting summaryの取得
  • slackに投稿

ZoomOauth認証

基本的には以下のようにコードを書いてzoom app marketplaceでアプリを作成すれば認証できます。
GAS側のコード

  • 実行を担うdoGet関数
var Properties = PropertiesService.getScriptProperties();
var Client_Id = Properties.getProperty('CLIENT_ID');
var Client_Secret = Properties.getProperty('CLIENT_SECRET');
/**
 * Authorizes and makes a request to the Zoom API.
 */
function doGet() {
  var service = getZoomService_();
  Logger.log(service);
  if (!service.hasAccess()) {
    var authorizationUrl = service.getAuthorizationUrl();
    return HtmlService.createHtmlOutput("Click <a href='" + authorizationUrl + "' target='_blank'>here</a> to authorize.");
  } else {
    // User is authorized
    return HtmlService.createHtmlOutput("Authentication successful!");

  }
}
  • OAuth2認証のセットアップ
function getZoomService_() {
  return OAuth2.createService('zoomreport')
      .setAuthorizationBaseUrl('https://zoom.us/oauth/authorize')
      .setTokenUrl('https://zoom.us/oauth/token')
      .setClientId(Client_Id)
      .setClientSecret(Client_Secret)
      .setCallbackFunction('authCallback') 
      .setPropertyStore(PropertiesService.getScriptProperties())
      .setRedirectUri('https://script.google.com/macros/d/{GASのスクリプトID}/usercallback')
      .setScope('{必要なスコープを追加}') //複数ある場合は「,」でスペースを開けずに繋げる
      .setTokenHeaders({
        'Authorization': 'Basic ' +
          Utilities.base64Encode(Client_Id + ':' + Client_Secret),
      });
}
  • callback関数
function authCallback(request) {
  var service = getZoomService_();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success! Access Token: ' + service.getAccessToken());
  } else {
    return HtmlService.createHtmlOutput('Denied.');
  }
}
  • リセット関数:スコープなどを変更した際にリセットして再認証する

function reset() {
  getZoomService_().reset();
}

Zoom app 側の設定は、適切なscopeを追加すれば問題ないと思います。
以下の記事などを参考にしました。

認証の流れ

GASで認証コードを書く+サービスからoauthを追加する → デプロイ(WEBアプリ) → zoom appの設定をする → デプロイされたWEBアプリのURLを踏むと認証できます。

meeting UUIDの取得

UUIDとは、会議ごとに与えらえる一意のIDのこと。
例えば毎日行われるAという会議のUUIDを取得する場合、meetingIDは毎日同じですが、UUIDは異なります
UUIDの例: aDYlohsHRtCd4ii1uC2+hA==

今回meetingIDとは別にUUIDを取得するのは、zoon apiで要約を取得する際にUUIDが必要となるからです。

Get a meeting summary

UUIDを直接取得することも考えましたが、取得したいミーティングがscheduledされていないものだったのでダメでした。(https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetings)

そのため、meetingID → UUID へと変換する必要があります。
(meetingIDの習得は省略します)

そのためのメソッドは、Get Past Meeting Details です。
meetingIDまたはUUIDをパラメータとしています。

meetingId: The meeting's ID or universally unique ID (UUID)
If you provide a meeting ID, the API will return a response for the latest meeting instance.
If you provide a meeting UUID that begins with a / character or contains the // characters, you must double encode the meeting UUID before making an API request.

コードは、以下のようになります。

function getMeetingUUID(meetingId) {
  try {
    const meetingDetails = sendZoomApiRequest(`/past_meetings/${meetingId}`);
    return meetingDetails.uuid;
  } catch (error) {
    console.error('Error fetching meeting UUID:', error);
    throw error;
  }
}

ここで、apiの取得について理解が浅かったのでまとめてみました。

APIリクエストについて

この記事を参考にまとめます。
UrlFetchApp.fetch(URL[, パラメータ]) という構文を用います。
fetch: urlに対してパラメータparamsを渡してHTTPリクエストを行う。
私のコードでは、

const url = `${ZOOM_API_BASE_URL}${endpoint}`;
const options = {
    method: method,
    headers: {
      'Authorization': 'Bearer ' + accessToken,
      'Content-Type': 'application/json'
    },
    
  };
const response = UrlFetchApp.fetch(url, options);

としています。
optionsでは、method(GET)とheaders(リクエストのHTTPヘッダー)を指定してます。

その後、文字型にするために以下の変換を行います。

JSON.parse(response.getContentText());

これにより、文字列になります。

以下は、zoom apiにリクエストする機能を汎化した関数です。

const ZOOM_API_BASE_URL = 'https://api.zoom.us/v2';
function sendZoomApiRequest(endpoint, method = 'GET') {
  const accessToken = getZoomAccessToken();
  const url = `${ZOOM_API_BASE_URL}${endpoint}`;
  const options = {
    method: method,
    headers: {
      'Authorization': 'Bearer ' + accessToken,
      'Content-Type': 'application/json'
    },
    
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    if (response.getResponseCode() === 200) {
      console.log(JSON.parse(response.getContentText()));
      return JSON.parse(response.getContentText());
    } else {
      throw new Error(`API request failed with status ${response.getResponseCode()}: ${response.getContentText()}`);
    }
  } catch (error) {
    console.error(`Error in Zoom API request to ${endpoint}:`, error);
    throw error;
  }
}

ここまでで、UUIDが取得できました。

残りは、UUIDからサマリーを取得してみます。

meeting summaryの取得

ドキュメントを参考に実装します。
apiリクエストをすると以下のような形式でデータが返ってきます。

{
  "meeting_host_id": "30R7kT7bTIKSNUFEuH_Qlg",
  "meeting_host_email": "jchill@example.com",
  "meeting_uuid": "aDYlohsHRtCd4ii1uC2+hA==",
  "meeting_id": 97763643886,
  "meeting_topic": "My Meeting",
  "meeting_start_time": "2019-07-15T23:24:52Z",
  "meeting_end_time": "2020-07-15T23:30:19Z",
  "summary_start_time": "2019-07-15T23:24:52Z",
  "summary_end_time": "2020-07-15T23:30:19Z",
  "summary_created_time": "2019-07-15T23:24:52Z",
  "summary_last_modified_time": "2020-07-15T23:30:19Z",
  "summary_title": "Meeting summary for my meeting",
  "summary_overview": "Meeting overview",
  "summary_details": [
    {
      "label": "Meeting overview",
      "summary": "Meeting overview"
    }
  ],
  "next_steps": [
    "step1"
  ],
  "edited_summary": {
    "summary_details": "Meeting overview",
    "next_steps": [
      "step1"
    ]
  }
}

今回必要な情報は、summary_overview(概要)・summary_details(詳細)・next_steps(今後の方針など)です。
以下がコードです。基本的には、UUIDを取得したのと同じ要領で取得すれば行けます。
AI Companion機能がオンになっていることが必要です

function getSummaryFromZoom(uuid) {
  let summaries = {};

  try {
    const encodedUUID = encodeUUID(uuid);
    const summary = sendZoomApiRequest(`/meetings/${encodedUUID}/meeting_summary`);
    // 全体のレスポンスを確認するため、ログ出力
    //console.log('Summary response:', summary);
    
    summaries = {
      'overview': summary.summary_overview,
      'details': summary.summary_details,
      'nextstep': summary.next_steps
    };
    console.log(summaries.details);
    return summaries;
  } catch (error) {
    console.error('Error fetching meeting summary:', error);
    throw error;
  }
}

また、/で始まる場合と//が含まれる場合二重エンコードする必要があるので以下の関数を作成しました。

// UUIDを必要に応じて二重エンコードする関数
function encodeUUID(uuid) {
  if (uuid.startsWith('/') || uuid.includes('//')) {
    return encodeURIComponent(encodeURIComponent(uuid));
  }
  return encodeURIComponent(uuid);
}

ここまでで、主要な関数を作成し終わりました。
slackに投稿する機能は、以下の記事が参考になりました。

肝となるのは、APIリクエストの部分でした。APIリクエストについての理解が浅いので今後勉強していきたいです。

1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?