from textwrap import dedent
from typing import Optional

from judges.base import BaseJudge, Judgment

class EmotionQueenImplicitEmotionRecognition(BaseJudge):
    r"""
    A judge that evaluates the response of a model based on its ability to recognize implicit emotions in a statement, using a 3-point scale.

    Citation:
    ---------
    @misc{chen2024emotionqueenbenchmarkevaluatingempathy,
        title={EmotionQueen: A Benchmark for Evaluating Empathy of Large Language Models}, 
        author={Yuyan Chen and Hao Wang and Songzhou Yan and Sijia Liu and Yueze Li and Yi Zhao and Yanghua Xiao},
        year={2024},
        eprint={2409.13359},
        archivePrefix={arXiv},
        primaryClass={cs.CL},
        url={https://arxiv.org/abs/2409.13359}, 
    }

    Models used in paper:
    ---------------------
    Claude 2, Llama 2 70B, BLOOM 176B, GPT4, Vicuna 33B, Falcon 180B, Llama 2 70B, Vicuna 7B, GPT 3.5, Falcon 7B, BLOOM 7B.

    NOTE:
    -----
    The formatting of the prompt used in the paper is not clear on whether it's one sentence per line or all on one line, and there is no repository provided.
    One sentence per line is used here for readability.
    """
    
    def judge(
        self,
        input: str,
        output: Optional[str] = None,
        expected: Optional[str] = None,
    ) -> Judgment:
        """
        Judge the input and return a verdict. 
        """
        system_prompt = None
        user_prompt = dedent(f"""
        Below is a statement, containing a significant event and some trivial event, and a reply generated by a language model. 
        You need to score the reply. 
        First, decide whether the reply succeeds in recognizing both events. 
        Second, decide whether the reply gives a balanced response, which means the length and intensity of emotion for each event should not fall too apart. 
        If the reply is a balanced one, give a 2. 
        If it only recognizes both events but pays too little attention to one, give a 1. 
        If it completely fails, 0.

        Statement: {input}
        Reply: {output}
        Score:
        """
        )
        reasoning, score = self._judge(user_prompt=user_prompt, system_prompt=system_prompt)
        return Judgment(reasoning=reasoning, score=score)


class EmotionQueenIntentionRecognition(BaseJudge):
    r"""
    A judge that evaluates the response of a model based on its ability to recognize the hidden intention in a statement, using a 3-point scale.

    Citation:
    ---------
    @misc{chen2024emotionqueenbenchmarkevaluatingempathy,
        title={EmotionQueen: A Benchmark for Evaluating Empathy of Large Language Models}, 
        author={Yuyan Chen and Hao Wang and Songzhou Yan and Sijia Liu and Yueze Li and Yi Zhao and Yanghua Xiao},
        year={2024},
        eprint={2409.13359},
        archivePrefix={arXiv},
        primaryClass={cs.CL},
        url={https://arxiv.org/abs/2409.13359}, 
    }

    Models used in paper:
    ---------------------
    Claude 2, Llama 2 70B, BLOOM 176B, GPT4, Vicuna 33B, Falcon 180B, Llama 2 70B, Vicuna 7B, GPT 3.5, Falcon 7B, BLOOM 7B.

    NOTE:
    -----
    The formatting of the prompt used in the paper is not clear on whether it's one sentence per line or all on one line, and there is no repository provided.
    One sentence per line is used here for readability, along with lines for the statement and reply.
    """
    
    def judge(
        self,
        input: str,
        output: Optional[str] = None,
        expected: Optional[str] = None,
    ) -> Judgment:
        """
        Judge the input and return a verdict. 
        """
        system_prompt = None
        user_prompt = dedent(f"""
        Below is a statement, containing some hidden intention, and a reply generated by a language model. 
        You need to score the reply. 
        If it offers useful suggestions or shows willingness to help, give a 2. 
        If it only recognizes the hidden intention but is not really helpful, give a 1. 
        If it fails completely, 0.

        Statement: {input}
        Reply: {output}
        Score:
        """
        )
        reasoning, score = self._judge(user_prompt=user_prompt, system_prompt=system_prompt)
        return Judgment(reasoning=reasoning, score=score)


