/** * 模拟后端API服务 * 用于语音转文字功能的模拟接口实现 */ // API响应接口 export interface ApiResponse { success: boolean data?: T error?: { code: string message: string } timestamp: number } // 语音转文字请求参数 export interface VoiceToTextRequest { audio: any // 音频文件 format: string // 音频格式 duration: number // 音频时长(秒) language?: string // 语言类型 userId?: string // 用户ID } // 语音转文字响应数据 export interface VoiceToTextResponse { text: string // 转换后的文本 confidence: number // 识别置信度 (0-1) duration: number // 音频时长 segments?: Array<{ // 分段结果 text: string start: number end: number confidence: number }> } /** * 模拟API服务类 */ export class MockApiService { private static instance: MockApiService private requestDelay: number = 1500 // 模拟网络延迟 private successRate: number = 0.95 // 成功率 // 预设的模拟文本库 private mockTexts = { short: [ "你好", "谢谢", "再见", "是的", "不是", "好的", "没问题", "可以" ], medium: [ "这是一段测试语音", "语音识别功能正常", "请检查录音质量", "系统运行正常", "欢迎使用语音功能", "录音测试成功", "语音转文字完成" ], long: [ "这是一段较长的语音转文字测试内容,用于验证系统的识别能力", "人工智能语音识别技术在近年来取得了重大突破,准确率不断提升", "语音交互将成为未来人机交互的重要方式,应用前景非常广阔", "通过深度学习和神经网络技术,语音识别系统能够更好地理解人类语言", "语音转文字功能在智能客服、会议记录、语音助手等场景中发挥重要作用" ] } // 错误类型库 private errorTypes = [ { code: 'NETWORK_ERROR', message: '网络连接异常,请检查网络设置' }, { code: 'AUDIO_QUALITY_LOW', message: '音频质量较低,识别结果可能不准确' }, { code: 'SERVER_BUSY', message: '服务器繁忙,请稍后重试' }, { code: 'FORMAT_NOT_SUPPORTED', message: '音频格式不支持,请使用标准格式' }, { code: 'DURATION_TOO_SHORT', message: '音频时长过短,无法识别' }, { code: 'LANGUAGE_NOT_SUPPORTED', message: '不支持的语言类型' } ] private constructor() {} /** * 获取单例实例 */ static getInstance(): MockApiService { if (!MockApiService.instance) { MockApiService.instance = new MockApiService() } return MockApiService.instance } /** * 语音转文字接口 */ async voiceToText(request: VoiceToTextRequest): Promise> { // 参数验证 const validationError = this.validateRequest(request) if (validationError) { return this.createErrorResponse(validationError.code, validationError.message) } // 模拟网络延迟 await this.delay(this.requestDelay + Math.random() * 1000) // 模拟请求失败 if (Math.random() > this.successRate) { const randomError = this.errorTypes[Math.floor(Math.random() * this.errorTypes.length)] return this.createErrorResponse(randomError.code, randomError.message) } // 生成模拟结果 const result = this.generateMockResult(request) return this.createSuccessResponse(result) } /** * 验证请求参数 */ private validateRequest(request: VoiceToTextRequest): { code: string, message: string } | null { if (!request.audio) { return { code: 'MISSING_AUDIO', message: '音频文件不能为空' } } if (request.duration < 0.5) { return { code: 'DURATION_TOO_SHORT', message: '音频时长过短,至少需要0.5秒' } } if (request.duration > 600) { return { code: 'DURATION_TOO_LONG', message: '音频时长过长,最多支持10分钟' } } const supportedFormats = ['mp3', 'wav', 'aac', 'PCM', 'webm'] if (!supportedFormats.includes(request.format?.toLowerCase())) { return { code: 'FORMAT_NOT_SUPPORTED', message: '不支持的音频格式' } } return null } /** * 生成模拟识别结果 */ private generateMockResult(request: VoiceToTextRequest): VoiceToTextResponse { const duration = request.duration let selectedText: string // 根据音频时长选择合适的文本 if (duration < 2) { selectedText = this.mockTexts.short[Math.floor(Math.random() * this.mockTexts.short.length)] } else if (duration < 8) { selectedText = this.mockTexts.medium[Math.floor(Math.random() * this.mockTexts.medium.length)] } else { selectedText = this.mockTexts.long[Math.floor(Math.random() * this.mockTexts.long.length)] } // 根据语言类型调整文本 if (request.language === 'en-US') { selectedText = this.translateToEnglish(selectedText) } // 生成置信度 (时长越长,置信度可能越低) let baseConfidence = 0.95 if (duration > 30) { baseConfidence = 0.85 } else if (duration > 60) { baseConfidence = 0.80 } const confidence = baseConfidence - Math.random() * 0.15 return { text: selectedText, confidence: Math.max(0.60, confidence), duration: duration, segments: this.generateSegments(selectedText, duration) } } /** * 简单的中英文翻译(模拟) */ private translateToEnglish(chineseText: string): string { const translations: Record = { '你好': 'Hello', '谢谢': 'Thank you', '再见': 'Goodbye', '是的': 'Yes', '不是': 'No', '好的': 'OK', '没问题': 'No problem', '可以': 'Sure', '这是一段测试语音': 'This is a test voice', '语音识别功能正常': 'Voice recognition is working', '请检查录音质量': 'Please check recording quality', '系统运行正常': 'System is running normally', '欢迎使用语音功能': 'Welcome to use voice function', '录音测试成功': 'Recording test successful', '语音转文字完成': 'Speech to text completed' } return translations[chineseText] || 'This is a voice recognition test' } /** * 生成分段结果 */ private generateSegments(text: string, duration: number): Array<{ text: string start: number end: number confidence: number }> { const segments = [] const words = text.split('') const avgTimePerChar = duration / words.length let currentTime = 0 let currentSegment = '' const segmentLength = Math.max(1, Math.floor(words.length / Math.max(1, Math.floor(duration / 3)))) for (let i = 0; i < words.length; i++) { currentSegment += words[i] if (currentSegment.length >= segmentLength || i === words.length - 1) { const segmentDuration = currentSegment.length * avgTimePerChar segments.push({ text: currentSegment, start: currentTime, end: currentTime + segmentDuration, confidence: 0.70 + Math.random() * 0.30 }) currentTime += segmentDuration currentSegment = '' } } return segments } /** * 创建成功响应 */ private createSuccessResponse(data: T): ApiResponse { return { success: true, data, timestamp: Date.now() } } /** * 创建错误响应 */ private createErrorResponse(code: string, message: string): ApiResponse { return { success: false, error: { code, message }, timestamp: Date.now() } } /** * 延迟函数 */ private delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)) } /** * 设置请求延迟 */ setRequestDelay(delay: number): void { this.requestDelay = Math.max(0, delay) } /** * 设置成功率 */ setSuccessRate(rate: number): void { this.successRate = Math.max(0, Math.min(1, rate)) } /** * 添加自定义文本 */ addMockText(category: 'short' | 'medium' | 'long', text: string): void { this.mockTexts[category].push(text) } /** * 添加自定义错误类型 */ addErrorType(code: string, message: string): void { this.errorTypes.push({ code, message }) } } /** * API客户端类 * 用于统一管理API调用 */ export class ApiClient { private baseUrl: string = '' private timeout: number = 30000 private mockService: MockApiService constructor(baseUrl: string = '', useMock: boolean = true) { this.baseUrl = baseUrl this.mockService = MockApiService.getInstance() // 如果没有提供baseUrl或者明确使用模拟服务,则使用模拟服务 if (!baseUrl || useMock) { console.log('使用模拟API服务') } } /** * 语音转文字接口调用 */ async voiceToText(audioFile: any, options: { format: string duration: number language?: string userId?: string }): Promise> { // 如果没有配置真实API地址,使用模拟服务 if (!this.baseUrl) { return this.mockService.voiceToText({ audio: audioFile, format: options.format, duration: options.duration, language: options.language || 'zh-CN', userId: options.userId }) } // 真实API调用实现 return this.realApiCall(audioFile, options) } /** * 真实API调用 */ private async realApiCall(audioFile: any, options: any): Promise> { try { const response = await uni.request({ url: `${this.baseUrl}/api/voice-to-text`, method: 'POST', data: { audio: audioFile, format: options.format, duration: options.duration, language: options.language || 'zh-CN', userId: options.userId }, timeout: this.timeout, header: { 'Content-Type': 'application/json' } }) if (response.statusCode === 200) { return response.data as ApiResponse } else { throw new Error(`API调用失败,状态码: ${response.statusCode}`) } } catch (error: any) { return { success: false, error: { code: 'API_ERROR', message: error.message || 'API调用失败' }, timestamp: Date.now() } } } /** * 设置超时时间 */ setTimeout(timeout: number): void { this.timeout = timeout } /** * 获取模拟服务实例 */ getMockService(): MockApiService { return this.mockService } } /** * 创建API客户端实例 */ export function createApiClient(baseUrl?: string, useMock: boolean = true): ApiClient { return new ApiClient(baseUrl, useMock) } /** * 默认API客户端实例 */ export const defaultApiClient = createApiClient() /** * 便捷的语音转文字函数 */ export async function convertVoiceToText( audioFile: any, options: { format: string duration: number language?: string userId?: string } ): Promise { try { const response = await defaultApiClient.voiceToText(audioFile, options) if (response.success && response.data) { return response.data.text } else { throw new Error(response.error?.message || '语音转换失败') } } catch (error: any) { console.error('语音转文字失败:', error) throw error } } // 导出模拟服务实例 export const mockApiService = MockApiService.getInstance()