CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
azure.ts199 linesDownload Raw Back to src
1import type { RequestInit } from './internal/builtin-types';2import * as Errors from './error';3import { FinalRequestOptions } from './internal/request-options';4import { isObj, readEnv } from './internal/utils';5import { ClientOptions, OpenAI } from './client';6import { buildHeaders, NullableHeaders } from './internal/headers';7 8/** API Client for interfacing with the Azure OpenAI API. */9export interface AzureClientOptions extends ClientOptions {10  /**11   * Defaults to process.env['OPENAI_API_VERSION'].12   */13  apiVersion?: string | undefined;14 15  /**16   * Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/`17   */18  endpoint?: string | undefined;19 20  /**21   * A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`.22   * Note: this means you won't be able to use non-deployment endpoints. Not supported with Assistants APIs.23   */24  deployment?: string | undefined;25 26  /**27   * Defaults to process.env['AZURE_OPENAI_API_KEY'].28   */29  apiKey?: string | undefined;30 31  /**32   * A function that returns an access token for Microsoft Entra (formerly known as Azure Active Directory),33   * which will be invoked on every request.34   */35  azureADTokenProvider?: (() => Promise<string>) | undefined;36}37 38/** API Client for interfacing with the Azure OpenAI API. */39export class AzureOpenAI extends OpenAI {40  private _azureADTokenProvider: (() => Promise<string>) | undefined;41  deploymentName: string | undefined;42  apiVersion: string = '';43 44  /**45   * API Client for interfacing with the Azure OpenAI API.46   *47   * @param {string | undefined} [opts.apiVersion=process.env['OPENAI_API_VERSION'] ?? undefined]48   * @param {string | undefined} [opts.endpoint=process.env['AZURE_OPENAI_ENDPOINT'] ?? undefined] - Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/`49   * @param {string | undefined} [opts.apiKey=process.env['AZURE_OPENAI_API_KEY'] ?? undefined]50   * @param {string | undefined} opts.deployment - A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`.51   * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null]52   * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL']] - Sets the base URL for the API, e.g. `https://example-resource.azure.openai.com/openai/`.53   * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.54   * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.55   * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.56   * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.57   * @param {Headers} opts.defaultHeaders - Default headers to include with every request to the API.58   * @param {DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.59   * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.60   */61  constructor({62    baseURL = readEnv('OPENAI_BASE_URL'),63    apiKey = readEnv('AZURE_OPENAI_API_KEY'),64    apiVersion = readEnv('OPENAI_API_VERSION'),65    endpoint,66    deployment,67    azureADTokenProvider,68    dangerouslyAllowBrowser,69    ...opts70  }: AzureClientOptions = {}) {71    if (!apiVersion) {72      throw new Errors.OpenAIError(73        "The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).",74      );75    }76 77    if (typeof azureADTokenProvider === 'function') {78      dangerouslyAllowBrowser = true;79    }80 81    if (!azureADTokenProvider && !apiKey) {82      throw new Errors.OpenAIError(83        'Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.',84      );85    }86 87    if (azureADTokenProvider && apiKey) {88      throw new Errors.OpenAIError(89        'The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.',90      );91    }92 93    // define a sentinel value to avoid any typing issues94    apiKey ??= API_KEY_SENTINEL;95 96    opts.defaultQuery = { ...opts.defaultQuery, 'api-version': apiVersion };97 98    if (!baseURL) {99      if (!endpoint) {100        endpoint = process.env['AZURE_OPENAI_ENDPOINT'];101      }102 103      if (!endpoint) {104        throw new Errors.OpenAIError(105          'Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable',106        );107      }108 109      baseURL = `${endpoint}/openai`;110    } else {111      if (endpoint) {112        throw new Errors.OpenAIError('baseURL and endpoint are mutually exclusive');113      }114    }115 116    super({117      apiKey,118      baseURL,119      ...opts,120      ...(dangerouslyAllowBrowser !== undefined ? { dangerouslyAllowBrowser } : {}),121    });122 123    this._azureADTokenProvider = azureADTokenProvider;124    this.apiVersion = apiVersion;125    this.deploymentName = deployment;126  }127 128  override async buildRequest(129    options: FinalRequestOptions,130    props: { retryCount?: number } = {},131  ): Promise<{ req: RequestInit & { headers: Headers }; url: string; timeout: number }> {132    if (_deployments_endpoints.has(options.path) && options.method === 'post' && options.body !== undefined) {133      if (!isObj(options.body)) {134        throw new Error('Expected request body to be an object');135      }136      const model = this.deploymentName || options.body['model'] || options.__metadata?.['model'];137      if (model !== undefined && !this.baseURL.includes('/deployments')) {138        options.path = `/deployments/${model}${options.path}`;139      }140    }141    return super.buildRequest(options, props);142  }143 144  async _getAzureADToken(): Promise<string | undefined> {145    if (typeof this._azureADTokenProvider === 'function') {146      const token = await this._azureADTokenProvider();147      if (!token || typeof token !== 'string') {148        throw new Errors.OpenAIError(149          `Expected 'azureADTokenProvider' argument to return a string but it returned ${token}`,150        );151      }152      return token;153    }154    return undefined;155  }156 157  protected override async authHeaders(opts: FinalRequestOptions): Promise<NullableHeaders | undefined> {158    return;159  }160 161  protected override async prepareOptions(opts: FinalRequestOptions): Promise<void> {162    opts.headers = buildHeaders([opts.headers]);163 164    /**165     * The user should provide a bearer token provider if they want166     * to use Azure AD authentication. The user shouldn't set the167     * Authorization header manually because the header is overwritten168     * with the Azure AD token if a bearer token provider is provided.169     */170    if (opts.headers.values.get('Authorization') || opts.headers.values.get('api-key')) {171      return super.prepareOptions(opts);172    }173 174    const token = await this._getAzureADToken();175    if (token) {176      opts.headers.values.set('Authorization', `Bearer ${token}`);177    } else if (this.apiKey !== API_KEY_SENTINEL) {178      opts.headers.values.set('api-key', this.apiKey);179    } else {180      throw new Errors.OpenAIError('Unable to handle auth');181    }182    return super.prepareOptions(opts);183  }184}185 186const _deployments_endpoints = new Set([187  '/completions',188  '/chat/completions',189  '/embeddings',190  '/audio/transcriptions',191  '/audio/translations',192  '/audio/speech',193  '/images/generations',194  '/batches',195  '/images/edits',196]);197 198const API_KEY_SENTINEL = '<Missing Key>';199 
basant307/AI_Governance_Project · CoolFace