|
@@ -179,8 +179,12 @@ function setBtnValue(val) {
|
|
|
sendMessage("text");
|
|
|
}
|
|
|
|
|
|
+const inputField = ref(null); // 文字輸入框
|
|
|
+
|
|
|
// 傳送訊息 (如 type="text" 代表為純文字訊息,不需語音回覆)
|
|
|
async function sendMessage(type = "") {
|
|
|
+ inputField;
|
|
|
+
|
|
|
if (userMessage.value === "") {
|
|
|
return;
|
|
|
}
|
|
@@ -199,6 +203,8 @@ async function sendMessage(type = "") {
|
|
|
author: "user",
|
|
|
});
|
|
|
|
|
|
+ inputField.value?.blur(); // 移除輸入框焦點
|
|
|
+
|
|
|
videoLoading.value = true;
|
|
|
let isVideoCache = await getVideoCache(message); // 判斷使用者問題是否有 Video Cache
|
|
|
|
|
@@ -356,6 +362,23 @@ function videoPlay() {
|
|
|
video.value.play();
|
|
|
}
|
|
|
|
|
|
+// 影片播放結束觸發
|
|
|
+const onVideoEnded = () => {
|
|
|
+ console.log("播放點頭影片");
|
|
|
+
|
|
|
+ // 清空音訊
|
|
|
+ if (currentAudio.value) {
|
|
|
+ currentAudio.value.pause();
|
|
|
+ currentAudio.value.currentTime = 0;
|
|
|
+ currentAudio.value = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 播放點頭影片
|
|
|
+ videoSrc.value = videoMuteSources.value;
|
|
|
+ videoPlay();
|
|
|
+ isVideoPause.value = true;
|
|
|
+};
|
|
|
+
|
|
|
// 底部選單
|
|
|
const menu = ref(null);
|
|
|
const menuHeight = ref(0);
|
|
@@ -381,6 +404,8 @@ const updateMenuHeight = () => {
|
|
|
if (menu.value) {
|
|
|
menuHeight.value = menu.value.clientHeight;
|
|
|
chatLoading.value = false;
|
|
|
+
|
|
|
+ console.log("menuHeight.value", menuHeight.value);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
@@ -445,6 +470,8 @@ function chooseLang(lang) {
|
|
|
sources = videoSources.value;
|
|
|
} else if (language === "en-us") {
|
|
|
sources = videoSourcesEn.value;
|
|
|
+ } else if (language === "ja-jp") {
|
|
|
+ sources = videoSourcesJp.value;
|
|
|
} else {
|
|
|
sources = videoSources.value;
|
|
|
}
|
|
@@ -1256,7 +1283,7 @@ let locationList = reactive([
|
|
|
},
|
|
|
{
|
|
|
value: "101F排隊處",
|
|
|
- text: "101f_queue_area",
|
|
|
+ text: "101f_queue",
|
|
|
},
|
|
|
],
|
|
|
// navigation: [
|
|
@@ -1326,7 +1353,6 @@ let arVideoDialog = ref(false);
|
|
|
async function getArviews(route, text, type = "") {
|
|
|
let url;
|
|
|
let lang = getLang();
|
|
|
- console.log("text >>>", text);
|
|
|
|
|
|
if (type === "garden") {
|
|
|
console.log("route", route);
|
|
@@ -1442,6 +1468,7 @@ function assignMapImg(item) {
|
|
|
// 動態引入視頻文件
|
|
|
const videoSources = ref([]); // 開場白影片(中)
|
|
|
const videoSourcesEn = ref([]); // 開場白影片(英)
|
|
|
+const videoSourcesJp = ref([]); // 開場白影片(日)
|
|
|
const videoMuteSources = ref([]); // 點頭影片(靜音)
|
|
|
const videoSpeakSources = ref([]); // 動嘴型影片
|
|
|
|
|
@@ -1463,6 +1490,9 @@ const loadVideoSources = async () => {
|
|
|
// "https://cmm.ai/101-ai-chatbot-new/video/start_en_1.mp4",
|
|
|
"https://cmm.ai/101-ai-chatbot-new/video/start_en_2.mp4",
|
|
|
];
|
|
|
+ videoSourcesJp.value = [
|
|
|
+ "https://cmm.ai:9101/static/video_cache/others/final-tmp_2024-08-27_12:33:13.mp4",
|
|
|
+ ];
|
|
|
videoMuteSources.value = [
|
|
|
// "https://cmm.ai/101-ai-chatbot-new/video/mute_1.mp4",
|
|
|
"https://cmm.ai/101-ai-chatbot-new/video/mute_2.mp4",
|
|
@@ -1501,6 +1531,8 @@ async function selectCategory(value, index) {
|
|
|
sources = videoSources.value;
|
|
|
} else if (lang === "en") {
|
|
|
sources = videoSourcesEn.value;
|
|
|
+ } else if (lang === "jp") {
|
|
|
+ sources = videoSourcesJp.value;
|
|
|
}
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * sources.length);
|
|
@@ -1535,7 +1567,7 @@ async function selectCategory(value, index) {
|
|
|
// menuList[0][0].value = "叫出真人客服";
|
|
|
// }
|
|
|
else if (value === "附近有什麼") {
|
|
|
- window.open("https://cmm.ai/101-aiv1/#/brand-search", "_blank"); // 另開頁面
|
|
|
+ window.open("https://cmm.ai/101-aiv2/#/brand-search", "_blank"); // 另開頁面
|
|
|
} else if (value === "秘境花園觀景台") {
|
|
|
messages.value.push({
|
|
|
label: "text",
|
|
@@ -1745,18 +1777,18 @@ const menuList = reactive([
|
|
|
// text: "customer_show",
|
|
|
// value: "叫出真人客服",
|
|
|
// },
|
|
|
- { imgSrc: "素材-11.png", text: "what_around", value: "附近有什麼" },
|
|
|
- { imgSrc: "素材-06.png", text: "service_information", value: "服務資訊" },
|
|
|
- { imgSrc: "素材-07.png", text: "shopping_discounts", value: "購物及優惠" },
|
|
|
- ],
|
|
|
- [
|
|
|
{
|
|
|
imgSrc: "素材-08.png",
|
|
|
text: "observation_deck",
|
|
|
value: "秘境花園觀景台",
|
|
|
},
|
|
|
+ { imgSrc: "素材-07.png", text: "shopping_discounts", value: "購物及優惠" },
|
|
|
+ { imgSrc: "素材-06.png", text: "service_information", value: "服務資訊" },
|
|
|
+ ],
|
|
|
+ [
|
|
|
{ imgSrc: "素材-09.png", text: "food_souvenirs", value: "美食/伴手禮" },
|
|
|
{ imgSrc: "素材-10.png", text: "location_guide", value: "位置導引" },
|
|
|
+ { imgSrc: "素材-11.png", text: "what_around", value: "附近有什麼" },
|
|
|
],
|
|
|
]);
|
|
|
|
|
@@ -2092,6 +2124,17 @@ async function cutVideo() {
|
|
|
// 音訊結束後暫停影片播放
|
|
|
const onAudioEnded = () => {
|
|
|
video.value.pause();
|
|
|
+
|
|
|
+ // 清空音訊
|
|
|
+ if (currentAudio.value) {
|
|
|
+ currentAudio.value.pause();
|
|
|
+ currentAudio.value.currentTime = 0;
|
|
|
+ currentAudio.value = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 播放點頭影片
|
|
|
+ videoSrc.value = videoMuteSources.value;
|
|
|
+ videoPlay();
|
|
|
};
|
|
|
|
|
|
// 判斷音訊是否為播放狀態
|
|
@@ -2479,6 +2522,7 @@ async function messageNotInCache(question, answer) {
|
|
|
<!-- 語言選單 -->
|
|
|
<div class="lang-select">
|
|
|
<v-select
|
|
|
+ density="compact"
|
|
|
:label="`${t('select_language')}`"
|
|
|
:items="['中文', 'English', '日本語']"
|
|
|
variant="solo"
|
|
@@ -2486,9 +2530,8 @@ async function messageNotInCache(question, answer) {
|
|
|
></v-select>
|
|
|
</div>
|
|
|
|
|
|
- <video ref="video" preload playsinline>
|
|
|
+ <video ref="video" preload playsinline @ended="onVideoEnded">
|
|
|
<source :src="videoSrc" type="video/mp4" />
|
|
|
- <!-- <source src="../assets/video/start_1.mp4" type="video/mp4" /> -->
|
|
|
Your browser does not support the video tag.
|
|
|
</video>
|
|
|
|
|
@@ -2651,8 +2694,9 @@ async function messageNotInCache(question, answer) {
|
|
|
ref="chatArea"
|
|
|
class="chat-area"
|
|
|
:class="{ 'area-open': isRotate, 'hide-menu': hideMenu }"
|
|
|
- :style="{ paddingBottom: !hideMenu ? menuHeight + 20 + 'px' : '90px' }"
|
|
|
+ :style="{ paddingBottom: menuHeight + 20 + 'px' }"
|
|
|
>
|
|
|
+ <!-- :style="{ paddingBottom: !hideMenu ? menuHeight + 20 + 'px' : '90px' }" -->
|
|
|
<div v-for="message in messages" class="message-content">
|
|
|
<p
|
|
|
v-if="message.label === 'text'"
|
|
@@ -2765,7 +2809,7 @@ async function messageNotInCache(question, answer) {
|
|
|
</v-btn>
|
|
|
</template>
|
|
|
|
|
|
- <v-list style="max-height: 155px; overflow-y: auto">
|
|
|
+ <v-list style="max-height: 250px; overflow-y: auto">
|
|
|
<v-list-item
|
|
|
v-for="(item, index) in locationList"
|
|
|
:key="index"
|
|
@@ -2928,7 +2972,7 @@ async function messageNotInCache(question, answer) {
|
|
|
<img
|
|
|
class="map-img"
|
|
|
:class="{ 'show-anchor': showAnchor }"
|
|
|
- :src="`../src/assets/img/map/${message.body}.webp`"
|
|
|
+ :src="`https://cmm.ai/101-aiv2/map/${message.body}.webp`"
|
|
|
alt=""
|
|
|
/>
|
|
|
</div>
|
|
@@ -3459,6 +3503,27 @@ async function messageNotInCache(question, answer) {
|
|
|
|
|
|
<!-- 底部選單 -->
|
|
|
<div ref="menu" class="menu">
|
|
|
+ <!-- 對話輸入框 -->
|
|
|
+ <form
|
|
|
+ @submit.prevent="sendMessage()"
|
|
|
+ class="chat-inputs"
|
|
|
+ :class="{ 'd-none': !showInput }"
|
|
|
+ >
|
|
|
+ <!-- <button @click="hideMenu = false" class="menu-btn">
|
|
|
+ <img src="../assets/img/icon/素材-02.png" alt="" width="50" />
|
|
|
+ </button> -->
|
|
|
+
|
|
|
+ <input
|
|
|
+ ref="inputField"
|
|
|
+ v-model="userMessage"
|
|
|
+ type="text"
|
|
|
+ :placeholder="t('type_message')"
|
|
|
+ />
|
|
|
+ <button type="submit" class="submit">
|
|
|
+ <img width="20" src="../assets/img/paper-plane-solid.svg" alt="" />
|
|
|
+ </button>
|
|
|
+ </form>
|
|
|
+
|
|
|
<!-- AI 主播影片 -->
|
|
|
<!-- <div
|
|
|
v-show="showAnchor"
|
|
@@ -3484,8 +3549,9 @@ async function messageNotInCache(question, answer) {
|
|
|
</div>
|
|
|
</div> -->
|
|
|
|
|
|
- <div class="menu-table mb-3" :class="{ 'hide-table': hideMenu }">
|
|
|
- <table class="mt-3">
|
|
|
+ <!-- <div class="menu-table mb-3" :class="{ 'hide-table': hideMenu }"> -->
|
|
|
+ <div class="menu-table my-5">
|
|
|
+ <table>
|
|
|
<tbody>
|
|
|
<tr v-for="(row, rowIndex) in menuList" :key="rowIndex">
|
|
|
<td v-for="(item, itemIndex) in row" :key="itemIndex">
|
|
@@ -3512,7 +3578,7 @@ async function messageNotInCache(question, answer) {
|
|
|
</tbody>
|
|
|
</table> -->
|
|
|
|
|
|
- <div class="d-flex align-center position-relative" style="bottom: 20px">
|
|
|
+ <!-- <div class="d-flex align-center position-relative" style="bottom: 20px">
|
|
|
<div class="position-absolute">
|
|
|
<button
|
|
|
v-if="!showInput"
|
|
@@ -3559,16 +3625,12 @@ async function messageNotInCache(question, answer) {
|
|
|
{{ t("question") }}
|
|
|
</button>
|
|
|
|
|
|
- <!-- 對話輸入框 -->
|
|
|
<form
|
|
|
v-else
|
|
|
@submit.prevent="sendMessage()"
|
|
|
class="chat-inputs"
|
|
|
:class="{ 'd-none': !showInput }"
|
|
|
>
|
|
|
- <!-- <button @click="hideMenu = false" class="menu-btn">
|
|
|
- <img src="../assets/img/icon/素材-02.png" alt="" width="50" />
|
|
|
- </button> -->
|
|
|
|
|
|
<input
|
|
|
v-model="userMessage"
|
|
@@ -3584,7 +3646,7 @@ async function messageNotInCache(question, answer) {
|
|
|
</button>
|
|
|
</form>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
</div>
|
|
|
|
|
|
<!-- 廣告輪播 -->
|
|
@@ -3673,8 +3735,14 @@ async function messageNotInCache(question, answer) {
|
|
|
<!-- 掃描視窗 -->
|
|
|
<v-dialog v-model="qrcodeImgDialog" width="auto">
|
|
|
<v-card class="pa-5">
|
|
|
- <v-card-title class="text-center"> 請掃描 QR Code 前往 </v-card-title>
|
|
|
+ <!-- <v-card-title class="text-center">
|
|
|
+ 請掃描 QR Code 前往
|
|
|
+ </v-card-title> -->
|
|
|
<v-card-text>
|
|
|
+ <p class="text-h5 mb-5" style="font-weight: 600">
|
|
|
+ {{ t("scan_qr_code") }}
|
|
|
+ </p>
|
|
|
+
|
|
|
<qrcode-vue
|
|
|
:value="qrcodeImgUrl"
|
|
|
class="w-100 h-100"
|
|
@@ -3737,7 +3805,7 @@ async function messageNotInCache(question, answer) {
|
|
|
overflow-x: hidden;
|
|
|
|
|
|
.video-content {
|
|
|
- height: 73vh;
|
|
|
+ height: 55vh;
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
transform: scale(1);
|
|
@@ -3747,7 +3815,7 @@ async function messageNotInCache(question, answer) {
|
|
|
|
|
|
video {
|
|
|
width: 100%;
|
|
|
- height: 100%;
|
|
|
+ height: 120%;
|
|
|
position: fixed;
|
|
|
top: 55px;
|
|
|
left: 0;
|
|
@@ -3806,7 +3874,8 @@ async function messageNotInCache(question, answer) {
|
|
|
}
|
|
|
|
|
|
.map-img {
|
|
|
- max-width: 100%;
|
|
|
+ max-width: 70%;
|
|
|
+ margin-bottom: 2rem;
|
|
|
|
|
|
&.show-anchor {
|
|
|
max-width: 70%;
|
|
@@ -3815,7 +3884,7 @@ async function messageNotInCache(question, answer) {
|
|
|
|
|
|
.chat-content {
|
|
|
width: 100%;
|
|
|
- height: 65vh;
|
|
|
+ height: 60vh;
|
|
|
margin-top: -1rem;
|
|
|
position: relative;
|
|
|
z-index: 100;
|
|
@@ -3866,7 +3935,7 @@ async function messageNotInCache(question, answer) {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
background: var(--sub-color);
|
|
|
- height: 45vh;
|
|
|
+ height: 60vh;
|
|
|
padding: 0 1em 2em;
|
|
|
overflow-x: hidden;
|
|
|
overflow-y: auto;
|
|
@@ -3962,6 +4031,7 @@ async function messageNotInCache(question, answer) {
|
|
|
display: flex;
|
|
|
padding: 13px 20px;
|
|
|
background-color: white;
|
|
|
+ box-shadow: 0px -3px 10px rgba(150, 150, 150, 0.7);
|
|
|
|
|
|
input {
|
|
|
width: 100%;
|
|
@@ -4447,7 +4517,7 @@ async function messageNotInCache(question, answer) {
|
|
|
}
|
|
|
|
|
|
.icon {
|
|
|
- width: 80px;
|
|
|
+ width: 90px;
|
|
|
|
|
|
@media (max-width: 767px) {
|
|
|
width: 50px;
|
|
@@ -4558,5 +4628,9 @@ async function messageNotInCache(question, answer) {
|
|
|
bottom: 15px;
|
|
|
right: 20px;
|
|
|
width: 150px;
|
|
|
+
|
|
|
+ @media (max-width: 575px) {
|
|
|
+ width: 130px;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|