|
|
const { reqBody, multiUserMode, userFromSession } = require("../utils/http"); |
|
|
const { handleFileUpload } = require("../utils/files/multer"); |
|
|
const { validatedRequest } = require("../utils/middleware/validatedRequest"); |
|
|
const { Telemetry } = require("../models/telemetry"); |
|
|
const { |
|
|
flexUserRoleValid, |
|
|
ROLES, |
|
|
} = require("../utils/middleware/multiUserProtected"); |
|
|
const { EventLogs } = require("../models/eventLogs"); |
|
|
const { validWorkspaceSlug } = require("../utils/middleware/validWorkspace"); |
|
|
const { CollectorApi } = require("../utils/collectorApi"); |
|
|
const { WorkspaceThread } = require("../models/workspaceThread"); |
|
|
const { WorkspaceParsedFiles } = require("../models/workspaceParsedFiles"); |
|
|
|
|
|
function workspaceParsedFilesEndpoints(app) { |
|
|
if (!app) return; |
|
|
|
|
|
app.get( |
|
|
"/workspace/:slug/parsed-files", |
|
|
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], |
|
|
async (request, response) => { |
|
|
try { |
|
|
const threadSlug = request.query.threadSlug || null; |
|
|
const user = await userFromSession(request, response); |
|
|
const workspace = response.locals.workspace; |
|
|
const thread = threadSlug |
|
|
? await WorkspaceThread.get({ slug: String(threadSlug) }) |
|
|
: null; |
|
|
const { files, contextWindow, currentContextTokenCount } = |
|
|
await WorkspaceParsedFiles.getContextMetadataAndLimits( |
|
|
workspace, |
|
|
thread || null, |
|
|
multiUserMode(response) ? user : null |
|
|
); |
|
|
|
|
|
return response |
|
|
.status(200) |
|
|
.json({ files, contextWindow, currentContextTokenCount }); |
|
|
} catch (e) { |
|
|
console.error(e.message, e); |
|
|
return response.sendStatus(500).end(); |
|
|
} |
|
|
} |
|
|
); |
|
|
|
|
|
app.delete( |
|
|
"/workspace/:slug/delete-parsed-files", |
|
|
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], |
|
|
async function (request, response) { |
|
|
try { |
|
|
const { fileIds = [] } = reqBody(request); |
|
|
if (!fileIds.length) return response.sendStatus(400).end(); |
|
|
const success = await WorkspaceParsedFiles.delete({ |
|
|
id: { in: fileIds.map((id) => parseInt(id)) }, |
|
|
}); |
|
|
return response.status(success ? 200 : 500).end(); |
|
|
} catch (e) { |
|
|
console.error(e.message, e); |
|
|
return response.sendStatus(500).end(); |
|
|
} |
|
|
} |
|
|
); |
|
|
|
|
|
app.post( |
|
|
"/workspace/:slug/embed-parsed-file/:fileId", |
|
|
[ |
|
|
validatedRequest, |
|
|
|
|
|
flexUserRoleValid([ROLES.admin, ROLES.manager]), |
|
|
validWorkspaceSlug, |
|
|
], |
|
|
async function (request, response) { |
|
|
const { fileId = null } = request.params; |
|
|
try { |
|
|
const user = await userFromSession(request, response); |
|
|
const workspace = response.locals.workspace; |
|
|
|
|
|
if (!fileId) return response.sendStatus(400).end(); |
|
|
const { success, error, document } = |
|
|
await WorkspaceParsedFiles.moveToDocumentsAndEmbed(fileId, workspace); |
|
|
|
|
|
if (!success) { |
|
|
return response.status(500).json({ |
|
|
success: false, |
|
|
error: error || "Failed to embed file", |
|
|
}); |
|
|
} |
|
|
|
|
|
await Telemetry.sendTelemetry("document_embedded"); |
|
|
await EventLogs.logEvent( |
|
|
"document_embedded", |
|
|
{ |
|
|
documentName: document?.name || "unknown", |
|
|
workspaceId: workspace.id, |
|
|
}, |
|
|
user?.id |
|
|
); |
|
|
|
|
|
return response.status(200).json({ |
|
|
success: true, |
|
|
error: null, |
|
|
document, |
|
|
}); |
|
|
} catch (e) { |
|
|
console.error(e.message, e); |
|
|
return response.sendStatus(500).end(); |
|
|
} finally { |
|
|
if (!fileId) return; |
|
|
await WorkspaceParsedFiles.delete({ id: parseInt(fileId) }); |
|
|
} |
|
|
} |
|
|
); |
|
|
|
|
|
app.post( |
|
|
"/workspace/:slug/parse", |
|
|
[ |
|
|
validatedRequest, |
|
|
flexUserRoleValid([ROLES.all]), |
|
|
handleFileUpload, |
|
|
validWorkspaceSlug, |
|
|
], |
|
|
async function (request, response) { |
|
|
try { |
|
|
const user = await userFromSession(request, response); |
|
|
const workspace = response.locals.workspace; |
|
|
const Collector = new CollectorApi(); |
|
|
const { originalname } = request.file; |
|
|
const processingOnline = await Collector.online(); |
|
|
|
|
|
if (!processingOnline) { |
|
|
return response.status(500).json({ |
|
|
success: false, |
|
|
error: `Document processing API is not online. Document ${originalname} will not be parsed.`, |
|
|
}); |
|
|
} |
|
|
|
|
|
const { success, reason, documents } = |
|
|
await Collector.parseDocument(originalname); |
|
|
if (!success || !documents?.[0]) { |
|
|
return response.status(500).json({ |
|
|
success: false, |
|
|
error: reason || "No document returned from collector", |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const { threadSlug = null } = reqBody(request); |
|
|
const thread = threadSlug |
|
|
? await WorkspaceThread.get({ |
|
|
slug: String(threadSlug), |
|
|
workspace_id: workspace.id, |
|
|
user_id: user?.id || null, |
|
|
}) |
|
|
: null; |
|
|
const files = await Promise.all( |
|
|
documents.map(async (doc) => { |
|
|
const metadata = { ...doc }; |
|
|
|
|
|
delete metadata.pageContent; |
|
|
const filename = `${originalname}-${doc.id}.json`; |
|
|
const { file, error: dbError } = await WorkspaceParsedFiles.create({ |
|
|
filename, |
|
|
workspaceId: workspace.id, |
|
|
userId: user?.id || null, |
|
|
threadId: thread?.id || null, |
|
|
metadata: JSON.stringify(metadata), |
|
|
tokenCountEstimate: doc.token_count_estimate || 0, |
|
|
}); |
|
|
|
|
|
if (dbError) throw new Error(dbError); |
|
|
return file; |
|
|
}) |
|
|
); |
|
|
|
|
|
Collector.log(`Document ${originalname} parsed successfully.`); |
|
|
await EventLogs.logEvent( |
|
|
"document_uploaded_to_chat", |
|
|
{ |
|
|
documentName: originalname, |
|
|
workspace: workspace.slug, |
|
|
thread: thread?.name || null, |
|
|
}, |
|
|
user?.id |
|
|
); |
|
|
|
|
|
return response.status(200).json({ |
|
|
success: true, |
|
|
error: null, |
|
|
files, |
|
|
}); |
|
|
} catch (e) { |
|
|
console.error(e.message, e); |
|
|
return response.sendStatus(500).end(); |
|
|
} |
|
|
} |
|
|
); |
|
|
} |
|
|
|
|
|
module.exports = { workspaceParsedFilesEndpoints }; |
|
|
|