from __future__ import annotations from datetime import datetime from pydantic import BaseModel, Field class LlmBillingPolicyCreate(BaseModel): scene_code: str = Field(..., min_length=1, max_length=64) scene_name: str | None = Field(default=None, min_length=1, max_length=128) charge_credits: float = Field(..., gt=0, le=999999999.99, multiple_of=0.01) is_active: bool = True class LlmBillingPolicyUpdate(BaseModel): scene_name: str | None = Field(default=None, min_length=1, max_length=128) charge_credits: float | None = Field(default=None, gt=0, le=999999999.99, multiple_of=0.01) is_active: bool | None = None class LlmBillingPolicyOut(BaseModel): id: str scene_code: str scene_name: str charge_credits: float is_active: bool version: int created_by: str | None = None updated_by: str | None = None created_at: datetime updated_at: datetime class LlmCallAttemptOut(BaseModel): id: str call_sequence: int retry_sequence: int model_config_id: str | None = None model_name_snapshot: str | None = None provider_snapshot: str | None = None provider_request_id: str | None = None request_started_at: datetime response_received_at: datetime | None = None duration_ms: int | None = None status: str input_tokens: int | None = None output_tokens: int | None = None total_tokens: int | None = None http_status: int | None = None provider_error_code: str | None = None error_message: str | None = None token_unavailable_reason: str | None = None postprocess_status: str | None = None postprocess_error: str | None = None model_config = {"from_attributes": True} class LlmBillingExecutionOut(BaseModel): id: str user_id: str scene_code: str scene_name_snapshot: str owner_type: str owner_id: str business_attempt_no: int model_config_id: str | None = None model_name_snapshot: str | None = None provider_snapshot: str | None = None request_time: datetime charge_credits: float status: str total_call_count: int successful_call_count: int failed_call_count: int total_input_tokens: int total_output_tokens: int total_tokens: int refund_available_credits: float refund_expired_credits: float final_error_message: str | None = None completed_at: datetime | None = None refunded_at: datetime | None = None calls: list[LlmCallAttemptOut] = Field(default_factory=list)