"""Patch recipe_web/config.yaml for HF Spaces deployment. Sets host=0.0.0.0, port=7860, image_source=remote, Turso config, and HF image URL. """ from __future__ import annotations import logging import os # nosemgrep: python-no-os-environ -- HF Space injects secrets as env vars from pathlib import Path import yaml logging.basicConfig(level=logging.INFO, format="%(message)s") log = logging.getLogger(__name__) WEB_CONFIG_PATH = Path("recipe_web/config.yaml") PIPELINE_CONFIG_PATH = Path("parsing_pipeline/config.yaml") HF_IMAGE_BASE_URL = "https://huggingface.co/datasets/ronheichman/recipe-images/resolve/main" PIPELINE_ONLY_KEYS = ["pipeline_scripts"] def main() -> None: config = yaml.safe_load(WEB_CONFIG_PATH.read_text()) config["server"]["host"] = "0.0.0.0" # noqa: S104 -- HF Space container must bind all interfaces config["server"]["port"] = 7860 config["image_source"] = "remote" config["image_base_url"] = HF_IMAGE_BASE_URL config["observability"]["enabled"] = False log.info("Observability disabled (no OTEL collector in HF Spaces)") # nosemgrep: python-no-os-environ -- HF Space env vars; no config in container turso_url = os.environ.get( "TURSO_DATABASE_URL", "", ) # nosemgrep: python-no-os-environ -- HF Space env vars; no config in container turso_token = os.environ.get( "TURSO_AUTH_TOKEN", "", ) if turso_url: config["user_db"]["turso_sync_url"] = "" config["user_db"]["turso_auth_token"] = "" config["user_db_backup"]["enabled"] = True config["user_db_backup"]["turso_sync_url"] = turso_url config["user_db_backup"]["turso_auth_token"] = turso_token log.info("Turso backup config injected: %s", turso_url) # nosemgrep: python-no-os-environ -- HF Space env vars; no config in container jwt_secret = os.environ.get("JWT_SECRET", "") if jwt_secret: config.setdefault("auth", {}) config["auth"]["jwt_secret"] = jwt_secret log.info("JWT secret injected from env (length %d)", len(jwt_secret)) else: log.warning("JWT_SECRET not set; auth uses the config.yaml dev placeholder") WEB_CONFIG_PATH.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False)) log.info("Web config patched: host=0.0.0.0, port=7860, image_source=remote") if PIPELINE_CONFIG_PATH.exists(): pipeline_config = yaml.safe_load(PIPELINE_CONFIG_PATH.read_text()) for key in PIPELINE_ONLY_KEYS: pipeline_config.pop(key, None) pipeline_config.setdefault("litellm_router", {}) # nosemgrep: python-no-os-environ -- HF Space env vars; no config in container mistral_key = os.environ.get("MISTRAL_API_KEY", "") if mistral_key: pipeline_config["litellm_router"]["proxy_url"] = "https://api.mistral.ai/v1" pipeline_config["litellm_router"]["proxy_api_key"] = mistral_key pipeline_config["litellm_router"]["model_alias"] = "mistral-small-latest" log.info("LiteLLM router pointed at Mistral API (model=mistral-small-latest)") else: pipeline_config["litellm_router"]["proxy_url"] = ( "https://ronheichman-llm-service.hf.space" ) log.info("LiteLLM router pointed at llm-service Space (no MISTRAL_API_KEY)") PIPELINE_CONFIG_PATH.write_text( yaml.dump(pipeline_config, default_flow_style=False, sort_keys=False), ) log.info("Pipeline config patched: stripped %s", PIPELINE_ONLY_KEYS) if __name__ == "__main__": main()