import pandas as pd
from openai import OpenAI


import argparse
def getParser():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model', type=str, default='deepseek-chat', help='model name')
    parser.add_argument('--field', type=str, default='API', help='intent field')
    args = parser.parse_args()
    return args

# 构建 ChatGPT 的提示语 prompt（含多种任务类型的评分模板）
def getInstruction(field,input_question,gpt4_answer,test_answer):
    # 定义不同意图的评分维度及评价方式的字典
    prompt_dict={"Leisure":'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[休闲娱乐]，因此你需要从下面的5个维度对回答进行评估:
    1 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    2 趣味性 (Engagement)
    回答是否有趣、吸引人，帮助用户放松，提供了高质量的情绪价值或娱乐价值等
    3 适宜性 (Appropriateness)
    内容适宜所有用户，避免不当或冒犯性内容
    4 创造性 (Creativity)
    是否具有创新性或独特性，是否提供了新颖的见解或解决方法
    5 事实正确性 (Factuality)
    回答中提供的信息是否准确无误，是否基于可信的事实和数据
    注意，不要让回答的长度影响你的打分！回答不是越长越好，简洁并且满足上述要求的回答是好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分的情况下，才能得9到10分。
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{{'满足用户需求': 6, '趣味性': 8..., '综合得分': 7}}。
    用户的提问：''',
    'Factual_QA':'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[信息检索]，因此你需要从下面的5个维度对回答进行评估:
    1 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    2 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    3 清晰度 (Clarity)
    回答是否表达清晰易懂，是否使用了简洁的语言和结构，以便用户可以轻松理解
    4 完备性 (Completeness)
    回答是否提供了足够的信息和细节，以满足用户的需求，是否遗漏了重要的方面
    5 逻辑连贯性(Logical Coherence)
    回答是否在整体上保持一致，是否在不同部分之间保持逻辑连贯性，避免了自相矛盾
    注意，不要让回答的长度影响你的打分！回答不是越长越好，简洁并且满足上述要求的回答是好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分的情况下，才能得9到10分。
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{{'事实正确性': 6, '满足用户需求': 8..., '综合得分': 7}}。
    用户的提问：''',
    'Seek_Creativity':'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[给出创意]，因此你需要从下面的5个维度对回答进行评估:
    1 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    2 逻辑连贯性(Logical Coherence)
    回答是否在整体上保持一致，是否在不同部分之间保持逻辑连贯性，避免了自相矛盾
    3 创造性(Creativity)
    是否具有创新性或独特性，是否提供了新颖的见解或解决方法
    4 丰富度(Richness)
    是否包含丰富的信息、深度、上下文考虑、多样性、详细解释和实例，以满足用户需求并提供全面理解
    5 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    注意，不要让回答的长度影响你的打分！回答不是越长越好，简洁并且满足上述要求的回答是好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分的情况下，才能得9到10分。
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{{'满足用户需求': 6, '逻辑连贯性': 8..., '综合得分': 7}}。
    用户的提问：''',
    'Ask_for_Advice':'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[给出建议]，因此你需要从下面的5个维度对回答进行评估:
    1 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    2 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    3 公平与可负责程度(Fairness and Responsibility)
    回答中提供的建议或信息是否可行，是否负有一定的责任，是否考虑了潜在风险和后果。
    4 创造性(Creativity)
    是否具有创新性或独特性，是否提供了新颖的见解或解决方法
    5 丰富度(Richness)
    是否包含丰富的信息、深度、上下文考虑、多样性、详细解释和实例，以满足用户需求并提供全面理解
    注意，不要让回答的长度影响你的打分！回答不是越长越好，简洁并且满足上述要求的回答是好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分的情况下，才能得9到10分。
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{{'满足用户需求': 6, '事实正确性': 8..., '综合得分': 7}}。
    用户的提问：''',
    'Solve_Professional_Problem':'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[解决专业问题]，因此你需要从下面的5个维度对回答进行评估: 
    1 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    2 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    3 清晰度(Clarity)
    是否表达清晰易懂，是否使用了简洁的语言和结构，以便用户可以轻松理解
    4 逻辑连贯性(Logical Coherence)
    是否在整体上保持一致，是否在不同部分之间保持逻辑连贯性，避免了自相矛盾
    5 完备性(Completeness)
    回答是否提供了足够的信息和细节，以满足用户的需求，是否遗漏了重要的方面
    注意，回答不是越长越好，简短并且满足上述要求的回答是最好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分 的情况下，才能得9到10分。 
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整 数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{’事实正确性’: 9, ’满足用户需求’: 6, ’综合得分’: 7}。
    用户的提问：''',
    "API":'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[解决专业问题]，因此你需要从下面的5个维度对回答进行评估: 
    1 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    2 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    3 清晰度(Clarity)
    是否表达清晰易懂，是否使用了简洁的语言和结构，以便用户可以轻松理解
    4 逻辑连贯性(Logical Coherence)
    是否在整体上保持一致，是否在不同部分之间保持逻辑连贯性，避免了自相矛盾
    5 完备性(Completeness)
    回答是否提供了足够的信息和细节，以满足用户的需求，是否遗漏了重要的方面
    注意，回答不是越长越好，简短并且满足上述要求的回答是最好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分 的情况下，才能得9到10分。 
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整 数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{’事实正确性’: 9, ’满足用户需求’: 6, ’综合得分’: 7}。
    用户的提问：''',
    "Text_Assistant":'''请你以公正的评判者的身份，评估一个AI助手对于用户提问的回答的质量。由于您评估的回答类型是[处理文本事务]，因此你需要从下面的5个维度对回答进行评估: 
    1 清晰度(Clarity)
    是否表达清晰易懂，是否使用了简洁的语言和结构，以便用户可以轻松理解
    2 满足用户需求(User Satisfaction)
    是否满足了用户提出问题的目的和需求，是否对问题进行了全面而恰当的回应
    3 逻辑连贯性(Logical Coherence)
    是否在整体上保持一致，是否在不同部分之间保持逻辑连贯性，避免了自相矛盾
    4 事实正确性(Factuality)
    提供的信息是否准确无误，是否基于可信的事实和数据
    5 创造性(Creativity)
    是否具有创新性或独特性，是否提供了新颖，有文采的内容
    注意，回答不是越长越好，简短并且满足上述要求的回答是最好的。

    我们会给您提供用户的提问，高质量的参考答案，和需要你评估的AI助手的答案。当你开始你的评估时，你需要按照遵守以下的流程：
    1. 将AI助手的答案与参考答案进行比较，指出AI助手的答案有哪些不足，并进一步解释。
    2. 从不同维度对AI助手的答案进行评价，在每个维度的评价之后，给每一个维度一个1～10的分数。
    3. 最后，综合每个维度的评估，对AI助手的回答给出一个1～10的综合分数。
    4. 你的打分需要尽可能严格，并且要遵守下面的评分规则：总的来说，模型回答的质量越高，则分数越高。
    其中，事实正确性和满足用户需求这两个维度是最重要的，这两个维度的分数主导了最后的综合分数。

    当模型回答存在与问题不相关，或者有本质性的事实错误，或生成了有害内容时，总分必须是1到2分；
    当模型回答没有严重错误而且基本无害，但是质量较低，没有满足用户需求，总分为3到4分；
    当模型回答基本满足用户要求，但是在部分维度上表现较差，质量中等，总分可以得5到6分；
    当模型回答质量与参考答案相近，在所有维度上表现良好，总分得7到8分；
    只有当模型回答质量显著超过参考答案，充分地解决了用户问题和所有需求，并且在所有维度上都接近满分的情况下，才能得9到10分。 
    作为示例，参考答案可以得到8分。

    请记住，你必须在你打分前进行评价和解释。在你对每个维度的解释之后，需要加上对该维度的打分。之后，在你回答的末尾，按照以下字典格式（包括括号）返回你所有的打分结果，并确保你的打分结果是整数： 
    {’维度一’: 打分, ’维度二’: 打分, ..., ’综合得分’: 打分}，例如：{’清晰度’: 9, ’满足用户需求’: 6, ...’综合得分’: 7}。
    用户的提问：'''
    }
    # 获取对应意图类别的评分模板前缀
    # 构建完整的 prompt，包含用户问题、参考答案、测试模型输出
    input_prompt=prompt_dict[field]
    prompt=input_prompt+input_question
    prompt+=f"\n[参考答案开始]\n{gpt4_answer}\n[参考答案结束]\n"
    prompt+=f"[助手的答案开始]\n{test_answer}\n[助手的答案结束]\n"
    # print(prompt)
    return prompt

