"""
    #################################################################################################################################################################################################
    # This code library is an adaptation of the original Transformers and was designed, developed and programmed by Sapiens Technology®.                                                            #
    # Any alteration and/or disclosure of this code without prior authorization is strictly prohibited and is subject to legal action that will be forwarded by the Sapiens Technology® legal team. #
    # This set of algorithms aims to download, train, fine-tune and/or infer large language models from various sources and slopes.                                                                 #
    #################################################################################################################################################################################################
"""
import inspect
import json
import re
from contextlib import contextmanager
from datetime import datetime
from functools import lru_cache
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, get_args, get_origin, get_type_hints
from packaging import version
from .import_utils import is_jinja_available, is_torch_available, is_vision_available
if is_jinja_available():
    import jinja2
    from jinja2.ext import Extension
    from jinja2.sandbox import ImmutableSandboxedEnvironment
else: jinja2 = None
if is_vision_available(): from PIL.Image import Image
if is_torch_available(): from torch import Tensor
BASIC_TYPES = (int, float, str, bool, Any, type(None), ...)
description_re = re.compile(r"^(.*?)[\n\s]*(Args:|Returns:|Raises:|\Z)", re.DOTALL)
args_re = re.compile(r"\n\s*Args:\n\s*(.*?)[\n\s]*(Returns:|Raises:|\Z)", re.DOTALL)
args_split_re = re.compile(
    r"""
(?:^|\n)
\s*(\w+):\s*
(.*?)\s*
(?=\n\s*\w+:|\Z)
""", re.DOTALL | re.VERBOSE)
returns_re = re.compile(r"\n\s*Returns:\n\s*(.*?)[\n\s]*(Raises:|\Z)", re.DOTALL)
class TypeHintParsingException(Exception): pass
class DocstringParsingException(Exception): pass
def _get_json_schema_type(param_type: str) -> Dict[str, str]:
    type_mapping = {int: {"type": "integer"}, float: {"type": "number"}, str: {"type": "string"}, bool: {"type": "boolean"}, Image: {"type": "image"}, Tensor: {"type": "audio"}, Any: {}}
    return type_mapping.get(param_type, {"type": "object"})
def _parse_type_hint(hint: str) -> Dict:
    origin = get_origin(hint)
    args = get_args(hint)
    if origin is None:
        try: return _get_json_schema_type(hint)
        except KeyError: raise TypeHintParsingException("Couldn't parse this type hint, likely due to a custom class or object: ", hint)
    elif origin is Union:
        subtypes = [_parse_type_hint(t) for t in args if t is not type(None)]
        if len(subtypes) == 1: return_dict = subtypes[0]
        elif all(isinstance(subtype["type"], str) for subtype in subtypes): return_dict = {"type": sorted([subtype["type"] for subtype in subtypes])}
        else: return_dict = {"anyOf": subtypes}
        if type(None) in args: return_dict["nullable"] = True
        return return_dict
    elif origin is list:
        if not args: return {"type": "array"}
        else: return {"type": "array", "items": _parse_type_hint(args[0])}
    elif origin is tuple:
        if not args: return {"type": "array"}
        if len(args) == 1: raise TypeHintParsingException(f"The type hint {str(hint).replace('typing.', '')} is a Tuple with a single element, which we do not automatically convert to JSON schema as it is rarely necessary. If this input can contain more than one element, we recommend using a List[] type instead, or if it really is a single element, remove the Tuple[] wrapper and just pass the element directly.")
        if ... in args: raise TypeHintParsingException("Conversion of '...' is not supported in Tuple type hints. Use List[] types for variable-length inputs instead.")
        return {"type": "array", "prefixItems": [_parse_type_hint(t) for t in args]}
    elif origin is dict:
        out = {"type": "object"}
        if len(args) == 2: out["additionalProperties"] = _parse_type_hint(args[1])
        return out
    raise TypeHintParsingException("Couldn't parse this type hint, likely due to a custom class or object: ", hint)
def _convert_type_hints_to_json_schema(func: Callable) -> Dict:
    type_hints = get_type_hints(func)
    signature = inspect.signature(func)
    required = []
    for param_name, param in signature.parameters.items():
        if param.annotation == inspect.Parameter.empty: raise TypeHintParsingException(f"Argument {param.name} is missing a type hint in function {func.__name__}")
        if param.default == inspect.Parameter.empty: required.append(param_name)
    properties = {}
    for param_name, param_type in type_hints.items(): properties[param_name] = _parse_type_hint(param_type)
    schema = {"type": "object", "properties": properties}
    if required: schema["required"] = required
    return schema
def parse_google_format_docstring(docstring: str) -> Tuple[Optional[str], Optional[Dict], Optional[str]]:
    description_match = description_re.search(docstring)
    args_match = args_re.search(docstring)
    returns_match = returns_re.search(docstring)
    description = description_match.group(1).strip() if description_match else None
    docstring_args = args_match.group(1).strip() if args_match else None
    returns = returns_match.group(1).strip() if returns_match else None
    if docstring_args is not None:
        docstring_args = "\n".join([line for line in docstring_args.split("\n") if line.strip()])
        matches = args_split_re.findall(docstring_args)
        args_dict = {match[0]: re.sub(r"\s*\n+\s*", " ", match[1].strip()) for match in matches}
    else: args_dict = {}
    return description, args_dict, returns
