
from ..base import Parser, RubricLikertScale
import time
from openai import OpenAI

class GPTParser(Parser):
    """
    Abstract base class for parsing model outputs into structured characteristic evaluations.

    Each characteristic maps to a CharacteristicScore with a rating and rationale.
    """
    def __init__(self, openai_key:str, parser_model:str="gpt-4o-mini"):
        self.client = OpenAI(api_key=openai_key)
        self.parser_model = parser_model

    def parse(self, raw_output: str) -> RubricLikertScale:
        """
        Parse the raw model output into structured characteristic evaluations.

        Args:
            raw_output (str): The text generated by the model.

        Returns:
            Dict[str, CharacteristicScore]: Mapping from characteristic name to its score and rationale.
        """
        functions = [
            {
                "name": "evaluate_characteristic",
                "description": "Extracting the exact `rating` and `rationale` from the given text.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "rating": {
                            "type": "number",
                            "description": "A numerical rating assigned to the characteristic in the text.",
                            "minimum": 1,
                            "maximum": 5
                        },
                        "rationale": {
                            "type": "string",
                            "description": "The explanation for the assigned rating."
                        }
                    },
                    "required": ["rating", "rationale"]
                }
            }
        ]
        while True:
            try:
                completion = self.client.chat.completions.create(
                    model=self.parser_model,
                    messages=[{"role": "user", "content": raw_output}],
                    functions=functions
                )
                parsed_output = eval(completion.choices[0].message.function_call.arguments)
                break
            except Exception as e:
                print(f"Error {e}")
                time.sleep(3)

        return RubricLikertScale(rating=parsed_output['rating'], rationale=parsed_output['rationale'])
