龍騰 AI 非選批閱平台 開發者文件中心
提交與批閱

作答與題幹的內容格式

ProseMirror 內容文件、數學節點、長度限制,以及空白作答的處理

ProseMirror JSON 文件

本服務的部分內容欄位中,使用 ProseMirror JSON 格式(Tiptap 編輯器產生的序列化格式)以提供內容樣式與多模態內容的支援,例如一般文字、數學式、圖像、填空格,以及其他未來可能擴充支援的節點型別。

適用的內容欄位包含學生的作答(answer.doc)與題目的題幹(content.stem)。其文件格式範例如下:

{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        { "type": "text", "text": "求 " },
        { "type": "math_inline", "attrs": { "latex": "f(x) = 2x^2 - 8x + 3" } },
        { "type": "text", "text": " 的最小值。" }
      ]
    }
  ]
}

ProseMirror JSON 的完整 schema 定義,請參考 Tiptap 官方文件

允許的節點

文件除了驗證為合法 JSON 外,也將依照 ProseMirror 的節點(Node)定義進行檢查。

目前支援的節點清單有:

節點用途屬性
doc文件根節點
paragraph一段行內內容
text文字
math_inline行內公式latex(必填)
math_block獨立成行的公式latex(必填)
image以網址引用的圖片url(必填)、alt
blank填充題題幹中的空格blank_id(必填)
  1. blank 空格節點僅能於填空題 fill_in_blank 的題幹中使用。該節點用於宣告「答案應寫在此處」,而非學生答案。學生對於空格的作答格式,請參見「作答內容格式」段落。
  2. image 圖片節點只接受網址引用,無法內嵌圖檔。
  3. math_* 數學節點的 LaTeX 以 KaTeX 解析並驗證,請參考其官方文件所述支援的 LaTex 函式或巨集。

文件所屬的資源建立或更新時,將驗證涵蓋節點集合、各節點必要屬性,以及每個數學節點內的 LaTeX。以下情況則將回應 400 ERR_VALIDATION_FAILED 錯誤,並在錯誤訊息中指出錯誤的節點路徑:

  1. 存在不支援的節點類型
  2. 節點缺少必要屬性
  3. math_ 數學節點 LaTex 不合法
  4. image 節點的 URL 指向資源無法讀取:請參閱「圖片節點」段落。

圖片節點

含有圖片節點的文件在建立或更新時,會在本服務中對引用的圖片建立一份副本,並將 attrs.url 改寫指向該副本,以避免持續的依賴外部參照。圖片來源網址在文件建立當下,必須為可公開存取的狀態。

圖片節點使用位置副本建立時間副本無法建立時
題幹寫入當下,同步將回應 400 ERR_VALIDATION_FAILED 錯誤,錯誤訊息會指出是哪個節點遭遇錯誤;題目不會被建立
學生作答批閱流程中,非同步該筆作答以終態 failed 結束,不會產生批閱結果

學生作答無法建立圖片副本時,該筆作答將視為系統失敗。因此無法建立人工覆核。 在圖片恢復可讀之後,請於 Studio 重新排程該筆作答。

未來此一錯誤將有專屬的錯誤代碼。但在更新之前,response.grading_failed 會以 ERR_INTERNAL 回報。

LaTex 於文件內的解析

在 ProseMirror JSON 文件中,純文字節點(例如 text不會解析以 $…$ 慣例包裹的 LaTex 數學式。所有需要被解析的 LaTex 均應使用任一個數學節點表示。

然而,非 ProseMirror JSON 的純字串欄位(如 scoring.reference_answer 以及評分標準descriptionexamples)則應仍使用行內 $…$ 包裹 LaTex 公式。

長度限制

送出的文件長度與大小需滿足以下限制:

  1. 內容長度需小於 5,000。字元計算方式為所有 text 節點的文字加上所有數學節點的原始碼。
  2. 文件大小為序列化後需小於 256 KB。

違反任一者時,將回應 400 ERR_CONTENT_TOO_LONG 錯誤。

空白作答

當學生完全沒有作答內容時,請使用以下文件內容,以送出一份空白的 ProseMirror 文件:

{
  "type": "text",
  "doc": { "type": "doc", "content": [{ "type": "paragraph" }] }
}

請注意務必存在一個 content 節點,裡面存在一個沒有內容的 paragraph 物件。只有定義 content: [] 將導致驗證失敗。

若回答內容只有包含空白字元及換行符號,批閱系統將同樣視為空白。針對空白的回答,批閱結果將特別標記其 outcome: blank

題目作答文件

學生對題目的作答文件,在 ProseMirror JSON 文件之外,另外需要依照以下任一種格式的包裹。請依照該題目的題型 type 選擇:

適用於除了填充題以外的簡答、作文等題型。

{ "type": "text", "doc": { "…": "…" } }

就算整題未作答時,本題型依然適用。

範例函式:從純文字內容建立 JSON 文件

我們建議,通常可以讓使用者終端直接使用 ProseMirror 或 Tiptap 編輯器進行輸入。

如果使用者終端使用 Markdown 格式輸入,則可使用 Tiptap 的 Markdown 擴充元件,將 Markdown 文件轉換為 ProseMirror JSON 文件。

若內容使用原生 HTML Input 或 Textarea,則其輸入值可能為一段純文字。下列範例提供一組示範 TypeScript 與 Python 函式,可將純文字轉換為 ProseMirror JSON 文件。

就算該函式呼叫時傳入空字串(如 textDoc('')),函式也可以產生一份合法的空白文件

type Doc = { type: 'doc'; content: unknown[] };

/** 將純文字(可含換行)轉為內容文件。 */
export function textDoc(text: string): Doc {
  return {
    type: 'doc',
    content: text.split('\n').map((line) => ({
      type: 'paragraph',
      content: line ? [{ type: 'text', text: line }] : [],
    })),
  };
}

/** 一段文字加一條獨立成行的公式。 */
export function textWithMath(lead: string, latex: string): Doc {
  return {
    type: 'doc',
    content: [
      { type: 'paragraph', content: [{ type: 'text', text: lead }] },
      { type: 'math_block', attrs: { latex } },
    ],
  };
}

/** 在送出前檢查長度。 */
export function contentLength(doc: Doc): number {
  let n = 0;
  const walk = (node: any) => {
    if (node.type === 'text') n += node.text.length;
    if (node.attrs?.latex) n += node.attrs.latex.length;
    node.content?.forEach(walk);
  };
  walk(doc);
  return n;
}

相關

本頁內容