Rifqi Hafizuddin
[NOTICKET] feat(llm): LLM_PROFILE selector for the chat LLM quad (54m default, 6l trial)
268ef5d Download src/config/settings.py from DataEyond/Agentic-Service-Data-Eyond-Catalog: direct link, hf CLI and curl.
- Browser
- Download file 9.58 kB
-
https://huggingface.co/spaces/DataEyond/Agentic-Service-Data-Eyond-Catalog/resolve/94de89b331583415f150d69415b964754bb481bc/src/config/settings.py
- Command line
-
hf download hf://spaces/DataEyond/Agentic-Service-Data-Eyond-Catalog@94de89b331583415f150d69415b964754bb481bc/src/config/settings.py
-
curl -L -o settings.py https://huggingface.co/spaces/DataEyond/Agentic-Service-Data-Eyond-Catalog/resolve/94de89b331583415f150d69415b964754bb481bc/src/config/settings.py
9.58 kB
| """Centralized configuration management using pydantic-settings.""" | |
| # import os | |
| # from typing import Optional | |
| from pydantic import Field | |
| from pydantic_settings import BaseSettings, SettingsConfigDict | |
| class Settings(BaseSettings): | |
| """Application settings loaded from environment variables.""" | |
| model_config = SettingsConfigDict( | |
| env_file=".env", | |
| env_file_encoding="utf-8", | |
| extra="allow", | |
| case_sensitive=False, | |
| ) | |
| # Feature flags | |
| # REMOVED 2026-07-02: the former ENABLE_SLOW_PATH flag is gone. `structured_flow` | |
| # now always runs the analytical slow path (Planner -> TaskRunner -> Assembler), so | |
| # every structured question persists a report_inputs record (reports no longer | |
| # depend on flipping a flag). extra="allow" ignores a stale ENABLE_SLOW_PATH in .env. | |
| # DEPRECATED 2026-06-24: the problem_validated gate was removed (the goal is now | |
| # user-entered objective + business_questions, no agent validation). This flag no | |
| # longer has any effect β the gate call site in ChatHandler is commented out. Kept | |
| # to avoid .env churn; remove once no environment references it. | |
| enable_gate: bool = Field(alias="enable_gate", default=False) | |
| # Skip init_db() (create_all + startup DDL) on boot. TRUE by default post-dedorch | |
| # cutover: Go owns the dedorch schema, so Python (consumer-only role) must NOT run | |
| # init_db β its ALTER/index DDL on Go-owned tables fails with InsufficientPrivilege | |
| # ("must be owner of table rooms"). Set to false only for a local Python-owned DB. | |
| skip_init_db: bool = Field(alias="SKIP_INIT_DB", default=True) | |
| # Database | |
| postgres_connstring: str | |
| # Redis | |
| redis_url: str | |
| redis_prefix: str = "dataeyond-agent-service_" | |
| # Azure OpenAI - GPT-5.4-mini (map to .env names with double underscores) | |
| azureai_api_key_54m: str = Field(alias="azureai__api_key__54m", default="") | |
| azureai_endpoint_url_54m: str = Field(alias="azureai__endpoint__url__54m", default="") | |
| azureai_deployment_name_54m: str = Field(alias="azureai__deployment__name__54m", default="") | |
| azureai_api_version_54m: str = Field(alias="azureai__api__version__54m", default="") | |
| # Azure OpenAI - GPT-6 Luna (trial 2026-11-03), same shape as the quad above. | |
| azureai_api_key_6l: str = Field(alias="azureai__api_key__6l", default="") | |
| azureai_endpoint_url_6l: str = Field(alias="azureai__endpoint__url__6l", default="") | |
| azureai_deployment_name_6l: str = Field(alias="azureai__deployment__name__6l", default="") | |
| azureai_api_version_6l: str = Field(alias="azureai__api__version__6l", default="") | |
| # Which quad the chat/planner/report LLM calls use: "54m" (default) or "6l". | |
| # Switching back is this one variable and a restart β the fallback if a model | |
| # trial does not work out. Any other value reads as "54m". | |
| llm_profile: str = Field(alias="LLM_PROFILE", default="54m") | |
| # Azure OpenAI - GPT-5.4-nano (knowledge-extraction pipeline; all four | |
| # branches route here β see KNOWLEDGE_PIPELINE_TODO.md D3) | |
| azureai_api_key_54n: str = Field(alias="azureai__api_key__54n", default="") | |
| azureai_endpoint_url_54n: str = Field(alias="azureai__endpoint__url__54n", default="") | |
| azureai_deployment_name_54n: str = Field(alias="azureai__deployment__name__54n", default="") | |
| azureai_api_version_54n: str = Field(alias="azureai__api__version__54n", default="") | |
| # Azure OpenAI - Embeddings | |
| azureai_api_key_embedding: str = Field(alias="azureai__api_key__embedding", default="") | |
| azureai_endpoint_url_embedding: str = Field(alias="azureai__endpoint__url__embedding", default="") | |
| azureai_deployment_name_embedding: str = Field(alias="azureai__deployment__name__embedding", default="") | |
| azureai_api_version_embedding: str = Field(alias="azureai__api__version__embedding", default="") | |
| # Azure Document Intelligence | |
| azureai_docintel_endpoint: str = Field(alias="azureai__docintel__endpoint", default="") | |
| azureai_docintel_key: str = Field(alias="azureai__docintel__key", default="") | |
| # Azure Blob Storage | |
| azureai_blob_sas: str = Field(alias="azureai__blob__sas", default="") | |
| azureai_container_endpoint: str = Field(alias="azureai__container__endpoint", default="") | |
| azureai_container_name: str = Field(alias="azureai__container__name", default="") | |
| azureai_container_account_name: str = Field(alias="azureai__container__account__name", default="") | |
| # Object storage provider toggle. Mirrors the Go data plane's `storage.provider` | |
| # (see Orchestrator config: azure_blob | supabase_s3). Blank falls back to azure_blob. | |
| # Tabular query execution reads the processed Parquet from whichever backend is active. | |
| storage_provider: str = Field(alias="STORAGE_PROVIDER", default="azure_blob") | |
| # Supabase S3-compatible object storage (active when storage_provider == "supabase_s3"). | |
| # BRIDGE (Option C): lets Python read the same bucket Go writes to, until Go exposes a | |
| # source-data endpoint (see docs/proposal_go_source_data_endpoint.md) β then this client | |
| # is removed and Python stops touching storage directly. | |
| supabase_s3_bucket: str = Field(alias="SUPABASE_S3_BUCKET", default="") | |
| supabase_s3_endpoint: str = Field(alias="SUPABASE_S3_ENDPOINT", default="") | |
| supabase_s3_region: str = Field(alias="SUPABASE_S3_REGION", default="") | |
| supabase_s3_access_key_id: str = Field(alias="SUPABASE_S3_ACCESS_KEY_ID", default="") | |
| supabase_s3_secret_access_key: str = Field(alias="SUPABASE_S3_SECRET_ACCESS_KEY", default="") | |
| # Mistral OCR β the knowledge-parsing primary backend (no GPU). Read here so the | |
| # key reaches a deployed HuggingFace Space the same way every other credential | |
| # does, instead of a bare os.environ lookup that a Space's secret injection can | |
| # miss. The standalone parser (`py -m src.knowledge_parsing.run`) still falls | |
| # back to the environment / repo .env β see src/knowledge_parsing/mistral_ocr.py. | |
| mistral_api_key: str = Field(alias="MISTRAL_API_KEY", default="") | |
| # Which OCR parser `POST /api/v2/document/process` uses (added 2026-09-24): | |
| # "paddleocr" (default) or "mistral". Server-side only β the request carries no | |
| # parser choice. The offline knowledge pipeline is NOT governed by this; its | |
| # default stays in src/knowledge_parsing/config.py. | |
| document_parser_backend: str = Field(alias="DOCUMENT_PARSER_BACKEND", default="paddleocr") | |
| # PaddleOCR-VL hosted job API (Baidu AI Studio). Names follow the official SDK. | |
| paddleocr_access_token: str = Field(alias="PADDLEOCR_ACCESS_TOKEN", default="") | |
| paddleocr_job_url: str = Field( | |
| alias="PADDLEOCR_JOB_URL", default="https://paddleocr.aistudio-app.com/api/v2/ocr/jobs" | |
| ) | |
| paddleocr_model: str = Field(alias="PADDLEOCR_MODEL", default="PaddleOCR-VL-1.6") | |
| # Langfuse | |
| LANGFUSE_PUBLIC_KEY: str | |
| LANGFUSE_SECRET_KEY: str | |
| LANGFUSE_HOST: str | |
| # MongoDB (for users - existing) | |
| # emarcal_mongo_endpoint_url: str = Field(alias="emarcal__mongo__endpoint__url", default="") | |
| # emarcal_buma_mongo_dbname: str = Field(alias="emarcal__buma__mongo__dbname", default="") | |
| # JWT (for users - existing) | |
| emarcal_jwt_secret_key: str = Field(alias="emarcal__jwt__secret_key", default="") | |
| emarcal_jwt_algorithm: str = Field(alias="emarcal__jwt__algorithm", default="HS256") | |
| # Bcrypt salt (for users - existing) | |
| emarcal_bcrypt_salt: str = Field(alias="emarcal__bcrypt__salt", default="") | |
| # DB credential encryption (Fernet key for user-registered database creds) | |
| dataeyond_db_credential_key: str = Field( | |
| alias="dataeyond__db__credential__key" | |
| ) | |
| # Shared service secret for the F-2 gate β UNWIRED 2026-07-27 (DEV_PLAN #37). The | |
| # gate is no longer mounted (see main.py), so this value is read by nothing. Kept | |
| # commented rather than deleted so the whole feature restores in one place. If a | |
| # deployment still has `dataeyond__service__secret` in its .env it is simply | |
| # ignored (extra="allow" on Settings). Restore alongside the main.py dependency. | |
| # dataeyond_service_secret: str = Field( | |
| # alias="dataeyond__service__secret", default="" | |
| # ) | |
| # The active chat-LLM quad, chosen by `llm_profile`. | |
| def _llm_suffix(self) -> str: | |
| return "6l" if self.llm_profile.strip().lower() == "6l" else "54m" | |
| def llm_api_key(self) -> str: | |
| return getattr(self, f"azureai_api_key_{self._llm_suffix}") | |
| def llm_endpoint_url(self) -> str: | |
| return getattr(self, f"azureai_endpoint_url_{self._llm_suffix}") | |
| def llm_deployment_name(self) -> str: | |
| return getattr(self, f"azureai_deployment_name_{self._llm_suffix}") | |
| def llm_api_version(self) -> str: | |
| return getattr(self, f"azureai_api_version_{self._llm_suffix}") | |
| # GPT-6 Luna on chat/completions (checked 2026-11-03): function tools β every | |
| # with_structured_output call β are refused unless reasoning_effort is "none", and | |
| # temperature accepts only 0 and 1. None leaves the 5.4-mini request unchanged. | |
| def llm_reasoning_effort(self) -> str | None: | |
| return "none" if self._llm_suffix == "6l" else None | |
| def llm_temperature(self, wanted: float) -> float: | |
| """`wanted`, or for Luna the nearer of the two values it accepts.""" | |
| if self._llm_suffix != "6l": | |
| return wanted | |
| return 0.0 if wanted < 0.5 else 1.0 | |
| # Singleton instance | |
| settings = Settings() | |