File size: 2,054 Bytes
65d68f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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 };
}