sales_tool/functions/generate_minutes/src/logics/process.ts
2025-12-05 16:01:59 +09:00

131 lines
No EOL
6.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import z from "zod";
import { aiController } from "./ai";
import { dateController } from "./date";
import { googleDriveController, LogRowData, LogRowDataSchema } from "./googleDrive";
import { fileController } from "./file";
import path, { join } from "path";
import fs from "fs";
import { createCustomError } from "./error";
import { storageController } from "./storage";
import { CLOUD_STORAGE_MASTER_FOLDER_NAME, DATE_FORMAT, DATETIME_FORMAT, DOCUMENT_MIMETYPE, OWNERS_FILE_NAME, YM_FORMAT } from "../../serverConfig";
import { hubspotController, OwnerSchema } from "./hubspot";
import { fuzzyMatchController } from "./fuzzyMatch";
const VideoInfoSchema = z.looseObject({
id: z.string(),
title: z.string(),
starts_at: z.string(),
ends_at: z.string(),
access_permission: z.string(),
host: z.object({
login_id: z.string(),
user_name: z.string(),
}),
speech_recognition: z.object({
raw: z.string(),
})
});
type VideoInfo = z.infer<typeof VideoInfoSchema>;
export const MiiTelWebhookSchema = z.object({
video: VideoInfoSchema,
});
const GOOGLE_DRIVE_FOLDER_ID = process.env.GOOGLE_DRIVE_FOLDER_ID || '';
const MIITEL_REQUEST_LOG_FOLDER_ID = process.env.MIITEL_REQUEST_LOG_FOLDER_ID || '';
const MINUTES_CREATION_HISTORY_FOLDER_ID = process.env.MINUTES_CREATION_HISTORY_FOLDER_ID || '';
const MIITEL_URL = process.env.MIITEL_URL || '';
const HUBSPOT_COMPANY_URL = process.env.HUBSPOT_COMPANY_URL || '';
const FILE_PATH = join(__dirname, "../files/");
let outputPath = '';
export const processRequest = async (videoInfo: VideoInfo) => {
try {
const videoId = videoInfo.id;
const title = videoInfo.title;
const startsAt = videoInfo.starts_at;
const endsAt = videoInfo.ends_at;
const accessPermission = videoInfo.access_permission;
const hostId = videoInfo.host.login_id;
const hostName = videoInfo.host.user_name;
const speechRecognition = videoInfo.speech_recognition.raw;
if (accessPermission !== "EVERYONE" || !title.includes("様") || title.includes("社内")) return;
// ===== Init =====
const googleAuth = await googleDriveController.getAuth();
const driveClient = googleDriveController.getDriveClient(googleAuth);
const docsClient = googleDriveController.getDocsClient(googleAuth);
const sheetsClient = googleDriveController.getSheetsClient(googleAuth);
const jstStartsAt = dateController.convertToJst(startsAt);
const jstEndsAt = dateController.convertToJst(endsAt);
const fileName = fileController.createMinutesFileName(title, hostName, jstStartsAt);
const videoUrl = `${MIITEL_URL}app/video/${videoId}`;
// ===== Save Request Log to Google Drive =====
if (!fs.existsSync(FILE_PATH)) fs.mkdirSync(FILE_PATH, { recursive: true });
outputPath = path.join(FILE_PATH, fileName + '.zip');
const createZip = await fileController.createZip(videoInfo, outputPath, fileName);
if(!createZip) throw createCustomError("CREATE_ZIP_FILE_FAILED");
const logFileId = await googleDriveController.uploadFile(driveClient, outputPath, MIITEL_REQUEST_LOG_FOLDER_ID, `${fileName}.zip`, "application/zip");
if(!logFileId) throw createCustomError("UPLOAD_LOG_FAILED");
// ===== Generate Minutes =====
const minutes = await aiController.generateMinutes(speechRecognition);
if (!minutes) throw createCustomError("AI_GENERATION_FAILED");
let content = `会議履歴URL${videoUrl}\n`;
content += `担当者:${hostName}\n\n`;
content += minutes;
// ===== Upload To Google Drive =====
const documentId = await googleDriveController.createNewFile(driveClient, GOOGLE_DRIVE_FOLDER_ID, fileName, DOCUMENT_MIMETYPE);
if (!documentId) throw createCustomError("CREATE_NEW_DOCUMENT_FAILED");
const result = await googleDriveController.addContentToDocs(docsClient, documentId, content);
if(!result) throw createCustomError("UPLOAD_MINUTES_FAILED");
// ===== Create Meeting Log at Hubspot =====
const ownersJson = await storageController.loadJsonFromGCS(CLOUD_STORAGE_MASTER_FOLDER_NAME, OWNERS_FILE_NAME);
if(!ownersJson) throw createCustomError("GET_OWNERS_FAILED");
const parsedOwners = z.array(OwnerSchema).safeParse(JSON.parse(ownersJson));
if(!parsedOwners.success) throw createCustomError("ZOD_FAILED");
const ownerId = hubspotController.searchOwnerIdByEmail(hostId, parsedOwners.data);
const extractedCompanyName = fileController.extractCompanyNameFromTitle(title);
const matchedCompany = await fuzzyMatchController.searchMatchedCompany(extractedCompanyName);
if(matchedCompany) await hubspotController.createMeetingLog(matchedCompany.id, title, ownerId, minutes, startsAt, endsAt);
// ===== Apeend Log To SpreadSheet =====
const currentYearMonth = dateController.getCurrentJstTime(YM_FORMAT);
const sheetId = await googleDriveController.getLogSheetId(driveClient, sheetsClient, MINUTES_CREATION_HISTORY_FOLDER_ID, currentYearMonth);
if(!sheetId) throw createCustomError("GET_SHEET_ID_FAILED");
const currentJstDateTimeStr = dateController.getCurrentJstTime(DATETIME_FORMAT);
const currentJstDateStr = dateController.getCurrentJstTime(DATE_FORMAT);
const rowData: LogRowData = LogRowDataSchema.parse({
timestamp: currentJstDateTimeStr,
meetingDate: currentJstDateStr,
title: title,
matchedCompanyName: matchedCompany?.name ?? '',
ownerName: hostName,
meetingUrl: videoUrl,
documentUrl: `https://docs.google.com/document/d/${documentId}/edit`,
hubspotUrl: matchedCompany ? `${HUBSPOT_COMPANY_URL}/${matchedCompany.id}` : '',
});
const insertResult = await googleDriveController.insertRowToSheet(sheetsClient, sheetId, Object.values(rowData));
if(!insertResult) throw createCustomError("INSERT_ROW_FAILED");
fs.unlinkSync(outputPath);
} catch (error) {
fs.unlinkSync(outputPath);
throw error;
}
};