aiCreateDialog.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <template>
  2. <el-dialog title="AI生成PPT" :visible.sync="dialogVisibleAiCreate" :append-to-body="true" width="700px"
  3. :before-close="handleClose" class="dialog_diy">
  4. <div style="height: 500px;padding:15px" v-loading="loading">
  5. <!-- <div class="t_box">
  6. <span>选择:</span>
  7. <el-radio-group v-model="radio" @change="changeRadio">
  8. <el-radio :label="0">PPT</el-radio>
  9. <el-radio :label="1">教案</el-radio>
  10. <el-radio :label="2">视频</el-radio>
  11. </el-radio-group>
  12. </div> -->
  13. <!-- <div class="t_box">
  14. <span>提示词:</span>
  15. <textarea rows="10" class="binfo_input binfo_textarea" cols placeholder="请输入提示词"
  16. v-model="detail"></textarea>
  17. </div> -->
  18. <wOffice v-if="url" :url="url"></wOffice>
  19. </div>
  20. <span slot="footer" class="dialog-footer">
  21. <el-button @click="aiGet" type="primary">重新生成</el-button>
  22. <el-button @click="confirm" type="primary">确 定</el-button>
  23. <el-button @click="close">关 闭</el-button>
  24. </span>
  25. </el-dialog>
  26. </template>
  27. <script>
  28. import Pptxgen from "pptxgenjs"
  29. import wOffice from '../components/wOffice.vue'
  30. import { v4 as uuidv4 } from "uuid";
  31. export default {
  32. components: {
  33. wOffice,
  34. },
  35. props: {
  36. dialogVisibleAiCreate: {
  37. type: Boolean,
  38. default: false
  39. },
  40. courseName: {
  41. type: String,
  42. default: ""
  43. },
  44. infoData: {
  45. type: Array,
  46. default: ""
  47. }
  48. },
  49. // 根据用户给你的参考资料
  50. data() {
  51. return {
  52. userid: this.$route.query.userid,
  53. radio: 0,
  54. aiJson: {
  55. ppt: `## 任务
  56. 请生成关于${this.courseName},为教师生成这节课的教学ppt,页数在20页左右。PPT的内容主要是讲解该课程中所有可能涉及到的知识点。
  57. ## 工作流
  58. 1. 从用户提供的参考资料中提取10个最重要的知识点(知识点水平限制在小学和初中),并输出。
  59. 2. 针对10个知识点中的每个,你使用1~3页ppt详细的对知识点进行讲解。你的讲解词应该在100token左右
  60. 3. 讲解完所有知识点后,再根据知识点出5道单选题(放在5页ppt中)
  61. ## 限制
  62. - 你不能输出错误的知识,如果你实在不清楚,输出“对不起,我不确定”
  63. - 你不能输出违反伦理的内容`,
  64. word: '',
  65. video: ''
  66. },
  67. aiUrl: {
  68. ppt: '',
  69. word: '',
  70. video: ''
  71. },
  72. detail: "",
  73. loading: false,
  74. url: "",
  75. uJson: {}
  76. }
  77. },
  78. watch: {
  79. dialogVisibleAiCreate(newValue, oldValue) {
  80. if (newValue) {
  81. // if (this.radio == 0) {
  82. this.detail = `## 任务
  83. 请根据用户给你的参考资料,生成关于${this.courseName},为教师生成这节课的教学ppt,页数在20页左右。PPT的内容主要是讲解该课程中所有可能涉及到的知识点。
  84. ## 工作流
  85. 1. 从用户提供的参考资料中提取10个最重要的知识点(知识点水平限制在小学和初中),并输出。
  86. 2. 针对10个知识点中的每个,你使用1~3页ppt详细的对知识点进行讲解。你的讲解词应该在100token左右
  87. 3. 讲解完所有知识点后,再根据知识点出5道单选题(放在5页ppt中)
  88. ## 限制
  89. - 你不能输出错误的知识,如果你实在不清楚,输出“对不起,我不确定”
  90. - 你不能输出违反伦理的内容`
  91. // }
  92. // if (this.radio == 1) {
  93. // this.detail = this.aiJson.word
  94. // }
  95. // if (this.radio == 2) {
  96. // this.detail = this.aiJson.video
  97. // }
  98. // this.loading = false
  99. this.aiGet()
  100. }
  101. },
  102. },
  103. methods: {
  104. handleClose(done) {
  105. this.close()
  106. done();
  107. },
  108. close() {
  109. this.$emit('update:dialogVisibleAiCreate', false)
  110. },
  111. confirm() {
  112. if(this.url){
  113. this.$emit('createAiPpt', this.uJson)
  114. }else {
  115. this.$message.error('请先生成ppt');
  116. }
  117. },
  118. changeRadio() {
  119. if (this.radio == 0) {
  120. this.detail = this.aiJson.ppt
  121. }
  122. if (this.radio == 1) {
  123. this.detail = this.aiJson.word
  124. }
  125. if (this.radio == 2) {
  126. this.detail = this.aiJson.video
  127. }
  128. },
  129. createFileid(url) {
  130. let _this = this
  131. return new Promise((resolve, reject) => {
  132. try {
  133. _this.ajax
  134. .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
  135. url: url,
  136. })
  137. .then((res) => {
  138. let _data = res.data.FunctionResponse;
  139. if (_data.result && _data.result.id) {
  140. resolve(_data.result.id)
  141. }
  142. }).catch(function (error) {
  143. resolve('')
  144. });
  145. }catch (e){
  146. resolve()
  147. }
  148. });
  149. },
  150. async aiGet() {
  151. if(this.loading){
  152. this.$message.error('正在生成中,请稍后');
  153. return;
  154. }
  155. this.url = ''
  156. this.uJson = {}
  157. let _this = this
  158. let fileid = []
  159. if (_this.infoData.length) {
  160. for (var i = 0; i < _this.infoData.length; i++) {
  161. if(_this.infoData[i].fileid){
  162. fileid.push(_this.infoData[i].fileid)
  163. }else {
  164. let _fileid = await _this.createFileid(_this.infoData[i].url)
  165. if(_fileid){
  166. _this.infoData[i].fileid = _fileid
  167. _this.$forceUpdate();
  168. fileid.push(_fileid)
  169. }
  170. }
  171. }
  172. }
  173. console.log('fileid=========',fileid)
  174. let message = ''
  175. if (_this.radio == 0) {
  176. message = `NOTICE
  177. Role: 提供的参考资料中读取10个最重要的知识点(知识点水平限制在小学和初中,作为ppt内容。
  178. Output: Provide your output in json format.
  179. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  180. Instruction: Based on the context, follow "Format example", write content.
  181. # Context
  182. ## 任务
  183. 请根据用户给你的参考资料,生成关于${this.courseName},为教师生成这节课的教学ppt,页数在20页左右。PPT的内容主要是讲解该课程中所有可能涉及到的知识点。
  184. ## 工作流
  185. 1. 提供的参考资料中读取10个最重要的知识点(知识点水平限制在小学和初中,作为ppt内容。
  186. 2. 针对10个知识点中的每个,你使用1~3页ppt详细的对知识点进行讲解。你的讲解词应该在100token左右
  187. 3. 讲解完所有知识点后,再根据知识点出5道单选题(放在5页ppt中)。
  188. # Format example
  189. [{"page": "页码(数字)","title": "标题","task": "对应教学任务:依据用户输入的参考资料而定,如果用户未提供则不输出","points": "知识点讲解:针对知识点的详细讲解,你的语气应该让小学或初中的学生清晰易懂的讲解。你的讲解词在100 token左右。请尽可能的详细,这对我很重要。"}]`
  190. } else if (_this.radio == 1) {
  191. } else if (_this.radio == 2) {
  192. }
  193. // let params = JSON.stringify({
  194. // // "model": "Chat",
  195. // model: 'gpt-3.5-turbo',
  196. // temperature: 0,
  197. // max_tokens: 4096,
  198. // top_p: 1,
  199. // frequency_penalty: 0,
  200. // presence_penalty: 0,
  201. // messages: [{
  202. // content: message,
  203. // role: 'user'
  204. // }],
  205. // stream: false,
  206. // uid: this.userid,
  207. // mind_map_question: "",
  208. // })
  209. // _this.loading = true
  210. // _this.ajax.post('https://gpt4.cocorobo.cn/chat', params).then(function (response) {
  211. // console.log(response);
  212. // let data = response.data.FunctionResponse
  213. // if (data.choices && data.choices.length && data.choices[0].message) {
  214. // console.log(data.choices[0].message.content);
  215. // try {
  216. // let _data = JSON.parse(data.choices[0].message.content)
  217. // _this.createPpt(_data)
  218. // } catch (e) {
  219. // console.log('error_________________'+e);
  220. // _this.$message.error(data.choices[0].message.content)
  221. // _this.loading = false
  222. // }
  223. // }
  224. // }).catch(function (error) {
  225. // _this.loading = false
  226. // console.log(error);
  227. // });
  228. let parm = {
  229. assistant_id: '6063369f-289a-11ef-8bf4-12e77c4cb76b',
  230. message: [{"type":"text", "text":message}],
  231. session_name: uuidv4(),
  232. userId: this.userid,
  233. file_ids: fileid.length ? [...fileid] : '',
  234. }
  235. _this.loading = true
  236. this.ajax
  237. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", parm)
  238. .then((response) => {
  239. console.log(response);
  240. let data = response.data.FunctionResponse
  241. if (data.message) {
  242. console.log(data.message);
  243. try {
  244. let _data = JSON.parse(data.message.replaceAll('```json','').replaceAll('```',''))
  245. _this.createPpt(_data)
  246. } catch (e) {
  247. console.log('error_________________'+e);
  248. _this.$message.error(data.message)
  249. _this.loading = false
  250. }
  251. }
  252. })
  253. .catch((error) => {
  254. _this.loading = false
  255. console.log(error);
  256. });
  257. },
  258. createPpt(array) {
  259. // 1. 创建PPT
  260. const pres = new Pptxgen()
  261. for (var i = 0; i < array.length; i++) {
  262. // 2. 创建一个PPT页面,每调用一次 pres.addSlide() 都可以生成一张新的页面
  263. // 建议把每个页面的构造抽成一个个函数,然后通过函数调用生成新页面,代码不会很乱
  264. const _slide = pres.addSlide()
  265. // 3. 调用addTetx(),在PPT页面中插入文字“Hello World from PptxGenJS...”
  266. // 括号里面是对文字的配置,文字横坐标x为1.5,纵坐标y为1.5,字体颜色 363636……
  267. // 关于坐标长度与px的转换 x 1 = 127~128px 左右
  268. const tempResult1 = array[i].title
  269. _slide.addText(tempResult1, {
  270. x: 0.5, // 横坐标
  271. y: 0.5,
  272. color: '363636',
  273. fontSize: 24, // 字号
  274. fill: { color: 'F1F1F1' },
  275. align: 'center'
  276. })
  277. const tempResult2 = array[i].task
  278. _slide.addText(tempResult2, {
  279. x: 0.5, // 横坐标
  280. y: 2,
  281. color: '363636',
  282. fontSize: 18, // 字号
  283. fill: { color: 'F1F1F1' },
  284. align: 'center'
  285. })
  286. const tempResult3 = array[i].points
  287. _slide.addText(tempResult3, {
  288. x: 0.5, // 横坐标
  289. y: 4,
  290. color: '363636',
  291. fontSize: 18, // 字号
  292. fill: { color: 'F1F1F1' },
  293. align: 'center'
  294. })
  295. }
  296. // 获取PPTX文件的ArrayBuffer
  297. // 保存为 Blob 并处理
  298. pres.write('blob').then((blob) => {
  299. // 现在你有了一个 Blob 对象
  300. console.log(blob);
  301. const file = new File([blob], 'aiPpt.pptx', { type: "application/vnd.openxmlformats-officedocument.presentationml.presentation" });
  302. console.log(pres)
  303. this.beforeUpload(file)
  304. });
  305. },
  306. beforeUpload(event) {
  307. var file = event;
  308. var credentials = {
  309. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  310. secretAccessKey: "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",
  311. }; //秘钥形式的登录上传
  312. window.AWS.config.update(credentials);
  313. window.AWS.config.region = "cn-northwest-1"; //设置区域
  314. var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
  315. var _this = this;
  316. if (file) {
  317. var params = {
  318. Key:
  319. file.name.split(".")[0] +
  320. new Date().getTime() +
  321. "." +
  322. file.name.split(".")[file.name.split(".").length - 1],
  323. ContentType: file.type,
  324. Body: file,
  325. "Access-Control-Allow-Credentials": "*",
  326. ACL: "public-read",
  327. }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
  328. var options = {
  329. partSize: 2048 * 1024 * 1024,
  330. queueSize: 2,
  331. leavePartsOnError: true,
  332. };
  333. bucket
  334. .upload(params, options)
  335. .on("httpUploadProgress", function (evt) {
  336. //这里可以写进度条
  337. // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
  338. })
  339. .send(function (err, data) {
  340. _this.loading = false
  341. if (err) {
  342. _this.$message.error("上传失败");
  343. } else {
  344. _this.url = data.Location
  345. _this.uJson = {
  346.                   name: file.name,
  347.                   url: data.Location,
  348.                   type: 3,
  349.                 }
  350. console.log(data.Location);
  351. }
  352. });
  353. }
  354. },
  355. },
  356. }
  357. </script>
  358. <style scoped>
  359. .dialog_diy>>>.el-dialog {
  360. height: auto;
  361. margin: 15vh auto 0 !important;
  362. }
  363. .dialog_diy>>>.el-dialog__header {
  364. background: #454545 !important;
  365. padding: 15px 20px;
  366. }
  367. .dialog_diy>>>.el-dialog__body {
  368. height: calc(100% - 124px);
  369. box-sizing: border-box;
  370. padding: 0px;
  371. }
  372. .dialog_diy>>>.el-dialog__title {
  373. color: #fff;
  374. }
  375. .dialog_diy>>>.el-dialog__headerbtn {
  376. top: 19px;
  377. }
  378. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
  379. color: #fff;
  380. }
  381. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
  382. color: #fff;
  383. }
  384. .dialog_diy>>>.el-dialog__body,
  385. .dialog_diy>>>.el-dialog__footer {
  386. background: #fafafa;
  387. }
  388. .binfo_input {
  389. width: 100%;
  390. margin: 0;
  391. padding: 5px 7px;
  392. display: block;
  393. min-width: 0;
  394. outline: none;
  395. box-sizing: border-box;
  396. background: none;
  397. border: none;
  398. border-radius: 4px;
  399. background: #fff;
  400. font-size: 15px;
  401. resize: none;
  402. font-family: "Microsoft YaHei";
  403. min-height: 48px;
  404. /* border: 1px solid #3682fc00; */
  405. border: 1.5px solid #cad1dc;
  406. }
  407. .binfo_textarea {
  408. border: 1.5px solid #cad1dc;
  409. font-size: 15px;
  410. resize: none;
  411. /* background: #f6f6f6; */
  412. font-family: "Microsoft YaHei";
  413. }
  414. .binfo_input:focus-visible {
  415. border: 1.5px solid #3681fc !important;
  416. }
  417. .t_box {
  418. display: flex;
  419. margin-bottom: 15px;
  420. }
  421. .t_box>span:nth-child(1) {
  422. min-width: 80px;
  423. font-size: 16px;
  424. color: #000;
  425. }
  426. </style>