Merge pull request 'lisa-feat' (#3) from lisa-feat into main

Reviewed-on: http://gitea.xhzone.cn/felix/miniprogram-1/pulls/3
This commit is contained in:
felix
2025-10-15 10:24:54 +00:00
9 changed files with 555 additions and 60 deletions

View File

@@ -7,6 +7,7 @@
"enablePullDownRefresh": false,
"onReachBottomDistance": 50,
"usingComponents": {
"t-slider": "tdesign-miniprogram/slider/slider",
"t-icon": "tdesign-miniprogram/icon/icon"
}
}

View File

@@ -20,6 +20,17 @@ interface IPageData {
hasScoreInfo: boolean // 是否有评分信息
words: string[] // 句子内容的单词数组
ipas: string[] // 音标的单词数组
isScoreExpanded: boolean // 评分区域是否展开
wordScores: Array<{ // 单词评分数组
word: string
pronAccuracy: number
pronFluency: number
}>
standardAudioMap: { [key: string]: string } // 标准语音文件ID映射
isPlaying: boolean // 是否正在播放音频
audioDuration: number // 音频总时长
currentTime: number // 当前播放时间
sliderValue: number // 进度条值0-100
}
type IPageMethods = {
@@ -31,11 +42,19 @@ type IPageMethods = {
handleRecordStart: () => void
handleRecordEnd: () => void
updateWordsAndIpas: (content: string, ipa: string) => void
toggleScoreSection: () => void
handleImagePreview: () => void
getStandardVoice: (sentenceId: string) => Promise<void>
playStandardVoice: () => void
resetAudioState: () => void
handleSliderChange: (e: any) => void
formatTime: (seconds: number) => string
}
interface IPageInstance extends IPageMethods {
recordTimer?: number
data: IPageData
audioContext?: WechatMiniprogram.InnerAudioContext
}
Page<IPageData, IPageInstance>({
@@ -56,6 +75,20 @@ Page<IPageData, IPageInstance>({
hasScoreInfo: false, // 是否有评分信息
words: [], // 句子内容的单词数组
ipas: [], // 音标的单词数组
isScoreExpanded: false, // 评分区域是否展开
wordScores: [], // 单词评分数组
standardAudioMap: {}, // 标准语音文件ID映射
isPlaying: false, // 是否正在播放音频
audioDuration: 0, // 音频总时长
currentTime: 0, // 当前播放时间
sliderValue: 0 // 进度条值0-100
},
// 切换评分区域展开状态
toggleScoreSection() {
this.setData({
isScoreExpanded: !this.data.isScoreExpanded
})
},
// 更新单词和音标数组
@@ -76,10 +109,26 @@ Page<IPageData, IPageInstance>({
this.setData({ circleProgressStyle: style })
},
// 重置音频播放状态
resetAudioState() {
if (this.audioContext) {
this.audioContext.stop()
}
this.setData({
isPlaying: false,
currentTime: 0,
sliderValue: 0,
audioDuration: 0
})
},
// 切换到上一个例句
prevSentence() {
const { currentIndex, sentences } = this.data
if (currentIndex <= 0) return;
// 重置音频播放状态
this.resetAudioState()
if (currentIndex > 0) {
const currentSentence = sentences[currentIndex - 1]
const assessmentResult = currentSentence?.details?.assessment?.result
@@ -91,6 +140,13 @@ Page<IPageData, IPageInstance>({
// 检查是否所有评分都为负数
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
// 处理单词评分数据
const wordScores = assessmentResult?.Words?.map((word: any) => ({
word: word.Word,
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
pronFluency: Number(word.PronFluency.toFixed(2))
})) || []
this.setData({
currentIndex: currentIndex - 1,
currentSentence: currentSentence,
@@ -98,9 +154,14 @@ Page<IPageData, IPageInstance>({
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
wordScores
})
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
// 获取当前例句的标准语音
if (currentSentence.id) {
this.getStandardVoice(currentSentence.id)
}
this.updateCircleProgress()
}
@@ -110,6 +171,9 @@ Page<IPageData, IPageInstance>({
nextSentence() {
const { currentIndex, sentences } = this.data
if (currentIndex >= sentences.length - 1) return;
// 重置音频播放状态
this.resetAudioState()
if (currentIndex < sentences.length - 1) {
const index = currentIndex + 1
const currentSentence = sentences[index]
@@ -122,6 +186,13 @@ Page<IPageData, IPageInstance>({
// 检查是否所有评分都为负数
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
// 处理单词评分数据
const wordScores = assessmentResult?.Words?.map((word: any) => ({
word: word.Word,
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
pronFluency: Number(word.PronFluency.toFixed(2))
})) || []
this.setData({
currentIndex: index,
currentSentence: currentSentence,
@@ -129,9 +200,14 @@ Page<IPageData, IPageInstance>({
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
wordScores
})
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
// 获取当前例句的标准语音
if (currentSentence.id) {
this.getStandardVoice(currentSentence.id)
}
this.updateCircleProgress()
}
},
@@ -211,6 +287,116 @@ Page<IPageData, IPageInstance>({
})
},
// 获取标准语音
async getStandardVoice(sentenceId: string) {
try {
// 如果已经获取过该例句的标准语音,直接返回
if (this.data.standardAudioMap[sentenceId]) return
const id = await apiManager.getStandardVoice(sentenceId)
if (id) {
const fileUrl = `${FILE_BASE_URL}/${id}`
this.setData({
standardAudioMap: {
...this.data.standardAudioMap,
[sentenceId]: fileUrl
}
})
}
} catch (err) {
console.error('获取标准语音失败:', err)
wx.showToast({
title: '获取语音失败',
icon: 'none'
})
}
},
// 播放标准语音
playStandardVoice() {
const { currentSentence, standardAudioMap, isPlaying } = this.data
const audioUrl = standardAudioMap[currentSentence.id]
if (!audioUrl) {
wx.showToast({
title: '暂无标准语音',
icon: 'none'
})
return
}
if (isPlaying) {
this.audioContext?.pause()
this.setData({ isPlaying: false })
return
}
if (!this.audioContext) {
this.audioContext = wx.createInnerAudioContext()
this.audioContext.onEnded(() => {
this.setData({
isPlaying: false,
currentTime: 0,
sliderValue: 0
})
})
this.audioContext.onError(() => {
this.setData({
isPlaying: false,
currentTime: 0,
sliderValue: 0
})
wx.showToast({
title: '播放失败',
icon: 'none'
})
})
this.audioContext.onTimeUpdate(() => {
const currentTime = this.audioContext!.currentTime
const duration = this.audioContext!.duration
const sliderValue = (currentTime / duration) * 100
this.setData({
currentTime,
audioDuration: duration,
sliderValue
})
})
}
if (this.audioContext.src !== audioUrl) {
this.audioContext.src = audioUrl
this.setData({
currentTime: 0,
sliderValue: 0
})
}
this.audioContext.play()
this.setData({ isPlaying: true })
},
// 处理进度条拖动
handleSliderChange(e: any) {
const value = e.detail.value
const duration = this.audioContext?.duration || 0
const currentTime = (value / 100) * duration
if (this.audioContext) {
this.audioContext.seek(currentTime)
this.setData({
currentTime,
sliderValue: value
})
}
},
// 格式化时间
formatTime(seconds: number) {
const minutes = Math.floor(seconds / 60)
const remainingSeconds = Math.floor(seconds % 60)
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`
},
onLoad(options: Record<string, string>) {
//如果有图片ID调用接口获取文本和评分信息
if (options.index) {
@@ -238,6 +424,13 @@ Page<IPageData, IPageInstance>({
// 检查是否所有评分都为负数
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every((score: number) => score < 0)
// 处理单词评分数据
const wordScores = assessmentResult?.Words?.map((word: any) => ({
word: word.Word,
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
pronFluency: Number(word.PronFluency.toFixed(2))
})) || []
this.setData({
sentences,
currentSentence,
@@ -246,9 +439,14 @@ Page<IPageData, IPageInstance>({
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
wordScores
})
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
// 获取当前例句的标准语音
if (currentSentence.id) {
this.getStandardVoice(currentSentence.id)
}
}
// 初始化圆形进度条
this.updateCircleProgress()
@@ -269,6 +467,13 @@ Page<IPageData, IPageInstance>({
}
},
onUnload() {
// 销毁音频实例
if (this.audioContext) {
this.audioContext.destroy()
}
},
onReady() {
// 监听录音结束事件
recorderManager.onStop((res) => {
@@ -278,6 +483,7 @@ Page<IPageData, IPageInstance>({
content: '录音完成,是否确认提交?',
success: (result) => {
if (result.confirm) {
wx.showLoading({ title: '正在解析...' })
console.log('录音文件路径:', res.tempFilePath)
apiManager.uploadFile(res.tempFilePath).then((fileId) => {
apiManager.getAssessmentResult(fileId, this.data.currentSentence.id).then((result) => {
@@ -291,17 +497,51 @@ Page<IPageData, IPageInstance>({
// 检查是否所有评分都为负数
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
// 更新当前例句的评分信息
const { sentences, currentIndex } = this.data
sentences[currentIndex].details = {
assessment: {
result: assessmentResult
}
}
// 处理单词评分数据
const wordScores = assessmentResult.Words?.map((word: any) => ({
word: word.Word,
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
pronFluency: Number(word.PronFluency.toFixed(2))
})) || []
// 更新评分信息
this.setData({
sentences, // 保存更新后的例句数组
hasScoreInfo: !allNegative && !!assessmentResult,
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
completenessScore: pronCompletion >= 0 ? Number(pronCompletion.toFixed(2)) : 0,
fluencyScore: pronFluency >= 0 ? Number(pronFluency.toFixed(2)) : 0
fluencyScore: pronFluency >= 0 ? Number(pronFluency.toFixed(2)) : 0,
wordScores
})
// 更新圆形进度条
this.updateCircleProgress()
wx.hideLoading()
})
.catch(err => {
console.error('获取评估结果失败:', err)
wx.showToast({
title: '评估失败',
icon: 'error'
})
wx.hideLoading()
})
})
.catch(err => {
console.error('上传录音失败:', err)
wx.showToast({
title: '上传失败',
icon: 'error'
})
wx.hideLoading()
})
}
}

View File

@@ -32,6 +32,20 @@
<view class="microphone-container">
<t-icon name="microphone-1" class="microphone {{isRecording ? 'recording' : ''}}" size="100rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
<text wx:if="{{isRecording}}" class="countdown">{{remainingTime}}s</text>
<!-- 音频播放控制区域 -->
<view class="audio-control">
<view class="audio-title">标准音频</view>
<view class="audio-player">
<t-button class="play-btn" theme="primary" size="large" variant="outline" bind:tap="playStandardVoice">
<t-icon name="{{isPlaying ? 'pause' : 'play'}}" size="48rpx" />
</t-button>
<view class="audio-progress">
<text class="time-text">{{formatTime(currentTime)}}</text>
<t-slider class="progress-slider" value="{{sliderValue}}" bind:change="handleSliderChange" showValue="{{false}}" />
<text class="time-text">{{formatTime(audioDuration)}}</text>
</view>
</view>
</view>
<!-- 评分详解按钮 -->
<t-button wx:if="{{hasScoreInfo}}" class="score-detail-btn" theme="primary" size="small" variant="outline" bind:tap="handleScoreDetailClick">
评分详解
@@ -39,50 +53,68 @@
</view>
</view>
<!-- 底部评分结果区域 -->
<view class="score-section">
<view class="score-section {{isScoreExpanded ? 'expanded' : ''}}" bindtap="toggleScoreSection">
<block wx:if="{{hasScoreInfo}}">
<view class="score-container">
<view class="total-score">
<view class="circle-progress" style="{{circleProgressStyle}}">
<text class="total-score-value">{{totalScore}}</text>
<text class="total-score-label">总分</text>
<view class="score-overview">
<view class="total-score">
<view class="circle-progress" style="{{circleProgressStyle}}">
<text class="total-score-value">{{totalScore}}</text>
<text class="total-score-label">总分</text>
</view>
</view>
<view class="score-details">
<view class="score-item">
<text class="score-label">准确性</text>
<view class="score-content">
<block wx:if="{{accuracyScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{accuracyScore}}%"></view>
</view>
<text class="score-value">{{accuracyScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
</view>
</view>
<view class="score-item">
<text class="score-label">完整性</text>
<view class="score-content">
<block wx:if="{{completenessScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{completenessScore}}%"></view>
</view>
<text class="score-value">{{completenessScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
</view>
</view>
<view class="score-item">
<text class="score-label">流利度</text>
<view class="score-content">
<block wx:if="{{fluencyScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{fluencyScore}}%"></view>
</view>
<text class="score-value">{{fluencyScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
</view>
</view>
</view>
</view>
<view class="score-details">
<view class="score-item">
<text class="score-label">准确性</text>
<view class="score-content">
<block wx:if="{{accuracyScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{accuracyScore}}%"></view>
</view>
<text class="score-value">{{accuracyScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
</view>
</view>
<view class="score-item">
<text class="score-label">完整性</text>
<view class="score-content">
<block wx:if="{{completenessScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{completenessScore}}%"></view>
</view>
<text class="score-value">{{completenessScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
</view>
</view>
<view class="score-item">
<text class="score-label">流利度</text>
<view class="score-content">
<block wx:if="{{fluencyScore >= 0}}">
<view class="progress-bar">
<view class="progress-fill" style="width: {{fluencyScore}}%"></view>
</view>
<text class="score-value">{{fluencyScore}}</text>
</block>
<text wx:else class="no-score-text">暂无评分</text>
<!-- 单词评分列表 -->
<view class="word-scores-list">
<view class="word-score-item" wx:for="{{wordScores}}" wx:key="word">
<text class="word-text">{{item.word}}</text>
<view class="word-score-details">
<view class="word-score-row">
<text class="word-score-label">准确性</text>
<text class="word-score-value">{{item.pronAccuracy}}</text>
</view>
<view class="word-score-row">
<text class="word-score-label">流利度</text>
<text class="word-score-value">{{item.pronFluency}}</text>
</view>
</view>
</view>
</view>
@@ -92,4 +124,6 @@
<text class="no-score-text">暂无评分</text>
</view>
</view>
<!-- 遮罩层 -->
<view class="mask" wx:if="{{isScoreExpanded}}" catchtap="toggleScoreSection"></view>
</view>

View File

@@ -100,6 +100,7 @@
}
.page-indicator {
margin-top: 30rpx;
font-size: 24rpx;
color: #666666;
display: block;
@@ -110,11 +111,63 @@
display: flex;
flex-direction: column;
align-items: center;
margin-top: 40rpx;
position: relative;
gap: 24rpx;
}
.audio-control {
display: flex;
align-items: center;
justify-content: start;
width: 100%;
padding: 24rpx 32rpx;
background: #ffffff;
border-radius: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.audio-title {
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
.audio-player {
display: flex;
align-items: center;
gap: 24rpx;
}
.play-btn {
display: flex;
align-items: center;
justify-content: center;
width: 96rpx;
height: 96rpx;
padding: 0;
border-radius: 50%;
flex-shrink: 0;
}
.audio-progress {
flex: 1;
display: flex;
align-items: center;
gap: 16rpx;
}
.time-text {
font-size: 24rpx;
color: #666;
min-width: 70rpx;
text-align: center;
}
.progress-slider {
flex: 1;
margin: 0 8rpx;
}
.score-detail-btn {
margin-top: 8rpx;
min-width: 160rpx;
@@ -171,12 +224,90 @@
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.1);
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
transition: all 0.3s ease-in-out;
max-height: 25vh;
}
.score-section.expanded {
transform: translateY(0);
height: 80vh;
max-height: 80vh;
overflow-y: auto;
}
.score-section::after {
content: '';
position: absolute;
top: 16rpx;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 6rpx;
background: #e0e0e0;
border-radius: 3rpx;
}
.expanded .score-section::after {
display: none;
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.expanded + .mask {
opacity: 1;
}
.score-container {
display: flex;
align-items: center;
flex-direction: column;
width: 100%;
transition: all 0.3s ease-in-out;
}
.score-overview {
display: flex;
align-items: flex-start;
gap: 32rpx;
width: 100%;
}
.expanded .score-overview {
flex-direction: column;
align-items: center;
margin-bottom: 32rpx;
}
.expanded .total-score {
margin-bottom: 48rpx;
transform: scale(1.2);
}
.expanded .score-details {
width: 100%;
padding: 0 32rpx;
opacity: 1;
transform: translateY(0);
}
.score-details {
transition: all 0.3s ease-in-out;
opacity: 0.8;
transform: translateY(20rpx);
}
.total-score {
@@ -285,4 +416,57 @@
.no-score-text {
font-size: 32rpx;
color: #999;
}
/* 单词评分列表样式 */
.word-scores-list {
width: 100%;
display: flex;
flex-direction: column;
gap: 24rpx;
max-height: calc(80vh - 400rpx);
overflow-y: auto;
border-top: 1rpx solid #f0f0f0;
margin-top: 32rpx;
}
.word-score-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
background: #f8f8f8;
border-radius: 12rpx;
}
.word-text {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.word-score-details {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.word-score-row {
display: flex;
align-items: center;
gap: 12rpx;
justify-content: flex-end;
}
.word-score-label {
font-size: 24rpx;
color: #666;
}
.word-score-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
min-width: 80rpx;
text-align: right;
}

View File

@@ -234,7 +234,6 @@ Page({
displayContent: validDescriptions,
errorTip: ''
})
console.log('--lisa-displayContent', this.data.displayContent)
} else {
this.setData({
errorTip: '暂无描述信息'

View File

@@ -130,7 +130,6 @@ Page({
hasMore: newData.length < result.total,
isLoading: false,
});
console.log('---lisa-groupedHistory', this.data.groupedHistory)
} catch (error) {
console.error('加载每日摘要失败:', error);
this.setData({ isLoading: false });
@@ -177,7 +176,7 @@ Page({
const { imageId } = e.currentTarget.dataset;
if (imageId) {
wx.navigateTo({
url: `/pages/result_show/result_show?imageId=${imageId}`
url: `/pages/assessment/assessment?imageId=${imageId}`
})
}
},
@@ -279,7 +278,7 @@ Page({
const { image_id } = e.detail.selected
if (image_id) {
wx.navigateTo({
url: `/pages/result_show/result_show?imageId=${image_id}`
url: `/pages/assessment/assessment?imageId=${image_id}`
})
}
},

View File

@@ -50,11 +50,11 @@
<view class="history-card-list">
<view class="history-card-item" catch:tap="onImageCardTap" data-image-items="{{historyItem}}" wx:for="{{item.items}}" wx:for-item="historyItem" wx:for-index="index" wx:key="index">
<p class="month-day">{{historyItem.monthDay}}</p>
<view class="images-list">
<view wx:for="{{historyItem.images}}" wx:for-item="image" wx:key="image_id" catch:tap="onImageTap" data-image-id="{{image.image_id}}">
<scroll-view class="images-list" scroll-x enable-flex>
<view class="image-item-wrap" wx:for="{{historyItem.images}}" wx:for-item="image" wx:key="image_id" catch:tap="onImageTap" data-image-id="{{image.image_id}}">
<image class="image-item" src="{{image.thumbnail_url}}" mode="aspectFill" />
</view>
</view>
</scroll-view>
</view>
</view>
</view>

View File

@@ -38,6 +38,10 @@
}
.login-prompt {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
background: #ffffff;
padding: 60rpx 40rpx;
@@ -94,10 +98,16 @@
.images-list {
margin-top: 20rpx;
width: 100%;
white-space: nowrap;
display: flex;
flex-wrap: nowrap;
overflow: hidden;
gap: 12rpx;
gap: 16rpx;
}
.images-list::-webkit-scrollbar {
display: none;
}
.image-item-wrap {
margin-right: 16rpx;
}
.image-item {
width: 100rpx;

View File

@@ -1254,7 +1254,11 @@ class ApiManager {
PronFluency: number,
PronCompletion: number,
SuggestedScore: number
Words: any
Words: {
Word: string
PronAccuracy: number,
PronFluency: number,
}[]
}
}
}
@@ -1277,7 +1281,11 @@ class ApiManager {
PronFluency: number,
PronCompletion: number,
SuggestedScore: number
Words: any
Words: {
Word: string
PronAccuracy: number,
PronFluency: number,
}[]
}
}
}
@@ -1314,7 +1322,11 @@ class ApiManager {
PronFluency: number,
PronCompletion: number,
SuggestedScore: number,
Words: any
Words: {
Word: string
PronAccuracy: number,
PronFluency: number,
}[]
}
}
} | null
@@ -1343,7 +1355,11 @@ class ApiManager {
PronFluency: number,
PronCompletion: number,
SuggestedScore: number,
Words: any
Words: {
Word: string
PronAccuracy: number,
PronFluency: number,
}[]
}
}
} | null
@@ -1361,6 +1377,18 @@ class ApiManager {
}
}
async getStandardVoice(text_id: string | number): Promise<number | string> {
try {
console.log('开始获取标准音频');
const response = await this.request<number | string>(`/api/v1/image_text/standard/${text_id}`);
console.log('获取标准音频成功:', response.data);
return response.data;
} catch (error) {
console.error('获取标准音频失败:', error);
throw error;
}
}
}
// 导出单例