#!/usr/bin/env python3 """基于环境变量生成 Toolify 配置文件。""" import os import sys from pathlib import Path from typing import Any, List import yaml def _str_to_bool(value: str | None, default: bool) -> bool: """将字符串环境变量解析为布尔值。""" if value is None: return default normalized = value.strip().lower() if normalized in {"1", "true", "yes", "y", "on"}: return True if normalized in {"0", "false", "no", "n", "off"}: return False return default def _parse_list(env_value: str | None) -> List[str]: """将逗号分隔的环境变量解析为字符串列表。""" if not env_value: return [] return [item.strip() for item in env_value.split(",") if item.strip()] def _load_config_from_env() -> Any: """尝试从直接提供的 YAML 或 JSON 环境变量加载配置。""" direct_yaml = os.getenv("TOOLIFY_CONFIG_YAML") if direct_yaml: return yaml.safe_load(direct_yaml) direct_json = os.getenv("TOOLIFY_CONFIG_JSON") if direct_json: return yaml.safe_load(direct_json) return None def _build_default_config() -> dict: """根据基础环境变量构造最小可用配置。""" openai_api_key = os.getenv("OPENAI_API_KEY") allowed_keys = _parse_list(os.getenv("CLIENT_ALLOWED_KEYS")) if not openai_api_key: raise RuntimeError("缺少 OPENAI_API_KEY 环境变量,无法生成配置。") if not allowed_keys: raise RuntimeError("缺少 CLIENT_ALLOWED_KEYS 环境变量,无法生成配置。") base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1").rstrip("/") models = _parse_list(os.getenv("OPENAI_MODELS", "gpt-4o-mini,gpt-4o")) if not models: raise RuntimeError("OPENAI_MODELS 环境变量解析为空,请至少指定一个模型。") server_port = int(os.getenv("SERVER_PORT", os.getenv("PORT", "8000"))) server_host = os.getenv("SERVER_HOST", "0.0.0.0") server_timeout = int(os.getenv("SERVER_TIMEOUT", "180")) features_log_level = os.getenv("FEATURE_LOG_LEVEL", "INFO").upper() prompt_template = os.getenv("FEATURE_PROMPT_TEMPLATE") if prompt_template: prompt_template = prompt_template.replace("\\n", "\n") return { "server": { "port": server_port, "host": server_host, "timeout": server_timeout, }, "upstream_services": [ { "name": os.getenv("OPENAI_NAME", "openai"), "base_url": base_url, "api_key": openai_api_key, "description": os.getenv("OPENAI_DESCRIPTION", "OpenAI Service"), "is_default": True, "models": models, } ], "client_authentication": { "allowed_keys": allowed_keys, }, "features": { "enable_function_calling": _str_to_bool(os.getenv("FEATURE_ENABLE_FUNCTION_CALLING"), True), "log_level": features_log_level if features_log_level else "INFO", "convert_developer_to_system": _str_to_bool(os.getenv("FEATURE_CONVERT_DEVELOPER_TO_SYSTEM"), True), "prompt_template": prompt_template, "key_passthrough": _str_to_bool(os.getenv("FEATURE_KEY_PASSTHROUGH"), False), "model_passthrough": _str_to_bool(os.getenv("FEATURE_MODEL_PASSTHROUGH"), False), }, } def main() -> None: """入口函数:生成配置文件。""" config_path = Path(os.getenv("CONFIG_PATH", "/app/config.yaml")) if config_path.exists(): print(f"配置文件已存在,跳过生成: {config_path}") return config_obj = _load_config_from_env() if config_obj is None: config_obj = _build_default_config() if not isinstance(config_obj, dict): raise ValueError("环境变量提供的配置必须是字典结构。") config_path.parent.mkdir(parents=True, exist_ok=True) config_yaml = yaml.safe_dump(config_obj, sort_keys=False, allow_unicode=True) config_path.write_text(config_yaml, encoding="utf-8") print(f"已生成配置文件: {config_path}") if __name__ == "__main__": try: main() except Exception as exc: # noqa: BLE001 print(f"生成配置文件时出现错误: {exc}", file=sys.stderr) sys.exit(1)