From 339af355f902a971cda27a0b393a5c52a6ee801b Mon Sep 17 00:00:00 2001 From: zydi Date: Sun, 19 Jan 2025 06:05:40 +0000 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=8A=E4=BC=A0=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paper.html | 358 +++++++++++++++++++---------------------------------- paper.py | 72 ++++------- 2 files changed, 154 insertions(+), 276 deletions(-) diff --git a/paper.html b/paper.html index 16e671b..065ccc3 100644 --- a/paper.html +++ b/paper.html @@ -449,7 +449,7 @@
Loading...
- Analyzing Paper content... + Checking analysis status...
@@ -473,7 +473,7 @@
`; @@ -508,22 +508,18 @@ papersList.innerHTML = paperCards; // Get analysis status and results for each paper - papers.forEach(async (ref) => { - try { - const checkAnalysisStatus = async () => { - const analysisResponse = await fetch(`${API_BASE_URL}/report/${ref.file_hash}`); - - if (!analysisResponse.ok) { - throw new Error('Failed to fetch analysis'); - } - - const analysisResult = await analysisResponse.json(); + const checkPromises = papers.map(ref => + fetch(`${API_BASE_URL}/report/${ref.file_hash}`) + .then(response => response.json()) + .then(analysisResult => { // 存储报告数据 paperReports.set(ref.file_hash, analysisResult); const contentElement = document.querySelector(`.analysis-content-${ref.file_hash}`); const statusElement = document.querySelector(`.analysis-status-${ref.file_hash}`); + if (!contentElement || !statusElement) return; + if (analysisResult.status === 'processing') { // Processing status contentElement.innerHTML = ` @@ -537,7 +533,7 @@ statusElement.innerHTML = 'Analysis in progress...'; // 如果还在处理中,5秒后再次检查 - setTimeout(checkAnalysisStatus, 10000); + setTimeout(() => checkAnalysisStatus(ref.file_hash), 10000); } else if (analysisResult.status === 'completed') { // Completed status let author = 'N/A'; @@ -566,39 +562,44 @@ statusElement.innerHTML = 'Analysis completed'; } catch (parseError) { console.error('Failed to parse analysis result:', parseError); + contentElement.innerHTML = ` +
+ + Failed to parse analysis result +
+ `; + statusElement.innerHTML = 'Failed to parse result'; } } else if (analysisResult.status === 'failed') { // Failed status contentElement.innerHTML = `
- Analysis failed + Analysis failed, please upload again
- `; statusElement.innerHTML = `Analysis failed: ${analysisResult.message || 'Unknown error'}`; } - }; + }) + .catch(error => { + console.error(`Failed to fetch analysis for paper ${ref.file_hash}:`, error); + const contentElement = document.querySelector(`.analysis-content-${ref.file_hash}`); + const statusElement = document.querySelector(`.analysis-status-${ref.file_hash}`); + + if (contentElement && statusElement) { + contentElement.innerHTML = ` +
+ + Failed to get analysis status +
+ `; + statusElement.innerHTML = 'Failed to get analysis status'; + } + }) + ); - // 开始首次检查 - await checkAnalysisStatus(); - } catch (error) { - console.error(`Failed to fetch analysis for paper ${ref.file_hash}:`, error); - const contentElement = document.querySelector(`.analysis-content-${ref.file_hash}`); - const statusElement = document.querySelector(`.analysis-status-${ref.file_hash}`); - - contentElement.innerHTML = ` -
- - Failed to get analysis status -
- `; - statusElement.innerHTML = 'Failed to get analysis status'; - } - }); + // 等待所有状态检查完成 + await Promise.all(checkPromises); } catch (error) { console.error('Failed to load Paper list:', error); @@ -606,13 +607,42 @@
Failed to load Paper list: ${error.message}
-
`; } } + // Add check analysis status function + async function checkAnalysisStatus(fileHash) { + try { + const response = await fetch(`${API_BASE_URL}/report/${fileHash}`); + if (!response.ok) { + throw new Error('Failed to fetch analysis status'); + } + + const analysisResult = await response.json(); + const contentElement = document.querySelector(`.analysis-content-${fileHash}`); + const statusElement = document.querySelector(`.analysis-status-${fileHash}`); + + if (!contentElement || !statusElement) return; + + // 更新报告数据 + paperReports.set(fileHash, analysisResult); + + if (analysisResult.status === 'processing') { + // 如果还在处理中,继续轮询 + setTimeout(() => checkAnalysisStatus(fileHash), 10000); + } else { + // 重新加载论文列表以更新显示 + await loadPapers(); + } + } catch (error) { + console.error(`Failed to check analysis status for ${fileHash}:`, error); + } + } + async function uploadPaper() { const input = document.createElement('input'); input.type = 'file'; @@ -676,102 +706,88 @@ const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); - // 检查是否已有报告 + // 1. 首先检查是否已有分析报告 try { const reportResponse = await fetch(`${API_BASE_URL}/check/${hashHex}`); if (reportResponse.ok) { const reportData = await reportResponse.json(); if (reportData.status === 'completed') { - progressText.textContent = `Report already exists for ${file.name}, skipping analysis...`; + progressText.textContent = `Report already exists for ${file.name}, skipping...`; progressFill.style.width = '100%'; + continue; } } } catch (error) { console.error('Error checking report:', error); - // 如果检查失败,继续上传流程 } - // 检查哈希值是否存在 + // 2. 检查文件是否已存在于文件管理系统 + let fileHash = hashHex; try { const checkResponse = await fetch(`https://files.aiot.ml/checkhash/${hashHex}`); - if (checkResponse.ok) { - // 哈希值已存在,直接使用 - progressText.textContent = `File ${file.name} already exists, skipping upload...`; - progressFill.style.width = '100%'; + const checkResult = await checkResponse.json(); + + if (!checkResult.exists) { + // 文件不存在,需要上传 + progressText.textContent = `Uploading ${file.name}...`; - // 将文件信息发送到后端 API - const response = await fetch(`${API_BASE_URL}/upload`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - files: [{ - filename: file.name, - hash: hashHex - }] - }) + const formData = new FormData(); + formData.append('file', file); + formData.append('client_hash', hashHex); + + const xhr = new XMLHttpRequest(); + xhr.upload.onprogress = function(e) { + if (e.lengthComputable) { + const percentComplete = (e.loaded / e.total) * 100; + progressFill.style.width = percentComplete + '%'; + progressText.textContent = `Uploading ${file.name}: ${Math.round(percentComplete)}%`; + } + }; + + const uploadPromise = new Promise((resolve, reject) => { + xhr.onload = function() { + if (xhr.status === 200) { + resolve(JSON.parse(xhr.response)); + } else { + reject(new Error('Upload failed')); + } + }; + xhr.onerror = () => reject(new Error('Upload failed')); }); - if (!response.ok) { - throw new Error('Failed to process file'); - } - continue; + xhr.open('POST', 'https://files.aiot.ml/upload'); + xhr.send(formData); + + const uploadResult = await uploadPromise; + fileHash = uploadResult.hash; } + + // 3. 调用分析接口 + progressText.textContent = `Starting analysis for ${file.name}...`; + const response = await fetch(`${API_BASE_URL}/upload`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + files: [{ + filename: file.name, + hash: fileHash + }] + }) + }); + + if (!response.ok) { + throw new Error('Failed to process file'); + } + + progressText.textContent = `Analysis started for ${file.name}`; + progressFill.style.width = '100%'; + } catch (error) { - console.error('Error checking hash:', error); - // 如果检查失败,继续上传流程 - } - - // 创建 FormData 对象 - const formData = new FormData(); - formData.append('file', file); - formData.append('client_hash', hashHex); - - // 使用 XMLHttpRequest 来获取上传进度 - const xhr = new XMLHttpRequest(); - - xhr.upload.onprogress = function(e) { - if (e.lengthComputable) { - const percentComplete = (e.loaded / e.total) * 100; - progressFill.style.width = percentComplete + '%'; - progressText.textContent = `Uploading ${file.name}: ${Math.round(percentComplete)}%`; - } - }; - - const uploadPromise = new Promise((resolve, reject) => { - xhr.onload = function() { - if (xhr.status === 200) { - resolve(JSON.parse(xhr.response)); - } else { - reject(new Error('Upload failed')); - } - }; - xhr.onerror = () => reject(new Error('Upload failed')); - }); - - // 发送到文件存储服务 - xhr.open('POST', 'https://files.aiot.ml/upload'); - xhr.send(formData); - - const uploadResult = await uploadPromise; - - // 将文件信息发送到后端 API - const response = await fetch(`${API_BASE_URL}/upload`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - files: [{ - filename: file.name, - hash: uploadResult.hash - }] - }) - }); - - if (!response.ok) { - throw new Error('Failed to process file'); + console.error('Error processing file:', error); + progressText.textContent = `Error processing ${file.name}: ${error.message}`; + continue; } } @@ -1304,122 +1320,6 @@ alert('Failed to download report'); } } - // 简化的重试函数,复用现有的上传流程 - async function retryAnalysis(fileHash, paperTitle) { - try { - // 更新UI状态 - const contentElement = document.querySelector(`.analysis-content-${fileHash}`); - const statusElement = document.querySelector(`.analysis-status-${fileHash}`); - - contentElement.innerHTML = ` -
-
- Loading... -
- Retrying analysis... -
- `; - statusElement.innerHTML = 'Retrying analysis...'; - - // 检查文件是否存在 - let fileExists = false; - try { - const checkResponse = await fetch(`https://files.aiot.ml/checkhash/${fileHash}`); - fileExists = checkResponse.ok; - } catch (error) { - console.error('Error checking hash:', error); - } - - if (!fileExists) { - // 如果文件不存在,需要重新上传 - try { - // 从原始URL获取文件内容 - const fileResponse = await fetch(`https://files.aiot.ml/pdf/${fileHash}`); - if (!fileResponse.ok) { - throw new Error('Failed to fetch original file'); - } - const fileBlob = await fileResponse.blob(); - - // 创建FormData对象重新上传 - const formData = new FormData(); - formData.append('file', fileBlob, paperTitle); - formData.append('client_hash', fileHash); - - // 使用XMLHttpRequest上传文件 - const xhr = new XMLHttpRequest(); - - // 创建上传进度提示 - contentElement.innerHTML = ` -
-
- Loading... -
- Re-uploading file... -
- `; - - const uploadPromise = new Promise((resolve, reject) => { - xhr.onload = function() { - if (xhr.status === 200) { - resolve(JSON.parse(xhr.response)); - } else { - reject(new Error('Upload failed')); - } - }; - xhr.onerror = () => reject(new Error('Upload failed')); - }); - - // 发送到文件存储服务 - xhr.open('POST', 'https://files.aiot.ml/upload'); - xhr.send(formData); - - await uploadPromise; - } catch (error) { - throw new Error(`Failed to re-upload file: ${error.message}`); - } - } - - // 文件确认存在后,触发分析 - const response = await fetch(`${API_BASE_URL}/upload`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - files: [{ - filename: paperTitle, - hash: fileHash - }] - }) - }); - - if (!response.ok) { - throw new Error('Failed to process file'); - } - - // 等待一段时间后刷新列表 - setTimeout(async () => { - await loadPapers(); - }, 2000); - - } catch (error) { - console.error('Retry analysis failed:', error); - const contentElement = document.querySelector(`.analysis-content-${fileHash}`); - const statusElement = document.querySelector(`.analysis-status-${fileHash}`); - - contentElement.innerHTML = ` -
- - Retry failed -
- - `; - statusElement.innerHTML = `Retry failed: ${error.message}`; - } - } // 在页面加载完成后自动显示文献列表 document.addEventListener('DOMContentLoaded', function() { showPaperList(); diff --git a/paper.py b/paper.py index ca2b6c3..b4ffc8e 100644 --- a/paper.py +++ b/paper.py @@ -100,14 +100,14 @@ async def delete_paper( try: # 获取文献信息 - paper = await db.papers.find_one({"_id": ObjectId(paper_id)}) + paper = await db.papers.find_one({"file_hash": paper_id}) if not paper: raise HTTPException(status_code=404, detail="paper not found") # 从文件存储服务删除文件 file_hash = paper.get("file_hash") # 删除数据库记录 - await db.papers.delete_one({"_id": ObjectId(paper_id)}) + await db.papers.delete_one({"file_hash": paper_id}) # 删除Redis中的分析报告(如果存在) try: @@ -193,9 +193,7 @@ class BatchUploadRequest(BaseModel): files: List[FileUpload] @app.post("/paper/upload") -async def batch_upload( - request: BatchUploadRequest -): +async def batch_upload(request: BatchUploadRequest): """批量上传项目相关文献""" db = await get_database() redis = await get_redis() @@ -204,39 +202,11 @@ async def batch_upload( uploaded_papers = [] papers_to_analyze = [] - # 批量处理文件 for file in request.files: try: - # 检查文件是否已存在分析报告 - await redis.select(190) - report_key = f"paper_report:{file.hash}" - existing_report = await redis.get(report_key) - print(f"[Redis] existing_report: {existing_report}") - print(f"[Redis] file.hash: {file.hash}") - if existing_report: - report_data = json.loads(existing_report) - if report_data.get("status") == "completed": - print(f"[Redis] Report already exists for file {file.filename} with hash {file.hash}") - # 即使报告存在,也创建新的文献记录 - paper = { - "paper_link": f"https://files.aiot.ml/pdf/content/{file.hash}", - "paper_title": file.filename, - "upload_time": datetime.now(timezone.utc), - "file_hash": file.hash - } - - result = await db.papers.insert_one(paper) - paper_info = { - "paper_id": str(result.inserted_id), - "file_hash": file.hash, - "paper_title": paper["paper_title"] - } - uploaded_papers.append(paper_info) - continue - - # 创建记录 + # 1. 创建新记录 paper = { - "paper_link": f"https://files.aiot.ml/pdf/content/{file.hash}", + "paper_link": f"https://files.aiot.ml/pdf/{file.hash}", "paper_title": file.filename, "upload_time": datetime.now(timezone.utc), "file_hash": file.hash @@ -250,25 +220,33 @@ async def batch_upload( } uploaded_papers.append(paper_info) - # 如果没有现有报告或报告未完成,创建初始状态并添加到待分析列表 - if not existing_report or json.loads(existing_report).get("status") != "completed": - initial_status = { - "status": "processing", - "message": "Analysis in progress" - } - await redis.set(report_key, json.dumps(initial_status)) - papers_to_analyze.append(paper_info) + # 2. 设置分析状态 + await redis.select(190) + report_key = f"paper_report:{file.hash}" + initial_status = { + "status": "processing", + "message": "Analysis in progress" + } + await redis.set(report_key, json.dumps(initial_status)) + papers_to_analyze.append(paper_info) except Exception as file_error: print(f"处理文件 {file.filename} 时出错: {str(file_error)}") + uploaded_papers.append({ + "file_hash": file.hash, + "paper_title": file.filename, + "status": "error", + "error_message": str(file_error) + }) continue - # 只对没有报告的文件启动分析任务 + # 启动分析任务 if papers_to_analyze: asyncio.create_task(batch_analysis(papers_to_analyze)) - print(f"[Redis] 报告不存在,开始分析: {papers_to_analyze}") + print(f"[Redis] 开始分析新文件: {papers_to_analyze}") + return { - "message": f"Successfully uploaded {len(uploaded_papers)} files", + "message": f"Successfully processed {len(uploaded_papers)} files", "uploaded_files": uploaded_papers, "files_to_analyze": len(papers_to_analyze) } @@ -307,7 +285,7 @@ async def batch_analysis(papers: List[dict]): return # 从文件存储服务获取PDF内容 async with aiohttp.ClientSession() as session: - async with session.get(f'https://files.aiot.ml/pdf/content/{file_hash}') as response: + async with session.get(f'https://files.aiot.ml/pdf/{file_hash}') as response: if response.status != 200: print(f"[Redis] 获取PDF内容失败: {response.status}") raise Exception(f"Failed to get PDF content for file hash: {file_hash}")