文件
gpt_academic/crazy_functions/paper_fns/journal_paper_recom.py
binary-husky 8042750d41 Master 4.0 (#2210)
* stage academic conversation

* stage document conversation

* fix buggy gradio version

* file dynamic load

* merge more academic plugins

* accelerate nltk

* feat: 为predict函数添加文件和URL读取功能
- 添加URL检测和网页内容提取功能,支持自动提取网页文本
- 添加文件路径识别和文件内容读取功能,支持private_upload路径格式
- 集成WebTextExtractor处理网页内容提取
- 集成TextContentLoader处理本地文件读取
- 支持文件路径与问题组合的智能处理

* back

* block unstable

---------

Co-authored-by: XiaoBoAI <liuboyin2019@ia.ac.cn>
2025-08-23 15:59:22 +08:00

635 行
30 KiB
Python

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

import os
import time
import glob
from typing import Dict, List, Generator, Tuple
from dataclasses import dataclass
from crazy_functions.pdf_fns.text_content_loader import TextContentLoader
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
from toolbox import update_ui, promote_file_to_downloadzone, write_history_to_file, CatchException, report_exception
from shared_utils.fastapi_server import validate_path_safety
# 导入论文下载相关函数
from crazy_functions.论文下载 import extract_paper_id, extract_paper_ids, get_arxiv_paper, format_arxiv_id, SciHub
from pathlib import Path
from datetime import datetime, timedelta
import calendar
@dataclass
class RecommendationQuestion:
"""期刊会议推荐分析问题类"""
id: str # 问题ID
question: str # 问题内容
importance: int # 重要性 (1-5,5最高)
description: str # 问题描述
class JournalConferenceRecommender:
"""论文期刊会议推荐器"""
def __init__(self, llm_kwargs: Dict, plugin_kwargs: Dict, chatbot: List, history: List, system_prompt: str):
"""初始化推荐器"""
self.llm_kwargs = llm_kwargs
self.plugin_kwargs = plugin_kwargs
self.chatbot = chatbot
self.history = history
self.system_prompt = system_prompt
self.paper_content = ""
self.analysis_results = {}
# 定义论文分析问题库(针对期刊会议推荐)
self.questions = [
RecommendationQuestion(
id="research_field_and_topic",
question="请分析这篇论文的研究领域、主题和关键词。具体包括1)论文属于哪个主要学科领域如自然科学、工程技术、医学、社会科学、人文学科等;2)具体的研究子领域或方向;3)论文的核心主题和关键概念;4)重要的学术关键词和专业术语;5)研究的跨学科特征如果有;6)研究的地域性特征(国际性研究还是特定地区研究)。",
importance=5,
description="研究领域与主题分析"
),
RecommendationQuestion(
id="methodology_and_approach",
question="请分析论文的研究方法和技术路线。包括1)采用的主要研究方法定量研究、定性研究、理论分析、实验研究、田野调查、文献综述、案例研究等;2)使用的技术手段、工具或分析方法;3)研究设计的严谨性和创新性;4)数据收集和分析方法的适当性;5)研究方法在该学科中的先进性或传统性;6)方法学上的贡献或局限性。",
importance=4,
description="研究方法与技术路线"
),
RecommendationQuestion(
id="novelty_and_contribution",
question="请评估论文的创新性和学术贡献。包括1)研究的新颖性程度理论创新、方法创新、应用创新等;2)对现有知识体系的贡献或突破;3)解决问题的重要性和学术价值;4)研究成果的理论意义和实践价值;5)在该学科领域的地位和影响潜力;6)与国际前沿研究的关系;7)对后续研究的启发意义。",
importance=4,
description="创新性与学术贡献"
),
RecommendationQuestion(
id="target_audience_and_scope",
question="请分析论文的目标受众和应用范围。包括1)主要面向的学术群体研究者、从业者、政策制定者等;2)研究成果的潜在应用领域和受益群体;3)对学术界和实践界的价值;4)研究的国际化程度和跨文化适用性;5)是否适合国际期刊还是区域性期刊;6)语言发表偏好英文、中文或其他语言;7)开放获取的必要性和可行性。",
importance=3,
description="目标受众与应用范围"
),
]
# 按重要性排序
self.questions.sort(key=lambda q: q.importance, reverse=True)
def _load_paper(self, paper_path: str) -> Generator:
"""加载论文内容"""
yield from update_ui(chatbot=self.chatbot, history=self.history)
# 使用TextContentLoader读取文件
loader = TextContentLoader(self.chatbot, self.history)
yield from loader.execute_single_file(paper_path)
# 获取加载的内容
if len(self.history) >= 2 and self.history[-2]:
self.paper_content = self.history[-2]
yield from update_ui(chatbot=self.chatbot, history=self.history)
return True
else:
self.chatbot.append(["错误", "无法读取论文内容,请检查文件是否有效"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
return False
def _analyze_question(self, question: RecommendationQuestion) -> Generator:
"""分析单个问题"""
try:
# 创建分析提示
prompt = f"请基于以下论文内容回答问题:\n\n{self.paper_content}\n\n问题:{question.question}"
# 使用单线程版本的请求函数
response = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=prompt,
inputs_show_user=question.question, # 显示问题本身
llm_kwargs=self.llm_kwargs,
chatbot=self.chatbot,
history=[], # 空历史,确保每个问题独立分析
sys_prompt="你是一个专业的学术期刊会议推荐专家,需要仔细分析论文内容并提供准确的分析。请保持客观、专业,并基于论文内容提供深入分析。"
)
if response:
self.analysis_results[question.id] = response
return True
return False
except Exception as e:
self.chatbot.append(["错误", f"分析问题时出错: {str(e)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
return False
def _generate_journal_recommendations(self) -> Generator:
"""生成期刊推荐"""
self.chatbot.append(["生成期刊推荐", "正在基于论文分析结果生成期刊推荐..."])
yield from update_ui(chatbot=self.chatbot, history=self.history)
# 构建期刊推荐提示
journal_prompt = """请基于以下论文分析结果,为这篇论文推荐合适的学术期刊。
推荐要求:
1. 根据论文的创新性和工作质量,分别推荐不同级别的期刊:
- 顶级期刊(影响因子>8或该领域顶级期刊2-3个
- 高质量期刊影响因子4-8或该领域知名期刊3-4个
- 中等期刊影响因子1.5-4或该领域认可期刊3-4个
- 入门期刊(影响因子<1.5但声誉良好的期刊2-3个
注意:不同学科的影响因子标准差异很大,请根据论文所属学科的实际情况调整标准。
特别是医学领域,需要考虑:
- 临床医学期刊通常影响因子较高顶级期刊IF>20,高质量期刊IF>10
- 基础医学期刊影响因子相对较低但学术价值很高
- 专科医学期刊在各自领域内具有权威性
- 医学期刊的临床实用性和循证医学价值
2. 对每个期刊提供详细信息:
- 期刊全名和缩写
- 最新影响因子(如果知道)
- 期刊级别分类Q1/Q2/Q3/Q4或该学科的分类标准
- 主要研究领域和范围
- 与论文内容的匹配度评分1-10分
- 发表难度评估(容易/中等/困难/极难)
- 平均审稿周期
- 开放获取政策
- 期刊的学科分类如SCI、SSCI、A&HCI等
- 医学期刊特殊信息(如适用):
* PubMed收录情况
* 是否为核心临床期刊
* 专科领域权威性
* 循证医学等级要求
* 临床试验注册要求
* 伦理委员会批准要求
3. 按推荐优先级排序,并说明推荐理由
4. 提供针对性的投稿建议,考虑该学科的特点
论文分析结果:"""
for q in self.questions:
if q.id in self.analysis_results:
journal_prompt += f"\n\n{q.description}:\n{self.analysis_results[q.id]}"
journal_prompt += "\n\n请提供详细的期刊推荐报告,重点关注期刊的层次性和适配性。请根据论文的具体学科领域,采用该领域通用的期刊评价标准和分类体系。"
try:
response = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=journal_prompt,
inputs_show_user="生成期刊推荐报告",
llm_kwargs=self.llm_kwargs,
chatbot=self.chatbot,
history=[],
sys_prompt="你是一个资深的跨学科学术期刊推荐专家,熟悉各个学科领域不同层次的期刊。请根据论文的具体学科和创新性,推荐从顶级到入门级的各层次期刊。不同学科有不同的期刊评价标准理工科重视影响因子和SCI收录,社会科学重视SSCI和学科声誉,人文学科重视A&HCI和同行评议,医学领域重视PubMed收录、临床实用性、循证医学价值和伦理规范。请根据论文所属学科采用相应的评价标准。"
)
if response:
return response
return "期刊推荐生成失败"
except Exception as e:
self.chatbot.append(["错误", f"生成期刊推荐时出错: {str(e)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
return "期刊推荐生成失败: " + str(e)
def _generate_conference_recommendations(self) -> Generator:
"""生成会议推荐"""
self.chatbot.append(["生成会议推荐", "正在基于论文分析结果生成会议推荐..."])
yield from update_ui(chatbot=self.chatbot, history=self.history)
# 获取当前时间信息
current_time = datetime.now()
current_date_str = current_time.strftime("%Y年%m月%d")
current_year = current_time.year
current_month = current_time.month
# 构建会议推荐提示
conference_prompt = f"""请基于以下论文分析结果,为这篇论文推荐合适的学术会议。
**重要提示:当前时间是{current_date_str}{current_year}{current_month}月),请基于这个时间点推断会议的举办时间和投稿截止时间。**
推荐要求:
1. 根据论文的创新性和工作质量,分别推荐不同级别的会议:
- 顶级会议该领域最权威的国际会议2-3个
- 高质量会议该领域知名的国际或区域会议3-4个
- 中等会议该领域认可的专业会议3-4个
- 专业会议该领域细分方向的专门会议2-3个
注意:不同学科的会议评价标准不同:
- 计算机科学可参考CCF分类A/B/C类
- 工程学可参考EI收录和影响力
- 医学:可参考会议的临床影响和同行认可度
- 社会科学:可参考会议的学术声誉和参与度
- 人文学科:可参考会议的历史和学术传统
- 自然科学:可参考会议的国际影响力和发表质量
特别是医学会议,需要考虑:
- 临床医学会议重视实用性和临床指导价值
- 基础医学会议重视科学创新和机制研究
- 专科医学会议在各自领域内具有权威性
- 国际医学会议的CME学分认证情况
2. 对每个会议提供详细信息:
- 会议全名和缩写
- 会议级别分类(根据该学科的评价标准)
- 主要研究领域和主题
- 与论文内容的匹配度评分1-10分
- 录用难度评估(容易/中等/困难/极难)
- 会议举办周期(年会/双年会/不定期等)
- **基于当前时间{current_date_str},推断{current_year}年和{current_year+1}年的举办时间和地点**(请根据往年的举办时间规律进行推断)
- **基于推断的会议时间,估算论文提交截止时间**通常在会议前3-6个月
- 会议的国际化程度和影响范围
- 医学会议特殊信息(如适用):
* 是否提供CME学分
* 临床实践指导价值
* 专科认证机构认可情况
* 会议论文集的PubMed收录情况
* 伦理和临床试验相关要求
3. 按推荐优先级排序,并说明推荐理由
4. **基于当前时间{current_date_str},提供会议投稿的时间规划建议**
- 哪些会议可以赶上{current_year}年的投稿截止时间
- 哪些会议需要准备{current_year+1}年的投稿
- 具体的时间安排建议
论文分析结果:"""
for q in self.questions:
if q.id in self.analysis_results:
conference_prompt += f"\n\n{q.description}:\n{self.analysis_results[q.id]}"
conference_prompt += f"\n\n请提供详细的会议推荐报告,重点关注会议的层次性和时效性。请根据论文的具体学科领域,采用该领域通用的会议评价标准。\n\n**特别注意:请根据当前时间{current_date_str}和各会议的历史举办时间规律,准确推断{current_year}年和{current_year+1}年的会议时间安排,不要使用虚构的时间。**"
try:
response = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=conference_prompt,
inputs_show_user="生成会议推荐报告",
llm_kwargs=self.llm_kwargs,
chatbot=self.chatbot,
history=[],
sys_prompt="你是一个资深的跨学科学术会议推荐专家,熟悉各个学科领域不同层次的学术会议。请根据论文的具体学科和创新性,推荐从顶级到专业级的各层次会议。不同学科有不同的会议评价标准和文化理工科重视技术创新和国际影响力,社会科学重视理论贡献和社会意义,人文学科重视学术深度和文化价值,医学领域重视临床实用性、CME学分认证、专科权威性和伦理规范。请根据论文所属学科采用相应的评价标准和推荐策略。"
)
if response:
return response
return "会议推荐生成失败"
except Exception as e:
self.chatbot.append(["错误", f"生成会议推荐时出错: {str(e)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
return "会议推荐生成失败: " + str(e)
def _generate_priority_summary(self, journal_recommendations: str, conference_recommendations: str) -> Generator:
"""生成优先级总结"""
self.chatbot.append(["生成优先级总结", "正在生成投稿优先级总结..."])
yield from update_ui(chatbot=self.chatbot, history=self.history)
# 获取当前时间信息
current_time = datetime.now()
current_date_str = current_time.strftime("%Y年%m月%d")
current_month = current_time.strftime("%Y年%m月")
# 计算未来时间点
def add_months(date, months):
"""安全地添加月份"""
month = date.month - 1 + months
year = date.year + month // 12
month = month % 12 + 1
day = min(date.day, calendar.monthrange(year, month)[1])
return date.replace(year=year, month=month, day=day)
future_6_months = add_months(current_time, 6).strftime('%Y年%m月')
future_12_months = add_months(current_time, 12).strftime('%Y年%m月')
future_year = (current_time.year + 1)
priority_prompt = f"""请基于以下期刊和会议推荐结果,生成一个综合的投稿优先级总结。
**重要提示:当前时间是{current_date_str}{current_month}),请基于这个时间点制定投稿计划。**
期刊推荐结果:
{journal_recommendations}
会议推荐结果:
{conference_recommendations}
请提供:
1. 综合投稿策略建议(考虑该学科的发表文化和惯例)
- 期刊优先还是会议优先(不同学科有不同偏好)
- 国际期刊/会议 vs 国内期刊/会议的选择策略
- 英文发表 vs 中文发表的考虑
2. 按时间线排列的投稿计划(**基于当前时间{current_date_str},考虑截止时间和审稿周期**
- 短期目标({current_month}起3-6个月内,即到{future_6_months}
- 中期目标6-12个月内,即到{future_12_months}
- 长期目标1年以上,即{future_year}年以后)
3. 风险分散策略
- 同时投稿多个不同级别的目标
- 考虑该学科的一稿多投政策
- 备选方案和应急策略
4. 针对论文可能需要的改进建议
- 根据目标期刊/会议的要求调整内容
- 语言和格式的优化建议
- 补充实验或分析的建议
5. 预期的发表时间线和成功概率评估(基于当前时间{current_date_str}
6. 该学科特有的发表注意事项
- 伦理审查要求(如医学、心理学等)
- 数据开放要求(如某些自然科学领域)
- 利益冲突声明(如医学、工程等)
- 医学领域特殊要求:
* 临床试验注册要求ClinicalTrials.gov、中国临床试验注册中心等
* 患者知情同意和隐私保护
* 医学伦理委员会批准证明
* CONSORT、STROBE、PRISMA等报告规范遵循
* 药物/器械安全性数据要求
* CME学分认证相关要求
* 临床指南和循证医学等级要求
- 其他学科特殊要求
请以表格形式总结前10个最推荐的投稿目标期刊+会议),包括优先级排序、预期时间线和成功概率。
**注意:所有时间规划都应基于当前时间{current_date_str}进行计算,不要使用虚构的时间。**"""
try:
response = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=priority_prompt,
inputs_show_user="生成投稿优先级总结",
llm_kwargs=self.llm_kwargs,
chatbot=self.chatbot,
history=[],
sys_prompt="你是一个资深的跨学科学术发表策略专家,熟悉各个学科的发表文化、惯例和要求。请综合考虑不同学科的特点:理工科通常重视期刊发表和影响因子,社会科学平衡期刊和专著,人文学科重视同行评议和学术声誉,医学重视临床意义和伦理规范。请为作者制定最适合其学科背景的投稿策略和时间规划。"
)
if response:
return response
return "优先级总结生成失败"
except Exception as e:
self.chatbot.append(["错误", f"生成优先级总结时出错: {str(e)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
return "优先级总结生成失败: " + str(e)
def save_recommendations(self, journal_recommendations: str, conference_recommendations: str, priority_summary: str) -> Generator:
"""保存推荐报告"""
timestamp = time.strftime("%Y%m%d_%H%M%S")
# 保存为Markdown文件
try:
md_content = f"""# 论文期刊会议推荐报告
## 投稿优先级总结
{priority_summary}
## 期刊推荐
{journal_recommendations}
## 会议推荐
{conference_recommendations}
---
# 详细分析结果
"""
# 添加详细分析结果
for q in self.questions:
if q.id in self.analysis_results:
md_content += f"\n\n## {q.description}\n\n{self.analysis_results[q.id]}"
result_file = write_history_to_file(
history=[md_content],
file_basename=f"期刊会议推荐_{timestamp}.md"
)
if result_file and os.path.exists(result_file):
promote_file_to_downloadzone(result_file, chatbot=self.chatbot)
self.chatbot.append(["保存成功", f"推荐报告已保存至: {os.path.basename(result_file)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
else:
self.chatbot.append(["警告", "保存报告成功但找不到文件"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
except Exception as e:
self.chatbot.append(["警告", f"保存报告失败: {str(e)}"])
yield from update_ui(chatbot=self.chatbot, history=self.history)
def recommend_venues(self, paper_path: str) -> Generator:
"""推荐期刊会议主流程"""
# 加载论文
success = yield from self._load_paper(paper_path)
if not success:
return
# 分析关键问题
for question in self.questions:
yield from self._analyze_question(question)
# 分别生成期刊和会议推荐
journal_recommendations = yield from self._generate_journal_recommendations()
conference_recommendations = yield from self._generate_conference_recommendations()
# 生成优先级总结
priority_summary = yield from self._generate_priority_summary(journal_recommendations, conference_recommendations)
# 显示结果
yield from update_ui(chatbot=self.chatbot, history=self.history)
# 保存报告
yield from self.save_recommendations(journal_recommendations, conference_recommendations, priority_summary)
# 将完整的分析结果和推荐内容添加到历史记录中,方便用户继续提问
self._add_to_history(journal_recommendations, conference_recommendations, priority_summary)
def _add_to_history(self, journal_recommendations: str, conference_recommendations: str, priority_summary: str):
"""将分析结果和推荐内容添加到历史记录中"""
try:
# 构建完整的内容摘要
history_content = f"""# 论文期刊会议推荐分析完成
## 📊 投稿优先级总结
{priority_summary}
## 📚 期刊推荐
{journal_recommendations}
## 🏛️ 会议推荐
{conference_recommendations}
## 📋 详细分析结果
"""
# 添加详细分析结果
for q in self.questions:
if q.id in self.analysis_results:
history_content += f"\n### {q.description}\n{self.analysis_results[q.id]}\n"
history_content += "\n---\n💡 您现在可以基于以上分析结果继续提问,比如询问特定期刊的详细信息、投稿策略建议、或者对推荐结果的进一步解释。"
# 添加到历史记录中
self.history.append("论文期刊会议推荐分析")
self.history.append(history_content)
self.chatbot.append(["✅ 分析完成", "所有分析结果和推荐内容已添加到对话历史中,您可以继续基于这些内容提问。"])
except Exception as e:
self.chatbot.append(["警告", f"添加到历史记录时出错: {str(e)},但推荐报告已正常生成"])
# 即使添加历史失败,也不影响主要功能
def _find_paper_file(path: str) -> str:
"""查找路径中的论文文件(简化版)"""
if os.path.isfile(path):
return path
# 支持的文件扩展名(按优先级排序)
extensions = ["pdf", "docx", "doc", "txt", "md", "tex"]
# 简单地遍历目录
if os.path.isdir(path):
try:
for ext in extensions:
# 手动检查每个可能的文件,而不使用glob
potential_file = os.path.join(path, f"paper.{ext}")
if os.path.exists(potential_file) and os.path.isfile(potential_file):
return potential_file
# 如果没找到特定命名的文件,检查目录中的所有文件
for file in os.listdir(path):
file_path = os.path.join(path, file)
if os.path.isfile(file_path):
file_ext = file.split('.')[-1].lower() if '.' in file else ""
if file_ext in extensions:
return file_path
except Exception:
pass # 忽略任何错误
return None
def download_paper_by_id(paper_info, chatbot, history) -> str:
"""下载论文并返回保存路径
Args:
paper_info: 元组,包含论文ID类型arxiv或doi和ID值
chatbot: 聊天机器人对象
history: 历史记录
Returns:
str: 下载的论文路径或None
"""
id_type, paper_id = paper_info
# 创建保存目录 - 使用时间戳创建唯一文件夹
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
user_name = chatbot.get_user() if hasattr(chatbot, 'get_user') else "default"
from toolbox import get_log_folder, get_user
base_save_dir = get_log_folder(get_user(chatbot), plugin_name='paper_download')
save_dir = os.path.join(base_save_dir, f"papers_{timestamp}")
if not os.path.exists(save_dir):
os.makedirs(save_dir)
save_path = Path(save_dir)
chatbot.append([f"下载论文", f"正在下载{'arXiv' if id_type == 'arxiv' else 'DOI'} {paper_id} 的论文..."])
update_ui(chatbot=chatbot, history=history)
pdf_path = None
try:
if id_type == 'arxiv':
# 使用改进的arxiv查询方法
formatted_id = format_arxiv_id(paper_id)
paper_result = get_arxiv_paper(formatted_id)
if not paper_result:
chatbot.append([f"下载失败", f"未找到arXiv论文: {paper_id}"])
update_ui(chatbot=chatbot, history=history)
return None
# 下载PDF
filename = f"arxiv_{paper_id.replace('/', '_')}.pdf"
pdf_path = str(save_path / filename)
paper_result.download_pdf(filename=pdf_path)
else: # doi
# 下载DOI
sci_hub = SciHub(
doi=paper_id,
path=save_path
)
pdf_path = sci_hub.fetch()
# 检查下载结果
if pdf_path and os.path.exists(pdf_path):
promote_file_to_downloadzone(pdf_path, chatbot=chatbot)
chatbot.append([f"下载成功", f"已成功下载论文: {os.path.basename(pdf_path)}"])
update_ui(chatbot=chatbot, history=history)
return pdf_path
else:
chatbot.append([f"下载失败", f"论文下载失败: {paper_id}"])
update_ui(chatbot=chatbot, history=history)
return None
except Exception as e:
chatbot.append([f"下载错误", f"下载论文时出错: {str(e)}"])
update_ui(chatbot=chatbot, history=history)
return None
@CatchException
def 论文期刊会议推荐(txt: str, llm_kwargs: Dict, plugin_kwargs: Dict, chatbot: List,
history: List, system_prompt: str, user_request: str):
"""主函数 - 论文期刊会议推荐"""
# 初始化推荐器
chatbot.append(["函数插件功能及使用方式", "论文期刊会议推荐:基于论文内容分析,为您推荐合适的学术期刊和会议投稿目标。适用于各个学科专业(自然科学、工程技术、医学、社会科学、人文学科等),根据不同学科的评价标准和发表文化,提供分层次的期刊会议推荐、影响因子分析、发表难度评估、投稿策略建议等。<br><br>📋 使用方式:<br>1、直接上传PDF文件<br>2、输入DOI号或arXiv ID<br>3、点击插件开始分析"])
yield from update_ui(chatbot=chatbot, history=history)
paper_file = None
# 检查输入是否为论文IDarxiv或DOI
paper_info = extract_paper_id(txt)
if paper_info:
# 如果是论文ID,下载论文
chatbot.append(["检测到论文ID", f"检测到{'arXiv' if paper_info[0] == 'arxiv' else 'DOI'} ID: {paper_info[1]},准备下载论文..."])
yield from update_ui(chatbot=chatbot, history=history)
# 下载论文
paper_file = download_paper_by_id(paper_info, chatbot, history)
if not paper_file:
report_exception(chatbot, history, a=f"下载论文失败", b=f"无法下载{'arXiv' if paper_info[0] == 'arxiv' else 'DOI'}论文: {paper_info[1]}")
yield from update_ui(chatbot=chatbot, history=history)
return
else:
# 检查输入路径
if not os.path.exists(txt):
report_exception(chatbot, history, a=f"解析论文: {txt}", b=f"找不到文件或无权访问: {txt}")
yield from update_ui(chatbot=chatbot, history=history)
return
# 验证路径安全性
user_name = chatbot.get_user()
validate_path_safety(txt, user_name)
# 查找论文文件
paper_file = _find_paper_file(txt)
if not paper_file:
report_exception(chatbot, history, a=f"解析论文", b=f"在路径 {txt} 中未找到支持的论文文件")
yield from update_ui(chatbot=chatbot, history=history)
return
yield from update_ui(chatbot=chatbot, history=history)
# 确保paper_file是字符串
if paper_file is not None and not isinstance(paper_file, str):
# 尝试转换为字符串
try:
paper_file = str(paper_file)
except:
report_exception(chatbot, history, a=f"类型错误", b=f"论文路径不是有效的字符串: {type(paper_file)}")
yield from update_ui(chatbot=chatbot, history=history)
return
# 开始推荐
chatbot.append(["开始分析", f"正在分析论文并生成期刊会议推荐: {os.path.basename(paper_file)}"])
yield from update_ui(chatbot=chatbot, history=history)
recommender = JournalConferenceRecommender(llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)
yield from recommender.recommend_venues(paper_file)