添加新建对话功能,修复其他问题

main
xushilin 3 months ago
parent 2e88029c58
commit 761d4718a6

@ -1,116 +1,116 @@
{ {
"name": "萃星智能AI", "name" : "萃星智能AI",
"appid": "__UNI__5BDEDB4", "appid" : "__UNI__5BDEDB4",
"description": "", "description" : "",
"versionName": "1.0.1", "versionName" : "1.0.1",
"versionCode": 100, "versionCode" : 100,
"transformPx": false, "transformPx" : false,
/* 5+App */ /* 5+App */
"app-plus": { "app-plus" : {
"usingComponents": true, "usingComponents" : true,
"nvueStyleCompiler": "uni-app", "nvueStyleCompiler" : "uni-app",
"compilerVersion": 3, "compilerVersion" : 3,
"splashscreen": { "splashscreen" : {
"alwaysShowBeforeRender": true, "alwaysShowBeforeRender" : true,
"waiting": true, "waiting" : true,
"autoclose": true, "autoclose" : true,
"delay": 0 "delay" : 0
}, },
"compatible": { "compatible" : {
"ignoreVersion": true "ignoreVersion" : true
}, },
/* */ /* */
"modules": { "modules" : {
"Record": {} "Record" : {}
}, },
/* */ /* */
"distribute": { "distribute" : {
/* android */ /* android */
"android": { "android" : {
"permissions": [ "permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
], ],
"abiFilters": ["armeabi-v7a", "arm64-v8a", "x86"] "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
}, },
/* ios */ /* ios */
"ios": { "ios" : {
"dSYMs": false "dSYMs" : false
}, },
/* SDK */ /* SDK */
"sdkConfigs": { "sdkConfigs" : {
"ad": {} "ad" : {}
}, },
"icons": { "icons" : {
"android": { "android" : {
"hdpi": "unpackage/res/icons/72x72.png", "hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi": "unpackage/res/icons/96x96.png", "xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi": "unpackage/res/icons/144x144.png", "xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi": "unpackage/res/icons/192x192.png" "xxxhdpi" : "unpackage/res/icons/192x192.png"
}, },
"ios": { "ios" : {
"appstore": "unpackage/res/icons/1024x1024.png", "appstore" : "unpackage/res/icons/1024x1024.png",
"ipad": { "ipad" : {
"app": "unpackage/res/icons/76x76.png", "app" : "unpackage/res/icons/76x76.png",
"app@2x": "unpackage/res/icons/152x152.png", "app@2x" : "unpackage/res/icons/152x152.png",
"notification": "unpackage/res/icons/20x20.png", "notification" : "unpackage/res/icons/20x20.png",
"notification@2x": "unpackage/res/icons/40x40.png", "notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x": "unpackage/res/icons/167x167.png", "proapp@2x" : "unpackage/res/icons/167x167.png",
"settings": "unpackage/res/icons/29x29.png", "settings" : "unpackage/res/icons/29x29.png",
"settings@2x": "unpackage/res/icons/58x58.png", "settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight": "unpackage/res/icons/40x40.png", "spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x": "unpackage/res/icons/80x80.png" "spotlight@2x" : "unpackage/res/icons/80x80.png"
}, },
"iphone": { "iphone" : {
"app@2x": "unpackage/res/icons/120x120.png", "app@2x" : "unpackage/res/icons/120x120.png",
"app@3x": "unpackage/res/icons/180x180.png", "app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x": "unpackage/res/icons/40x40.png", "notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x": "unpackage/res/icons/60x60.png", "notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x": "unpackage/res/icons/58x58.png", "settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x": "unpackage/res/icons/87x87.png", "settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x": "unpackage/res/icons/80x80.png", "spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x": "unpackage/res/icons/120x120.png" "spotlight@3x" : "unpackage/res/icons/120x120.png"
} }
} }
} }
} }
}, },
/* */ /* */
"quickapp": {}, "quickapp" : {},
/* */ /* */
"mp-weixin": { "mp-weixin" : {
"appid": "wxb86917d1487922b9", "appid" : "wxb86917d1487922b9",
"setting": { "setting" : {
"urlCheck": false, "urlCheck" : false,
"postcss": true, "postcss" : true,
"minified": true "minified" : true
}, },
"usingComponents": true "usingComponents" : true
}, },
"mp-alipay": { "mp-alipay" : {
"usingComponents": true "usingComponents" : true
}, },
"mp-baidu": { "mp-baidu" : {
"usingComponents": true "usingComponents" : true
}, },
"mp-toutiao": { "mp-toutiao" : {
"usingComponents": true "usingComponents" : true
}, },
"uniStatistics": { "uniStatistics" : {
"enable": false "enable" : false
}, },
"vueVersion": "2" "vueVersion" : "2"
} }