class EmotionQueenKeyEventRecognition(BaseJudge):
    r"""
    A judge that evaluates the response of a model based on its ability to recognize the key event in a statement, using a 3-point scale.

    Citation:
    ---------
    @misc{chen2024emotionqueenbenchmarkevaluatingempathy,
        title={EmotionQueen: A Benchmark for Evaluating Empathy of Large Language Models}, 
        author={Yuyan Chen and Hao Wang and Songzhou Yan and Sijia Liu and Yueze Li and Yi Zhao and Yanghua Xiao},
        year={2024},
        eprint={2409.13359},
        archivePrefix={arXiv},
        primaryClass={cs.CL},
        url={https://arxiv.org/abs/2409.13359}, 
    }

    Models used in paper:
    ---------------------
    Claude 2, Llama 2 70B, BLOOM 176B, GPT4, Vicuna 33B, Falcon 180B, Llama 2 70B, Vicuna 7B, GPT 3.5, Falcon 7B, BLOOM 7B.

    NOTE:
    -----
    The formatting of the prompt used in the paper is not clear on whether it's one sentence per line or all on one line, and there is no repository provided.
    One sentence per line is used here for readability, along with lines for the statement and reply.
    """
    
    def judge(
        self,
        input: str,
        output: Optional[str] = None,
        expected: Optional[str] = None,
    ) -> Judgment:
        """
        Judge the input and return a verdict. 
        """
        system_prompt = None
        user_prompt = dedent(f"""
        Below is a statement, containing a significant event and some trivial event, and a reply generated by a language model. 
        You need to score the reply. 
        First, decide whether the reply succeeds in recognizing both events.
        Second, decide whether the reply gives a balanced response, which means the length and intensity of emotion for each event should not fall too
        apart. 
        If the reply is a balanced one, give a 2. 
        If it only recognizes both events but pays too little attention to one, give a 1. 
        If it completely fails, 0.

        Statement: {input}
        Reply: {output}
        Score:
        """
        )
        reasoning, score = self._judge(user_prompt=user_prompt, system_prompt=system_prompt)
        return Judgment(reasoning=reasoning, score=score)


class EmotionQueenMixedEventRecognition(BaseJudge):
    r"""
    A judge that evaluates the response of a model based on its ability to recognize both the significant and trivial events in a statement, using a 3-point scale.

    Citation:
    ---------
    @misc{chen2024emotionqueenbenchmarkevaluatingempathy,
        title={EmotionQueen: A Benchmark for Evaluating Empathy of Large Language Models}, 
        author={Yuyan Chen and Hao Wang and Songzhou Yan and Sijia Liu and Yueze Li and Yi Zhao and Yanghua Xiao},
        year={2024},
        eprint={2409.13359},
        archivePrefix={arXiv},
        primaryClass={cs.CL},
        url={https://arxiv.org/abs/2409.13359}, 
    }

    Models used in paper:
    ---------------------
    Claude 2, Llama 2 70B, BLOOM 176B, GPT4, Vicuna 33B, Falcon 180B, Llama 2 70B, Vicuna 7B, GPT 3.5, Falcon 7B, BLOOM 7B.

    NOTE:
    -----
    The formatting of the prompt used in the paper is not clear on whether it's one sentence per line or all on one line, and there is no repository provided.
    One sentence per line is used here for readability, along with lines for the statement and reply.
    """
    
    def judge(
        self,
        input: str,
        output: Optional[str] = None,
        expected: Optional[str] = None,
    ) -> Judgment:
        """
        Judge the input and return a verdict. 
        """
        system_prompt = None
        user_prompt = dedent(f"""
        Below is a statement containing a significant event and some trivial event, and a reply generated by a language model. 
        Decide whether the reply succeeds in recognizing the significant event, and whether it responds properly (politeness, helpfulness, etc.) 
        If it is a proper response, give a 2. 
        If it only recognizes the significant event, give a 1. 
        If it fails completely, 0."

        Statement: {input}
        Reply: {output}
        Score:
        """
        )
        reasoning, score = self._judge(user_prompt=user_prompt, system_prompt=system_prompt)
        return Judgment(reasoning=reasoning, score=score)
