# coding: utf-8

"""
    Mixpeek API

    This is the Mixpeek API, providing access to various endpoints for data processing and retrieval.

    The version of the OpenAPI document: 1.3.0
    Contact: info@mixpeek.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from mixpeek.models.llm_provider import LLMProvider
from typing import Optional, Set
from typing_extensions import Self

class StageParamsLlmFilter(BaseModel):
    """
    Configuration for delegating filtering decisions to an LLM.  **Stage Category**: FILTER  **Transformation**: N documents → ≤N documents (subset, same schema)  **Purpose**: Produces a subset of input documents using LLM-based reasoning. Use this when filtering criteria are too complex for simple attribute conditions and require semantic understanding, content analysis, or subjective judgment. Output documents have identical schema to input.  **When to Use**:     - After initial FILTER stages for intelligent content filtering     - When filtering criteria involve content understanding (sentiment, topic relevance)     - For subjective filtering (quality, appropriateness, brand alignment)     - When simple attribute filters aren't sufficient (complex policies, nuanced rules)     - To filter multimodal content (images, videos) based on visual criteria     - For dynamic filtering based on natural language criteria  **When NOT to Use**:     - For simple metadata filtering (use attribute_filter - much faster and cheaper)     - For reordering results (use SORT stages)     - For enriching documents (use APPLY stages)     - For aggregating documents (use REDUCE stages)     - When fast response time is critical (LLM calls are slow, 100ms-2s per batch)     - When cost is a major concern (LLM inference costs per document)  **Operational Behavior**:     - Operates on in-memory document results (no database queries)     - Produces subset of documents (removes those not meeting LLM criteria)     - Slow operation (LLM API calls, network latency)     - Processes documents in batches to optimize LLM calls     - Makes HTTP requests to Engine service for LLM inference     - Supports concurrent batching for throughput     - Output schema = Input schema (no schema changes)  **Common Pipeline Position**: FILTER (attribute_filter) → FILTER (this stage) → SORT  **Cost & Performance**:     - Expensive: LLM API costs per document evaluated     - Slow: 100ms-2s per batch depending on LLM and batch size     - Use batch_size to balance throughput vs latency     - Consider filtering with attribute_filter first to reduce LLM calls  Requirements:     - provider: OPTIONAL, LLM provider (openai, google, anthropic). Auto-inferred if not specified.     - model_name: OPTIONAL, specific model name. Uses provider default if not specified.     - criteria: OPTIONAL, natural language filtering description (defaults to empty string)       * If criteria is empty/null, stage is SKIPPED (all documents pass through)       * This saves 100ms-30s when no filtering is needed     - batch_size: OPTIONAL, defaults to 10 documents per batch     - max_concurrency: OPTIONAL, defaults to 5 concurrent requests  Use Cases:     - Content quality filtering: \"Keep only well-written, professional articles\"     - Sentiment filtering: \"Discard negative or controversial content\"     - Topic relevance: \"Keep only documents about enterprise SaaS\"     - Visual filtering: \"Keep only images with people smiling\"     - Policy compliance: \"Filter out any content mentioning competitors\"
    """ # noqa: E501
    provider: Optional[LLMProvider] = Field(default=None, description="LLM provider to use. Supported providers: - openai: GPT models (GPT-4o, GPT-4o-mini) - google: Gemini models (Gemini 2.0 Flash) - anthropic: Claude models (Claude 3.5 Sonnet/Haiku)  If not specified, defaults to 'google'. Can be auto-inferred from model_name.")
    model_name: Optional[StrictStr] = Field(default='null', description="Specific LLM model to use. If not specified, uses provider default. Faster models recommended for filtering (gemini-2.0-flash, gpt-4o-mini).")
    inference_name: Optional[StrictStr] = Field(default='null', description="DEPRECATED: Use 'provider' and 'model_name' instead. Legacy format: 'provider:model' (e.g., 'gemini:gemini-2.0-flash'). Kept for backward compatibility only.")
    criteria: Optional[StrictStr] = Field(default='Keep only documents relevant to {{INPUT.query}}', description="Natural language description of filtering criteria. The LLM will evaluate each document against this criteria. Be specific and clear about what to keep vs discard. If empty or null, the stage is skipped (all documents pass through). Supports template variables: - {INPUT.field}: From pipeline inputs - {DOC.field}: From current document Template expressions are evaluated per-document for dynamic filtering. Examples: 'Keep only...', 'Discard if...', 'Filter out...'")
    include_reasoning: Optional[StrictBool] = Field(default=False, description="Whether to include LLM reasoning strings in stage metadata.")
    api_key: Optional[StrictStr] = Field(default='null', description="OPTIONAL. Bring Your Own Key (BYOK) - use your own LLM API key instead of Mixpeek's.  **How to use:** 1. Store your API key as an organization secret via POST /v1/organizations/secrets    Example: {\"secret_name\": \"openai_api_key\", \"secret_value\": \"sk-proj-...\"}  2. Reference it here using template syntax: {{secrets.openai_api_key}}  **Benefits:** - Use your own API credits and rate limits - Keep your API keys secure in Mixpeek's encrypted vault - No changes needed to your retriever when rotating keys  If not provided, uses Mixpeek's default API keys (usage charged to your account).")
    __properties: ClassVar[List[str]] = ["provider", "model_name", "inference_name", "criteria", "include_reasoning", "api_key"]

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of StageParamsLlmFilter from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of StageParamsLlmFilter from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "provider": obj.get("provider"),
            "model_name": obj.get("model_name") if obj.get("model_name") is not None else 'null',
            "inference_name": obj.get("inference_name") if obj.get("inference_name") is not None else 'null',
            "criteria": obj.get("criteria") if obj.get("criteria") is not None else 'Keep only documents relevant to {{INPUT.query}}',
            "include_reasoning": obj.get("include_reasoning") if obj.get("include_reasoning") is not None else False,
            "api_key": obj.get("api_key") if obj.get("api_key") is not None else 'null'
        })
        return _obj


