|
@@ -1,51 +1,93 @@
|
|
|
<template>
|
|
|
- <el-dialog title="AI生成" :visible.sync="dialogVisibleAiCreate" :append-to-body="true" width="650px" :before-close="handleClose"
|
|
|
- class="dialog_diy">
|
|
|
- <div style="height: 100%;padding:15px">
|
|
|
- <div class="t_box">
|
|
|
+ <el-dialog title="AI生成PPT" :visible.sync="dialogVisibleAiCreate" :append-to-body="true" width="700px"
|
|
|
+ :before-close="handleClose" class="dialog_diy">
|
|
|
+ <div style="height: 500px;padding:15px" v-loading="loading">
|
|
|
+ <!-- <div class="t_box">
|
|
|
<span>选择:</span>
|
|
|
- <el-radio-group v-model="radio">
|
|
|
+ <el-radio-group v-model="radio" @change="changeRadio">
|
|
|
<el-radio :label="0">PPT</el-radio>
|
|
|
<el-radio :label="1">教案</el-radio>
|
|
|
<el-radio :label="2">视频</el-radio>
|
|
|
</el-radio-group>
|
|
|
- </div>
|
|
|
- <div class="t_box">
|
|
|
+ </div> -->
|
|
|
+ <!-- <div class="t_box">
|
|
|
<span>提示词:</span>
|
|
|
<textarea rows="10" class="binfo_input binfo_textarea" cols placeholder="请输入提示词"
|
|
|
v-model="detail"></textarea>
|
|
|
- </div>
|
|
|
-
|
|
|
+ </div> -->
|
|
|
+ <wOffice v-if="url" :url="url"></wOffice>
|
|
|
</div>
|
|
|
<span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="aiGet" type="primary">重新生成</el-button>
|
|
|
<el-button @click="confirm" type="primary">确 定</el-button>
|
|
|
<el-button @click="close">关 闭</el-button>
|
|
|
</span>
|
|
|
</el-dialog>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
<script>
|
|
|
+import Pptxgen from "pptxgenjs"
|
|
|
+import wOffice from '../components/wOffice.vue'
|
|
|
|
|
|
export default {
|
|
|
+ components: {
|
|
|
+ wOffice,
|
|
|
+ },
|
|
|
props: {
|
|
|
dialogVisibleAiCreate: {
|
|
|
type: Boolean,
|
|
|
default: false
|
|
|
},
|
|
|
+ courseName: {
|
|
|
+ type: String,
|
|
|
+ default: ""
|
|
|
+ }
|
|
|
},
|
|
|
+ // 根据用户给你的参考资料
|
|
|
data() {
|
|
|
return {
|
|
|
+ userid: this.$route.query.userid,
|
|
|
radio: 0,
|
|
|
- detail: ""
|
|
|
+ aiJson: {
|
|
|
+ ppt: `## 任务
|
|
|
+请生成关于${this.courseName},为教师生成这节课的教学ppt,页数在20页左右。PPT的内容主要是讲解该课程中所有可能涉及到的知识点。
|
|
|
+
|
|
|
+## 工作流
|
|
|
+1. 从用户提供的参考资料中提取10个最重要的知识点(知识点水平限制在小学和初中),并输出。
|
|
|
+2. 针对10个知识点中的每个,你使用1~3页ppt详细的对知识点进行讲解。你的讲解词应该在100token左右
|
|
|
+3. 讲解完所有知识点后,再根据知识点出5道单选题(放在5页ppt中)
|
|
|
+
|
|
|
+## 限制
|
|
|
+- 你不能输出错误的知识,如果你实在不清楚,输出“对不起,我不确定”
|
|
|
+- 你不能输出违反伦理的内容`,
|
|
|
+ word: '',
|
|
|
+ video: ''
|
|
|
+ },
|
|
|
+ aiUrl: {
|
|
|
+ ppt: '',
|
|
|
+ word: '',
|
|
|
+ video: ''
|
|
|
+ },
|
|
|
+ detail: "",
|
|
|
+ loading: false,
|
|
|
+ url: "",
|
|
|
+ uJson: {}
|
|
|
}
|
|
|
},
|
|
|
- watch:{
|
|
|
+ watch: {
|
|
|
dialogVisibleAiCreate(newValue, oldValue) {
|
|
|
- if(newValue){
|
|
|
- this.text = JSON.parse(JSON.stringify(this.aiText))
|
|
|
- if(this.clickType == 2){
|
|
|
- this.confirm();
|
|
|
- }
|
|
|
+ if (newValue) {
|
|
|
+ // if (this.radio == 0) {
|
|
|
+ this.detail = this.aiJson.ppt
|
|
|
+ // }
|
|
|
+ // if (this.radio == 1) {
|
|
|
+ // this.detail = this.aiJson.word
|
|
|
+ // }
|
|
|
+ // if (this.radio == 2) {
|
|
|
+ // this.detail = this.aiJson.video
|
|
|
+ // }
|
|
|
+ // this.loading = false
|
|
|
+ this.aiGet()
|
|
|
}
|
|
|
},
|
|
|
},
|
|
@@ -57,14 +99,194 @@ export default {
|
|
|
close() {
|
|
|
this.$emit('update:dialogVisibleAiCreate', false)
|
|
|
},
|
|
|
- confirm(){
|
|
|
- this.$emit("aiConfirm",this.text);
|
|
|
- this.$emit('update:dialogVisibleAiCreate', false)
|
|
|
- }
|
|
|
+ confirm() {
|
|
|
+ if(this.url){
|
|
|
+ this.$emit('createAiPpt', this.uJson)
|
|
|
+ }else {
|
|
|
+ this.$message.error('请先生成ppt');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeRadio() {
|
|
|
+ if (this.radio == 0) {
|
|
|
+ this.detail = this.aiJson.ppt
|
|
|
+ }
|
|
|
+ if (this.radio == 1) {
|
|
|
+ this.detail = this.aiJson.word
|
|
|
+ }
|
|
|
+ if (this.radio == 2) {
|
|
|
+ this.detail = this.aiJson.video
|
|
|
+ }
|
|
|
+ },
|
|
|
+ aiGet() {
|
|
|
+ if(this.loading){
|
|
|
+ this.$message.error('正在生成中,请稍后');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.url = ''
|
|
|
+ this.uJson = {}
|
|
|
+ let _this = this
|
|
|
+ let message = ''
|
|
|
+ if (_this.radio == 0) {
|
|
|
+ message = `ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
|
|
|
+
|
|
|
+${this.detail}
|
|
|
+
|
|
|
+## 要求
|
|
|
+根据Format example的要求返回要以数组的格式
|
|
|
+
|
|
|
+## Format example
|
|
|
+[{"page": "页码(数字)","title": "标题","task": "对应教学任务:依据用户输入的参考资料而定,如果用户未提供则不输出","points": "知识点讲解:针对知识点的详细讲解,你的语气应该让小学或初中的学生清晰易懂的讲解。你的讲解词在100 token左右。请尽可能的详细,这对我很重要。"}]`
|
|
|
+ } else if (_this.radio == 1) {
|
|
|
+
|
|
|
+ } else if (_this.radio == 2) {
|
|
|
+
|
|
|
+ }
|
|
|
+ let params = JSON.stringify({
|
|
|
+ // "model": "Chat",
|
|
|
+ model: 'gpt-3.5-turbo',
|
|
|
+ temperature: 0,
|
|
|
+ max_tokens: 4096,
|
|
|
+ top_p: 1,
|
|
|
+ frequency_penalty: 0,
|
|
|
+ presence_penalty: 0,
|
|
|
+ messages: [{
|
|
|
+ content: message,
|
|
|
+ role: 'user'
|
|
|
+ }],
|
|
|
+ stream: false,
|
|
|
+ uid: this.userid,
|
|
|
+ mind_map_question: "",
|
|
|
+ })
|
|
|
+
|
|
|
+ _this.loading = true
|
|
|
+ _this.ajax.post('https://gpt4.cocorobo.cn/chat', params).then(function (response) {
|
|
|
+ console.log(response);
|
|
|
+ let data = response.data.FunctionResponse
|
|
|
+ if (data.choices && data.choices.length && data.choices[0].message) {
|
|
|
+ console.log(data.choices[0].message.content);
|
|
|
+ try {
|
|
|
+ let _data = JSON.parse(data.choices[0].message.content)
|
|
|
+ _this.createPpt(_data)
|
|
|
+ } catch (e) {
|
|
|
+ console.log('error_________________'+e);
|
|
|
+ _this.$message.error(data.choices[0].message.content)
|
|
|
+ _this.loading = false
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }).catch(function (error) {
|
|
|
+ _this.loading = false
|
|
|
+ console.log(error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ createPpt(array) {
|
|
|
+ // 1. 创建PPT
|
|
|
+ const pres = new Pptxgen()
|
|
|
+ for (var i = 0; i < array.length; i++) {
|
|
|
+ // 2. 创建一个PPT页面,每调用一次 pres.addSlide() 都可以生成一张新的页面
|
|
|
+ // 建议把每个页面的构造抽成一个个函数,然后通过函数调用生成新页面,代码不会很乱
|
|
|
+ const _slide = pres.addSlide()
|
|
|
+
|
|
|
+ // 3. 调用addTetx(),在PPT页面中插入文字“Hello World from PptxGenJS...”
|
|
|
+ // 括号里面是对文字的配置,文字横坐标x为1.5,纵坐标y为1.5,字体颜色 363636……
|
|
|
+ // 关于坐标长度与px的转换 x 1 = 127~128px 左右
|
|
|
+ const tempResult1 = array[i].title
|
|
|
+ _slide.addText(tempResult1, {
|
|
|
+ x: 0.5, // 横坐标
|
|
|
+ y: 0.5,
|
|
|
+ color: '363636',
|
|
|
+ fontSize: 24, // 字号
|
|
|
+ fill: { color: 'F1F1F1' },
|
|
|
+ align: 'center'
|
|
|
+ })
|
|
|
+ const tempResult2 = array[i].task
|
|
|
+ _slide.addText(tempResult2, {
|
|
|
+ x: 0.5, // 横坐标
|
|
|
+ y: 2,
|
|
|
+ color: '363636',
|
|
|
+ fontSize: 18, // 字号
|
|
|
+ fill: { color: 'F1F1F1' },
|
|
|
+ align: 'center'
|
|
|
+ })
|
|
|
+ const tempResult3 = array[i].points
|
|
|
+ _slide.addText(tempResult3, {
|
|
|
+ x: 0.5, // 横坐标
|
|
|
+ y: 4,
|
|
|
+ color: '363636',
|
|
|
+ fontSize: 18, // 字号
|
|
|
+ fill: { color: 'F1F1F1' },
|
|
|
+ align: 'center'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取PPTX文件的ArrayBuffer
|
|
|
+
|
|
|
+ // 保存为 Blob 并处理
|
|
|
+ pres.write('blob').then((blob) => {
|
|
|
+ // 现在你有了一个 Blob 对象
|
|
|
+ console.log(blob);
|
|
|
+
|
|
|
+ const file = new File([blob], 'aiPpt.pptx', { type: "application/vnd.openxmlformats-officedocument.presentationml.presentation" });
|
|
|
+ console.log(pres)
|
|
|
+ this.beforeUpload(file)
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ beforeUpload(event) {
|
|
|
+ var file = event;
|
|
|
+ var credentials = {
|
|
|
+ accessKeyId: "AKIATLPEDU37QV5CHLMH",
|
|
|
+ secretAccessKey: "Q2SQw37HfolS7yeaR1Ndpy9Jl4E2YZKUuuy2muZR",
|
|
|
+ }; //秘钥形式的登录上传
|
|
|
+ window.AWS.config.update(credentials);
|
|
|
+ window.AWS.config.region = "cn-northwest-1"; //设置区域
|
|
|
+
|
|
|
+ var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
|
|
|
+ var _this = this;
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ var params = {
|
|
|
+ Key:
|
|
|
+ file.name.split(".")[0] +
|
|
|
+ new Date().getTime() +
|
|
|
+ "." +
|
|
|
+ file.name.split(".")[file.name.split(".").length - 1],
|
|
|
+ ContentType: file.type,
|
|
|
+ Body: file,
|
|
|
+ "Access-Control-Allow-Credentials": "*",
|
|
|
+ ACL: "public-read",
|
|
|
+ }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
|
|
|
+ var options = {
|
|
|
+ partSize: 2048 * 1024 * 1024,
|
|
|
+ queueSize: 2,
|
|
|
+ leavePartsOnError: true,
|
|
|
+ };
|
|
|
+ bucket
|
|
|
+ .upload(params, options)
|
|
|
+ .on("httpUploadProgress", function (evt) {
|
|
|
+ //这里可以写进度条
|
|
|
+ // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
|
|
|
+ })
|
|
|
+ .send(function (err, data) {
|
|
|
+ _this.loading = false
|
|
|
+ if (err) {
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ } else {
|
|
|
+ _this.url = data.Location
|
|
|
+ _this.uJson = {
|
|
|
+ name: file.name,
|
|
|
+ url: data.Location,
|
|
|
+ type: 3,
|
|
|
+ }
|
|
|
+ console.log(data.Location);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
},
|
|
|
}
|
|
|
</script>
|
|
|
-
|
|
|
+
|
|
|
<style scoped>
|
|
|
.dialog_diy>>>.el-dialog {
|
|
|
height: auto;
|