@ -66,24 +66,6 @@
<view class="mark-layer" v-if="isOpenTextTool" @touchstart="closeTool"></view> <view class="mark-layer" v-if="isOpenTextTool" @touchstart="closeTool"></view>
<uni-popup ref="popup" type="bottom" class="popup" @change="changeShow">
<view class="feedback">
<view class="top">
<view class="title">反馈</view>
<view class="close" @tap="closeFeedback">×</view>
</view>
<view class="quick-ask">
<view :class="['ask',item.id === askActive ? 'active' : '']" v-for="item in quickAskList"
:key="item.id" @tap="selectAsk(item.id)">{{item.label}}</view>
</view>
<view>
<textarea class="textarea" placeholder="我们想知道你对此回答不满意的原因,你认为更好的回答是什么?"></textarea>
</view>
<button type="primary" style="font-size: 16px;" @tap="submitFeedback"></button>
</view>
</uni-popup>
<uni-popup ref="popup" type="bottom" class="popup" @change="changeShow"> <uni-popup ref="popup" type="bottom" class="popup" @change="changeShow">
<view class="feedback"> <view class="feedback">
<view class="top"> <view class="top">
@ -119,7 +101,7 @@
type: Boolean, type: Boolean,
default: false, default: false,
}, },
isPalyingVoice: { isPlayingVoice: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
@ -178,7 +160,7 @@
}, },
watch: { watch: {
isPalyingVoice(val) { isPlayingVoice(val) {
if (val) { if (val) {
this.voiceTimer = setInterval(() => { this.voiceTimer = setInterval(() => {
if (this.current === 2) { if (this.current === 2) {
@ -343,7 +325,6 @@
max-width: 80%; max-width: 80%;
padding: 10px 12px; padding: 10px 12px;
border-radius: 14px; border-radius: 14px;
font-size: 14px;
line-height: 1.5; line-height: 1.5;
} }

@ -1,11 +1,12 @@
<template> <template>
<view class="ai-page"> <view class="ai-page">
<page-meta :page-style="'overflow:' + (show ? 'hidden' : 'visible')"></page-meta> <page-meta :page-style="'overflow:' + (show ? 'hidden' : 'visible')"></page-meta>
<top @clickLeft="openDrawer"></top> <top @clickLeft="openDrawer" @resetMessage="resetMessage"></top>
<scroll-view class="content" :scroll-y="true" show-scrollbar="false" scroll-with-animation ref="scrollView"> <scroll-view class="content" :scroll-y="true" show-scrollbar="false" scroll-with-animation ref="scrollView">
<front @onSuggestionTap="onQuickAsk" /> <front @onSuggestionTap="onQuickAsk" />
<chat :messages="messages" @continueCreate="continueCreate" :isReplying="isReplying" @refresh="refresh" <chat :messages="messages" @continueCreate="continueCreate" :isReplying="isReplying" @refresh="refresh"
@changeShow="changeShow" @changeInputText="changeInputText" @handleVoice="handleVoice" :isPalyingVoice="isPalyingVoice" :playSrc="playSrc"/> @changeShow="changeShow" @changeInputText="changeInputText" @handleVoice="handleVoice"
:isPlayingVoice="isPlayingVoice" :playSrc="playSrc" />
</scroll-view> </scroll-view>
<view :style="{ height: marginBottom + 'px', backgroundColor: '#fff' }" /> <view :style="{ height: marginBottom + 'px', backgroundColor: '#fff' }" />
<leftDrawer :historyGroups="historyGroups" ref="popup" @changeShow="changeShow" <leftDrawer :historyGroups="historyGroups" ref="popup" @changeShow="changeShow"
@ -14,7 +15,7 @@
<search ref="searchRef" :inputText="inputText" @onSend="onSend" @onQuickAsk="onQuickAsk" <search ref="searchRef" :inputText="inputText" @onSend="onSend" @onQuickAsk="onQuickAsk"
@changeInputText="changeInputText" :isReplying="isReplying" @handleBreak="handleBreak" @changeInputText="changeInputText" :isReplying="isReplying" @handleBreak="handleBreak"
@changeShow="changeShow" /> @changeShow="changeShow" @startRecord="startRecord"/>
</view> </view>
</template> </template>
@ -56,11 +57,14 @@
replyData: {}, // replyData: {}, //
isRefresh: false, // isRefresh: false, //
audioContext: null, audioContext: null,
isPalyingVoice : false, // isPlayingVoice: false, //
playSrc : '' playSrc: '',
breakRequestList: [],
speechIdList: [],
textToVoiceLoading: false
}; };
}, },
async mounted() { async mounted() {
this.loadChatHistory(); this.loadChatHistory();
uni.onKeyboardHeightChange((res) => { uni.onKeyboardHeightChange((res) => {
uni.pageScrollTo({ uni.pageScrollTo({
@ -75,59 +79,66 @@
}); });
// #endif // #endif
this.marginBottom = 103; this.marginBottom = 103;
this.initAudio(); this.initAudio();
}, },
beforeDestroy() { beforeDestroy() {
// this.clearTypewriterTimers();
Object.values(this.typewriterTimers).forEach((timer) => {
if (timer) clearInterval(timer);
});
this.typewriterTimers = {};
}, },
methods: { methods: {
handleVoice(src){ //
if(this.isReplying){ startRecord(){
console.log('正在回复中'); if(this.isPlayingVoice && this.audioContext.src){
return; this.audioContext.stop();
this.isPlayingVoice = false;
} }
if(this.audioContext.src === src && this.isPalyingVoice){ },
this.isPalyingVoice = false; //
handleVoice(src) {
if (this.audioContext.src === src && this.isPlayingVoice) {
this.isPlayingVoice = false;
this.audioContext.stop(); this.audioContext.stop();
return; return;
}; };
if(this.audioContext.src === src && !this.isPalyingVoice){ if (this.audioContext.src === src && !this.isPlayingVoice) {
this.isPalyingVoice = true; this.isPlayingVoice = true;
this.audioContext.play(); this.audioContext.play();
return; return;
}; };
if(this.isPalyingVoice){ if (this.isPlayingVoice) {
this.audioContext.stop(); this.audioContext.stop();
}; };
this.isPalyingVoice = true; this.isPlayingVoice = true;
this.audioContext.src = src; this.audioContext.src = src;
this.playSrc = src; this.playSrc = src;
this.audioContext.play(); this.audioContext.play();
}, },
//
initAudio() { initAudio() {
this.audioContext = uni.createInnerAudioContext() this.audioContext = uni.createInnerAudioContext()
this.audioContext.onCanplay((e) => { this.audioContext.onCanplay((e) => {
console.log('src onCanplay',this.audioContext.src);
let items = this.messages.find(item => item.src && item.src === this.audioContext.src); let items = this.messages.find(item => item.src && item.src === this.audioContext.src);
if (!items) return;
items.duration = this.audioContext.duration; items.duration = this.audioContext.duration;
this.isPalyingVoice = true; // this.isPlayingVoice = true;
this.audioContext.play(); // this.audioContext.play()
}); });
this.audioContext.onEnded(res => { this.audioContext.onEnded(res => {
this.isPalyingVoice = false this.isPlayingVoice = false
// const platform = uni.getSystemInfoSync().uniPlatform; // const platform = uni.getSystemInfoSync().uniPlatform;
// if(platform === 'web') return; // if(platform === 'web') return;
// removeFile(this.audioContext.src) // removeFile(this.audioContext.src)
}) })
}, },
getSpeech(speechStr) { // arraybuff
getSpeech(speechStr) {
let self = this; let self = this;
return new Promise((resolve, reject) => { this.textToVoiceLoading = true;
let startTime = Date.now();
return new Promise((resolve) => {
textToSpeech(speechStr).then(audioData => { textToSpeech(speechStr).then(audioData => {
let endTime = Date.now();
console.log('语音合成耗时:', endTime - startTime, 'ms');
const platform = uni.getSystemInfoSync().uniPlatform; const platform = uni.getSystemInfoSync().uniPlatform;
// H5 // H5
if (platform === 'web') { if (platform === 'web') {
@ -136,8 +147,8 @@
}); });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
this.playSrc = url; this.playSrc = url;
console.log('赋值 h5');
this.audioContext.src = url; this.audioContext.src = url;
this.textToVoiceLoading = false;
resolve(true) resolve(true)
} }
// App // App
@ -146,9 +157,11 @@
const base64WithPrefix = `data:audio/mp3;base64,${base64Audio}`; const base64WithPrefix = `data:audio/mp3;base64,${base64Audio}`;
const fileName = `_doc/${Date.now()}_numberPerson.mp3`; const fileName = `_doc/${Date.now()}_numberPerson.mp3`;
base64ToFile(base64WithPrefix, fileName, (path) => { base64ToFile(base64WithPrefix, fileName, (path) => {
console.log('赋值 plus'); this.playSrc = path;
this.playSrc = path; self.textToVoiceLoading = false;
self.audioContext.src = path; self.audioContext.src = path;
let endTime2 = Date.now();
console.log('语音下载到手机耗时:', endTime2 - startTime, 'ms');
resolve(true) resolve(true)
}); });
} }
@ -156,10 +169,7 @@
resolve(true) resolve(true)
}) })
}) })
},
deleteSpeech() {
removeFile(this.audioContext.src)
}, },
// //
refresh() { refresh() {
@ -204,25 +214,53 @@
} }
this.breakReplying = true; this.breakReplying = true;
}, },
//
resetMessage() {
if (this.messages.length === 0) return;
if (this.isLoading) {
this.breakRequestList.push({
requestId: this.requestId
});
};
if (this.textToVoiceLoading) {
this.speechIdList.push({
speedId: this.speedId
})
};
if (this.isPlayingVoice) {
this.isPlayingVoice = false;
this.audioContext.stop();
}
this.clearTypewriterTimers();
this.isReplying = false;
this.messages = [];
},
//
clearTypewriterTimers() {
Object.values(this.typewriterTimers).forEach((timer) => {
if (timer) clearInterval(timer);
});
this.typewriterTimers = {};
},
// //
changeInputText(text) { changeInputText(text) {
this.inputText = text; this.inputText = text;
}, },
// top //
openDrawer() { openDrawer() {
this.$refs.popup.open(); this.$refs.popup.open();
}, },
// leftDrawer //
onHistoryItemTap(text) { onHistoryItemTap(text) {
this.inputText = text; this.inputText = text;
this.onSend(); this.onSend();
this.$refs.popup.close(); this.$refs.popup.close();
}, },
// leftDrawer //
changeShow(e) { changeShow(e) {
this.show = e; this.show = e;
}, },
// leftDrawer //
removeFromHistory(text) { removeFromHistory(text) {
let groups = uni.getStorageSync(HISTORY_KEY)?.groups || []; let groups = uni.getStorageSync(HISTORY_KEY)?.groups || [];
groups.forEach((group) => { groups.forEach((group) => {
@ -235,7 +273,7 @@
updatedAt: Date.now(), updatedAt: Date.now(),
}); });
}, },
// leftDrawer //
clearAllHistory() { clearAllHistory() {
uni.showModal({ uni.showModal({
title: "清除全部", title: "清除全部",
@ -252,7 +290,7 @@
}, },
}); });
}, },
// ==================== ====================
formatDate(date) { formatDate(date) {
const y = date.getFullYear(); const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0"); const m = String(date.getMonth() + 1).padStart(2, "0");
@ -337,24 +375,44 @@
this.isRefresh = false; this.isRefresh = false;
this.scrollToBottom(); this.scrollToBottom();
this.addToHistory(text); this.addToHistory(text);
if(this.isPalyingVoice){ if (this.isPlayingVoice) {
this.audioContext.stop(); this.audioContext.stop();
this.isPalyingVoice = false; this.isPlayingVoice = false;
} };
let requestId = Date.now();
this.requestId = requestId;
// 3. AI // 3. AI
const reply = await getAIResponse({ const reply = await getAIResponse({
message: text, message: text,
}); });
await this.getSpeech(reply); this.isLoading = false;
let requestIndex = this.breakRequestList.findIndex(item => item.requestId === requestId)
if (requestIndex > -1) {
this.breakRequestList = this.breakRequestList.splice(requestIndex, -1)
return;
}
this.replyData = reply; this.replyData = reply;
this.isLoading = false;
if (this.breakReplying) { if (this.breakReplying) {
this.breakReplying = false; this.breakReplying = false;
return; return;
} }
this.replyAction(reply) this.replyAction(reply)
}, },
replyAction(reply, isCreate) { async replyAction(reply, isCreate) {
if (!this.messages[this.messages.length - 1].src) {
let speechId = Date.now();
this.speechId = speechId;
const result = await this.getSpeech(reply);
let speechIndex = this.speechIdList.findIndex(item => item.speechId === speechId)
if (speechIndex > -1) {
this.speechIdList = this.speechIdList.splice(speechIndex, -1)
return;
}
if (result) {
this.isPlayingVoice = true;
this.audioContext.play();
};
};
let content = '' let content = ''
if (reply.errMsg) { if (reply.errMsg) {
content = `请求出错: ${reply.errMsg}` content = `请求出错: ${reply.errMsg}`
@ -366,7 +424,6 @@
if (loadingIdx > -1) this.messages.splice(loadingIdx, 1); if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);
// 5. + // 5. +
const replyId = this.baseId + 1; const replyId = this.baseId + 1;
console.log('添加');
if (!isCreate) { if (!isCreate) {
this.messages.push({ this.messages.push({
id: replyId, id: replyId,
@ -374,8 +431,8 @@
type: "text", type: "text",
content, content,
displayText: "", displayText: "",
src : JSON.parse(JSON.stringify(this.audioContext.src)), src: JSON.parse(JSON.stringify(this.audioContext.src)),
duration : null duration: null
}); });
} }
this.$nextTick(() => this.scrollToBottom()); this.$nextTick(() => this.scrollToBottom());
@ -402,8 +459,9 @@
this.isReplying = false; this.isReplying = false;
this.breakReplying = false this.breakReplying = false
this.isLoading = false; this.isLoading = false;
this.isPalyingVoice =false; this.isPlayingVoice = false;
this.audioContext.stop(); this.audioContext.stop();
this.scrollToBottom();
} }
if (index < fullText.length) { if (index < fullText.length) {
msg.displayText = fullText.substring(0, index + 1); msg.displayText = fullText.substring(0, index + 1);
@ -418,7 +476,7 @@
this.breakReplying = false; this.breakReplying = false;
this.$nextTick(() => { this.$nextTick(() => {
this.scrollToBottom(); this.scrollToBottom();
}); });
} }
}, speed); }, speed);
this.typewriterTimers[messageId] = timer; this.typewriterTimers[messageId] = timer;

