整体修改
parent
cc29d195ce
commit
11a5eb5b65
@ -0,0 +1,2 @@
|
||||
unpackage/*
|
||||
.hbuilderx
|
||||
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<view class="chat">
|
||||
<view
|
||||
v-for="m in messages"
|
||||
:key="m.id"
|
||||
:id="'msg-' + m.id"
|
||||
:class="['msg', m.role]"
|
||||
>
|
||||
<view v-if="m.role === 'user'" class="bubble user-bubble">
|
||||
<text v-if="m.inputType === 'text'">{{ m.content }}</text>
|
||||
<view
|
||||
class="text-voice"
|
||||
v-if="m.inputType === 'voice'"
|
||||
@tap="playVoice(m)"
|
||||
>
|
||||
<text>{{ m.duration }}</text>
|
||||
<image
|
||||
class="voice-play"
|
||||
src="@/static/voice-play.png"
|
||||
mode="widthFix"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="bubble ai-bubble">
|
||||
<view v-if="m.type === 'card'" class="ai-card">
|
||||
<view class="ai-card-title">{{ m.title }}</view>
|
||||
<view class="ai-card-body">{{ m.content }}</view>
|
||||
</view>
|
||||
<view v-else-if="m.loading" class="ai-loading">
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
<view class="loading-dot"></view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<text>{{
|
||||
m.displayText !== undefined ? m.displayText : m.content
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
messages: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
playVoice(voicePath) {
|
||||
console.log('voicePath',voicePath);
|
||||
// if (!voicePath) {
|
||||
// uni.showToast({
|
||||
// title: "无可播放的语音",
|
||||
// icon: "none",
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// if (!this.innerAudioContext) {
|
||||
// this.innerAudioContext = uni.createInnerAudioContext();
|
||||
// this.innerAudioContext.autoplay = false;
|
||||
// this.innerAudioContext.onError(() => {
|
||||
// uni.showToast({
|
||||
// title: "播放失败",
|
||||
// icon: "none",
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// try {
|
||||
// this.innerAudioContext.stop();
|
||||
// } catch (e) {}
|
||||
// this.innerAudioContext.src = voicePath;
|
||||
// this.innerAudioContext.play();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chat {
|
||||
margin: 6px 0 12px;
|
||||
}
|
||||
|
||||
.msg {
|
||||
/* margin: 10px 0; */
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.msg.user {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
max-width: 80%;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.user-bubble {
|
||||
background: #4e7bff;
|
||||
color: #fff;
|
||||
border-bottom-right-radius: 4px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.ai-bubble {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border-bottom-left-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.listen-btn {
|
||||
margin-left: 8px;
|
||||
color: #6b7280;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ai-card-title {
|
||||
color: #5f6fff;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.ai-card-body {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* loading animation */
|
||||
.ai-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.loading-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #9ca3af;
|
||||
animation: loading-bounce 1.5s ease-in-out infinite both;
|
||||
}
|
||||
|
||||
.loading-dot:nth-child(1) {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.loading-dot:nth-child(2) {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@keyframes loading-bounce {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale(1.2);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.text-voice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.voice-play {
|
||||
width: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<uni-nav-bar left-icon="left" title="AI对话" @clickLeft="clickLeft" @clickRight="onSettingTap">
|
||||
<template v-slot:left>
|
||||
<view class="hamburger">
|
||||
<view class="line" />
|
||||
<view class="line" />
|
||||
<view class="line" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<view class="nav-right">
|
||||
<image
|
||||
src="@/static/set.png"
|
||||
mode="widthFix"
|
||||
style="width: 18px"
|
||||
></image>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods : {
|
||||
clickLeft(){
|
||||
this.$emit('clickLeft')
|
||||
},
|
||||
onSettingTap() {
|
||||
uni.navigateTo({
|
||||
url: "/pages/setting/index",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.hamburger .line {
|
||||
height: 2px;
|
||||
background: #333;
|
||||
margin: 3px 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,35 @@
|
||||
|
||||
.overflow-one {
|
||||
white-space: nowrap;
|
||||
/* 不换行 */
|
||||
overflow: hidden;
|
||||
/* 隐藏超出部分 */
|
||||
text-overflow: ellipsis;
|
||||
/* 显示省略号 */
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.text-container {
|
||||
white-space: pre-wrap;
|
||||
/* 保留空白符号,但是进行换行 */
|
||||
overflow: hidden;
|
||||
/* 隐藏溢出的内容 */
|
||||
text-overflow: ellipsis;
|
||||
/* 剪切溢出的内容 */
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
|
||||
}
|
||||
|
||||
.align-center{
|
||||
display: flex;align-items: center;
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
var isReady=false;var onReadyCallbacks=[];
|
||||
var isServiceReady=false;var onServiceReadyCallbacks=[];
|
||||
var __uniConfig = {"pages":["pages/index/index","pages/setting/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"萃星智能AI","compilerVersion":"4.76","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}};
|
||||
var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom"}},{"path":"/pages/setting/index","meta":{},"window":{"navigationStyle":"custom"}}];
|
||||
var __uniConfig = {"pages":["pages/index/index","pages/setting/index"],"window":{"navigationBarTextStyle":"black","navigationBarTitleText":"uni-app","navigationBarBackgroundColor":"#F8F8F8","backgroundColor":"#F8F8F8"},"darkmode":false,"nvueCompiler":"uni-app","nvueStyleCompiler":"uni-app","renderer":"auto","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":false},"appname":"萃星智能AI","compilerVersion":"4.29","entryPagePath":"pages/index/index","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000}};
|
||||
var __uniRoutes = [{"path":"/pages/index/index","meta":{"isQuit":true},"window":{"navigationStyle":"custom","titleNView":false,"softinputMode":"adjustResize"}},{"path":"/pages/setting/index","meta":{},"window":{"navigationStyle":"custom"}}];
|
||||
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
|
||||
__uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
|
||||
service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:Math.round(f/20)})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:void 0,window:void 0,document:void 0,frames:void 0,self:void 0,location:void 0,navigator:void 0,localStorage:void 0,history:void 0,Caches:void 0,screen:void 0,alert:void 0,confirm:void 0,prompt:void 0,fetch:void 0,XMLHttpRequest:void 0,WebSocket:void 0,webkit:void 0,print:void 0}}}});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"萃星智能AI","version":{"name":"1.0.1","code":100},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"Record":{},"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"target":"id:1","autoclose":true,"waiting":true,"delay":0},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"distribute":{"icons":{"android":{"hdpi":"unpackage/res/icons/72x72.png","xhdpi":"unpackage/res/icons/96x96.png","xxhdpi":"unpackage/res/icons/144x144.png","xxxhdpi":"unpackage/res/icons/192x192.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"}}},"google":{"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"abiFilters":["armeabi-v7a","arm64-v8a","x86"]},"apple":{"dSYMs":false},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}}},"uniStatistics":{"enable":false},"arguments":"{\"name\":\"\",\"path\":\"\",\"query\":\"\",\"id\":0}","allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.76","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html"}}
|
||||
{"@platforms":["android","iPhone","iPad"],"id":"__UNI__5BDEDB4","name":"萃星智能AI","version":{"name":"1.0.1","code":100},"description":"","launch_path":"__uniappview.html","developer":{"name":"","email":"","url":""},"permissions":{"Record":{},"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"target":"id:1","autoclose":true,"waiting":true,"delay":0},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F8F8F8"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"compatible":{"ignoreVersion":true},"distribute":{"icons":{"android":{"hdpi":"unpackage/res/icons/72x72.png","xhdpi":"unpackage/res/icons/96x96.png","xxhdpi":"unpackage/res/icons/144x144.png","xxxhdpi":"unpackage/res/icons/192x192.png"},"ios":{"appstore":"unpackage/res/icons/1024x1024.png","ipad":{"app":"unpackage/res/icons/76x76.png","app@2x":"unpackage/res/icons/152x152.png","notification":"unpackage/res/icons/20x20.png","notification@2x":"unpackage/res/icons/40x40.png","proapp@2x":"unpackage/res/icons/167x167.png","settings":"unpackage/res/icons/29x29.png","settings@2x":"unpackage/res/icons/58x58.png","spotlight":"unpackage/res/icons/40x40.png","spotlight@2x":"unpackage/res/icons/80x80.png"},"iphone":{"app@2x":"unpackage/res/icons/120x120.png","app@3x":"unpackage/res/icons/180x180.png","notification@2x":"unpackage/res/icons/40x40.png","notification@3x":"unpackage/res/icons/60x60.png","settings@2x":"unpackage/res/icons/58x58.png","settings@3x":"unpackage/res/icons/87x87.png","spotlight@2x":"unpackage/res/icons/80x80.png","spotlight@3x":"unpackage/res/icons/120x120.png"}}},"google":{"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"],"abiFilters":["armeabi-v7a","arm64-v8a","x86"]},"apple":{"dSYMs":false},"plugins":{"ad":{},"audio":{"mp3":{"description":"Android平台录音支持MP3格式文件"}}}},"uniStatistics":{"enable":false},"arguments":"{\"name\":\"\",\"path\":\"\",\"query\":\"\",\"id\":0}","allowsInlineMediaPlayback":true,"uni-app":{"compilerVersion":"4.29","control":"uni-v3","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal"},"launch_path":"__uniappview.html"}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,53 @@
|
||||
import config from "@/config";
|
||||
export const recognizeAudio = async (tempFilePath) => {
|
||||
try {
|
||||
const fileInfo = await new Promise((resolve, reject) => {
|
||||
uni.getFileInfo({
|
||||
filePath: tempFilePath,
|
||||
success: resolve,
|
||||
fail: reject,
|
||||
});
|
||||
});
|
||||
const uploadRes = await new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `http://192.168.1.18:9022/recognize_speech`,
|
||||
filePath: tempFilePath,
|
||||
name: "speech",
|
||||
formData: {
|
||||
format: "amr",
|
||||
rate: 16000,
|
||||
channel: 1,
|
||||
cuid: "uniapp_user",
|
||||
audio_len: fileInfo.size,
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
try {
|
||||
const data = JSON.parse(res.data);
|
||||
resolve({ statusCode: 200, data });
|
||||
} catch (e) {
|
||||
reject(new Error("响应解析失败: " + e.message));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`上传失败: ${res.statusCode}`));
|
||||
}
|
||||
},
|
||||
fail: (err) => reject(new Error("上传请求失败: " + err.errMsg)),
|
||||
});
|
||||
});
|
||||
|
||||
const result = uploadRes.data;
|
||||
if (result.status === "success") {
|
||||
return result.result;
|
||||
} else {
|
||||
throw new Error(result.error || "识别失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("语音识别错误:", error);
|
||||
uni.showToast({
|
||||
title: "识别失败: " + (error.message || "网络错误"),
|
||||
icon: "none",
|
||||
});
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue