镜像自地址
https://github.com/binary-husky/gpt_academic.git
已同步 2025-12-05 22:16:49 +00:00
* 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>
635 行
30 KiB
Python
635 行
30 KiB
Python
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
|
||
|
||
# 检查输入是否为论文ID(arxiv或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) |