学术论文GPT源码解读:从chatpaper、chatwithpaper到gpt_academic

news2024/12/27 13:11:33

前言

之前7月中旬,我曾在微博上说准备做“20个LLM大型项目的源码解读”

针对这个事,目前的最新情况是

  • 已经做了的:LLaMA、Alpaca、ChatGLM-6B、deepspeedchat、transformer、langchain、langchain-chatglm知识库
  • 准备做的:chatpaper、deepspeed、Megatron-LM
  • 再往后则:BERT、GPT、pytorch、chatdoctor、baichuan、BLOOM/BELLE、Chinese LLaMA、PEFT BLIP2 llama.cpp

总之,够未来半年忙了。为加快这个事情的进度,本文解读两个关于学术论文的GPT(由于我司每周都有好几个或为申博、或为评职称、或为毕业而报名论文1V1发表辅导的,比如中文期刊、EI会议、ei期刊/SCI等等,所以对这个方向一直都是高度关注,我司也在做类似的LLM产品,敬请期待)

  • 一个是chatpaper:https://github.com/kaixindelele/ChatPaper
  • 一个是gpt_academic:https://github.com/binary-husky/gpt_academic

我把这两个项目的结构做了拆解/解析,且基本把原有代码的每一行都补上了注释,如果大家对任何一行代码有疑问,可以随时在本文评论区留言,我会及时做补充说明


第一部分 ChatPaper:论文对话、总结、翻译

ChatPaper的自身定位是全流程加速科研:论文总结+专业级翻译+润色+审稿+审稿回复,因为论文更多是PDF的格式,故针对PDF的对话、总结、翻译,便不可避免的涉及到PDF的解析

1.1 ChatPaper/ChatReviewerAndResponse

1.1.1 对PDF的解析:ChatReviewerAndResponse/get_paper.py

// 待更

1.1.2 论文审查:ChatReviewerAndResponse/chat_reviewer.py

