aiCreateVideoDialog.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. <template>
  2. <el-dialog title="智能检索" :visible.sync="dialogVisibleAiCreateVideo" :append-to-body="true" width="90%"
  3. :before-close="handleClose" class="dialog_diy">
  4. <div style="box-sizing:border-box;padding:15px" v-loading="loading" element-loading-text="小可正在努力生成中,请稍等...">
  5. <div style="position: relative; width: 100%;height: 40px;margin-bottom: 10px;">
  6. <el-input class="inputC" style="height: 100%;" placeholder="搜索视频关键字(如需搜索多个可“,”隔开)" v-model="detail"
  7. @keyup.enter.native="searchA()"></el-input>
  8. <div class="search_img" @click="searchA" style="right: 10px">
  9. <img src="../../../assets/icon/search.png" alt />
  10. </div>
  11. </div>
  12. <div class="nav_box">
  13. <div class="nav" :class="{ active: navActive == 0 }" @click="navClick(0)">综合排序</div>
  14. <div class="nav" :class="{ active: navActive == 1 }" @click="navClick(1)">最多播放</div>
  15. <div class="nav" :class="{ active: navActive == 2 }" @click="navClick(2)">最新发布</div>
  16. <div class="nav" :class="{ active: navActive == 3 }" @click="navClick(3)">最多弹幕</div>
  17. <div class="nav" :class="{ active: navActive == 4 }" @click="navClick(4)">最多收藏</div>
  18. </div>
  19. <div class="Box">
  20. <div class="video_box video_box2" v-for="(item, index) in data" :key="index">
  21. <!-- <img :src="item.pic" /> -->
  22. <span class="name" v-html="item.title"></span>
  23. <span class="author">作者:{{ item.author }}</span>
  24. <span class="detail">{{ item.description }}</span>
  25. <div class="tag" v-if="item.tag.split(',').length > 0">
  26. <span v-for="(tag, index) in item.tag.split(',')" :key="index">{{ tag }}</span>
  27. </div>
  28. <div class="btn">
  29. <span @click="openUrl(item.bvid)">查看</span>
  30. <span @click="checkUrl(item.title, item.bvid)">加入</span>
  31. </div>
  32. </div>
  33. <div v-if="data.length == 0" class="no_data">暂无数据</div>
  34. </div>
  35. </div>
  36. <span slot="footer" class="dialog-footer">
  37. <el-button @click="close">关 闭</el-button>
  38. </span>
  39. </el-dialog>
  40. </template>
  41. <script>
  42. import { v4 as uuidv4 } from "uuid";
  43. import _ from "lodash";
  44. export default {
  45. components: {
  46. },
  47. props: {
  48. dialogVisibleAiCreateVideo: {
  49. type: Boolean,
  50. default: false
  51. },
  52. courseName: {
  53. type: String,
  54. default: ""
  55. },
  56. courseState: {
  57. type: Number,
  58. },
  59. lineCount: {
  60. type: Number,
  61. },
  62. unitJson: {
  63. type: Array,
  64. }
  65. },
  66. // 根据用户给你的参考资料
  67. data() {
  68. return {
  69. userid: this.$route.query.userid,
  70. radio: 0,
  71. aiJson: {
  72. ppt: ``,
  73. word: '',
  74. video: ''
  75. },
  76. aiUrl: {
  77. ppt: '',
  78. word: '',
  79. video: ''
  80. },
  81. detail: "",
  82. loading: false,
  83. url: "",
  84. data: [],
  85. uJson: {},
  86. navActive: 0
  87. }
  88. },
  89. watch: {
  90. dialogVisibleAiCreateVideo(newValue, oldValue) {
  91. if (newValue) {
  92. this.searchA = ""
  93. this.data = []
  94. this.againEva()
  95. }
  96. },
  97. },
  98. methods: {
  99. handleClose(done) {
  100. this.close()
  101. done();
  102. },
  103. close() {
  104. this.$emit('update:dialogVisibleAiCreateVideo', false)
  105. },
  106. openUrl(url) {
  107. // window.open('https://www.youtube.com/embed/'+url)
  108. window.open(`//www.bilibili.com/video/${url}`)
  109. },
  110. checkUrl(name, id) {
  111. let json = {
  112. name: "链接",
  113. title: name.replace(/<[^>]*>?/gm, ''),
  114. // url: 'https://www.youtube.com/embed/'+id,
  115. url: `//player.bilibili.com/player.html?isOutside=true&bvid=${id}`,
  116. type: 8,
  117. }
  118. this.$emit('createAiVideo', json)
  119. this.$message.success('加入成功')
  120. },
  121. changeRadio() {
  122. if (this.radio == 0) {
  123. this.detail = this.aiJson.ppt
  124. }
  125. if (this.radio == 1) {
  126. this.detail = this.aiJson.word
  127. }
  128. if (this.radio == 2) {
  129. this.detail = this.aiJson.video
  130. }
  131. },
  132. // async aiGet() {
  133. // let _this = this
  134. // _this.loading = true
  135. // this.ajax
  136. // .get(`https://www.googleapis.com/youtube/v3/search?key=AIzaSyBUvNQ5Wyua4PbStE2vp3t7MIY4htry-4M&part=snippet&q=${this.detail}&maxResults=10&type=video&order=relevance&regionCode=HK`)
  137. // .then((response) => {
  138. // console.log(response);
  139. // _this.data = response.data.items
  140. // _this.loading = false
  141. // })
  142. // .catch((error) => {
  143. // _this.loading = false
  144. // console.log(error);
  145. // });
  146. // },
  147. async aiGet() {
  148. let _this = this
  149. _this.loading = true
  150. this.ajax.post(`https://gpt4.cocorobo.cn/get_network_search`, {
  151. engine: "bilibili",
  152. keyword: this.detail
  153. }).then(response => {
  154. console.log(response);
  155. _this.data = response.data.FunctionResponse
  156. _this.loading = false
  157. })
  158. .catch((error) => {
  159. _this.loading = false
  160. console.log(error);
  161. });
  162. },
  163. // async aiGet2(msg) {
  164. // let _this = this
  165. // _this.loading = true
  166. // this.ajax
  167. // .get(`https://www.googleapis.com/youtube/v3/search?key=AIzaSyBUvNQ5Wyua4PbStE2vp3t7MIY4htry-4M&part=snippet&q=${msg}&maxResults=10&type=video&order=relevance&regionCode=HK`)
  168. // .then((response) => {
  169. // console.log(response);
  170. // _this.data = response.data.items
  171. // _this.loading = false
  172. // })
  173. // .catch((error) => {
  174. // _this.loading = false
  175. // console.log(error);
  176. // });
  177. // },
  178. async aiGet2(msg) {
  179. let _this = this
  180. return new Promise((resolve, reject) => {
  181. this.ajax.post(`https://gpt4.cocorobo.cn/get_network_search`, {
  182. engine: "bilibiliNew",
  183. keyword: msg,
  184. page: 1,
  185. page_size: 20,
  186. order: this.navActive,
  187. duration: 0,
  188. }).then(response => {
  189. console.log(response);
  190. // _this.data = [..._this.data,...response.data.FunctionResponse]
  191. resolve(response.data.FunctionResponse)
  192. })
  193. .catch((error) => {
  194. resolve([])
  195. console.log(error);
  196. });
  197. });
  198. },
  199. navClick(item) {
  200. if(this.navActive == item){
  201. return
  202. }
  203. this.navActive = item
  204. this.searchA()
  205. },
  206. async searchA(){
  207. let _this = this
  208. try {
  209. if(!_this.detail){
  210. _this.$message.error("请输入关键字")
  211. return
  212. }
  213. _this.loading = true
  214. let _content = ""
  215. if(_this.detail.split(",").length>1){
  216. _content = _this.detail.split(",")
  217. }else{
  218. _content = _this.detail.split(",")
  219. }
  220. _this.data = []
  221. let data2 = []
  222. for (var a = 0; a < _content.length; a++) {
  223. let _data = await _this.aiGet2(_content[a])
  224. data2[a] = _data
  225. }
  226. _this.data = _.flatMap(_.zip(...data2), (pair) => pair.filter(value => value !== undefined))
  227. // _this.data = _this.data.sort(
  228. // function (a, b) {
  229. // return b.play - a.play;
  230. // }
  231. // );
  232. _this.againEva2();
  233. // _this.loading = false
  234. } catch (error){
  235. console.log(error);
  236. _this.loading = false
  237. }
  238. },
  239. againEva() {
  240. let _this = this
  241. _this.loading = true
  242. let message = `从以下内容中识别出1~2个学科知识点关键词,用于检索知识点相关视频。注意,你仅需要返回关键词,“,”分开。教案:${_this.unitJson[0].chapterInfo[0].taskJson[_this.lineCount].taskDetail3.replaceAll('#', '').replaceAll('*', '').replaceAll('-', '').replaceAll('\n', '')}`
  243. let parm = {
  244. assistant_id: 'f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b',
  245. message: [{ "type": "text", "text": message.replaceAll('\n', " ").replaceAll('*', "") }],
  246. session_name: uuidv4(),
  247. userId: _this.userid,
  248. file_ids: [],
  249. model: 'gpt-4o-2024-08-06',
  250. }
  251. _this.ajax
  252. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", parm)
  253. .then(async (response) => {
  254. console.log(response);
  255. let data = response.data.FunctionResponse
  256. if (data.message) {
  257. console.log(data.message);
  258. let content = data.message;
  259. _this.detail = content
  260. let _content = content.split(",")
  261. if(content.split(",").length>1){
  262. _content = content.split(",")
  263. }else{
  264. _content = content.split(",")
  265. }
  266. _this.data = []
  267. let data2 = []
  268. for (var a = 0; a < _content.length; a++) {
  269. let _data = await _this.aiGet2(_content[a])
  270. data2[a] = _data
  271. }
  272. _this.data = _.flatMap(_.zip(...data2), (pair) => pair.filter(value => value !== undefined))
  273. // _this.data = _this.data.sort(
  274. // function (a, b) {
  275. // return b.play - a.play;
  276. // }
  277. // );
  278. _this.againEva2();
  279. }else {
  280. _this.$message.error("哎呀,请求太多了,服务器忙不过来了,请自行搜索关键词")
  281. _this.loading = false
  282. }
  283. // _this.loading = false
  284. })
  285. .catch((error) => {
  286. console.log(error);
  287. _this.$message.error("哎呀,请求太多了,服务器忙不过来了,请自行搜索关键词")
  288. _this.loading = false
  289. });
  290. },
  291. againEva2() {
  292. let _this = this
  293. _this.loading = true
  294. let message = `ATTENTION: Use '##' to SPLIT SECTIONS, not '#'.Output format carefully referenced "Format example".
  295. 针对以下视频数组内容,删除其中不适合k12年级的学生在教室里看到的条目,返回以下视频数组不符合的视频的aid,视频数组:${JSON.stringify(_this.data)}
  296. # Format example
  297. [{aid:""},{aid:""}]
  298. `
  299. let parm = {
  300. model: 'gpt-4o-2024-08-06',
  301. temperature: 0,
  302. max_tokens: 4096,
  303. top_p: 1,
  304. frequency_penalty: 0,
  305. presence_penalty: 0,
  306. messages: [{
  307. content: message.replaceAll('\n', " ").replaceAll('*', ""),
  308. role: 'user'
  309. }],
  310. uid: uuidv4(),
  311. stream: false,
  312. mind_map_question: "",
  313. }
  314. _this.ajax
  315. .post("https://gpt4.cocorobo.cn/chat", parm)
  316. .then(async (response) => {
  317. console.log(response);
  318. let data = response.data.FunctionResponse
  319. if (data.choices && data.choices.length && data.choices[0].message) {
  320. console.log(data.choices[0].message.content);
  321. let dArray = []
  322. try {
  323. dArray = JSON.parse(data.choices[0].message.content.replaceAll('```json','').replaceAll('```',''))
  324. } catch (error) {
  325. console.log("error_________________" + error);
  326. try {
  327. let regex = new RegExp("(?<=```json)([\\s\\S]*?)(?=```)");
  328. let match = data.choices[0].message.content.match(regex);
  329. dArray = JSON.parse(match[0]);
  330. } catch (error) {
  331. console.log("error_________________" + error);
  332. }
  333. }
  334. let aid = []
  335. for(var i = 0; i < dArray.length; i++){
  336. aid.push(dArray[i].aid)
  337. }
  338. _this.data = _this.data.filter(el => {
  339. return aid.indexOf(el.aid) === -1
  340. })
  341. _this.$forceUpdate()
  342. }
  343. _this.loading = false
  344. })
  345. .catch((error) => {
  346. console.log(error);
  347. // _this.$message.error("哎呀,请求太多了,服务器忙不过来了,请自行搜索关键词")
  348. _this.loading = false
  349. });
  350. },
  351. },
  352. mounted () {
  353. },
  354. }
  355. </script>
  356. <style scoped>
  357. @media screen and (max-width: 1080px) {
  358. .video_box {
  359. width: calc(100% / 3 - 10px) !important;
  360. }
  361. }
  362. @media screen and (max-width: 760px) {
  363. .video_box {
  364. width: calc(100% / 2 - 10px) !important;
  365. }
  366. }
  367. .dialog_diy>>>.el-dialog {
  368. height: auto;
  369. margin: 50px auto 0 !important;
  370. }
  371. .dialog_diy>>>.el-dialog__header {
  372. background: #454545 !important;
  373. padding: 15px 20px;
  374. }
  375. .dialog_diy>>>.el-dialog__body {
  376. height: calc(100% - 124px);
  377. box-sizing: border-box;
  378. padding: 0px;
  379. }
  380. .dialog_diy>>>.el-dialog__title {
  381. color: #fff;
  382. }
  383. .dialog_diy>>>.el-dialog__headerbtn {
  384. top: 19px;
  385. }
  386. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
  387. color: #fff;
  388. }
  389. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
  390. color: #fff;
  391. }
  392. .dialog_diy>>>.el-dialog__body,
  393. .dialog_diy>>>.el-dialog__footer {
  394. background: #fafafa;
  395. }
  396. .binfo_input {
  397. width: 100%;
  398. margin: 0;
  399. padding: 5px 7px;
  400. display: block;
  401. min-width: 0;
  402. outline: none;
  403. box-sizing: border-box;
  404. background: none;
  405. border: none;
  406. border-radius: 4px;
  407. background: #fff;
  408. font-size: 15px;
  409. resize: none;
  410. font-family: "Microsoft YaHei";
  411. min-height: 48px;
  412. /* border: 1px solid #3682fc00; */
  413. border: 1.5px solid #cad1dc;
  414. }
  415. .binfo_textarea {
  416. border: 1.5px solid #cad1dc;
  417. font-size: 15px;
  418. resize: none;
  419. /* background: #f6f6f6; */
  420. font-family: "Microsoft YaHei";
  421. }
  422. .binfo_input:focus-visible {
  423. border: 1.5px solid #3681fc !important;
  424. }
  425. .t_box {
  426. display: flex;
  427. margin-bottom: 15px;
  428. }
  429. .t_box>span:nth-child(1) {
  430. min-width: 80px;
  431. font-size: 16px;
  432. color: #000;
  433. }
  434. .inputC>>>.el-input__inner {
  435. padding: '0 35px 0 15px'
  436. }
  437. .search_img {
  438. width: 20px;
  439. height: 20px;
  440. position: absolute;
  441. right: 10px;
  442. top: 50%;
  443. transform: translateY(-50%);
  444. }
  445. .search_img>img {
  446. width: 100%;
  447. height: 100%;
  448. }
  449. .Box {
  450. width: 100%;
  451. height: 500px;
  452. overflow: auto;
  453. display: flex;
  454. flex-direction: row;
  455. justify-content: flex-start;
  456. flex-wrap: wrap;
  457. padding: 5px;
  458. box-sizing: border-box;
  459. }
  460. .video_box {
  461. width: calc(100% / 4 - 10px);
  462. /* overflow: hidden; */
  463. margin-right: 10px;
  464. display: flex;
  465. flex-direction: column;
  466. margin-bottom: 15px;
  467. cursor: pointer;
  468. }
  469. .video_box>img {
  470. height: 200px;
  471. object-fit: cover;
  472. }
  473. .video_box>.detail {
  474. color: #cecece;
  475. display: -webkit-box;
  476. -webkit-box-orient: vertical;
  477. -webkit-line-clamp: 3; /* 显示3行文本 */
  478. overflow: hidden;
  479. text-overflow: ellipsis; /* 超出部分显示点点点 */
  480. margin: 0 0 5px;
  481. }
  482. .video_box>.name {
  483. color: #000;
  484. margin: 5px 0;
  485. height: 32px;
  486. display: -webkit-box;
  487. -webkit-box-orient: vertical;
  488. -webkit-line-clamp: 2; /* 显示3行文本 */
  489. overflow: hidden;
  490. text-overflow: ellipsis; /* 超出部分显示点点点 */
  491. }
  492. .video_box>.author{
  493. margin: 0 0 5px;
  494. width: 100%;
  495. display: block;
  496. overflow: hidden;
  497. text-overflow: ellipsis; /* 超出部分显示点点点 */
  498. white-space: nowrap;
  499. }
  500. .video_box>.tag{
  501. display: flex;
  502. flex-wrap: wrap;
  503. margin-top: auto;
  504. }
  505. .video_box>.tag>span{
  506. background-color: #007bff;
  507. color: white;
  508. padding: 5px 10px;
  509. border-radius: 15px;
  510. font-size: 0.9em;
  511. margin: 0 0 5px 5px;
  512. }
  513. .btn {
  514. width: 100%;
  515. height: 35px;
  516. display: flex;
  517. align-items: center;
  518. /* margin-top: auto; */
  519. }
  520. .btn>span:hover {
  521. background: #4087f1;
  522. }
  523. .btn>span {
  524. width: 100%;
  525. height: 100%;
  526. background: #3681fc;
  527. color: #fff;
  528. border-radius: 5px;
  529. margin-top: 10px;
  530. cursor: pointer;
  531. display: flex;
  532. align-items: center;
  533. justify-content: center;
  534. }
  535. .btn>span+span {
  536. margin-left: 10px;
  537. }
  538. .video_box2 {
  539. box-shadow: 0px 0px 4px 2px #d2d2d282;
  540. padding: 5px 10px 10px;
  541. box-sizing: border-box;
  542. border-radius: 5px;
  543. }
  544. .nav_box {
  545. display: flex;
  546. margin-bottom: 10px;
  547. align-content: center;
  548. }
  549. .nav_box .nav{
  550. padding: 8px 10px;
  551. color: #060e17;
  552. border-radius: 5px;
  553. cursor: pointer;
  554. }
  555. .nav_box .nav.active{
  556. background: #eef3fb;
  557. font-weight: bold;
  558. color: #0061ff;
  559. }
  560. .nav_box .nav + .nav{
  561. margin-left: 20px;
  562. }
  563. .no_data{
  564. height: 500px;
  565. display: flex;
  566. align-items: center;
  567. justify-content: center;
  568. width: 100%;
  569. height: 500px;
  570. }
  571. </style>