feat: add new role 'bot'
This commit is contained in:
@@ -1,142 +0,0 @@
|
||||
import OpenAI from "openai";
|
||||
import fsp from "fs/promises";
|
||||
import { PdfReader } from "pdfreader";
|
||||
|
||||
const openaiClient = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
async function queryChatGPT(prompt: string) {
|
||||
let res = await openaiClient.chat.completions.create({
|
||||
model: "gpt-4o",
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: prompt,
|
||||
},
|
||||
],
|
||||
response_format: { type: "json_object" },
|
||||
});
|
||||
|
||||
return JSON.parse(res.choices[0].message.content);
|
||||
}
|
||||
|
||||
async function parseBufferAsync(buffer: Buffer): Promise<string> {
|
||||
let parsedData = "";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
new PdfReader().parseBuffer(buffer, (error, item) => {
|
||||
if (error) return reject(error);
|
||||
if (!item) return resolve(parsedData);
|
||||
if (item.text) parsedData += item.text;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default async function generateNote(
|
||||
folderPath: string
|
||||
): Promise<string> {
|
||||
let energyData = {};
|
||||
let checklistData = {};
|
||||
let energyDataFlag = false;
|
||||
let checklistDataFlag = false;
|
||||
let energyFilePath = "";
|
||||
let checklistFilePath = "";
|
||||
|
||||
const files = await fsp.readdir(folderPath);
|
||||
|
||||
for (const file of files) {
|
||||
const input = await fsp.readFile(folderPath + `/${file}`);
|
||||
const pdfData = await parseBufferAsync(input);
|
||||
|
||||
if (
|
||||
Object.keys(checklistData).length == 0 &&
|
||||
pdfData.toLowerCase().includes("general contractors")
|
||||
) {
|
||||
const prompt = `
|
||||
Extract the following fields and contractor info from the given data and return the response in JSON.
|
||||
Fields: ["Site Address", "Lot Number", "Estimated Construction Cost", "Total Square Footage", "A/C Square Footage", "Number of Bedrooms", "Number of Bathrooms", "Construction Type", "Number of Stories", "Height", "General Contractors License", "Mechanical Contractors License", "Electrical Contractors License", "Plumbing Contractors License", "Roofing Contractors License", "Concrete/Mason Contractors License", "Confirm the following"]
|
||||
|
||||
Data: ${pdfData}
|
||||
`;
|
||||
|
||||
checklistDataFlag = true;
|
||||
checklistFilePath = file;
|
||||
checklistData = await queryChatGPT(prompt);
|
||||
}
|
||||
|
||||
if (
|
||||
Object.keys(energyData).length == 0 &&
|
||||
pdfData.toLowerCase().includes("energy efficiency")
|
||||
) {
|
||||
const prompt = `
|
||||
Extract the following fields form the given data and return the response in JSON.
|
||||
Fields: [Project Name, address, county]
|
||||
|
||||
Data: ${pdfData}
|
||||
`;
|
||||
|
||||
energyDataFlag = true;
|
||||
energyFilePath = file;
|
||||
energyData = await queryChatGPT(prompt);
|
||||
}
|
||||
}
|
||||
|
||||
const addressCheck = {};
|
||||
|
||||
if (checklistDataFlag && Object.keys(checklistData).length > 0) {
|
||||
for (const file of files) {
|
||||
if (file == checklistFilePath) continue;
|
||||
|
||||
const input = await fsp.readFile(folderPath + `${file}`);
|
||||
const pdfData = await parseBufferAsync(input);
|
||||
|
||||
const prompt = `
|
||||
Check if the address in the data given below matches this ${checklistData["Site Address"]}. Return the response in JSON with schema {match: Boolean}.
|
||||
|
||||
Data: ${pdfData}
|
||||
`;
|
||||
|
||||
const { match } = await queryChatGPT(prompt);
|
||||
addressCheck[file] = match;
|
||||
}
|
||||
}
|
||||
|
||||
let note = "";
|
||||
|
||||
if (!energyDataFlag) {
|
||||
note += "Energy Efficiency document not found.\n";
|
||||
}
|
||||
|
||||
if (!checklistDataFlag) {
|
||||
note += `Checklist document not found.\n\n`;
|
||||
}
|
||||
|
||||
let filesList = "";
|
||||
for (const file in addressCheck) {
|
||||
if (!addressCheck[file]) {
|
||||
filesList += file.split("/").pop() + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (filesList != "") {
|
||||
note +=
|
||||
"Below files don't have address or the address doesn't match with the address in checklist\n\n";
|
||||
note += filesList;
|
||||
note += "\n";
|
||||
}
|
||||
|
||||
if (energyDataFlag || checklistDataFlag) {
|
||||
note += "\nExtracted Data:\n";
|
||||
}
|
||||
|
||||
if (Object.keys(energyData).length > 0) {
|
||||
note += `\n${JSON.stringify(energyData, null, 2)}\n`;
|
||||
}
|
||||
|
||||
if (Object.keys(checklistData).length > 0) {
|
||||
note += `\n${JSON.stringify(checklistData, null, 2)}\n`;
|
||||
}
|
||||
|
||||
return note;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||
import { validate } from "./validate";
|
||||
|
||||
export async function validateRoutes(fastify: FastifyInstance) {
|
||||
fastify.post(
|
||||
"/:rtsId",
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: "object",
|
||||
properties: { rtsId: { type: "string" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
const { rtsId } = req.params as { rtsId: string };
|
||||
|
||||
try {
|
||||
validate(rtsId, req.user.tenantId);
|
||||
return res.code(200).send();
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import fsp from "fs/promises";
|
||||
import axios from "axios";
|
||||
import { rtsModel } from "../rts/rts.schema";
|
||||
import { getChildren } from "../file/file.service";
|
||||
import { getFileUrlS3 } from "../utils/s3";
|
||||
import generateNote from "./ai";
|
||||
import { createNote, createNoteBot } from "../note/note.service";
|
||||
|
||||
async function downloadFile(url: string, downloadPath: string) {
|
||||
try {
|
||||
const res = await axios({
|
||||
url: url,
|
||||
method: "GET",
|
||||
responseType: "stream",
|
||||
});
|
||||
|
||||
await fsp.writeFile(downloadPath, res.data);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadFileTree(
|
||||
basePath: string,
|
||||
recId: string,
|
||||
tenantId: string
|
||||
) {
|
||||
const rts = await rtsModel.findOne({ pid: recId });
|
||||
|
||||
async function downloadFolder(folderId: string, path: string) {
|
||||
const items = await getChildren(folderId, tenantId);
|
||||
for (const item of items) {
|
||||
if (item.mimeType == "folder") {
|
||||
const newPath = path + `/${item.name}`;
|
||||
await fsp.mkdir(newPath);
|
||||
await downloadFolder(item.pid, newPath);
|
||||
} else {
|
||||
await downloadFile(
|
||||
await getFileUrlS3(item.pid, null, false),
|
||||
path + `/${item.name}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await downloadFolder(recId, basePath);
|
||||
}
|
||||
|
||||
async function deleteFolder(path: string) {
|
||||
await fsp.rm(path, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
export async function validate(recId: string, tenantId: string) {
|
||||
const basePath = process.env.BASE_PATH || "/root/tmp/quickerPermit";
|
||||
const folderPath = basePath + `/${recId}`;
|
||||
|
||||
try {
|
||||
await fsp.mkdir(folderPath);
|
||||
await downloadFileTree(folderPath, recId, tenantId);
|
||||
|
||||
const files = await fsp.readdir(folderPath);
|
||||
|
||||
const notes: { folder: string; note: string }[] = [];
|
||||
for (const file of files) {
|
||||
const filePath = folderPath + `/${file}`;
|
||||
const stats = await fsp.stat(filePath);
|
||||
if (stats.isDirectory()) {
|
||||
const note = await generateNote(filePath);
|
||||
notes.push({ folder: file, note });
|
||||
}
|
||||
}
|
||||
|
||||
let finalNote = "";
|
||||
for (const note of notes) {
|
||||
finalNote += `${note.folder}\n`;
|
||||
finalNote += `${note.note}\n\n`;
|
||||
}
|
||||
|
||||
await createNoteBot(finalNote, recId, tenantId);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
deleteFolder(folderPath);
|
||||
}
|
||||
}
|
||||
@@ -80,21 +80,6 @@ export async function createNote(
|
||||
return newNote.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
}
|
||||
|
||||
export async function createNoteBot(
|
||||
content: string,
|
||||
resourceId: string,
|
||||
tenantId: string
|
||||
) {
|
||||
const newNote = await noteModel.create({
|
||||
tenantId: tenantId,
|
||||
pid: generateId(),
|
||||
resourceId: resourceId,
|
||||
content: content,
|
||||
createdAt: new Date(),
|
||||
createdBy: "6762acd606db9d07307a302d",
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateNote(
|
||||
input: CreateNoteInput,
|
||||
resourceId: string,
|
||||
|
||||
@@ -163,6 +163,10 @@ export const rules: Record<
|
||||
users: ["__v"],
|
||||
},
|
||||
},
|
||||
bot: {
|
||||
claims: ["file:download", "note:write"],
|
||||
hiddenFields: {},
|
||||
},
|
||||
};
|
||||
|
||||
export const roles = Object.keys(rules) as [
|
||||
|
||||
Reference in New Issue
Block a user