使用OpenAI的GPT模型进行论文审查的脚本。它首先定义了一个Reviewer类来处理审查工作,然后在if __name__ == '__main__':语句下使用argparse处理命令行参数,并调用chat_reviewer_main函数来开始审查过程

  • 导入模块:与第一段代码相似,但新增了一些库,如jieba、tenacity等
  • 命名元组定义:用于保存与论文审稿相关的参数
    ReviewerParams = namedtuple(
        "ReviewerParams",
        [
            "paper_path",
            "file_format",
            "research_fields",
            "language"
        ],
    )
  • 判断文本中是否包含中文:
    def contains_chinese(text):
        for ch in text:
            if u'\u4e00' <= ch <= u'\u9fff':
                return True
        return False
  • 插入句子到文本
    主要功能是在给定文本的每隔一定数量的单词或中文字符后插入一个指定的句子。如果文本行包含中文字符,则使用jieba分词工具来切分中文,否则使用空格来切分:
    def insert_sentence(text, sentence, interval):
        # 将输入文本按换行符分割成行
        lines = text.split('\n')
        # 初始化一个新的行列表
        new_lines = []
    
        # 遍历每一行
        for line in lines:
            # 检查行中是否包含中文字符
            if contains_chinese(line):
                # 如果是中文,使用jieba分词工具进行分词
                words = list(jieba.cut(line))
                # 定义分隔符为空字符(对于中文分词)
                separator = ''
            else:
                # 如果不包含中文,按空格分割行
                words = line.split()
                # 定义分隔符为空格(对于英文或其他非中文语言)
                separator = ' '
    
            # 初始化一个新的单词列表
            new_words = []
            # 初始化一个计数器
            count = 0
    
            # 遍历当前行的每一个单词
            for word in words:
                # 将当前单词添加到新的单词列表
                new_words.append(word)
                # 计数器增加
                count += 1
    
                # 检查是否达到了插入句子的间隔
                if count % interval == 0:
                    # 在达到指定间隔时,将要插入的句子添加到新的单词列表
                    new_words.append(sentence)
    
            # 将新的单词列表连接起来,并添加到新的行列表
            new_lines.append(separator.join(new_words))
    
        # 将新的行列表连接起来,返回结果
        return '\n'.join(new_lines)
  • 论文审稿类:定义了一个Reviewer类,包含以下功能:
    \rightarrow  第一阶段审稿:先是基于论文标题和摘要,选择要审稿的部分
    # 定义Reviewer类
    class Reviewer:
        # 初始化方法,设置属性
        def __init__(self, args=None):
            if args.language == 'en':
                self.language = 'English'
            elif args.language == 'zh':
                self.language = 'Chinese'
            else:
                self.language = 'Chinese'        
            # 创建一个ConfigParser对象
            self.config = configparser.ConfigParser()
            # 读取配置文件
            self.config.read('apikey.ini')
            # 获取某个键对应的值        
            self.chat_api_list = self.config.get('OpenAI', 'OPENAI_API_KEYS')[1:-1].replace('\'', '').split(',')
            self.chat_api_list = [api.strip() for api in self.chat_api_list if len(api) > 5]
            self.cur_api = 0
            self.file_format = args.file_format        
            self.max_token_num = 4096
            self.encoding = tiktoken.get_encoding("gpt2")
        
        def validateTitle(self, title):
            # 修正论文的路径格式
            rstr = r"[\/\\\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
            new_title = re.sub(rstr, "_", title) # 替换为下划线
            return new_title
    然后分别实现两个函数
    一个stage_1主要功能是为了与GPT-3模型进行对话,获取模型对于文章的两个最关键部分的选择意见
    def stage_1(self, paper):
        # 初始化一个空列表,用于存储生成的HTML内容
        htmls = []
        
        # 初始化一个空字符串,用于存储文章的标题和摘要
        text = ''
        # 添加文章的标题
        text += 'Title: ' + paper.title + '. '
        # 添加文章的摘要
        text += 'Abstract: ' + paper.section_texts['Abstract']
        
        # 计算文本的token数量
        text_token = len(self.encoding.encode(text))
        # 判断token数量是否超过最大token限制的一半减去800
        if text_token > self.max_token_num/2 - 800:
            input_text_index = int(len(text)*((self.max_token_num/2)-800)/text_token)
            # 如果超出,则截取文本以满足长度要求
            text = text[:input_text_index]
        
        # 设置OpenAI API的密钥
        openai.api_key = self.chat_api_list[self.cur_api]
        # 更新当前使用的API索引
        self.cur_api += 1
        # 如果当前API索引超过API列表的长度,则重置为0
        self.cur_api = 0 if self.cur_api >= len(self.chat_api_list)-1 else self.cur_api
        
        # 创建与GPT-3的对话消息
        messages = [
            {"role": "system",
             "content": f"You are a professional reviewer in the field of {args.research_fields}. "
                        f"I will give you a paper. You need to review this paper and discuss the novelty and originality of ideas, correctness, clarity, the significance of results, potential impact and quality of the presentation. "
                        f"Due to the length limitations, I am only allowed to provide you the abstract, introduction, conclusion and at most two sections of this paper."
                        f"Now I will give you the title and abstract and the headings of potential sections. "
                        f"You need to reply at most two headings. Then I will further provide you the full information, includes aforementioned sections and at most two sections you called for.\n\n"
                        f"Title: {paper.title}\n\n"
                        f"Abstract: {paper.section_texts['Abstract']}\n\n"
                        f"Potential Sections: {paper.section_names[2:-1]}\n\n"
                        f"Follow the following format to output your choice of sections:"
                        f"{{chosen section 1}}, {{chosen section 2}}\n\n"},
            {"role": "user", "content": text},
        ]
        
        # 调用OpenAI API与GPT-3进行对话
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=messages,
        )
        
        # 初始化一个空字符串,用于存储模型的回复
        result = ''
        # 遍历模型的回复,将其添加到结果字符串中
        for choice in response.choices:
            result += choice.message.content
        # 打印模型的回复
        print(result)
        
        # 返回模型的回复,将其分割为多个部分
        return result.split(',')
    一个chat_review,主要功能是调用GPT-3模型进行论文审稿,对输入的文章文本进行审查,并按照预定格式生成审稿意见
    def chat_review(self, text):
        # 设置OpenAI API的密钥
        openai.api_key = self.chat_api_list[self.cur_api]
        
        # 更新当前使用的API密钥索引
        self.cur_api += 1
        # 如果当前API密钥索引超过API密钥列表的长度,则将其重置为0
        self.cur_api = 0 if self.cur_api >= len(self.chat_api_list)-1 else self.cur_api
    
        # 定义用于审稿提示的token数量
        review_prompt_token = 1000
        
        # 计算输入文本的token数量
        text_token = len(self.encoding.encode(text))
        # 计算输入文本的截取位置
        input_text_index = int(len(text)*(self.max_token_num-review_prompt_token)/text_token)
        # 截取文本并添加前缀
        input_text = "This is the paper for your review:" + text[:input_text_index]
        
        # 从'ReviewFormat.txt'文件中读取审稿格式
        with open('ReviewFormat.txt', 'r') as file:
            review_format = file.read()
        
        # 创建与GPT-3的对话消息
        messages=[
            {"role": "system", 
             "content": "You are a professional reviewer in the field of "+args.research_fields+". Now I will give you a paper. You need to give a complete review opinion according to the following requirements and format:"+ review_format +" Please answer in {}.".format(self.language)},
            {"role": "user", "content": input_text},
        ]
        
        # 调用OpenAI API与GPT-3进行对话
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=messages,
        )
        
        # 初始化一个空字符串,用于存储模型的回复
        result = ''
        # 遍历模型的回复,将其添加到结果字符串中
        for choice in response.choices:
            result += choice.message.content
    
        # 在结果中插入特定的句子,警告不允许复制
        result = insert_sentence(result, '**Generated by ChatGPT, no copying allowed!**', 15)
        # 追加伦理声明
        result += "\n\n⚠伦理声明/Ethics statement:\n--禁止直接复制生成的评论用于任何论文审稿工作!\n--Direct copying of generated comments for any paper review work is prohibited!"
        
        # 打印分隔符和结果
        print("********"*10)
        print(result)
        print("********"*10)
        # 打印相关的token使用信息和响应时间
        print("prompt_token_used:", response.usage.prompt_tokens)
        print("completion_token_used:", response.usage.completion_tokens)
        print("total_token_used:", response.usage.total_tokens)
        print("response_time:", response.response_ms/1000.0, 's')
        
        # 返回模型生成的审稿意见
        return result  
    \rightarrow  使用ChatGPT进行审稿,且有tenacity重试机制和更多的功能,其中review_by_chatgpt 调用了上面所示的两个函数,一个stage_1,一个chat_review
    def review_by_chatgpt(self, paper_list):
        # 创建一个空列表用于存储每篇文章审稿后的HTML格式内容
        htmls = []
        
        # 遍历paper_list中的每一篇文章
        for paper_index, paper in enumerate(paper_list):
            # 使用第一阶段审稿方法选择文章的关键部分
            sections_of_interest = self.stage_1(paper)
            
            # 初始化一个空字符串用于提取文章的主要部分
            text = ''
            # 添加文章的标题
            text += 'Title:' + paper.title + '. '
            # 添加文章的摘要
            text += 'Abstract: ' + paper.section_texts['Abstract']
            
            # 查找并添加“Introduction”部分
            intro_title = next((item for item in paper.section_names if 'ntroduction' in item.lower()), None)
            if intro_title is not None:
                text += 'Introduction: ' + paper.section_texts[intro_title]
            
            # 同样地,查找并添加“Conclusion”部分
            conclusion_title = next((item for item in paper.section_names if 'onclusion' in item), None)
            if conclusion_title is not None:
                text += 'Conclusion: ' + paper.section_texts[conclusion_title]
            
            # 遍历sections_of_interest,添加其他感兴趣的部分
            for heading in sections_of_interest:
                if heading in paper.section_names:
                    text += heading + ': ' + paper.section_texts[heading]
            
            # 使用ChatGPT进行审稿,并得到审稿内容
            chat_review_text = self.chat_review(text=text)
            
            # 将审稿的文章编号和内容添加到htmls列表中
            htmls.append('## Paper:' + str(paper_index+1))
            htmls.append('\n\n\n')
            htmls.append(chat_review_text)
            
            # 获取当前日期和时间,并转换为字符串格式
            date_str = str(datetime.datetime.now())[:13].replace(' ', '-')
            try:
                # 创建输出文件夹
                export_path = os.path.join('./', 'output_file')
                os.makedirs(export_path)
            except:
                # 如果文件夹已存在,则不执行任何操作
                pass
            
            # 如果是第一篇文章,则写模式为'w',否则为'a'
            mode = 'w' if paper_index == 0 else 'a'
            
            # 根据文章标题和日期生成文件名
            file_name = os.path.join(export_path, date_str+'-'+self.validateTitle(paper.title)+"."+self.file_format)
            
            # 将审稿内容导出为Markdown格式并保存
            self.export_to_markdown("\n".join(htmls), file_name=file_name, mode=mode)
            
            # 清空htmls列表,为下一篇文章做准备
            htmls = []
  • 主程序部分:
    定义了一个chat_reviewer_main 函数,该函数创建了一个Reviewer对象,并对指定路径中的PDF文件进行审稿
    def chat_reviewer_main(args):            
    
        reviewer1 = Reviewer(args=args)
        # 开始判断是路径还是文件:   
        paper_list = []     
        if args.paper_path.endswith(".pdf"):
            paper_list.append(Paper(path=args.paper_path))            
        else:
            for root, dirs, files in os.walk(args.paper_path):
                print("root:", root, "dirs:", dirs, 'files:', files) #当前目录路径
                for filename in files:
                    # 如果找到PDF文件,则将其复制到目标文件夹中
                    if filename.endswith(".pdf"):
                        paper_list.append(Paper(path=os.path.join(root, filename)))        
        print("------------------paper_num: {}------------------".format(len(paper_list)))        
        [print(paper_index, paper_name.path.split('\\')[-1]) for paper_index, paper_name in enumerate(paper_list)]
        reviewer1.review_by_chatgpt(paper_list=paper_list)
    主程序中定义了命令行参数解析,并调用了chat_reviewer_main 函数
    在主程序中增加了审稿时间的计算功能
    if __name__ == '__main__':    
        parser = argparse.ArgumentParser()
        parser.add_argument("--paper_path", type=str, default='', help="path of papers")
        parser.add_argument("--file_format", type=str, default='txt', help="output file format")
        parser.add_argument("--research_fields", type=str, default='computer science, artificial intelligence and reinforcement learning', help="the research fields of paper")
        parser.add_argument("--language", type=str, default='en', help="output lauguage, en or zh")
        
        reviewer_args = ReviewerParams(**vars(parser.parse_args()))
        start_time = time.time()
        chat_reviewer_main(args=reviewer_args)
        print("review time:", time.time() - start_time)

