aiCreateDialog.vue 12 KB

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