diff --git a/CHANGELOG.md b/CHANGELOG.md index d6c55fd..7314baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how * Add support for `Audio` requests (#9) * Implemented `auth-source` and add arguments for `content-type` and `org-id` (#13) +* Add `openai-base-url` variable that configures the Open AI API endpoint base-url (#15) ## 0.1.0 > Released N/A diff --git a/README.md b/README.md index b9b6fce..9c1620a 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,12 @@ For requests that need your user identifier, (setq openai-user "[YOUR USER UID]") ``` +For using another OpenAI endpoint, + +```elisp +(setq openai-base-url "[OPENAI BASE URL]") +``` + > 💡 Tip > > The two variables `openai-key` and `openai-user` are the default values for diff --git a/openai-audio.el b/openai-audio.el index f9ed72f..e50515f 100644 --- a/openai-audio.el +++ b/openai-audio.el @@ -34,6 +34,7 @@ ;;;###autoload (cl-defun openai-audio-create-transcription ( file callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -48,13 +49,13 @@ Argument FILE is audio file to transcribe, in one of these formats: mp3, mp4, mpeg, mpga, m4a, wav, or webm. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL PROMPT, RESPONSE-FORMAT, TEMPERATURE, and LANGUAGE." - (openai-request "https://api.openai.com/v1/audio/transcriptions" + (openai-request (concat base-url "/audio/transcriptions") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -72,6 +73,7 @@ TEMPERATURE, and LANGUAGE." ;;;###autoload (cl-defun openai-audio-create-translation ( file callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -85,13 +87,13 @@ Argument FILE is the audio file to translate, in one of these formats: mp3, mp4, mpeg, mpga, m4a, wav, or webm. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL PROMPT, RESPONSE-FORMAT, and TEMPERATURE." - (openai-request "https://api.openai.com/v1/audio/transcriptions" + (openai-request (concat base-url "/audio/translations") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-chat.el b/openai-chat.el index b4d586b..a3f125c 100644 --- a/openai-chat.el +++ b/openai-chat.el @@ -34,6 +34,7 @@ ;;;###autoload (cl-defun openai-chat ( messages callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -53,13 +54,13 @@ Arguments MESSAGES and CALLBACK are required for this type of request. MESSAGES is the conversation data. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL, TEMPERATURE, TOP-P, N, STREAM, STOP, MAX-TOKENS, PRESENCE-PENALTY, FREQUENCY-PENALTY, and LOGIT-BIAS." - (openai-request "https://api.openai.com/v1/chat/completions" + (openai-request (concat base-url "/chat/completions") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -113,7 +114,7 @@ This is a ping pong message, so you will only get one response." :max-tokens openai-chat-max-tokens :temperature openai-chat-temperature :user (unless (string= user "user") user)) - (user-error "Abort, canecel chat operation"))) + (user-error "Abort, cancel chat operation"))) (provide 'openai-chat) ;;; openai-chat.el ends here diff --git a/openai-completion.el b/openai-completion.el index 58c5bd9..1d317c0 100644 --- a/openai-completion.el +++ b/openai-completion.el @@ -34,6 +34,7 @@ ;;;###autoload (cl-defun openai-completion ( prompt callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -58,14 +59,14 @@ Arguments PROMPT and CALLBACK are required for this type of request. PROMPT is either the question or instruction to OpenAI. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL, SUFFIX, MAX-TOKENS, TEMPERATURE, TOP-P, N, STREAM, LOGPROBS, ECHO, STOP, PRESENCE-PENALTY, FREQUENCY-PENALTY, BEST-OF, and LOGIT-BIAS." - (openai-request "https://api.openai.com/v1/completions" + (openai-request (concat base-url "/completions") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-edit.el b/openai-edit.el index a4fa403..f8073ee 100644 --- a/openai-edit.el +++ b/openai-edit.el @@ -34,6 +34,7 @@ (cl-defun openai-edit-create ( input instruction callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -46,15 +47,15 @@ The INPUT is text to use as a starting point for the edit. The INSTRUCTION that tells the model how to edit the prompt. -The argument CALLBACK is execuated after request is made. +The argument CALLBACK is executed after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in. -The rest of the arugments are optional, please see OpenAI API reference page +The rest of the arguments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL, TEMPERATURE, TOP-P, and N." - (openai-request "https://api.openai.com/v1/edits" + (openai-request (concat base-url "/edits") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-embedding.el b/openai-embedding.el index 87abf9d..8b5452e 100644 --- a/openai-embedding.el +++ b/openai-embedding.el @@ -34,6 +34,7 @@ (cl-defun openai-embedding-create ( input callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -46,14 +47,14 @@ To get embeddings for multiple inputs in a single request, pass an array of strings or array of token arrays. Each input must not exceed 8192 tokens in length. -The argument CALLBACK is execuated after request is made. +The argument CALLBACK is executed after the request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. -The rest of the arugments are optional, please see OpenAI API reference page +The rest of the arguments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL." - (openai-request "https://api.openai.com/v1/embeddings" + (openai-request (concat base-url "/embeddings") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-engine.el b/openai-engine.el index ca9c412..63fbfb8 100644 --- a/openai-engine.el +++ b/openai-engine.el @@ -36,6 +36,7 @@ (cl-defun openai-engine-list ( callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -44,9 +45,9 @@ information about each one such as the owner and availability. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/engines" + (openai-request (concat base-url "/engines") :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -56,6 +57,7 @@ can overwrite the value by passing it in." (cl-defun openai-engine-retrieve ( engine-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -66,9 +68,9 @@ The argument ENGINE-ID is the engine to use for this request. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/engines/%s" engine-id) + (openai-request (format "%s/engines/%s" base-url engine-id) :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read diff --git a/openai-file.el b/openai-file.el index a7f6f0e..e61b9f9 100644 --- a/openai-file.el +++ b/openai-file.el @@ -34,6 +34,7 @@ (cl-defun openai-file-list ( callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -41,9 +42,9 @@ The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/files" + (openai-request (concat base-url "/files") :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -53,6 +54,7 @@ can overwrite the value by passing it in." (cl-defun openai-file-upload ( file purpose callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -71,9 +73,9 @@ uploaded file. Argument CALLBACK is function with data pass in. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/files" + (openai-request (concat base-url "/files") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -86,6 +88,7 @@ can overwrite the value by passing it in." (cl-defun openai-file-delete ( file-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -95,9 +98,9 @@ The arument FILE-ID is id of the file to use for this request. Argument CALLBACK is function with data pass in. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/files" + (openai-request (concat base-url "/files") :type "DELETE" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -109,6 +112,7 @@ can overwrite the value by passing it in." (cl-defun openai-file-retrieve ( file-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -118,9 +122,9 @@ The arument FILE-ID is id of the file to use for this request. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/files/%s" file-id) + (openai-request (format "%s/files/%s" base-url file-id) :type "GET" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -132,6 +136,7 @@ can overwrite the value by passing it in." (cl-defun openai-file-retrieve-content ( file-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -142,9 +147,9 @@ The arument FILE-ID is id of the file to use for this request. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/files/%s/content" file-id) + (openai-request (format "%s/files/%s/content" base-url file-id) :type "GET" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-fine-tune.el b/openai-fine-tune.el index 42b704b..5fa52d0 100644 --- a/openai-fine-tune.el +++ b/openai-fine-tune.el @@ -33,6 +33,7 @@ (cl-defun openai-fine-tune-create ( training-file callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -57,15 +58,15 @@ data. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, and ORG-ID are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL, VALIDATION-FILE, N-EPOCHS, BATCH-SIZE, LEARNING-RATE-MULTIPLIER, PROMPT-LOSS-WEIGHT, COMPUTE-CLASSIFICATION-METRICS, CLASSIFICATION-N-CLASSES, -CLASSIFICATION-POSITIVE-CLASS, CLASSIFICATION-BETAS, and SUFFIX" - (openai-request "https://api.openai.com/v1/fine-tunes" +CLASSIFICATION-POSITIVE-CLASS, CLASSIFICATION-BETAS and SUFFIX." + (openai-request (concat base-url "/fine-tunes") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -88,6 +89,7 @@ CLASSIFICATION-POSITIVE-CLASS, CLASSIFICATION-BETAS, and SUFFIX" (cl-defun openai-fine-tune-list ( callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -95,9 +97,9 @@ CLASSIFICATION-POSITIVE-CLASS, CLASSIFICATION-BETAS, and SUFFIX" The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/fine-tunes" + (openai-request (concat base-url "/fine-tunes") :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -107,6 +109,7 @@ can overwrite the value by passing it in." (cl-defun openai-fine-tune-retrieve ( fine-tune-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -116,9 +119,9 @@ The FINE-TUNE-ID of the fine-tune job. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/fine-tunes/%s" fine-tune-id) + (openai-request (format "%s/fine-tunes/%s" base-url fine-tune-id) :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -128,6 +131,7 @@ can overwrite the value by passing it in." (cl-defun openai-fine-tune-cancel ( fine-tune-id callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) @@ -137,9 +141,9 @@ The FINE-TUNE-ID of the fine-tune job to cancel. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/fine-tunes/%s/cancel" fine-tune-id) + (openai-request (format "%s/fine-tunes/%s/cancel" base-url fine-tune-id) :type "POST" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -151,16 +155,17 @@ can overwrite the value by passing it in." &key (content-type "application/json") (key openai-key) - org-id) + org-id + (base-url openai-base-url)) "Get fine-grained status update for a fine-tune job. The FINE-TUNE-ID of the fine-tune job to get events for. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments CONTENT-TYPE, KEY, ORG-ID and BASE-URL are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/fine-tunes/%s/events" fine-tune-id) + (openai-request (format "%s/fine-tunes/%s/events" base-url fine-tune-id) :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -172,16 +177,17 @@ can overwrite the value by passing it in." &key (content-type "application/json") (key openai-key) - org-id) + org-id + (base-url openai-base-url)) "Delete a fine-tuned model. You must have the Owner role in your organization. The MODEL to delete. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments CONTENT-TYPE, KEY, ORG-ID and BASE-URL are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/models/%s" model) + (openai-request (format "%s/models/%s" base-url model) :type "DELETE" :headers (openai--headers content-type key org-id) :parser 'json-read diff --git a/openai-image.el b/openai-image.el index ae17ac0..40a7144 100644 --- a/openai-image.el +++ b/openai-image.el @@ -33,6 +33,7 @@ (cl-defun openai-image ( prompt callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -46,12 +47,12 @@ Arguments PROMPT and CALLBACK are required for this type of request. PROMPT is either the question or instruction to OpenAI. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to N, SIZE, and RESPONSE-FORMAT." - (openai-request "https://api.openai.com/v1/images/generations" + (openai-request (concat base-url "/images/generations") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -67,6 +68,7 @@ for more information. Arguments here refer to N, SIZE, and RESPONSE-FORMAT." (cl-defun openai-image-edit ( image prompt callback &key + (base-url openai-base-url) content-type (key openai-key) org-id @@ -81,13 +83,13 @@ Arguments IMAGE, PROMPT and CALLBACK are required for this type of request. PROMPT is a text description of the desired image(s). IMAGE is the image file to edit. CALLBACK is the execuation after request is made. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MASK, N, SIZE, and RESPONSE-FORMAT." - (openai-request "https://api.openai.com/v1/images/edits" + (openai-request (concat base-url "/images/edits") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode @@ -105,6 +107,7 @@ RESPONSE-FORMAT." (cl-defun openai-image-variation ( image callback &key + (base-url openai-base-url) content-type (key openai-key) org-id @@ -118,13 +121,13 @@ RESPONSE-FORMAT." Argument CALLBACK is function with data pass in, and the argument IMAGE must be a valid PNG file, less than 4MB, and square. -Arguments CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY, ORG-ID and USER are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MASK, N, SIZE, and RESPONSE-FORMAT." - (openai-request "https://api.openai.com/v1/images/variations" + (openai-request (concat base-url "/images/variations") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai-model.el b/openai-model.el index 866be95..a77ef57 100644 --- a/openai-model.el +++ b/openai-model.el @@ -31,14 +31,15 @@ (cl-defun openai-models ( callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) "Return models data and execute the CALLBACK. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request "https://api.openai.com/v1/models" + (openai-request (concat base-url "/models") :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read @@ -48,15 +49,16 @@ can overwrite the value by passing it in." (cl-defun openai-model ( model callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id) "Return MODEL data and execute the CALLBACK. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in." - (openai-request (format "https://api.openai.com/v1/models/%s" model) + (openai-request (format "%s/models/%s" base-url model) :type "GET" :headers (openai--headers content-type key org-id) :parser 'json-read diff --git a/openai-moderation.el b/openai-moderation.el index 88c651a..c4f5198 100644 --- a/openai-moderation.el +++ b/openai-moderation.el @@ -34,6 +34,7 @@ (cl-defun openai-moderation-create ( input callback &key + (base-url openai-base-url) (content-type "application/json") (key openai-key) org-id @@ -44,12 +45,12 @@ Argument INPUT is the text to classify. The argument CALLBACK is execuated after request is made. -Arguments CONTENT-TYPE, KEY, and ORG-ID are global options; however, you +Arguments BASE-URL, CONTENT-TYPE, KEY and ORG-ID are global options; however, you can overwrite the value by passing it in. The rest of the arugments are optional, please see OpenAI API reference page for more information. Arguments here refer to MODEL." - (openai-request "https://api.openai.com/v1/embeddings" + (openai-request (concat base-url "/embeddings") :type "POST" :headers (openai--headers content-type key org-id) :data (openai--json-encode diff --git a/openai.el b/openai.el index f418a1e..5e49cf1 100644 --- a/openai.el +++ b/openai.el @@ -62,10 +62,11 @@ ;;; Request ;;;###autoload -(defun openai-key-auth-source () - "Retrieve the OpenAI API key from auth-source." +(defun openai-key-auth-source (&optional base-url) + "Retrieve the OpenAI API key from auth-source given a BASE-URL. +If BASE-URL is not specified, it defaults to `openai-base-url'." (if-let ((auth-info (auth-source-search :max 1 - :host "api.openai.com" + :host (url-host (url-generic-parse-url (or base-url openai-base-url))) :require '(:user :secret)))) (funcall (plist-get (car auth-info) :secret)) (error "OpenAI API key not found in auth-source"))) @@ -82,6 +83,11 @@ auth-source is provided for convenience.") "A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.") +(defcustom openai-base-url "https://api.openai.com/v1" + "The base URL for OpenAI API requests." + :type 'string + :group 'openai) + (defun openai--resolve-key (key) "If the given KEY is a function call it and return the result, otherwise return KEY."