|
|
@@ -9,7 +9,7 @@
|
|
|
<button class="btn btn-secondary" @click="showImportModal = true">
|
|
|
<i class="fas fa-file-import"></i> 批量导入
|
|
|
</button>
|
|
|
- <button class="btn btn-primary" @click="showAddModal = true">
|
|
|
+ <button class="btn btn-primary" @click="addKnowledgeDocument()">
|
|
|
<i class="fas fa-plus"></i> 添加知识
|
|
|
</button>
|
|
|
</div>
|
|
|
@@ -18,40 +18,31 @@
|
|
|
<!-- Stats -->
|
|
|
<div class="stats-row">
|
|
|
<div class="stat-card-lg">
|
|
|
- <div class="stat-icon-lg blue"><i class="fas fa-book"></i></div>
|
|
|
+ <div class="stat-icon-lg green"><i class="fas fa-check-circle"></i></div>
|
|
|
<div class="stat-content-lg">
|
|
|
- <h3>{{ formatNumber(knowledgeStats.total) }}</h3>
|
|
|
- <p>知识点总数</p>
|
|
|
+ <h3>{{ formatNumber(knowledgeStats.totalDatasets) }}</h3>
|
|
|
+ <p>知识库总数</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="stat-card-lg">
|
|
|
<div class="stat-icon-lg purple"><i class="fas fa-folder"></i></div>
|
|
|
<div class="stat-content-lg">
|
|
|
- <h3>{{ knowledgeStats.categories }}</h3>
|
|
|
- <p>知识分类</p>
|
|
|
+ <h3>{{ knowledgeStats.totalDocuments }}</h3>
|
|
|
+ <p>文档总数</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="stat-card-lg">
|
|
|
- <div class="stat-icon-lg green"><i class="fas fa-check-circle"></i></div>
|
|
|
+ <div class="stat-icon-lg blue"><i class="fas fa-book"></i></div>
|
|
|
<div class="stat-content-lg">
|
|
|
- <h3>{{ knowledgeStats.coverage }}%</h3>
|
|
|
- <p>AI 覆盖率</p>
|
|
|
+ <h3>{{ knowledgeStats.totalChunks }}</h3>
|
|
|
+ <p>文本块总数</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="stat-card-lg">
|
|
|
<div class="stat-icon-lg orange"><i class="fas fa-chart-line"></i></div>
|
|
|
<div class="stat-content-lg">
|
|
|
- <h3>+{{ knowledgeStats.weeklyNew }}</h3>
|
|
|
- <p>本周新增</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="stat-card-lg">
|
|
|
- <div class="stat-icon-lg" style="background: rgba(139, 92, 246, 0.2); color: var(--secondary);">
|
|
|
- <i class="fas fa-brain"></i>
|
|
|
- </div>
|
|
|
- <div class="stat-content-lg">
|
|
|
- <h3>{{ knowledgeStats.modelVersion }}</h3>
|
|
|
- <p>模型版本</p>
|
|
|
+ <h3>+{{ knowledgeStats.thisWeekNewChunks }}</h3>
|
|
|
+ <p>本周新增文本块数</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -111,7 +102,7 @@
|
|
|
<div v-for="tab in tabs" :key="tab.key"
|
|
|
class="tab-item"
|
|
|
:class="{ active: activeTab === tab.key }"
|
|
|
- @click="activeTab = tab.key">
|
|
|
+ @click="changeTab(tab.key)">
|
|
|
<i :class="tab.icon"></i>
|
|
|
{{ tab.label }}
|
|
|
<span class="tab-count">{{ tab.count }}</span>
|
|
|
@@ -159,6 +150,14 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ layout="prev, pager, next"
|
|
|
+ :total="1000">
|
|
|
+ </el-pagination>
|
|
|
+ </div>
|
|
|
+
|
|
|
</div>
|
|
|
|
|
|
<!-- 全部知识 Tab -->
|
|
|
@@ -173,8 +172,8 @@
|
|
|
<div class="knowledge-question">{{ item.name }}</div>
|
|
|
<!-- <span class="knowledge-category" :style="{ background: item.iconBg }">{{ item.categoryName }}</span> -->
|
|
|
</div>
|
|
|
- <!-- <div class="knowledge-answer">{{ item.answer }}</div>
|
|
|
- <div class="knowledge-meta">
|
|
|
+ <!-- <div class="knowledge-answer">{{ item.text }}</div> -->
|
|
|
+ <!-- <div class="knowledge-meta">
|
|
|
<span><i class="fas fa-eye"></i> {{ item.views }}次查看</span>
|
|
|
<span><i class="fas fa-thumbs-up"></i> {{ item.likes }}次好评</span>
|
|
|
<span><i class="fas fa-clock"></i> {{ item.time }}</span>
|
|
|
@@ -198,11 +197,11 @@
|
|
|
<div class="qa-header">
|
|
|
<h4><i class="fas fa-comments"></i> 智能问答记录</h4>
|
|
|
<div class="qa-filters">
|
|
|
- <select v-model="qaFilter" class="filter-select">
|
|
|
+ <!-- <select v-model="qaFilter" class="filter-select">
|
|
|
<option value="all">全部来源</option>
|
|
|
<option value="customer">客户问答</option>
|
|
|
<option value="internal">内部查询</option>
|
|
|
- </select>
|
|
|
+ </select> -->
|
|
|
<select v-model="qaRating" class="filter-select">
|
|
|
<option value="all">全部评价</option>
|
|
|
<option value="positive">好评</option>
|
|
|
@@ -212,13 +211,13 @@
|
|
|
</div>
|
|
|
<div class="qa-list">
|
|
|
<div v-for="qa in filteredQA" :key="qa.id" class="qa-card">
|
|
|
- <div class="qa-source">
|
|
|
+ <!-- <div class="qa-source">
|
|
|
<span class="source-badge" :class="qa.sourceType">{{ qa.sourceLabel }}</span>
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
<div class="qa-content">
|
|
|
<div class="qa-question">
|
|
|
<span class="qa-label">问</span>
|
|
|
- {{ qa.question }}
|
|
|
+ {{ qa.query }}
|
|
|
</div>
|
|
|
<div class="qa-answer-block">
|
|
|
<span class="qa-label answer">答</span>
|
|
|
@@ -229,10 +228,10 @@
|
|
|
<div class="qa-time">{{ qa.time }}</div>
|
|
|
<div class="qa-rating">
|
|
|
<button class="rating-btn" :class="{ active: qa.rating === 'positive' }" @click="rateQA(qa, 'positive')">
|
|
|
- <i class="fas fa-thumbs-up"></i>
|
|
|
+ <i class="fas fa-thumbs-up"></i><span style="margin-left: 2px;">{{qa.agree}}</span>
|
|
|
</button>
|
|
|
<button class="rating-btn" :class="{ active: qa.rating === 'negative' }" @click="rateQA(qa, 'negative')">
|
|
|
- <i class="fas fa-thumbs-down"></i>
|
|
|
+ <i class="fas fa-thumbs-down"></i><span style="margin-left: 2px;">{{qa.disagree}}</span>
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -252,13 +251,13 @@
|
|
|
</div>
|
|
|
<div class="training-list">
|
|
|
<div v-for="task in trainingTasks" :key="task.id" class="training-card">
|
|
|
- <div class="training-icon" :class="task.status">
|
|
|
- <i :class="task.status === 'running' ? 'fas fa-spinner fa-spin' : task.status === 'completed' ? 'fas fa-check' : 'fas fa-pause'"></i>
|
|
|
+ <div class="training-icon" :class="task.status==0?'running':'completed'">
|
|
|
+ <i :class="task.status === 0 ? 'fas fa-spinner fa-spin' : 'fas fa-check'"></i>
|
|
|
</div>
|
|
|
<div class="training-content">
|
|
|
<div class="training-name">{{ task.name }}</div>
|
|
|
<div class="training-desc">{{ task.description }}</div>
|
|
|
- <div class="training-progress" v-if="task.status === 'running'">
|
|
|
+ <div class="training-progress" v-if="task.status === 0">
|
|
|
<div class="progress-bar">
|
|
|
<div class="progress-fill" :style="{ width: task.progress + '%' }"></div>
|
|
|
</div>
|
|
|
@@ -267,16 +266,16 @@
|
|
|
</div>
|
|
|
<div class="training-stats">
|
|
|
<div class="training-stat">
|
|
|
- <span class="value">{{ task.documents }}</span>
|
|
|
+ <span class="value">{{ task.totalDocumentCount }}</span>
|
|
|
<span class="label">文档数</span>
|
|
|
</div>
|
|
|
<div class="training-stat">
|
|
|
- <span class="value">{{ task.learned }}</span>
|
|
|
+ <span class="value">{{ task.completedDcumentCount }}</span>
|
|
|
<span class="label">已学习</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="training-status" :class="task.status">
|
|
|
- {{ getTaskStatusLabel(task.status) }}
|
|
|
+ <div class="training-status" :class="task.status==0?'running':'completed'">
|
|
|
+ {{ task.status==0?'训练中':'已完成' }}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -365,29 +364,27 @@
|
|
|
<div class="modal-body">
|
|
|
<div class="form-group">
|
|
|
<label class="form-label">问题/关键词 <span class="required">*</span></label>
|
|
|
- <input type="text" class="form-input" v-model="newKnowledge.question" placeholder="例如:MOQ最小起订量是多少?">
|
|
|
+ <input type="text" class="form-input" v-model="newKnowledge.name" placeholder="例如:MOQ最小起订量是多少?">
|
|
|
</div>
|
|
|
<div class="form-group">
|
|
|
<label class="form-label">答案/内容 <span class="required">*</span></label>
|
|
|
- <textarea class="form-textarea" v-model="newKnowledge.answer" rows="4" placeholder="输入详细答案..."></textarea>
|
|
|
+ <textarea class="form-textarea" v-model="newKnowledge.text" rows="4" placeholder="输入详细答案..."></textarea>
|
|
|
</div>
|
|
|
- <div class="form-row">
|
|
|
- <div class="form-group">
|
|
|
- <label class="form-label">知识分类</label>
|
|
|
- <select class="form-select" v-model="newKnowledge.category">
|
|
|
- <option value="">选择分类</option>
|
|
|
- <option v-for="cat in categories" :key="cat.id" :value="cat.id">{{ cat.name }}</option>
|
|
|
- </select>
|
|
|
- </div>
|
|
|
- <div class="form-group">
|
|
|
+ <div class="form-group">
|
|
|
+ <label class="form-label">知识分类 <span class="required">*</span></label>
|
|
|
+ <select class="form-select" v-model="newKnowledge.dataset_id">
|
|
|
+ <option value="">选择分类</option>
|
|
|
+ <option v-for="cat in categories" :key="cat.id" :value="cat.id">{{ cat.name }}</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="form-group">
|
|
|
<label class="form-label">关键词标签</label>
|
|
|
<input type="text" class="form-input" v-model="newKnowledge.tags" placeholder="用逗号分隔多个标签">
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="form-group">
|
|
|
+ </div> -->
|
|
|
+ <!-- <div class="form-group">
|
|
|
<label class="form-label">关联问题(可选)</label>
|
|
|
<input type="text" class="form-input" v-model="newKnowledge.relatedQuestions" placeholder="例如:起订量,MOQ,最小订单">
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
</div>
|
|
|
<div class="modal-footer">
|
|
|
<button class="btn btn-secondary" @click="showAddModal = false">取消</button>
|
|
|
@@ -462,9 +459,15 @@
|
|
|
</div>
|
|
|
<div class="modal-body">
|
|
|
<div class="import-zone">
|
|
|
- <div class="import-icon"><i class="fas fa-cloud-upload-alt"></i></div>
|
|
|
- <div class="import-text">拖拽文件到此处,或点击上传</div>
|
|
|
- <div class="import-formats">支持 Excel、CSV、JSON、PDF 格式</div>
|
|
|
+ <el-upload
|
|
|
+ class="upload-demo"
|
|
|
+ drag
|
|
|
+ action="https://jsonplaceholder.typicode.com/posts/"
|
|
|
+ multiple>
|
|
|
+ <div class="import-icon"><i class="fas fa-cloud-upload-alt"></i></div>
|
|
|
+ <div class="import-text">拖拽文件到此处,或点击上传</div>
|
|
|
+ <div class="import-formats">支持 Excel、CSV、JSON、PDF 格式</div>
|
|
|
+ </el-upload>
|
|
|
</div>
|
|
|
<div class="import-options">
|
|
|
<div class="import-option">
|
|
|
@@ -486,6 +489,59 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 新建训练 -->
|
|
|
+ <div v-if="showTrainModal" class="modal-overlay" @click.self="showTrainModal = false">
|
|
|
+ <div class="modal import-modal">
|
|
|
+ <div class="modal-header">
|
|
|
+ <div class="modal-title"><i class="fas fa-file-import"></i> 新建训练</div>
|
|
|
+ <button class="modal-close" @click="showTrainModal = false"><i class="fas fa-times"></i></button>
|
|
|
+ </div>
|
|
|
+ <div class="modal-body">
|
|
|
+ <div class="form-group">
|
|
|
+ <label class="form-label">知识分类 <span class="required">*</span></label>
|
|
|
+ <select class="form-select" v-model="trainKnowledge.datasetId">
|
|
|
+ <option value="">选择分类</option>
|
|
|
+ <option v-for="cat in categories" :key="cat.id" :value="cat.id">{{ cat.name }}</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label class="form-label">标题 <span class="required">*</span></label>
|
|
|
+ <input type="text" class="form-input" maxlength="30" v-model="trainKnowledge.name" placeholder="30字内">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label class="form-label">备注信息 <span class="required">*</span></label>
|
|
|
+ <textarea class="form-textarea" v-model="trainKnowledge.describe" rows="4" maxlength="60" placeholder="请输入内容60字内"></textarea>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="import-zone">
|
|
|
+ <el-upload
|
|
|
+ class="upload-demo"
|
|
|
+ drag
|
|
|
+ action=""
|
|
|
+ :auto-upload="false"
|
|
|
+ :show-file-list="false"
|
|
|
+ @change="handleFileChange"
|
|
|
+ multiple>
|
|
|
+ <div class="import-icon"><i class="fas fa-cloud-upload-alt"></i></div>
|
|
|
+ <div class="import-text">拖拽文件到此处,或点击上传</div>
|
|
|
+ <div class="import-formats">支持 Excel、CSV、JSON、PDF 格式</div>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <div class="import-options">
|
|
|
+ <div class="import-option" v-for="item in fileListRaw" :key="item.name">
|
|
|
+ <i class="fas fa-file-excel"></i>
|
|
|
+ <span>{{ item.name }}</span>
|
|
|
+ <button icon="el-icon-edit"></button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="modal-footer">
|
|
|
+ <button class="btn btn-secondary" @click="showTrainModal = false">取消</button>
|
|
|
+ <button class="btn btn-primary" @click="startTrain"><i class="fas fa-upload"></i>添加</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<!-- Toast -->
|
|
|
<transition name="toast">
|
|
|
<div v-if="showToast" class="toast" :class="toastType">
|
|
|
@@ -499,8 +555,9 @@
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, computed } from 'vue'
|
|
|
-import { knowledgeDatasets,knowledgeDocuments } from '../api/knowledge'
|
|
|
+import { knowledgeDatasets,knowledgeDocuments,createKnowledge,chatMessages,baseTraining,creatTraining,baseStatistics } from '../api/knowledge'
|
|
|
import { formatTimeAgo } from '@/utils/time'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
|
|
|
const showAddModal = ref(false)
|
|
|
const showDetailModal = ref(false)
|
|
|
@@ -516,13 +573,6 @@ const showToast = ref(false)
|
|
|
const toastMessage = ref('')
|
|
|
const toastType = ref('success')
|
|
|
|
|
|
-const knowledgeStats = {
|
|
|
- total: 1247,
|
|
|
- categories: 12,
|
|
|
- coverage: 95,
|
|
|
- weeklyNew: 127,
|
|
|
- modelVersion: 'v2.3'
|
|
|
-}
|
|
|
|
|
|
const syncStatus = {
|
|
|
products: 234,
|
|
|
@@ -536,15 +586,16 @@ const tabs = ref([
|
|
|
{ key: 'all', label: '全部知识', count: 0, icon: 'fas fa-book' },
|
|
|
{ key: 'qa', label: '问答记录', count: 0, icon: 'fas fa-comments' },
|
|
|
{ key: 'training', label: 'AI 训练', count: 0, icon: 'fas fa-dumbbell' },
|
|
|
- { key: 'settings', label: '设置', count: 0, icon: 'fas fa-cog' }
|
|
|
+ // { key: 'settings', label: '设置', count: 0, icon: 'fas fa-cog' }
|
|
|
])
|
|
|
|
|
|
const newKnowledge = ref({
|
|
|
- question: '',
|
|
|
- answer: '',
|
|
|
- category: '',
|
|
|
- tags: '',
|
|
|
- relatedQuestions: ''
|
|
|
+ dataset_id: '',
|
|
|
+ text: '',
|
|
|
+ name: '',
|
|
|
+ indexing_technique: "high_quality",
|
|
|
+ doc_form: "text_model",
|
|
|
+ doc_language:"Chinese Simplified"
|
|
|
})
|
|
|
|
|
|
// const categories = ref([
|
|
|
@@ -567,20 +618,42 @@ const newKnowledge = ref({
|
|
|
// { id: 6, icon: '🏭', iconBg: 'rgba(6, 182, 212, 0.2)', categoryName: '行业知识', question: 'NVMe和SATA有什么区别?', answer: 'NVMe采用PCIe通道,速度更快延迟更低,适合高性能应用。', extendedAnswer: 'NVMe SSD通过PCIe总线直接与CPU通信,理论带宽可达32GB/s,延迟极低。SATA SSD受限于SATA接口,最大速度约600MB/s。对于需要高IOPS的应用场景,NVMe是更好的选择。', tags: ['NVMe', 'SATA', '技术'], relatedQuestions: ['如何选择接口?', '兼容性如何?'], views: 432, likes: 34, time: '5天前' }
|
|
|
// ])
|
|
|
|
|
|
-const qaRecords = ref([
|
|
|
- { id: 1, sourceType: 'customer', sourceLabel: '客户问答', question: '你们的NVMe SSD支持哪些接口?', answer: '我们提供M.2 2280、M.2 2242和U.2三种接口规格,支持PCIe 4.0 x4总线,向下兼容PCIe 3.0。', time: '10分钟前', rating: 'positive' },
|
|
|
- { id: 2, sourceType: 'internal', sourceLabel: '内部查询', question: '中东地区的主要竞争对手有哪些?', answer: '中东SSD市场主要竞争者包括Samsung、WD、Kingston以及本地品牌。我们在价格和交期方面有竞争优势。', time: '1小时前', rating: null },
|
|
|
- { id: 3, sourceType: 'customer', sourceLabel: '客户问答', question: '能否提供样品测试?', answer: '可以提供样品,标准样品免费提供(限2片),定制样品需支付样品费(后续订单可抵扣)。', time: '2小时前', rating: 'positive' },
|
|
|
- { id: 4, sourceType: 'customer', sourceLabel: '客户问答', question: '产品有CE认证吗?', answer: '所有出口产品均通过CE、FCC、RoHS认证,可提供认证证书副本。', time: '3小时前', rating: 'positive' },
|
|
|
- { id: 5, sourceType: 'internal', sourceLabel: '内部查询', question: '上周最热门的产品是什么?', answer: '上周销量最高的是NVMe SSD 1TB企业级型号,其次是2TB消费级型号。', time: '昨天', rating: 'negative' }
|
|
|
-])
|
|
|
+// const qaRecords = ref([
|
|
|
+// { id: 1, sourceType: 'customer', sourceLabel: '客户问答', question: '你们的NVMe SSD支持哪些接口?', answer: '我们提供M.2 2280、M.2 2242和U.2三种接口规格,支持PCIe 4.0 x4总线,向下兼容PCIe 3.0。', time: '10分钟前', rating: 'positive' },
|
|
|
+// { id: 2, sourceType: 'internal', sourceLabel: '内部查询', question: '中东地区的主要竞争对手有哪些?', answer: '中东SSD市场主要竞争者包括Samsung、WD、Kingston以及本地品牌。我们在价格和交期方面有竞争优势。', time: '1小时前', rating: null },
|
|
|
+// { id: 3, sourceType: 'customer', sourceLabel: '客户问答', question: '能否提供样品测试?', answer: '可以提供样品,标准样品免费提供(限2片),定制样品需支付样品费(后续订单可抵扣)。', time: '2小时前', rating: 'positive' },
|
|
|
+// { id: 4, sourceType: 'customer', sourceLabel: '客户问答', question: '产品有CE认证吗?', answer: '所有出口产品均通过CE、FCC、RoHS认证,可提供认证证书副本。', time: '3小时前', rating: 'positive' },
|
|
|
+// { id: 5, sourceType: 'internal', sourceLabel: '内部查询', question: '上周最热门的产品是什么?', answer: '上周销量最高的是NVMe SSD 1TB企业级型号,其次是2TB消费级型号。', time: '昨天', rating: 'negative' }
|
|
|
+// ])
|
|
|
+
|
|
|
+// const trainingTasks = ref([
|
|
|
+// { id: 1, name: '新产品知识训练', description: '导入2024新品规格文档进行训练', status: 'running', progress: 68, documents: 45, learned: 31 },
|
|
|
+// { id: 2, name: '行业报告更新', description: '更新Q1存储行业市场报告数据', status: 'completed', progress: 100, documents: 12, learned: 12 },
|
|
|
+// { id: 3, name: '客户问答优化', description: '基于历史问答记录优化回复准确性', status: 'paused', progress: 35, documents: 234, learned: 82 }
|
|
|
+// ])
|
|
|
+
|
|
|
+const knowledgeStats = ref({
|
|
|
+ totalDatasets:0,
|
|
|
+ totalDocuments:0,
|
|
|
+ totalChunks:0,
|
|
|
+ thisWeekNewChunks:0,
|
|
|
+})
|
|
|
+// 获取汇总数
|
|
|
+const getBaseStatistics = () => {
|
|
|
+ baseStatistics().then(res => {
|
|
|
+ knowledgeStats.value = res.result.data
|
|
|
+ console.log('res :>> ', res);
|
|
|
+ })
|
|
|
+}
|
|
|
+getBaseStatistics()
|
|
|
|
|
|
-const trainingTasks = ref([
|
|
|
- { id: 1, name: '新产品知识训练', description: '导入2024新品规格文档进行训练', status: 'running', progress: 68, documents: 45, learned: 31 },
|
|
|
- { id: 2, name: '行业报告更新', description: '更新Q1存储行业市场报告数据', status: 'completed', progress: 100, documents: 12, learned: 12 },
|
|
|
- { id: 3, name: '客户问答优化', description: '基于历史问答记录优化回复准确性', status: 'paused', progress: 35, documents: 234, learned: 82 }
|
|
|
-])
|
|
|
|
|
|
+const changeTab = (tab)=>{
|
|
|
+ activeTab.value = tab
|
|
|
+ if(tab =='qa'){
|
|
|
+ getChatMessages()
|
|
|
+ }
|
|
|
+}
|
|
|
const categories = ref([])
|
|
|
// 获取知识分类
|
|
|
const getKnowledgeDatasets = () => {
|
|
|
@@ -613,7 +686,78 @@ const openCategory = (category) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+const qaRecords = ref([])
|
|
|
+// 获取问答记录
|
|
|
+const chatParams=ref({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ keyword:'',
|
|
|
+})
|
|
|
+const getChatMessages = () => {
|
|
|
+ chatMessages(chatParams.value).then(res => {
|
|
|
+ tabs.value[2].count = res.result.total
|
|
|
+ res.result.records.forEach(el => {
|
|
|
+ el.time = formatTimeAgo(el.createdAt)
|
|
|
+ });
|
|
|
+ qaRecords.value = res.result.records
|
|
|
+ console.log('res :>> ', res);
|
|
|
+ })
|
|
|
+}
|
|
|
+getChatMessages()
|
|
|
+
|
|
|
+const trainingTasks = ref([])
|
|
|
+//获取ai训练列表
|
|
|
+const trainingParams=ref({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ keyword:'',
|
|
|
+})
|
|
|
+const getTraining = () => {
|
|
|
+ baseTraining(trainingParams.value).then(res => {
|
|
|
+ tabs.value[3].count = res.result.total
|
|
|
+ trainingTasks.value = res.result.records
|
|
|
+ console.log('res :>> ', res);
|
|
|
+ })
|
|
|
+}
|
|
|
+getTraining()
|
|
|
+
|
|
|
+const fileListRaw = ref([])
|
|
|
+const handleFileChange = (file, fileList) => {
|
|
|
+ // 提取所有原生File对象
|
|
|
+ fileListRaw.value = fileList.map(item => item.raw)
|
|
|
+ console.log('当前选中所有文件:', fileListRaw.value)
|
|
|
+}
|
|
|
+const trainKnowledge = ref({
|
|
|
+ datasetId: '',
|
|
|
+ name: '',
|
|
|
+ describe: '',
|
|
|
+})
|
|
|
+const startTrain = async () => {
|
|
|
+ if (fileListRaw.value.length === 0) {
|
|
|
+ return ElMessage.warning('请先选择文件')
|
|
|
+ }
|
|
|
+ const formData = new FormData()
|
|
|
+ const jsonBody = {
|
|
|
+ datasetsId: trainKnowledge.value.datasetId,
|
|
|
+ name: trainKnowledge.value.name,
|
|
|
+ describe: trainKnowledge.value.describe,
|
|
|
+ }
|
|
|
+ formData.append('data', JSON.stringify(jsonBody))
|
|
|
+
|
|
|
+ fileListRaw.value.forEach(file => {
|
|
|
+ formData.append('file', file)
|
|
|
+ })
|
|
|
|
|
|
+ try {
|
|
|
+ await creatTraining(formData)
|
|
|
+ ElMessage.success('全部文件上传成功')
|
|
|
+ // 清空上传列表、缓存文件
|
|
|
+ uploadRef.value.clearFiles()
|
|
|
+ fileListRaw.value = []
|
|
|
+ } catch (err) {
|
|
|
+ ElMessage.error(err?.message || '上传失败,请重试')
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
// const filteredCategories = computed(() => {
|
|
|
// if (!searchQuery.value) return categories.value
|
|
|
@@ -642,7 +786,6 @@ const filteredQA = computed(() => {
|
|
|
|
|
|
const formatNumber = (num) => num.toLocaleString()
|
|
|
|
|
|
-const getTaskStatusLabel = (status) => ({ running: '训练中', completed: '已完成', paused: '已暂停' }[status] || status)
|
|
|
|
|
|
|
|
|
|
|
|
@@ -660,9 +803,23 @@ const deleteKnowledge = (item) => {
|
|
|
showToastMessage('知识已删除', 'success')
|
|
|
}
|
|
|
|
|
|
+const addKnowledgeDocument = ()=> {
|
|
|
+ newKnowledge.value.name = ''
|
|
|
+ newKnowledge.value.text=''
|
|
|
+ newKnowledge.value.dataset_id=''
|
|
|
+ showAddModal.value = true
|
|
|
+}
|
|
|
const addKnowledge = () => {
|
|
|
- showAddModal.value = false
|
|
|
- showToastMessage('知识添加成功,AI 已学习', 'success')
|
|
|
+ if(!newKnowledge.value.name||!newKnowledge.value.text||!newKnowledge.value.dataset_id){
|
|
|
+ ElMessage.error('请填入必填项')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ createKnowledge(newKnowledge.value).then(res => {
|
|
|
+ if(res.success){
|
|
|
+ howToastMessage('知识添加成功,AI 已学习', 'success')
|
|
|
+ showAddModal.value = false
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
const optimizeAnswer = (item) => {
|
|
|
@@ -892,7 +1049,8 @@ const showToastMessage = (message, type = 'success') => {
|
|
|
.detail-stat i { color: var(--primary); }
|
|
|
|
|
|
/* Import Zone */
|
|
|
-.import-zone { border: 2px dashed var(--border); border-radius: 14px; padding: 40px; text-align: center; margin-bottom: 20px; }
|
|
|
+.import-zone { border: 2px dashed var(--border); border-radius: 14px; padding: 0px; text-align: center; margin-bottom: 20px; }
|
|
|
+.import-zone :deep(.el-upload-dragger){border: none;background: none;}
|
|
|
.import-icon { font-size: 48px; color: var(--primary); margin-bottom: 12px; }
|
|
|
.import-text { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
|
|
|
.import-formats { font-size: 12px; color: var(--text-muted); }
|