update
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# Papers 文献分析系统
|
||||
|
||||
该项目是一个用于管理和分析学术文献的系统,使用FastAPI作为后端框架,并提供了一个基于HTML和JavaScript的前端界面。
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 2025-01-17 更新
|
||||
1. 优化report设计,接入了memarid.js,支持流程图展示(已完成)
|
||||
|
||||
### 2025-01-16 更新
|
||||
Initial commit(初始化,未完成)
|
||||
|
||||
## 功能
|
||||
|
||||
- **文献上传**:支持批量上传PDF和Word文档。
|
||||
- **文献分析**:上传的文献会被自动分析,提取基本信息和内容分析。
|
||||
- **文献管理**:可以查看、删除和下载文献分析报告。
|
||||
- **问答功能**:用户可以就文献内容提出问题,系统会基于分析结果提供回答。
|
||||
- **流程图展示**:使用Mermaid.js展示文献的研究方法流程图。
|
||||
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 文件结构
|
||||
paper/
|
||||
├── #后端
|
||||
├── paper.py # 后端程序
|
||||
├── paper.html # web页面
|
||||
└── README.md # 项目说明
|
||||
|
||||
### 后端 paper.py https://dev.obscura.work/paper
|
||||
|
||||
1. 服务器:222.186.10.253
|
||||
2. PORT = 9005
|
||||
3. 数据库:
|
||||
mongodb: 222.186.10.253:27017/paper
|
||||
Redis:222.186.10.253:6379; db190-192
|
||||
|
||||
### web页面 https://beta.obscura.work/paper/paper.html
|
||||
|
||||
|
||||
## 使用说明
|
||||
|
||||
1. **上传文献**:点击“Upload”按钮,选择要上传的文献文件。
|
||||
2. **查看文献列表**:上传后,文献会显示在列表中,点击“View Details”查看详细分析。
|
||||
3. **删除文献**:点击“Delete”按钮删除文献。
|
||||
4. **问答功能**:点击聊天图标,输入问题,系统会基于文献内容提供回答。
|
||||
5. **下载报告**:在文献详情页面,可以下载分析报告。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 确保MongoDB和Redis服务已启动并正确配置。
|
||||
- 上传的文献文件类型仅支持PDF和Word文档。
|
||||
- 文献分析可能需要一些时间,请耐心等待。
|
||||
+215
-110
@@ -3,9 +3,22 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Paper Analysis</title>
|
||||
<title>Papers</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
window.mermaid = mermaid;
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'default',
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true,
|
||||
curve: 'basis'
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
/* 基础样式优化 */
|
||||
body {
|
||||
@@ -351,17 +364,14 @@
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="navbar-brand">Paper</div>
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-menu-item active" onclick="window.location.href='Paper.html'">Paper</div>
|
||||
</div>
|
||||
<div class="navbar-brand">Papers</div>
|
||||
</nav>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- 左侧侧边栏 -->
|
||||
<div class="col-auto">
|
||||
<div class="sidebar">
|
||||
<!-- 项目文献页面的侧边栏 -->
|
||||
<!-- 文献页面的侧边栏 -->
|
||||
<div class="sidebar-menu hidden" id="DetailSidebar">
|
||||
<div class="sidebar-item" onclick="showPaperList()">
|
||||
<i class="bi bi-list-ul"></i>
|
||||
@@ -374,39 +384,19 @@
|
||||
<!-- 右侧主要内容区 -->
|
||||
<div class="col">
|
||||
<div class="content-wrapper">
|
||||
<!-- 项目文献详情页面 -->
|
||||
<!-- 文献详情页面 -->
|
||||
<div id="DetailPage" class="content-body hidden">
|
||||
<div class="content-header d-flex justify-content-between align-items-center">
|
||||
<h3 class="content-title" id="referenceAnalysisTitle">Paper Analysis</h3>
|
||||
<button class="btn btn-info" onclick="uploadPaper()">
|
||||
<h3 class="content-title" id="paperTitle">Paper List</h3>
|
||||
<button class="btn btn-info" onclick="uploadPaper()" style="padding: 10px 20px;">
|
||||
<i class="bi bi-upload me-2"></i>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
<div id="referenceAnalysis" class="mt-4">
|
||||
<div id="paper" class="mt-4">
|
||||
<!-- 文献分析内容将在这里动态加载 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文献分析报告页面 -->
|
||||
<div id="paperReportPage" class="content-body hidden">
|
||||
<div class="content-header d-flex justify-content-between align-items-center">
|
||||
<h3 class="content-title" id="paperReportTitle">Paper Summary Report</h3>
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-infoy" onclick="regenerateReport()">
|
||||
<i class="bi bi-arrow-clockwise me-2"></i>
|
||||
Regenerate
|
||||
</button>
|
||||
<button class="btn btn-info" onclick="downloadReport()">
|
||||
<i class="bi bi-download me-2"></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="paperReportContent" class="mt-4">
|
||||
<!-- 报告内容将在这里动态加载 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -416,16 +406,13 @@
|
||||
<script>
|
||||
// 全局变量
|
||||
const API_BASE_URL = 'https://dev.obscura.work/paper'; // 修改为正确的API地址
|
||||
let currentReportData = null;
|
||||
let currentReportData = null; // 添加存储当前报告数据的变量
|
||||
|
||||
// 页面加载时加载项目列表
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
document.getElementById('DetailPage').classList.remove('hidden');
|
||||
await loadReferences();
|
||||
});
|
||||
// 添加一个全局变量来存储论文报告数据
|
||||
const paperReports = new Map();
|
||||
|
||||
// Add show paper analysis page function
|
||||
async function showReferenceAnalysis() {
|
||||
async function showpaper() {
|
||||
try {
|
||||
// Hide other pages
|
||||
document.querySelectorAll('.page-content').forEach(page => {
|
||||
@@ -433,14 +420,14 @@
|
||||
});
|
||||
|
||||
// Show paper analysis page
|
||||
document.getElementById('referenceAnalysisPage').classList.add('active');
|
||||
document.getElementById('paperPage').classList.add('active');
|
||||
|
||||
// Set title
|
||||
document.getElementById('referenceAnalysisTitle').textContent =
|
||||
`Paper Analysis - ${document.getElementById('projectDetailTitle').textContent}`;
|
||||
document.getElementById('paperTitle').textContent =
|
||||
`Paper Analysis`;
|
||||
|
||||
// Load paper list
|
||||
await loadReferences(currentProjectId);
|
||||
await loadPapers();
|
||||
} catch (error) {
|
||||
console.error('Failed to show Paper analysis page:', error);
|
||||
alert('Failed to show Paper analysis page, please try again');
|
||||
@@ -448,16 +435,16 @@
|
||||
}
|
||||
|
||||
// paper card rendering function
|
||||
function renderReferenceCard(reference) {
|
||||
const uploadTime = reference.upload_time;
|
||||
const cardId = `reference-${reference._id}`;
|
||||
function renderPaperCard(paper) {
|
||||
const uploadTime = paper.upload_time;
|
||||
const cardId = `paper-${paper._id}`;
|
||||
|
||||
return `
|
||||
<div class="card mb-3" id="${cardId}">
|
||||
<div class="card-body d-flex position-relative">
|
||||
<div class="flex-grow-1" style="cursor: pointer;" onclick="viewReferenceDetailFromCard(this.closest('.card'))">
|
||||
<h5 class="card-title">${reference.reference_title}</h5>
|
||||
<div class="card-text analysis-content-${reference._id}">
|
||||
<div class="flex-grow-1" style="cursor: pointer;" onclick="DetailFromCard(this.closest('.card'))">
|
||||
<h5 class="card-title">${paper.paper_title}</h5>
|
||||
<div class="card-text analysis-content-${paper._id}">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="spinner-border spinner-border-sm text-primary me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
@@ -467,11 +454,11 @@
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-warning btn-sm"
|
||||
onclick="event.stopPropagation(); viewReferenceDetailFromCard(this.closest('.card'))">
|
||||
onclick="event.stopPropagation(); DetailFromCard(this.closest('.card'))">
|
||||
View Details
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm"
|
||||
onclick="event.stopPropagation(); deleteReference('${reference._id}')">
|
||||
onclick="event.stopPropagation(); deletepaper('${paper._id}')">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
@@ -479,49 +466,49 @@
|
||||
<div class="position-absolute" style="right: 1rem; top: 50%; transform: translateY(-50%);">
|
||||
<button class="btn rounded-circle d-flex align-items-center justify-content-center"
|
||||
style="width: 48px; height: 48px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); background: var(--primary-color); color: white;"
|
||||
onclick="event.stopPropagation(); openChatDialog('${reference._id}', '${reference.reference_title}')">
|
||||
onclick="event.stopPropagation(); openChatDialog('${paper._id}')">
|
||||
<i class="bi bi-chat-dots" style="font-size: 1.2rem;"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-muted">
|
||||
Upload Time: ${uploadTime}
|
||||
<span class="ms-2 analysis-status-${reference._id}">Analysis in progress...</span>
|
||||
<span class="ms-2 analysis-status-${paper._id}">Analysis in progress...</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Load paper list function
|
||||
async function loadReferences() {
|
||||
const referencesList = document.getElementById('referenceAnalysis');
|
||||
async function loadPapers() {
|
||||
const papersList = document.getElementById('paper');
|
||||
|
||||
try {
|
||||
// Get paper list
|
||||
const response = await fetch(`${API_BASE_URL}`);
|
||||
const response = await fetch(`${API_BASE_URL}/papers`);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.detail || 'Failed to fetch references');
|
||||
throw new Error(errorData.detail || 'Failed to fetch papers');
|
||||
}
|
||||
|
||||
const references = await response.json();
|
||||
const papers = await response.json();
|
||||
|
||||
if (!Array.isArray(references)) {
|
||||
if (!Array.isArray(papers)) {
|
||||
throw new Error('Invalid data format: expected an array');
|
||||
}
|
||||
|
||||
if (references.length === 0) {
|
||||
referencesList.innerHTML = '<div class="alert alert-info">No paper data, please upload paper</div>';
|
||||
if (papers.length === 0) {
|
||||
papersList.innerHTML = '<div class="alert alert-info">No paper, please upload paper</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Render paper cards
|
||||
const referenceCards = references.map(ref => renderReferenceCard(ref)).join('');
|
||||
referencesList.innerHTML = referenceCards;
|
||||
const paperCards = papers.map(ref => renderPaperCard(ref)).join('');
|
||||
papersList.innerHTML = paperCards;
|
||||
|
||||
// Get analysis status and results for each paper
|
||||
references.forEach(async (ref) => {
|
||||
papers.forEach(async (ref) => {
|
||||
try {
|
||||
const checkAnalysisStatus = async () => {
|
||||
const analysisResponse = await fetch(`${API_BASE_URL}/${ref._id}/report`);
|
||||
@@ -531,6 +518,9 @@
|
||||
}
|
||||
|
||||
const analysisResult = await analysisResponse.json();
|
||||
// 存储报告数据
|
||||
paperReports.set(ref._id, analysisResult);
|
||||
|
||||
const contentElement = document.querySelector(`.analysis-content-${ref._id}`);
|
||||
const statusElement = document.querySelector(`.analysis-status-${ref._id}`);
|
||||
|
||||
@@ -562,7 +552,7 @@
|
||||
journal = basicInfo.journal_publisher || 'N/A';
|
||||
|
||||
// 更新卡片标题为分析结果中的标题
|
||||
const titleElement = document.querySelector(`#reference-${ref._id} .card-title`);
|
||||
const titleElement = document.querySelector(`#paper-${ref._id} .card-title`);
|
||||
if (titleElement && basicInfo.title) {
|
||||
titleElement.textContent = basicInfo.title;
|
||||
}
|
||||
@@ -592,7 +582,7 @@
|
||||
// 开始首次检查
|
||||
await checkAnalysisStatus();
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch analysis for reference ${ref._id}:`, error);
|
||||
console.error(`Failed to fetch analysis for paper ${ref._id}:`, error);
|
||||
const contentElement = document.querySelector(`.analysis-content-${ref._id}`);
|
||||
const statusElement = document.querySelector(`.analysis-status-${ref._id}`);
|
||||
|
||||
@@ -608,10 +598,19 @@
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load Paper list:', error);
|
||||
papersList.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
Failed to load Paper list: ${error.message}
|
||||
<br>
|
||||
<button class="btn btn-primary mt-2" onclick="loadpapers()">
|
||||
Retry
|
||||
</button>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadPaper() {
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.pdf,.doc,.docx';
|
||||
@@ -660,7 +659,7 @@
|
||||
progressCardBody.appendChild(progressInner);
|
||||
progressCard.appendChild(progressCardBody);
|
||||
|
||||
const titleElement = document.getElementById('referenceAnalysisTitle');
|
||||
const titleElement = document.getElementById('paperTitle');
|
||||
titleElement.parentNode.parentNode.insertBefore(progressCard, titleElement.parentNode);
|
||||
|
||||
try {
|
||||
@@ -669,6 +668,7 @@
|
||||
formData.append('files', file);
|
||||
});
|
||||
|
||||
// 使用 XMLHttpRequest 来获取上传进度
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.onprogress = function(e) {
|
||||
@@ -690,7 +690,7 @@
|
||||
xhr.onerror = () => reject(new Error('Upload failed'));
|
||||
});
|
||||
|
||||
xhr.open('POST', `${API_BASE_URL}/analyze`);
|
||||
xhr.open('POST', `${API_BASE_URL}/upload`);
|
||||
xhr.send(formData);
|
||||
|
||||
await uploadPromise;
|
||||
@@ -705,7 +705,7 @@
|
||||
}, 500);
|
||||
|
||||
// 刷新文献列表
|
||||
await loadReferences();
|
||||
await loadPapers();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Upload failed:', error);
|
||||
@@ -718,9 +718,9 @@
|
||||
}
|
||||
|
||||
// View paper details function
|
||||
async function viewReferenceDetail(referenceId) {
|
||||
async function viewDetail(paperId) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/${referenceId}/report`);
|
||||
const response = await fetch(`${API_BASE_URL}/${paperId}/report`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch analysis report');
|
||||
@@ -744,14 +744,36 @@
|
||||
.replace(/},/g, '')
|
||||
.replace(/{ },/g, '')
|
||||
.replace(/^\s*,/gm, '')
|
||||
.replace(/Paper Analysis Report:/, '<div style="text-align: center"><strong>Paper Analysis</strong></div>')
|
||||
.replace(/^(\s*\d+\.[^:\n]+:)/gm, '<strong>$1</strong>')
|
||||
.replace(/Paper Analysis Report:/, '<div style="text-align: center; margin-bottom: 20px;"><strong style="font-size: 1.5rem;">Paper Analysis</strong></div>')
|
||||
.replace(/^(\s*\d+\.[^:\n]+:)/gm, '<strong style="color: #6366F1;font-size: 1.2rem;">$1</strong>')
|
||||
.replace(/(author|publication_date|title|journal_publisher|document_type):/g, '<span style="font-weight: bold; font-size: 1rem;">$1:</span>')
|
||||
.replace(/(abstract|research_purpose|methodology|main_arguments|conclusions|innovations|flowchart):/g, '<span style="font-weight: bold; font-size: 1rem;">$1:</span>')
|
||||
.replace(/(academic_contribution|practical_significance|limitations|implications):/g, '<span style="font-weight: bold; font-size: 1rem;">$1:</span>')
|
||||
.split('\n')
|
||||
.map(line => line.trimEnd())
|
||||
.join('\n');
|
||||
.map(line => `<p style="margin: 0 0 10px;">${line.trimEnd()}</p>`)
|
||||
.join('');
|
||||
// 检查是否有流程图数据
|
||||
let flowchartData = analysisResult.flowchart || 'No flowchart data available';
|
||||
|
||||
modalContent = `
|
||||
<pre class="report-content" style="white-space: pre-wrap; word-wrap: break-word;">${formattedReport}</pre>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 pe-3" style="width: 70%;">
|
||||
<h5 class="mb-2" style="font-size: 1.2rem; font-weight: 600;">Report</h5>
|
||||
<div style="background-color: white; padding: 10px 35px 10px 35px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); height: calc(80vh - 30px);">
|
||||
<pre class="report-content custom-scrollbar" style="white-space: pre-wrap; word-wrap: break-word; height: 100%; overflow-y: auto; scrollbar-width: 4px; scrollbar-color: #d3d3d3 transparent; scrollbar-gutter: stable; margin: 0;padding: 10px 20px 10px 20px;">
|
||||
${formattedReport}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 ps-3" style="width: 30%;">
|
||||
<h5 class="mb-2" style="font-size: 1.2rem; font-weight: 600;">FlowChart</h5>
|
||||
<div class="mermaid-wrapper custom-scrollbar" style="background-color: white; padding: 10px 35px 10px 35px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); height: calc(80vh - 30px); overflow: auto; scrollbar-width: 4px; scrollbar-color: #d3d3d3 transparent; scrollbar-gutter: stable;padding: 10px 20px 10px;">
|
||||
<div class="mermaid">
|
||||
${flowchartData}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else if (analysisResult.status === 'failed') {
|
||||
modalContent = `
|
||||
@@ -764,19 +786,19 @@
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal fade';
|
||||
modal.id = 'referenceDetailModal';
|
||||
modal.id = 'paperDetailModal';
|
||||
modal.setAttribute('role', 'dialog');
|
||||
modal.setAttribute('aria-modal', 'true');
|
||||
modal.setAttribute('aria-labelledby', 'referenceDetailModalTitle');
|
||||
modal.setAttribute('aria-labelledby', 'paperDetailModalTitle');
|
||||
|
||||
modal.innerHTML = `
|
||||
<div class="modal-dialog modal-lg" style="max-width: 80%; margin: 1.75rem auto;">
|
||||
<div class="modal-content" style="min-height: 80vh;">
|
||||
<div class="modal-dialog modal-lg" style="max-width: 70%; margin: 1.75rem auto;">
|
||||
<div class="modal-content" style="min-height: 90vh;">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="referenceDetailModalTitle">Paper Analysis</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<h5 class="modal-title" id="paperDetailModalTitle">Paper Analysis</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" style="outline: none; box-shadow: none;"></button>
|
||||
</div>
|
||||
<div class="modal-body" style="max-height: calc(80vh - 60px); overflow-y: auto;">
|
||||
<div class="modal-body" style="padding: 20px;">
|
||||
${modalContent}
|
||||
</div>
|
||||
</div>
|
||||
@@ -785,12 +807,43 @@
|
||||
|
||||
document.body.appendChild(modal);
|
||||
const modalInstance = new bootstrap.Modal(modal, {
|
||||
keyboard: true,
|
||||
focus: true
|
||||
backdrop: 'static', // 禁用点击空白处关闭
|
||||
keyboard: false // 禁用 ESC 键关闭
|
||||
});
|
||||
|
||||
modalInstance.show();
|
||||
|
||||
// 初始化 Mermaid 图表
|
||||
if (analysisResult.status === 'completed' && analysisResult.flowchart) {
|
||||
// 在模态框显示后重新初始化 Mermaid
|
||||
modal.addEventListener('shown.bs.modal', async () => {
|
||||
try {
|
||||
// 清除之前的图表
|
||||
const mermaidDiv = modal.querySelector('.mermaid');
|
||||
if (mermaidDiv) {
|
||||
mermaidDiv.innerHTML = analysisResult.flowchart;
|
||||
// 重新初始化 mermaid
|
||||
await window.mermaid.init();
|
||||
// 如果初始化失败,尝试重新渲染
|
||||
if (!mermaidDiv.querySelector('svg')) {
|
||||
window.mermaid.contentLoaded();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize mermaid:', error);
|
||||
const mermaidDiv = modal.querySelector('.mermaid');
|
||||
if (mermaidDiv) {
|
||||
mermaidDiv.innerHTML = `
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
Failed to render flowchart. Please try closing and reopening this dialog.
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
modal.addEventListener('hide.bs.modal', () => {
|
||||
const focusedElement = document.activeElement;
|
||||
if (modal.contains(focusedElement)) {
|
||||
@@ -809,32 +862,31 @@
|
||||
}
|
||||
|
||||
// View paper details from card
|
||||
function viewReferenceDetailFromCard(card) {
|
||||
const referenceId = card.id.replace('reference-', '');
|
||||
viewReferenceDetail(referenceId);
|
||||
function DetailFromCard(card) {
|
||||
const paperId = card.id.replace('paper-', '');
|
||||
viewDetail(paperId);
|
||||
}
|
||||
|
||||
|
||||
// Delete paper function
|
||||
async function deleteReference(referenceId) {
|
||||
async function deletePaper(paperId) {
|
||||
if (!confirm('Are you sure you want to delete this Paper? This action cannot be undone.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/${referenceId}`, {
|
||||
const response = await fetch(`${API_BASE_URL}/delete/${paperId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const card = document.getElementById(`reference-${referenceId}`);
|
||||
const card = document.getElementById(`paper-${paperId}`);
|
||||
if (card) {
|
||||
card.remove();
|
||||
}
|
||||
|
||||
const referencesList = document.getElementById('referenceAnalysis');
|
||||
if (!referencesList.children.length) {
|
||||
referencesList.innerHTML = '<div class="alert alert-info">No Paper data, please upload</div>';
|
||||
const papersList = document.getElementById('paper');
|
||||
if (!papersList.children.length) {
|
||||
papersList.innerHTML = '<div class="alert alert-info">No Paper data, please upload</div>';
|
||||
}
|
||||
|
||||
alert('Deleted successfully');
|
||||
@@ -848,9 +900,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add chat dialog function
|
||||
async function openChatDialog(referenceId, title) {
|
||||
async function openChatDialog(paperId) {
|
||||
try {
|
||||
// 使用已获取的报告数据
|
||||
const report = paperReports.get(paperId);
|
||||
let paperTitle = 'Chat';
|
||||
|
||||
// 从报告中获取标题
|
||||
if (report && report.status === 'completed' && report['1. Basic Information'] && report['1. Basic Information'].title) {
|
||||
paperTitle = report['1. Basic Information'].title;
|
||||
}
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal fade';
|
||||
modal.id = 'chatModal';
|
||||
@@ -862,7 +923,7 @@
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered" style="max-width: 800px;">
|
||||
<div class="modal-content" style="min-height: 60vh;">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="chatModalTitle">${title}</h5>
|
||||
<h5 class="modal-title" id="chatModalTitle">${paperTitle}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body d-flex flex-column" style="height: calc(60vh - 76px);">
|
||||
@@ -875,7 +936,7 @@
|
||||
aria-label="Question input">
|
||||
<button class="btn"
|
||||
style="background: var(--primary-color); color: white;"
|
||||
onclick="sendQuestion('${referenceId}')"
|
||||
onclick="sendQuestion('${paperId}')"
|
||||
aria-label="Send question">
|
||||
Send
|
||||
</button>
|
||||
@@ -916,22 +977,26 @@
|
||||
modalInstance.show();
|
||||
|
||||
// 加载聊天历史
|
||||
await loadChatHistory(referenceId);
|
||||
await loadChatHistory(paperId);
|
||||
|
||||
// 添加回车键事件监听器
|
||||
const input = document.getElementById('questionInput');
|
||||
input.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
sendQuestion(referenceId);
|
||||
sendQuestion(paperId);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to open chat dialog:', error);
|
||||
alert('Failed to open chat dialog');
|
||||
}
|
||||
}
|
||||
|
||||
// Load chat history function
|
||||
async function loadChatHistory(referenceId) {
|
||||
async function loadChatHistory(paperId) {
|
||||
const chatHistory = document.getElementById('chatHistory');
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/${referenceId}/qa/history`);
|
||||
const response = await fetch(`${API_BASE_URL}/${paperId}/qa/history`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to load chat history');
|
||||
@@ -948,14 +1013,14 @@
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-start mb-2">
|
||||
<div class="me-2">👤</div>
|
||||
<div class="bg-light rounded p-2 flex-grow-1">
|
||||
<div class="bg-light rounded p-2 flex-grow-1" style="word-break: break-word;">
|
||||
${chat.question}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="me-2">🤖</div>
|
||||
<div class="bg-primary bg-opacity-10 rounded p-2 flex-grow-1">
|
||||
<pre><code>${processMarkdownContent(chat.answer)}</code></pre>
|
||||
<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;"><code style="word-break: break-word;">${MarkdownContent(chat.answer)}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end text-muted small mt-1">
|
||||
@@ -972,7 +1037,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function processMarkdownContent(content) {
|
||||
function MarkdownContent(content) {
|
||||
try {
|
||||
// 如果内容是JSON字符串,先解析它
|
||||
if (typeof content === 'string' && content.startsWith('"') && content.endsWith('"')) {
|
||||
@@ -1002,7 +1067,7 @@
|
||||
}
|
||||
|
||||
// Send question function
|
||||
async function sendQuestion(referenceId) {
|
||||
async function sendQuestion(paperId) {
|
||||
const input = document.getElementById('questionInput');
|
||||
const question = input.value.trim();
|
||||
|
||||
@@ -1023,7 +1088,7 @@
|
||||
questionDiv.innerHTML = `
|
||||
<div class="d-flex align-items-start mb-2">
|
||||
<div class="me-2">👤</div>
|
||||
<div class="bg-light rounded p-2 flex-grow-1">
|
||||
<div class="bg-light rounded p-2 flex-grow-1" style="word-break: break-word;">
|
||||
${question}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1047,12 +1112,12 @@
|
||||
chatHistory.appendChild(loadingDiv);
|
||||
chatHistory.scrollTop = chatHistory.scrollHeight;
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/qa`, {
|
||||
const response = await fetch(`${API_BASE_URL}/${paperId}/qa`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ question, reference_id })
|
||||
body: JSON.stringify({ question })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -1088,7 +1153,7 @@
|
||||
answerDiv.innerHTML = `
|
||||
<div class="me-2">🤖</div>
|
||||
<div class="bg-primary bg-opacity-10 rounded p-2 flex-grow-1">
|
||||
<pre><code>${processMarkdownContent(result.answer)}</code></pre>
|
||||
<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;"><code style="word-break: break-word;">${MarkdownContent(result.answer)}</code></pre>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1123,9 +1188,49 @@
|
||||
|
||||
// 添加显示文献列表的函数
|
||||
function showPaperList() {
|
||||
loadReferences();
|
||||
// 显示文献列表页面
|
||||
document.getElementById('DetailPage').classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 添加下载报告功能
|
||||
function downloadReport() {
|
||||
if (!currentReportData) {
|
||||
alert('No report available to download');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用原始的JSON数据创建下载内容
|
||||
const downloadContent = JSON.stringify(currentReportData, null, 2);
|
||||
|
||||
// 创建Blob对象
|
||||
const blob = new Blob([downloadContent], { type: 'application/json' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
|
||||
// 创建临时下载链接
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `paper_analysis_report_${new Date().toISOString().split('T')[0]}.json`;
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
// 清理
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
} catch (error) {
|
||||
console.error('Failed to download report:', error);
|
||||
alert('Failed to download report');
|
||||
}
|
||||
}
|
||||
|
||||
// 在页面加载完成后自动显示文献列表
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
showPaperList();
|
||||
loadPapers();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user