diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index 86d7e8061..40bb53689 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -1348,6 +1348,55 @@ class DialogController extends AbstractController } } + /** + * @api {post} api/dialog/msg/convertrecord 25. 录音转文字 + * + * @apiDescription 需要token身份 + * @apiVersion 1.0.0 + * @apiGroup dialog + * @apiName msg__convertrecord + * + * @apiParam {Number} dialog_id 对话ID + * @apiParam {String} base64 语音base64 + * @apiParam {Number} duration 语音时长(毫秒) + * + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function msg__convertrecord() + { + $user = User::auth(); + $user->checkChatInformation(); + // + $dialog_id = intval(Request::input('dialog_id')); + // + WebSocketDialog::checkDialog($dialog_id); + // + $path = "uploads/tmp/chat/" . date("Ym") . "/" . $dialog_id . "/"; + $base64 = Request::input('base64'); + $duration = intval(Request::input('duration')); + if ($duration < 600) { + return Base::retError('说话时间太短'); + } + $data = Base::record64save([ + "base64" => $base64, + "path" => $path, + ]); + if (Base::isError($data)) { + return Base::retError($data['msg']); + } + $recordData = $data['data']; + $res = Extranet::openAItranscriptions($recordData['file']); + if (Base::isError($res)) { + return $res; + } + if (strlen($res['data']) < 1) { + return Base::retError('转文字失败'); + } + return $res; + } + /** * @api {post} api/dialog/msg/sendfile 26. 文件上传 * diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue index 069436a21..c9b82675d 100755 --- a/resources/assets/js/pages/manage/components/ChatInput/index.vue +++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue @@ -188,15 +188,53 @@ v-transfer-dom :data-transfer="true" class="chat-input-record-transfer" - :class="{cancel: touchLimitY}" + :class="recordClassName" :style="recordTransferStyle" @click="stopRecord">
{{recordFormatDuration}}
-
{{$L(touchLimitY ? '松开取消' : '向上滑动取消')}}
+
{{$L(recordFormatTip)}}
+ + +
+
+
+ +
+ +
+
+
+ + 0 ? (this.cacheDialogs.find(({id}) => id == this.dialogId) || {}) : {}; }, @@ -1140,7 +1202,7 @@ export default { if (this.showMenu) { return; } - if (this.stopRecord(this.touchLimitY)) { + if (this.stopRecord(this.touchLimitY, this.touchLimitX)) { return; } if (this.touchLimitY || this.touchLimitX) { @@ -1222,7 +1284,7 @@ export default { } }, - stopRecord(isCancel) { + stopRecord(isCancel, isConvert = false) { switch (this.recordState) { case "ing": this.recordState = "stop"; @@ -1235,7 +1297,12 @@ export default { $A.messageWarning("说话时间太短") // 小于 600ms 不发送 } else { this.recordBlob = blob; - this.uploadRecord(duration); + this.recordDuration = duration; + if (isConvert === true) { + this.convertRecord(); + } else { + this.uploadRecord(); + } } }, (msg) => { this.recordRec.close(); @@ -1270,7 +1337,54 @@ export default { }) }, - uploadRecord(duration) { + convertRecord() { + if (this.recordBlob === null) { + this.recordConvertIng = false + return; + } + this.recordConvertResult = '' + this.recordConvertStatus = 0 + this.recordConvertIng = true + // + const reader = new FileReader(); + reader.onloadend = () => { + this.$store.dispatch("call", { + url: 'dialog/msg/convertrecord', + data: { + dialog_id: this.dialogId, + base64: reader.result, + duration: this.recordDuration, + }, + method: 'post', + }).then(({data}) => { + this.recordConvertStatus = data ? 1 : 2 + this.recordConvertResult = data || this.$L('转文字失败') + }).catch(({msg}) => { + this.recordConvertStatus = 2 + this.recordConvertResult = msg + }); + }; + reader.readAsDataURL(this.recordBlob); + }, + + convertSend(type) { + if (!this.recordConvertIng) { + return; + } + if (type === 'voice') { + this.uploadRecord(); + this.recordConvertIng = false + } else { + if (this.recordConvertStatus === 1) { + this.$emit('on-send', this.recordConvertResult) + this.recordConvertIng = false + } else if (this.recordConvertStatus === 2) { + this.convertRecord() + } + } + }, + + uploadRecord() { if (this.recordBlob === null) { return; } @@ -1279,7 +1393,7 @@ export default { this.$emit('on-record', { type: this.recordBlob.type, base64: reader.result, - duration, + duration: this.recordDuration, }) }; reader.readAsDataURL(this.recordBlob); diff --git a/resources/assets/sass/dark.scss b/resources/assets/sass/dark.scss index f1f3206bd..b9e9e9ab2 100644 --- a/resources/assets/sass/dark.scss +++ b/resources/assets/sass/dark.scss @@ -571,6 +571,7 @@ body.dark-mode-reverse { } .chat-input-record-transfer { + &.convert, &.cancel { color: #000000; } diff --git a/resources/assets/sass/pages/components/chat-input.scss b/resources/assets/sass/pages/components/chat-input.scss index a069e988f..1e715d42d 100755 --- a/resources/assets/sass/pages/components/chat-input.scss +++ b/resources/assets/sass/pages/components/chat-input.scss @@ -723,12 +723,122 @@ margin-top: 6px; opacity: 0.6; } + &.convert { + background-color: #2db7f5; + color: #ffffff; + } &.cancel { background-color: #ff6565; color: #ffffff; } } +.chat-input-convert-transfer { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + display: flex; + align-items: center; + justify-content: flex-end; + flex-direction: column; + background-color: rgba(255, 255, 255, 0.8); + .convert-box { + width: 100%; + max-width: 500px; + height: 50%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + .convert-content { + position: relative; + background-color: $primary-color; + color: #000000; + width: 88%; + padding: 18px; + border-radius: 14px; + transform: translateY(-50%); + &:before { + content: ""; + position: absolute; + bottom: -15px; + right: 12%; + transform: translateX(-50%); + border-width: 8px; + border-style: solid; + border-color: $primary-color transparent transparent transparent; + } + .convert-result { + .ivu-input { + font-size: 18px; + border: 0; + box-shadow: none; + background: transparent; + color: #000000; + border-radius: 0; + outline: none; + resize: none; + &::placeholder { + color: rgba(0, 0, 0, 0.7); + } + } + } + } + .convert-footer { + width: 88%; + display: flex; + justify-content: space-around; + margin-bottom: 64px; + > li { + flex-grow: 0; + flex-shrink: 0; + width: 76px; + height: 76px; + list-style: none; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + > i { + font-size: 18px; + &.voice { + transform: rotate(180deg); + } + &.send, + &.error { + font-size: 22px; + width: 100%; + height: 100%; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + color: #0a7600; + background: #000000; + font-weight: 600; + .common-loading { + width: 26px; + height: 26px; + } + } + &.error { + color: #ff0000; + font-size: 30px; + font-weight: 500; + } + } + > span { + font-size: 12px; + margin-top: 4px; + } + } + } + } +} + .chat-input-full-input { .ivu-modal { .ivu-modal-content {