mirror of
https://github.com/hanzoai/dataroom.git
synced 2026-10-30 18:41:07 +00:00
hanzo-build-linux-amd64 is the only ARC runner pool installed on hanzo-k8s today (arm64 pool is paused until DigitalOcean ships arm64 droplets, per ~/work/hanzo/.github/RUNNERS.md). The arm64 job was waiting on spark-hanzoai-arm64 — not provisioned in this cluster — so every build sat in queue forever and the amd64 leg got cancelled. Set platforms: linux/amd64 on the reusable build call to skip arm64 entirely. Re-add arm64 if/when DO ships arm64 droplets and the spark runner pool comes back online.
195 lines
5.7 KiB
TypeScript
195 lines
5.7 KiB
TypeScript
import { logger, metadata, task } from "@trigger.dev/sdk/v3";
|
|
|
|
import prisma from "@/lib/prisma";
|
|
|
|
import { addFileToVectorStoreTask } from "./add-file-to-vector-store";
|
|
import { processExcelForAITask } from "./process-excel-for-ai";
|
|
import { processImageForAITask } from "./process-image-for-ai";
|
|
import { processPdfForAITask } from "./process-pdf-for-ai";
|
|
import {
|
|
EXCEL_CONTENT_TYPES,
|
|
IMAGE_CONTENT_TYPES,
|
|
PDF_CONTENT_TYPES,
|
|
SUPPORTED_AI_CONTENT_TYPES,
|
|
type ProcessDocumentPayload,
|
|
} from "./types";
|
|
|
|
/**
|
|
* Main orchestrator task for processing documents for AI
|
|
* Routes to appropriate subtask based on content type, then adds to vector store
|
|
*/
|
|
export const processDocumentForAITask = task({
|
|
id: "process-document-for-ai",
|
|
retry: { maxAttempts: 3 },
|
|
queue: {
|
|
concurrencyLimit: 10,
|
|
},
|
|
run: async (
|
|
payload: ProcessDocumentPayload,
|
|
): Promise<{ vectorStoreFileId: string; fileId: string }> => {
|
|
const {
|
|
documentId,
|
|
documentVersionId,
|
|
teamId,
|
|
vectorStoreId,
|
|
documentName,
|
|
filePath,
|
|
storageType,
|
|
contentType,
|
|
metadata: fileMetadata,
|
|
} = payload;
|
|
|
|
logger.info("Starting document processing for AI", {
|
|
documentId,
|
|
documentVersionId,
|
|
teamId,
|
|
contentType,
|
|
});
|
|
|
|
// Initialize metadata for real-time tracking
|
|
metadata.set("status", "pending");
|
|
metadata.set("documentName", documentName);
|
|
metadata.set("documentId", documentId);
|
|
metadata.set("step", "Initializing...");
|
|
metadata.set("progress", 0);
|
|
|
|
// Validate content type
|
|
if (!SUPPORTED_AI_CONTENT_TYPES.includes(contentType)) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "Unsupported file type");
|
|
metadata.set("error", `Unsupported content type: ${contentType}`);
|
|
throw new Error(`Unsupported content type: ${contentType}`);
|
|
}
|
|
|
|
// Check if fileId already exists
|
|
const version = await prisma.documentVersion.findUnique({
|
|
where: { id: documentVersionId },
|
|
select: { fileId: true },
|
|
});
|
|
|
|
let fileId = version?.fileId;
|
|
|
|
// Process document if no fileId exists
|
|
if (!fileId) {
|
|
metadata.set("status", "processing");
|
|
metadata.set("step", "Processing document...");
|
|
metadata.set("progress", 10);
|
|
|
|
// Route to appropriate processing task based on content type
|
|
if (PDF_CONTENT_TYPES.includes(contentType)) {
|
|
const result = await processPdfForAITask.triggerAndWait({
|
|
documentId,
|
|
documentVersionId,
|
|
teamId,
|
|
documentName,
|
|
filePath,
|
|
storageType,
|
|
contentType,
|
|
});
|
|
|
|
if (!result.ok) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "PDF processing failed");
|
|
metadata.set("error", "Failed to process PDF");
|
|
throw new Error("Failed to process PDF");
|
|
}
|
|
|
|
fileId = result.output.fileId;
|
|
} else if (EXCEL_CONTENT_TYPES.includes(contentType)) {
|
|
const result = await processExcelForAITask.triggerAndWait({
|
|
documentId,
|
|
documentVersionId,
|
|
teamId,
|
|
documentName,
|
|
filePath,
|
|
storageType,
|
|
contentType,
|
|
});
|
|
|
|
if (!result.ok) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "Excel processing failed");
|
|
metadata.set("error", "Failed to process Excel file");
|
|
throw new Error("Failed to process Excel file");
|
|
}
|
|
|
|
fileId = result.output.fileId;
|
|
} else if (IMAGE_CONTENT_TYPES.includes(contentType)) {
|
|
const result = await processImageForAITask.triggerAndWait({
|
|
documentId,
|
|
documentVersionId,
|
|
teamId,
|
|
documentName,
|
|
filePath,
|
|
storageType,
|
|
contentType,
|
|
});
|
|
|
|
if (!result.ok) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "Image processing failed");
|
|
metadata.set("error", "Failed to process image");
|
|
throw new Error("Failed to process image");
|
|
}
|
|
|
|
fileId = result.output.fileId;
|
|
}
|
|
} else {
|
|
logger.info("Document already processed, reusing fileId", {
|
|
documentId,
|
|
fileId,
|
|
});
|
|
metadata.set("step", "Using existing processed file...");
|
|
metadata.set("progress", 50);
|
|
}
|
|
|
|
if (!fileId) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "Processing failed");
|
|
metadata.set("error", "No file ID returned from processing");
|
|
throw new Error("No file ID returned from processing");
|
|
}
|
|
|
|
metadata.set("fileId", fileId);
|
|
|
|
// Add file to vector store
|
|
metadata.set("status", "indexing");
|
|
metadata.set("step", "Adding to vector store...");
|
|
metadata.set("progress", 80);
|
|
|
|
const vsResult = await addFileToVectorStoreTask.triggerAndWait({
|
|
fileId,
|
|
vectorStoreId,
|
|
metadata: fileMetadata,
|
|
});
|
|
|
|
if (!vsResult.ok) {
|
|
metadata.set("status", "failed");
|
|
metadata.set("step", "Failed to add to vector store");
|
|
metadata.set("error", "Failed to add file to vector store");
|
|
throw new Error("Failed to add file to vector store");
|
|
}
|
|
|
|
const { vectorStoreFileId } = vsResult.output;
|
|
|
|
// Update document version with vectorStoreFileId
|
|
await prisma.documentVersion.update({
|
|
where: { id: documentVersionId },
|
|
data: { vectorStoreFileId },
|
|
});
|
|
|
|
metadata.set("status", "completed");
|
|
metadata.set("step", "Indexed successfully");
|
|
metadata.set("progress", 100);
|
|
metadata.set("vectorStoreFileId", vectorStoreFileId);
|
|
|
|
logger.info("Document processed and indexed successfully", {
|
|
documentId,
|
|
fileId,
|
|
vectorStoreFileId,
|
|
});
|
|
|
|
return { vectorStoreFileId, fileId };
|
|
},
|
|
});
|