|
@@ -5,22 +5,13 @@
|
|
|
<img src="@/assets/images/environment/ai-career-profile.png" alt="404">
|
|
|
</div>
|
|
|
<div class="introduce-text">
|
|
|
- 在生涯访谈中,通过与不同职业人物对话,可以了解不同职业的发展前景、职业要求,为尽早规划职业发展 xxxx
|
|
|
+ AI生涯访谈依托人工智能,输入想访谈的职业名称后,AI将精准模拟该职业从业者,与你展开沉浸式职业探索对话。从职业发展前景、核心能力要求,到日常工作细节、学科适配方向,均可通过开放式提问进行深度探索,为高中选科、大学选专业和未来职业规划提供支持。
|
|
|
<p>访谈时你可以提出以下问题:</p>
|
|
|
</div>
|
|
|
<div class="question-list">
|
|
|
- <p class="question-list-item">您为什么要选择这一职业?</p>
|
|
|
- <p class="question-list-item">这项职业每天的核心任务是什么?</p>
|
|
|
- <p class="question-list-item">这项职业的工作环境如何?(室内/室外,办公室/工厂,团队工作/独自工作等)</p>
|
|
|
- <p class="question-list-item">从事这项职业需要哪些学历、证书、经验或关键能力?</p>
|
|
|
- <p class="question-list-item">这项职业在招聘或晋升时,更看重哪些个人特质或阶段特征?</p>
|
|
|
- <p class="question-list-item">大学里哪些专业与这项职业直接相关?</p>
|
|
|
- <p class="question-list-item">为了从事这项职业,在校期间应做哪些具体准备?</p>
|
|
|
- <p class="question-list-item">请分享一个最有成就感的项目/瞬间,以及一次印象深刻的挫折,您从中学到的关键经验是什么?</p>
|
|
|
- <p class="question-list-item">这项职业未来的发展前景如何?</p>
|
|
|
- <p class="question-list-item">这项职业进一步提升的途径有哪些?(培训、证书、项目、学历等)</p>
|
|
|
- <p class="question-list-item">如果未来的我将选择从事该职业,您会给我哪些具体建议?</p>
|
|
|
- <p class="question-list-item">请用时间轴描述一个典型工作日从上班到下班的详细流程?</p>
|
|
|
+ <p class="question-list-item" v-for="(item, index) in questionBankList" :key="index" @click="sendRequest(item.question)">
|
|
|
+ {{index+1}}.{{item.question}}
|
|
|
+ </p>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
@@ -29,7 +20,7 @@
|
|
|
<div class="center-header">
|
|
|
<div style="margin-left: 30px"></div>
|
|
|
<div>小新老师</div>
|
|
|
- <div class="header-exit-btn">退出</div>
|
|
|
+ <div class="header-exit-btn" @click="exitChatPage">退出</div>
|
|
|
</div>
|
|
|
<div v-loading="loadingHistoryRecord" class="chat-container">
|
|
|
<div class="message-list" ref="chatContainerRef">
|
|
@@ -59,8 +50,9 @@
|
|
|
<div v-show="expandIndexList.includes(index)" v-html="item.content" class="content-text"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div style="margin: 4px">
|
|
|
- <el-text>{{item.createTime}}</el-text>
|
|
|
+ <div style="margin: 4px;display: flex;align-items: center">
|
|
|
+ <p><el-text>{{item.createTime}}</el-text></p>
|
|
|
+ <p style="margin-left: 1vw"><el-text>数据来源于AI,仅供参考</el-text></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="index !== chatRecordList.length-1">
|
|
@@ -68,25 +60,54 @@
|
|
|
@click="foldOrExpandMessage(index, expandIndexList.includes(index))">
|
|
|
{{expandIndexList.includes(index)?'折叠':'展开'}}
|
|
|
</el-button>-->
|
|
|
- <img v-if="item.content.length>80"
|
|
|
+ <img v-if="item.content.length>60"
|
|
|
@click="foldOrExpandMessage(index, expandIndexList.includes(index))"
|
|
|
:src="expandIndexList.includes(index)?msgFold:msgExpand"
|
|
|
alt="icon"
|
|
|
style="margin-left: 4px;height: 36px;width: 36px"/>
|
|
|
</div>
|
|
|
- <el-button @click="ttsStartPlay(item.content, index)">{{playActiveIndex === index && playButtonFlag ?'停止':'播放'}}</el-button>
|
|
|
+ <!--<el-button @click="ttsStartPlay(item.content, index)">{{playActiveIndex === index && playButtonFlag ?'停止':'播放'}}</el-button>-->
|
|
|
+ <img @click="ttsStartPlay(item.content, index)"
|
|
|
+ :src="playActiveIndex === index && playButtonFlag ?playingPlayer:mutePlayer"
|
|
|
+ alt="icon"
|
|
|
+ style="margin-left: 4px;height: 36px;width: 36px"/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="input-container">
|
|
|
- <el-input
|
|
|
- v-model="inputMessage"
|
|
|
- type="textarea"
|
|
|
- placeholder="请输入消息"
|
|
|
- @keyup.enter="sendMessage"
|
|
|
- ></el-input>
|
|
|
- <el-button @click="sendMessage" :disabled="isSending" type="primary">发送</el-button>
|
|
|
+ <div class="question-tip-box" ref="questionTipBoxRef" v-if="showQuestionTipBoxFlag">
|
|
|
+ <div>
|
|
|
+ <div style="display: flex;justify-content: space-between;align-items: center">
|
|
|
+ <div class="tip-title">你可以选择以下问题</div>
|
|
|
+ <div>X</div>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex;align-items: center;flex-wrap: wrap">
|
|
|
+ <div class="tip-item" v-for="(item, index) in questionBankByKeywordList" :key="index" @click="tipSendRequest(item.question)">
|
|
|
+ {{index+1}}.{{item.question}}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="input-component">
|
|
|
+ <div class="input-search">
|
|
|
+ <el-input
|
|
|
+ v-model="inputMessage"
|
|
|
+ style="width: 1220px;height: 84px"
|
|
|
+ placeholder="请输入消息"
|
|
|
+ @input="getQuestionBankByKeyword"
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
+ >
|
|
|
+ <template #suffix>
|
|
|
+ <span style="font-size: 38px;color: #444040;margin-left: 37px;cursor: pointer" @click="clearInput">
|
|
|
+ X
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ <div @click="sendMessage" :disabled="isSending" type="primary">发送</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="iat-box-default" @click="iatRecognizeVoice">
|
|
|
+ <img class="recognize-img" :src="iatVoiceOpen? recognize:microphone">
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -106,14 +127,18 @@
|
|
|
import {Base64} from 'js-base64'
|
|
|
import * as AudioPlayer from "/public/ai/tts/dist/index.umd.js"
|
|
|
import {aiChatRecordList, aiChatRecordAdd} from '@/api/xjc-integratedmachine/common/aiChat.js'
|
|
|
+ import {getCareerChatRecordList, addCareerChatRecord, getQuestionBankList} from "@/api/xjc-integratedmachine/environment/ai-career.js";
|
|
|
import msgFold from '@/assets/images/environment/ai-career-msg-fold.png'
|
|
|
import msgExpand from '@/assets/images/environment/ai-career-msg-expand.png'
|
|
|
+ import mutePlayer from '@/assets/images/environment/ai-career-mute-player.png'
|
|
|
+ import playingPlayer from '@/assets/images/environment/ai-career-playing-player.gif'
|
|
|
+ import microphone from '@/assets/images/environment/ai-career-microphone.png'
|
|
|
+ import recognize from '@/assets/images/environment/ai-career-recognize.gif'
|
|
|
const router = useRouter()
|
|
|
const route = useRoute()
|
|
|
|
|
|
const param = route.query
|
|
|
|
|
|
-
|
|
|
const loadingHistoryRecord = ref(false)
|
|
|
// 聊天记录
|
|
|
let chatRecordList = ref([])
|
|
@@ -136,14 +161,24 @@
|
|
|
// 播放按钮状态
|
|
|
let playActiveIndex = ref(0)
|
|
|
let playButtonFlag = ref(false)
|
|
|
+ // 左侧推荐问题
|
|
|
+ let questionBankList = ref([])
|
|
|
+ // 关键词提示问题
|
|
|
+ let questionBankByKeywordList = ref([])
|
|
|
+
|
|
|
+ // 显示提示
|
|
|
+ let showQuestionTipBoxFlag = ref(false)
|
|
|
+ // 提示信息
|
|
|
+ const HELLO_MSG = '你是谁?'
|
|
|
// 查看所有聊天记录
|
|
|
function list() {
|
|
|
loadingHistoryRecord.value = true
|
|
|
let queryForm = {
|
|
|
pageNum: 1,
|
|
|
- pageSize: 10000
|
|
|
+ pageSize: 10000,
|
|
|
+ occupationId: param.occupationId,
|
|
|
}
|
|
|
- aiChatRecordList(queryForm).then(resp =>{
|
|
|
+ getCareerChatRecordList(queryForm).then(resp =>{
|
|
|
chatRecordList.value = resp.rows;
|
|
|
loadingHistoryRecord.value = false
|
|
|
setTimeout(()=>{
|
|
@@ -157,22 +192,31 @@
|
|
|
|
|
|
function addRecord(content) {
|
|
|
let queryForm = {
|
|
|
- content: content,
|
|
|
- isUser: 0
|
|
|
+ 'occupationName': param.occupationName,
|
|
|
+ 'occupationId': param.occupationId,
|
|
|
+ 'content': content,
|
|
|
+ 'isUser': 0
|
|
|
}
|
|
|
- aiChatRecordAdd(queryForm).then(resp =>{
|
|
|
+ addCareerChatRecord(queryForm).then(resp =>{
|
|
|
console.log(resp)
|
|
|
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ // 第一次聊天发送消息
|
|
|
function sayHi() {
|
|
|
- const botMsg = {
|
|
|
- isUser: false,
|
|
|
- content: '你好,我是来帮助你进行学习规划、选科辅导以及志愿填报的生涯教育专家。如果你有关于这些方面的问题,欢迎随时向我咨询!', // 增量填充
|
|
|
- isTyping: false, // 显示加载动画
|
|
|
- }
|
|
|
- chatRecordList.value.push(botMsg)
|
|
|
+ sendRequest(HELLO_MSG)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除输入框
|
|
|
+ function clearInput(){
|
|
|
+ inputMessage.value = '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在关键词搜索页点击发送问题
|
|
|
+ function tipSendRequest(content){
|
|
|
+ sendRequest(content);
|
|
|
+ showQuestionTipBoxFlag.value = false
|
|
|
}
|
|
|
|
|
|
const sendMessage = () => {
|
|
@@ -183,14 +227,17 @@
|
|
|
}
|
|
|
|
|
|
const sendRequest = async(message) => {
|
|
|
- // 用户信息
|
|
|
- const userMessage = {
|
|
|
- isUser: true,
|
|
|
- content: message,
|
|
|
- isTyping: false
|
|
|
- }
|
|
|
- // 消息加入聊天记录
|
|
|
- chatRecordList.value.push(userMessage)
|
|
|
+ if(message !== HELLO_MSG){
|
|
|
+ // 用户信息
|
|
|
+ const userMsg = {
|
|
|
+ isUser: true,
|
|
|
+ content: message,
|
|
|
+ isTyping: false
|
|
|
+ }
|
|
|
+ // 消息加入聊天记录
|
|
|
+ chatRecordList.value.push(userMsg)
|
|
|
+ }
|
|
|
+
|
|
|
const botMsg = {
|
|
|
isUser: false,
|
|
|
content: '', // 增量填充
|
|
@@ -209,10 +256,12 @@
|
|
|
|
|
|
// 请求体
|
|
|
let form = {
|
|
|
+ 'occupationName': param.occupationName,
|
|
|
+ 'occupationId': param.occupationId,
|
|
|
"content": message? message: "你是谁?"
|
|
|
}
|
|
|
// 发送fetch请求
|
|
|
- const response = await fetch('/dev-api/ai/chat/record/stream', {
|
|
|
+ const response = await fetch('/dev-api/ai/career/chat/record/stream', {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Content-Type': 'application/json',
|
|
@@ -279,9 +328,11 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 存储职业
|
|
|
+
|
|
|
/* 语音识别 ↓*/
|
|
|
- // 控制录音弹窗
|
|
|
- let iatVoiceOpen = false
|
|
|
+ // 语音识别按钮状态
|
|
|
+ let iatVoiceOpen = ref(false)
|
|
|
// 是否开始录音
|
|
|
let iatStartVoiceStatus = false
|
|
|
// 识别中状态
|
|
@@ -331,15 +382,27 @@
|
|
|
console.log('录音结束,停止定时器');
|
|
|
clearInterval(iatCountdownInterval);
|
|
|
iatStartVoiceStatus = false;
|
|
|
+ iatVoiceOpen.value = false;
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function iatRecognizeVoice(){
|
|
|
+ if(iatVoiceOpen.value){
|
|
|
+ iatCloseVoiceOpen();
|
|
|
+ }else{
|
|
|
+ iatStartVoice();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 开始录音
|
|
|
+ * */
|
|
|
async function iatStartVoice() {
|
|
|
if (iatLoading) {
|
|
|
return;
|
|
|
}
|
|
|
- iatVoiceOpen = true;
|
|
|
+ iatVoiceOpen.value = true;
|
|
|
await iatPlayIatVoice();
|
|
|
}
|
|
|
|
|
@@ -368,7 +431,7 @@
|
|
|
* 关闭录音弹窗
|
|
|
*/
|
|
|
function iatCloseVoiceOpen() {
|
|
|
- iatVoiceOpen = false;
|
|
|
+ iatVoiceOpen.value = false;
|
|
|
iatStartVoiceStatus = false;
|
|
|
if (iatRecorder) {
|
|
|
iatRecorder.stop();
|
|
@@ -708,11 +771,46 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function exitChatPage(){
|
|
|
+ router.go(-1)
|
|
|
+ }
|
|
|
+
|
|
|
+ function getRecommendQuestionBank(){
|
|
|
+ let form = {
|
|
|
+ type: 1,
|
|
|
+ isRecommend: 1,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10000
|
|
|
+ }
|
|
|
+ getQuestionBankList(form).then(resp => {
|
|
|
+ questionBankList.value = resp.rows
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ function getQuestionBankByKeyword(){
|
|
|
+ let form = {
|
|
|
+ type: 1,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10000,
|
|
|
+ keyword: inputMessage.value
|
|
|
+ }
|
|
|
+ getQuestionBankList(form).then(resp => {
|
|
|
+ if(resp.rows && resp.rows.length >0){
|
|
|
+ showQuestionTipBoxFlag.value = true
|
|
|
+ questionBankByKeywordList.value = resp.rows
|
|
|
+ }else{
|
|
|
+ showQuestionTipBoxFlag.value = false
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
onMounted(()=>{
|
|
|
nextTick(()=>{
|
|
|
initSpeechRecognition();
|
|
|
initSpeechSynthesis();
|
|
|
list();
|
|
|
+ getRecommendQuestionBank();
|
|
|
})
|
|
|
|
|
|
})
|
|
@@ -752,7 +850,7 @@
|
|
|
width: 392px;
|
|
|
margin-left: 14px;
|
|
|
font-weight: 400;
|
|
|
- font-size: 28px;
|
|
|
+ font-size: 24px;
|
|
|
color: #7D7C7C;
|
|
|
line-height: 40px;
|
|
|
text-align: left;
|
|
@@ -765,7 +863,7 @@
|
|
|
overflow: auto;
|
|
|
margin-left: 14px;
|
|
|
font-weight: 400;
|
|
|
- font-size: 28px;
|
|
|
+ font-size: 24px;
|
|
|
color: #7D7C7C;
|
|
|
line-height: 40px;
|
|
|
text-align: left;
|
|
@@ -815,6 +913,7 @@
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
margin-right: 30px;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
}
|
|
|
.chat-container {
|
|
@@ -865,7 +964,7 @@
|
|
|
|
|
|
.content-text{
|
|
|
font-weight: 400;
|
|
|
- font-size: 28px !important;
|
|
|
+ font-size: 24px !important;
|
|
|
color: #333333;
|
|
|
line-height: 52px;
|
|
|
letter-spacing: 3px;
|
|
@@ -902,4 +1001,105 @@
|
|
|
opacity: 1;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /*输入框*/
|
|
|
+
|
|
|
+ .input-component {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .input-search {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ /*margin-top: 57px;*/
|
|
|
+
|
|
|
+ ::v-deep .el-input__inner {
|
|
|
+ font-size: 24px;
|
|
|
+ margin-left: 34px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-input__suffix {
|
|
|
+ font-size: 100px;
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-input__wrapper {
|
|
|
+ background-color: #F5F9FA;;
|
|
|
+ box-shadow: none;
|
|
|
+ height: 84px;
|
|
|
+ width: 1220px;
|
|
|
+ }
|
|
|
+ div{
|
|
|
+ width: 170px;
|
|
|
+ height: 84px;
|
|
|
+ background: linear-gradient( 180deg, #73EE71 0%, #0ACB63 100%);
|
|
|
+ border-radius: 0px 5px 5px 0px;
|
|
|
+
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 24px;
|
|
|
+ color: #FFFFFF;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .iat-box-default{
|
|
|
+ position: absolute;
|
|
|
+ right: 97px;
|
|
|
+ top:50vh;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ width: 200px;
|
|
|
+ height: 200px;
|
|
|
+ background: linear-gradient( 180deg, #F8F8F8 0%, #EAEAEA 100%);
|
|
|
+ box-shadow: 0px 8px 20px 0px rgba(0,0,0,0.1);
|
|
|
+ border-radius: 227px 227px 227px 227px;
|
|
|
+ /*border: 1px solid;*/
|
|
|
+ border-image: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.13)) 1 1;
|
|
|
+ .recognize-img{
|
|
|
+ height: 150px;
|
|
|
+ width: 150px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .question-tip-box{
|
|
|
+ width: 1346px;
|
|
|
+ height: 100px;
|
|
|
+ overflow: auto;
|
|
|
+ z-index: 10;
|
|
|
+ position: absolute;
|
|
|
+ right: 68px;
|
|
|
+ bottom: 100px;
|
|
|
+
|
|
|
+ .tip-title{
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 24px;
|
|
|
+ color: #000000;
|
|
|
+ line-height: 40px;
|
|
|
+ text-align: left;
|
|
|
+ font-style: normal;
|
|
|
+ text-transform: none;
|
|
|
+ }
|
|
|
+ .tip-item{
|
|
|
+ height: 41px;
|
|
|
+ background: #E9FBFF;
|
|
|
+ border-radius: 35px 35px 35px 35px;
|
|
|
+ border: 1px solid #8CE349;
|
|
|
+ padding: 0 20px;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 24px;
|
|
|
+ color: #7D7C7C;
|
|
|
+ line-height: 40px;
|
|
|
+ text-align: left;
|
|
|
+ font-style: normal;
|
|
|
+ text-transform: none;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
</style>
|