// 待更

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/868510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

b站如何调整视频播放倍速3倍

b站pc网页端目前最大倍速为2倍&#xff0c;可以手动调节倍速的一个办法 视频页面-按下f12-点击console-复制粘贴代码-按下enter回车键 下面是代码&#xff0c;3可以换成自己想要的倍速&#xff0c;最大可以16倍速 document. querySelector(video).playbackRate3

C++笔记之静态成员函数的使用场景

C笔记之静态成员函数的使用场景 C静态成员函数的核心特点是不与特定类实例相关&#xff0c;可通过类名直接调用&#xff0c;用于执行与类相关的操作而无需创建类对象。其主要用途是在类级别上共享功能&#xff0c;管理全局状态或提供工具函数。 code review! 文章目录 C笔记之…

移远RM500U-CN模块直连嵌入式ubuntu实现拨号上网

目录 1 平台&#xff1a; 2 需要准备的资料 3 参考文档 4 编译环境与驱动移植 4.1 内核驱动添加厂家ID和产品ID 4. 2.添加零包处理 4.3 增加复位恢复机制 4.4 增加批量输出 批量输出 URB 的数量和容量 的数量和容量 4.5 内核配置与编译 5 QM500U-CN拨号&#xff08;在开…

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速 说明 Tensorflow-GPU 已被移除。请安装 tensorflow 。 tensorflow 通过 Nvidia CUDA 支持 GPU 加速操作。 自 2019 年 9月发布 的 TensorFlow2.1 以来&#xff0c;tensorFlow 和 tensorflow-GPU 一直是同…

