DocDoeAI / src /lib /uploads /document-upload-contract.ts
asnannp's picture
deploy: sync backend to Space root (learn-lesson HF cache fix)
65d68f5
Raw History Blame Contribute Delete
2.05 kB
export type StudentUploadKind = "material" | "paper" | "study-chat";
export type StudentUploadFile = {
name: string;
type?: string;
size?: number;
};
export const DOCUMENT_UPLOAD_MAX_BYTES = 20 * 1024 * 1024;
export const DOCUMENT_UPLOAD_MAX_MB = DOCUMENT_UPLOAD_MAX_BYTES / (1024 * 1024);
export const MATERIAL_UPLOAD_ACCEPT = ".pdf,.txt,application/pdf,text/plain";
export const PDF_UPLOAD_ACCEPT = ".pdf,application/pdf";
const MATERIAL_EXTENSIONS = new Set(["pdf", "txt"]);
const PDF_EXTENSIONS = new Set(["pdf"]);
function extensionOf(name: string) {
return name.split(".").pop()?.trim().toLowerCase() || "";
}
/**
* Browser-side mirror of the deployed document ingestion contract.
*
* Images and office files stay disabled until the backend can extract them in
* production. This prevents the UI from accepting a file that can only become
* a failed document after upload.
*/
export function validateStudentUpload(file: StudentUploadFile, kind: StudentUploadKind) {
const extension = extensionOf(file.name);
const allowed = kind === "material" ? MATERIAL_EXTENSIONS : PDF_EXTENSIONS;
const label = kind === "paper" ? "question paper" : kind === "study-chat" ? "StudyChat source" : "study source";
if (!extension || !allowed.has(extension)) {
return {
ok: false as const,
message:
kind === "material"
? "Upload a selectable-text PDF or TXT file. Images and Word files are not supported yet."
: kind === "study-chat"
? "Upload a selectable-text PDF."
: `Upload the ${label} as a selectable-text PDF. Images and scanned PDFs are not supported yet.`,
};
}
if (file.size === 0) {
return { ok: false as const, message: "That file is empty. Choose a file with readable text." };
}
if (typeof file.size === "number" && file.size > DOCUMENT_UPLOAD_MAX_BYTES) {
return {
ok: false as const,
message: `That ${label} is too large. The upload limit is ${DOCUMENT_UPLOAD_MAX_MB} MB.`,
};
}
return { ok: true as const };
}