Google Meetの文字起こし
Google Meet REST APIがGAになってたので試した。
認証が必要なのでGoogle Cloudの方でプロジェクトを作成し、↓の解説に沿ってcredentials.jsonを生成する。
ほんで適当なJSプロジェクトを立ち上げる。
code:sh
mkdir meet-sample
cd meet-sample
bun init
でクイックスタートに書いてあるサンプルコードをindex.tsに貼り付けてMeetのspaceを作成するサンプルコードを実行。
code:sh
bun run index.ts
これでまずは動く。
録画と文字起こしに関して。自分はよくわかってなかったけど、Google Meetには会議中に録画したり文字起こしをしたりする機能がすでに備わっているっぽい。なのでまずは適当な会議spaceを作成しその中で文字起こしを開始するというボタンを押して喋る。そうすると自分のDriveに文字起こしファイルが作成されるという感じ。
なんか自動で全ての会議が録音されているのかと思ったけどそういうわけではなかった。で、APIではそうして自前で作成した録音データに関するメタデータを取得したり、文字起こしならテキスト検索できたりするというわけ。
REST APIで取得したデータをOpenAIのAPIに投げて要約させたりプログラマブルに処理できるというのが便利ということかな。
APIの使い方に関してはYoutubeにある動画での解説が結構わかりやすかった。
https://www.youtube.com/watch?v=S1oGdUvgfSc
最後にサンプル実行で使ったジャンクコード↓
code:js
const fs = require("fs").promises;
const path = require("path");
const process = require("process");
const { authenticate } = require("@google-cloud/local-auth");
const { SpacesServiceClient, ConferenceRecordsServiceClient } =
require("@google-apps/meet").v2;
const { auth } = require("google-auth-library");
// If modifying these scopes, delete token.json.
const SCOPES = [
];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = path.join(process.cwd(), "token.json");
const CREDENTIALS_PATH = path.join(process.cwd(), "credentials.json");
/**
* Reads previously authorized credentials from the save file.
*
* @return {Promise<OAuth2Client|null>}
*/
async function loadSavedCredentialsIfExist() {
try {
const content = await fs.readFile(TOKEN_PATH);
const credentials = JSON.parse(content);
return auth.fromJSON(credentials);
} catch (err) {
console.log(err);
return null;
}
}
/**
* Serializes credentials to a file compatible with GoogleAuth.fromJSON.
*
* @param {OAuth2Client} client
* @return {Promise<void>}
*/
async function saveCredentials(client: any) {
const content = await fs.readFile(CREDENTIALS_PATH);
const keys = JSON.parse(content);
const key = keys.installed || keys.web;
const payload = JSON.stringify({
type: "authorized_user",
client_id: key.client_id,
client_secret: key.client_secret,
refresh_token: client.credentials.refresh_token,
});
await fs.writeFile(TOKEN_PATH, payload);
}
/**
* Load or request or authorization to call APIs.
*
*/
async function authorize() {
let client = await loadSavedCredentialsIfExist();
if (client) {
return client;
}
client = await authenticate({
scopes: SCOPES,
keyfilePath: CREDENTIALS_PATH,
});
if (client.credentials) {
await saveCredentials(client);
}
return client;
}
/**
* Creates a new meeting space.
* @param {OAuth2Client} authClient An authorized OAuth2 client.
*/
async function createSpace(authClient: any) {
const meetClient = new SpacesServiceClient({
authClient: authClient,
});
// Construct request
const request = {};
// Run request
const response = await meetClient.createSpace(request);
console.log(Meet URL: ${response[0].meetingUri});
}
async function getSpace(authClient: any) {
const meetClient = new SpacesServiceClient({
authClient: authClient,
});
const request = {
name: "spaces/aaa-aaa-aaa",
};
const response = await meetClient.getSpace(request);
console.log(response);
}
// Response例
// {
// name: "conferenceRecords/tekitou",
// startTime: {
// seconds: "1721376164",
// nanos: 892590000,
// },
// endTime: {
// seconds: "1721376176",
// nanos: 826065000,
// },
// expireTime: {
// seconds: "1723968176",
// nanos: 826065000,
// },
// space: "spaces/tekitou",
// }
async function listConferenceRecords(authClient: any) {
const meetClient = new ConferenceRecordsServiceClient({
authClient: authClient,
});
const request = {
// parent: "spaces/aaa-aaa-aaa",
};
const iterable = await meetClient.listConferenceRecordsAsync(request);
for await (const response of iterable) {
console.log(response);
}
}
async function getConferenceRecords(authClient: any) {
const meetClient = new ConferenceRecordsServiceClient({
authClient: authClient,
});
const request = {
name: "conferenceRecords/aaa-aaa-aaa-aaa",
};
const iterable = await meetClient.getConferenceRecord(request);
for await (const response of iterable) {
console.log(response);
}
}
async function listTranscriptsAsync(authClient: any) {
const meetClient = new ConferenceRecordsServiceClient({
authClient: authClient,
});
const request = {
parent: "conferenceRecords/aaaa-aaa-aaa-aaa",
};
const iterable = await meetClient.listTranscriptsAsync(request);
for await (const response of iterable) {
console.log(response);
}
}
authorize().then(listTranscriptsAsync).catch(console.error);