AI 评阅:DeepSeek Flash 给老师评分项出建议分和评语,老师采纳后生效
- 学生提交时浏览器给每个窗体截图(运行时同一套 FormWindow 在屏幕外渲染),随提交保存 - 自动评分后进入 AI 评阅队列:按书上评价表给老师评分项打建议分、写评语(JSON 输出,服务器再校验、限制分数); 发出的内容不含姓名学号;学生代码里像指令的文字一律当作品内容;学生又交了新的只评最新的 - 提示词按教材命名习惯校准("缩写_含义"、书上规定的控件名、界面上不用的标签保留默认名不扣分): 教材参考答案 28/30,默认控件名且没有注释 15/30 - 评阅页:界面截图标签页、AI 建议卡片(采纳、重新评阅)、全部采纳(不覆盖老师已评的分)、评阅后又提交的提醒; 成绩表显示"AI 建议,待确认";学生在老师确认前看不到 AI 的建议 - 规范提示移到 shared,服务端组装提示词时也用 - 配置 DEEPSEEK_API_KEY、AI_MODEL;部署说明提醒 NPM 调大请求体上限 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
302eae4f13
commit
14a82a3e24
25 files changed
+700
-44
No files matched your search
+18
-6
@@ -1,7 +1,8 @@
|
||||
// 老师评阅和成绩:给老师评分项打分、写评语;全班成绩表。
|
||||
// 一个学生的总分 = 最近一次提交的自动评分 + 老师评分(没提交时没有总分)。
|
||||
import type { Database } from 'bun:sqlite'
|
||||
import type { Review, Scoring, SourceFile } from '@iot/shared'
|
||||
import type { Review, Scoring, Screenshot, SourceFile } from '@iot/shared'
|
||||
import { getAiReview } from './ai-review'
|
||||
import { getAssignment, latestSubmission } from './assignments'
|
||||
|
||||
/**
|
||||
@@ -52,11 +53,19 @@ export function studentDetail(db: Database, assignmentId: number, userId: number
|
||||
const student = db.query<{ id: number; username: string; name: string }, [number]>('SELECT id, username, name FROM users WHERE id = ?').get(userId)
|
||||
if (!student) return null
|
||||
const latest = latestSubmission(db, assignmentId, userId)
|
||||
const files = latest
|
||||
? (JSON.parse(db.query<{ files: string }, [number]>('SELECT files FROM submissions WHERE id = ?').get(latest.id)!.files) as SourceFile[])
|
||||
: null
|
||||
const row = latest && db.query<{ files: string; screenshots: string | null }, [number]>('SELECT files, screenshots FROM submissions WHERE id = ?').get(latest.id)
|
||||
const files = row ? (JSON.parse(row.files) as SourceFile[]) : null
|
||||
const screenshots = row?.screenshots ? (JSON.parse(row.screenshots) as Screenshot[]) : []
|
||||
const count = db.query<{ n: number }, [number, number]>('SELECT COUNT(*) AS n FROM submissions WHERE assignment_id = ? AND user_id = ?').get(assignmentId, userId)!.n
|
||||
return { student, submission: latest, files, review: getReview(db, assignmentId, userId), submissionCount: count }
|
||||
return {
|
||||
student,
|
||||
submission: latest,
|
||||
files,
|
||||
screenshots,
|
||||
aiReview: latest ? getAiReview(db, latest.id) : null,
|
||||
review: getReview(db, assignmentId, userId),
|
||||
submissionCount: count,
|
||||
}
|
||||
}
|
||||
|
||||
/** 一份提交的代码和它属于谁(老师在实验页里运行学生的程序时用) */
|
||||
@@ -96,7 +105,10 @@ export function gradebook(db: Database, classId: number) {
|
||||
const review = getReview(db, a.id, s.id)
|
||||
const auto = latest?.status === 'done' ? latest.autoScore : null
|
||||
const manual = manualScore(review)
|
||||
return [a.id, { submitted: latest !== null, auto, manual, total: latest ? (auto ?? 0) + (manual ?? 0) : null }]
|
||||
// 老师还没评阅时,带上 AI 的建议分(成绩表里标"待确认")
|
||||
const ai = latest && !review ? getAiReview(db, latest.id) : null
|
||||
const aiManual = ai?.status === 'done' ? ai.scores.reduce((sum, s) => sum + s.score, 0) : null
|
||||
return [a.id, { submitted: latest !== null, auto, manual, aiManual, total: latest ? (auto ?? 0) + (manual ?? 0) : null }]
|
||||
}),
|
||||
),
|
||||
})),
|
||||
|
||||
Reference in new issue
Block a user