feat(aihr): add voice answers to daily drills

This commit is contained in:
2026-07-14 05:44:26 +08:00
parent 841df00740
commit 9bbfd575a3
10 changed files with 156 additions and 32 deletions
@@ -261,7 +261,9 @@ public final class AihrPracticeDto {
String referenceAnswer,
String userAnswer,
String feedback,
Boolean correct
Boolean correct,
String audioUrl,
Long audioOssId
) {
}
@@ -276,10 +278,19 @@ public final class AihrPracticeDto {
) {
}
public record DailyDrillAnswerRequest(String answer) {
public record DailyDrillAnswerRequest(String answer, String audioUrl, Long audioOssId) {
}
public record DailyDrillAnswerResponse(Long id, String status, Boolean correct, Integer score, String feedback, String referenceAnswer) {
public record DailyDrillAnswerResponse(
Long id,
String status,
Boolean correct,
Integer score,
String feedback,
String referenceAnswer,
String audioUrl,
Long audioOssId
) {
}
public record PromptTemplateRequest(
@@ -913,7 +913,7 @@ public class AihrPracticeSeedService {
args.add(limit);
String sql = """
SELECT id, ext_party_id, trainee_name, scenario_id, scenario_name, source, reason, status, create_time,
answer_text, feedback, correct
answer_text, answer_audio_url, answer_audio_oss_id, feedback, correct
FROM aihr_practice_assignment
%s
ORDER BY create_time DESC, id DESC
@@ -1587,7 +1587,7 @@ public class AihrPracticeSeedService {
ensureDailyDrills(party);
return jdbcTemplate.query("""
SELECT id, ext_party_id, trainee_name, scenario_id, scenario_name, source, reason, status, create_time,
answer_text, feedback, correct
answer_text, answer_audio_url, answer_audio_oss_id, feedback, correct
FROM aihr_practice_assignment
WHERE tenant_id = ?
AND (? = '' OR ext_party_id = ?)
@@ -1625,7 +1625,7 @@ public class AihrPracticeSeedService {
args.add(normalizeLimit(limit));
return jdbcTemplate.query("""
SELECT id, ext_party_id, trainee_name, scenario_id, scenario_name, source, reason, status, create_time,
answer_text, feedback, correct
answer_text, answer_audio_url, answer_audio_oss_id, feedback, correct
FROM aihr_practice_assignment
WHERE tenant_id = ?
AND ext_party_id IN (%s)
@@ -1694,13 +1694,13 @@ public class AihrPracticeSeedService {
""", TENANT_ID, extPartyId, traineeName, scenario.id(), firstNonBlank(request == null ? null : request.scenarioName(), scenario.name()), source, reason, createdAt, createdAt);
List<PracticeAssignmentResponse> rows = jdbcTemplate.query("""
SELECT id, ext_party_id, trainee_name, scenario_id, scenario_name, source, reason, status, create_time,
answer_text, feedback, correct
answer_text, answer_audio_url, answer_audio_oss_id, feedback, correct
FROM aihr_practice_assignment
WHERE tenant_id = ? AND ext_party_id = ? AND scenario_id = ? AND source = ? AND reason = ?
ORDER BY id DESC
LIMIT 1
""", this::mapAssignment, TENANT_ID, extPartyId, scenario.id(), source, reason);
return rows.isEmpty() ? new PracticeAssignmentResponse(null, extPartyId, traineeName, scenario.id(), scenario.name(), source, reason, "待训练", now.format(TIME_FORMATTER), null, null, null, null, null) : rows.get(0);
return rows.isEmpty() ? new PracticeAssignmentResponse(null, extPartyId, traineeName, scenario.id(), scenario.name(), source, reason, "待训练", now.format(TIME_FORMATTER), null, null, null, null, null, null, null) : rows.get(0);
}
public PracticeAssignmentResponse createAssignment(PracticeAssignmentRequest request, String supervisorExtPartyId) {
@@ -1758,12 +1758,16 @@ public class AihrPracticeSeedService {
}
DailyDrillParts parts = dailyDrillParts((String) rows.get(0).get("reason"), (String) rows.get(0).get("scenario_id"));
String answer = maskSensitiveText(firstNonBlank(request == null ? null : request.answer(), ""));
String audioUrl = firstNonBlank(request == null ? null : request.audioUrl(), "");
Long audioOssId = request == null ? null : request.audioOssId();
DailyDrillScore score = scoreDailyDrill(answer, parts.referenceAnswer());
LocalDateTime now = LocalDateTime.now();
jdbcTemplate.update("""
UPDATE aihr_practice_assignment
SET status = '已完成',
answer_text = ?,
answer_audio_url = ?,
answer_audio_oss_id = ?,
feedback = ?,
correct = ?,
finished_time = ?,
@@ -1771,6 +1775,8 @@ public class AihrPracticeSeedService {
WHERE tenant_id = ? AND id = ? AND source = 'daily'
""",
answer,
audioUrl,
audioOssId,
score.feedback(),
score.correct() ? 1 : 0,
Timestamp.valueOf(now),
@@ -1778,7 +1784,7 @@ public class AihrPracticeSeedService {
TENANT_ID,
id
);
return new DailyDrillAnswerResponse(id, "已完成", score.correct(), score.score(), score.feedback(), parts.referenceAnswer());
return new DailyDrillAnswerResponse(id, "已完成", score.correct(), score.score(), score.feedback(), parts.referenceAnswer(), audioUrl, audioOssId);
}
public List<PromptTemplateResponse> promptTemplates(String category, String code, Boolean enabled) {
@@ -2248,7 +2254,9 @@ public class AihrPracticeSeedService {
"daily".equals(source) && "已完成".equals(status) ? daily.referenceAnswer() : null,
rs.getString("answer_text"),
"daily".equals(source) ? stripReferenceAnswer(rs.getString("feedback")) : rs.getString("feedback"),
correctValue == null ? null : rs.getBoolean("correct")
correctValue == null ? null : rs.getBoolean("correct"),
rs.getString("answer_audio_url"),
rs.getObject("answer_audio_oss_id") == null ? null : rs.getLong("answer_audio_oss_id")
);
}
@@ -3057,6 +3065,8 @@ public class AihrPracticeSeedService {
`reason` varchar(500) DEFAULT NULL COMMENT '派发原因',
`status` varchar(30) NOT NULL DEFAULT '待训练' COMMENT '状态',
`answer_text` varchar(1000) DEFAULT NULL COMMENT '每日三题作答',
`answer_audio_url` varchar(500) DEFAULT NULL COMMENT '每日三题语音回放地址',
`answer_audio_oss_id` bigint DEFAULT NULL COMMENT '每日三题语音OSS编号',
`feedback` varchar(1000) DEFAULT NULL COMMENT '每日三题反馈',
`correct` tinyint DEFAULT NULL COMMENT '是否答对',
`finished_time` datetime DEFAULT NULL COMMENT '完成时间',
@@ -3068,7 +3078,9 @@ public class AihrPracticeSeedService {
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI HR 对练派发任务';
""");
ensureColumn("aihr_practice_assignment", "answer_text", "ALTER TABLE aihr_practice_assignment ADD COLUMN `answer_text` varchar(1000) DEFAULT NULL COMMENT '每日三题作答' AFTER `status`");
ensureColumn("aihr_practice_assignment", "feedback", "ALTER TABLE aihr_practice_assignment ADD COLUMN `feedback` varchar(1000) DEFAULT NULL COMMENT '每日三题反馈' AFTER `answer_text`");
ensureColumn("aihr_practice_assignment", "answer_audio_url", "ALTER TABLE aihr_practice_assignment ADD COLUMN `answer_audio_url` varchar(500) DEFAULT NULL COMMENT '每日三题语音回放地址' AFTER `answer_text`");
ensureColumn("aihr_practice_assignment", "answer_audio_oss_id", "ALTER TABLE aihr_practice_assignment ADD COLUMN `answer_audio_oss_id` bigint DEFAULT NULL COMMENT '每日三题语音OSS编号' AFTER `answer_audio_url`");
ensureColumn("aihr_practice_assignment", "feedback", "ALTER TABLE aihr_practice_assignment ADD COLUMN `feedback` varchar(1000) DEFAULT NULL COMMENT '每日三题反馈' AFTER `answer_audio_oss_id`");
ensureColumn("aihr_practice_assignment", "correct", "ALTER TABLE aihr_practice_assignment ADD COLUMN `correct` tinyint DEFAULT NULL COMMENT '是否答对' AFTER `feedback`");
ensureColumn("aihr_practice_assignment", "finished_time", "ALTER TABLE aihr_practice_assignment ADD COLUMN `finished_time` datetime DEFAULT NULL COMMENT '完成时间' AFTER `correct`");
assignmentTableReady = true;