简介:这份PDF是田纳西大学数字人文研究生证书课程的作品集评估量表(Rubric1),面向数字人文方向的研究生、课程指导教师及作品集评审人员,用于明确作品集在提交与答辩环节的评分依据。文件为单份PDF,压缩包约109KB,仅1个文件,开篇给出评审说明、候选人信息栏与四档评分制(1分不可接受/不完整至4分优秀),主体逐条列出公共网站是否清晰呈现项目与学生贡献、作品集是否覆盖每门DH课程、是否体现对多种技术工具与协作方式的理解、是否有效反思研究方法的学习过程、图像与引文是否规范署名、个人与协作分工是否标明,以及修改建议栏等条目。借助这份量表,读者可以对照评估要点逐项自检作品集,把握课程覆盖度、技术广度与学术规范之间的平衡,并据此规划公共网站展示与年终作品集论坛的汇报准备。目前已有82人学习。
1. 把评估量规当成接口契约来读
真正让人栽跟头的,往往不是不会做项目,而是四月一号截止前两周才打开那份《Digital Humanities Portfolio Rubric1》,发现评审问的七个问题自己只答上了三个。田纳西大学这份量规表面上是一张打分表,实质上是一份接口契约:它规定了输入(公开网站 + 私有 dossier 两份材料)、输出(每条课程对应一个项目条目)、以及字段级约束(图片署名、角色声明、反思文字、技术路径数量)。契约读不懂,做多少年数字人文都白搭。把量规当文档读,你会觉得它在讲"展示你的成长";把量规当 schema 读,你会看到 8 个必填字段、2 个交付面、1 条 2 分及格线。这份 PDF 适合两类人:准备提交作品集的 DH 证书候选人,以及任何需要给"项目成果"做结构化归档的技术人——它示范了一套不依赖具体工具的成果建模办法。
2. 把 Rubric 七问翻译成可校验的字段
量规本身的文风是评审语,读起来像建议,实际每条都对应一个可以填、可以查、可以判真假的数据点。第一步不是搭网站,是先把这些问句拆成字段,否则后面所有排版工作都是在给一个空壳刷漆。
2.1 先分清两个交付面的数据边界
量规把作品集拆成 A、B 两份。A 是 public website,公开可搜,面向未来雇主,要求每个项目配图、简述、贡献说明、项目链接或 GitHub 链接、以及相关博客文章链接。B 是 submitted portfolio,私有文档,交给证书项目主任,包含课程清单、每门课的项目要求、项目本体、以及可选的反思性写作。
这两个面共用同一批项目数据,但可见字段不同。公开面能放的:项目描述、你的角色、技术栈、截图、不涉密链接。私有面才能放的:课程作业原文要求、导师评语、未发表的手稿、涉及他人版权的合作材料。工程上最简单的处理是"一份数据源、两个渲染目标",而不是手工维护两份内容——手工维护必然在最后一周出现版本漂移,公开网站上挂着一个两个月前就被删掉的项目链接。
2.2 七条评审问题拆成字段
把量规里的问句逐条对到字段上,这是整件事的核心动作。做法是:每个问题写出"评审怎么判它不合格",那个判据就是字段。
| Rubric 问句 | 对应字段 | 校验方式 |
|---|---|---|
| 网站是否清晰呈现项目与你的贡献? | titlesummaryrole | 非空,summary≥ 120 字 |
| 是否每门 DH 课程都有一个项目? | courses[] | 与课程清单做集合差 |
| 是否体现技术经验、且不止一种技术路径? | stack[] | 去重后长度 ≥ 2 |
| 是否有效呈现学习与研究方法的过程? | reflection | 指向一篇反思文章或侧栏注释 |
| 图片、引文是否给出清晰署名? | image_creditcitation[] | 非空,含来源与许可 |
| 是否说明个人/协作、作业/独立项目? | rolecontext | 枚举值,不可为自由文本 |
| 技术选型、研究问题、IP 处理是否有硬伤? | licenserepoquestion | 许可非空,question是可回答的研究问题 |
表格里有两处容易糊弄过去、但评审一眼能看出来的地方。一是role,绝不能写"参与了这个项目",要写枚举:solo、lead、collaborator、consultant,枚举值才能在模板里生成统一的措辞。二是context,量规明确区分 coursework、RA-ship、independent、thesis/dissertation 四种情境,这也是枚举。
2.3 用 JSON Schema 把约束固化下来
字段定完,用一份 schema 写死类型和必填项,好处是构建时能直接报错,不用等评审告诉你漏了东西。
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "DHProjectEntry", "type": "object", "required": ["title", "summary", "role", "context", "courses", "stack", "image", "image_credit"], "properties": { "title": { "type": "string", "minLength": 4 }, "summary": { "type": "string", "minLength": 120 }, "role": { "enum": ["solo", "lead", "collaborator", "consultant"] }, "context": { "enum": ["coursework", "raship", "independent", "thesis"] }, "courses": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "stack": { "type": "array", "minItems": 2, "items": { "type": "string" } }, "repo": { "type": "string", "format": "uri" }, "demo": { "type": "string", "format": "uri" }, "license": { "type": "string" }, "image_credit": { "type": "string" }, "question": { "type": "string" }, "withheld_reason": { "type": "string" } } }minLength: 120那条不是形式主义。量规第四条问的是"是否有效呈现了学习与使用 DH 研究方法的过程",二十个字的"我学会了用 Python 处理文本"满足不了它,而 120 字逼着你写清数据来源、方法选择和踩到的坑。stack的minItems: 2对应的是量规里那句"show acquaintance with more than one technical approach (preferably)"——技术路径的广度是加分项,但别为了凑数把 Excel 写成一种技术路径,评审看的是方法差异,比如"语料标注 + 关系数据库查询"就比"Python + Jupyter"更像两条路径。
2.4 字段与前端渲染的对应关系
字段不是给评审看的,是给模板看的。每个字段最终要落到页面上一个确定的位置:role和context拼成一句固定的角色声明,image_credit渲染成图片下方的角标,reflection在项目卡片下面生成一个"关于这个项目我学到了什么"的折叠入口。这个映射一旦定下来,后面加项目就是填数据,不是改版式。
3. 静态站点落地:目录结构、构建与自动部署
公开面是量规里文字最多、要求最碎的一块,也是最容易被低估工程量的一块。评审第一条问的是"网站是否清晰呈现项目与你的贡献",这里面既包含内容,也包含可访问性和导航。
3.1 为什么优先选静态站点生成器
常见做法是用 Hugo、Eleventy 或 Jekyll 这类静态站点生成器,而不是直接手写 HTML,也不是上 WordPress。理由有三条:一是项目条目天然是重复结构,模板化之后新增一个项目只需要加一个 Markdown 文件;二是量规要求"每个项目一张图、一段描述、若干外链",这些正好是 front matter 的标准形态;三是产物是一堆静态文件,可以直接扔到 GitHub Pages 或任何对象存储上,十年后不依赖数据库还在线。
WordPress 在"雇主打开链接"这个场景下反而危险:插件过期、缓存没刷、证书到期,任何一个都会让你在评审面前丢分。静态站点的失效模式只有一种——链接写错了,而这个可以在提交前用脚本查。
3.2 目录结构与单个项目条目
目录按"内容类型"分,不按课程分。课程只是条目的一个属性,按课程建目录会让你在项目同时属于两门课时陷入纠结。
portfolio/ ├── content/ │ ├── projects/ # 每个项目一个 md,公开面主体 │ │ ├── newspaper-corpus.md │ │ └── mapping-lynching.md │ └── posts/ # 反思文章,被 projects 里的 reflection 字段引用 ├── static/images/ # 截图,文件名与项目 slug 保持一致 ├── layouts/ # 模板 └── config.toml单个项目条目的 front matter 大致长这样,注意字段名与前面 schema 一一对应:
+++ title = "19 世纪南方报刊语料分析" date = 2024-11-08 summary = "抓取 Chronicling America 公开 OCR 文本共 42 万页,用 spaCy 做实体识别后对比三家报社的人物提及偏差,重点在于处理 OCR 噪声与版本对齐。" role = "solo" # 枚举:solo / lead / collaborator / consultant context = "coursework" # 枚举:coursework / raship / independent / thesis courses = ["ENGL 593", "DH 510"] stack = ["Python", "spaCy", "PostgreSQL", "Git"] question = "同一事件的报道中,不同报社对人物的命名策略是否存在系统性差异?" repo = "https://github.com/xxx/newspaper-corpus" demo = "https://xxx.github.io/newspaper-corpus" image = "/images/newspaper-corpus.png" image_credit = "原始扫描件为公有领域,来源 Library of Congress;截图由本人制作" license = "CC-BY-4.0" reflection = "/posts/newspaper-corpus-reflection/" +++reflection字段对应量规第四条:它要求作品集呈现"学习并使用 DH 研究方法"的过程,量规甚至给了三种呈现位置——一段简短的叙事引言、侧栏注释、或者分散在不同部分的随笔。工程上选第三种最好维护:项目卡片只管事实,反思写在独立的posts/里,用reflection指过去。
3.3 列表页模板:把字段渲染成人能读的句子
评审不会看你的 front matter,只会看渲染结果。角色和情境这两个枚举值必须在模板里转成完整陈述句,否则页面上会出现一行孤零零的lead。
<!-- layouts/partials/project-card.html --> <article class="project"> <img src="{{ .Params.image }}" alt="{{ .Title }} 项目界面截图"> <p class="credit">图片来源:{{ .Params.image_credit }}</p> <h3><a href="{{ .Permalink }}">{{ .Title }}</a></h3> <p class="role"> {{/* 枚举转自然语言,避免页面上出现裸字段值 */}} {{ if eq .Params.role "solo" }}独立完成{{ else if eq .Params.role "lead" }}担任负责人,团队协作{{ else }}作为协作者参与{{ end }}, {{ if eq .Params.context "coursework" }}属于 {{ delimit .Params.courses "、" }} 课程作业{{ else }}为独立研究项目{{ end }}。 </p> <p class="stack">技术路径:{{ delimit .Params.stack "、" }}</p> <p class="summary">{{ .Params.summary }}</p> {{ with .Params.reflection }}<a href="{{ . }}">关于这个项目的反思</a>{{ end }} </article>delimit负责把数组拼成顿号分隔的中文串,比在模板里手写循环干净。with块处理可选字段:量规允许某些项目"仅用文字描述",比如你只是参与协作、没有发布权的那类,这种条目可以没有repo,但必须有withheld_reason说明为什么不给链接。
3.4 构建与部署
本地预览和构建就只有两条命令,别在这上面搞复杂工艺:
hugo server --buildDrafts # 本地预览,包含草稿 hugo --minify # 生成 public/ 静态产物,压缩 HTML/CSS部署交给 CI,每次 push 自动出站,避免"本地是好的、线上是旧的"这种低级事故。
# .github/workflows/deploy.yml name: deploy on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: recursive # 主题是 submodule 时必须开 - uses: actions/configure-pages@v5 - run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" - uses: actions/upload-pages-artifact@v3 with: path: ./publicsubmodules: recursive是最常被漏掉的一行,主题作为 submodule 引入时不开这个选项,构建会直接失败并且报错信息指向主题目录为空。baseURL用 CI 输出而不是写死在配置里,是为了在自定义域名和默认域名之间切换时不用改代码。
3.5 可访问性与署名的工程处理
量规里"图片、引文是否给出清晰署名"这条,靠自觉是守不住的,靠模板才守得住。图片统一放static/images/,文件名与项目 slug 一致,模板里image_credit是必渲染项,缺字段就构建报错。alt 文本不要写"项目截图"四个字,写清图里是什么,比如"实体识别结果表格,三列分别为报社、人物、出现次数"。
外链检查放在提交前跑一遍:
# 抽出所有外链,逐个探测状态码,只关心非 2xx grep -rhoE 'https?://[^")> ]+' public/ | sort -u | while read -r url; do code=$(curl -s -o /dev/null -w '%{http_code}' -m 10 "$url") [ "${code:0:1}" != "2" ] && echo "$code $url" done-m 10是超时上限,防止某条链接卡住整个批处理;只打印非 2xx 结果,是因为一个作品集站点的外链通常在 20 到 60 条之间,全量打印反而看不出问题。GitHub 仓库链接和 Pages 演示链接是重灾区,私有仓库改公开、改名、或者 Pages 分支被删,都会让链接变成 404。
4. 公开网站与私有 dossier 的双轨管理
量规明确要求提交两份材料,公开面给雇主看,私有文档给评审委员会看,两份内容有交集但不能混。这一章解决的是工程边界问题:怎么让一份素材同时喂给两个面,又不至于哪天手抖把导师评语推到公网。
4.1 两个仓库还是一个仓库两个目录
三种方案各有代价,选择取决于你是否需要公开版本历史。
| 方案 | 优点 | 风险 | 适用 |
|---|---|---|---|
单仓库,public/与private/分目录 | 改动一次同步 | 误提交私有内容,历史里删不掉 | 个人短期项目 |
| 两个独立仓库 | 物理隔离,权限清晰 | 项目描述要维护两遍 | 大多数情况 |
| 主仓库 + 私有子模块 | 复用条目数据 | 子模块权限配错会 404 | 熟悉 Git 的人 |
常见做法是两个独立仓库:公开站点的内容源放portfolio-site,私有 dossier 用 Markdown 写好后导出 PDF 提交,源文件留在本地或私有仓库。理由很直接——Git 历史一旦推到公开仓库,即使后来git rm,内容仍然留在提交记录里,评审如果翻到会非常尴尬。私有材料不进公开仓库,比任何清理手段都可靠。
4.2 用忽略规则和钩子防住误提交
防线要建在提交之前。.gitignore先挡住明显的:
# .gitignore private/ # 私有 dossier 源文件 *.pdf # 导出的评审材料 drafts/ transcripts/ # 导师邮件、评语、未公开的访谈记录 .env但.gitignore挡不住"你把一份评语直接粘贴进某个项目的 front matter"。这一层用 pre-commit 钩子做字段白名单:
#!/usr/bin/env bash # .git/hooks/pre-commit —— 拦截私有字段进入公开仓库 blocked="advisor_comment|grade|confidential|导师评语" if git diff --cached | grep -E "^\+" | grep -qE "$blocked"; then echo "检测到疑似私有内容,提交已中止" exit 1 figit diff --cached只看暂存区,也就是"这次准备提交什么",比扫全量文件快得多;grep -E "^\+"只匹配新增行,避免因为旧文件里有这个词就永远提交不上去。这个钩子只能防住关键词,真正的兜底还是:私有材料根本不放在这个工作目录里。
4.3 引用元数据与许可声明
量规第六条要求说明知识产权处理,第七条把"handling of intellectual property"直接列为可能的修订意见。工程化的做法是每个项目条目带license,仓库根目录放CITATION.cff,让引用格式自动生成。
# CITATION.cff cff-version: 1.2.0 title: "数字人文作品集:公开项目集" authors: - family-names: "Zhang" given-names: "San" version: "1.0.0" date-released: "2025-03-20" license: CC-BY-4.0license的选择有讲究:文字与图像用 CC-BY-4.0 表示允许转载但要署名,代码用 MIT 表示允许复用,二者不冲突,可以分开放。注意量规特别提到的情形——如果某个项目是协作项目、版权不属于你,正确做法不是给它挂一个许可,而是"仅在公开网站上用文字描述",不给仓库链接和可下载产物。
4.4 角色与协作声明的写法
量规两个地方都在问同一件事:这个项目里哪部分是你做的。公开网站和私有 dossier 都要答,但答法不同。公开面用一句话给读者,私有面用一段话给评审。
公开面(模板自动生成):"作为协作者参与,项目属于 DH 510 课程作业,本人负责数据清洗与地名对齐模块。"
私有面(dossier 手写):"该项目由 4 人小组完成,本人承担 OCR 后处理与地名规范化,占工程量的约三分之一;成果发布权归小组共有,故公开面不提供仓库链接。"
差别在于私有面必须给出量与边界——"约三分之一""不提供链接的原因"。评审打分时对"clear credit"的判断,靠的就是这类具体表述,而不是"我们团队一起完成了这个项目"。
5. 提交前自检:把 Rubric 写成 lint 脚本
量规里最实用的一条是那个四级评分和 2 分及格线,配合"2 月提交初版、4 月 1 日提交终版"的时间节点。既然标准是明文写好的,就没必要靠人眼通读自己的网站找漏项。
5.1 解析 front matter 做完整性检查
脚本只做一件事:遍历项目条目,把 rubric 的硬性要求翻译成真假判断。
# check_portfolio.py 用法: python check_portfolio.py content/projects import sys, pathlib, frontmatter # pip install python-frontmatter REQUIRED = ["title", "summary", "role", "context", "courses", "stack", "image", "image_credit", "question", "license"] ROLE_ENUM = {"solo", "lead", "collaborator", "consultant"} def check(path): post = frontmatter.load(path) meta, problems = post.metadata, [] for key in REQUIRED: if not meta.get(key): problems.append(f"缺少字段 {key}") if meta.get("role") not in ROLE_ENUM: problems.append(f"role 取值非法: {meta.get('role')}") if len(meta.get("stack", [])) < 2: problems.append("技术路径少于 2 条,rubric 第 3 条会失分") if not (meta.get("repo") or meta.get("demo")) and not meta.get("withheld_reason"): problems.append("既无链接也未说明不公开原因") if len(post.content.strip()) < 120: problems.append("正文过短,撑不起 rubric 第 4 条") return problems def main(root): root, total, bad = pathlib.Path(root), 0, 0 for md in sorted(root.glob("*.md")): total += 1 problems = check(md) print(f"[{'PASS' if not problems else 'FAIL'}] {md.name}") for p in problems: print(f" - {p}") bad += bool(problems) print(f"\n{total - bad}/{total} 通过") return 1 if bad else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else "content/projects"))REQUIRED列表对应的是"字段非空即可判定"的那些项,ROLE_ENUM和stack长度检查对应枚举与数量约束,withheld_reason这条是量规允许的特例通道——不是所有项目都要给链接,但必须解释为什么。脚本返回非零退出码,就可以直接挂到 CI 里,构建失败即提交失败。
5.2 把检查结果映射回分数
自检输出应该能直接对照量规打分,否则你只是在跑一个语法检查器。
| 脚本判定 | 对应 Rubric 问句 | 预判分数 |
|---|---|---|
courses集合覆盖全部 DH 课程 | 是否每门课都有项目 | 2 分底线 |
所有条目stack≥ 2 且彼此不同 | 是否展示不止一种技术路径 | 3 分 |
每条目都有reflection且可访问 | 是否呈现学习过程 | 3 分以上 |
image_credit与license全覆盖 | 署名与知识产权 | 无修订意见的关键项 |
| 存在 FAIL 条目 | 不完整 | 1 分,需重交 |
量规写得很清楚:总体 2 分及以上通过,拿到 1 分要在终版截止日前重交并修改。所以自检脚本的真正价值不是"拿高分",而是把"是否需要重交"这件事提前一个月变成可计算的结论,而不是等评审邮件。
5.3 失分点排序与修订顺序
时间不够的时候,修订顺序要按影响面排,不是按工作量排。第一优先是courses覆盖度,缺一门课的项目直接触发"complete in all respects"这一条,属于结构性失分,其他细节做得再好也补不回来。第二优先是角色声明与协作边界,量规有两处独立问它,也是评审最容易产生疑问的地方——看到一个没有归属说明的合作项目,评审会直接写进修订意见。第三优先是署名与许可,这一项不影响通过与否,但会被写进"带具体意见反馈给候选人"的注释里。最后才是视觉与版式。
改完之后重跑一遍脚本,再跑一次外链探测,把两份材料的截止日期倒排进日历:私有 dossier 导出 PDF 前先确认里面没有指向公开仓库的临时链接,公开网站部署后确认构建产物里的项目数与content/projects/下的 Markdown 文件数一致。
本文还有配套的精品资源,点击获取