From 4dbbb57aa58b538a6f33f6616dc37d6d59e6f29a Mon Sep 17 00:00:00 2001 From: scout <1134087124@qq.com> Date: Fri, 29 Dec 2023 11:53:55 +0800 Subject: [PATCH] fixbug --- .hbuilderx/launch.json | 29 +- pages/index/index.vue | 509 ++++++++++++++---- static/image/V.png | Bin 0 -> 4980 bytes uni_modules/mumu-recorder/changelog.md | 4 + .../mumu-recorder/mumu-recorder.vue | 113 ++++ uni_modules/mumu-recorder/package.json | 87 +++ uni_modules/mumu-recorder/readme.md | 117 ++++ 7 files changed, 734 insertions(+), 125 deletions(-) create mode 100644 static/image/V.png create mode 100644 uni_modules/mumu-recorder/changelog.md create mode 100644 uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue create mode 100644 uni_modules/mumu-recorder/package.json create mode 100644 uni_modules/mumu-recorder/readme.md diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json index a1c56ae..4de0beb 100644 --- a/.hbuilderx/launch.json +++ b/.hbuilderx/launch.json @@ -1,27 +1,16 @@ { - // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/ - // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 - "version" : "0.0", + "version" : "1.0", "configurations" : [ - { - "app-plus" : { - "launchtype" : "local" - }, - "default" : { - "launchtype" : "local" - }, - "mp-weixin" : { - "launchtype" : "local" - }, - "type" : "uniCloud" - }, - { - "playground" : "custom", - "type" : "uni-app:app-android" - }, { "playground" : "custom", "type" : "uni-app:app-ios" - } + }, + { + "app-plus" : + { + "launchtype" : "local" + }, + "type" : "uniCloud" + } ] } diff --git a/pages/index/index.vue b/pages/index/index.vue index 5b5dadf..90797b3 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -1,31 +1,44 @@ @@ -158,19 +211,77 @@ import { TEMPERATURE, TOP_P, } from "utils/openAiConfig"; +import MumuRecorder from "@/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue"; export default { + components: { MumuRecorder }, data() { return { chatList: [], inputMsg: "", acqStatus: true, gptMode: "gpt-3.5-turbo", - isGPT3: true, fileList: [], + show: false, + gptModeColumns: [["GPT-3", "GPT-4", "GPT-V"]], + audio: null, + + isUseRecorder: false, + playItemIndex: -1, + isText: true, + currentAudio: "", }; }, + mounted() { + this.audio = document.createElement("audio"); + this.audio.addEventListener("ended", () => { + this.playItemIndex = -1; + this.currentAudio = ""; + }); + }, onLoad(item) {}, methods: { + // 开始录音 + startRecorder() { + // this.$refs.recorderRef.start(); + + this.isUseRecorder = true; + }, + // 结束录音 + endRecorder() { + // this.$refs.recorderRef.stop(); + this.isUseRecorder = false; + }, + // 录音成功 + handlerSuccess(res) { + if (res.duration < 1) + return uni.showToast({ + title: "语言时间小于1秒", + icon: "error", + }); + + console.log(res, 666); + }, + // 播放报错 + handlerError(code) { + switch (code) { + case "101": + uni.showModal({ + content: "当前浏览器版本较低,请更换浏览器使用,推荐在微信中打开。", + }); + break; + case "201": + uni.showModal({ + content: "麦克风权限被拒绝,请刷新页面后授权麦克风权限。", + }); + break; + default: + uni.showModal({ + content: "未知错误,请刷新页面重试", + }); + break; + } + }, + //发送文字信息 sendText() { this.$nextTick(() => { @@ -223,23 +334,26 @@ export default { // 自动滚动到底部 scrollToBottom() { this.$nextTick(() => { - uni - .createSelectorQuery() - .select(".chat-content") - .boundingClientRect((data) => { - uni.pageScrollTo({ - duration: 100, //过渡时间 - scrollTop: 1600, //到达目标class的top值 - }); - }) - .exec(); + let chatBox = document.getElementById("chat-content"); + chatBox.scrollTop = chatBox.scrollHeight; }); }, // 切换模式 changeMode(e) { + this.show = true; + }, + // 确认模式 + confirm(e) { + console.log(e, 666); + this.show = false; + this.gptMode = + e.value[0] == "GPT-3" + ? "gpt-3.5-turbo" + : e.value[0] == "GPT-4" + ? "gpt-4-1106-preview" + : "gpt-4-vision-preview"; this.acqStatus = true; - this.isGPT3 = !this.isGPT3; - this.gptMode = this.isGPT3 ? "gpt-3.5-turbo" : "gpt-4-1106-preview"; + this.fileList = []; // 清空对话 this.chatList = []; }, @@ -258,11 +372,10 @@ export default { const self = this; const currentResLocation = this.chatList.length - 1; // 获取当前环境地址 - const baseUrl = "http://114.218.158.24:9020/"; - const token = - "46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644e756eda7154e1af9e70d1c9d2f100823a26885ea6df3249fe619995cb79dc5dbd5ead32d43b955d6b3ce83129097bb21bb8169898f48692de4f966db140c71b85a2065acfc948561c465279fc05194a79a1115f3b00170944b6c4bd6c52ada909a075c55d18d76c2ed2175602421b34b27362a05c350733ed73382471df0a08950f7f1e812a610c17bdac82d82d54be38969f6b41201af79b8d36ef177c5b94b533b1600017241188832aaee0ff1844b2560f527e9f563e3c561bffc356ffe5777a3d2030a9579e443bb04a2b565d05f9d2d3d1efaefdb703ae0575f1542aeba992ba5ba7c2db5b5573509b172bc26aaf8c05b27bc981ec23f0873a801f42c51"; + const baseUrl = "https://erpapi.fontree.cn/"; + const token = ""; try { - await fetch(baseUrl + "chat/completion", { + await fetch(baseUrl + "chat/app-completion", { method: "POST", timeout: 10000, body: JSON.stringify({ @@ -326,13 +439,13 @@ export default { let role = []; if (chat.uid == "admin") { let my; - if (this.gptMode === "gpt-4-1106-preview-vision-preview") { + if (this.gptMode === "gpt-4-vision-preview") { if (chat.fileList.length > 0) { chat.fileList.forEach((item) => { if (item) { role.push({ type: "image_url", - image_url: item, + image_url: item.url, }); } }); @@ -362,37 +475,62 @@ export default { scrollToUpper() { console.log("滚动到顶部"); }, + // 上传接口 uploadFilePromise(url) { - return new Promise((resolve, reject) => { - const Authorization = uni.getStorageSync('token'); - let a = uni.uploadFile({ - url: 'http://114.218.158.24:9020/upload/img', - filePath: url, - name: 'file', - formData: { - source: 'gpt', - mask:'' + console.log(url, 123); + return new Promise((resolve, reject) => { + const Authorization = ""; + let a = uni.uploadFile({ + url: "https://erpapi.fontree.cn/upload/img", + filePath: url, + name: "file", + formData: { + source: "artwork", + type: "image", + }, + header: { + Authorization, + }, + success: (res) => { + resolve(JSON.parse(res.data).data.ori_url); }, - header: { - Authorization - }, - success: res => { - resolve(res.data); - this.fileList.push( - JSON.parse(res.data).data.ori_url - ); - console.log(this.fileList, 888); - - } - }); - }); - }, + }); + }); + }, + // 上传图片 async upLoaded(file, lists, name) { - this.uploadFilePromise(file.file.url) - }, + const item = file.file[0]; + this.fileList.push({ + ...item, + //提示上传中 + status: "uploading", + message: "上传中", + }); + let result = await this.uploadFilePromise(file.file[0].url); + this.fileList.splice( + 0, + 1, + Object.assign(item, { + status: "success", + message: "上传成功", + url: result, + }) + ); + }, + // 删除图片 + deleteFile(file, detail) { + this.fileList = []; + }, + // 刷新 + reLoad() { + location.reload(); + }, + // 切换语音和文字 + changeMic() { + this.isText = !this.isText; + }, }, }; - diff --git a/static/image/V.png b/static/image/V.png new file mode 100644 index 0000000000000000000000000000000000000000..5d11eacea8a1314a4c23ab7f904a998dbb248fd0 GIT binary patch literal 4980 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 + + + + + + diff --git a/uni_modules/mumu-recorder/package.json b/uni_modules/mumu-recorder/package.json new file mode 100644 index 0000000..00d5e90 --- /dev/null +++ b/uni_modules/mumu-recorder/package.json @@ -0,0 +1,87 @@ +{ + "id": "mumu-recorder", + "displayName": "h5录音组件,调用H5原生功能使用麦克风进行录音", + "version": "1.0.1", + "description": "演示案例中模仿了微信的长按发送语音,与普通录音demo。", + "keywords": [ + "录音", + "麦克风", + "模仿微信" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "麦克风" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "n", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "n", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u", + "小红书": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/mumu-recorder/readme.md b/uni_modules/mumu-recorder/readme.md new file mode 100644 index 0000000..1f888e5 --- /dev/null +++ b/uni_modules/mumu-recorder/readme.md @@ -0,0 +1,117 @@ +## 插件简绍 + +### 实现原理 + +> 通过 navigator.mediaDevices.getUserMedia(需要https环境) 这个api调用麦克风,获取到到音频流数据。 +> +> 通过 MediaRecorder 这个构造函数对音频流进行接收,完成录制后会返回一个存储`Blob`内容的录制数据。 + + +### 使用环境 + +需要https环境才能使用,本地测试可以在 manifest.json 中点击源码展示,找到h5 ,添加:"devServer" : { "https" : true} + +**请勿使用 UC浏览器 与 夸克等阿里旗下的浏览器,发现他们使用的内核都较低,无法正常获取音频流,并且都有对接音频流截取的插件,导致无法正常获取音频流的数据。在微信中可以正常使用,推荐在微信内打开演示案例 ** + +需要https环境才能使用!!! + +需要https环境才能使用!!! + +需要https环境才能使用!!! + +### 插件使用 + +**插件已支持 uni_modules 支持组件easycom,以下代码演示的是普通使用** + +``` html + + + + + {{!status?'开始录音':'结束录音'}} + + + +``` + +``` javascript +// js + import MumuRecorder from '@/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue' + export default { + components: { MumuRecorder }, + data() { + return { + status: false, + recorder: null + } + }, + onLoad() { + + }, + methods: { + handlerSave() { + let tag = document.createElement('a') + tag.href = this.recorder.localUrl + tag.download = '录音' + tag.click() + }, + handlerOnCahnger() { + if (this.status) { + this.$refs.recorder.stop() + } else { + this.$refs.recorder.start() + } + this.status = !this.status + }, + handlerSuccess(res) { + console.log(res) + this.recorder = res + }, + handlerError(code) { + switch (code) { + case '101': + uni.showModal({ + content: '当前浏览器版本较低,请更换浏览器使用,推荐在微信中打开。' + }) + break; + case '201': + uni.showModal({ + content: '麦克风权限被拒绝,请刷新页面后授权麦克风权限。' + }) + break + default: + uni.showModal({ + content: '未知错误,请刷新页面重试' + }) + break + } + } + } + } +``` + +### 相关API + +##### 组件内部方法($refs 调用) + +| 方法名 | 说明 | 参数 | +| ------ | -------- | ---- | +| start | 开始录音 | 无 | +| stop | 结束录音 | 无 | + + + +##### 事件(Events) + +| 事件名 | 说明 | 回调参数 | +| ------- | -------------------- | ------------------------------------------------------------ | +| success | 停止录音后调用此事件 | 返回录音数据,是一个对象
{ data: 音频的 blob 数据,上传请使用这个
duration: 当前音频长度
localUrl: 当前音频的本地链接,可直接通过 audio 标签进行播放 } | +| error | 组件内部发生错误 | 错误码:<100 当前不是https环境> <101 浏览器不支持> <201 麦克风权限被拒绝> <500 未知错误> | + +### 案例演示 + +![enter description here](https://h5plugin.mumudev.top/public/recorder/qrcode.png) + +## 支持作者 + +![支持作者](https://student.mumudev.top/wxMP.jpg) \ No newline at end of file