def get_json_schema(func: Callable) -> Dict:
    doc = inspect.getdoc(func)
    if not doc: raise DocstringParsingException(f"Cannot generate JSON schema for {func.__name__} because it has no docstring!")
    doc = doc.strip()
    main_doc, param_descriptions, return_doc = parse_google_format_docstring(doc)
    json_schema = _convert_type_hints_to_json_schema(func)
    if (return_dict := json_schema["properties"].pop("return", None)) is not None:
        if return_doc is not None: return_dict["description"] = return_doc
    for arg, schema in json_schema["properties"].items():
        if arg not in param_descriptions: raise DocstringParsingException(f"Cannot generate JSON schema for {func.__name__} because the docstring has no description for the argument '{arg}'")
        desc = param_descriptions[arg]
        enum_choices = re.search(r"\(choices:\s*(.*?)\)\s*$", desc, flags=re.IGNORECASE)
        if enum_choices:
            schema["enum"] = [c.strip() for c in json.loads(enum_choices.group(1))]
            desc = enum_choices.string[: enum_choices.start()].strip()
        schema["description"] = desc
    output = {"name": func.__name__, "description": main_doc, "parameters": json_schema}
    if return_dict is not None: output["return"] = return_dict
    return {"type": "function", "function": output}
def _render_with_assistant_indices(compiled_template, messages, tools, documents, add_generation_prompt, **template_kwargs):
    rendered_blocks = []
    generation_indices = []
    with compiled_template.environment.activate_tracker(rendered_blocks, generation_indices):
        for block in compiled_template.generate(messages=messages, tools=tools, documents=documents, add_generation_prompt=add_generation_prompt, **template_kwargs): rendered_blocks.append(block)
        rendered_chat = "".join(rendered_blocks)
    return rendered_chat, generation_indices
@lru_cache
def _compile_jinja_template(chat_template):
    class AssistantTracker(Extension):
        tags = {"generation"}
        def __init__(self, environment: ImmutableSandboxedEnvironment):
            super().__init__(environment)
            environment.extend(activate_tracker=self.activate_tracker)
            self._rendered_blocks = None
            self._generation_indices = None
        def parse(self, parser: jinja2.parser.Parser) -> jinja2.nodes.CallBlock:
            lineno = next(parser.stream).lineno
            body = parser.parse_statements(["name:endgeneration"], drop_needle=True)
            return jinja2.nodes.CallBlock(self.call_method("_generation_support"), [], [], body).set_lineno(lineno)
        @jinja2.pass_eval_context
        def _generation_support(self, context: jinja2.nodes.EvalContext, caller: jinja2.runtime.Macro) -> str:
            rv = caller()
            if self.is_active():
                start_index = len("".join(self._rendered_blocks))
                end_index = start_index + len(rv)
                self._generation_indices.append((start_index, end_index))
            return rv
        def is_active(self) -> bool: return self._rendered_blocks or self._generation_indices
        @contextmanager
        def activate_tracker(self, rendered_blocks: List[int], generation_indices: List[int]):
            try:
                if self.is_active(): raise ValueError("AssistantTracker should not be reused before closed")
                self._rendered_blocks = rendered_blocks
                self._generation_indices = generation_indices
                yield
            finally:
                self._rendered_blocks = None
                self._generation_indices = None
    if version.parse(jinja2.__version__) < version.parse("3.1.0"): raise ImportError("apply_chat_template requires jinja2>=3.1.0 to be installed. Your version is " f"{jinja2.__version__}.")
    def raise_exception(message): raise jinja2.exceptions.TemplateError(message)
    def tojson(x, ensure_ascii=False, indent=None, separators=None, sort_keys=False): return json.dumps(x, ensure_ascii=ensure_ascii, indent=indent, separators=separators, sort_keys=sort_keys)
    def strftime_now(format): return datetime.now().strftime(format)
    jinja_env = ImmutableSandboxedEnvironment(trim_blocks=True, lstrip_blocks=True, extensions=[AssistantTracker, jinja2.ext.loopcontrols])
    jinja_env.filters["tojson"] = tojson
    jinja_env.globals["raise_exception"] = raise_exception
    jinja_env.globals["strftime_now"] = strftime_now
    return jinja_env.from_string(chat_template)
"""
    #################################################################################################################################################################################################
    # This code library is an adaptation of the original Transformers and was designed, developed and programmed by Sapiens Technology®.                                                            #
    # Any alteration and/or disclosure of this code without prior authorization is strictly prohibited and is subject to legal action that will be forwarded by the Sapiens Technology® legal team. #
    # This set of algorithms aims to download, train, fine-tune and/or infer large language models from various sources and slopes.                                                                 #
    #################################################################################################################################################################################################
"""
