Spaces:
Sleeping
Sleeping
| # 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() | |