# 主函数：读取数据、构造prompt、调用OpenAI API、保存结果
def main():
    args=getParser()

    field=args.field # seekCreativity
    ans_path=f"../data/data_all.csv"
    question_tag='question'

    # 读取数据（原始问题+参考答案）
    ans_df=pd.read_csv(ans_path)

    # 根据模型名读取对应模型的回答输出
    # test_model='deepseek-chat'
    # test_model='gpt-3.5-turbo'
    # test_model='glm-4'
    # test_model='spark-3.5'
    # test_model='Baichuan2-Turbo'
    # test_model='qwen-max'
    # test_model='gpt-4-0125-preview'
    test_model=args.model
    test_df=pd.read_csv(f'../data/modelOutput/{field}_{test_model}.csv')
    print(test_model)
    print(field)

    # 空值填充（防止合并失败）
    ans_df.fillna('无',inplace=True)
    test_df.fillna('无',inplace=True)
    # 筛选掉无效问题
    ans_df_v1=ans_df[ans_df[question_tag]!='无']
    test_df_v1=test_df[test_df[question_tag]!='无']
     # 根据问题字段合并数据集，suffix 分别为参考答案和模型回答
    df=pd.merge(ans_df_v1,test_df_v1,on=question_tag,suffixes=['_ans','_test'])
    print('merged df:',len(df))


    client=OpenAI()

     # 初始化或补全评价列
    if 'evaluation' not in df.columns.tolist():
        df['evaluation']=""
    else:
        df.fillna('',inplace=True)

    # 遍历每条问题-答案样本，逐条进行评价
    for index,row in df.iterrows():
        if row['evaluation']!='':
            continue
        # print(index)
        # break
        # 构造 prompt
        INPUT_TEXT=getInstruction(field,row[question_tag],row['reference_ans'],row[test_model])

        try:
            # 调用 OpenAI API 获取评分结果（模型默认为 gpt-4-0125-preview）
            completion = client.chat.completions.create(
                # model="gpt-3.5-turbo",
                # model='gpt-4-1106-preview',
                model='gpt-4-0125-preview',
            messages=[
                # {"role": "system", "content": "You are a poetic assistant, skilled in explaining complex programming concepts with creative flair."},
                {"role": "user", "content": INPUT_TEXT}
            ]
            )
            x=completion.choices[0].message.content
        except Exception as e:
            # 异常处理：输出错误信息并保存当前中间结果
            x="Error!!!!!!\n"+str(e)
            print(x)
            df[[question_tag,'reference_ans',test_model,'evaluation']].to_csv(f'../data/evaluation/{field}_{test_model}_evaluation_tmp.csv',encoding='utf-8-sig')
            return
        # 保存该条评价结果
        df.loc[index,'evaluation']=x
        print(x)
        print('****** ******')
         # 每处理10条中间保存一次
        if index%10==0:
            df[[question_tag,'reference_ans',test_model,'evaluation']].to_csv(f'../data/evaluation/{field}_{test_model}_evaluation_tmp.csv',encoding='utf-8-sig')
    # 所有处理完成后，保存最终的评价结果
    df[[question_tag,'reference_ans',test_model,'evaluation']].to_csv(f'../data/evaluation/{field}_{test_model}_evaluation.csv',encoding='utf-8-sig')


if __name__ == "__main__":
    main()
