UNPKG

defect-inspection-tools-mcp-server

Version:

Defect inspection tools server handling defect detection, analysis, and reporting with AI/ML capabilities for quality control

322 lines 11.5 kB
import { MongoClient } from 'mongodb'; import axios from 'axios'; import { logger } from './logger.js'; import { config } from './config.js'; export function getArtifact(functionName, url) { /** * Handle get artifact tool using updated artifact format */ const artifact = { id: "msg_browser_ghi789", parentTaskId: "task_japan_itinerary_7d8f9g", timestamp: Math.floor(Date.now() / 1000), agent: { id: "agent_siya_browser", name: "SIYA", type: "qna" }, messageType: "action", action: { tool: "browser", operation: "browsing", params: { url: url, pageTitle: `Tool response for ${functionName}`, visual: { icon: "browser", color: "#2D8CFF" }, stream: { type: "vnc", streamId: "stream_browser_1", target: "browser" } } }, content: `Viewed page: ${functionName}`, artifacts: [ { id: "artifact_webpage_1746018877304_994", type: "browser_view", content: { url: url, title: functionName, screenshot: "", textContent: `Observed output of cmd \`${functionName}\` executed:`, extractedInfo: {} }, metadata: { domainName: "example.com", visitTimestamp: Date.now(), category: "web_page" } } ], status: "completed" }; return artifact; } export async function getVesselQnaSnapshot(imoNumber, questionNo) { /** * Fetch vessel QnA snapshot data asynchronously. * * Args: * imoNumber (string): The IMO number of the vessel * questionNo (string): The question number to fetch * * Returns: * Promise<any>: The response data from the snapshot API * * Throws: * Error: If the API request fails */ // API endpoint const snapshotUrl = `https://dev-api.siya.com/v1.0/vessel-info/qna-snapshot/${imoNumber}/${questionNo}`; // Authentication token const jwtToken = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjoiNjRkMzdhMDM1Mjk5YjFlMDQxOTFmOTJhIiwiZmlyc3ROYW1lIjoiU3lpYSIsImxhc3ROYW1lIjoiRGV2IiwiZW1haWwiOiJkZXZAc3lpYS5haSIsInJvbGUiOiJhZG1pbiIsInJvbGVJZCI6IjVmNGUyODFkZDE4MjM0MzY4NDE1ZjViZiIsImlhdCI6MTc0MDgwODg2OH0sImlhdCI6MTc0MDgwODg2OCwiZXhwIjoxNzcyMzQ0ODY4fQ.1grxEO0aO7wfkSNDzpLMHXFYuXjaA1bBguw2SJS9r2M"; // Headers for the request const headers = { "Authorization": jwtToken }; try { const response = await axios.get(snapshotUrl, { headers }); // Parse and return the JSON response const data = response.data; if ("resultData" in data) { return data.resultData; } return data; } catch (error) { logger.error(`Failed to fetch vessel QnA snapshot: ${error}`); return null; } } async function getComponentData(componentId) { // Parse the component_id into parts const match = componentId.match(/^(\d+)_(\d+)_(\d+)$/); if (!match) { return `⚠️ Invalid component_id format: ${componentId}`; } const [, componentNumber, questionNumber, imo] = match; const componentNo = `${componentNumber}_${questionNumber}_${imo}`; // Connect to MongoDB using config const mongoUri = config.secondaryMongoUri || config.mongoUri; const dbName = config.secondaryDbName || config.dbName; const client = new MongoClient(mongoUri); try { await client.connect(); const db = client.db(dbName); const collection = db.collection("vesselinfocomponents"); // Fetch document const doc = await collection.findOne({ "componentNo": componentNo }); if (!doc) { return `⚠️ No component found for ID: ${componentId}`; } if (!doc.data) { return "No data found in the table component"; } // Extract headers excluding lineitem const headers = doc.data.headers .filter((h) => h.name !== "lineitem") .map((h) => h.name); const rows = doc.data.body; // Build markdown table let md = "| " + headers.join(" | ") + " |\n"; md += "| " + headers.map(() => "---").join(" | ") + " |\n"; for (const row of rows) { const formattedRow = row .filter((cell) => !cell.lineitem) // Exclude lineitem .map((cell) => { if (cell.value && cell.link) { return `[${cell.value}](${cell.link})`; } else if (cell.status && cell.color) { return cell.status; } return String(cell); }); md += "| " + formattedRow.join(" | ") + " |\n"; } return md; } catch (error) { logger.error(`Error getting component data: ${error}`); return `Error getting component data: ${error}`; } finally { await client.close(); } } async function addComponentData(answer, imo) { const pattern = /httpsdev\.syia\.ai\/chat\/ag-grid-table\?component=(\d+_\d+)/g; const matches = Array.from(answer.matchAll(pattern)); let result = answer; for (const match of matches) { const component = match[1]; try { const replacement = await getComponentData(`${component}_${imo}`); result = result.replace(match[0], replacement); } catch (error) { logger.error(`Error replacing component data: ${error}`); } } return result; } export async function fetchQaDetails(imo, questionNo) { // Use secondary database configuration for fetchQaDetails const mongoUri = config.secondaryMongoUri || config.mongoUri; const dbName = config.secondaryDbName || config.dbName; const client = new MongoClient(mongoUri); try { await client.connect(); const db = client.db(dbName); const vesselinfos = db.collection('vesselinfos'); const imoNumber = parseInt(imo); const query = { 'imo': imoNumber, 'questionNo': parseInt(questionNo) }; const projection = { '_id': 0, 'imo': 1, 'vesselName': 1, 'refreshDate': 1, 'answer': 1 }; let res = await vesselinfos.findOne(query, { projection }); if (res === null) { res = { 'imo': imoNumber, 'vesselName': null, 'refreshDate': null, 'answer': null }; } if (res && res.refreshDate instanceof Date) { const datestr = res.refreshDate.toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }); res.refreshDate = datestr; } if (res && res.answer !== null) { res.answer = await addComponentData(res.answer, String(imoNumber)); } try { const link = await getVesselQnaSnapshot(String(imoNumber), String(questionNo)); if (res) { res.link = link; } } catch (error) { if (res) { res.link = null; } } return res; } catch (error) { logger.error(`Error fetching QA details: ${error}`); throw error; } finally { await client.close(); } } export async function getDataLink(data) { const url = "https://dev-api.siya.com/v1.0/vessel-info/qna-snapshot"; const headers = { "Content-Type": "application/json", "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjoiNjRkMzdhMDM1Mjk5YjFlMDQxOTFmOTJhIiwiZmlyc3ROYW1lIjoiU3lpYSIsImxhc3ROYW1lIjoiRGV2IiwiZW1haWwiOiJkZXZAc3lpYS5haSIsInJvbGUiOiJhZG1pbiIsInJvbGVJZCI6IjVmNGUyODFkZDE4MjM0MzY4NDE1ZjViZiIsImlhdCI6MTc0MDgwODg2OH0sImlhdCI6MTc0MDgwODg2OCwiZXhwIjoxNzcyMzQ0ODY4fQ.1grxEO0aO7wfkSNDzpLMHXFYuXjaA1bBguw2SJS9r2M" }; const payload = { "data": data }; try { const response = await axios.post(url, payload, { headers }); if (response.data.status === "OK") { return response.data.resultData; } else { return null; } } catch (error) { logger.error(`Error getting data link: ${error}`); return null; } } export async function insertDataLinkToMongodb(dataLink, linkHeader, sessionId, imo, vesselName) { /** * Insert data link into MongoDB collection */ // Insert the datalink to mongodb collection casefile_data const MONGO_URI_dev_syia_api = 'mongodb://dev-syia:m3BFsUxaPTHhE78@13.202.154.63:27017/?authMechanism=DEFAULT&authSource=dev-syia-api'; const DB_NAME_dev_syia_api = 'dev-syia-api'; // Create connection to dev-syia-api database const client = new MongoClient(MONGO_URI_dev_syia_api); try { await client.connect(); const db = client.db(DB_NAME_dev_syia_api); // Insert the datalink to mongodb collection casefile_data const collection = "casefile_data"; const casefileDataCollection = db.collection(collection); // Check if sessionId exists in casefile_data collection const sessionExists = await casefileDataCollection.findOne({ "sessionId": sessionId }); const linkData = { "link": dataLink, "linkHeader": linkHeader }; if (sessionExists) { // Append the data_link to the existing session await casefileDataCollection.updateOne({ "sessionId": sessionId }, { "$push": { "links": linkData }, "$set": { "datetime": new Date() } }); } else { const toInsert = { "sessionId": sessionId, "imo": imo, "vesselName": vesselName, "links": [linkData], "datetime": new Date() }; await casefileDataCollection.insertOne(toInsert); } } catch (error) { logger.error(`Error inserting data link to MongoDB: ${error}`); throw error; } finally { await client.close(); } } export function convertDefectDates(document) { /** * Convert Unix timestamps to human readable format for defect date fields. */ const dateFields = [ 'reportDate', 'closingDate', 'inspectionTargetDate', 'targetDate', 'extendedDate', 'nextDueDate' ]; for (const field of dateFields) { if (field in document) { try { if (typeof document[field] === 'number') { document[field] = new Date(document[field] * 1000).toISOString().replace('T', ' ').substr(0, 19); } } catch (error) { logger.warn(`Failed to convert ${field}: ${error}`); } } } return document; } //# sourceMappingURL=helpers.js.map