feat(aihr): switch interview and case flows to real-model-first pipeline

AI 面试 /start 动态出题、/finish 按真实回答结构化评分(未配模型用本地
Rubric 估分);案例沉淀 /upload 改 multipart 真实语音+ASR 转写,
/organize 用真实 transcript 调 chat 模型整理;seed service 重构为
AihrInterviewService/AihrCaseService;前端面试/案例/对练页与移动端、
demo-check、验收文档同步真实链路口径。
This commit is contained in:
2026-07-03 23:45:20 +08:00
parent 4fa23617a4
commit 77aa992872
18 changed files with 1475 additions and 389 deletions
+13 -13
View File
@@ -87,7 +87,7 @@
<div class="reply-box">
<div class="reply-head">
<span>学员下一句</span>
<el-button text type="danger" :disabled="finished" @click="fillSeedReply">填入 seed 回复</el-button>
<el-button text type="danger" :disabled="finished" @click="fillReferenceReply">填入参考回复</el-button>
</div>
<el-input
v-model="draftReply"
@@ -95,7 +95,7 @@
:rows="5"
resize="none"
:disabled="finished"
placeholder="输入学员回复,或点击“填入 seed 回复”推进演示"
placeholder="输入学员回复,或点击“填入参考回复”推进测试"
/>
</div>
@@ -276,7 +276,7 @@ const showGoal = ref(false);
const activeRound = ref(0);
const draftReply = ref('');
const sessionId = ref('');
const apiMode = ref<'seed' | 'api' | 'fallback'>('seed');
const apiMode = ref<'local' | 'api' | 'fallback'>('local');
const apiScores = ref<ScenarioSeed['scores'] | null>(null);
const apiTotal = ref<number | null>(null);
const apiRewrite = ref('');
@@ -306,12 +306,12 @@ const trustScore = computed(() => {
});
const apiPill = computed(() => {
if (apiMode.value === 'api') {
return { text: '后端 API seed', className: 'pill-info' };
return { text: '真实 API', className: 'pill-info' };
}
if (apiMode.value === 'fallback') {
return { text: 'API 失败回退', className: 'pill-warning' };
return { text: '本地剧本', className: 'pill-warning' };
}
return { text: '本地 seed 演示', className: 'pill-info' };
return { text: '待调用 API', className: 'pill-info' };
});
const flowPill = computed(() => {
if (!started.value) {
@@ -354,7 +354,7 @@ const resetPractice = () => {
activeRound.value = 0;
draftReply.value = '';
sessionId.value = '';
apiMode.value = 'seed';
apiMode.value = 'local';
apiScores.value = null;
apiTotal.value = null;
apiRewrite.value = '';
@@ -371,23 +371,23 @@ const startPractice = async () => {
const { data } = await startPracticeSession({
extPartyId: selectedScenario.value.trainee,
scenarioId: selectedScenario.value.id,
mode: 'seed'
mode: 'real'
});
sessionId.value = data.sessionId;
apiMode.value = 'api';
apiTrust.value = data.trust;
appendTurn('customer', data.customerText || fallbackCustomer);
ElMessage.success(`已通过后端 API 进入 ${selectedScenario.value.name} seed 对练`);
ElMessage.success(`已通过后端 API 进入 ${selectedScenario.value.name} 对练`);
} catch {
sessionId.value = '';
apiMode.value = 'fallback';
appendTurn('customer', fallbackCustomer);
ElMessage.warning('后端对练 API 不可用,已回退本地 seed 对练');
ElMessage.warning('后端对练 API 不可用,已回退本地剧本');
}
started.value = true;
};
const fillSeedReply = () => {
const fillReferenceReply = () => {
draftReply.value = selectedScenario.value.rounds[activeRound.value].sampleReply;
};
@@ -420,7 +420,7 @@ const continueRound = async () => {
return;
} catch {
apiMode.value = 'fallback';
ElMessage.warning('后端回合 API 不可用,已回退本地 seed 推进');
ElMessage.warning('后端回合 API 不可用,已回退本地剧本推进');
}
}
@@ -460,7 +460,7 @@ const finishScore = async () => {
apiTotal.value = null;
apiRewrite.value = '';
apiSummary.value = '';
ElMessage.warning('后端评分 API 不可用,已回退本地 seed 评分');
ElMessage.warning('后端评分 API 不可用,已回退本地评分');
}
} else {
apiScores.value = null;