fix code
This commit is contained in:
@@ -134,6 +134,7 @@ interface IData {
|
||||
showChatSuggestions: boolean
|
||||
chatSuggestions: Array<{ label: string; text: string }>
|
||||
inputBottom: number
|
||||
isRecording: boolean
|
||||
}
|
||||
|
||||
interface IPageInstance {
|
||||
@@ -144,6 +145,10 @@ interface IPageInstance {
|
||||
suggestionTimer?: number
|
||||
isSuggestionTouching?: boolean
|
||||
audioCtx?: WechatMiniprogram.InnerAudioContext
|
||||
recorderManager?: WechatMiniprogram.RecorderManager
|
||||
handleRecordStart: () => void
|
||||
handleRecordEnd: () => void
|
||||
uploadAndRecognizeAudio: (filePath: string) => Promise<void>
|
||||
onKeyboardHeightChange: (res: any) => void
|
||||
startPlaceholderTimer: () => void
|
||||
startSuggestionTimer: () => void
|
||||
@@ -342,13 +347,63 @@ Page<IData, IPageInstance>({
|
||||
chatPlaceholder: '请输入...',
|
||||
showChatSuggestions: false,
|
||||
chatSuggestions: [],
|
||||
inputBottom: 0
|
||||
inputBottom: 0,
|
||||
isRecording: false
|
||||
},
|
||||
|
||||
onKeyboardHeightChange(res: any) {
|
||||
this.setData({ inputBottom: res.height })
|
||||
},
|
||||
|
||||
handleRecordStart() {
|
||||
if (!this.recorderManager) return
|
||||
wx.authorize({
|
||||
scope: 'scope.record',
|
||||
success: () => {
|
||||
this.recorderManager?.start({ format: 'mp3' })
|
||||
},
|
||||
fail: () => {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '需要录音权限才能使用语音输入',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.openSetting()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleRecordEnd() {
|
||||
if (this.data.isRecording && this.recorderManager) {
|
||||
this.recorderManager.stop()
|
||||
}
|
||||
},
|
||||
|
||||
async uploadAndRecognizeAudio(filePath: string) {
|
||||
wx.showLoading({ title: '识别中...' })
|
||||
try {
|
||||
const fileId = await apiManager.uploadFile(filePath)
|
||||
|
||||
const sessionId = this.data.conversationLatestSession?.session_id
|
||||
if (!sessionId) throw new Error('没有会话ID')
|
||||
|
||||
const res = await apiManager.recognizeQaAudio(sessionId, fileId)
|
||||
if (res.data && res.data.text) {
|
||||
this.setData({ chatInputValue: res.data.text })
|
||||
} else {
|
||||
wx.showToast({ title: '未能识别出文字', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('语音识别失败', e)
|
||||
wx.showToast({ title: '识别失败', icon: 'none' })
|
||||
} finally {
|
||||
wx.hideLoading()
|
||||
}
|
||||
},
|
||||
|
||||
pollTimer: undefined,
|
||||
variationPollTimer: undefined,
|
||||
conversationPollTimer: undefined,
|
||||
@@ -560,6 +615,26 @@ Page<IData, IPageInstance>({
|
||||
|
||||
async onLoad(options: Record<string, string>) {
|
||||
wx.onKeyboardHeightChange(this.onKeyboardHeightChange)
|
||||
this.recorderManager = wx.getRecorderManager()
|
||||
this.recorderManager.onStart(() => {
|
||||
this.setData({ isRecording: true })
|
||||
wx.showToast({ title: '正在录音...', icon: 'none', duration: 60000 })
|
||||
})
|
||||
this.recorderManager.onStop((res) => {
|
||||
this.setData({ isRecording: false })
|
||||
wx.hideToast()
|
||||
const { tempFilePath, duration } = res
|
||||
if (duration < 500) {
|
||||
wx.showToast({ title: '说话时间太短', icon: 'none' })
|
||||
return
|
||||
}
|
||||
this.uploadAndRecognizeAudio(tempFilePath)
|
||||
})
|
||||
this.recorderManager.onError((err) => {
|
||||
console.error('录音报错', err)
|
||||
this.setData({ isRecording: false })
|
||||
wx.showToast({ title: '录音失败', icon: 'none' })
|
||||
})
|
||||
try {
|
||||
const app = getApp<IAppOption>()
|
||||
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
</block>
|
||||
</view>
|
||||
<view class="question-scroll-wrapper {{questionMode === 'conversation' && conversationViewMode === 'chat' && isChatInputVisible ? 'chat-input-mode-scroll' : 'chat-mode-scroll'}}">
|
||||
<scroll-view class="inner-scroll" scroll-y="true" scroll-into-view="{{scrollIntoView}}" scroll-with-animation>
|
||||
<scroll-view class="inner-scroll" scroll-y >
|
||||
<view class="image-card" wx:if="{{questionMode !== 'variation'}}">
|
||||
<image wx:if="{{imageLocalUrl}}" class="image" src="{{imageLocalUrl}}" mode="aspectFill" bindtap="previewImage" bindload="onImageLoad" binderror="onImageError"></image>
|
||||
<view class="view-full" wx:if="{{imageLocalUrl}}" bindtap="previewImage">
|
||||
<t-icon name="zoom-in" size="32rpx" />
|
||||
<!-- <text>View Full</text> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="question-title" wx:if="{{questionMode !== 'conversation'}}">
|
||||
@@ -48,7 +47,6 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="question-content {{modeAnim}}" wx:if="{{questionMode === 'cloze'}}">
|
||||
<!-- <view class="choice-title">Select the correct word to complete the sentence:</view> -->
|
||||
<view class="cloze-sentence">
|
||||
<text wx:for="{{clozeSentenceTokens}}" wx:key="index" class="{{item.isBlank ? 'cloze-fill' : 'cloze-text'}}" data-word="{{item.word}}" bindtap="handleWordClick">{{item.text}}</text>
|
||||
</view>
|
||||
@@ -338,9 +336,12 @@
|
||||
bind:blur="onChatBlur"
|
||||
>
|
||||
<view slot="footer-prefix" class="footer-prefix">
|
||||
<view class="chat-icon-block" bind:tap="onChatCloseTap">
|
||||
<view class="chat-icon-block" bind:tap="onChatCloseTap" style="margin-right: 16rpx;">
|
||||
<t-icon name="close-circle" size="64rpx" color="#dcdcdc"/>
|
||||
</view>
|
||||
<view class="chat-icon-block" bind:touchstart="handleRecordStart" bind:touchend="handleRecordEnd">
|
||||
<t-icon name="microphone-1" size="64rpx" color="{{isRecording ? '#0052d9' : '#dcdcdc'}}"/>
|
||||
</view>
|
||||
</view>
|
||||
</t-chat-sender>
|
||||
</view>
|
||||
@@ -383,7 +384,7 @@
|
||||
<text class="modal-title">题目解析</text>
|
||||
<t-icon name="close" class="modal-close" size="40rpx" bind:tap="onCloseDetailModal" />
|
||||
</view>
|
||||
<scroll-view class="detail-body" scroll-y="true">
|
||||
<scroll-view class="detail-body" scroll-y="{{true}}">
|
||||
<view class="section">
|
||||
<text class="question-text">{{qaDetailQuestionText}}</text>
|
||||
</view>
|
||||
|
||||
@@ -26,17 +26,20 @@
|
||||
|
||||
.question-scroll-wrapper {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
min-height: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
/* padding-bottom: calc(110rpx + env(safe-area-inset-bottom)); */
|
||||
/* transition: padding-bottom 0.3s ease; */
|
||||
transition: margin-bottom 0.3s ease;
|
||||
}
|
||||
.inner-scroll {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
/* height: 100%; */
|
||||
height: 500rpx;
|
||||
}
|
||||
.chat-mode-scroll {
|
||||
/* padding-bottom: calc(110rpx + env(safe-area-inset-bottom)); */
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<text class="sentence-zh">{{scene.list[currentIndex].sentenceZh}}</text>
|
||||
</view>
|
||||
|
||||
<scroll-view class="sentence-body" scroll-y="true" scroll-with-animation="true">
|
||||
<scroll-view class="sentence-body" scroll-y="{{true}}" scroll-with-animation="true">
|
||||
<view class="tags-wrap">
|
||||
<t-tag wx:for="{{scene.list[currentIndex].functionTags}}" wx:key="idx" variant="light"><text>#</text>{{item}}</t-tag>
|
||||
</view>
|
||||
|
||||
@@ -687,6 +687,15 @@ class ApiManager {
|
||||
})
|
||||
}
|
||||
|
||||
// 语音识别
|
||||
async recognizeQaAudio(sessionId: string, fileId: string): Promise<IApiResponse<any>> {
|
||||
return this.request(
|
||||
`/api/v1/qa/conversations/${sessionId}/recognize_audio`,
|
||||
'POST',
|
||||
{ file_id: fileId }
|
||||
)
|
||||
}
|
||||
|
||||
// 上传文件(第一步:上传文件获取ID)
|
||||
async uploadFile(filePath: string, retryCount: number = 0): Promise<string> {
|
||||
if (USE_CLOUD) {
|
||||
|
||||
Reference in New Issue
Block a user