brain/scripts/lib/graph-meetings.js

93 lines
3.1 KiB
JavaScript

const { ConfidentialClientApplication } = require('@azure/msal-node');
const { Client } = require('@microsoft/microsoft-graph-client');
const { readFileSync } = require('node:fs');
const { resolve } = require('node:path');
function loadEnv() {
const envPath = resolve(__dirname, '..', '.env');
const content = readFileSync(envPath, 'utf-8');
const vars = {};
for (const line of content.split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const [key, ...rest] = trimmed.split('=');
vars[key.trim()] = rest.join('=').trim();
}
return vars;
}
async function buildGraphClient(env = loadEnv()) {
const cca = new ConfidentialClientApplication({
auth: {
clientId: env.AZURE_CLIENT_ID,
clientSecret: env.AZURE_CLIENT_SECRET,
authority: `https://login.microsoftonline.com/${env.AZURE_TENANT_ID}`
}
});
const tokenResponse = await cca.acquireTokenByClientCredential({
scopes: ['https://graph.microsoft.com/.default']
});
return Client.init({
authProvider: (done) => done(null, tokenResponse.accessToken),
defaultVersion: 'v1.0'
});
}
async function safeGet(client, path, options = {}) {
try {
let req = client.api(path);
if (options.version && typeof req.version === 'function') req = req.version(options.version);
if (options.query && typeof req.query === 'function') req = req.query(options.query);
return await req.get();
} catch (err) {
if (err.statusCode === 404 || err.statusCode === 403) return null;
throw err;
}
}
async function resolveOnlineMeeting(client, userId, joinWebUrl) {
const path = `/users/${userId}/onlineMeetings`;
const resp = await safeGet(client, path, {
query: { $filter: `JoinWebUrl eq '${joinWebUrl}'` }
});
const list = resp?.value || [];
return list[0] || null;
}
async function fetchTranscriptVtt(client, userId, meetingId) {
const list = await safeGet(client, `/users/${userId}/onlineMeetings/${meetingId}/transcripts`);
const items = list?.value || [];
if (items.length === 0) return null;
const latest = [...items].sort((a, b) =>
new Date(b.createdDateTime) - new Date(a.createdDateTime)
)[0];
const contentPath = `/users/${userId}/onlineMeetings/${meetingId}/transcripts/${latest.id}/content`;
return await safeGet(client, contentPath);
}
async function fetchAiInsights(client, userId, meetingId) {
const path = `/users/${userId}/onlineMeetings/${meetingId}/aiInsights`;
const resp = await safeGet(client, path, { version: 'beta' });
const items = resp?.value || [];
return items[0] || null;
}
async function fetchRecordingUrl(client, userId, meetingId) {
const list = await safeGet(client, `/users/${userId}/onlineMeetings/${meetingId}/recordings`);
const items = list?.value || [];
if (items.length === 0) return null;
const latest = [...items].sort((a, b) =>
new Date(b.createdDateTime) - new Date(a.createdDateTime)
)[0];
return latest.recordingContentUrl || latest.contentCorrelationId || null;
}
module.exports = {
loadEnv,
buildGraphClient,
resolveOnlineMeeting,
fetchTranscriptVtt,
fetchAiInsights,
fetchRecordingUrl
};