dialogArea.vue 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788
  1. <template>
  2. <div class="dialog">
  3. <div v-show="cardType == 0">
  4. <div class="d_top" ref="chatRef">
  5. <div class="d_t_chat" v-for="(item, index) in chatList" :key="index">
  6. <div
  7. class="d_t_c_user"
  8. v-if="item.content && item.content != 'addAsk'"
  9. >
  10. <div class="d_t_c_u_left">
  11. <div class="d_t_c_u_l_content">{{ item.content }}</div>
  12. <div class="d_t_c_u_l_time">{{ item.createtime }}</div>
  13. </div>
  14. <div class="d_t_c_u_right">
  15. <span>Me</span>
  16. </div>
  17. </div>
  18. <div class="d_t_c_ai" v-if="item.content != 'addAsk'">
  19. <div class="d_t_c_a_left">
  20. <el-avatar v-if="item.filename" :src="item.filename"></el-avatar>
  21. <span v-else>AI</span>
  22. </div>
  23. <div class="d_t_c_a_right">
  24. <div
  25. class="d_t_c_a_r_content"
  26. style="display: flex;justify-content: space-between;flex-wrap: wrap;"
  27. v-if="pan(item.aiContent).length"
  28. >
  29. <div
  30. v-if="!pan(item.aiContent).length"
  31. class="d_t_c_a_r_content"
  32. v-loading="item.loading"
  33. v-html="item.aiContent"
  34. ></div>
  35. <div
  36. v-else
  37. v-for="i in pan(item.aiContent)"
  38. style="position: relative;"
  39. class="d_t_c_a_r_c_img"
  40. >
  41. <img
  42. style="width: 130px;height: 130px;object-fit: cover;"
  43. :src="i.image"
  44. alt=""
  45. @click="previewImg(i.image)"
  46. />
  47. <span class="download_image" @click.stop="download(i.image)">
  48. <img
  49. :src="
  50. require('../../../assets/icon/fileIcon/download.png')
  51. "
  52. />
  53. </span>
  54. </div>
  55. </div>
  56. <div
  57. v-else
  58. class="d_t_c_a_r_content"
  59. v-loading="item.loading"
  60. v-html="htmlContent(item.aiContent)"
  61. ></div>
  62. <div
  63. v-if="!pan(item.aiContent).length && !item.loading"
  64. class="aiCopy"
  65. >
  66. <img
  67. @click="onCopy(item.aiContent)"
  68. style="width: 30px;"
  69. src="../../../assets/icon/course/copyTxt.png"
  70. alt=""
  71. />
  72. <img @click.stop="aiTalkAll(item)" v-if="aiTalkUid==item.uid && aiIsTalk" style="width: 15px;margin:7px 0 7px 7px;" :src="require('../../../assets/icon/course/megaphone.svg')">
  73. <img @click.stop="aiTalkAll(item)" v-else style="width: 15px;margin:7px 0 7px 7px;" :src="require('../../../assets/icon/course/megaphone3.svg')">
  74. <img v-if="chatList.length-2 == index" @click.stop="refresh(item)" style="width: 15px;margin:7px 0 7px 7px;" :src="require('../../../assets/icon/course/refresh.svg')">
  75. </div>
  76. <div class="d_t_c_a_r_time">{{ item.createtime }}</div>
  77. </div>
  78. </div>
  79. <div
  80. class="s_t_addAsk"
  81. v-if="
  82. item.content == 'addAsk' &&
  83. !item.aiContent.questions &&
  84. item.aiContent.length &&
  85. !item.loading
  86. "
  87. >
  88. <span
  89. v-for="item2 in item.aiContent"
  90. :key="item2.index"
  91. @click.stop="send(item2.label)"
  92. >{{ item2.label }}</span
  93. >
  94. </div>
  95. <div
  96. class="s_t_addAsk"
  97. v-if="
  98. item.content == 'addAsk' &&
  99. item.aiContent.questions &&
  100. !item.loading
  101. "
  102. >
  103. <span
  104. v-for="(item2, index2) in item.aiContent.questions"
  105. :key="index2"
  106. @click.stop="send(item2.question ? item2.question : item2)"
  107. >{{ item2.question ? item2.question : item2 }}</span
  108. >
  109. </div>
  110. <div
  111. class="s_t_addAsk"
  112. v-if="item.content == 'addAsk' && item.loading"
  113. >
  114. <span style="width:50px;height:50px" v-loading="true"></span>
  115. </div>
  116. </div>
  117. </div>
  118. <div class="d_bottom">
  119. <div class="s_b_btnAreaTop">
  120. <div class="s_b_bat_left">
  121. <el-tooltip
  122. class="item"
  123. effect="dark"
  124. content="Clear chat history"
  125. placement="top"
  126. >
  127. <img
  128. :src="require('../../../assets/icon/course/clean.svg')"
  129. @click.stop="clear()"
  130. />
  131. </el-tooltip>
  132. <el-tooltip
  133. class="item"
  134. effect="dark"
  135. :content="openMegaphone ? 'Turn off the megaphone' : 'Turn on the megaphone'"
  136. placement="top"
  137. >
  138. <img
  139. v-if="!openMegaphone"
  140. :src="require('../../../assets/icon/course/megaphone2.svg')"
  141. @click.stop="$parent.changeMegaphone()"
  142. />
  143. <img
  144. v-else
  145. :src="require('../../../assets/icon/course/megaphone.svg')"
  146. @click.stop="$parent.changeMegaphone()"
  147. />
  148. </el-tooltip>
  149. </div>
  150. <div class="s_b_bat_right">
  151. <!-- <img :src="require('../../../assets/icon/course/bulb.svg')"> -->
  152. <img :src="require('../../../assets/icon/course/bulb2.svg')">
  153. </div>
  154. </div>
  155. <div class="d_b_btnArea">
  156. <div class="d_b_ba-item" @click.stop="choiceRole()">
  157. <img
  158. style="width: 20px;"
  159. src="../../../assets/icon/course/role.png"
  160. alt=""
  161. />
  162. Choose Intelligent Agent
  163. </div>
  164. </div>
  165. <div class="d_b_inputArea">
  166. <!-- <div class="d_b_tape" @click="goTape()"></div> -->
  167. <div class="d_b_input">
  168. <el-input
  169. :disabled="loading || chatLoading || sendFnType == 1"
  170. v-loading="loading || chatLoading"
  171. @keyup.enter.native="send()"
  172. :placeholder="
  173. sendFnType == 0
  174. ? 'Please enter the content you want to know here'
  175. : 'Please click the recording button to start recording'
  176. "
  177. class="d_b_i_left"
  178. v-model="text"
  179. ></el-input>
  180. <!-- <div class="d_b_i_right" @click="sendFile()">
  181. <span></span>
  182. </div> -->
  183. </div>
  184. <div class="voice_or_keyboard">
  185. <el-tooltip
  186. v-if="sendFnType == 0"
  187. class="item"
  188. effect="dark"
  189. content="Use voice"
  190. placement="top"
  191. >
  192. <img
  193. :src="require('../../../assets/icon/course/voice.svg')"
  194. @click.stop="changeFnType(1)"
  195. />
  196. </el-tooltip>
  197. <el-tooltip
  198. v-if="sendFnType == 1"
  199. class="item"
  200. effect="dark"
  201. content="Use keyboard"
  202. placement="top"
  203. >
  204. <img
  205. :src="require('../../../assets/icon/course/keyboard.svg')"
  206. @click.stop="changeFnType(0)"
  207. />
  208. </el-tooltip>
  209. </div>
  210. <div class="d_b_btn" @click="send()" v-if="sendFnType == 0">
  211. <span v-if="!loading && !chatLoading"></span>
  212. <div v-else @click.stop="stopSend()">Stop</div>
  213. </div>
  214. <div class="d_b_btn" v-if="sendFnType == 1">
  215. <img
  216. v-if="!loading && !chatLoading && !isTalk"
  217. @click.stop="talk()"
  218. :src="require('../../../assets/icon/course/voice2.svg')"
  219. />
  220. <img
  221. style="width:50px;height:50px"
  222. v-else-if="!loading && !chatLoading && isTalk"
  223. @click.stop="stopTalk()"
  224. :src="require('../../../assets/icon/course/isTape.svg')"
  225. />
  226. <div v-else @click.stop="stopSend()">Stop</div>
  227. </div>
  228. </div>
  229. </div>
  230. </div>
  231. <div class="" v-show="cardType == 1">
  232. <div class="choiceTop">
  233. <div class="choiceRoleHeader">
  234. <div>Switch Role:</div>
  235. <span>Please choose which role you would like to answer your question:</span>
  236. </div>
  237. <div class="choiceSelect">
  238. <el-button
  239. class="option"
  240. :style="{
  241. background: sortOption == 0 ? '#36A9FC' : '',
  242. color: sortOption == 0 ? '#fff' : ''
  243. }"
  244. @click="optBtn(0)"
  245. plain
  246. >My</el-button
  247. >
  248. <el-button
  249. class="option"
  250. :style="{
  251. background: sortOption == 1 ? '#36A9FC' : '',
  252. color: sortOption == 1 ? '#fff' : ''
  253. }"
  254. @click="optBtn(1)"
  255. plain
  256. >Community</el-button
  257. >
  258. </div>
  259. <div
  260. class="characterBlock"
  261. v-if="sortOption == 0"
  262. v-for="(item, index) in roleList"
  263. :key="item.id"
  264. @click.stop="choseRole(item)"
  265. >
  266. <div class="imgLeft">
  267. <div class="img">
  268. <img style="width: 100%;height: 100%;" :src="item.avatar" />
  269. </div>
  270. </div>
  271. <div class="txtRight">
  272. <div class="bir">{{ item.assistantName }}</div>
  273. <div
  274. :style="{
  275. color: '#fff',
  276. display:
  277. choseRoleItem.assistant_id == item.assistant_id
  278. ? 'block'
  279. : 'none'
  280. }"
  281. >
  282. Selected
  283. </div>
  284. <!-- <span></span> -->
  285. </div>
  286. </div>
  287. <div
  288. class="characterBlock"
  289. v-if="sortOption == 1"
  290. v-for="(item, index) in roleList2"
  291. :key="item.id"
  292. @click.stop="choseRole(item)"
  293. >
  294. <div class="imgLeft">
  295. <div class="img">
  296. <img
  297. style="width: 100%;height: 100%;"
  298. :src="
  299. item.headUrl
  300. ? item.headUrl
  301. : require('../../../assets/icon/course/ai.png')
  302. "
  303. />
  304. </div>
  305. </div>
  306. <div class="txtRight">
  307. <div class="bir">{{ item.assistantName }}</div>
  308. <div
  309. :style="{
  310. color: '#fff',
  311. display:
  312. choseRoleItem.assistant_id == item.assistant_id
  313. ? 'block'
  314. : 'none'
  315. }"
  316. >
  317. Selected
  318. </div>
  319. <!-- <span></span> -->
  320. </div>
  321. </div>
  322. <!-- <div class="characterBlock" @click="addCharacter">
  323. <div class="imgLeft">
  324. <div class="img2">
  325. <img style="width: 100%;height: 100%;" src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/basil_add-outline1715564539170.png">
  326. </div>
  327. </div>
  328. <div class="txtRight">
  329. <div style="color: #fff;margin-left: 5px;">添加新角色</div>
  330. </div>
  331. </div> -->
  332. <!-- <div class="filterSubjects">
  333. <div class="fs_title">筛选科目</div>
  334. <div class="fs_box">
  335. <div :class="['fs_b_item',subjectsType==index?'fs_b_itemActive':'']" v-for="(item,index) in subjectsList" :key="index" @click="subjectsType = index">{{ item }}</div>
  336. </div>
  337. </div>
  338. <div class="roleList">
  339. <div class="r_title">角色列表 ({{ roleList.length }})</div>
  340. <div class="r_box">
  341. <div :class="['r_b_item',roleType==index?'r_b_itemActive':'']" v-for="(item,index) in roleList" :key="item.id" @click.stop="roleType=index">
  342. <img :src="item.avatar">
  343. <span>{{ item.name }}</span>
  344. </div>
  345. </div>
  346. </div> -->
  347. </div>
  348. <div class="choiceBottom">
  349. <el-button class="cb_btn" size="mini" @click="noChangeRole()"
  350. >Cancel</el-button
  351. >
  352. <el-button
  353. class="cb_btn"
  354. size="mini"
  355. type="primary"
  356. @click="changeRole()"
  357. >Confirm</el-button
  358. >
  359. </div>
  360. </div>
  361. <iframe
  362. allow="camera *; microphone *;display-capture;midi;encrypted-media;"
  363. src="https://beta.cloud.cocorobo.cn/browser/public/index.html"
  364. ref="iiframe"
  365. v-show="false"
  366. ></iframe>
  367. <!-- Text to Speech -->
  368. <iframe
  369. allow="camera *; microphone *;display-capture;midi;encrypted-media;"
  370. src="https://beta.cloud.cocorobo.cn/browser/public/index1.html"
  371. ref="iiframe2"
  372. v-show="false"
  373. ></iframe>
  374. </div>
  375. </template>
  376. <script>
  377. import { v4 as uuidv4 } from "uuid";
  378. import MarkdownIt from "markdown-it";
  379. var OpenCC = require("opencc-js");
  380. let converter = OpenCC.Converter({
  381. from: "hk",
  382. to: "cn"
  383. });
  384. export default {
  385. props: {
  386. fileId: {
  387. type: Array,
  388. default: () => []
  389. },
  390. openMegaphone: {
  391. type: Boolean,
  392. default: false
  393. }
  394. },
  395. data() {
  396. return {
  397. sendFnType: 0,
  398. isTalk: false,
  399. cardType: 0, //0-对话 1-选角色
  400. userid: this.$route.query.userid,
  401. courseId: this.$route.query.courseId,
  402. org: this.$route.query.org,
  403. choseRoleItem: {},
  404. text: "",
  405. sortOption: 0, //切换角色 0我的 1 社区
  406. subjectsList: [
  407. "语文",
  408. "数学",
  409. "英语",
  410. "科学",
  411. "信息",
  412. "历史",
  413. "地理",
  414. "政治",
  415. "生物",
  416. "化学",
  417. "物理",
  418. "其他"
  419. ],
  420. subjectsType: -1,
  421. rightSubjects: -1,
  422. roleType: -1,
  423. rightRole: -1,
  424. loading: false,
  425. chatLoading: false,
  426. roleList2: [],
  427. chatList: [],
  428. nowChatList: [],
  429. source: null,
  430. saveUid: "",
  431. aiTalkList: [],
  432. aiIsTalk: false,
  433. aiTalkUid: "",
  434. userName:"",
  435. };
  436. },
  437. computed: {
  438. pan() {
  439. return content => {
  440. try {
  441. return JSON.parse(content);
  442. } catch (error) {
  443. return [];
  444. }
  445. };
  446. },
  447. htmlContent() {
  448. const md = new MarkdownIt();
  449. return _md => {
  450. return md.render(_md);
  451. };
  452. }
  453. },
  454. methods: {
  455. refresh(item) {
  456. this.send(item.content);
  457. },
  458. changeFnType(newValue) {
  459. if (this.isTalk) return this.$message.info("Please stop recording first");
  460. this.sendFnType = newValue;
  461. },
  462. talk() {
  463. let iiframe = this.$refs["iiframe"];
  464. iiframe.contentWindow.window.document.getElementById(
  465. "languageOptions"
  466. ).selectedIndex = 2; //普通话
  467. iiframe.contentWindow.testdoContinuousPronunciationAssessment();
  468. this.isTalk = true;
  469. iiframe.contentWindow.onRecognizedResult = e => {
  470. let _msg = e.privText;
  471. console.log(_msg)
  472. if (_msg) this.text += _msg;
  473. };
  474. },
  475. stopTalk() {
  476. if (!this.isTalk) return this.$message.info("请先开始录音");
  477. //this.isTalk = false;
  478. let iiframe = this.$refs["iiframe"];
  479. iiframe.contentWindow.window.document
  480. .getElementById("scenarioStopButton")
  481. .click();
  482. iiframe.contentWindow.onSessionStopped = (s, e) => {
  483. this.isTalk = false;
  484. this.send();
  485. };
  486. },
  487. stopSend() {
  488. if (this.source) {
  489. this.source.close();
  490. if (this.chatList[this.chatList.length - 1].content == "wanSearch") {
  491. this.chatList.pop();
  492. }
  493. this.loading = false;
  494. this.chatLoading = false;
  495. this.source = null;
  496. this.insertChat(this.saveUid);
  497. }
  498. },
  499. onCopy(content) {
  500. // 创建临时textarea元素
  501. const tempInput = document.createElement("textarea");
  502. tempInput.value = content; // 设置要复制的内容
  503. // 隐藏元素
  504. tempInput.style.position = "absolute";
  505. tempInput.style.left = "-9999px";
  506. // 将元素添加到DOM中
  507. document.body.appendChild(tempInput);
  508. // 选中元素内容
  509. tempInput.select();
  510. // 执行复制操作
  511. document.execCommand("copy");
  512. // 移除临时元素
  513. document.body.removeChild(tempInput);
  514. this.$message({
  515. message: "复制成功",
  516. type: "success"
  517. });
  518. },
  519. previewImg(url) {
  520. this.$hevueImgPreview(url);
  521. },
  522. clear() {
  523. this.chatList = [];
  524. },
  525. // addCharacter(){
  526. // this.$message.info("点击了添加新角色")
  527. // },
  528. optBtn(val) {
  529. this.sortOption = val;
  530. },
  531. choiceRole() {
  532. if (this.loading) return this.$message.info("请稍等");
  533. this.cardType = 1;
  534. },
  535. // sendFile() {
  536. // if (this.loading) return this.$message.info("请稍等");
  537. // this.$message.info("点击了附件");
  538. // },
  539. // goTape() {
  540. // if (this.loading) return this.$message.info("请稍等");
  541. // this.$message.info(`点击了语音`);
  542. // },
  543. send(_text = this.text) {
  544. if (this.loading || this.chatLoading) return this.$message.info("请稍等");
  545. if (_text.trim().length == 0) return this.$message.info("请输入内容");
  546. this.chatLoading = true;
  547. if (this.choseRoleItem.assistant_id) {
  548. let _uid = uuidv4();
  549. let _item = this.choseRoleItem;
  550. this.chatList.push({
  551. loading: true,
  552. role: "user",
  553. content: `${_text}`,
  554. uid: _uid,
  555. AI: "AI",
  556. aiContent: "",
  557. oldContent: "",
  558. isShowSynchronization: false,
  559. filename: _item.headUrl,
  560. index: this.chatList.length,
  561. is_mind_map: false,
  562. fileid: _item.assistantName
  563. // createtime: new Date().toLocaleString().replaceAll("/", "-")
  564. });
  565. this.text = "";
  566. let params = {
  567. assistant_id: this.choseRoleItem.assistant_id,
  568. userId: this.userid,
  569. message: _text,
  570. session_name: `${this.courseId}-studyStudent-md`,
  571. uid: _uid,
  572. file_ids: this.fileId
  573. };
  574. this.ajax
  575. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
  576. .then(res => {
  577. if (
  578. converter(res.data.FunctionResponse.result) ==
  579. converter("发送成功")
  580. ) {
  581. } else {
  582. this.chatLoading = false;
  583. console.log(res.data.FunctionResponse.result);
  584. //this.$message.warning(res.data.FunctionResponse.result);
  585. }
  586. })
  587. .catch(err => {
  588. this.chatLoading = false;
  589. console.log(err);
  590. });
  591. this.saveUid = _uid;
  592. this.getAtAuContent(_uid);
  593. } else {
  594. let _uuid = uuidv4();
  595. this.chatList.push({
  596. role: "user",
  597. content: `${_text}`,
  598. uid: _uuid,
  599. AI: "AI",
  600. aiContent: "",
  601. oldContent: "",
  602. isShowSynchronization: false,
  603. filename: "",
  604. index: this.chatList.length,
  605. is_mind_map: false,
  606. loading: true
  607. });
  608. this.scrollBottom();
  609. let history = [];
  610. this.nowChatList.forEach(i => {
  611. if (i.content == "wanSearch") {
  612. return history.push({
  613. role: "assistant",
  614. content: JSON.stringify(i.aiContent)
  615. });
  616. } else if (i.content == "getImage") {
  617. return history.push({
  618. role: "assistant",
  619. content: i.aiContent
  620. });
  621. }
  622. if (i.content) {
  623. history.push({
  624. role: "user",
  625. content: i.content
  626. });
  627. }
  628. if (i.aiContent) {
  629. history.push({
  630. role: "assistant",
  631. content: i.aiContent
  632. });
  633. }
  634. });
  635. history.push({ role: "user", content: _text });
  636. let params = {
  637. assistant_id: "f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b",
  638. userId: this.userid,
  639. message: _text,
  640. session_name: `${this.courseId}-studyStudent-md`,
  641. uid: _uuid,
  642. file_ids: this.fileId
  643. };
  644. // history.pop();
  645. // let params = {
  646. // model: "gpt-3.5-turbo",
  647. // temperature: 0,
  648. // max_tokens: 4096,
  649. // top_p: 1,
  650. // frequency_penalty: 0,
  651. // presence_penalty: 0,
  652. // messages: history,
  653. // uid: _uuid,
  654. // mind_map_question: _text
  655. // };
  656. // let params = {
  657. // message: {
  658. // anthropic_version: "bedrock-2023-05-31",
  659. // max_tokens: 4096,
  660. // temperature: 0,
  661. // top_p: 1,
  662. // messages: history
  663. // },
  664. // uid: _uuid,
  665. // model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
  666. // };
  667. this.text = "";
  668. console.log("发送信息", params);
  669. this.ajax
  670. // .post("https://claude3.cocorobo.cn/chat", params)
  671. // .post("https://gpt4.cocorobo.cn/chat", params)
  672. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
  673. .then(res => {
  674. if (
  675. converter(res.data.FunctionResponse.result) ==
  676. converter("发送成功")
  677. ) {
  678. } else {
  679. this.chatLoading = false;
  680. // this.$message.warning(res.data.FunctionResponse.result);
  681. console.log(res.data.FunctionResponse.result);
  682. }
  683. })
  684. .catch(e => {
  685. this.chatLoading = false;
  686. console.log(e);
  687. });
  688. this.saveUid = _uuid;
  689. this.getAtAuContent(_uuid);
  690. // this.getAiContent(_uuid);
  691. }
  692. },
  693. // 获取ai对话
  694. getAiContent(_uid) {
  695. // this.source = new EventSource(`https://claude3.cocorobo.cn/streamChat/${_uid}`);
  696. // this.source = new EventSource(`https://gpt4.cocorobo.cn/question/${_uid}`);
  697. // this.source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
  698. let _allText = "";
  699. let _mdText = "";
  700. // const md = new MarkdownIt();
  701. this.source.onmessage = _e => {
  702. if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
  703. //对话已经完成
  704. _mdText = _mdText.replace("_", "");
  705. this.source.close();
  706. this.scrollBottom();
  707. this.chatLoading = false;
  708. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  709. this.chatList.find(i => i.uid == _uid).isalltext = true;
  710. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  711. this.chatList.find(i => i.uid == _uid).loading = false;
  712. this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
  713. this.addAsk(this.chatList.find(i => i.uid == _uid).content);
  714. // 这里保存对话
  715. this.insertChat(_uid);
  716. return;
  717. } else {
  718. //对话还在继续
  719. let _text = "";
  720. _text = _e.data.replaceAll("'", "");
  721. if (_allText == "") {
  722. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  723. } else {
  724. _allText += _text;
  725. }
  726. _mdText = _allText + "_";
  727. _mdText = _mdText.replace(/\\n/g, "\n");
  728. _mdText = _mdText.replace(/\\/g, "");
  729. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  730. //转化返回的回复流数据
  731. // _mdText = md.render(_mdText);
  732. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  733. this.chatList.find(i => i.uid == _uid).loading = false;
  734. this.scrollBottom();
  735. // 处理流数据
  736. }
  737. };
  738. },
  739. getAtAuContent(_uid) {
  740. this.source = new EventSource(
  741. `https://gpt4.cocorobo.cn/question/${_uid}`
  742. );
  743. //http://gpt4.cocorobo.cn:8011/question/ https://gpt4.cocorobo.cn/question/
  744. let _allText = "";
  745. let _mdText = "";
  746. let _index = 0;
  747. let _talkText = "";
  748. // const md = new MarkdownIt();
  749. this.source.onmessage = _e => {
  750. let _eData = JSON.parse(_e.data);
  751. if (_eData.content.replace("'", "").replace("'", "") == "[DONE]") {
  752. let _result = [];
  753. if ("result" in _eData) {
  754. _result = _eData.result;
  755. for (let i = 0; i < _result.length; i++) {
  756. _mdText = _mdText.replace(_result[i].text, _result[i].fileName);
  757. }
  758. }
  759. _mdText = _mdText.replace("_", "");
  760. if (this.openMegaphone && this.aiTalkUid == _uid) {
  761. this.aiTalkUid = "";
  762. if (_talkText != "") {
  763. let _resultText = this.removeMarkdown(_talkText);
  764. this.aiTalkList.push(_resultText);
  765. _talkText = "";
  766. if (!this.aiIsTalk) this.aiTalk(1);
  767. }
  768. }
  769. this.chatLoading = false;
  770. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  771. this.chatList.find(i => i.uid == _uid).isalltext = true;
  772. this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
  773. this.chatList.find(i => i.uid == _uid).loading = false;
  774. this.nowChatList.push(this.chatList.find(i => i.uid == _uid));
  775. this.addAsk(this.chatList.find(i => i.uid == _uid).content);
  776. this.source.close();
  777. this.insertChat(_uid);
  778. } else {
  779. _index += 1;
  780. let _text = _eData.content.replace("'", "").replace("'", "");
  781. if (_allText == "") {
  782. _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
  783. _talkText += _text.replace(/^\n+/, "");
  784. } else {
  785. _allText += _text;
  786. _talkText += _text;
  787. }
  788. _mdText = _allText + "_";
  789. _mdText = _mdText.replace(/\\n/g, "\n");
  790. _mdText = _mdText.replace(/\\/g, "");
  791. if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
  792. //转化返回的回复流数据
  793. // _mdText = md.render(_mdText);
  794. if (_index == 10) {
  795. this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
  796. this.chatList.find(i => i.uid == _uid).loading = false;
  797. this.$nextTick(() => {
  798. this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
  799. });
  800. _index = 0;
  801. }
  802. if (this.openMegaphone && /[,。:;?!)]/.test(_talkText)) {
  803. let _resultText = this.removeMarkdown(_talkText);
  804. if (this.aiTalkUid != _uid) {
  805. this.aiTalkList = [];
  806. }
  807. this.aiTalkList.push(_resultText);
  808. _talkText = "";
  809. if (this.aiTalkUid != _uid) {
  810. this.aiTalkUid = _uid;
  811. this.aiTalk(0);
  812. } else if (!this.aiIsTalk) {
  813. this.aiTalk(1);
  814. }
  815. }
  816. // 处理流数据
  817. }
  818. };
  819. },
  820. //保存消息
  821. async insertChat(_uid) {
  822. if (_uid == "") return;
  823. let _data = this.chatList.find(i => i.uid == _uid);
  824. if (!_data) return;
  825. let params = {
  826. userId: this.userid,
  827. userName: this.userName?this.userName:await this.getUser(this.userid),
  828. groupId: "602def61-005d-11ee-91d8-005056b8q12w",
  829. answer: _data.aiContent,
  830. problem: _data.content,
  831. file_id: _data.fileid ? _data.fileid : "",
  832. alltext: _data.aiContent,
  833. type: "chat",
  834. filename: _data.filename,
  835. session_name: `${this.courseId}-studyStudent-md` //这是对话记录位置
  836. };
  837. this.saveUid = "";
  838. this.ajax
  839. .post("https://gpt4.cocorobo.cn/insert_chat", params)
  840. .then(res => {});
  841. },
  842. getUser(uid) {
  843. return new Promise(resolve => {
  844. let params = { uid: uid };
  845. this.ajax
  846. .get(this.$store.state.api + "getUser", params)
  847. .then(res => {
  848. let data = res.data[0][0];
  849. this.userName = data.username;
  850. resolve(data.username)
  851. })
  852. .catch(err => {
  853. console.error(err);
  854. });
  855. });
  856. },
  857. // 获取对应的聊天记录
  858. getChatList() {
  859. return new Promise((resolve, reject) => {
  860. if (this.loading) return this.$message.info("请稍等...");
  861. this.chatList = [];
  862. this.loading = true;
  863. this.chatLoading = true;
  864. let params = {
  865. userid: this.userid,
  866. groupid: "602def61-005d-11ee-91d8-005056b8q12w",
  867. // session_name:``
  868. session_name: `${this.courseId}-studyStudent-md`
  869. };
  870. this.ajax
  871. .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
  872. .then(res => {
  873. let _data = JSON.parse(res.data.FunctionResponse);
  874. if (_data.length > 0) {
  875. let _chatList = [];
  876. for (let i = 0; i < _data.length; i++) {
  877. _chatList.push({
  878. loading: false,
  879. role: "user",
  880. content: _data[i].problem,
  881. uid: _data[i].id,
  882. AI: "AI",
  883. aiContent: _data[i].answer,
  884. oldContent: _data[i].answer,
  885. isShowSynchronization: false,
  886. filename: _data[i].filename,
  887. index: i,
  888. is_mind_map: false,
  889. fileid: _data[i].fileid
  890. });
  891. }
  892. this.chatList = _chatList;
  893. // console.log(' this.chatList', this.chatList);
  894. this.loading = false;
  895. this.chatLoading = false;
  896. } else {
  897. //没有对话记录
  898. this.chatLoading = false;
  899. this.loading = false;
  900. }
  901. resolve();
  902. })
  903. .catch(err => {
  904. console.log(err);
  905. this.$message.error("获取对话记录失败");
  906. this.loading = false;
  907. this.chatLoading = false;
  908. resolve();
  909. });
  910. });
  911. },
  912. getRoleList() {
  913. this.roleList = [];
  914. let params = {
  915. userId: this.userid
  916. };
  917. this.ajax
  918. .post("https://gpt4.cocorobo.cn/get_ai_agent_assistant_list", params)
  919. .then(res => {
  920. let _data = res.data.FunctionResponse.result;
  921. if (_data.length == 0) return;
  922. if (_data) {
  923. this.roleList = JSON.parse(_data);
  924. }
  925. })
  926. .catch(e => {
  927. console.log("获取角色列表失败");
  928. this.roleList = [];
  929. });
  930. },
  931. getPublicRoleList() {
  932. this.roleList2 = [];
  933. let params = {
  934. userId: this.userid,
  935. // organizeid: this.org,
  936. organizeid: "45facc0a-1211-11ec-80ad-005056b86db5"
  937. };
  938. this.ajax
  939. .post(
  940. "https://gpt4.cocorobo.cn/get_ai_agent_assistant_share_list",
  941. params
  942. )
  943. .then(res => {
  944. let _data = res.data.FunctionResponse.result;
  945. if (_data.length == 0) return;
  946. if (_data) {
  947. this.roleList2 = JSON.parse(_data);
  948. }
  949. })
  950. .catch(e => {
  951. this.roleList2 = [];
  952. console.log("获取公共角色失败", e);
  953. });
  954. },
  955. addAsk(_text) {
  956. // this.chatLoading = true;
  957. let _uuid = uuidv4();
  958. let _msg = `NOTICERole: 你是一个多功能的AI助手,能够根据学生的文本内容判断其情感状态,并提供相应的支持和引导。Output: Provide your output in json format.ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced \"Format example\".Instruction: Based on the context, follow \"Format example\", write content.# Context## 任务1.学生文本内容,执行以下任务。首先,请你判断学生是否进行情感倾诉,比如心情不好、遭遇校园暴力、对他人进行人身攻击等。如果是,请扮演一个心理咨询师的角色,坚持人本主义的立场,善良、温柔地引导对方,安抚对方的情绪,为对方提供心理支持。剩下的其它情况,请你扮演提问引导者的角色,延续学生的提问,围绕问题本身,提出3个问题,激发学生的深度思考、创造性思考。2.人本主义心理学人本主义心理学强调个体的主观体验和自我实现,认为每个人都有内在的潜力和价值。心理咨询师应当以同理心、无条件积极关注和真诚的态度对待来访者,帮助他们发现自身的力量和解决问题的能力。3.提问引导技巧提问引导技巧包括开放性问题、反思性问题和假设性问题等,旨在通过提问激发对方的思考和探索,帮助他们深入理解问题并找到解决方案。## 工作流程1. 仔细阅读并分析学生提供的文本内容。2. 判断学生是否进行情感倾诉。3. 如果是情感倾诉,扮演心理咨询师的角色,提供情感支持和引导。4. 如果不是情感倾诉,扮演提问引导者的角色,围绕问题本身提出3个问题。## 限制/注意事项 1.在回答时应保持专业性和权威性,确保信息的准确性和可靠性。2.避免生成与问题无关或不恰当的回答,确保回答的相关性和实用性。3.在提供情感支持时,注意用词温柔,避免引起对方的负面情绪。## 要求1. 内容包含情感支持或追加问题。2. 情感支持部分应体现同理心和积极关注。3. 追加问题应具有启发性和深度。## 学生文本内容${_text}# Format example [{\"index\": 1,\"label\": \"不同国家的垃圾分类标准和方法?\"},{\"index\": 2, \"label\": \"可回收垃圾的处理流程和再利用方法?\"},{\"index\": 3,\"label\": \"有害垃圾对环境和人体健康的潜在影响?\"}]`;
  959. _msg = _msg.replace(/[\r\n]/g, "");
  960. this.chatList.push({
  961. role: "user",
  962. content: `addAsk`,
  963. uid: _uuid,
  964. AI: "AI",
  965. aiContent: "",
  966. oldContent: "",
  967. isShowSynchronization: false,
  968. filename: "",
  969. index: this.chatList.length,
  970. is_mind_map: false,
  971. loading: true
  972. });
  973. this.scrollBottom();
  974. let history = [];
  975. // this.nowChatList.forEach(i => {
  976. // if (i.content == "wanSearch") {
  977. // // history.push({
  978. // // role:"assistant",
  979. // // content: JSON.stringify(i.aiContent)
  980. // // })
  981. // return;
  982. // } else if (i.content == "getImage") {
  983. // return history.push({
  984. // role: "assistant",
  985. // content: i.aiContent
  986. // });
  987. // }else if(i.content == "addAsk"){
  988. // }
  989. // if (i.content) {
  990. // history.push({
  991. // role: "user",
  992. // content: i.content
  993. // });
  994. // }
  995. // if (i.aiContent) {
  996. // history.push({
  997. // role: "assistant",
  998. // content: i.aiContent
  999. // });
  1000. // }
  1001. // });
  1002. history.push({ type: "text", text: _msg });
  1003. console.log(history);
  1004. // let params = {
  1005. // model: "gpt-3.5-turbo",
  1006. // temperature: 0,
  1007. // max_tokens: 4096,
  1008. // top_p: 1,
  1009. // frequency_penalty: 0,
  1010. // presence_penalty: 0,
  1011. // messages:history,
  1012. // stream: false,
  1013. // uid: _uuid,
  1014. // mind_map_question: ""
  1015. // };
  1016. let params = {
  1017. assistant_id: "6063369f-289a-11ef-8bf4-12e77c4cb76b",
  1018. userId: this.userid,
  1019. message: history,
  1020. session_name: _uuid,
  1021. // uid: _uuid,
  1022. file_ids: this.fileId
  1023. };
  1024. // let params = {
  1025. // message: {
  1026. // anthropic_version: "bedrock-2023-05-31",
  1027. // max_tokens: 4096,
  1028. // temperature: 0,
  1029. // top_p: 1,
  1030. // messages: [{ role: "user", content: _msg }]
  1031. // },
  1032. // uid: _uuid,
  1033. // model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
  1034. // };
  1035. this.text = "";
  1036. this.ajax
  1037. // .post("https://gpt4.cocorobo.cn/chat", params)
  1038. // .post("https://claude3.cocorobo.cn/chat", params)
  1039. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", params)
  1040. .then(res => {
  1041. console.log(res);
  1042. let _data = res.data.FunctionResponse.message;
  1043. console.log(_data);
  1044. _data = _data.replaceAll("```json", "").replaceAll("```", "");
  1045. this.chatList.find(i => i.uid == _uuid).aiContent = JSON.parse(_data);
  1046. this.chatList.find(i => i.uid == _uuid).isalltext = true;
  1047. this.chatList.find(i => i.uid == _uuid).isShowSynchronization = true;
  1048. this.chatList.find(i => i.uid == _uuid).loading = false;
  1049. this.scrollBottom();
  1050. // this.chatLoading = false;
  1051. })
  1052. .catch(e => {
  1053. this.chatLoading = false;
  1054. this.chatList.find(i => i.uid == _uuid).loading = false;
  1055. console.log(e);
  1056. });
  1057. },
  1058. changeRole() {
  1059. this.cardType = 0;
  1060. // this.rightSubjects = this.subjectsType;
  1061. // this.rightRole = this.roleType;
  1062. if (this.choseRoleItem.assistant_id) {
  1063. this.chatList = [];
  1064. this.nowChatList = [];
  1065. let _uuid = uuidv4();
  1066. this.chatList.push({
  1067. role: "user",
  1068. content: `您好,${this.choseRoleItem.assistantName}`,
  1069. uid: _uuid,
  1070. AI: "AI",
  1071. aiContent: this.choseRoleItem.prologue
  1072. ? this.choseRoleItem.prologue
  1073. : "您好,有什么需要我帮忙的吗?",
  1074. oldContent: "",
  1075. isShowSynchronization: false,
  1076. filename: this.choseRoleItem.headUrl,
  1077. index: this.chatList.length,
  1078. is_mind_map: false,
  1079. loading: false
  1080. });
  1081. this.scrollBottom();
  1082. }
  1083. },
  1084. choseRole(item) {
  1085. this.choseRoleItem = item;
  1086. console.log("选择角色", this.choseRoleItem);
  1087. },
  1088. noChangeRole() {
  1089. this.cardType = 0;
  1090. this.choseRoleItem = {};
  1091. // this.subjectsType = this.rightSubjects;
  1092. // this.roleType = this.rightRole;
  1093. },
  1094. scrollBottom() {
  1095. this.$nextTick(() => {
  1096. this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
  1097. });
  1098. },
  1099. download(_url) {
  1100. let xhr = new XMLHttpRequest();
  1101. xhr.open("GET", _url, true);
  1102. xhr.responseType = "blob";
  1103. xhr.onload = () => {
  1104. if (xhr.status === 200) {
  1105. let blob = xhr.response;
  1106. // const _blob = new Blob([blob], { type: fileType });
  1107. const downloadElement = document.createElement("a");
  1108. const url = window.URL.createObjectURL(blob);
  1109. downloadElement.href = url;
  1110. downloadElement.download = "Image.jpg";
  1111. downloadElement.click();
  1112. window.URL.revokeObjectURL(url); // 释放内存
  1113. } else {
  1114. this.$message.error("此图片不支持下载");
  1115. }
  1116. };
  1117. xhr.onerror = e => {
  1118. console.log(e);
  1119. this.$message.error("此图片不支持下载");
  1120. };
  1121. xhr.send();
  1122. },
  1123. removeMarkdown(text) {
  1124. return text
  1125. .replace(/[#*_~`>+\-]/g, "") // 移除 #、*、_、~、`、>、+、- 符号
  1126. .replace(/!\[.*?\]\(.*?\)/g, "") // 移除图片
  1127. .replace(/\[.*?\]\(.*?\)/g, "") // 移除链接
  1128. .replace(/```[\s\S]*?```/g, "") // 移除代码块(不使用 s 标志)
  1129. .replace(/`[^`]*`/g, "") // 移除行内代码
  1130. .replace(/\d+\./g, "") // 移除有序列表
  1131. .replace(/^\s*[-*+]\s+/gm, "") // 移除无序列表
  1132. .replace(/\s+/g, " ") // 将多个空白字符替换为一个空格
  1133. .trim(); // 去除字符串两端的空白字符
  1134. },
  1135. aiTalk(type = 0) {
  1136. //0 新的 1继续
  1137. if (type == 0 && this.aiIsTalk) {
  1138. let _talkTextIiframe2 = this.$refs.iiframe2;
  1139. try {
  1140. _talkTextIiframe2.contentWindow.pausesynthesizer();
  1141. _talkTextIiframe2.contentWindow.closesynthesizer();
  1142. this.aiIsTalk = false;
  1143. if (this.aiTalkList.length) this.aiTalk(0);
  1144. else this.aiTalkUid = ""
  1145. } catch (error) {
  1146. // console.log("error")
  1147. this.aiIsTalk = false;
  1148. if (this.aiTalkList.length) this.aiTalk(0);
  1149. else this.aiTalkUid = ""
  1150. }
  1151. } else {
  1152. let _text = this.aiTalkList.shift();
  1153. let _talkTextIiframe2 = this.$refs.iiframe2;
  1154. if (_text) {
  1155. this.aiIsTalk = true;
  1156. // console.log("👇说👇");
  1157. // console.log(_text);
  1158. _talkTextIiframe2.contentWindow.texttospeech(
  1159. _text,
  1160. () => {
  1161. this.aiTalk(1);
  1162. },
  1163. () => {
  1164. this.aiTalk(0);
  1165. }
  1166. );
  1167. } else {
  1168. try {
  1169. _talkTextIiframe2.contentWindow.closesynthesizer();
  1170. } catch (error) {
  1171. return
  1172. }
  1173. }
  1174. }
  1175. // if(_text){
  1176. // this.aiIsTalk = true;
  1177. // }
  1178. },
  1179. aiTalkAll(item) {
  1180. if (this.aiTalkUid == item.uid && this.aiIsTalk) {
  1181. try {
  1182. this.aiTalkList = [];
  1183. let _talkTextIiframe2 = this.$refs.iiframe2;
  1184. _talkTextIiframe2.contentWindow.pausesynthesizer();
  1185. _talkTextIiframe2.contentWindow.closesynthesizer();
  1186. this.aiIsTalk = false;
  1187. } catch (error) {
  1188. this.aiTalkList = [];
  1189. this.aiIsTalk = false;
  1190. }
  1191. } else {
  1192. let _resultText = this.removeMarkdown(item.aiContent);
  1193. this.aiTalkUid = item.uid;
  1194. this.aiTalkList = [];
  1195. this.aiTalkList.push(_resultText);
  1196. this.aiTalk(0);
  1197. }
  1198. // console.log(_resultText);
  1199. }
  1200. },
  1201. mounted() {
  1202. this.getRoleList();
  1203. this.getPublicRoleList();
  1204. this.getChatList().then(_ => {
  1205. this.scrollBottom();
  1206. });
  1207. this.nowChatList = [];
  1208. }
  1209. };
  1210. </script>
  1211. <style scoped>
  1212. .dialog {
  1213. width: 100%;
  1214. height: 100%;
  1215. box-sizing: border-box;
  1216. }
  1217. .dialog > div {
  1218. width: 100%;
  1219. height: 100%;
  1220. }
  1221. .aiCopy {
  1222. position: absolute;
  1223. right: 5px;
  1224. bottom: 0%;
  1225. display: flex;
  1226. flex-direction: column;
  1227. justify-content: flex-end;
  1228. /* transform: translate(0, -30%); */
  1229. cursor: pointer;
  1230. }
  1231. .characterBlock {
  1232. display: flex;
  1233. background: rgba(54, 169, 252, 1);
  1234. width: 100%;
  1235. height: 80px;
  1236. margin: 0 auto;
  1237. border-radius: 10px;
  1238. margin-bottom: 15px;
  1239. cursor: pointer;
  1240. }
  1241. .characterBlock > .imgLeft {
  1242. width: 100px;
  1243. display: flex;
  1244. justify-content: center;
  1245. align-items: center;
  1246. }
  1247. .characterBlock > .imgLeft > .img {
  1248. width: 60px;
  1249. height: 60px;
  1250. overflow: hidden;
  1251. border-radius: 50%;
  1252. }
  1253. .characterBlock > .imgLeft > .img2 {
  1254. width: 70px;
  1255. height: 70px;
  1256. overflow: hidden;
  1257. border-radius: 50%;
  1258. }
  1259. .characterBlock > .txtRight {
  1260. flex: 1;
  1261. display: flex;
  1262. justify-content: flex-start;
  1263. align-items: center;
  1264. }
  1265. .characterBlock > .txtRight > .bir {
  1266. width: 180px;
  1267. height: 35px;
  1268. display: flex;
  1269. align-items: center;
  1270. background-color: #fff;
  1271. border-radius: 10px;
  1272. box-sizing: border-box;
  1273. padding: 5px 10px;
  1274. box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
  1275. margin-right: 10px;
  1276. white-space: nowrap;
  1277. overflow: hidden;
  1278. text-overflow: ellipsis;
  1279. }
  1280. .d_top {
  1281. width: 100%;
  1282. height: calc(100% - 130px);
  1283. overflow: auto;
  1284. box-sizing: border-box;
  1285. padding: 20px 0;
  1286. }
  1287. .d_t_chat {
  1288. width: 100%;
  1289. display: flex;
  1290. box-sizing: border-box;
  1291. padding: 10px;
  1292. flex-direction: column;
  1293. }
  1294. .d_t_chat > div {
  1295. display: flex;
  1296. align-items: flex-start;
  1297. width: 100%;
  1298. }
  1299. .d_t_c_user {
  1300. box-sizing: border-box;
  1301. padding-left: 35px;
  1302. }
  1303. .d_t_c_u_left {
  1304. width: 90%;
  1305. height: auto;
  1306. }
  1307. .d_t_c_u_l_content {
  1308. width: auto;
  1309. max-width: 100%;
  1310. height: auto;
  1311. box-sizing: border-box;
  1312. padding: 10px;
  1313. color: white;
  1314. background-color: #3681fc;
  1315. border-radius: 8px 2px 8px 8px;
  1316. white-space: pre-line;
  1317. }
  1318. .d_t_c_u_l_time {
  1319. width: 100%;
  1320. display: flex;
  1321. justify-content: flex-end;
  1322. font-size: 12px;
  1323. color: #9f9f9f;
  1324. margin-top: 5px;
  1325. }
  1326. .d_t_c_u_right {
  1327. width: 35px;
  1328. height: 35px;
  1329. display: flex;
  1330. justify-content: center;
  1331. margin-left: 5px;
  1332. }
  1333. .d_t_c_u_right > span {
  1334. width: 32px;
  1335. height: 32px;
  1336. display: flex;
  1337. justify-content: center;
  1338. align-items: center;
  1339. color: white;
  1340. background-color: #3681fc;
  1341. border-radius: 50%;
  1342. }
  1343. .d_t_c_ai {
  1344. box-sizing: border-box;
  1345. padding-right: 35px;
  1346. margin-top: 10px;
  1347. position: relative;
  1348. }
  1349. .d_t_c_a_right {
  1350. min-width: 90%;
  1351. height: auto;
  1352. }
  1353. .d_t_c_a_r_content {
  1354. width: auto;
  1355. max-width: 100%;
  1356. height: auto;
  1357. box-sizing: border-box;
  1358. padding: 10px;
  1359. background-color: #f6f8ff;
  1360. border-radius: 2px 8px 8px 8px;
  1361. white-space: pre-line;
  1362. word-break: break-all;
  1363. }
  1364. .d_t_c_a_r_time {
  1365. width: 100%;
  1366. display: flex;
  1367. justify-content: flex-start;
  1368. font-size: 12px;
  1369. color: #9f9f9f;
  1370. margin-top: 5px;
  1371. }
  1372. .d_t_c_a_left {
  1373. width: 35px;
  1374. height: 35px;
  1375. display: flex;
  1376. justify-content: center;
  1377. margin-right: 5px;
  1378. }
  1379. .d_t_c_a_left > span {
  1380. width: 32px;
  1381. height: 32px;
  1382. display: flex;
  1383. justify-content: center;
  1384. align-items: center;
  1385. color: white;
  1386. background-color: #3681fc;
  1387. border-radius: 50%;
  1388. }
  1389. .d_bottom {
  1390. width: 100%;
  1391. height: 130px;
  1392. display: flex;
  1393. flex-direction: column;
  1394. justify-content: space-between;
  1395. }
  1396. .d_b_btnArea {
  1397. width: 100%;
  1398. height: 30px;
  1399. display: flex;
  1400. align-items: center;
  1401. box-sizing: border-box;
  1402. padding: 0 10px;
  1403. }
  1404. .d_b_ba-item {
  1405. width: auto;
  1406. box-sizing: border-box;
  1407. padding: 0 10px;
  1408. height: 25px;
  1409. background-color: white;
  1410. display: flex;
  1411. justify-content: center;
  1412. align-items: center;
  1413. /* 阴影 */
  1414. box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.363);
  1415. border-radius: 15px;
  1416. margin-right: 10px;
  1417. font-size: 14px;
  1418. cursor: pointer;
  1419. }
  1420. .d_b_inputArea {
  1421. width: 100%;
  1422. height: 55px;
  1423. box-sizing: border-box;
  1424. border-top: solid 1px #ededed;
  1425. display: flex;
  1426. justify-content: space-between;
  1427. padding-right: 10px;
  1428. align-items: center;
  1429. }
  1430. .d_b_tape {
  1431. width: 35px;
  1432. height: 35px;
  1433. background: url("../../../assets/icon/course/tape.png") no-repeat;
  1434. background-size: 50% 60%;
  1435. background-position: center;
  1436. cursor: pointer;
  1437. }
  1438. .d_b_input {
  1439. /* width: 75%; */
  1440. flex: 1;
  1441. height: 45px;
  1442. background-color: #f3f3f3;
  1443. border-radius: 50px;
  1444. margin: 0 10px;
  1445. display: flex;
  1446. overflow: hidden;
  1447. align-items: center;
  1448. }
  1449. .d_b_i_left {
  1450. width: 100%;
  1451. line-height: 45px;
  1452. height: 100%;
  1453. }
  1454. .d_b_i_left >>> .el-input__inner {
  1455. border: none;
  1456. background-color: #f3f3f3;
  1457. outline: none;
  1458. border-radius: 50px 0 0 50px;
  1459. }
  1460. .d_b_i_right {
  1461. width: 45px;
  1462. height: 45px;
  1463. display: flex;
  1464. justify-content: center;
  1465. align-items: center;
  1466. }
  1467. .d_b_i_right > span {
  1468. width: 35px;
  1469. height: 35px;
  1470. background: url("../../../assets/icon/course/file.png") no-repeat;
  1471. background-size: 50% 60%;
  1472. background-position: center;
  1473. cursor: pointer;
  1474. }
  1475. .d_b_btn {
  1476. width: 40px;
  1477. height: 40px;
  1478. background-color: #3681fc;
  1479. display: flex;
  1480. justify-content: center;
  1481. align-items: center;
  1482. border-radius: 50%;
  1483. cursor: pointer;
  1484. }
  1485. .d_b_btn > div {
  1486. color: white;
  1487. width: 100%;
  1488. height: 100%;
  1489. display: flex;
  1490. justify-content: center;
  1491. align-items: center;
  1492. }
  1493. .d_b_btn > span {
  1494. width: 30px;
  1495. height: 30px;
  1496. background: url("../../../assets/icon/course/send.png") no-repeat;
  1497. background-size: 70% 70%;
  1498. background-position: center;
  1499. }
  1500. .d_b_btn > img {
  1501. width: 30px;
  1502. height: 30px;
  1503. }
  1504. .choiceTop {
  1505. width: 100%;
  1506. height: 95%;
  1507. overflow-x: hidden;
  1508. box-sizing: border-box;
  1509. padding: 10px;
  1510. }
  1511. .choiceBottom {
  1512. width: 100%;
  1513. height: 5%;
  1514. display: flex;
  1515. align-items: center;
  1516. justify-content: flex-end;
  1517. }
  1518. .cb_btn {
  1519. margin: 0 10px;
  1520. }
  1521. .choiceRoleHeader {
  1522. width: 100%;
  1523. /* margin: 10px; */
  1524. margin-bottom: 20px;
  1525. }
  1526. .choiceRoleHeader > div {
  1527. font-size: 16px;
  1528. font-weight: bold;
  1529. }
  1530. .choiceRoleHeader > span {
  1531. font-size: 14px;
  1532. }
  1533. .choiceSelect {
  1534. width: 100%;
  1535. display: flex;
  1536. height: 35px;
  1537. justify-content: flex-start;
  1538. align-items: center;
  1539. margin: 15px 0;
  1540. }
  1541. .choiceSelect > .option {
  1542. width: 80px;
  1543. height: 100%;
  1544. border-radius: 5px;
  1545. margin-right: 10px;
  1546. display: flex;
  1547. justify-content: center;
  1548. align-items: center;
  1549. cursor: pointer;
  1550. }
  1551. .filterSubjects {
  1552. margin: 10px;
  1553. width: 100%;
  1554. height: auto;
  1555. }
  1556. .fs_box {
  1557. width: 100%;
  1558. display: flex;
  1559. flex-wrap: wrap;
  1560. margin-top: 10px;
  1561. }
  1562. .fs_b_item {
  1563. width: auto;
  1564. height: 35px;
  1565. font-size: 14px;
  1566. box-sizing: border-box;
  1567. padding: 0 9px;
  1568. background-color: #f3f7fd;
  1569. border: solid 1px #f3f7fd;
  1570. border-radius: 5px;
  1571. margin-right: 8px;
  1572. margin-bottom: 8px;
  1573. display: flex;
  1574. justify-content: center;
  1575. align-items: center;
  1576. cursor: pointer;
  1577. }
  1578. .fs_b_itemActive {
  1579. border: solid 1px #4d8ffc;
  1580. color: #4d8ffc;
  1581. background-color: #f3f7fd;
  1582. }
  1583. .roleList {
  1584. width: 100%;
  1585. height: auto;
  1586. margin: 10px;
  1587. }
  1588. .r_box {
  1589. width: 100%;
  1590. height: auto;
  1591. display: flex;
  1592. flex-wrap: wrap;
  1593. }
  1594. .r_b_item {
  1595. height: 40px;
  1596. font-size: 14px;
  1597. display: flex;
  1598. /* justify-content: center; */
  1599. align-items: center;
  1600. background-color: #f0f2f5;
  1601. border-radius: 5px;
  1602. margin: 5px;
  1603. cursor: pointer;
  1604. box-sizing: border-box;
  1605. padding: 0 4px;
  1606. border: solid 1px #f0f2f5;
  1607. }
  1608. .r_b_itemActive {
  1609. box-sizing: border-box;
  1610. border: solid 1px #aeccfe;
  1611. color: #4d8ffb;
  1612. }
  1613. .r_b_item > img {
  1614. min-width: 24px;
  1615. min-height: 24px;
  1616. width: 24px;
  1617. height: 24px;
  1618. border-radius: 50%;
  1619. margin-right: 10px;
  1620. /* margin-left: 10px; */
  1621. }
  1622. .s_t_addAsk {
  1623. width: 100%;
  1624. height: auto;
  1625. padding: 10px 20px;
  1626. display: flex;
  1627. flex-direction: column;
  1628. justify-content: center;
  1629. align-items: center;
  1630. box-sizing: border-box;
  1631. }
  1632. .s_t_addAsk > span {
  1633. box-sizing: border-box;
  1634. width: auto;
  1635. height: auto;
  1636. padding: 15px;
  1637. margin-bottom: 10px;
  1638. background-color: #f5f6f7;
  1639. border-radius: 10px;
  1640. cursor: pointer;
  1641. border: solid 1px #e8e9ec;
  1642. transition: 0.3s;
  1643. }
  1644. .s_t_addAsk > span:hover {
  1645. background-color: #e8e9ec;
  1646. }
  1647. .d_t_c_a_r_c_img:hover .download_image {
  1648. display: block;
  1649. }
  1650. .download_image {
  1651. position: absolute;
  1652. display: none;
  1653. right: 5px;
  1654. bottom: 5px;
  1655. width: 30px;
  1656. height: 30px;
  1657. cursor: pointer;
  1658. }
  1659. .download_image > img {
  1660. width: 100%;
  1661. height: 100%;
  1662. }
  1663. .s_b_btnAreaTop {
  1664. width: 100%;
  1665. height: 35px;
  1666. margin-bottom: 5px;
  1667. display: flex;
  1668. align-items: center;
  1669. box-sizing: border-box;
  1670. padding: 0 10px;
  1671. overflow: auto;
  1672. display: flex;
  1673. justify-content: space-between;
  1674. }
  1675. .s_b_bat_left {
  1676. width: auto;
  1677. height: 100%;
  1678. display: flex;
  1679. align-items: flex-end;
  1680. }
  1681. .s_b_bat_left > img {
  1682. width: 25px;
  1683. height: 25px;
  1684. cursor: pointer;
  1685. margin-right: 5px;
  1686. }
  1687. .s_b_bat_right{
  1688. width: auto;
  1689. height: 100%;
  1690. display: flex;
  1691. align-items: flex-end;
  1692. }
  1693. .s_b_bat_right > img {
  1694. width: 25px;
  1695. height: 25px;
  1696. /* cursor: pointer; */
  1697. margin-right: 5px;
  1698. }
  1699. .voice_or_keyboard {
  1700. width: 35px;
  1701. height: 35px;
  1702. margin-right: 10px;
  1703. }
  1704. .voice_or_keyboard > img {
  1705. width: 100%;
  1706. height: 100%;
  1707. cursor: pointer;
  1708. }
  1709. </style>