@ -25,9 +25,13 @@
</view> </view>
</scroll-view> </scroll-view>
<view class="drawer-footer"> <view class="drawer-footer">
<view class="user-icon">👤</view> <view @tap="onSettingTap">
<text class="user-name">用户</text> <text class="user-icon">👤</text>
<view class="footer-gear" @tap="clearAllHistory"></view> <text class="user-name">用户</text>
</view>
<view class="footer-gear" @tap="clearAllHistory">
<uni-icons type="trash" size="25" />
</view>
</view> </view>
</view> </view>
</view> </view>
@ -57,7 +61,6 @@ export default {
onHistoryItemTap(text){ onHistoryItemTap(text){
this.$emit('onHistoryItemTap',text) this.$emit('onHistoryItemTap',text)
}, },
onLongPressHistory(text) { onLongPressHistory(text) {
uni.showModal({ uni.showModal({
title: "删除记录", title: "删除记录",
@ -80,6 +83,12 @@ export default {
}, },
clearAllHistory(){ clearAllHistory(){
this.$emit('clearAllHistory') this.$emit('clearAllHistory')
},
onSettingTap() {
uni.navigateTo({
url: "/pages/setting/index",
});
this.close();
} }
} }
}; };
@ -139,15 +148,11 @@ export default {
} }
.drawer-footer { .drawer-footer {
padding: 12px; padding: 12px 20px;
border-top: 1px solid #eeeeee; border-top: 1px solid #eeeeee;
display: flex; display: flex;
align-items: center; align-items: center;
} justify-content: space-between;
.drawer-footer {
/* fixed height for calc above */
height: 64px;
} }
.user-icon { .user-icon {

@ -18,7 +18,9 @@
<input class="input" confirm-type="send" v-model="inputTextValue" @confirm="onSend()" <input class="input" confirm-type="send" v-model="inputTextValue" @confirm="onSend()"
placeholder="你可以说…" placeholder-class="ph" /> placeholder="你可以说…" placeholder-class="ph" />
<view :class="['mic', { recording: isRecording }]" @touchstart.stop="onPressMic" <view :class="['mic', { recording: isRecording }]" @touchstart.stop="onPressMic"
@touchmove.stop="onMoveMic" @touchend.stop="onReleaseMic">🎙</view> @touchmove.stop="onMoveMic" @touchend.stop="onReleaseMic">
<image src="../../../static/mic.png" mode="widthFix"></image>
</view>
<!-- <button class="send" type="primary" @tap="onSend"></button> --> <!-- <button class="send" type="primary" @tap="onSend"></button> -->
<view <view
:class="['send', (!isReplying && inputTextValue && inputTextValue.trim()) ? 'normal' : 'disabled']"> :class="['send', (!isReplying && inputTextValue && inputTextValue.trim()) ? 'normal' : 'disabled']">
@ -29,12 +31,11 @@
</view> </view>
</view> </view>
</view> </view>
<view v-if="isRecording" class="record-mask"> <view v-if="isRecording" class="record-mask" >
<view class="record-box" :class="{ cancel: willCancel }"> <view class="record-box" :class="{ cancel: willCancel }">
<view class="record-icon">🎙</view>
<view class="record-text">{{ <view class="record-text">{{
willCancel ? "松开手指,取消发送" : "手指上滑,取消发送" willCancel ? "松开手指,取消发送" : "手指上滑,取消发送"
}}</view> }}</view>
</view> </view>
</view> </view>
@ -88,6 +89,9 @@
uni.createSelectorQuery().select(".dock").boundingClientRect((rect) => { uni.createSelectorQuery().select(".dock").boundingClientRect((rect) => {
self.searchHeight = Math.ceil(rect.height) self.searchHeight = Math.ceil(rect.height)
}).exec(); }).exec();
uni.createSelectorQuery().select(".record-box").boundingClientRect((rect) => {
console.log('rect',rect);
}).exec();
}, },
beforeDestroy() { beforeDestroy() {
if (this.recordSimTimer) { if (this.recordSimTimer) {
@ -128,11 +132,11 @@
}, },
dialogInputConfirm() { dialogInputConfirm() {
this.$emit('changeShow',false) this.$emit('changeShow',false)
if(!this.dialogText && !this.dialogText.trim()){ if(!this.dialogText || !this.dialogText.trim()){
uni.showToast({ // uni.showToast({
title: '内容不能为空', // title: '',
icon: 'none' // icon: 'none'
}) // })
return; return;
} }
let index = this.quickAskList.findIndex(item => item.quickAskText.trim() === this.dialogText.trim()); let index = this.quickAskList.findIndex(item => item.quickAskText.trim() === this.dialogText.trim());
@ -236,7 +240,8 @@
}) })
return return
} }
this.$emit('changeShow',true) this.$emit('changeShow',true);
this.$emit('startRecord')
this.ensureRecorder(); this.ensureRecorder();
this.isRecording = true; this.isRecording = true;
this.willCancel = false; this.willCancel = false;
@ -364,7 +369,7 @@
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 18px; border-radius: 18px;
background: #fff; /* background: #4F46E5; */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -403,7 +408,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 9999; z-index: 100005;
} }
.record-box { .record-box {
@ -414,7 +419,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
min-width: 220rpx; min-width: 220rpx;
} }
.record-text { .record-text {
@ -427,7 +432,7 @@
right: 0; right: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, .4);
z-index: 100004; z-index: 100004;
} }

