更新了文献分析部分
This commit is contained in:
+322
-59
@@ -88,6 +88,22 @@
|
||||
transform: translateY(-1px);
|
||||
color: white;
|
||||
}
|
||||
.btn-info {
|
||||
background: linear-gradient(45deg, #818CF8, #6366F1);
|
||||
border: none;
|
||||
color: white !important;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-info:hover,
|
||||
.btn-info:active,
|
||||
.btn-info:focus {
|
||||
background: linear-gradient(45deg, #6366F1, #818CF8);
|
||||
transform: translateY(-1px);
|
||||
color: white !important;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #d3d3d3;
|
||||
@@ -373,9 +389,9 @@
|
||||
|
||||
<!-- 项目文献页面的侧边栏 -->
|
||||
<div class="sidebar-menu hidden" id="projectDetailSidebar">
|
||||
<div class="sidebar-item" onclick="uploadLiterature()">
|
||||
<i class="bi bi-upload"></i>
|
||||
<span>Upload</span>
|
||||
<div class="sidebar-item" onclick="showLiteratureList()">
|
||||
<i class="bi bi-list-ul"></i>
|
||||
<span>Literature List</span>
|
||||
</div>
|
||||
<div class="sidebar-item" onclick="downloadReferenceReport()">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
@@ -404,13 +420,37 @@
|
||||
|
||||
<!-- 项目文献详情页面 -->
|
||||
<div id="projectDetailPage" class="content-body hidden">
|
||||
<div class="content-header">
|
||||
<div class="content-header d-flex justify-content-between align-items-center">
|
||||
<h3 class="content-title" id="referenceAnalysisTitle">Literature Analysis</h3>
|
||||
<button class="btn btn-info" onclick="uploadLiterature()">
|
||||
<i class="bi bi-upload me-2"></i>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
<div id="referenceAnalysis" class="mt-4">
|
||||
<!-- 文献分析内容将在这里动态加载 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文献分析报告页面 -->
|
||||
<div id="literatureReportPage" class="content-body hidden">
|
||||
<div class="content-header d-flex justify-content-between align-items-center">
|
||||
<h3 class="content-title" id="literatureReportTitle">Literature 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="literatureReportContent" class="mt-4">
|
||||
<!-- 报告内容将在这里动态加载 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -422,6 +462,7 @@
|
||||
const API_BASE_URL = 'https://dev.obscura.work/lab'; // 修改为正确的API地址
|
||||
let token = localStorage.getItem('token');
|
||||
let currentProjectId = null;
|
||||
let currentReportData = null; // 添加存储当前报告数据的变量
|
||||
|
||||
// 检查登录状态
|
||||
if (!token) {
|
||||
@@ -520,9 +561,10 @@
|
||||
document.getElementById('projectsListPage').classList.remove('hidden');
|
||||
document.getElementById('projectListSidebar').classList.remove('hidden');
|
||||
|
||||
// 隐藏项目文献页面和对应的侧边栏
|
||||
// 隐藏其他页面和侧边栏
|
||||
document.getElementById('projectDetailPage').classList.add('hidden');
|
||||
document.getElementById('projectDetailSidebar').classList.add('hidden');
|
||||
document.getElementById('literatureReportPage').classList.add('hidden');
|
||||
|
||||
currentProjectId = null;
|
||||
// 重新加载项目列表数据
|
||||
@@ -541,6 +583,9 @@
|
||||
document.getElementById('projectDetailPage').classList.remove('hidden');
|
||||
document.getElementById('projectDetailSidebar').classList.remove('hidden');
|
||||
|
||||
// 隐藏报告页面
|
||||
document.getElementById('literatureReportPage').classList.add('hidden');
|
||||
|
||||
document.getElementById('referenceAnalysisTitle').textContent = `Literature Analysis - ${projectName}`;
|
||||
|
||||
await loadReferences(projectId);
|
||||
@@ -976,65 +1021,147 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const loadingToast = document.createElement('div');
|
||||
loadingToast.className = 'alert alert-info position-fixed top-50 start-50 translate-middle';
|
||||
loadingToast.innerHTML = `
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="spinner-border spinner-border-sm" role="status">
|
||||
<span class="visually-hidden">Generating...</span>
|
||||
// 1. 检查是否有文献
|
||||
const referencesList = document.getElementById('referenceAnalysis');
|
||||
if (referencesList && referencesList.innerHTML.includes('No literature data')) {
|
||||
alert('Please upload literature first!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示报告页面
|
||||
document.getElementById('projectsListPage').classList.add('hidden');
|
||||
document.getElementById('projectDetailPage').classList.add('hidden');
|
||||
const reportPage = document.getElementById('literatureReportPage');
|
||||
reportPage.classList.remove('hidden');
|
||||
|
||||
// Show loading status
|
||||
const showLoading = (message) => {
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="d-flex align-items-center justify-content-center" style="min-height: 200px;">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<h5 class="mb-0">${message}</h5>
|
||||
<p class="text-muted mt-2">This may take a few minutes</p>
|
||||
</div>
|
||||
</div>
|
||||
<span>Generating literature analysis report, please wait...</span>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(loadingToast);
|
||||
`;
|
||||
};
|
||||
|
||||
const analyzeResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/analyze_report`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
showLoading('Getting literature analysis report...');
|
||||
|
||||
// 2. Check if report already exists
|
||||
const existingReport = await fetch(`${API_BASE_URL}/references/${currentProjectId}/summary_report`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (!analyzeResponse.ok) {
|
||||
throw new Error((await analyzeResponse.json()).detail || 'Failed to generate report');
|
||||
if (existingReport.ok) {
|
||||
const report = await existingReport.json();
|
||||
currentReportData = report;
|
||||
document.getElementById('literatureReportContent').innerHTML = formatReportContent(report);
|
||||
return;
|
||||
}
|
||||
|
||||
const reportResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/summary_report`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
// If no report exists, start generation process
|
||||
const generateResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/analyze_report`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
if (!reportResponse.ok) {
|
||||
throw new Error((await reportResponse.json()).detail || 'Failed to get report');
|
||||
if (!generateResponse.ok) {
|
||||
throw new Error((await generateResponse.json()).detail || 'Failed to generate report');
|
||||
}
|
||||
|
||||
document.body.removeChild(loadingToast);
|
||||
// 3. Monitor status
|
||||
const checkStatus = async () => {
|
||||
const statusResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/analysis_status`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
return await statusResponse.json();
|
||||
};
|
||||
|
||||
const reportData = await reportResponse.json();
|
||||
const reportText = JSON.stringify(reportData, null, 2);
|
||||
const blob = new Blob([reportText], { type: 'application/json' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `literature_analysis_report_${currentProjectId}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
let attempts = 0;
|
||||
const maxAttempts = 24; // 2 minutes (5 seconds × 24)
|
||||
|
||||
const statusCheck = setInterval(async () => {
|
||||
try {
|
||||
const status = await checkStatus();
|
||||
attempts++;
|
||||
|
||||
alert('Literature analysis report generated and downloaded, you can view it in the "Reports" page');
|
||||
if (status.status === 'completed') {
|
||||
clearInterval(statusCheck);
|
||||
const finalReport = await fetch(`${API_BASE_URL}/references/${currentProjectId}/summary_report`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const report = await finalReport.json();
|
||||
currentReportData = report;
|
||||
document.getElementById('literatureReportContent').innerHTML = formatReportContent(report);
|
||||
}
|
||||
else if (status.status === 'failed') {
|
||||
clearInterval(statusCheck);
|
||||
throw new Error(status.error || 'Report generation failed');
|
||||
}
|
||||
else if (attempts >= maxAttempts) {
|
||||
clearInterval(statusCheck);
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-warning">
|
||||
Report generation is taking longer than expected. Please refresh and try again later.
|
||||
<button class="btn btn-primary mt-2" onclick="downloadReferenceReport()">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
else {
|
||||
showLoading(`${status.status === 'processing' ? 'Generating report' : 'Waiting'}...`);
|
||||
}
|
||||
} catch (error) {
|
||||
clearInterval(statusCheck);
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
Failed to generate report: ${error.message}
|
||||
<button class="btn btn-primary mt-2" onclick="downloadReferenceReport()">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
} catch (error) {
|
||||
const loadingToast = document.querySelector('.alert-info');
|
||||
if (loadingToast) {
|
||||
document.body.removeChild(loadingToast);
|
||||
}
|
||||
|
||||
console.error('Failed to generate literature analysis report:', error);
|
||||
alert(`Failed to generate literature analysis report: ${error.message}`);
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
Operation failed: ${error.message}
|
||||
<button class="btn btn-primary mt-2" onclick="downloadReferenceReport()">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加格式化报告内容的函数
|
||||
function formatReportContent(jsonData) {
|
||||
if (!jsonData) return '<div class="alert alert-info">No report data available</div>';
|
||||
|
||||
return `<div class="card">
|
||||
<div class="card-body">
|
||||
<pre style="white-space: pre-wrap; word-wrap: break-word;">${
|
||||
JSON.stringify(jsonData, null, 2)
|
||||
.replace(/[{}"]/g, '')
|
||||
.replace(/},/g, '')
|
||||
.replace(/{ },/g, '')
|
||||
.replace(/^\s*,/gm, '')
|
||||
.replace(/Literature Summary Report:/, '<div style="text-align: center"><strong style="font-size: 24px;">Literature Summary Report</strong></div>')
|
||||
.replace(/^(\s*\d+\.[^:\n]+:)/gm, '<strong>$1</strong>')
|
||||
.split('\n')
|
||||
.map(line => line.trimEnd())
|
||||
.join('\n')
|
||||
}</pre>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// Delete literature function
|
||||
async function deleteReference(projectId, referenceId) {
|
||||
if (!confirm('Are you sure you want to delete this literature? This action cannot be undone.')) {
|
||||
@@ -1357,19 +1484,155 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 添加一些基本的样式
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
// 添加显示文献列表的函数
|
||||
function showLiteratureList() {
|
||||
// 隐藏报告页面
|
||||
document.getElementById('literatureReportPage').classList.add('hidden');
|
||||
// 显示文献列表页面
|
||||
document.getElementById('projectDetailPage').classList.remove('hidden');
|
||||
|
||||
// 如果有当前项目ID,重新加载文献列表
|
||||
if (currentProjectId) {
|
||||
loadReferences(currentProjectId);
|
||||
}
|
||||
code {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
}
|
||||
|
||||
// 添加下载报告功能
|
||||
function downloadReport() {
|
||||
if (!currentReportData) {
|
||||
alert('No report available to download');
|
||||
return;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
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 = `literature_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');
|
||||
}
|
||||
}
|
||||
|
||||
// 添加重新生成报告功能
|
||||
async function regenerateReport() {
|
||||
if (!currentProjectId) {
|
||||
alert('Please select a project first');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('Are you sure you want to regenerate the report? This may take a few minutes.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 显示加载状态
|
||||
const showLoading = (message) => {
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="d-flex align-items-center justify-content-center" style="min-height: 200px;">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<h5 class="mb-0">${message}</h5>
|
||||
<p class="text-muted mt-2">This may take a few minutes</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
showLoading('Regenerating report...');
|
||||
|
||||
// 直接调用重新生成API
|
||||
const generateResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/analyze_report?force=true`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!generateResponse.ok) {
|
||||
throw new Error((await generateResponse.json()).detail || 'Failed to regenerate report');
|
||||
}
|
||||
|
||||
// 监控状态
|
||||
let attempts = 0;
|
||||
const maxAttempts = 24; // 2 minutes (5 seconds × 24)
|
||||
|
||||
const statusCheck = setInterval(async () => {
|
||||
try {
|
||||
const statusResponse = await fetch(`${API_BASE_URL}/references/${currentProjectId}/analysis_status`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const status = await statusResponse.json();
|
||||
attempts++;
|
||||
|
||||
if (status.status === 'completed') {
|
||||
clearInterval(statusCheck);
|
||||
const finalReport = await fetch(`${API_BASE_URL}/references/${currentProjectId}/summary_report`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const report = await finalReport.json();
|
||||
currentReportData = report;
|
||||
document.getElementById('literatureReportContent').innerHTML = formatReportContent(report);
|
||||
}
|
||||
else if (status.status === 'failed') {
|
||||
clearInterval(statusCheck);
|
||||
throw new Error(status.error || 'Report regeneration failed');
|
||||
}
|
||||
else if (attempts >= maxAttempts) {
|
||||
clearInterval(statusCheck);
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-warning">
|
||||
Report regeneration is taking longer than expected. Please refresh and try again later.
|
||||
<button class="btn btn-primary mt-2" onclick="regenerateReport()">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
else {
|
||||
showLoading(`${status.status === 'processing' ? 'Regenerating report' : 'Waiting'}...`);
|
||||
}
|
||||
} catch (error) {
|
||||
clearInterval(statusCheck);
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
Failed to regenerate report: ${error.message}
|
||||
<button class="btn btn-primary mt-2" onclick="regenerateReport()">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
} catch (error) {
|
||||
document.getElementById('literatureReportContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
Operation failed: ${error.message}
|
||||
<button class="btn btn-primary mt-2" onclick="regenerateReport()">
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -27,6 +27,7 @@ from io import BytesIO, StringIO
|
||||
import aiohttp
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from functools import partial
|
||||
import threading
|
||||
|
||||
# Database Configuration
|
||||
MONGODB_URL = "mongodb://lab:[email protected]:27017/lab"
|
||||
@@ -1275,7 +1276,7 @@ async def export_experiment_data(
|
||||
experiment = await db.experiments.find_one({"_id": ObjectId(experiment_id)})
|
||||
zip_filename = f"experiment_{experiment['experiment_name']}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
|
||||
|
||||
# 准备ZIP文��下载
|
||||
# 准备ZIP文<50><E69687>下载
|
||||
zip_buffer.seek(0)
|
||||
|
||||
return StreamingResponse(
|
||||
@@ -1649,68 +1650,6 @@ async def analyze_project_data(project_data):
|
||||
return None
|
||||
|
||||
|
||||
# 修改函数定义为异步函数
|
||||
async def analyze_reference_summary(reference_data):
|
||||
system_prompt = """
|
||||
You are an AI assistant responsible for analyzing literature reports.
|
||||
You will summarize and analyze all literature reports and generate a comprehensive analysis report in JSON format.
|
||||
The JSON structure must strictly follow the provided template.
|
||||
"""
|
||||
|
||||
user_prompt = f"""Analyze the following literature reports:
|
||||
Literature reports: {json.dumps(reference_data, ensure_ascii=False)}
|
||||
|
||||
Generate a JSON response with the following structure:
|
||||
|
||||
{{
|
||||
"Literature Summary Report": {{
|
||||
"overview": {{
|
||||
"total_papers": "[Number of papers]",
|
||||
"time_range": {{"start_year": "[Start year]", "end_year": "[End year]"}},
|
||||
"main_research_areas": "[Main research areas of the papers]"
|
||||
}},
|
||||
"research_trends": {{
|
||||
"major_themes": "[Major themes areas of the papers]",
|
||||
"common_methodologies": "[Common methodologies used in the papers]",
|
||||
"emerging_topics": "[Emerging topics in the papers]"
|
||||
}},
|
||||
"key_findings": {{
|
||||
"theoretical_advances": "[Theoretical advances in the papers]",
|
||||
"experimental_results": "[Experimental results in the papers]",
|
||||
"common_conclusions": "[Common conclusions in the papers]"
|
||||
}},
|
||||
"research_gaps": {{
|
||||
"current_limitations": "[Current limitations]",
|
||||
"unexplored_areas": "[Unexplored areas]",
|
||||
"technical_challenges": "[Technical challenges"
|
||||
}},
|
||||
"future_directions": {{
|
||||
"potential_applications": "[Potential future applications]",
|
||||
"methodological_suggestions": "[Methodological suggestions based on literature summary]"
|
||||
}},
|
||||
"impact_assessment": {{
|
||||
"academic_influence": "[Summarize the academic influence of the literature]",
|
||||
"practical_value": "[Summarize the practical value of the literature]"
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
]
|
||||
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=messages,
|
||||
response_format={'type': 'json_object'}
|
||||
)
|
||||
return json.loads(response.choices[0].message.content)
|
||||
except Exception as e:
|
||||
print(f"Error calling DeepSeek API: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@app.get("/lab/projects/{project_id}/analyze")
|
||||
@@ -2116,6 +2055,75 @@ async def get_reference_report(
|
||||
except Exception as e:
|
||||
print(f"Error closing Redis connection: {e}")
|
||||
|
||||
|
||||
|
||||
# 修改函数定义为异步函数
|
||||
async def analyze_reference_summary(reference_data):
|
||||
system_prompt = """
|
||||
You are an AI assistant responsible for analyzing literature reports.
|
||||
You will summarize and analyze all literature reports and generate a comprehensive analysis report in JSON format.
|
||||
The JSON structure must strictly follow the provided template.
|
||||
"""
|
||||
|
||||
user_prompt = f"""Analyze the following literature reports:
|
||||
Literature reports: {json.dumps(reference_data, ensure_ascii=False)}
|
||||
|
||||
Generate a JSON response with the following structure:
|
||||
|
||||
{{
|
||||
"Literature Summary Report": {{
|
||||
"overview": {{
|
||||
"total_papers": "[Number of papers]",
|
||||
"time_range": {{"start_year": "[Start year]", "end_year": "[End year]"}},
|
||||
"main_research_areas": "[Main research areas of the papers]"
|
||||
}},
|
||||
"research_trends": {{
|
||||
"major_themes": "[Major themes areas of the papers]",
|
||||
"common_methodologies": "[Common methodologies used in the papers]",
|
||||
"emerging_topics": "[Emerging topics in the papers]"
|
||||
}},
|
||||
"key_findings": {{
|
||||
"theoretical_advances": "[Theoretical advances in the papers]",
|
||||
"experimental_results": "[Experimental results in the papers]",
|
||||
"common_conclusions": "[Common conclusions in the papers]"
|
||||
}},
|
||||
"research_gaps": {{
|
||||
"current_limitations": "[Current limitations]",
|
||||
"unexplored_areas": "[Unexplored areas]",
|
||||
"technical_challenges": "[Technical challenges"
|
||||
}},
|
||||
"future_directions": {{
|
||||
"potential_applications": "[Potential future applications]",
|
||||
"methodological_suggestions": "[Methodological suggestions based on literature summary]"
|
||||
}},
|
||||
"impact_assessment": {{
|
||||
"academic_influence": "[Summarize the academic influence of the literature]",
|
||||
"practical_value": "[Summarize the practical value of the literature]"
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
]
|
||||
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
messages=messages,
|
||||
response_format={'type': 'json_object'}
|
||||
)
|
||||
return json.loads(response.choices[0].message.content)
|
||||
except Exception as e:
|
||||
print(f"Error calling DeepSeek API: {e}")
|
||||
return None
|
||||
|
||||
|
||||
# 创建线程池
|
||||
analysis_thread_pool = ThreadPoolExecutor(max_workers=3)
|
||||
|
||||
@app.get("/lab/references/{project_id}/analyze_report")
|
||||
async def analyze_reference_summary_report(
|
||||
project_id: str,
|
||||
@@ -2126,6 +2134,21 @@ async def analyze_reference_summary_report(
|
||||
redis = await get_redis()
|
||||
|
||||
try:
|
||||
# 检查是否已经有正在进行的分析任务
|
||||
await redis.select(204)
|
||||
status_key = f"reference_analysis_status:{project_id}"
|
||||
current_status = await redis.get(status_key)
|
||||
|
||||
if current_status:
|
||||
status_data = json.loads(current_status)
|
||||
if status_data.get("status") == "processing":
|
||||
return {
|
||||
"message": "文献分析任务正在进行中",
|
||||
"status": "processing",
|
||||
"project_id": project_id,
|
||||
"start_time": status_data.get("start_time")
|
||||
}
|
||||
|
||||
# 从MongoDB查找项目下的所有实验ID
|
||||
reference_cursor = db.references.find({
|
||||
"project_id": ObjectId(project_id)
|
||||
@@ -2138,9 +2161,62 @@ async def analyze_reference_summary_report(
|
||||
if not reference_ids:
|
||||
raise HTTPException(status_code=404, detail="No references found for this project")
|
||||
|
||||
# 记录分析开始状态
|
||||
status_data = {
|
||||
"status": "processing",
|
||||
"start_time": datetime.now(timezone.utc).isoformat(),
|
||||
"total_references": len(reference_ids),
|
||||
"completed_references": 0
|
||||
}
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
|
||||
# 在新线程中运行分析任务
|
||||
analysis_thread_pool.submit(run_analysis_in_thread, project_id, reference_ids)
|
||||
|
||||
return {
|
||||
"message": "文献分析任务已启动",
|
||||
"status": "processing",
|
||||
"project_id": project_id,
|
||||
"start_time": status_data["start_time"],
|
||||
"total_references": len(reference_ids)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error starting reference analysis: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
finally:
|
||||
try:
|
||||
await redis.aclose()
|
||||
except Exception as e:
|
||||
print(f"Error closing Redis connection: {e}")
|
||||
|
||||
def run_analysis_in_thread(project_id: str, reference_ids: List[str]):
|
||||
"""在独立线程中运行分析任务"""
|
||||
# 创建新的事件循环
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
try:
|
||||
# 在新的事件循环中运行异步任务
|
||||
loop.run_until_complete(process_reference_analysis(project_id, reference_ids))
|
||||
except Exception as e:
|
||||
print(f"Error in analysis thread: {str(e)}")
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
async def process_reference_analysis(project_id: str, reference_ids: List[str]):
|
||||
"""后台处理文献分析任务"""
|
||||
redis = await get_redis()
|
||||
|
||||
try:
|
||||
# 更新状态键
|
||||
await redis.select(204)
|
||||
status_key = f"reference_analysis_status:{project_id}"
|
||||
|
||||
# 从Redis db203获取所有实验报告
|
||||
await redis.select(203)
|
||||
all_reference_reports = {} # 修改为字典,使用实验ID作为key
|
||||
all_reference_reports = {}
|
||||
completed_count = 0
|
||||
|
||||
for ref_id in reference_ids:
|
||||
report_key = f"reference_report:{ref_id}"
|
||||
@@ -2149,28 +2225,101 @@ async def analyze_reference_summary_report(
|
||||
if report_data:
|
||||
try:
|
||||
parsed_report = json.loads(report_data)
|
||||
all_reference_reports[ref_id] = parsed_report # 使用实验ID作为key存储报告
|
||||
all_reference_reports[ref_id] = parsed_report
|
||||
completed_count += 1
|
||||
|
||||
# 更新进度
|
||||
await redis.select(204)
|
||||
current_status = await redis.get(status_key)
|
||||
if current_status:
|
||||
status_data = json.loads(current_status)
|
||||
status_data["completed_references"] = completed_count
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
await redis.select(203)
|
||||
|
||||
except json.JSONDecodeError:
|
||||
print(f"Error parsing reference {ref_id} report")
|
||||
continue
|
||||
|
||||
if not all_reference_reports:
|
||||
raise HTTPException(status_code=404, detail="No reference report data found")
|
||||
# 发送所有实验报告进行项目级分析
|
||||
analysis_result = await analyze_reference_summary(all_reference_reports) # 传递带有ID的报告字典
|
||||
|
||||
if not analysis_result:
|
||||
raise HTTPException(status_code=500, detail="Failed to generate project analysis report")
|
||||
|
||||
# 将分析结果保存到Redis db202
|
||||
if all_reference_reports:
|
||||
analysis_result = await analyze_reference_summary(all_reference_reports)
|
||||
|
||||
if analysis_result:
|
||||
await redis.select(204)
|
||||
report_key = f"reference_summary_report:{project_id}"
|
||||
await redis.set(report_key, json.dumps(analysis_result))
|
||||
|
||||
# 更新最终状态
|
||||
status_data = {
|
||||
"status": "completed",
|
||||
"completion_time": datetime.now(timezone.utc).isoformat(),
|
||||
"total_references": len(reference_ids),
|
||||
"completed_references": completed_count
|
||||
}
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
|
||||
print(f"Reference analysis completed for project {project_id}")
|
||||
else:
|
||||
# 更新失败状态
|
||||
status_data = {
|
||||
"status": "failed",
|
||||
"error": "Failed to generate analysis result",
|
||||
"completion_time": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
print(f"Failed to generate analysis for project {project_id}")
|
||||
else:
|
||||
# 更新失败状态
|
||||
status_data = {
|
||||
"status": "failed",
|
||||
"error": "No valid reference reports found",
|
||||
"completion_time": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
print(f"No valid reference reports found for project {project_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in background reference analysis: {str(e)}")
|
||||
try:
|
||||
await redis.select(204)
|
||||
status_data = {
|
||||
"status": "failed",
|
||||
"error": str(e),
|
||||
"completion_time": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
await redis.set(status_key, json.dumps(status_data))
|
||||
except Exception as redis_error:
|
||||
print(f"Error updating Redis status: {redis_error}")
|
||||
finally:
|
||||
try:
|
||||
await redis.aclose()
|
||||
except Exception as e:
|
||||
print(f"Error closing Redis connection: {e}")
|
||||
|
||||
# 添加新的状态检查路由
|
||||
@app.get("/lab/references/{project_id}/analysis_status")
|
||||
async def get_reference_analysis_status(
|
||||
project_id: str,
|
||||
current_user: UserModel = Depends(get_current_user)
|
||||
):
|
||||
"""获取文献分析任务的状态"""
|
||||
redis = await get_redis()
|
||||
|
||||
try:
|
||||
await redis.select(204)
|
||||
report_key = f"reference_summary_report:{project_id}"
|
||||
await redis.set(report_key, json.dumps(analysis_result))
|
||||
status_key = f"reference_analysis_status:{project_id}"
|
||||
status_data = await redis.get(status_key)
|
||||
|
||||
return analysis_result
|
||||
if not status_data:
|
||||
return {
|
||||
"status": "not_started",
|
||||
"project_id": project_id
|
||||
}
|
||||
|
||||
return json.loads(status_data)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error analyzing project data: {str(e)}")
|
||||
print(f"Error getting analysis status: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
finally:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user