diff --git a/src/components/HeaderTitle.vue b/src/components/HeaderTitle.vue
index 4ae827b..e144d14 100644
--- a/src/components/HeaderTitle.vue
+++ b/src/components/HeaderTitle.vue
@@ -21,7 +21,7 @@
diff --git a/src/stores/modules/userInfo.ts b/src/stores/modules/userInfo.ts
index b8d3198..9af438d 100644
--- a/src/stores/modules/userInfo.ts
+++ b/src/stores/modules/userInfo.ts
@@ -1,26 +1,42 @@
// 每一个存储的模块,命名规则use开头,store结尾
import { defineStore } from 'pinia'
-export const useUserInfoStore = defineStore({
- id: 'userInfo', // 必须指明唯一的pinia仓库的id
- state: () => {
- return {
- num: 0,
- name: '张三',
- token: ''
- }
- },
- getters: {
- doubleCount: (state) => state.num * 2
- },
- actions: {
- changeNum() {
- this.num++
- },
- loginOut() {
- // 处理退出登录的一些逻辑
- return new Promise((rez) => {
- rez('111')
- })
- }
+import { ref, computed } from 'vue'
+
+export const useUserInfoStore = defineStore('userInfo', () => {
+ // state
+ const num = ref(0)
+ const name = ref('张三')
+ const token = ref('')
+
+ // getters
+ const getUserInfo = computed(() => ({
+ num: num.value,
+ name: name.value,
+ token: token.value
+ }))
+
+ // actions
+ const setUserInfo = (data: any) => {
+ name.value = data.name
+ token.value = data.token
+ }
+
+ const loginOut = () => {
+ // 处理退出登录的一些逻辑
+ return new Promise((rez) => {
+ rez('111')
+ })
+ }
+
+ return {
+ // state
+ num,
+ name,
+ token,
+ // getters
+ getUserInfo,
+ // actions
+ setUserInfo,
+ loginOut
}
})
diff --git a/src/utils/audioUtils.ts b/src/utils/audioUtils.ts
new file mode 100644
index 0000000..2028469
--- /dev/null
+++ b/src/utils/audioUtils.ts
@@ -0,0 +1,231 @@
+/**
+ * 音频处理工具函数
+ * 为后续集成第三方TTS方案做准备
+ */
+
+// 音频文件类型定义
+export interface AudioFile {
+ blob: Blob
+ name: string
+ size: number
+ type: string
+ duration?: number
+}
+
+// 音频格式转换选项
+export interface AudioConvertOptions {
+ format: 'webm' | 'mp3' | 'wav' | 'ogg'
+ quality?: number
+ bitrate?: number
+}
+
+/**
+ * 将Blob转换为指定格式的音频文件
+ * @param audioBlob 原始音频Blob
+ * @param options 转换选项
+ * @returns Promise 转换后的音频Blob
+ */
+export const convertAudioFormat = async (
+ audioBlob: Blob,
+ options: AudioConvertOptions
+): Promise => {
+ return new Promise((resolve, reject) => {
+ try {
+ const audio = new Audio()
+ const url = URL.createObjectURL(audioBlob)
+
+ audio.onloadedmetadata = () => {
+ // 这里可以添加格式转换逻辑
+ // 目前直接返回原始Blob,实际项目中可以使用Web Audio API或第三方库
+ URL.revokeObjectURL(url)
+ resolve(audioBlob)
+ }
+
+ audio.onerror = () => {
+ URL.revokeObjectURL(url)
+ reject(new Error('音频加载失败'))
+ }
+
+ audio.src = url
+ } catch (error) {
+ reject(error)
+ }
+ })
+}
+
+/**
+ * 获取音频文件信息
+ * @param audioBlob 音频Blob
+ * @returns Promise 音频文件信息
+ */
+export const getAudioFileInfo = async (audioBlob: Blob): Promise => {
+ return new Promise((resolve, reject) => {
+ const audio = new Audio()
+ const url = URL.createObjectURL(audioBlob)
+
+ audio.onloadedmetadata = () => {
+ const audioFile: AudioFile = {
+ blob: audioBlob,
+ name: `audio-${Date.now()}.webm`,
+ size: audioBlob.size,
+ type: audioBlob.type,
+ duration: audio.duration
+ }
+
+ URL.revokeObjectURL(url)
+ resolve(audioFile)
+ }
+
+ audio.onerror = () => {
+ URL.revokeObjectURL(url)
+ reject(new Error('无法获取音频信息'))
+ }
+
+ audio.src = url
+ })
+}
+
+/**
+ * 压缩音频文件
+ * @param audioBlob 原始音频Blob
+ * @param quality 压缩质量 (0-1)
+ * @returns Promise 压缩后的音频Blob
+ */
+export const compressAudio = async (
+ audioBlob: Blob,
+ quality: number = 0.8
+): Promise => {
+ // 这里可以实现音频压缩逻辑
+ // 目前直接返回原始Blob,实际项目中可以使用Web Audio API
+ return audioBlob
+}
+
+/**
+ * 上传音频文件到服务器
+ * @param audioFile 音频文件
+ * @param uploadUrl 上传地址
+ * @returns Promise 服务器返回的文件ID或URL
+ */
+export const uploadAudioFile = async (
+ audioFile: AudioFile,
+ uploadUrl: string
+): Promise => {
+ const formData = new FormData()
+ formData.append('audio', audioFile.blob, audioFile.name)
+ formData.append('duration', audioFile.duration?.toString() || '0')
+
+ try {
+ const response = await fetch(uploadUrl, {
+ method: 'POST',
+ body: formData
+ })
+
+ if (!response.ok) {
+ throw new Error(`上传失败: ${response.statusText}`)
+ }
+
+ const result = await response.json()
+ return result.fileId || result.url
+ } catch (error) {
+ console.error('音频上传失败:', error)
+ throw error
+ }
+}
+
+/**
+ * 为第三方TTS服务准备音频数据
+ * @param audioBlob 音频Blob
+ * @param serviceType TTS服务类型
+ * @returns Promise 准备好的音频数据
+ */
+export const prepareAudioForTTS = async (
+ audioBlob: Blob,
+ serviceType: 'openai' | 'azure' | 'aws' | 'google'
+): Promise => {
+ const audioFile = await getAudioFileInfo(audioBlob)
+
+ switch (serviceType) {
+ case 'openai':
+ return {
+ file: audioFile.blob,
+ model: 'whisper-1',
+ language: 'zh',
+ response_format: 'json'
+ }
+
+ case 'azure':
+ return {
+ audio: audioFile.blob,
+ language: 'zh-CN',
+ format: 'json'
+ }
+
+ case 'aws':
+ return {
+ Audio: audioFile.blob,
+ LanguageCode: 'zh-CN',
+ MediaFormat: 'webm'
+ }
+
+ case 'google':
+ return {
+ audio: {
+ content: await blobToBase64(audioFile.blob)
+ },
+ config: {
+ encoding: 'WEBM_OPUS',
+ languageCode: 'zh-CN',
+ sampleRateHertz: 16000
+ }
+ }
+
+ default:
+ throw new Error(`不支持的TTS服务类型: ${serviceType}`)
+ }
+}
+
+/**
+ * 将Blob转换为Base64字符串
+ * @param blob Blob对象
+ * @returns Promise Base64字符串
+ */
+export const blobToBase64 = (blob: Blob): Promise => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onload = () => resolve(reader.result as string)
+ reader.onerror = reject
+ reader.readAsDataURL(blob)
+ })
+}
+
+/**
+ * 验证音频文件格式
+ * @param blob 音频Blob
+ * @returns boolean 是否为有效的音频格式
+ */
+export const validateAudioFormat = (blob: Blob): boolean => {
+ const validTypes = [
+ 'audio/webm',
+ 'audio/mp3',
+ 'audio/wav',
+ 'audio/ogg',
+ 'audio/mpeg'
+ ]
+
+ return validTypes.includes(blob.type)
+}
+
+/**
+ * 获取音频录制权限
+ * @returns Promise 是否获得权限
+ */
+export const requestAudioPermission = async (): Promise => {
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
+ stream.getTracks().forEach(track => track.stop())
+ return true
+ } catch (error) {
+ console.error('获取音频权限失败:', error)
+ return false
+ }
+}
diff --git a/src/views/asistant/components/AudioRecorder.vue b/src/views/asistant/components/AudioRecorder.vue
new file mode 100644
index 0000000..02f15ae
--- /dev/null
+++ b/src/views/asistant/components/AudioRecorder.vue
@@ -0,0 +1,557 @@
+
+
+
+
+
+
+
+ 正在录制...
+ 录制完成
+
+
+ {{ formatTime(recordingTime) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ error }}
+
+
+
+
+
+
+
diff --git a/src/views/asistant/components/InputArea.vue b/src/views/asistant/components/InputArea.vue
index 331045d..446bbdd 100644
--- a/src/views/asistant/components/InputArea.vue
+++ b/src/views/asistant/components/InputArea.vue
@@ -11,16 +11,13 @@