gpt_client_utils.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import os
  2. import logging
  3. from openai import AzureOpenAI, OpenAI
  4. logger = logging.getLogger(__name__)
  5. class LLMError(RuntimeError):
  6. pass
  7. class GPTClientFactory:
  8. def __init__(self):
  9. self.auth_mode = os.getenv("OPENAI_AUTH_MODE", "entra_id").lower()
  10. self.base_url = os.getenv("AZURE_OPENAI_ENDPOINT") or os.getenv("OPENAI_BASE_URL")
  11. self.api_key = os.getenv("OPENAI_API_KEY")
  12. self.azure_api_version = os.getenv("AZURE_OPENAI_API_VERSION")
  13. timeout_value = os.getenv("OPENAI_TIMEOUT", "120")
  14. self.timeout = float(timeout_value) if timeout_value else 120.0
  15. self.client = None
  16. def _init_entra_id_client(self) -> None:
  17. """Initialize client with Entra ID (Azure AD) authentication."""
  18. try:
  19. from azure.identity import (
  20. AzureCliCredential,
  21. ChainedTokenCredential,
  22. ManagedIdentityCredential,
  23. get_bearer_token_provider,
  24. )
  25. except ImportError:
  26. raise LLMError(
  27. "azure-identity package is required for Entra ID authentication. "
  28. "Install with: pip install azure-identity"
  29. )
  30. if not self.base_url:
  31. raise LLMError("AZURE_OPENAI_ENDPOINT or OPENAI_BASE_URL is required for Entra ID authentication")
  32. if not self.azure_api_version:
  33. raise LLMError("AZURE_OPENAI_API_VERSION is required for Entra ID authentication")
  34. credential = ChainedTokenCredential(
  35. AzureCliCredential(),
  36. ManagedIdentityCredential(),
  37. )
  38. token_provider = get_bearer_token_provider(
  39. credential,
  40. "https://cognitiveservices.azure.com/.default"
  41. )
  42. self.client = AzureOpenAI(
  43. azure_endpoint=self.base_url,
  44. azure_ad_token_provider=token_provider,
  45. api_version=self.azure_api_version,
  46. timeout=self.timeout,
  47. )
  48. logger.debug(f"Initialized Azure OpenAI client with Entra ID authentication (endpoint: {self.base_url})")
  49. def _init_api_key_client(self) -> None:
  50. """Initialize client with API Key authentication."""
  51. if not self.api_key:
  52. raise LLMError("OPENAI_API_KEY is required for APIKey authentication")
  53. if self.base_url and ("azure" in self.base_url.lower() or "cognitiveservices" in self.base_url.lower()):
  54. if not self.azure_api_version:
  55. raise LLMError("AZURE_OPENAI_API_VERSION is required for Azure OpenAI APIKey authentication")
  56. self.client = AzureOpenAI(
  57. azure_endpoint=self.base_url,
  58. api_key=self.api_key,
  59. api_version=self.azure_api_version,
  60. timeout=self.timeout,
  61. )
  62. logger.debug(f"Initialized Azure OpenAI client with API Key authentication (endpoint: {self.base_url})")
  63. else:
  64. client_kwargs = {
  65. "api_key": self.api_key,
  66. "timeout": self.timeout,
  67. }
  68. if self.base_url:
  69. client_kwargs["base_url"] = self.base_url
  70. self.client = OpenAI(**client_kwargs)
  71. logger.debug(f"Initialized OpenAI client with API Key authentication (base_url: {self.base_url})")
  72. def build(self):
  73. if self.auth_mode in ["entra", "entra_id", "aad", "azure_ad"]:
  74. self._init_entra_id_client()
  75. elif self.auth_mode in ["api_key", "apikey", "key"]:
  76. self._init_api_key_client()
  77. else:
  78. raise LLMError(f"Unsupported OPENAI_AUTH_MODE: {self.auth_mode}. Use 'entra_id' or 'api_key'.")
  79. return self.client