s生成PPT
This commit is contained in:
parent
050f87a84a
commit
8a8f90ce16
|
@ -97,4 +97,34 @@ const getProgress = async (id) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { createOutline, getBackGround, createPPT, getProgress, createByOutline };
|
const getBackGroundV2 = async () => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aipptV2/themeListV2", "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const createPPTV2 = async (data) => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aipptV2/createV2", "POST", data);
|
||||||
|
console.log("createOutline response:", response);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getProgressV2 = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await req(`/api/aipptV2/progressV2?sid=${id}`, "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createPPTV2, getProgressV2, createByOutline };
|
||||||
|
|
|
@ -0,0 +1,378 @@
|
||||||
|
<template>
|
||||||
|
<div class="ai-container">
|
||||||
|
<el-steps style="max-width:100% " :active="activeStep" align-center>
|
||||||
|
<el-step title="生成大纲" />
|
||||||
|
<el-step title="选择模板" />
|
||||||
|
<el-step title="制作PPT" />
|
||||||
|
</el-steps>
|
||||||
|
<div class="card-box">
|
||||||
|
<el-card class="card2" v-if="activeStep === 0">
|
||||||
|
<div class="paragraphs">
|
||||||
|
{{ outputText }}
|
||||||
|
</div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 1">
|
||||||
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
<div class="themes">
|
||||||
|
<div v-for="item in backGroundList" :key="item.key" :style="{
|
||||||
|
padding: '20px',
|
||||||
|
paddingRight: '30px',
|
||||||
|
paddingLeft: '30px',
|
||||||
|
margin: '10px',
|
||||||
|
backgroundColor: getBackgroundColor(item.key),
|
||||||
|
borderRadius: '10px',
|
||||||
|
borderBlock: '10px solid #e6e6e6'
|
||||||
|
}" @click="chooseBackground(item.key)" @mouseenter="changeCursor('pointer')" @mouseleave="changeCursor('default')">
|
||||||
|
{{ item.name }}
|
||||||
|
<br />
|
||||||
|
<img style="width: 150px; height: auto" :src="item.thumbnail" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row class="el-row">
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>自动配图</div>
|
||||||
|
<el-switch v-model="outlineData.is_figure" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>PPT作者名:</div>
|
||||||
|
<el-input v-model="outlineData.author" style="width: 50%" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 2">
|
||||||
|
<el-progress :percentage="percentage" type="circle" ></el-progress>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { creatAIPPT } from '@/utils/talkFile'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBackGround,
|
||||||
|
createPPT,
|
||||||
|
getProgress,
|
||||||
|
} from "@/utils/ppt-request.js";
|
||||||
|
import CryptoJS from "crypto-js"
|
||||||
|
|
||||||
|
import { getSignature } from "@/utils/index.js";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let apikey = "39d05b269fa229f431a56c21794a8ea5"
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
|
||||||
|
const outputText = ref(""); // 用于展示的大纲数据
|
||||||
|
const stagingData = ref([]); //储存的对话数据,用于多轮对话
|
||||||
|
const stagOutputText = ref(""); // 暂存大纲用于拆分
|
||||||
|
let extractedParts = ref([]) // 初步拆分
|
||||||
|
|
||||||
|
let firstArray = ref([]); //大纲的大纲等级数字部分
|
||||||
|
let secondArray = ref([]); //大纲的文字部分
|
||||||
|
|
||||||
|
|
||||||
|
const backGroundList = ref([]);
|
||||||
|
|
||||||
|
const inputTheme = ref("高中语文《沁园春雪》的授课课件"); // 输入的主题
|
||||||
|
const inputRequire = ref("") // 输入的需求
|
||||||
|
const activeStep = ref(0); // 上方进度条
|
||||||
|
const combined = ref('') // 修改完毕的大纲数据,准备传入ppt生成模型
|
||||||
|
|
||||||
|
const treeData = ref([]);
|
||||||
|
const status = ref("init");
|
||||||
|
|
||||||
|
const percentage = ref(0);
|
||||||
|
|
||||||
|
const getBackground = () => {
|
||||||
|
treeData.value = [];
|
||||||
|
getBackGround().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
backGroundList.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackgroundColor = (key) => {
|
||||||
|
return outlineData.value.theme === key ? '#83e2b6' : '#f5f5f5';
|
||||||
|
};
|
||||||
|
|
||||||
|
const outlineData = ref({
|
||||||
|
query: '', // 用户要求(最多8000字)
|
||||||
|
theme: 'auto', // ppt生成主题
|
||||||
|
author: 'AIX平台',
|
||||||
|
is_card_note: false, // 是否自动生成ppt演讲备注
|
||||||
|
is_cover_img: false, // 是否自动生成封面
|
||||||
|
is_figure: false, // 是否自动配图
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 将输入数据或返回数据存入记忆中
|
||||||
|
function updateStagingData(role, newData) {
|
||||||
|
stagingData.value.push({ role: role, content: newData });
|
||||||
|
}
|
||||||
|
//大纲直接生成ppt
|
||||||
|
const outlineCreatePPT = () => {
|
||||||
|
const newOutlineData = { ...outlineData.value, };
|
||||||
|
newOutlineData.query = outputText.value;
|
||||||
|
|
||||||
|
createPPT(newOutlineData).then((res) => {
|
||||||
|
console.log(res, "正在生成中");
|
||||||
|
activeStep.value = 2
|
||||||
|
|
||||||
|
const checkProgress = () => {
|
||||||
|
getProgress(res.sid).then((response) => {
|
||||||
|
percentage.value = response.process;
|
||||||
|
if (response && response.pptUrl && response.pptUrl.length > 4) {
|
||||||
|
// window.location.href = response.data.pptUrl;
|
||||||
|
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
emit('addSuccess',res)
|
||||||
|
ElMessage.success("生成成功");
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
checkProgress();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProgress();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//初次对话
|
||||||
|
const addMessage = () => {
|
||||||
|
const themeValue = inputTheme.value;
|
||||||
|
const requireValue = inputRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${themeValue}。具体内容要求为:${requireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
connectWebSocket(stagingData.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttsWS
|
||||||
|
function connectWebSocket(data) {
|
||||||
|
outputText.value = ""; //清楚展示部分内容
|
||||||
|
status.value = "ttsing";
|
||||||
|
return getWebsocketUrl().then((url) => {
|
||||||
|
ttsWS = new WebSocket(url);
|
||||||
|
ttsWS.onopen = () => {
|
||||||
|
webSocketSend(ttsWS, data);
|
||||||
|
};
|
||||||
|
ttsWS.onmessage = (e) => {
|
||||||
|
result1(e.data);
|
||||||
|
};
|
||||||
|
ttsWS.onerror = (e) => {
|
||||||
|
status.value = "error";
|
||||||
|
console.log("WebSocket error:", e);
|
||||||
|
};
|
||||||
|
ttsWS.onclose = () => {
|
||||||
|
status.value = "init";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWebsocketUrl() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var apiKey = apikey;
|
||||||
|
var apiSecret = secret;
|
||||||
|
var url = "wss://spark-api.xf-yun.com/v4.0/chat";
|
||||||
|
|
||||||
|
var host = "spark-api.xf-yun.com";
|
||||||
|
var date = new Date().toGMTString();
|
||||||
|
var algorithm = "hmac-sha256";
|
||||||
|
var headers = "host date request-line";
|
||||||
|
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
|
||||||
|
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
|
||||||
|
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||||
|
|
||||||
|
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||||||
|
var authorization = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.enc.Utf8.parse(authorizationOrigin)
|
||||||
|
);
|
||||||
|
|
||||||
|
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
|
console.log(url);
|
||||||
|
resolve(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function webSocketSend(ws, data) {
|
||||||
|
const params = {
|
||||||
|
header: {
|
||||||
|
app_id: appId,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
chat: {
|
||||||
|
domain: "4.0Ultra",
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 1024,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
message: {
|
||||||
|
text: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
function result1(resultData) {
|
||||||
|
let jsonData = JSON.parse(resultData);
|
||||||
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (jsonData.payload && jsonData.payload.usage) {
|
||||||
|
startExtraction() // 返回完毕后开始拆分大纲
|
||||||
|
console.log(firstArray.value, secondArray.value)
|
||||||
|
activeStep.value = 2
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (jsonData.header.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseBackground = (data) => {
|
||||||
|
outlineData.value.theme = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCursor = (cursorStyle) => {
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx"
|
||||||
|
// creatAIPPT(props.currentNode.itemtitle + '.pptx',url, props.uploadData).then((res) => {
|
||||||
|
// emit('addSuccess',res)
|
||||||
|
// })
|
||||||
|
// connectWebSocket("");
|
||||||
|
props.dataList.filter(item => {
|
||||||
|
inputRequire.value += item.answer
|
||||||
|
})
|
||||||
|
getBackground();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-container {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7f6;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card1 {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphs {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.themes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
outline-style: none;
|
||||||
|
/* margin: 5px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col>div,
|
||||||
|
.outline-row>.el-col>div>.el-input {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash {
|
||||||
|
margin-left: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash::after {
|
||||||
|
content: "";
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #c2dbf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row {
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
:deep(.el-card__body){
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,391 @@
|
||||||
|
<template>
|
||||||
|
<div class="ai-container">
|
||||||
|
<el-steps style="max-width:100% " :active="activeStep" align-center>
|
||||||
|
<el-step title="生成大纲" />
|
||||||
|
<el-step title="选择模板" />
|
||||||
|
<el-step title="制作PPT" />
|
||||||
|
</el-steps>
|
||||||
|
<div class="card-box">
|
||||||
|
<el-card class="card2" v-if="activeStep === 0">
|
||||||
|
<div class="paragraphs">
|
||||||
|
{{ outputText }}
|
||||||
|
</div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 1">
|
||||||
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
<div class="themes">
|
||||||
|
<div v-for="item in backGroundList" :key="item.templateIndexId" :style="{
|
||||||
|
padding: '5px',
|
||||||
|
paddingRight: '5px',
|
||||||
|
paddingLeft: '5px',
|
||||||
|
margin: '5px',
|
||||||
|
backgroundColor: getBackgroundColor(item.templateIndexId),
|
||||||
|
borderRadius: '10px',
|
||||||
|
borderBlock: '10px solid #e6e6e6'
|
||||||
|
}" @click="chooseBackground(item.templateIndexId)" @mouseenter="changeCursor('pointer')" @mouseleave="changeCursor('default')">
|
||||||
|
{{ item.name }}
|
||||||
|
<img style="width: 150px; height: auto" :src="getBackGroundImg(item.detailImage)" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row class="el-row">
|
||||||
|
<!-- <el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>演讲备注</div>
|
||||||
|
<el-switch v-model="outlineData.is_card_note" />
|
||||||
|
</div>
|
||||||
|
</el-col>-->
|
||||||
|
<!-- <el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>生成封面</div>
|
||||||
|
<el-switch v-model="outlineData.is_cover_img" />
|
||||||
|
</div>
|
||||||
|
</el-col>-->
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>自动配图</div>
|
||||||
|
<el-switch v-model="outlineData.isFigure" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>PPT作者名:</div>
|
||||||
|
<el-input v-model="outlineData.author" style="width: 50%" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep === 2">
|
||||||
|
<el-progress :percentage="30" type="circle" v-if="percentage === 30"></el-progress>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBackGroundV2,
|
||||||
|
createPPTV2,
|
||||||
|
getProgressV2,
|
||||||
|
} from "@/utils/ppt-request.js";
|
||||||
|
import CryptoJS from "crypto-js"
|
||||||
|
|
||||||
|
import { getSignature } from "@/utils/index.js";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let apikey = "39d05b269fa229f431a56c21794a8ea5"
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
|
||||||
|
const outputText = ref(""); // 用于展示的大纲数据
|
||||||
|
const stagingData = ref([]); //储存的对话数据,用于多轮对话
|
||||||
|
const stagOutputText = ref(""); // 暂存大纲用于拆分
|
||||||
|
let extractedParts = ref([]) // 初步拆分
|
||||||
|
|
||||||
|
let firstArray = ref([]); //大纲的大纲等级数字部分
|
||||||
|
let secondArray = ref([]); //大纲的文字部分
|
||||||
|
|
||||||
|
|
||||||
|
const backGroundList = ref([]);
|
||||||
|
|
||||||
|
const inputTheme = ref("高中语文《沁园春雪》的授课课件"); // 输入的主题
|
||||||
|
const inputRequire = ref("") // 输入的需求
|
||||||
|
const activeStep = ref(0); // 上方进度条
|
||||||
|
const combined = ref('') // 修改完毕的大纲数据,准备传入ppt生成模型
|
||||||
|
|
||||||
|
const treeData = ref([]);
|
||||||
|
const status = ref("init");
|
||||||
|
|
||||||
|
const percentage = ref(0);
|
||||||
|
|
||||||
|
const getBackgrounds = () => {
|
||||||
|
treeData.value = [];
|
||||||
|
getBackGroundV2().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
backGroundList.value = res.records;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackGroundImg = (imgUrlStr) => {
|
||||||
|
return JSON.parse(imgUrlStr).titleCoverImage
|
||||||
|
};
|
||||||
|
|
||||||
|
const outlineData = ref({
|
||||||
|
query: '', // 用户要求(最多8000字)
|
||||||
|
// templateId: 'auto', // ppt生成主题
|
||||||
|
author: 'AIX平台',
|
||||||
|
isFigure: false, // 是否自动配图
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 将输入数据或返回数据存入记忆中
|
||||||
|
function updateStagingData(role, newData) {
|
||||||
|
stagingData.value.push({ role: role, content: newData });
|
||||||
|
}
|
||||||
|
//大纲直接生成ppt
|
||||||
|
const outlineCreatePPT = () => {
|
||||||
|
const newOutlineData = { ...outlineData.value, };
|
||||||
|
newOutlineData.query = outputText.value;
|
||||||
|
|
||||||
|
createPPTV2(newOutlineData).then((res) => {
|
||||||
|
console.log(res, "正在生成中");
|
||||||
|
activeStep.value = 2
|
||||||
|
|
||||||
|
const checkProgress = () => {
|
||||||
|
getProgressV2(res.sid).then((response) => {
|
||||||
|
percentage.value = response.process;
|
||||||
|
if (response && response.pptUrl && response.pptUrl.length > 4) {
|
||||||
|
console.log('PPT',response)
|
||||||
|
// window.location.href = response.data.pptUrl;
|
||||||
|
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
emit('addSuccess',res)
|
||||||
|
ElMessage.success("生成成功");
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
checkProgress();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProgress();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//初次对话
|
||||||
|
const addMessage = () => {
|
||||||
|
const themeValue = inputTheme.value;
|
||||||
|
const requireValue = inputRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${themeValue}。具体内容要求为:${requireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
connectWebSocket(stagingData.value);
|
||||||
|
// activeStep.value = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
let ttsWS
|
||||||
|
function connectWebSocket(data) {
|
||||||
|
outputText.value = ""; //清楚展示部分内容
|
||||||
|
status.value = "ttsing";
|
||||||
|
return getWebsocketUrl().then((url) => {
|
||||||
|
ttsWS = new WebSocket(url);
|
||||||
|
ttsWS.onopen = () => {
|
||||||
|
webSocketSend(ttsWS, data);
|
||||||
|
};
|
||||||
|
ttsWS.onmessage = (e) => {
|
||||||
|
result1(e.data);
|
||||||
|
};
|
||||||
|
ttsWS.onerror = (e) => {
|
||||||
|
status.value = "error";
|
||||||
|
console.log("WebSocket error:", e);
|
||||||
|
};
|
||||||
|
ttsWS.onclose = () => {
|
||||||
|
status.value = "init";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBackgroundColor = (key) => {
|
||||||
|
return outlineData.value.templateId === key ? '#83e2b6' : '#f5f5f5';
|
||||||
|
};
|
||||||
|
|
||||||
|
function getWebsocketUrl() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var apiKey = apikey;
|
||||||
|
var apiSecret = secret;
|
||||||
|
var url = "wss://spark-api.xf-yun.com/v4.0/chat";
|
||||||
|
|
||||||
|
var host = "spark-api.xf-yun.com";
|
||||||
|
var date = new Date().toGMTString();
|
||||||
|
var algorithm = "hmac-sha256";
|
||||||
|
var headers = "host date request-line";
|
||||||
|
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
|
||||||
|
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
|
||||||
|
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||||
|
|
||||||
|
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||||||
|
var authorization = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.enc.Utf8.parse(authorizationOrigin)
|
||||||
|
);
|
||||||
|
|
||||||
|
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
|
console.log(url);
|
||||||
|
resolve(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function webSocketSend(ws, data) {
|
||||||
|
const params = {
|
||||||
|
header: {
|
||||||
|
app_id: appId,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
chat: {
|
||||||
|
domain: "4.0Ultra",
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 1024,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
message: {
|
||||||
|
text: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
function result1(resultData) {
|
||||||
|
let jsonData = JSON.parse(resultData);
|
||||||
|
console.log(jsonData)
|
||||||
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (jsonData.payload && jsonData.payload.usage) {
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (jsonData.header.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseBackground = (data) => {
|
||||||
|
outlineData.value.templateId = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCursor = (cursorStyle) => {
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx"
|
||||||
|
// creatAIPPT(props.currentNode.itemtitle + '.pptx',url, props.uploadData).then((res) => {
|
||||||
|
// emit('addSuccess',res)
|
||||||
|
// })
|
||||||
|
// connectWebSocket("init");
|
||||||
|
props.dataList.filter(item => {
|
||||||
|
inputRequire.value += item.answer
|
||||||
|
})
|
||||||
|
getBackgrounds();
|
||||||
|
// addMessage()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-container {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7f6;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card1 {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphs {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.themes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
outline-style: none;
|
||||||
|
/* margin: 5px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col>div,
|
||||||
|
.outline-row>.el-col>div>.el-input {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash {
|
||||||
|
margin-left: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash::after {
|
||||||
|
content: "";
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #c2dbf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row {
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
:deep(.el-card__body){
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog class="ppt-dialog" v-model="model" :show-close="false" width="800" destroy-on-close :top="'3vh'">
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4 :id="titleId" :class="titleClass">生成PPT(试验版)</h4>
|
||||||
|
<i class="iconfont icon-guanbi" @click="close"></i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<AiPptist @add-success="addAiPPT" :dataList="dataList"/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import AiPptist from './ai-pptist.vue';
|
||||||
|
const model = defineModel()
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const addAiPPT = (data) => {
|
||||||
|
emit('addSuccess', data)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.ppt-dialog){
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
.dialog-header{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.icon-guanbi {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue