|
|
|
|
@ -49,13 +49,13 @@
|
|
|
|
|
<span>三、模型参数设置</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="metrics-table" style="margin-top: 10px">
|
|
|
|
|
<el-select v-model="preProcessText.text3" placeholder="请选择模型" style="width: 180px" @change="preProcess">
|
|
|
|
|
<el-select v-model="preProcessText.text3" placeholder="请选择模型" style="width: 180px" @change="switchingModels">
|
|
|
|
|
<el-option label="评论观点抽取" value="评论观点抽取" />
|
|
|
|
|
<el-option label="情感倾向分析" value="情感倾向分析" />
|
|
|
|
|
<el-option label="词频分析" value="词频分析" />
|
|
|
|
|
<el-option label="词云生成" value="词云生成" />
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-button @click="modelCalculation">计算</el-button>
|
|
|
|
|
<el-button @click="sentimentAnalysis">情感分析</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="margin-top: auto">
|
|
|
|
|
@ -65,45 +65,77 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="main-right">
|
|
|
|
|
<div>
|
|
|
|
|
<span style="font-weight: bold; font-size: 18px; color: #3596eb">分析数据:</span>
|
|
|
|
|
<div class="text-type" v-show="preProcessText.text3 == '评论观点抽取'">
|
|
|
|
|
<el-button v-for="text in textType" :key="text" type="primary" plain>{{ text }}</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="analysis">
|
|
|
|
|
<el-input v-model="g_analyzeTheNumberOfDataItems" :rows="2" type="textarea" placeholder="" />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<el-button type="primary" plain @click="sentimentAnalysis">情感分析</el-button>
|
|
|
|
|
<el-button type="primary" plain>清空</el-button>
|
|
|
|
|
<div class="main-right" v-loading="loading" :element-loading-spinner="svg" element-loading-svg-view-box="-10, -10, 50, 50" element-loading-background="rgba(122, 122, 122, 0.8)">
|
|
|
|
|
<el-scrollbar height="550px" style="padding: 20px">
|
|
|
|
|
<div>
|
|
|
|
|
<span style="font-weight: bold; font-size: 18px; color: #3596eb">分析数据:</span>
|
|
|
|
|
<div class="text-type" v-show="preProcessText.text3 == '评论观点抽取'">
|
|
|
|
|
<el-button :class="s_commentType == text.id ? 'btnActive' : ''" v-for="text in textType" :key="text" type="primary" plain @click="commentType(text)">{{ text.name }}</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="analysis">
|
|
|
|
|
<el-input maxlength="256" show-word-limit v-model="g_analyzeTheNumberOfDataItems" :rows="2" type="textarea" placeholder="" />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<el-button type="primary" plain @click="sentimentAnalysis">情感分析</el-button>
|
|
|
|
|
<el-button type="primary" plain @click="clear">清空</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="analysisResults" style="margin-top: 20px">
|
|
|
|
|
<span style="font-weight: bold; font-size: 18px; color: #3596eb; display: block">分析结果:</span>
|
|
|
|
|
<el-button @click="download">下载</el-button>
|
|
|
|
|
<h4>词频列表</h4>
|
|
|
|
|
<p>你可以对词频词语进行修改删除以及增加,频次数越大,显示越大,最多200关键词。</p>
|
|
|
|
|
<div class="conditions">
|
|
|
|
|
<label>显示条件:</label>
|
|
|
|
|
<div>
|
|
|
|
|
<span>频次>=</span>
|
|
|
|
|
<el-input v-model="input" style="width: 120px" placeholder="" />
|
|
|
|
|
<div class="analysisResults" style="margin-top: 20px">
|
|
|
|
|
<span style="font-weight: bold; font-size: 18px; color: #3596eb; display: block">分析结果:</span>
|
|
|
|
|
<el-button @click="download">下载</el-button>
|
|
|
|
|
<div v-show="preProcessText.text3 == '词频分析'" v-loading="loading2" :element-loading-spinner="svg" element-loading-svg-view-box="-10, -10, 50, 50" element-loading-background="rgba(122, 122, 122, 0.8)">
|
|
|
|
|
<h4>词频列表</h4>
|
|
|
|
|
<p>你可以对词频词语进行修改删除以及增加,频次数越大,显示越大,最多200关键词。</p>
|
|
|
|
|
<div class="conditions">
|
|
|
|
|
<label>显示条件:</label>
|
|
|
|
|
<div>
|
|
|
|
|
<span>频次>=</span>
|
|
|
|
|
<el-input v-model="mWordFrequency.frequency" style="width: 120px" placeholder="" v-debounce="wordFrequencySearch" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<span>词语长度>=</span>
|
|
|
|
|
<el-input v-model="mWordFrequency.namenum" style="width: 120px" placeholder="" v-debounce="wordFrequencySearch" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table border :data="aWordFrequency" style="width: 80%" :header-cell-style="headerCellStyle">
|
|
|
|
|
<el-table-column :label="`内容(${aWordFrequency?.length || 0})`" align="center" prop="keyword" width="747" />
|
|
|
|
|
<el-table-column label="频次" align="center" prop="frequency" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<pagination :autoScroll="false" v-show="nOriginalWordFrequencyNum > 0" :total="nOriginalWordFrequencyNum" v-model:page="mWordFrequency.index" v-model:limit="mWordFrequency.size" @pagination="wordFrequencyNext" />
|
|
|
|
|
</div>
|
|
|
|
|
<!-- v-show="preProcessText.text3 == '词云生成'" -->
|
|
|
|
|
<div class="div" v-if="preProcessText.text3 == '词云生成'">
|
|
|
|
|
<div id="mywordcloud_positive" style="width: 50%; height: 600px"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<span>词语长度>=</span>
|
|
|
|
|
<el-input v-model="input" style="width: 120px" placeholder="" />
|
|
|
|
|
<div ref="captureElement" v-if="preProcessText.text3 == '情感倾向分析' && n_emotiveTendency">
|
|
|
|
|
<div class="emotion_analysis">
|
|
|
|
|
<div class="emotion_analysis-ani-in-le">
|
|
|
|
|
<span>正向情感</span>
|
|
|
|
|
<img src="../../../assets/images/笑脸.png" alt="" />
|
|
|
|
|
</div>
|
|
|
|
|
<el-progress style="width: 480px" :text-inside="true" :stroke-width="20" :percentage="n_emotiveTendency" :color="'#ff540a'" />
|
|
|
|
|
<div class="emotion_analysis-ani-in-ri">
|
|
|
|
|
<img src="" alt="" />
|
|
|
|
|
<span>负向情感</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="emotion_analysis_title">{{ g_emotionAnalysis == 0 ? "情感偏负向" : g_emotionAnalysis == 1 ? "情感偏中性" : "情感偏正向" }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div ref="captureElement" class="comment-opinion" v-if="preProcessText.text3 == '评论观点抽取'">
|
|
|
|
|
<div class="result" v-for="(item, sentiment) in aCommentOpinion" :key="item.abstract">
|
|
|
|
|
<div class="result-pos" :class="sentiment == 0 ? 'result-neg' : sentiment == 1 ? 'result-neutral' : 'result-img'"></div>
|
|
|
|
|
<div class="result-title">{{ sentiment == 0 ? "负向评价" : sentiment == 1 ? "中性评价" : "正向评价" }}:</div>
|
|
|
|
|
<div class="result-view" v-for="items in item" :key="items">
|
|
|
|
|
{{ items.prop + items.adj }}
|
|
|
|
|
<div class="result-bar"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table border :data="aWordFrequency" style="width: 80%" :header-cell-style="headerCellStyle">
|
|
|
|
|
<el-table-column label="内容(5)" align="center" prop="keyword" width="747"/>
|
|
|
|
|
<el-table-column label="频次" align="center" prop="frequency" />
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
</el-scrollbar>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- </el-scrollbar> -->
|
|
|
|
|
<el-dialog v-model="dialogVisible" title="实训任务提交" width="565" custom-class="dialogClass" :show-close="false">
|
|
|
|
|
<el-dialog v-model="dialogVisible" title="实训任务提交" width="700" custom-class="dialogClass" :show-close="false">
|
|
|
|
|
<template #header="{ close, titleId, titleClass }">
|
|
|
|
|
<div class="my-header">
|
|
|
|
|
<span :id="titleId" :class="titleClass">实训任务提交</span>
|
|
|
|
|
@ -112,42 +144,33 @@
|
|
|
|
|
<img class="xtImg" src="../../../assets/images/线条.png" alt="" />
|
|
|
|
|
</template>
|
|
|
|
|
<div class="from-item">
|
|
|
|
|
<el-form :inline="true" label-position="right" label-width="84px" :model="form" class="demo-form-inline">
|
|
|
|
|
<el-form-item label="平均数:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.average" clearable />
|
|
|
|
|
<el-form :inline="true" label-width="84px" :model="form" class="demo-form-inline">
|
|
|
|
|
<el-form-item label="平均数:" label-width="120px">
|
|
|
|
|
<el-form-item label="最多数量词语:" label-width="120px" label-position="left">
|
|
|
|
|
<el-input style="width: 140px" v-model="formInline.max" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="频次:" label-position="left" label-width="46px">
|
|
|
|
|
<el-input style="width: 140px" v-model="formInline.frequency" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="众数:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.mode" clearable />
|
|
|
|
|
<el-form-item label="评论观点抽取: " label-width="120px">
|
|
|
|
|
<el-form-item label="前两位词语:" label-width="120px" label-position="left">
|
|
|
|
|
<el-input style="width: 140px" v-model="formInline.text1" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-input style="width: 140px" v-model="formInline.text2" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="中位数:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.median" clearable />
|
|
|
|
|
<el-form-item label="情感倾向分析: " label-width="120px">
|
|
|
|
|
<el-radio-group v-model="formInline.emotional" style="margin-left: 31px">
|
|
|
|
|
<el-radio value="1" label="正向" size="large"></el-radio>
|
|
|
|
|
<el-radio value="2" label="负向" size="large"></el-radio>
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="标准差:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.standardDeviation" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="方差:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.variance" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="峰度:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.kurtosis" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="标准误差:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.standardError" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="偏度:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.skewness" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="最大值:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.max" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="最小值:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.min" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="求和:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.summation" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="观测数:">
|
|
|
|
|
<el-input style="width: 120px" v-model="formInline.observations" clearable />
|
|
|
|
|
<el-form-item label="词云生成: " label-width="120px">
|
|
|
|
|
<el-form-item label="中间最突出单词: " label-width="120px">
|
|
|
|
|
<el-input style="width: 140px" v-model="formInline.prominent" clearable />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
</div>
|
|
|
|
|
@ -160,14 +183,21 @@
|
|
|
|
|
</el-dialog>
|
|
|
|
|
</template>
|
|
|
|
|
<script setup>
|
|
|
|
|
import { paginate } from "@/utils/index.js";
|
|
|
|
|
import * as echarts from "echarts";
|
|
|
|
|
import * as XLSX from "XLSX";
|
|
|
|
|
import "echarts-wordcloud/dist/echarts-wordcloud";
|
|
|
|
|
import "echarts-wordcloud/dist/echarts-wordcloud.min";
|
|
|
|
|
import * as portraitModel from "@/api/portraitModel";
|
|
|
|
|
import * as API from "@/api/AI.js";
|
|
|
|
|
import * as marketingAlgorithmApi from "@/api/marketing-algorithm.js";
|
|
|
|
|
import html2canvas from "html2canvas";
|
|
|
|
|
import useAlgorithmStore from "@/store/modules/algorithm.js";
|
|
|
|
|
import useUserStore from "@/store/modules/user";
|
|
|
|
|
import { getUserInfo } from "@/utils/auth";
|
|
|
|
|
const userInfo = JSON.parse(getUserInfo());
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
const loading2 = ref(false);
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
|
|
const algorithmStore = useAlgorithmStore();
|
|
|
|
|
const multipleTableRef = ref(null);
|
|
|
|
|
@ -178,39 +208,42 @@ const n_dataTableQuery = ref({
|
|
|
|
|
tableName: "用户属性表",
|
|
|
|
|
userId: userInfo.userId,
|
|
|
|
|
});
|
|
|
|
|
const textType = ["酒店", "KTV", "丽人", "关食", "旅游", "健束", "教育", "商业", "房产", "汽车", "生活", "购物", "3C"];
|
|
|
|
|
const textType = [
|
|
|
|
|
{ name: "酒店", id: 1 },
|
|
|
|
|
{ name: "KTV", id: 2 },
|
|
|
|
|
{ name: "丽人", id: 3 },
|
|
|
|
|
{ name: "关食", id: 4 },
|
|
|
|
|
{ name: "旅游", id: 5 },
|
|
|
|
|
{ name: "健束", id: 6 },
|
|
|
|
|
{ name: "教育", id: 7 },
|
|
|
|
|
{ name: "商业", id: 8 },
|
|
|
|
|
{ name: "房产", id: 9 },
|
|
|
|
|
{ name: "汽车", id: 10 },
|
|
|
|
|
{ name: "生活", id: 11 },
|
|
|
|
|
{ name: "购物", id: 12 },
|
|
|
|
|
{ name: "3C", id: 13 },
|
|
|
|
|
];
|
|
|
|
|
const dialogVisible = ref(false);
|
|
|
|
|
const analysisData = ref([]);
|
|
|
|
|
const analysisHanderKry = ref([]);
|
|
|
|
|
//
|
|
|
|
|
const aWordFrequency=ref([])
|
|
|
|
|
//
|
|
|
|
|
const aWordFrequency = ref([]);
|
|
|
|
|
const s_commentType = ref("");
|
|
|
|
|
const tableLabel = reactive([
|
|
|
|
|
{ prop: "average", label: "平均数" },
|
|
|
|
|
{ prop: "median", label: "中位数" },
|
|
|
|
|
{ prop: "mode", label: "众数" },
|
|
|
|
|
{ prop: "standardDeviation", label: "标准差" },
|
|
|
|
|
{ prop: "variance", label: "方差" },
|
|
|
|
|
{ prop: "standardError", label: "标准误差" },
|
|
|
|
|
{ prop: "kurtosis", label: "峰度" },
|
|
|
|
|
{ prop: "skewness", label: "偏度" },
|
|
|
|
|
{ prop: "max", label: "最大值" },
|
|
|
|
|
{ prop: "min", label: "最小值" },
|
|
|
|
|
{ prop: "summation", label: "求和" },
|
|
|
|
|
{ prop: "observations", label: "观测数" },
|
|
|
|
|
{ prop: "max", label: "最多数量词语" },
|
|
|
|
|
{ prop: "frequency", label: "频次" },
|
|
|
|
|
{ prop: "text1", label: "前两位词语" },
|
|
|
|
|
{ prop: "text2", label: "前两位词语" },
|
|
|
|
|
{ prop: "emotional", label: "情感倾向分析" },
|
|
|
|
|
{ prop: "prominent", label: "中间最突出单词" },
|
|
|
|
|
]);
|
|
|
|
|
const formInline = ref({
|
|
|
|
|
average: "",
|
|
|
|
|
median: "",
|
|
|
|
|
mode: "",
|
|
|
|
|
standardDeviation: "",
|
|
|
|
|
variance: "",
|
|
|
|
|
standardError: "",
|
|
|
|
|
kurtosis: "",
|
|
|
|
|
skewness: "",
|
|
|
|
|
max: "",
|
|
|
|
|
min: "",
|
|
|
|
|
summation: "",
|
|
|
|
|
observations: "",
|
|
|
|
|
frequency: "",
|
|
|
|
|
text1: "",
|
|
|
|
|
text2: "",
|
|
|
|
|
emotional: "",
|
|
|
|
|
prominent: "",
|
|
|
|
|
});
|
|
|
|
|
const g_indicatorData = ref([]);
|
|
|
|
|
const preProcessText = ref({
|
|
|
|
|
@ -219,16 +252,29 @@ const preProcessText = ref({
|
|
|
|
|
text3: "",
|
|
|
|
|
});
|
|
|
|
|
const aOriginalDataOfAnalysisResults2 = ref({});
|
|
|
|
|
const nOriginalWordFrequency = ref([]); //词频原始数据
|
|
|
|
|
const nOriginalWordFrequencyNum = ref(0); //词频原始数据
|
|
|
|
|
const nOriginalWordFrequencySearch = ref([]); //词频原始数据
|
|
|
|
|
const mWordFrequency = ref({
|
|
|
|
|
index: 1,
|
|
|
|
|
size: 10,
|
|
|
|
|
namenum: "",
|
|
|
|
|
frequency: "",
|
|
|
|
|
}); //词频数据
|
|
|
|
|
|
|
|
|
|
// 分析变量
|
|
|
|
|
const g_analyzeTheNumberOfDataItems = ref("");
|
|
|
|
|
// 模型参数
|
|
|
|
|
const g_modelParameter = ref([]);
|
|
|
|
|
const n_emotiveTendency = ref(0);
|
|
|
|
|
const g_emotionAnalysis = ref(0);
|
|
|
|
|
const aCommentOpinion = ref([]);
|
|
|
|
|
// 预处理
|
|
|
|
|
const preProcess = (tetx) => {
|
|
|
|
|
if (analysisData.value.length == 0) {
|
|
|
|
|
if (g_indicatorData.value.length == 0) {
|
|
|
|
|
proxy.$modal.msgWarning("请先选择指标进行数据分析!");
|
|
|
|
|
preProcessText.value.text2 = "";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
API.dataPreprocessing({
|
|
|
|
|
mapList: analysisData.value,
|
|
|
|
|
@ -263,9 +309,11 @@ const handleSelectionChange = (type) => {
|
|
|
|
|
// 提交指標
|
|
|
|
|
const submit = () => {
|
|
|
|
|
if (g_indicatorData.value.length == 0) return proxy.$modal.msgWarning("请选择指标");
|
|
|
|
|
loading.value = true;
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithm({ userId: n_dataTableQuery.value.userId, tableName: n_dataTableQuery.value.tableName, fieldList: g_indicatorData.value }).then((res) => {
|
|
|
|
|
g_analyzeTheNumberOfDataItems.value = res.data.map((item) => (item ? item.text : "")).join(",");
|
|
|
|
|
analysisData.value = res.data.filter((item) => item !== null);
|
|
|
|
|
loading.value = false;
|
|
|
|
|
proxy.$modal.msgSuccess("分析数据成功");
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
@ -279,8 +327,8 @@ const modelCalculation = () => {
|
|
|
|
|
proxy.$modal.msgWarning("请先分析数据/未选择模型参数!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const processedData = processArrayData(analysisHanderKry.value, analysisData.value);
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithmPreprocessing(JSON.stringify({ map: processedData, statistic: g_modelParameter.value, userId: n_dataTableQuery.value.userId })).then((res) => {
|
|
|
|
|
const processedData = processArrayData(["text"], analysisData.value);
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithmPreprocessing(JSON.stringify({ map: processedData, statistic: [preProcessText.value.text3 == "词云生成" ? "词频分析" : preProcessText.value.text3], userId: n_dataTableQuery.value.userId })).then((res) => {
|
|
|
|
|
aOriginalDataOfAnalysisResults2.value = res.data;
|
|
|
|
|
tableData.value = res.data.map((item) => item.statistics);
|
|
|
|
|
if (res.data.length > 5) {
|
|
|
|
|
@ -327,7 +375,7 @@ const submitTask = () => {
|
|
|
|
|
portraitModel
|
|
|
|
|
.submit({
|
|
|
|
|
userId: n_dataTableQuery.value.userId,
|
|
|
|
|
taskName: "描述性统计",
|
|
|
|
|
taskName: "情感分析",
|
|
|
|
|
numberOfErrors: 0,
|
|
|
|
|
})
|
|
|
|
|
.then((res) => {
|
|
|
|
|
@ -363,33 +411,198 @@ const restart = () => {
|
|
|
|
|
proxy.$modal.msgSuccess("重新开始成功");
|
|
|
|
|
multipleTableRef.value.clearSelection();
|
|
|
|
|
};
|
|
|
|
|
const captureElement = ref(null);
|
|
|
|
|
// 下载
|
|
|
|
|
const download = () => {
|
|
|
|
|
aOriginalDataOfAnalysisResults2.value.forEach((item) => {
|
|
|
|
|
item.statistics.field = item.field;
|
|
|
|
|
for (let key in item.statistics) {
|
|
|
|
|
item.statistics[key] = item.statistics[key] ?? 0;
|
|
|
|
|
const download = async () => {
|
|
|
|
|
// let tableData = ["内容", "频次"];
|
|
|
|
|
// XLSX.utils.aoa_to_sheet(tableData);
|
|
|
|
|
if (preProcessText.value.text3 == "情感倾向分析" || preProcessText.value.text3 == "评论观点抽取") {
|
|
|
|
|
if (captureElement.value) {
|
|
|
|
|
try {
|
|
|
|
|
// 使用 html2canvas 将元素转换为画布
|
|
|
|
|
let VDOM = document.querySelector(".emotion_analysis_title");
|
|
|
|
|
let VDOM2 = document.querySelector(".result");
|
|
|
|
|
|
|
|
|
|
if (preProcessText.value.text3 == "情感倾向分析") {
|
|
|
|
|
VDOM.style.color = "#221f1f";
|
|
|
|
|
} else {
|
|
|
|
|
VDOM2.style.color = "#212020";
|
|
|
|
|
}
|
|
|
|
|
const canvas = await html2canvas(captureElement.value);
|
|
|
|
|
|
|
|
|
|
// 将画布转换为图片
|
|
|
|
|
const image = canvas.toDataURL("image/png");
|
|
|
|
|
// 创建一个链接,设置为图片的下载链接
|
|
|
|
|
const link = document.createElement("a");
|
|
|
|
|
link.href = image;
|
|
|
|
|
link.download = `${preProcessText.value.text3}.png`; // 图片的文件名
|
|
|
|
|
// 触发点击事件,下载图片
|
|
|
|
|
link.click();
|
|
|
|
|
if (preProcessText.value.text3 == "情感倾向分析") {
|
|
|
|
|
VDOM.style.color = "#ffffff";
|
|
|
|
|
} else {
|
|
|
|
|
VDOM2.style.color = "#ffffff";
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("无法生成图片", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (preProcessText.value.text3 == "词频分析") {
|
|
|
|
|
const aoaData = [
|
|
|
|
|
["内容", "频次"], // 标题行
|
|
|
|
|
...nOriginalWordFrequency.value.map((item) => [item.keyword, item.frequency]), // 数据行
|
|
|
|
|
];
|
|
|
|
|
const worksheet = XLSX.utils.aoa_to_sheet(aoaData);
|
|
|
|
|
const workbook = XLSX.utils.book_new();
|
|
|
|
|
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
|
|
|
|
|
XLSX.writeFile(workbook, "词频分析.xlsx");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 情感分析
|
|
|
|
|
const sentimentAnalysis = () => {
|
|
|
|
|
let g_emotionAnalysisinfo = {};
|
|
|
|
|
if (g_indicatorData.value.length > 0) {
|
|
|
|
|
if (preProcessText.value.text2 == "") return proxy.$modal.msgWarning("请先对数据进行预处理!");
|
|
|
|
|
}
|
|
|
|
|
if (preProcessText.value.text3 == "") return proxy.$modal.msgWarning("请先选择模型!");
|
|
|
|
|
if (preProcessText.value.text3 === "评论观点抽取" && s_commentType.value == "") {
|
|
|
|
|
return proxy.$modal.msgWarning("请先选择评论类型!");
|
|
|
|
|
}
|
|
|
|
|
if (g_analyzeTheNumberOfDataItems.value == "") return proxy.$modal.msgWarning("请先选择指标/手动输入进行情感分析!");
|
|
|
|
|
loading.value = true;
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithmSentiment({ id: s_commentType.value, userId: n_dataTableQuery.value.userId, content: g_analyzeTheNumberOfDataItems.value, modelType: preProcessText.value.text3 == "词云生成" ? "词频分析" : preProcessText.value.text3 }).then((res) => {
|
|
|
|
|
if (preProcessText.value.text3 === "词云生成") {
|
|
|
|
|
nOriginalWordFrequency.value = res.data;
|
|
|
|
|
initChart();
|
|
|
|
|
} else if (preProcessText.value.text3 === "词频分析") {
|
|
|
|
|
nOriginalWordFrequency.value = res.data;
|
|
|
|
|
aWordFrequency.value = res.data.slice(0, 5);
|
|
|
|
|
nOriginalWordFrequencyNum.value = res.data.length;
|
|
|
|
|
} else if (preProcessText.value.text3 === "情感倾向分析") {
|
|
|
|
|
g_emotionAnalysisinfo = JSON.parse(res.data);
|
|
|
|
|
g_emotionAnalysis.value = JSON.parse(res.data)?.items[0]?.sentiment;
|
|
|
|
|
n_emotiveTendency.value = Math.round(g_emotionAnalysisinfo.items[0].positive_prob * 100);
|
|
|
|
|
} else {
|
|
|
|
|
aCommentOpinion.value = JSON.parse(res.data).items.reduce((groups, item) => {
|
|
|
|
|
// 如果该 sentiment 的组不存在,则创建
|
|
|
|
|
if (!groups[item.sentiment]) {
|
|
|
|
|
groups[item.sentiment] = [];
|
|
|
|
|
}
|
|
|
|
|
// 将 item 加入到相应的组中
|
|
|
|
|
groups[item.sentiment].push(item);
|
|
|
|
|
return groups;
|
|
|
|
|
}, {});
|
|
|
|
|
}
|
|
|
|
|
loading.value = false;
|
|
|
|
|
proxy.$modal.msgSuccess("分析成功");
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
// 清空
|
|
|
|
|
const clear = () => {
|
|
|
|
|
g_analyzeTheNumberOfDataItems.value = "";
|
|
|
|
|
aWordFrequency.value = [];
|
|
|
|
|
proxy.$modal.msgSuccess("清空成功");
|
|
|
|
|
};
|
|
|
|
|
const initChart = () => {
|
|
|
|
|
var myChart = echarts.init(document.getElementById("mywordcloud_positive"));
|
|
|
|
|
const arr = nOriginalWordFrequency.value.map((item) => {
|
|
|
|
|
return {
|
|
|
|
|
name: item.keyword,
|
|
|
|
|
value: item.frequency,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
myChart.setOption({
|
|
|
|
|
title: {
|
|
|
|
|
text: "词云分析",
|
|
|
|
|
x: "center",
|
|
|
|
|
textStyle: {
|
|
|
|
|
fontSize: 23,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
backgroundColor: "#ffffff",
|
|
|
|
|
tooltip: {
|
|
|
|
|
show: true,
|
|
|
|
|
},
|
|
|
|
|
toolbox: {
|
|
|
|
|
feature: {
|
|
|
|
|
saveAsImage: {
|
|
|
|
|
iconStyle: {
|
|
|
|
|
normal: {
|
|
|
|
|
color: "#FFFFFF",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithmDownload(aOriginalDataOfAnalysisResults2.value).then((res) => {
|
|
|
|
|
const blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
|
|
|
|
|
const url = window.URL.createObjectURL(blob);
|
|
|
|
|
const a = document.createElement("a");
|
|
|
|
|
a.href = url;
|
|
|
|
|
a.download = "描述性统计.xlsx";
|
|
|
|
|
document.body.appendChild(a);
|
|
|
|
|
a.click();
|
|
|
|
|
document.body.removeChild(a);
|
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
|
proxy.$modal.msgSuccess("下载成功");
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: "词云分析",
|
|
|
|
|
type: "wordCloud",
|
|
|
|
|
// //size: ['9%', '99%'],
|
|
|
|
|
sizeRange: [6, 66],
|
|
|
|
|
// //textRotation: [0, 45, 90, -45],
|
|
|
|
|
rotationRange: [-45, 90],
|
|
|
|
|
// //shape: 'circle',
|
|
|
|
|
// gridSize: 5,
|
|
|
|
|
// sizeRange: [12, 32],
|
|
|
|
|
width: "90%",
|
|
|
|
|
height: "86%",
|
|
|
|
|
textPadding: 0,
|
|
|
|
|
autoSize: {
|
|
|
|
|
enable: true,
|
|
|
|
|
minSize: 16,
|
|
|
|
|
},
|
|
|
|
|
textStyle: {
|
|
|
|
|
color: function () {
|
|
|
|
|
return "rgb(" + [Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(",") + ")";
|
|
|
|
|
},
|
|
|
|
|
emphasis: {
|
|
|
|
|
shadowBlur: 10,
|
|
|
|
|
shadowColor: "#333",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
data: arr,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
// 情感分析
|
|
|
|
|
const sentimentAnalysis = () => {
|
|
|
|
|
marketingAlgorithmApi.getMarketingAlgorithmSentiment({ userId: n_dataTableQuery.value.userId, content: g_analyzeTheNumberOfDataItems.value, modelType: preProcessText.value.text3 }).then(res=>{
|
|
|
|
|
aWordFrequency.value=res.data
|
|
|
|
|
})
|
|
|
|
|
const commentType = (text) => {
|
|
|
|
|
s_commentType.value = text.id;
|
|
|
|
|
};
|
|
|
|
|
const wordFrequencyNext = () => {
|
|
|
|
|
if (mWordFrequency.value.frequency !== "" || mWordFrequency.value.namenum !== "") {
|
|
|
|
|
wordFrequencySearch();
|
|
|
|
|
} else {
|
|
|
|
|
aWordFrequency.value = paginate(nOriginalWordFrequency.value, mWordFrequency.value.index, mWordFrequency.value.size).data;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const wordFrequencySearch = () => {
|
|
|
|
|
// 根据频次和词语长度进行查找
|
|
|
|
|
loading2.value = true;
|
|
|
|
|
const filteredData = nOriginalWordFrequency.value.filter((item) => {
|
|
|
|
|
const matchesKeyword1 = mWordFrequency.value.frequency ? item.frequency === Number(mWordFrequency.value.frequency) : true;
|
|
|
|
|
const matchesKeyword2 = mWordFrequency.value.namenum ? item.keyword.length == mWordFrequency.value.namenum : true;
|
|
|
|
|
return matchesKeyword1 && matchesKeyword2;
|
|
|
|
|
});
|
|
|
|
|
aWordFrequency.value = filteredData.length > 5 ? paginate(filteredData, mWordFrequency.value.index, mWordFrequency.value.size).data : filteredData;
|
|
|
|
|
nOriginalWordFrequencyNum.value = filteredData.length;
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
loading2.value = false;
|
|
|
|
|
}, 600);
|
|
|
|
|
};
|
|
|
|
|
const switchingModels = () => {
|
|
|
|
|
// 清空右边的数据
|
|
|
|
|
n_emotiveTendency.value = 0;
|
|
|
|
|
aCommentOpinion.value = [];
|
|
|
|
|
nOriginalWordFrequencyNum.value = 0;
|
|
|
|
|
aWordFrequency.value = [];
|
|
|
|
|
nOriginalWordFrequency.value = [];
|
|
|
|
|
mWordFrequency.value.index = 1;
|
|
|
|
|
mWordFrequency.value.size = 5;
|
|
|
|
|
mWordFrequency.value.frequency = "";
|
|
|
|
|
mWordFrequency.value.namenum = "";
|
|
|
|
|
s_commentType.value = "";
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
@ -421,8 +634,6 @@ const sentimentAnalysis = () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.app-main {
|
|
|
|
|
// background-color: #f5f5f5;
|
|
|
|
|
min-height: 965px;
|
|
|
|
|
margin: 5px 20px 0;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
@ -430,7 +641,7 @@ const sentimentAnalysis = () => {
|
|
|
|
|
.main-left {
|
|
|
|
|
//水平居中
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
min-height: 965px;
|
|
|
|
|
// min-height: 965px;
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 205px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
@ -476,9 +687,9 @@ const sentimentAnalysis = () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.main-right {
|
|
|
|
|
width: 1639px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
// height: 100%;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
// padding: 20px;
|
|
|
|
|
border: 1px solid #0452c6;
|
|
|
|
|
.text-type {
|
|
|
|
|
margin: 29px 0 20px 0px;
|
|
|
|
|
@ -489,16 +700,26 @@ const sentimentAnalysis = () => {
|
|
|
|
|
--el-button-bg-color: #041d3b;
|
|
|
|
|
--el-button-border-color: #1983dd;
|
|
|
|
|
}
|
|
|
|
|
.btnActive {
|
|
|
|
|
background: #409eff;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.analysis {
|
|
|
|
|
.el-textarea {
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
:deep(.el-textarea) {
|
|
|
|
|
height: 343px;
|
|
|
|
|
background: #002652;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
:deep(.el-textarea__inner) {
|
|
|
|
|
.el-textarea__inner {
|
|
|
|
|
min-height: 343px !important;
|
|
|
|
|
background: transparent;
|
|
|
|
|
box-shadow: 0 0 0 1px #1983dd;
|
|
|
|
|
box-shadow: 0 0 0 0px #1983dd !important;
|
|
|
|
|
border: 1px solid #1983dd;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
.el-input__count {
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -530,6 +751,8 @@ const sentimentAnalysis = () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.analysisResults {
|
|
|
|
|
transition: all 6s;
|
|
|
|
|
|
|
|
|
|
.el-button {
|
|
|
|
|
width: 89px;
|
|
|
|
|
height: 31px;
|
|
|
|
|
@ -570,6 +793,109 @@ const sentimentAnalysis = () => {
|
|
|
|
|
margin-right: 55px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.emotion_analysis {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: flex;
|
|
|
|
|
// align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 30px;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
height: 180px;
|
|
|
|
|
margin-top: 40px;
|
|
|
|
|
.emotion_analysis-ani-in-ri,
|
|
|
|
|
.emotion_analysis-ani-in-le {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.emotion_analysis_title {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 0px;
|
|
|
|
|
right: 48%;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
font-weight: normal;
|
|
|
|
|
}
|
|
|
|
|
:deep(.el-progress-bar__outer) {
|
|
|
|
|
background-color: #036fe2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.comment-opinion {
|
|
|
|
|
padding: 30px 20px 0px 90px !important;
|
|
|
|
|
|
|
|
|
|
.result {
|
|
|
|
|
height: 40px;
|
|
|
|
|
-webkit-text-size-adjust: 100%;
|
|
|
|
|
font: 14px BlinkMacSystemFont, Roboto, Helvetica Neue, Helvetica, PingFangSC-Regular, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
|
|
|
|
|
-webkit-tap-highlight-color: transparent;
|
|
|
|
|
-webkit-font-smoothing: antialiased;
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text, Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB, arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
position: relative;
|
|
|
|
|
padding: 8px 0 8px 55px;
|
|
|
|
|
margin-right: 1px;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
.result-img {
|
|
|
|
|
-webkit-text-size-adjust: 100%;
|
|
|
|
|
font: 14px BlinkMacSystemFont, Roboto, Helvetica Neue, Helvetica, PingFangSC-Regular, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
|
|
|
|
|
-webkit-tap-highlight-color: transparent;
|
|
|
|
|
-webkit-font-smoothing: antialiased;
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text, Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB, arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 8px;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 26px;
|
|
|
|
|
height: 26px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background-size: contain;
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-image: url(../../../assets/images/笑脸.png);
|
|
|
|
|
background-color: #ff6b0f;
|
|
|
|
|
}
|
|
|
|
|
.result-neg {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 8px;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 26px;
|
|
|
|
|
height: 26px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background-size: contain;
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
background-image: url(../../../assets/images/哭脸.png);
|
|
|
|
|
background-color: #60aefd;
|
|
|
|
|
}
|
|
|
|
|
.result-title {
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
.result-view {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
margin-right: 2px;
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
top: -26px;
|
|
|
|
|
left: 61px;
|
|
|
|
|
.result-bar {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 50%;
|
|
|
|
|
right: -1px;
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
height: 15px;
|
|
|
|
|
width: 1px;
|
|
|
|
|
color: #d8d8d8;
|
|
|
|
|
border-right: 1px solid #d8d8d8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.result-view:last-child {
|
|
|
|
|
.result-bar {
|
|
|
|
|
border: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
:deep(.el-form-item__label) {
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
@ -590,4 +916,13 @@ p {
|
|
|
|
|
color: #ffffff !important;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
:deep(.pagination-container .el-pagination) {
|
|
|
|
|
// 去除定位
|
|
|
|
|
position: static;
|
|
|
|
|
}
|
|
|
|
|
:deep(.demo-form-inline) {
|
|
|
|
|
.el-form-item__content {
|
|
|
|
|
flex-wrap: nowrap !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|