@ -1,5 +1,5 @@
<template> <template>
<uni-nav-bar left-icon="left" title="AI对话" @clickLeft="clickLeft" @clickRight="onSettingTap"> <uni-nav-bar left-icon="left" title="AI对话" @clickLeft="clickLeft" @clickRight="addNewChat">
<template v-slot:left> <template v-slot:left>
<view class="hamburger"> <view class="hamburger">
<view class="line" /> <view class="line" />
@ -10,7 +10,7 @@
<template v-slot:right> <template v-slot:right>
<view class="nav-right"> <view class="nav-right">
<image <image
src="@/static/set.png" src="@/static/MapsUgcSharp.png"
mode="widthFix" mode="widthFix"
style="width: 18px" style="width: 18px"
></image> ></image>
@ -25,10 +25,8 @@ export default {
clickLeft(){ clickLeft(){
this.$emit('clickLeft') this.$emit('clickLeft')
}, },
onSettingTap() { addNewChat(){
uni.navigateTo({ this.$emit('resetMessage')
url: "/pages/setting/index",
});
} }
} }
}; };

@ -42,14 +42,14 @@
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view>
<view class="divider" /> <!-- <view class="divider" />
<view class="item" @tap="onItem('字体大小')"> <view class="item" @tap="onItem('字体大小')">
<view class="left"> <view class="left">
<view class="icon-wrap"><uni-icons type="help" size="20" color="#3b3f45" /></view> <view class="icon-wrap"><uni-icons type="help" size="20" color="#3b3f45" /></view>
<text class="text">字体大小</text> <text class="text">字体大小</text>
</view> </view>
<text class="arrow"></text> <text class="arrow"></text>
</view> </view> -->
</view> </view>
</view> </view>
@ -124,12 +124,9 @@
items : [{ items : [{
label : '文字回复', label : '文字回复',
value : '0' value : '0'
},{
label : '语音回复',
value : '1'
},{ },{
label : '文字 + 语音回复', label : '文字 + 语音回复',
value : '2' value : '1'
}] }]
} }
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -16,7 +16,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.text-container { .text-container {
white-space: pre-wrap; white-space: pre-wrap;
/* 保留空白符号,但是进行换行 */ /* 保留空白符号,但是进行换行 */
overflow: hidden; overflow: hidden;
@ -26,7 +26,7 @@
word-wrap: break-word; word-wrap: break-word;
word-break: break-all; word-break: break-all;
} }
.align-center{ .align-center{
display: flex;align-items: center; display: flex;align-items: center;
@ -35,5 +35,4 @@
::v-deep uni-toast, uni-modal{ ::v-deep uni-toast, uni-modal{
z-index: 100001; z-index: 100001;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,134 +0,0 @@
// base64.ts
export const Base64 = {
keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
const utf8Input = this.utf8Encode(input);
while (i < utf8Input.length) {
chr1 = utf8Input.charCodeAt(i);
chr2 = utf8Input.charCodeAt(i + 1);
chr3 = utf8Input.charCodeAt(i + 2);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output =
output +
this.keyStr.charAt(enc1) +
this.keyStr.charAt(enc2) +
this.keyStr.charAt(enc3) +
this.keyStr.charAt(enc4);
i += 3;
}
return output;
},
decode(input) {
let output = '';
let chr1;
let chr2;
let chr3;
let enc1;
let enc2;
let enc3;
let enc4;
let i = 0;
const base64Input = input.replace(/[^A-Za-z0-9+/=]/g, '');
while (i < base64Input.length) {
enc1 = this.keyStr.indexOf(base64Input.charAt(i));
enc2 = this.keyStr.indexOf(base64Input.charAt(i + 1));
enc3 = this.keyStr.indexOf(base64Input.charAt(i + 2));
enc4 = this.keyStr.indexOf(base64Input.charAt(i + 3));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output += String.fromCharCode(chr1);
if (enc3 !== 64) {
output += String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output += String.fromCharCode(chr3);
}
i += 4;
}
return this.utf8Decode(output);
},
utf8Encode(string) {
let utftext = '';
let c;
for (let n = 0; n < string.length; n += 1) {
c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
utf8Decode(utftext) {
let string = '';
let i = 0;
let c = 0;
let c1 = 0;
let c2 = 0;
// const c3 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i += 1;
} else if (c < 224) {
c1 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i + 1);
c2 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
};

@ -10,7 +10,7 @@ export const recognizeAudio = async (tempFilePath) => {
}); });
const uploadRes = await new Promise((resolve, reject) => { const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({ uni.uploadFile({
url: `http://192.168.1.25:9022/recognize_speech`, url: `http://106.227.91.181:9022/recognize_speech`,
filePath: tempFilePath, filePath: tempFilePath,
name: "speech", name: "speech",
formData: { formData: {

Loading…
Cancel
Save