# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. import os import re import time import json import matplotlib.pyplot as plt from openai import OpenAI import multiprocessing FONT_SIZE = 20 COLORS = ['#26547c', '#06d6a0', '#ef476f', '#ffd166'] openai_api_key = os.getenv("OPENAI_KEY") # print(openai.api_key) base_dir = '/home/v-qinlinzhao/agent4reviews/simulated_review/reviews' save_base_dir = '/home/v-qinlinzhao/agent4reviews/simulated_review/classified_reason/' with open('iter_prompt.txt', 'r') as f: iter_prompt = f.read() with open('classification_prompt.txt', 'r') as f: classification_prompt = f.read() with open('reason_library.txt', 'r') as f: reason_library = f.read() def get_gpt_response(prompt): client = OpenAI(api_key=openai_api_key) messages = [{'role': 'user', 'content': prompt}] completion = client.chat.completions.create( model="gpt-4-1106-preview", messages=messages, temperature=0.7, max_tokens=2000, ) response = completion.choices[0].message.content response = response.strip() # time.sleep(5) return response def extract_review_from_real_data(): base_dir = '/home/v-qinlinzhao/agent4reviews/real_review/original_data' result_dir = '/home/v-qinlinzhao/agent4reviews/real_review/extracted_real_review/' # 目录为 ICLR202X/notes/xxx.json # 将其中所有的json文件的review提取处理 for root, dirs, files in os.walk(base_dir): for file in files: if file.endswith('.json'): with open(os.path.join(root, file), 'r') as f: data = json.load(f) reviews = [] data = data['details']['replies'] id = [] for d in data: if d['id'] not in id: id.append(d['id']) # 2020-2021 if 'content' in d and 'review' in d['content']: reviews.append(d['content']['review']) # 2022 if 'content' in d and 'main_review' in d['content']: reviews.append(d['content']['main_review']) # 2023 if 'content' in d and 'strength_and_weaknesses' in d['content']: reviews.append(d['content']['strength_and_weaknesses']) # 将每个review分别存入到json文件中,命名格式为 {当前文件名}_{序号}.json # 同时保持每个文件在原目录下相对路径 relative_dir = os.path.relpath(root, base_dir) result_file_dir = os.path.join(result_dir, relative_dir) os.makedirs(result_file_dir, exist_ok=True) file_base_name = os.path.splitext(file)[0] for i, review in enumerate(reviews): result_file_name = f"{file_base_name}_{i}.json" result_file_path = os.path.join(result_file_dir, result_file_name) with open(result_file_path, 'w') as result_file: json.dump({"review": review}, result_file, ensure_ascii=False, indent=4) def extract_meta_review_from_simulated_data(): base_dir = '/home/v-qinlinzhao/agent4reviews/simulated_review/full_paper_discussion' result_dir = '/home/v-qinlinzhao/agent4reviews/simulated_review/meta_review/' # 目录为 ICLR202X/notes/xxx.json # 将其中所有的json文件的review提取处理 for root, dirs, files in os.walk(base_dir): for file in files: if file.endswith('.json'): with open(os.path.join(root, file), 'r') as f: data = json.load(f) # review在data['messages']中最后一个元素中的"content"中 review = data['messages'][-1]['content'] # write review into file, keep the abstract path relative_dir = os.path.relpath(root, base_dir) result_file_dir = os.path.join(result_dir, relative_dir) os.makedirs(result_file_dir, exist_ok=True) result_file_path = os.path.join(result_file_dir, file) with open(result_file_path, 'w') as result_file: json.dump({"meta_review": review}, result_file, ensure_ascii=False, indent=4) # Select 1% of the data randomly, let GPT-4 summarize the reasons, and add them to the reason library if there are reasons that do not exist def construct_reason_library(): base_dir = '/home/v-qinlinzhao/agent4reviews/paper_review_and_rebuttal/selected_files/' json_files = [] for root, dirs, files in os.walk(base_dir): for file in files: if file.endswith('.json'): json_files.append(os.path.join(root, file)) for file in json_files: with open(file, 'r') as f: data = json.load(f) review = data['review'] prompt = iter_prompt.format(review=review, reason_library=reason_library) ans = get_gpt_response(prompt) print(ans) def analyze_reason_in_batch(json_files): for file in json_files: with open(file, 'r') as f: data = json.load(f) review = data['review'] prompt = classification_prompt.format(review=review) res = get_gpt_response(prompt) # 解析res的输出,将accept和reject的原因分别提取出来,写成json格式 # 依据该字符串分别抽取Accept和Reject的原因 reason_dict = {} if 'Reject' in res: accept_reason = re.search(r"Accept: (.+?);", res) else: accept_reason = re.search(r"Accept: (.+)", res) reject_reason = re.search(r"Reject: (.+)", res) # print(reject_reason) if accept_reason: accept_reason = accept_reason.group(1).split(',') reason_dict['accept'] = [] for r in accept_reason: r = r.strip() if r in ['1', '2', '3', '4', '5']: reason_dict['accept'].append(r) if reject_reason: reject_reason = reject_reason.group(1).split(',') reason_dict['reject'] = [] for r in reject_reason: r = r.strip() if r in ['1', '2', '3', '4', '5', '6', '7']: reason_dict['reject'].append(r) # print(res) relative_path = os.path.relpath(file, base_dir) save_path = os.path.join(save_base_dir, relative_path) save_dir = os.path.dirname(save_path) # 首先找到原来目录的目录结构,然后在save_dir中按照该目录保存结果保存结果 if not os.path.exists(save_dir): os.makedirs(save_dir) with open(save_path, 'w') as f: json.dump(reason_dict, f, indent=4) def convert_txt_to_json(): base_dir = '/home/v-qinlinzhao/agent4reviews/simulated_review/classified_meta_review_reason' reason_count = {} reason_total_count = {'accept': {}, 'reject': {}} def process_directory(path, reason_dict): # 迭代path下的内容 for item in os.listdir(path): item_path = os.path.join(path, item) if os.path.isdir(item_path): # 如果是目录,递归处理 reason_dict[item] = {} process_directory(item_path, reason_dict[item]) elif item.endswith('.txt'): # 去除txt后缀 item_name = item.replace('.txt', '') reason_dict[item_name] = {'accept': {}, 'reject': {}} # 如果是txt文件,处理文件内容 with open(item_path, 'r') as f: content = f.read() # "Accept: 1,2,3; Reject: 3,4,7" # 依据该字符串分别抽取Accept和Reject的原因 if 'Reject' in content: accept_reason = re.search(r"Accept: (.+?);", content) else: accept_reason = re.search(r"Accept: (.+)", content) reject_reason = re.search(r"Reject: (.+)", content) # print(reject_reason) if accept_reason: accept_reason = accept_reason.group(1).split(',') reason_dict[item_name]['accept'] = [] for r in accept_reason: r = r.strip() if r in ['1', '2', '3', '4', '5']: if r not in reason_total_count['accept']: reason_total_count['accept'][r] = 0 reason_total_count['accept'][r] += 1 reason_dict[item_name]['accept'].append(r) if reject_reason: reject_reason = reject_reason.group(1).split(',') reason_dict[item_name]['reject'] = [] for r in reject_reason: r = r.strip() if r in ['1', '2', '3', '4', '5', '6', '7']: if r not in reason_total_count['reject']: reason_total_count['reject'][r] = 0 reason_total_count['reject'][r] += 1 reason_dict[item_name]['reject'].append(r) process_directory(base_dir, reason_count) # 将统计结果写入文件 with open('reason.json', 'w') as f: json.dump(reason_count, f, indent=4) # 计算accept 和 reject中每一类原因的占比 # reason_percentage = {'accept': {}, 'reject': {}} # for key, value in reason_total_count.items(): # total = sum(value.values()) # for k, v in value.items(): # reason_percentage[key][k] = v / total # with open('reason_count.json', 'w') as f: # json.dump(reason_total_count, f, indent=4) # with open('reason_percentage.json', 'w') as f: # json.dump(reason_percentage, f, indent=4) def count_reasons(): with open('../reason_result/reason.json', 'r') as f: reason_count = json.load(f) count = {} for year, year_dict in reason_count.items(): count[year] = {} for model, model_dict in year_dict.items(): count[year][model] = {} for type, type_dict in model_dict.items(): count[year][model][type] = {} count[year][model][type]['accept'] = {} count[year][model][type]['reject'] = {} # 只在type层面做统计就好了 for paper_id, paper_id_dict in type_dict.items(): for review_id, review_id_dict in paper_id_dict.items(): print(year, model, type, paper_id, review_id, review_id_dict) # {'accept': {'1': 1, '2': 1, '5': 1}, 'reject': {'3': 1, '4': 1, '5': 1, '7': 1}} if 'accept' in review_id_dict: for accept_reason in review_id_dict['accept']: if accept_reason not in count[year][model][type]['accept'] \ and accept_reason in ['1', '2', '3', '4', '5']: count[year][model][type]['accept'][accept_reason] = 0 count[year][model][type]['accept'][accept_reason] += 1 if 'reject' in review_id_dict: for reject_reason in review_id_dict['reject']: if reject_reason not in count[year][model][type]['reject'] \ and reject_reason in ['1', '2', '3', '4', '5', '6', '7']: count[year][model][type]['reject'][reject_reason] = 0 count[year][model][type]['reject'][reject_reason] += 1 with open('reason_count.json', 'w') as f: json.dump(count, f, indent=4) def calcu_reason_percentage_every_year(): with open('../reason_result/reason_count.json', 'r') as f: reason_count = json.load(f) distribution = {} for year, year_dict in reason_count.items(): distribution[year] = {} for model, model_dict in year_dict.items(): distribution[year][model] = {} for type, type_dict in model_dict.items(): distribution[year][model][type] = {} distribution[year][model][type]['accept'] = {} distribution[year][model][type]['reject'] = {} # 统计百分比,先将accept下面的count加起来,然后得到每个百分比 accept_sum = sum(type_dict['accept'].values()) for reason, count in type_dict['accept'].items(): distribution[year][model][type]['accept'][reason] = count / accept_sum reject_sum = sum(type_dict['reject'].values()) for reason, count in type_dict['reject'].items(): distribution[year][model][type]['reject'][reason] = count / reject_sum with open('reason_percentage.json', 'w') as f: json.dump(distribution, f, indent=4) def calcu_reason_percentage(): # 以每种类别为单位,计算每种类别下的accept和reject的百分比 with open('../reason_result/reason_count.json', 'r') as f: reason_count = json.load(f) count_dict = {} for year, year_dict in reason_count.items(): for model, model_dict in year_dict.items(): for type, type_dict in model_dict.items(): count_dict[type] = {'accept': {}, 'reject': {}} # 得到所有year和model的accept和reject的count accept_count = type_dict['accept'] reject_count = type_dict['reject'] # 将accept中每一类原因进行累加 for reason, count in accept_count.items(): if reason not in count_dict[type]['accept']: count_dict[type]['accept'][reason] = 0 count_dict[type]['accept'][reason] += count for reason, count in reject_count.items(): if reason not in count_dict[type]['reject']: count_dict[type]['reject'][reason] = 0 count_dict[type]['reject'][reason] += count # 计算count_dict中accept和reject其中原因的百分比 reason_percentage = {} for type, type_dict in count_dict.items(): reason_percentage[type] = {'accept': {}, 'reject': {}} accept_sum = sum(type_dict['accept'].values()) for reason, count in type_dict['accept'].items(): reason_percentage[type]['accept'][reason] = count / accept_sum reject_sum = sum(type_dict['reject'].values()) for reason, count in type_dict['reject'].items(): reason_percentage[type]['reject'][reason] = count / reject_sum with open('reason_percentage.json', 'w') as f: json.dump(reason_percentage, f, indent=4) def draw_bar_chart(accept_or_reject, ax, type, name1, name2): # accept_or_reject = 'accept' x = { "accept": ['Novelty', 'Significance', 'Theoretical', 'Clarity', 'Future'], "reject": ['Novelty', 'Theoretical', 'Validation', 'Practicality', 'Limitations', 'Presentation', 'Related Work'] } x_range = range(1, len(x[accept_or_reject])+1) # 画出每一年的type1 和 type2两种type的比例图 with open('../reason_result/reason_percentage.json', 'r') as f: reason_percentage = json.load(f) # 取出其中的type1和type2两种type type1 = reason_percentage[name1][accept_or_reject] type2 = reason_percentage[name2][accept_or_reject] # 按照key排序 type1 = dict(sorted(type1.items(), key=lambda x: int(x[0]))) type2 = dict(sorted(type2.items(), key=lambda x: int(x[0]))) # dict中key应该是1-7,如果有的Key没有,就加上这个key,value设置为0 for i in x_range: if str(i) not in type1: type1[str(i)] = 0 if str(i) not in type2: type2[str(i)] = 0 width = 0.35 # 柱子的宽度 # fig, ax = plt.subplots() ax.bar([i - width/2 for i in x_range], type1.values(), width, label=name1, color=COLORS[0], alpha=0.3) ax.bar([i + width/2 for i in x_range], type2.values(), width, label=name2, color=COLORS[1], alpha=0.3) ax.legend() ax.set_xlabel('Reason', fontsize=FONT_SIZE) # ax.set_ylabel('Percentage', fontsize=FONT_SIZE) ax.set_title(type, fontsize=FONT_SIZE) ax.set_xticks(x_range) # 设置x轴刻度为整数 ax.set_xticklabels(x[accept_or_reject], rotation=30) # plt.savefig(f'reason_distribution_{type}.png') # plt.close() def draw_bar_chart_baseline(ax, baseline_or_ground, accept_or_reject): # if baseline_or_ground == 'Baseline': # with open('../simulated_review/reason_result/reason_percentage.json', 'r') as f: # reason_percentage = json.load(f) # type_data = reason_percentage['BASELINE'][accept_or_reject] # elif baseline_or_ground == 'Ground Truth': with open('reason_percentage.json', 'r') as f: reason_percentage = json.load(f) type_data = reason_percentage[baseline_or_ground][accept_or_reject] x = { "accept": ['Novelty', 'Significance', 'Theoretical', 'Clarity', 'Future'], "reject": ['Novelty', 'Theoretical', 'Validation', 'Practicality', 'Limitations', 'Presentation', 'Related Work'] } x_range = range(1, len(x[accept_or_reject])+1) # 按照key排序 type_data = dict(sorted(type_data.items(), key=lambda x: int(x[0]))) # dict中key应该是1-7,如果有的Key没有,就加上这个key,value设置为0 for i in x_range: if str(i) not in type_data: type_data[str(i)] = 0 # 画图,将单一类型画到图上,选取颜色,设置透明度 width = 0.35 # 柱子的宽度 # fig, ax = plt.subplots() ax.bar(x_range, type_data.values(), width, label=accept_or_reject, color=COLORS[0], alpha=0.7) ax.legend() ax.set_xlabel('Reason', fontsize=FONT_SIZE) # ax.set_ylabel('Percentage', fontsize=FONT_SIZE) ax.set_title(baseline_or_ground, fontsize=FONT_SIZE) ax.set_xticks(x_range) # 设置x轴刻度为整数 ax.set_xticklabels(x[accept_or_reject], rotation=30) # plt.savefig(f'{baseline_or_ground}_{accept_or_reject}_reason_distribution.pdf') # plt.close() def draw_reason_distribution(accept_or_reject): type2name = {'accept': 'Acceptance', 'reject': 'Rejection'} fig, axs = plt.subplots(1, 3, figsize=(15, 5)) fig.suptitle(f'Distribution of {type2name[accept_or_reject]} Reasons', fontsize=FONT_SIZE) # authoritarian_ACx1 inclusive_ACx1 conformist_ACx1 draw_bar_chart_baseline(axs[0], 'authoritarian_ACx1', accept_or_reject) draw_bar_chart_baseline(axs[1], 'inclusive_ACx1', accept_or_reject) draw_bar_chart_baseline(axs[2], 'conformist_ACx1', accept_or_reject) # draw_bar_chart_baseline(axs[0], 'Baseline', accept_or_reject) # draw_bar_chart_baseline(axs[1], 'Ground Truth', accept_or_reject) # for i, (key, value) in enumerate(types.items()): # if i == 3: # break # draw_bar_chart(accept_or_reject, axs[i], key, value[0], value[1]) axs[0].set_ylabel('Percentage', fontsize=FONT_SIZE) plt.tight_layout() plt.savefig(f'reason_distribution_AC_{accept_or_reject}.pdf') plt.close() if __name__ == "__main__": # analysis_pipeline() # convert_txt_to_json() draw_reason_distribution('reject') # if __name__ == "__main__": # # get current path # # print(os.getcwd()) # print("Start analysis...") # json_files = [] # for root, dirs, files in os.walk(base_dir): # for file in files: # if file.endswith('.json'): # json_files.append(os.path.join(root, file)) # # json_files = [f for f in json_files] # # print(json_files) # # 将其平均分为6份,每份分配给一个进程 # n = len(json_files) # n_per_process = n // 6 # processes = [] # for i in range(6): # start = i * n_per_process # end = (i + 1) * n_per_process # if i == 5: # end = n # p = multiprocessing.Process(target=analyze_reason_in_batch, args=(json_files[start:end], )) # processes.append(p) # p.start()