NFT Insider#102:The Sandbox重新上线LAND桥接服务,YGG加入Base生态

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members(https://twitter.com/WHALEMembers)、BeepCrypto&#xff08;https://twitter.com/beep_crypto&#xff09;联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周…

【JVM】类装载的执行过程

文章目录 类装载的执行过程1.加载2.验证3.准备4.解析5.初始化6.使用7.卸载 类装载的执行过程 类装载总共分为7个过程&#xff0c;分别是 加载&#xff0c;验证&#xff0c;准备、解析、初始化、使用、卸载 1.加载 将类的字节码文件加载到内存(元空间&#xff09;中。这一步会…

实时时钟+闹钟

在江科大实时时钟的基础上添加闹钟的配置&#xff0c;参考http://t.csdn.cn/YDlYy。 实现功能 &#xff1a;每隔time秒蜂鸣器响一次、设置闹钟的年月日时分秒&#xff0c;到时间蜂鸣器响。 前三个函数没有变&#xff0c;添加 void RTC_AlarmInit(void) 闹钟的中断配置void…

分享Python技术下AutojsPro7云控代码

引言 有图有真相&#xff0c;那短视频就更是真相了。下面是三大语言的短视频。 Java源码版云控示例&#xff1a; Java源码版云控示例在线视频 Net源码版云控示例&#xff1a; Net源码版云控示例在线视频亚丁号-知识付费平台 支付后可见 扫码付费可见 Python源码版云控示例…

STM32CubeMX之freeRTOS消息通知(有点全能)

任务通知是任务自带的程序&#xff0c;不需要单独去创建 一&#xff1a; 二&#xff1a; 进入前不清除数据&#xff0c;退出清除数据参数 0x0000000000 0xffffffff的意思 三&#xff1a; 这里就是发送过去&#xff0c;然后把其存到了num中 不要有太多疑问&#xff0c;并不是发…

【Linux】TCP协议简介

TCP协议简介 TCP协议格式面向连接1.连接管理机制2.包序管理 可靠传输1.保证数据可靠到达对端2.保证数据的传输效率 面向字节流&#xff34;&#xff23;&#xff30;粘包问题 TCP协议格式 16位源端口号和16位目的端口号&#xff1a;标识数据从哪个进程来&#xff0c;到哪个进程…

阿里云Windows服务器安装部署MySQL数据库流程

阿里云百科分享如何在Windows系统ECS实例上手动部署MySQL数据库。 目录 前提条件 操作步骤 前提条件 使用本教程进行操作前&#xff0c;请确保您已经注册了阿里云账号。如还未注册&#xff0c;请先完成账号注册。操作系统&#xff1a;Windows Server 2012准备一台ECS云服务…

JDK、JRE、JVM:揭秘Java的关键三者关系

文章目录 JDK&#xff1a;Java开发工具包JRE&#xff1a;Java运行环境JVM&#xff1a;Java虚拟机关系概述 案例示例&#xff1a;Hello World结语 在Java世界中&#xff0c;你可能经常听到JDK、JRE和JVM这几个概念&#xff0c;它们分别代表了Java开发工具包、Java运行环境和Java…

计算机丢失msvcr71.dll解决办法,总结三个常见的解决方法

修复msvcr71.dll文件的过程中&#xff0c;我对系统动态链接库文件的重要性有了更深入的了解。这个文件对于许多使用Visual C编译的软件来说是必不可少的&#xff0c;缺失或损坏可能导致软件无法正常运行。因此&#xff0c;当遇到类似问题时&#xff0c;及时解决并修复这个文件是…

页面文件太小,无法完成操作。

1、右键“我的电脑”&#xff0c;选择“属性”&#xff1b; 2、点击“高级系统设置”&#xff1b; 3、点击“高级”&#xff0c;再点击“设置”&#xff1b; 4、选择“高级”&#xff0c;选择“程序”&#xff0c;点击“更改”&#xff1b; 5、 不要勾选“自动管理所有驱动器…

Spring Boot+Mybatis实现增删改查接口开发+测试(超详细建议收藏)

前言 Java也是测试必知必会的内容&#xff0c;特别是现在类似spring boot 等Java框架更是成为主流。之前实现的图书增删改查是用Python实现的&#xff0c;没看过的请移步&#xff1a;Flaskmysql 实现增删改查接口开发测试&#xff08;图文教程附源码&#xff09;&#xff0c;本…

教你如何使用AES对接口参数进行加密

教你如何使用AES对接口参数进行加密 前言 我们作为程序猿&#xff0c;在浏览网站的时候偶尔也会打开控制台看看请求的接口&#xff0c;我们会发现有些接口的传输是 “乱码” &#xff0c;那么这个乱码究竟是什么呢&#xff1f;为什么要这么做&#xff1f; 其实这个所谓的 “…

无涯教程-Perl - qq函数

描述 可以使用此函数代替双引号。这实际上不是一个函数,更像是一个运算符,但是如果您在其他程序员的程序中看到它却不记得它是什么,那么可能会在这里看。实际上,您可以使用任何一组定界符,而不仅仅是括号。 语法 以下是此函数的简单语法- qq ( string )返回值 该函数返回双…

De Bruijin序列与魔术(三)——De Bruijin序列的拓展思考

早点关注我&#xff0c;精彩不错过&#xff01; 在前面的文章中&#xff0c;我们已经介绍完经典DeBruijin序列的原理和魔术&#xff0c;相关内容请戳&#xff1a; De Bruijin序列与魔术&#xff08;二&#xff09;——魔术《De Bruijin序列》 De Bruijin序列与魔术&#xff08;…

Chord diagram | 啧啧啧!~人人必会的Chord diagram你不来学一学吗!?

1写在前面 啊啊啊啊啊&#xff01;&#xff01;&#xff01;&#xff01;~终于值完夜班休息了。&#x1f62d; 最近是大搞医疗反腐的日子&#xff0c;㊗️各位执法人员成绩满满&#xff01;~&#x1f912; 听说以后医务人员要年薪制了&#xff0c;完全搞不懂这些东西的初衷和理…

七夕好物分享,哪些礼物适合送男/女朋友?这几款好物最为合适!

七夕是个值得纪念的日子&#xff0c;牛郎织女鹊桥相会的故事百年流传&#xff0c;七夕是一个表达爱意的节日&#xff0c;送礼物是必不可少的&#xff0c;情侣们可以选择一份有意义的礼物&#xff0c;也可以选择对方需要的东西当做礼物来赠送&#xff0c;总的来说&#xff0c;送…