feat: latest code update
This commit is contained in:
@@ -100,12 +100,13 @@ let recorder = null
|
||||
let timerSeconds = 0
|
||||
let timerInterval = null
|
||||
|
||||
const progressPercent = computed(() => Math.min((answeredCount.value / 5) * 100, 100))
|
||||
let MAX_QUESTIONS = 10
|
||||
const progressPercent = computed(() => Math.min((answeredCount.value / MAX_QUESTIONS) * 100, 100))
|
||||
const formatTime = computed(() => {
|
||||
const m = Math.floor(timerSeconds / 60); const s = timerSeconds % 60
|
||||
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
|
||||
})
|
||||
const token = computed(() => uni.getStorageSync('token') || '')
|
||||
const token = () => uni.getStorageSync('token') || ''
|
||||
|
||||
onLoad((options) => {
|
||||
if (options?.position) {
|
||||
@@ -117,7 +118,7 @@ onLoad((options) => {
|
||||
|
||||
onMounted(() => {
|
||||
timerInterval = setInterval(() => timerSeconds++, 1000)
|
||||
if (token.value) startInterview()
|
||||
if (token()) startInterview()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -125,7 +126,7 @@ onBeforeUnmount(() => {
|
||||
})
|
||||
|
||||
const checkLogin = () => {
|
||||
if (!token.value) {
|
||||
if (!token()) {
|
||||
uni.showModal({
|
||||
title: '请先登录', content: '登录后即可开始 AI 模拟面试', confirmText: '去登录',
|
||||
success: (r) => { if (r.confirm) uni.navigateTo({ url: '/pages/login/login' }) },
|
||||
@@ -141,18 +142,22 @@ const startInterview = async () => {
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: api('/interview/create'), method: 'POST',
|
||||
header: { 'Authorization': `Bearer ${token.value}`, 'Content-Type': 'application/json' },
|
||||
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
||||
data: { position: position.value },
|
||||
})
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
interviewId.value = res.data.id
|
||||
messages.value = res.data.messages || messages.value
|
||||
answeredCount.value = res.data.questionCount || 0
|
||||
if (res.data.totalQuestions) MAX_QUESTIONS = res.data.totalQuestions
|
||||
// Speak first question in avatar mode
|
||||
if (avatarMode.value && res.data.messages?.length) {
|
||||
const last = res.data.messages[res.data.messages.length - 1]
|
||||
if (last?.role === 'ai') await speakAiText(last.content)
|
||||
}
|
||||
} else {
|
||||
const msg = res.data?.message || '创建面试失败'
|
||||
messages.value.push({ role: 'ai', content: msg })
|
||||
}
|
||||
} catch {
|
||||
messages.value.push({ role: 'ai', content: '创建面试失败,请重试' })
|
||||
@@ -164,8 +169,11 @@ const startInterview = async () => {
|
||||
|
||||
const sendAnswer = async () => {
|
||||
if (!inputText.value.trim() || aiLoading.value || isComplete.value) return
|
||||
if (!token.value) { checkLogin(); return }
|
||||
if (!interviewId.value) { await startInterview(); return }
|
||||
if (!token()) { checkLogin(); return }
|
||||
if (!interviewId.value) {
|
||||
await startInterview()
|
||||
if (!interviewId.value) return // creation failed, don't discard answer
|
||||
}
|
||||
|
||||
const answer = inputText.value.trim()
|
||||
messages.value.push({ role: 'user', content: answer })
|
||||
@@ -176,19 +184,24 @@ const sendAnswer = async () => {
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: api(`/interview/${interviewId.value}/answer`), method: 'POST',
|
||||
header: { 'Authorization': `Bearer ${token.value}`, 'Content-Type': 'application/json' },
|
||||
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
||||
data: avatarMode.value ? { answer, avatar: true } : { answer },
|
||||
})
|
||||
if (res.statusCode === 200 && res.data?.messages) {
|
||||
const aiMsg = res.data.messages.find(m => m.role === 'ai')
|
||||
messages.value.push(...res.data.messages)
|
||||
if (avatarMode.value && aiMsg) {
|
||||
// Only push AI messages from response to avoid duplicating the user message already added above
|
||||
const newAiMessages = res.data.messages.filter(m => m.role === 'ai')
|
||||
if (newAiMessages.length > 0) messages.value.push(...newAiMessages)
|
||||
if (avatarMode.value && aiMsg) {
|
||||
await speakAiText(aiMsg.content, res.data.ttsHash, res.data.ttsAmplitude)
|
||||
}
|
||||
answeredCount.value = res.data.questionCount || answeredCount.value + 1
|
||||
if (res.data.ttsHash && !avatarMode.value) {
|
||||
// Still got TTS but not in avatar mode, just show text
|
||||
}
|
||||
if (res.data.totalQuestions) MAX_QUESTIONS = res.data.totalQuestions
|
||||
} else if (res.statusCode === 403) {
|
||||
messages.value.push({ role: 'ai', content: res.data?.message || '面试次数已用完' })
|
||||
isComplete.value = true
|
||||
} else {
|
||||
messages.value.push({ role: 'ai', content: res.data?.message || '回答提交失败' })
|
||||
}
|
||||
} catch {
|
||||
messages.value.push({ role: 'ai', content: '回答提交失败,请重试' })
|
||||
@@ -207,7 +220,7 @@ async function speakAiText(text, ttsHash, ttsAmplitude) {
|
||||
try {
|
||||
const synthRes = await uni.request({
|
||||
url: api('/tts/synthesize'), method: 'POST',
|
||||
header: { 'Content-Type': 'application/json' },
|
||||
header: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token()}` },
|
||||
data: { text },
|
||||
})
|
||||
if (synthRes.statusCode === 200 && synthRes.data?.hash) {
|
||||
@@ -240,12 +253,17 @@ const confirmExit = () => {
|
||||
|
||||
function startRecord() {
|
||||
if (aiLoading.value || isComplete.value) return
|
||||
// #ifdef MP-WEIXIN
|
||||
isRecording.value = true
|
||||
recorder = uni.getRecorderManager()
|
||||
recorder.onStart(() => {})
|
||||
recorder.onError(() => { isRecording.value = false })
|
||||
recorder.start({ format: 'mp3' })
|
||||
uni.vibrateShort({ type: 'medium' })
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' })
|
||||
// #endif
|
||||
}
|
||||
|
||||
function stopRecord() {
|
||||
@@ -260,7 +278,7 @@ function stopRecord() {
|
||||
url: api(API_ENDPOINTS.TTS.ASR),
|
||||
filePath: audioPath,
|
||||
name: 'audio',
|
||||
header: { 'Authorization': `Bearer ${token.value}` },
|
||||
header: { 'Authorization': `Bearer ${token()}` },
|
||||
})
|
||||
console.log('[ASR] upload response:', uploadRes.statusCode, typeof uploadRes.data === 'string' ? uploadRes.data.slice(0, 200) : JSON.stringify(uploadRes.data).slice(0, 200))
|
||||
if (uploadRes.statusCode === 200 && uploadRes.data) {
|
||||
|
||||
Reference in New Issue
Block a user