佈局自定義
在 Potato 中用 HTML 模板和 CSS 構建自定義標註佈局,涵蓋並排對比、多列 scheme 和項目級樣式。
v2.1.0 新增
Potato 提供兩種自定義標註介面佈局的方式:
- 自動生成佈局:Potato 生成一個 HTML 佈局檔案,你可以編輯它
- 自定義佈局檔案:建立你自己的 HTML 模板,完全掌控樣式
快速開始
使用自動生成的佈局
- 執行一次伺服器,Potato 會寫出
layouts/task_layout.html - 編輯生成的檔案來自定義樣式
- 你的修改在伺服器重啟後依然保留(除非你修改了配置中的
annotation_schemes)
編輯 annotation_schemes 會重新生成該檔案,因為表單標記必須與它收集的 scheme 相匹配。如果某個佈局你想保留,請在改動 scheme 之前把它另存為自己的檔名。
使用自定義佈局檔案
- 建立你的佈局檔案(例如
layouts/custom_task_layout.html) - 在配置中引用它:
task_layout: layouts/custom_task_layout.html該路徑相對於配置檔案所在目錄解析,因此與配置放在一起的佈局檔案會隨項目一同遷移。
項目級基礎 CSS
佈局檔案只負責標註頁面的樣式。若要為項目提供的每一個頁面設定樣式,包括知情同意頁和說明頁,請用 base_css 指向一個樣式表:
base_css: styles/custom.cssPotato 在伺服器啟動時讀取該檔案,並把它作為 <style id="potato-project-base-css"> 塊注入每個頁面的 <head> 中,位置在所有內建樣式之後,因此你的規則優先生效。修改後需要重啟伺服器;檔案缺失只會記錄一條警告,不會讓伺服器停止。
佈局檔案結構
自定義佈局檔案必須包含:
<style>
/* Your custom CSS */
</style>
<div class="annotation_schema">
<!-- Your annotation forms -->
<form id="schema_name" class="annotation-form radio" data-annotation-id="0">
<fieldset schema="schema_name">
<legend>Question text</legend>
<!-- Input elements -->
</fieldset>
</form>
</div>必需的表單屬性
Potato 通過以下四個屬性把標記與你的配置對應起來,其中任何一個不匹配,標註就到不了輸出檔案:
| 屬性 | 描述 |
|---|---|
id | 必須與配置中 annotation_schemes 的 name 一致 |
class | 包含 annotation-form 和類型(如 radio、multiselect) |
data-annotation-id | 順序索引(0, 1, 2...) |
schema | fieldset 和 input 上的屬性,與 scheme 名稱一致 |
必需的輸入屬性
<input class="schema_name annotation-input"
type="radio"
name="schema_name"
value="label_value"
schema="schema_name"
label_name="label_value"
onclick="onlyOne(this);registerAnnotation(this);">示例佈局
Potato 附帶三個完整的示例佈局。下面的命令要在克隆下來的 Potato 倉庫根目錄下執行,因為這些配置及其資料檔案都是該 checkout 的一部分。若要用你自己的配置執行自己的佈局,請改用 potato start <your-config>.yaml -p 8000。
1. 內容稽核儀表板
位置:examples/custom-layouts/content-moderation/
包含帶內容後設資料的警告橫幅頭部、違規類別的雙列網格、按顏色編碼的嚴重程度級別,以及一條稽核工作流。
python potato/flask_server.py start examples/custom-layouts/content-moderation/config.yaml -p 80002. 客服對話品質評估
位置:examples/custom-layouts/dialogue-qa/
包含帶後設資料徽章的案例頭部、分組的評估區塊、圓形 Likert 量表評分、品質問題清單,以及按顏色編碼的解決狀態指示。
python potato/flask_server.py start examples/custom-layouts/dialogue-qa/config.yaml -p 80003. 醫學影像審閱
位置:examples/custom-layouts/medical-review/
包含醫療風格的 UI 樣式、位置與嚴重程度的雙列布局、分組的檢查結果區塊、結構化報告,以及帶說明的建議卡片。
python potato/flask_server.py start examples/custom-layouts/medical-review/config.yaml -p 8000CSS 技巧
網格佈局
建立多列布局:
.annotation-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.full-width {
grid-column: 1 / -1;
}
@media (max-width: 768px) {
.annotation-grid {
grid-template-columns: 1fr;
}
}按顏色編碼的選項
用表示嚴重程度的顏色來設定單選按鈕的樣式:
.severity-option input[type="radio"] {
position: absolute;
opacity: 0;
}
.severity-label {
display: block;
padding: 10px;
border-radius: 6px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.2s;
}
/* Green for "None" */
.severity-none .severity-label {
background: #dcfce7;
color: #166534;
}
.severity-none input:checked + .severity-label {
background: #22c55e;
color: white;
}
/* Red for "Severe" */
.severity-severe .severity-label {
background: #fee2e2;
color: #991b1b;
}
.severity-severe input:checked + .severity-label {
background: #ef4444;
color: white;
}隱藏原生 input 而對它的 label 設定樣式,可以讓整個彩色區塊都能點選,當選項集是網格而不是豎排列表時這一點尤其重要。
區塊樣式
建立視覺分組:
.annotation-section {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.section-title {
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 2px solid #3b82f6;
}圓形 Likert 評分
圓點一眼就能讀作一個量表,而且比一摞單選行佔用更少的垂直空間,這能讓多問題表單保持在一屏之內:
.likert-circle {
width: 36px;
height: 36px;
border-radius: 50%;
border: 2px solid #e2e8f0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.likert-option input:checked + .likert-circle {
background: #8b5cf6;
color: white;
border-color: #7c3aed;
}與實例顯示結合
自定義佈局可以和 instance_display 配置一起使用。實例內容(影像、文本、對話)在標註表單上方單獨渲染,因此佈局檔案控制的是問題,instance_display 控制的是被標註的材料。
instance_display:
fields:
- key: image_url
type: image
display_options:
zoomable: true
task_layout: layouts/custom_task_layout.html
annotation_schemes:
- annotation_type: radio
name: category
description: "Which category does this image belong to?"
labels: [A, B, C]最佳實踐
- 讓 scheme 名稱對上:表單
id必須與annotation_schemes中的name完全一致 - 順序的標註 ID:
data-annotation-id使用 0, 1, 2... - 帶上必需的處理函式:單選用
onclick="onlyOne(this);registerAnnotation(this);",核取方塊用onclick="registerAnnotation(this);" - 測試響應式:用媒體查詢支援移動端
- 保持可訪問性:使用規範的 label,並保留鍵盤導航
故障排除
標註沒有儲存
檢查:
- 表單
id是否與標註 scheme 的name一致 - input 是否帶有
schema和label_name屬性 - 點選處理函式(
registerAnnotation)是否存在
樣式沒有生效
- 確認 CSS 優先順序足夠高,能覆蓋預設樣式
- 檢查
<style>塊是否位於佈局檔案內部 - 用瀏覽器開發者工具檢視實際生效的樣式
佈局沒有載入
- 確認
task_layout中的路徑是相對於配置檔案的 - 檢查 HTML 語法錯誤
- 檢視伺服器日誌中的錯誤資訊
延伸閱讀
有關實現細節,請參閱原始碼文件。