igerasimov's picture
MVP Milestone 5
d840c10
Raw
History Blame Contribute Delete
3.58 kB
"""Configuration helpers for the GCMD classifier MVP."""
from __future__ import annotations
import os
from collections.abc import Mapping
from pydantic import BaseModel, ConfigDict, Field
class ModelSettings(BaseModel):
"""Model and prompt settings loaded from environment-compatible mappings."""
model_config = ConfigDict(extra="forbid", frozen=True)
provider: str = "fake"
model_name: str = "fake-model"
temperature: float = Field(default=0.0, ge=0.0)
timeout_seconds: float = Field(default=30.0, gt=0.0)
max_retries: int = Field(default=2, ge=0)
prompt_version_topic: str = "topic-v1"
prompt_version_term: str = "term-v1"
prompt_version_variable: str = "variable-v1"
api_key_env_var: str = "OPENAI_API_KEY"
include_cost_metadata: bool = True
@classmethod
def from_environment(cls, env: Mapping[str, str] | None = None) -> ModelSettings:
"""Load model settings from an environment mapping without reading secrets."""
source = os.environ if env is None else env
return cls(
provider=source.get("MODEL_PROVIDER", cls.model_fields["provider"].default),
model_name=source.get("MODEL_NAME", cls.model_fields["model_name"].default),
temperature=_float_env(
source,
"MODEL_TEMPERATURE",
cls.model_fields["temperature"].default,
),
timeout_seconds=_float_env(
source,
"MODEL_TIMEOUT_SECONDS",
cls.model_fields["timeout_seconds"].default,
),
max_retries=_int_env(
source,
"MODEL_MAX_RETRIES",
cls.model_fields["max_retries"].default,
),
prompt_version_topic=source.get(
"PROMPT_VERSION_TOPIC",
cls.model_fields["prompt_version_topic"].default,
),
prompt_version_term=source.get(
"PROMPT_VERSION_TERM",
cls.model_fields["prompt_version_term"].default,
),
prompt_version_variable=source.get(
"PROMPT_VERSION_VARIABLE",
cls.model_fields["prompt_version_variable"].default,
),
api_key_env_var=source.get(
"MODEL_API_KEY_ENV_VAR",
cls.model_fields["api_key_env_var"].default,
),
include_cost_metadata=_bool_env(
source,
"MODEL_INCLUDE_COST_METADATA",
cls.model_fields["include_cost_metadata"].default,
),
)
def prompt_version_for_stage(self, stage: str) -> str:
"""Return the configured prompt version for a model-call stage."""
if stage == "topic":
return self.prompt_version_topic
if stage == "term":
return self.prompt_version_term
if stage == "variable":
return self.prompt_version_variable
raise ValueError(f"Unknown prompt stage: {stage}")
def _float_env(source: Mapping[str, str], name: str, default: float) -> float:
value = source.get(name)
return default if value is None else float(value)
def _int_env(source: Mapping[str, str], name: str, default: int) -> int:
value = source.get(name)
return default if value is None else int(value)
def _bool_env(source: Mapping[str, str], name: str, default: bool) -> bool:
value = source.get(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "on"}