123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- <template>
- <div class="chat bg-white">
- <div class="flex items-center h-screen relative">
- <div class="leftInfo relative" v-show="!showNodata">
- <div class="history">
- <!-- historyActive -->
- <div class="historyBox" v-for="(item, index) in allRecords" :key="index">
- <div class="top flex w-full cursor-pointer" @click="item.open = !item.open">
- <div class="photo">
- <img class="object-cover" :src="baseApi + item.picture" @error="$AIPohotoError" alt="">
- </div>
- <div class="info flex-1 ml-2 flex flex-col justify-around">
- <div class="text-sm font-semibold">{{ item.characterName }}</div>
- <div class="text-sm text-gray-400">{{ item.prologue }}
- </div>
- </div>
- <div class="flex items-center text-lg" style="height: 48px;">
- <i v-if="!item.open" class="el-icon-arrow-down" style="font-size: 16px;"></i>
- <i v-else class="el-icon-arrow-up" style="font-size: 16px;"></i>
- </div>
- </div>
- <!-- <transition name="el-zoom-in-top"> -->
- <div class="dialogueList mt-4" v-show="item.open">
- <div class="flex justify-between mb-2">
- <el-button v-if="item.isDelete == 0" type="primary" class="flex-1" round
- @click="newStart_juese(item)">新的对话</el-button>
- <div v-else class="flex-1 rounded border border-gray-200 text-sm p-2 text-gray-600">
- {{ item.characterName }}已经被设定为私有或被创建者删除。
- </div>
- <el-dropdown class="flex justify-end items-center ml-2" trigger="click"
- @command="handleCommand2($event, item)">
- <div class=" w-8 h-8 bg-gray-100 rounded flex justify-center items-center cursor-pointer">
- <i slot="reference" class="el-icon-more"></i>
- </div>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="2">删除</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- <div
- class="dialogue flex justify-between items-center w-full h-16 rounded-md px-2 mb-2 cursor-pointer relative"
- :class="info.id == item.id && index2 == recordsIndex && 'historyActive'"
- v-for="(item2, index2) in item.chatCharacterList" :key="index2"
- @click.self="clickDialogue(item, item2, index2)">
- <span @click.self="clickDialogue(item, item2, index2)">
- <i v-if="item2.sceneId || item2.sceneIcon" class="el-icon-video-camera"></i>
- {{ item2.chatTitle }}
- </span>
- <span @click.self="clickDialogue(item, item2, index2)" class=" text-sm text-gray-500">{{ item2.createTime
- }}</span>
- <el-dropdown class="dialogueIconBg absolute h-16 w-20 right-0 flex justify-end items-center pr-4"
- trigger="click" @command="handleCommand($event, item, item2)">
- <div>
- <i slot="reference" class="el-icon-more"></i>
- </div>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="1">修改标题</el-dropdown-item>
- <el-dropdown-item command="2">删除</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- </div>
- <!-- </transition> -->
- </div>
- </div>
- <!-- 角色详情 -->
- <div class="chatInfo absolute top-0 left-0 w-full h-full z-30 bg-white" v-show="showInfo == 1">
- <div class="flex flex-col p-4 h-full">
- <div class="flex justify-between items-center text-base mb-3">
- <div>角色详情</div>
- <i class="el-icon-close cursor-pointer" @click="showInfoChange(0)"></i>
- </div>
- <div class="flex">
- <span class="chatInfo_photo">
- <img class="w-16 h-16 rounded-full overflow-hidden object-cover" :src="baseApi + info.picture"
- @error="$AIPohotoError">
- </span>
- <div class="w-0 flex-1 ml-2">
- <div class="text-xl font-medium">{{ info.characterName }}</div>
- <div class="mt-1 text-gray-500 text-sm">Xchat No.{{ info.id }}</div>
- </div>
- </div>
- <div class="flex mt-4">
- <div class="hot flex w-auto items-center px-2 py-1 text-sm mr-2 rounded-full">
- <v-icon name="fire" scale="1" />
- <span class="ml-1">{{ info.hotCount }}</span>
- </div>
- </div>
- <div class="flex justify-around mt-4">
- <div class=" rounded-full w-32 text-center py-2 text-sm cursor-pointer" style="border: solid 1px #000">分享
- </div>
- <div class=" rounded-full w-32 text-center py-2 text-sm cursor-pointer" style="border: solid 1px #000"
- @click="showDetail = !showDetail">角色详情</div>
- </div>
- <transition name="el-zoom-in-top">
- <div v-show="showDetail">
- <div class="mt-5 text-base pb-3 border-b border-gray-200">
- <div>
- <i class="el-icon-document"></i>
- 简介
- </div>
- <div class="flex">
- <div ref="prologue" class="mt-3 text-sm max-h-48 prologue" :class="showPrologue && 'prologueOpen'">
- <div v-show="showPrologueButton" class="textButton" @click="showPrologue = !showPrologue">{{
- showPrologue ? '收起' :
- '展开' }}</div>
- {{ info.prologue }}
- </div>
- </div>
- </div>
- <div class="flex justify-between items-center mt-5 text-base pb-3 border-b border-gray-200">
- <div>
- <i class="el-icon-user"></i>
- 创作人
- </div>
- <div class="text-sm max-h-48">
- {{ info.author }}
- </div>
- </div>
- <div class="flex justify-between items-center mt-5 text-base pb-3 border-b border-gray-200">
- <div>
- <i class="el-icon-time"></i>
- 创建时间
- </div>
- <div class="text-sm max-h-48">
- {{ info.createTime }}
- </div>
- </div>
- <div class="mt-5 text-base">
- <i class="el-icon-discount"></i>
- 特征
- </div>
- <div class="tags mt-4 pb-3">
- <span class="tag" v-for="(item, index) in info.labelArr" :key="index">
- {{ item }}
- </span>
- </div>
- </div>
- </transition>
- <div class="mt-5 text-base pb-3 flex-1 flex flex-col">
- <div>
- <!-- <i class="el-icon-document"></i> -->
- 查看场景
- </div>
- <div class="mt-3 text-sm max-h-48">
- <div v-if="info.sceneList && info.sceneList.length > 0"
- class="grid grid-cols-2 gap-2 mb-4 cursor-pointer">
- <template v-for="(item, index) in info.sceneList">
- <div v-if="item.isDelete == 0" class="flex flex-col justify-center" :key="index"
- @click="sceneChange(item)">
- <img class=" rounded w-full h-24 object-cover" :src="baseApi + item.background" alt="">
- <div>{{ item.sceneName }}</div>
- <div class=" text-gray-400">{{ item.sceneDescription }}</div>
- </div>
- </template>
- </div>
- <el-empty v-else description="暂无场景"></el-empty>
- <div class="flex justify-center mt-10">
- <el-button type="primary" round @click="toCreateScene">创建场景</el-button>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 场景详情 -->
- <div class="absolute top-0 left-0 w-full h-full z-30 bg-white overflow-hidden" v-show="showInfo == 2">
- <div class="flex flex-col p-4 h-full">
- <div class="flex justify-between items-center text-base mb-3">
- <div>场景详情</div>
- <i class="el-icon-close cursor-pointer" @click="showInfoChange(0)"></i>
- </div>
- <div class=" text-gray-500">{{ sceneInfo.sceneDescription }}</div>
- </div>
- </div>
- </div>
- <div class="content" :class="fullScreen && 'contentFull'" v-show="!showNodata"
- :style="{ backgroundImage: `url(${baseApi}${sceneInfo.background})` }">
- <!-- <div class="leftImg">
- <img :src="baseApi + info.picture" alt="">
- <div class="aiInfo">
- <span class="photo">
- <img :src="baseApi + info.picture">
- </span>
- <div class="info">
- <div class="name">{{ info.characterName }}</div>
- <div class="tags">
- <span class="tag" v-for="(item, index) in info.labelArr" :key="index">
- {{ item }}
- </span>
- </div>
- <div class="infoContent">{{ info.prologue }}</div>
- </div>
- </div>
- </div> -->
- <div class="fullScreenButton rounded-full border border-gray-200" @click="clickFullScreen">
- <i class="el-icon-arrow-left" v-if="!fullScreen"></i>
- <i class="el-icon-arrow-right" v-else></i>
- </div>
- <div class="chat-box" :class="sceneId && 'mask'">
- <div class="chatBoxTitle absolute top-0">
- <div>
- {{ info.characterName }}
- <el-dropdown v-if="sceneId" class="flex justify-end items-center" trigger="click" @command="handleCommand3"
- @visible-change="dropdown3Show = !dropdown3Show">
- <div>
- <div slot="reference" class="flex justify-center items-center cursor-pointer text-white">
- 已进入场景:{{ sceneInfo.sceneName }}
- <i class="el-icon-arrow-up ml-2" style="font-size: 16px;" v-if="dropdown3Show"></i>
- <i class="el-icon-arrow-down ml-2" style="font-size: 16px;" v-else></i>
- </div>
- </div>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="1">场景详情</el-dropdown-item>
- <el-dropdown-item command="2">新场景对话</el-dropdown-item>
- <el-dropdown-item command="3">回到常规对话</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- <div class="flex w-60 justify-end">
- <el-tooltip effect="dark" content="设定" placement="bottom">
- <el-popover placement="bottom" width="400" trigger="click">
- <div class="p-2">
- <div class="flex justify-between mb-4">
- <span>语音自动播放</span>
- <el-switch v-model="setting.value1" @change="ChangeSettingValue1">
- </el-switch>
- </div>
- <div class="flex justify-between">
- <span>全屏幕</span>
- <el-switch v-model="fullScreen">
- </el-switch>
- </div>
- </div>
- <i slot="reference" class="fa-solid fa-sliders cursor-pointer text-xl mr-6"></i>
- </el-popover>
- </el-tooltip>
- <el-tooltip effect="dark" content="角色详情" placement="bottom">
- <i class="fa-solid fa-file-invoice cursor-pointer text-xl mr-6" @click="showInfoChange(1)"></i>
- </el-tooltip>
- <el-tooltip v-if="!sceneId" effect="dark" content="开始新的对话" placement="bottom">
- <i class="fa-solid fa-comment-medical cursor-pointer text-xl mr-6" @click="newStart"></i>
- </el-tooltip>
- <el-tooltip effect="dark" content="历史对话" placement="bottom">
- <i class="fa-solid fa-clock-rotate-left cursor-pointer text-xl" @click="showInfoChange(0)"></i>
- </el-tooltip>
- </div>
- </div>
- <audio ref="audio" muted v-show="false" :src="audioUrl" autoplay="" @ended="audioEnd" controls></audio>
- <div class="messages" ref="messages">
- <template v-for="(item, index) in returnMessage">
- <div v-if="item.role == 'assistant'" class="mb-4 flex" :key="index">
- <!-- ai返回的信息 -->
- <div class="pt-2 photo">
- <img :src="baseApi + info.picture" class="rounded-full w-14 h-14 object-cover"
- @error="$AIPohotoError" />
- </div>
- <div class="messageRight">
- <div v-show="!item.edit" :ref="`message${index}`"
- class="message mt-4 ml-4 p-4 rounded-r-md rounded-bl-md text-xs relative">
- <div class="yyPlayBg mb-2 w-16 p-1 cursor-pointer">
- <img v-if="audioPlayIndex == index" class="yyPlay" src="@/assets/images/播放/yyPlay1.png" alt="">
- <img v-else class="yyPlay" src="@/assets/images/播放/yyPlay.png" alt=""
- @click="historyGetVoice(item, index)">
- <!-- <svg-icon class="icon" class-name="speech-icon" icon-class="speech" @click.stop="click" /> -->
- </div>
- <div v-show="!item.content" class="loadingMessage">
- <div v-loading="!item.content" element-loading-background="rgba(0, 0, 0, 0.0)"></div>
- </div>
- <p style="white-space: pre-line;" v-show="item.content">{{ item.content }}</p>
- <div class="messageOptions" v-show="returnMessage.length == 1">
- <div class="option" v-for="(item, index) in messageOptions" :key="index"
- @click="messageOptionClick(item.chatGuidance)">
- {{ item.chatGuidance }}
- </div>
- </div>
- <el-dropdown v-if="index != 0" class="messageDropdown" @command="handleCommand4($event, item, index)"
- placement="top-end">
- <el-button class="messageButton" icon="el-icon-more" circle></el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="1">编辑</el-dropdown-item>
- <el-dropdown-item command="2">删除</el-dropdown-item>
- <el-dropdown-item v-if="index == returnMessage.length - 1" command="3">重新生成</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- <div :ref="`messageEdit${index}`" v-show="item.edit"
- class="message messageEdit mt-4 ml-4 p-4 rounded-r-md rounded-bl-md text-xs relative">
- <el-input class="eidtTextarea" :ref="`messageEditInput${index}`" type="textarea" resize="none"
- v-model="item.editContent">
- </el-input>
- <div class="flex justify-end mt-2">
- <el-button @click="editCancel(item, index)">取消</el-button>
- <el-button @click="editSave(item, index)">保存</el-button>
- </div>
- </div>
- </div>
- </div>
- <!-- 用户发送的信息 -->
- <div v-if="item.role == 'user'" class="mb-4 flex me" :key="index">
- <div class="pt-2 photo">
- <img :src="$store.state.user.avatar" class="rounded-full w-14 h-14 object-cover"
- @error="$userPohotoError" />
- </div>
- <div class="messageRight">
- <div :ref="`message${index}`" v-show="!item.edit"
- class="messageUser mr-4 mt-4 p-4 rounded-l-md rounded-br-md text-xs relative">
- {{ item.content }}
- <el-dropdown v-if="index != 0" class="messageDropdown" @command="handleCommand4($event, item, index)"
- placement="top-end">
- <el-button class="messageButton" icon="el-icon-more" circle></el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="1">编辑</el-dropdown-item>
- <el-dropdown-item command="2">删除</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- <div :ref="`messageEdit${index}`" v-show="item.edit"
- class="messageUser messageEdit mt-4 ml-4 p-4 rounded-r-md rounded-bl-md text-xs relative">
- <el-input class="eidtTextarea" :ref="`messageEditInput${index}`" type="textarea" resize="none"
- v-model="item.editContent">
- </el-input>
- <div class="flex justify-end mt-2">
- <el-button @click="editCancel(item, index)">取消</el-button>
- <el-button @click="editSave(item, index)">保存</el-button>
- </div>
- </div>
- </div>
- </div>
- </template>
- </div>
- <div class="inputBox absolute left-2 right-2 bottom-4 " @click="inputBoxClick">
- <input v-if="canChat" ref="input" type="text" placeholder="输入消息..."
- class="w-full flex-1 py-2 px-4 rounded-l-lg text-sm focus:outline-none" v-model="content"
- @keydown="Enterkey" />
- <div class="flex pt-6 justify-between" v-if="canChat" style="height: 70px;">
- <div class="tools w-36 flex justify-between">
- <i class="el-icon-setting text-2xl cursor-pointer" @click="showConfig = true"></i>
- <!-- <i class="el-icon-picture-outline text-2xl cursor-pointer"></i> -->
- <!-- <i class="el-icon-s-opportunity text-2xl cursor-pointer"></i> -->
- </div>
- <el-button type="text" :disabled="!content" :loading="notChatSend" @click.prevent="getStreamChatWithWeb"
- class="px-4 rounded-r-lg text-sm text-gray-400" :class="content && 'planeColor'">
- <v-icon v-show="!notChatSend" name="paper-plane" scale="1.5" />
- </el-button>
- </div>
- <div v-if="!canChat" class=" flex w-full text-sm text-gray-400">
- 当前角色或场景已被设定为私有或被创作者删除,但你任然可以查看历史对话。
- </div>
- </div>
- </div>
- </div>
- <div v-show="showNodata" class=" w-full h-full flex flex-col justify-center items-center">
- <el-empty description="暂无聊天记录,点击按钮并探索新角色。"></el-empty>
- <el-button type="primary" round @click="$router.push('/')">寻找一个角色</el-button>
- </div>
- <el-dialog title="配置" :visible.sync="showConfig" width="500px">
- <!-- <p class="text-base">身分</p>
- <p class="text-sm text-gray-400">选择你和角色聊天的身份</p>
- <div class="flex items-start py-3 border-b border-gray-200">
- <el-radio-group class="radio" v-model="configForm.radio1">
- <el-radio-button label="上海"></el-radio-button>
- </el-radio-group>
- <el-button>
- <i class="el-icon-sort" style="transform: rotate(90deg);"></i>
- </el-button>
- </div> -->
- <p class="text-base mt-3">选择模型</p>
- <p class="text-sm text-gray-400">每个模型可能有不同的效果,仅对当前对话有影响</p>
- <div class="flex items-start py-3 border-b border-gray-200">
- <el-radio-group class="radio" v-model="configForm.radio2">
- <el-radio-button v-for="(item, index) in modelList" :key="index" :label="item.id">{{ item.model
- }}</el-radio-button>
- </el-radio-group>
- </div>
- <!-- <p class="text-base mt-3">角色语言</p>
- <p class="text-sm text-gray-400">请选择角色的回复语言</p>
- <div class="flex items-start py-3">
- <el-radio-group class="radio" v-model="configForm.radio3">
- <el-radio-button label="自动"></el-radio-button>
- <el-radio-button label="简体中文"></el-radio-button>
- <el-radio-button label="繁體中文"></el-radio-button>
- <el-radio-button label="English"></el-radio-button>
- <el-radio-button label="Español"></el-radio-button>
- </el-radio-group>
- </div> -->
- <span slot="footer" class="dialog-footer">
- <el-button @click="showConfig = false">取 消</el-button>
- <el-button type="primary" @click="configConfirm">确 定</el-button>
- </span>
- </el-dialog>
- </div>
- </div>
- </template>
- <script>
- import Cookies from 'js-cookie'
- import {
- streamChatWithWebApi,
- getGuidanceApi,
- getModelListApi,
- addChatApi,
- getChatCharacterRecordsApi,
- getChatRecordApi,
- updateTitleApi,
- clearRecordApi,
- queryVoiceListApi,
- updateRecordApi,
- deleteRecordApi
- } from "@/api/chat.js"
- import { detailApi } from "@/api/detail.js"
- import { queryUserBalanceApi } from "@/api/user.js"
- import { Message, MessageBox, Notification, Loading } from 'element-ui'
- import 'vue-awesome/icons/paper-plane'
- import 'vue-awesome/icons/fire'
- export default {
- components: {
- },
- data() {
- return {
- // 展开收起简介按钮是否显示
- showPrologueButton: false,
- // 展开收起简介
- showPrologue: false,
- // 对话请求超时参数
- timeOut: null,
- // 聊天等待
- chatLoading: false,
- // 是否全屏
- fullScreen: false,
- // 角色所有聊天列表
- allRecords: [],
- // 聊天记录id
- recordId: null,
- // 选中的角色聊天记录
- historyRes: [],
- recordsIndex: null,
- showDetail: true,
- showConfig: false,
- showInfo: 0,
- messageOptions: [],
- info: {},
- messageLoading: false,
- returnMessage: [],
- content: '',
- audioPlayIndex: null,
- configForm: {
- radio1: null,
- radio2: null,
- radio3: null,
- },
- // 对话接口是否返回错误状态
- resError: false,
- // 模型列表
- modelList: [],
- setting: {
- value1: false,
- value2: false,
- },
- //音频相关↓
- //音频地址
- audioUrl: '',
- audioUrlArr: [],
- audioUrlArrIndx: 0,
- videoLoop: null,
- videoLoopTime: 0,
- loopPlay: false,
- //场景下拉菜单
- dropdown3Show: false,
- // 场景对话相关
- sceneId: null,
- sceneInfo: {},
- }
- },
- computed: {
- canChat() {
- console.log(this.info, 'this.info');
- if (!this.sceneId) {
- if (this.info.isDelete == 1) {
- console.log(1);
- return false
- } else {
- console.log(2);
- return true
- }
- } else {
- if (this.sceneInfo.isDelete == 1) {
- return false
- } else {
- return true
- }
- }
- },
- notChatSend() {
- return this.chatLoading != false || this.audioPlayIndex != null
- },
- showNodata() {
- return this.allRecords.length == 0 && !this.$route.query.characterId
- }
- },
- mounted() {
- this.init()
- this.$nextTick(() => {
- })
- },
- watch: {
- '$route.query.characterId': {
- handler(newVal, lodVal) {
- console.log(newVal, 'newVal');
- if (!newVal) {
- this.$nextTick(() => {
- this.showInfoChange(0)
- })
- }
- },
- deep: true
- },
- returnMessage: {
- handler(newVal, lodVal) {
- this.$nextTick(() => {
- let messages = this.$refs.messages
- messages.scrollTop = messages.scrollHeight
- })
- },
- deep: true
- }
- },
- methods: {
- async init() {
- // 获取模型列表
- this.getModelList()
- // 获取用户所有聊天记录
- await this.getChatCharacterRecords()
- // 如果用角色id获取角色详情
- if (this.$route.query.characterId) {
- if (this.$route.query.sceneId) {
- this.sceneId = this.$route.query.sceneId
- }
- this.showInfoChange(1)
- await this.getDetail(this.$route.query.characterId)
- } else {
- this.allRecords[0].open = true
- await this.getDetail(this.allRecords[0].id)
- }
- // 查找当前角色是否有对话记录
- // this.searchHistory(this.info.id)
- },
- // 左侧面板变化
- showInfoChange(index) {
- this.fullScreen = false
- this.showInfo = index
- },
- // 全屏
- clickFullScreen() {
- this.fullScreen = !this.fullScreen
- },
- // 点击聊天记录切换聊天
- async clickDialogue(value1, value2, index) {
- console.log(value2, 'value2');
- let _this = this
- this.audioUrl = ""
- this.messageOptions = []
- this.returnMessage = []
- if (this.$route.query.characterId) {
- this.$route.query.characterId = value1.id
- }
- if (!value2) {
- return
- }
- // 如果点击的是场景聊天
- if (value2.sceneId) {
- this.sceneId = value2.sceneId
- await this.getDetail(value1.id)
- // 从角色详情中获取场景列表
- let sceneList = this.info.sceneList
- // 获取当前聊天对应的场景
- for (let i = 0; i < sceneList.length; i++) {
- const element = sceneList[i];
- if (element.sceneId == value2.sceneId) {
- _this.sceneInfo = element
- }
- }
- } else {
- this.sceneId = null
- this.sceneInfo = {}
- await this.getDetail(value1.id)
- }
- this.recordId = value2.id
- this.getChatRecord(value2.id)
- this.recordsIndex = index
- },
- // 场景下拉菜单
- handleCommand3(value) {
- if (value == 1) {
- this.showInfoChange(2)
- } else if (value == 2) {
- // 情况聊天记录
- this.returnMessage = []
- // 新建场景对话
- this.newStart()
- // 增加开场白
- this.returnMessage.push({
- role: 'assistant',
- content: this.sceneInfo.sceneWelcome
- })
- } else if (value == 3) {
- // 回到常规对话
- // 遍历当前聊天记录是否有常规对话
- let messages = null
- for (let i = 0; i < this.allRecords.length; i++) {
- const element = this.allRecords[i];
- if (element.id == this.info.id) {
- messages = element
- }
- }
- console.log(messages, 'messages');
- let flag = false
- for (let i = 0; i < messages.chatCharacterList.length; i++) {
- const element = messages.chatCharacterList[i];
- console.log(element, 'element');
- if (!element.sceneId) {
- flag = true
- this.clickDialogue(messages, element, i)
- break
- }
- }
- // 如果聊天记录里没有常规对话,则新增一个常规对话
- if (!flag) {
- this.sceneId = null
- this.sceneInfo = {}
- this.newStart()
- }
- }
- },
- // 聊天记录列表-角色下拉菜单
- handleCommand2(value, value1) {
- if (value == 2) {
- this.$confirm('此操作将永久删除该角色所有聊天记录, 是否继续?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.clearRecord(value1)
- })
- }
- },
- // 聊天记录列表-角色-聊天记录下拉菜单
- handleCommand(value, value1, value2) {
- console.log(value, 'value');
- if (value == 1) {
- this.editDialogueTitle(value1, value2)
- } else if (value == 2) {
- this.$confirm('此操作将永久删除该聊天记录, 是否继续?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.clearRecord(value1, value2)
- })
- }
- },
- // 聊天记录操作相关↓
- handleCommand4(value1, value2, value3) {
- console.log(value1, 'value1');
- console.log(value2, 'value2');
- if (value1 == 1) {
- // 编辑
- let height = this.$refs[`message${value3}`][0].offsetHeight
- let width = this.$refs[`message${value3}`][0].offsetWidth
- value2.edit = true
- this.$nextTick(() => {
- this.$refs[`messageEditInput${value3}`][0].$el.children[0].style.height = height + 'px'
- this.$refs[`messageEdit${value3}`][0].style.width = width + 'px'
- })
- } else if (value1 == 2) {
- // 删除
- this.$confirm('此操作将永久删除该聊天记录, 是否继续?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.deleteRecord(value2, value3)
- })
- } else if (value1 == 3) {
- // 重新生成最后一句对话
- this.resetChat(value2, value3)
- }
- },
- // 重新生成最后一条聊天记录
- resetChat(value, index) {
- let params = {
- recordId: value.id,
- role: value.role,
- }
- deleteRecordApi(params).then(res => {
- this.returnMessage.splice(index, 1)
- this.getStreamChatWithWeb()
- })
- },
- // 编辑单条聊天记录-取消
- editCancel(value, index) {
- value.edit = false
- value.editContent = value.content
- },
- // 编辑单条聊天记录-保存
- editSave(value, index) {
- console.log(value, 'value');
- let params = {
- content: value.editContent,
- recordId: value.id,
- role: value.role,
- }
- updateRecordApi(params).then(res => {
- console.log(res, 'ressss');
- value.edit = false
- this.getChatRecord(this.recordId)
- })
- },
- // 删除单条聊天记录
- deleteRecord(value, index) {
- let params = {
- recordId: value.id,
- role: value.role,
- }
- deleteRecordApi(params).then(res => {
- this.$message({
- message: '删除成功',
- type: 'success'
- });
- this.getChatRecord(this.recordId)
- })
- },
- // 聊天记录新增对话
- async newStart_juese(value) {
- console.log(value, 'value');
- this.audioUrl = ""
- this.sceneId = null
- this.sceneInfo = {}
- this.messageOptions = []
- this.returnMessage = []
- // 点击聊天记录切换聊天
- if (this.$route.query.characterId) {
- this.$route.query.characterId = value.id
- }
- await this.getDetail(value.id)
- this.recordId = await this.addChat()
- for (let i = 0; i < this.allRecords.length; i++) {
- const element = this.allRecords[i];
- if (element.id == this.info.id) {
- element.chatCharacterList.push({
- chatTitle: "常规聊天",
- createTime: '',
- id: this.recordId
- })
- this.recordsIndex = element.chatCharacterList.length - 1
- }
- }
- },
- // 修改聊天记录标题
- editDialogueTitle(value1, value2) {
- this.$prompt('新标题名称', '修改标题', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- }).then(({ value }) => {
- let params = {
- chatTitle: value,
- id: value2.id
- }
- updateTitleApi(params).then(res => {
- console.log(res, '修改标题');
- this.$message({
- type: 'success',
- message: '修改成功!'
- });
- this.getChatCharacterRecords()
- })
- })
- },
- clearRecord(value1, value2) {
- let params = {
- characterId: value1.id,
- }
- if (value2) {
- params.recordId = value2.id
- }
- clearRecordApi(params).then(res => {
- this.$message({
- type: 'success',
- message: '删除成功!'
- });
- this.getChatCharacterRecords()
- })
- },
- async getChatRecord(recordId) {
- let params = {
- characterId: this.info.id,
- recordId: recordId
- }
- getChatRecordApi(params).then(res => {
- console.log(res, '查询到的聊天记录');
- let array = res.data
- // this.returnMessage
- this.historyRes = res.data
- if (this.returnMessage.length > 1) {
- this.returnMessage = this.returnMessage.splice(0, 1)
- }
- for (let i = 0; i < array.length; i++) {
- const element = array[i];
- let history = JSON.parse(element.history)
- history.map(item => {
- item.id = element.id
- item.uuid = element.uuid
- item.edit = false
- item.editContent = item.content
- if (item.role == 'assistant') {
- item.voiceFilePosition = element.voiceFilePosition
- }
- })
- this.returnMessage = [...this.returnMessage, ...history]
- }
- this.configForm.radio2 = this.modelList[0].id
- this.modelList.map(item => {
- if (item.id == array[array.length - 1].modelId) {
- this.configForm.radio2 = item.id
- }
- })
- })
- },
- searchHistory(characterId) {
- // 查看对话记录是否有选中的角色
- // console.log('查看对话记录是否有选中的角色');
- let flg = false
- for (let i = 0; i < this.allRecords.length; i++) {
- const element = this.allRecords[i];
- // 如果有则选中角色的最新一条记录并获取对话聊天记录
- if (element.id == characterId) {
- console.log(element, '查看对话记录是否有选中的角色');
- flg = true
- element.open = true
- // 二级对话判断当前是普通对话还是场景对话
- // 取对应的最后一条消息记录
- let chatCharacterList = element.chatCharacterList
- let chatCharacter = null
- let index = null
- for (let i = 0; i < chatCharacterList.length; i++) {
- const element2 = chatCharacterList[i];
- if (this.$route.query.sceneId == element2.sceneId) {
- chatCharacter = element2
- index = i
- } else if (!this.$route.query.sceneId && !element2.sceneId) {
- chatCharacter = element2
- index = i
- }
- }
- // 如果有聊天记录则点击
- if (chatCharacter) {
- this.clickDialogue(element, chatCharacter, index)
- } else {
- // 如果没有场景聊天记录则新增场景聊天
- // 从角色详情中获取场景列表
- let sceneList = this.info.sceneList
- // 获取当前聊天对应的场景
- for (let i = 0; i < sceneList.length; i++) {
- const element = sceneList[i];
- if (element.sceneId == this.$route.query.sceneId) {
- this.sceneInfo = element
- }
- }
- }
- // this.recordsIndex = element.chatCharacterList.length - 1
- // let recordId = element.chatCharacterList[element.chatCharacterList.length - 1].id
- // this.recordId = recordId
- // this.getChatRecord(recordId)
- }
- }
- // 如果没有聊天记录,则增加开场聊天引导
- if (!flg) {
- this.getGuidance(this.info.id)
- }
- },
- async getChatCharacterRecords() {
- let res = await getChatCharacterRecordsApi()
- console.log(res, '聊天记录');
- if (res.data) {
- for (let i = 0; i < res.data.length; i++) {
- const element = res.data[i];
- if (this.info.id == element.id) {
- element.open = true
- } else {
- element.open = false
- }
- }
- this.allRecords = res.data
- }
- },
- // 新增对话记录
- async addChat() {
- let params = {
- characterId: this.info.id,
- chatTitle: ""
- }
- if (this.sceneId) {
- params.sceneId = this.sceneId
- }
- let res = await addChatApi(params)
- console.log(res, '新增对话记录');
- return res.data
- },
- getModelList() {
- getModelListApi().then(res => {
- console.log(res, '模型列表');
- this.modelList = res.data
- })
- },
- inputBoxClick() {
- this.$refs.input.focus()
- },
- async getDetail(id) {
- let res = await detailApi(id)
- console.log(res, '角色详情');
- this.info = res.data
- this.$nextTick(() => {
- this.showPrologueButton = this.$refs.prologue.scrollHeight > this.$refs.prologue.offsetHeight
- })
- // 模型选中角色默认模型
- this.configForm.radio2 = this.info.modelId
- // 如果用户有设置过模型使用用户设置模型
- if (Cookies.get(`userConfig_${this.$store.state.user.userId}_${this.info.id}`)) {
- let userConfig = JSON.parse(Cookies.get(`userConfig_${this.$store.state.user.userId}_${this.info.id}`))
- if (userConfig.radio2) {
- this.configForm.radio2 = userConfig.radio2
- }
- }
- // let HistoryMessage = JSON.parse(localStorage.getItem(`[userId:${123},aiId:${this.info.id}]`));
- // if (HistoryMessage) {
- // this.returnMessage = HistoryMessage
- // } else {
- // this.returnMessage.push({
- // role: 'assistant',
- // content: this.info.firstContent
- // })
- // localStorage.setItem(`[userId:${123},aiId:${this.info.id}]`, JSON.stringify(this.returnMessage));
- // }
- if (this.sceneId) {
- console.log(this.sceneId);
- let sceneList = this.info.sceneList
- for (let i = 0; i < sceneList.length; i++) {
- const element = sceneList[i];
- if (element.sceneId == this.sceneId) {
- this.sceneInfo = element
- this.configForm.radio2 = element.modelId
- this.returnMessage.push({
- role: 'assistant',
- content: element.sceneWelcome
- })
- }
- }
- } else {
- console.log('fffffffffffffffffffffff');
- this.returnMessage.push({
- role: 'assistant',
- content: this.info.firstContent
- })
- }
- },
- getGuidance(id) {
- getGuidanceApi(id).then(res => {
- console.log(res, '聊天引导');
- this.messageOptions = res.data
- })
- },
- goBack() {
- this.$router.back()
- },
- async newStart() {
- // 新业务,创建一个新的对话记录
- this.recordId = await this.addChat()
- for (let i = 0; i < this.allRecords.length; i++) {
- const element = this.allRecords[i];
- if (element.id == this.info.id) {
- if (this.sceneId) {
- element.chatCharacterList.push({
- chatTitle: "场景聊天",
- createTime: '',
- id: this.recordId,
- sceneIcon: true
- })
- } else {
- element.chatCharacterList.push({
- chatTitle: "常规聊天",
- createTime: '',
- id: this.recordId
- })
- }
- this.recordsIndex = element.chatCharacterList.length - 1
- }
- }
- this.returnMessage = []
- this.getDetail(this.info.id)
- // 废弃》》
- // 清空历史数据
- // localStorage.removeItem(`[userId:${123},aiId:${this.info.id}]`);
- // this.returnMessage = []
- // this.getDetail(this.info.id)
- },
- Enterkey(e) {
- if (e.keyCode == 13) {
- console.log(this.notChatSend, 'this.notChatSend');
- if (this.notChatSend) {
- return
- }
- if (!this.content) {
- return
- }
- this.getStreamChatWithWeb()
- }
- },
- // 设置用户配置
- configConfirm() {
- console.log(this.info, 'this.info');
- // 在浏览器缓存用户的配置
- Cookies.set(`userConfig_${this.$store.state.user.userId}_${this.info.id}`, JSON.stringify(this.configForm))
- this.showConfig = false
- },
- // 前往创建场景
- toCreateScene() {
- this.$router.push({
- name: 'CreateScene',
- query: {
- characterId: this.info.id,
- }
- })
- },
- async getStreamChatWithWeb_old() {
- this.messageLoading = true
- if (!this.content) {
- return
- }
- this.returnMessage.push({
- role: 'user',
- content: this.content
- })
- let HistoryMessage = JSON.parse(localStorage.getItem(`[userId:${123},aiId:${this.info.id}]`));
- // 历史记录取最新的20条传给后端
- if (HistoryMessage && HistoryMessage.length > 20) {
- HistoryMessage = HistoryMessage.slice(HistoryMessage.length - 1, 20)
- }
- let params = {
- historyMessage: HistoryMessage || [],
- characterId: this.info.id,
- prompt: JSON.parse(JSON.stringify(this.content))
- }
- // 清空输入框的值
- this.content = ''
- // 新增一条ai信息
- this.returnMessage.push({
- role: 'assistant',
- content: ''
- })
- let res = await streamChatWithWebApi(params)
- console.log(res.data.message.content, 'res');
- let content = res.data.message.content
- let index = 0
- let xing = 1
- let messageInterval = setInterval(() => {
- if (index > content.length - 1) {
- console.log('结束');
- // 消息全部显示后存到历史localStorage
- let HistoryMessage = []
- // 历史只存100条,长度超出截取最新的
- if (this.returnMessage.length > 100) {
- HistoryMessage = JSON.stringify(this.returnMessage.slice(this.returnMessage.length - 100, 100))
- } else {
- HistoryMessage = JSON.stringify(this.returnMessage)
- }
- localStorage.setItem(`[userId:${123},aiId:${this.info.id}]`, HistoryMessage);
- clearInterval(messageInterval)
- return
- }
- console.log(content[index], 'content[index]');
- if (content[index] == "*") {
- if (xing == 1) {
- xing = 2
- this.returnMessage[this.returnMessage.length - 1].content += "("
- } else if (xing == 2) {
- xing = 1
- this.returnMessage[this.returnMessage.length - 1].content += ")"
- }
- } else {
- this.returnMessage[this.returnMessage.length - 1].content += content[index]
- }
- index += 1
- }, 50)
- },
- async getStreamChatWithWeb() {
- this.audioUrl = []
- this.audioUrlArrIndx = 0
- this.textCache = ''
- this.resError = false
- this.messageLoading = true
- this.chatLoading = true
- // 初始化定时器和audio的状态
- if (this.videoLoop) {
- clearInterval(this.videoLoop)
- this.videoLoop = null
- this.audioUrl = ''
- this.$refs.audio.currentTime = 0;
- this.$refs.audio.pause()
- }
- // 如果没有对话记录id,新增对话记录
- if (!this.recordId) {
- this.recordId = await this.addChat()
- }
- if (this.content) {
- this.returnMessage.push({
- role: 'user',
- content: this.content
- })
- }
- let HistoryMessage = JSON.parse(JSON.stringify(this.returnMessage))
- console.log(HistoryMessage, 'HistoryMessage1');
- HistoryMessage = HistoryMessage.splice(1, HistoryMessage.length)
- console.log(HistoryMessage, 'HistoryMessage2');
- // 历史记录取最新的20条传给后端
- if (HistoryMessage && HistoryMessage.length > 20) {
- HistoryMessage = HistoryMessage.slice(HistoryMessage.length - 1, 20)
- }
- let params = {
- historyMessage: HistoryMessage,
- characterId: this.info.id,
- prompt: this.content,
- modelId: this.configForm.radio2,
- recordId: this.recordId,
- }
- // 如果当前是场景对话则需要传sceneId
- if (this.sceneId) {
- params.sceneId = this.sceneId
- }
- // 新增一条ai信息
- this.returnMessage.push({
- role: 'assistant',
- content: '',
- voiceFilePosition: '',
- })
- // 清空输入框的值
- this.content = ''
- let res = await streamChatWithWebApi(params)
- console.log(res, 'res');
- this.messageLoading = false
- if (res.status != 200) {
- this.$message.error(res.statusText)
- this.returnMessage.splice(this.returnMessage.length - 1, 2)
- this.chatLoading = false
- return
- }
- const reader = res.body.getReader()
- const decoder = new TextDecoder()
- while (1) {
- const { done, value } = await reader.read()
- // console.log(done, 'done');
- if (done) {
- console.log(value, '结束value');
- this.chatLoading = false
- // if (typeof(value) == "undefined") {
- // this.$message.error('错误')
- // this.returnMessage.splice(this.returnMessage.length - 1, 1)
- // }
- // 每次对话完刷新聊天记录
- this.getChatCharacterRecords()
- let params = {
- characterId: this.info.id,
- recordId: this.recordId
- }
- let historyRes = await getChatRecordApi(params)
- this.historyRes = historyRes.data
- // 如果开启自动播放,则查询并播放语音
- // this.audioUrl = ""
- // if (!this.resError) {
- // }
- console.log('结束');
- break;
- }
- //txt就是一个一个的字 然后添加到页面上就可以了
- const txt = decoder.decode(value).split('data:')
- // 超时处理
- if (this.timeOut) {
- clearTimeout(this.timeOut)
- this.timeOut = setTimeout(() => {
- this.returnMessage[this.returnMessage.length - 1].content = 'AI智能累得打起了小盹儿,咱们让他缓一缓,再来试试!'
- this.chatLoading = false
- }, 10000)
- }
- // const txt = decoder.decode(value)
- this.addMessage(txt)
- // let data = JSON.parse(txt).message.content
- // console.log(txt, 'txt');
- // if (this.isJSON(txt) && JSON.parse(txt).code != 200) {
- // let data = JSON.parse(txt)
- // this.$message.error(data.msg)
- // this.returnMessage.splice(this.returnMessage.length - 1, 1)
- // break;
- // }
- }
- },
- addMessage(value) {
- // console.log(value, 'value');
- for (let i = 0; i < value.length; i++) {
- const element = value[i];
- if (this.isJSON(element)) {
- let value = JSON.parse(element)
- if (value.code == 401) {
- this.returnMessage.splice(this.returnMessage.length - 1, 1)
- this.noLogin(element)
- this.chatLoading = false
- break;
- }
- if (value.code == 500) {
- console.log(value, 'JSON.parse(element)');
- this.returnMessage.splice(this.returnMessage.length - 2, 2)
- this.$message.error(value.content || '系统错误请联系管理员')
- this.resError = true
- this.chatLoading = false
- break;
- }
- // 获取语音id
- if (value.code == -1) {
- this.returnMessage[this.returnMessage.length - 1].uuid = value.content
- // 如果开启了自动播放开始轮巡查询语音
- if (this.setting.value1) {
- this.audioUrlArrIndx = 0
- this.videoLoopTime = 0
- this.audioUrlArr = []
- this.loopPlay = false
- this.audioPlayIndex = this.returnMessage.length - 1
- this.loopGetVoice(value.content, this.returnMessage.length - 1)
- }
- break;
- }
- if (!value.done) {
- let txt = value.content
- this.returnMessage[this.returnMessage.length - 1].content += txt
- } else {
- // 对话流结束
- // 临时插入的ai对话记录和用户记录插入聊天id
- this.returnMessage[this.returnMessage.length - 1].id = value.content
- this.returnMessage[this.returnMessage.length - 2].id = value.content
- }
- }
- }
- },
- noLogin(value) {
- let _this = this
- MessageBox.confirm(
- value.content,
- "系统提示",
- {
- confirmButtonText: "前往登录",
- cancelButtonText: "取消",
- type: "warning",
- }
- )
- .then(() => {
- // isRelogin.show = false;
- this.$store.dispatch("LogOut").then(() => {
- // location.href = "/";
- _this.$refs.Header.showLogin()
- });
- })
- .catch(() => {
- // isRelogin.show = false;
- });
- },
- isJSON(str) {
- if (typeof str == 'string') {
- try {
- JSON.parse(str);
- return true;
- } catch (e) {
- // console.log(e);
- return false;
- }
- }
- },
- messageOptionClick(value) {
- this.content = value
- this.getStreamChatWithWeb()
- },
- // 播放聊天语音
- initAudio(index) {
- // 从聊天记录获取id
- console.log(this.returnMessage[index], 'swssssssss');
- let id = this.returnMessage[index].id
- let history = this.historyRes.map((item) => {
- if (item.id == id) {
- return item
- }
- })
- console.log(history, 'history');
- return
- this.loopGetVoice(history.id, index)
- },
- playAudio(index) {
- if (index) {
- this.audioPlayIndex = index
- }
- // this.audioUrlArrIndx = 0
- console.log(this.audioUrlArrIndx, 'this.audioUrlArrIndx');
- console.log(this.audioUrlArr, 'this.audioUrlArr');
- // console.log(audioUrlArr[this.audioUrlArrIndx].voiceAddress, 'audioUrlArr[this.audioUrlArrIndx].voiceAddress');
- // 如果当前播放的语音地址为空,则等待2秒后重新获取
- if (!this.audioUrlArr[this.audioUrlArrIndx].voiceAddress && this.videoLoopTime <= 50) {
- setTimeout(() => {
- this.playAudio(index)
- }, 2000)
- return
- }
- // 如果当前播放的语音地址为false,则跳过当前语音
- if (this.audioUrlArr[this.audioUrlArrIndx].voiceAddress == 'false' && this.audioUrlArrIndx < this.audioUrlArr.length - 1) {
- this.audioUrlArrIndx += 1
- this.playAudio(index)
- return
- } else if (this.audioUrlArrIndx > this.audioUrlArr.length - 1) {
- this.audioUrl = ''
- this.audioUrlArrIndx = 0
- this.videoLoopTime = 0
- this.audioUrlArr = []
- return
- }
- this.audioUrl = this.audioUrlArr[this.audioUrlArrIndx].voiceAddress
- setTimeout(() => {
- if (this.audioUrl && this.audioUrl != 'false') {
- this.$refs.audio.play()
- } else {
- this.audioClose()
- }
- }, 1000)
- },
- async historyGetVoice(value, index) {
- console.log(value, 'value');
- if (!value.uuid) {
- return
- }
- let params = {
- uuid: value.uuid
- }
- let fileRes = await queryVoiceListApi(params)
- console.log(fileRes.data, 'file>>>');
- this.audioUrlArr = fileRes.data.voices
- this.audioUrlArrIndx = 0
- this.videoLoopTime = 0
- this.loopPlay = false
- this.playAudio(index)
- },
- async loopGetVoice(id, index) {
- this.videoLoopTime += 1
- // 获取语音文件
- let params = {
- uuid: id
- }
- let fileRes = await queryVoiceListApi(params)
- console.log(fileRes.data, 'file>>>');
- let voices = fileRes.data.voices
- let _continue = fileRes.data.continue
- this.apiHaveVideo = _continue
- // 判断语音文件是否获取完毕
- let trueLength = 0
- for (let i = 0; i < voices.length; i++) {
- const element = voices[i];
- if (element.voiceAddress) {
- trueLength += 1
- }
- }
- if (!_continue && trueLength == voices.length) {
- if (this.videoLoop) {
- clearTimeout(this.videoLoop)
- this.videoLoop = null
- }
- // this.returnMessage[index].voiceFilePosition = fileRes.data.voiceFilePosition
- // 有语音文件则开始播放
- if (voices.length > 0) {
- this.audioUrlArr = voices
- console.log(this.audioUrlArr, '进入播放流程1');
- if (this.$refs.audio.paused || this.audioUrlArrIndx > this.audioUrlArr.length - 1) {
- if (this.loopPlay == false) {
- this.playAudio(index)
- this.loopPlay = true
- }
- }
- }
- } else {
- if (voices.length > 0) {
- this.audioUrlArr = voices
- console.log(this.audioUrlArr, '进入播放流程2');
- if (this.$refs.audio.paused || this.audioUrlArrIndx > this.audioUrlArr.length - 1) {
- if (this.loopPlay == false) {
- this.playAudio(index)
- this.loopPlay = true
- }
- }
- }
- // 没有语音文件则开启定时器每两秒查询一次
- if (this.videoLoopTime > 50) {
- // 如果调用次数超过30次则停止
- return
- }
- this.videoLoop = setTimeout(() => {
- this.loopGetVoice(id, index)
- }, 2000)
- }
- },
- audioEnd() {
- this.audioUrlArrIndx += 1
- console.log(this.audioUrlArrIndx, 'audioUrlArrIndx');
- if (this.audioUrlArrIndx < this.audioUrlArr.length && this.videoLoopTime <= 50) {
- // 如果当前播放的语音地址为空,则等待2秒后重新获取
- if (!this.audioUrlArr[this.audioUrlArrIndx].voiceAddress) {
- setTimeout(() => {
- this.playAudio()
- }, 2000)
- return
- }
- // 如果当前播放的语音地址为false,则跳过当前语音
- if (this.audioUrlArr[this.audioUrlArrIndx].voiceAddress == 'false' && this.audioUrlArrIndx < this.audioUrlArr.length - 1) {
- this.audioUrlArrIndx += 1
- this.playAudio()
- return
- }
- this.audioUrl = this.audioUrlArr[this.audioUrlArrIndx].voiceAddress
- setTimeout(() => {
- if (this.audioUrl && this.audioUrl != 'false') {
- this.$refs.audio.play()
- } else {
- this.audioClose()
- }
- }, 100)
- } else {
- this.audioClose()
- }
- },
- audioClose() {
- this.audioUrlArrIndx = 0
- this.audioPlayIndex = null
- },
- ChangeSettingValue1(value) {
- console.log(value, 'value');
- if (value) {
- queryUserBalanceApi().then(res => {
- console.log(res, '用户余额');
- if (res.data <= 0) {
- this.setting.value1 = false
- this.$message({
- message: '余额不足,无法开启次功能',
- type: 'error'
- });
- }
- })
- }
- },
- // 场景业务相关↓
- async sceneChange(item) {
- console.log(item, 'item');
- this.$message({
- message: `已进入场景${item.sceneName}`,
- type: 'success'
- });
- // 当用户选中场景
- this.sceneInfo = item
- // 切换当前场景id
- this.sceneId = item.sceneId
- // 情况聊天记录
- this.returnMessage = []
- // 新建场景对话
- this.newStart()
- // 增加开场白
- // this.returnMessage.push({
- // role: 'assistant',
- // content: item.sceneWelcome
- // })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .fullScreenButton {
- position: absolute;
- top: 50%;
- left: 0;
- transform: translateX(-50%) translateY(-50%);
- z-index: 50;
- background: #fff;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 1.6rem;
- height: 1.6rem;
- cursor: pointer;
- }
- .chat {
- height: 100vh;
- }
- .leftInfo {
- width: 375px;
- height: 100%;
- padding: 32px 24px;
- overflow-y: auto;
- >.history {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- >.historyBox {
- padding: 8px;
- border-radius: 15px;
- border: solid 1px var(--color1);
- margin-bottom: 10px;
- .top {
- >.photo {
- >img {
- width: 48px;
- height: 48px;
- border-radius: 50%;
- }
- }
- >.info {
- width: calc(100% - 60px - 16px);
- >div {
- overflow: hidden;
- /* 确保超出容器的文本被裁剪 */
- white-space: nowrap;
- /* 确保文本在一行内显示 */
- text-overflow: ellipsis;
- /* 使用省略号表示文本超出 */
- }
- }
- }
- }
- }
- >.chatInfo {
- overflow: hidden;
- .chatInfo_photo {
- >img {}
- }
- .hot {
- color: #f03d3d;
- background: #fff1f1;
- }
- .tags {
- margin-top: 10px;
- .tag {
- display: inline-flex;
- justify-content: center;
- padding: 5px 10px;
- border-radius: 4px;
- border: solid 1px var(--color1);
- margin-right: 5px;
- }
- }
- }
- }
- .content {
- z-index: 40;
- position: absolute;
- right: 0;
- background-repeat: no-repeat;
- // background-attachment: fixed;
- background-size: cover;
- background-color: #fff;
- background-position: center center;
- display: flex;
- height: 100%;
- justify-content: center;
- width: calc(100% - 375px);
- border-left: solid 1px var(--color1);
- transition: width 0.5s ease;
- >.chat-box {
- position: relative;
- background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4) 0%, rgba(255, 255, 255, 0) 20%, rgba(255, 255, 255, 0) 75%, rgba(0, 0, 0, 0.4) 100%);
- background-size: auto;
- // border: 1px solid #635677 !important;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- height: 100%;
- width: 100%;
- padding: 55px 25px 170px 25px;
- >.chatBoxTitle {
- color: #fff;
- margin-top: 15px;
- width: calc(100% - 50px);
- height: 30px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- }
- >.mask {
- background: rgba(0, 0, 0, 0.5);
- }
- }
- .contentFull {
- width: 100%;
- }
- .historyActive {
- background: var(--color1);
- }
- .dialogue:hover {
- background: var(--color1);
- .dialogueIconBg {
- display: flex;
- }
- }
- .dialogueIconBg {
- display: none;
- background: linear-gradient(90deg, rgba(0, 0, 0, 0) 10%, var(--color1) 50%, var(--color1) 100%);
- }
- .messages {
- height: calc(100% - 68px);
- overflow-y: auto;
- }
- .messages::-webkit-scrollbar {
- width: 0px;
- }
- .messageRight {
- max-width: calc(100% - 72px);
- // min-width: 400px;
- }
- .yyPlayBg {
- // background: rgba(103, 103, 168, 1);
- // border-radius: 999px;
- // position: absolute;
- .icon {
- height: 24px;
- width: 96px;
- }
- }
- .yyPlay {
- width: 15px;
- height: 15px;
- // background: url('../../assets/images/播放/yyPlay.gif') no-repeat;
- // background-size: 170% 170%;
- // background-position: 50% 50%;
- // animation: heart-burst steps(28) 0.9s infinite both;
- // animation-play-state: paused;
- // height: 50px;
- // background: #fff;
- }
- .message {
- // background: #ffffff0f;
- // border: 1px solid #5b5b5e;
- background: var(--bg-color3);
- color: #fff;
- font-size: 14px;
- // flex: 1;
- }
- .messageUser {
- background: rgba(255, 255, 255, 0.9);
- border: 1px solid var(--color1);
- // max-width: calc(100% - 72px);
- font-size: 14px;
- width: auto;
- // min-width: 400px;
- }
- .photo {
- width: 56px;
- }
- .me {
- flex-direction: row-reverse;
- }
- .loadingMessage {
- position: relative;
- // display: flex;
- // justify-content: center;
- width: 120px;
- height: 64px;
- }
- .messageOptions {
- // margin-top: 20px;
- display: flex;
- flex-wrap: wrap;
- justify-content: space-around;
- min-width: 400px;
- .option {
- background: #ade4ff32;
- // border: 1px solid #5b5b5e;
- border-radius: 10px;
- padding: 10px;
- width: 40%;
- height: 50px;
- margin-top: 10px;
- cursor: pointer;
- }
- }
- .inputBox {
- border: solid 1px var(--color1);
- border-radius: 10px;
- padding: 24px;
- background: #fff;
- max-width: 900px;
- margin: 0 auto;
- }
- .planeColor {
- color: var(--bg-color1);
- }
- .prologue {
- position: relative;
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
- overflow: hidden;
- padding-bottom: 4px;
- .textButton {
- // display: inline-block;
- float: right;
- clear: both;
- color: #fff;
- padding: 0 5px;
- border-radius: 5px;
- background: var(--bg-color1);
- font-size: 12px;
- cursor: pointer;
- }
- }
- .prologueOpen {
- -webkit-line-clamp: 20;
- }
- .prologueOpen::before {}
- .prologue::before {
- content: '';
- float: right;
- // width: 10px;
- height: calc(100% - 20px);
- /*先随便设置一个高度*/
- background: red
- }
- </style>
- <style scoped>
- .loadingMessage>>>.el-loading-parent--relative {
- width: 100%;
- height: 100%;
- }
- .loadingMessage>>>.el-loading-spinner {
- display: flex;
- justify-content: center;
- }
- .mButton {
- border: solid 0px;
- }
- .radio>>>.el-radio-button {
- margin-bottom: 5px;
- margin-right: 10px;
- /* border-left: solid 1px #DCDFE6; */
- }
- .radio>>>.el-radio-button__inner {
- border-left: solid 1px #DCDFE6;
- border-radius: 4px;
- }
- .radio>>>.el-radio-button__orig-radio:checked+.el-radio-button__inner {
- border-left: solid 1px var(--bg-color1);
- background-color: var(--bg-color1);
- border-color: var(--bg-color1);
- -webkit-box-shadow: -1px 0 0 0 var(--bg-color1);
- box-shadow: -1px 0 0 0 var(--bg-color1);
- }
- .message:hover>>>.messageButton,
- .messageUser:hover>>>.messageButton {
- display: block;
- }
- .messageButton {
- display: none;
- width: 25px;
- height: 25px;
- padding: 0;
- }
- .messageDropdown {
- position: absolute;
- bottom: -12px;
- right: 10px;
- }
- .eidtTextarea>>>.el-textarea__inner {
- padding: 0;
- background: none;
- border: 0;
- color: #fff;
- }
- .messageUser>>>.el-textarea__inner {
- color: #000;
- }
- .messageEdit {
- min-width: 400px;
- }
- </style>
|