|
|
| """基于环境变量生成 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:
|
| print(f"生成配置文件时出现错误: {exc}", file=sys.stderr)
|
| sys.exit(1)
|
|
|