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 0000000..5d11eac Binary files /dev/null and b/static/image/V.png differ diff --git a/uni_modules/mumu-recorder/changelog.md b/uni_modules/mumu-recorder/changelog.md new file mode 100644 index 0000000..eb2c332 --- /dev/null +++ b/uni_modules/mumu-recorder/changelog.md @@ -0,0 +1,4 @@ +## 1.0.1(2022-06-11) +修复苹果手机在微信中无法获取音频长度问题 +## 1.0.0(2022-06-10) +版本上线 diff --git a/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue b/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue new file mode 100644 index 0000000..b890c7d --- /dev/null +++ b/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue @@ -0,0 +1,113 @@ + + + + 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