diff --git a/core/siren-core-modules.el b/core/siren-core-modules.el index f79bf17..9ba432e 100644 --- a/core/siren-core-modules.el +++ b/core/siren-core-modules.el @@ -68,7 +68,6 @@ (require 'siren-chatgpt) (require 'siren-chatgpt-shell) (require 'siren-gptel) -(require 'siren-openai-chatgpt) ;; Misc. (require 'siren-explain-pause) diff --git a/modules/ai/siren-chatgpt-shell.el b/modules/ai/siren-chatgpt-shell.el index e7a5574..d2c1f03 100644 --- a/modules/ai/siren-chatgpt-shell.el +++ b/modules/ai/siren-chatgpt-shell.el @@ -10,17 +10,16 @@ (use-package chatgpt-shell :straight (:host github :repo "xenodium/chatgpt-shell") + :defer t :custom (chatgpt-shell-chatgpt-streaming t) - (chatgpt-shell-model-temperature 0.13) + (chatgpt-shell-model-temperature 1.0) :config - ;; Dynamically load the API key after package has loaded. - (setq chatgpt-shell-openai-key (siren-openai-api-key)) - (setq dall-e-shell-openai-key (siren-openai-api-key)) - - ;; Set model via `siren-chatgpt-model'. + ;; Set and manage API Key and Model via `siren-chatgpt' helpers. + (siren-chatgpt-register-api-key-var 'chatgpt-shell-openai-key) + (siren-chatgpt-register-api-key-var 'dall-e-shell-openai-key) (siren-chatgpt-register-model-var 'chatgpt-shell-model-version) (require 'ob-chatgpt-shell) diff --git a/modules/ai/siren-chatgpt.el b/modules/ai/siren-chatgpt.el index fc17426..223af7d 100644 --- a/modules/ai/siren-chatgpt.el +++ b/modules/ai/siren-chatgpt.el @@ -12,50 +12,94 @@ "Options for `siren-chatgpt'." :group 'siren) -(defcustom siren-chatgpt-model-variables nil - "List of variable names to be updated when `siren-chatgpt-model' change. +(defvar siren-chatgpt--api-key-login nil + "The login value used to retrieve the current API key.") + +(defun siren-chatgpt--set-api-key () + "Set `siren-chatgpt-api-key' based on provided LOGIN. + +If the key is not already set, try to retrieve it from the +auth-source. If LOGIN is non-nil, use that value to retrieve the" + (let ((login (siren-chatgpt--login-user))) + (or (and siren-chatgpt--api-key-login + (string= siren-chatgpt--api-key-login login)) + (let ((api-key (auth-source-pick-first-password :host "openai.com" + :user login))) + (if api-key + (progn + (setq siren-chatgpt--api-key-login login) + (customize-set-variable 'siren-chatgpt-api-key api-key)) + (error (format "OpenAI key for login \"%s\" not found in auth-source." + login))))))) + +(defvar siren-chatgpt--api-key-variables nil + "List of variable names to be updated on `siren-chatgpt-api-key' change. + +Other packages should use `siren-chatgpt-register-api-key-var' to register +their API key settings to be kept in sync with `siren-chatgpt-api-key'.") + +(defcustom siren-chatgpt-api-key nil + "OpenAI API key." + :type 'string + :set (lambda (symbol value) + (set-default symbol value) + (dolist (var siren-chatgpt--api-key-variables) + (set-default var value))) + :group 'siren-chatgpt) + +(defvar siren-chatgpt--model-variables nil + "List of variable names to be updated on `siren-chatgpt-model' change. Other packages should use `siren-chatgpt-register-model-var' -their model settings are kept in sync with `siren-chatgpt-model'." - :type '(repeat symbol) - :group 'siren-chatgpt) +their model settings are kept in sync with `siren-chatgpt-model'.") + +(defvar siren-chatgpt-models '("gpt-3.5-turbo" + "gpt-4" + "gpt-4-32k") + "List of supported models.") (defcustom siren-chatgpt-model "gpt-4" "The model to use for chatgpt." - :type '(choice (const "gpt-3.5-turbo") - (const "gpt-3.5-turbo-0301") - (const "gpt-4") - (const "gpt-4-0314") - (const "gpt-4-32k") - (const "gpt-4-32k-0314")) + :type '(choice (mapcar (lambda (model) (list 'const model)) + siren-chatgpt-models)) :set (lambda (symbol value) (set-default symbol value) - (dolist (var siren-chatgpt-model-variables) - (set-default var value))) + (dolist (var siren-chatgpt--model-variables) + (set-default var value)) + (if siren-chatgpt-api-key + (siren-chatgpt--set-api-key))) :group 'siren-chatgpt) +(defun siren-chatgpt--login-user () + "Return the login name of the current user. + +Used to allow different API keys for different models." + (if (string-prefix-p "gpt-4" siren-chatgpt-model) + "gpt-4" + "default")) + +(defun siren-chatgpt-select-model () + "Select a model to use for chatgpt." + (interactive) + (let ((model (completing-read "Select model: " siren-chatgpt-models))) + (customize-set-variable 'siren-chatgpt-model model))) + (defun siren-chatgpt-register-model-var (var) "Register VAR to be updated on `siren-chatgpt-model' change. VAR should be a symbol representing a variable. When the value of -`siren-chatgpt-model' changes, the value of VAR will be updated -to match it." - (add-to-list 'siren-chatgpt-model-variables var) +`siren-chatgpt-model' changes, VAR will be updated accordingly." + (add-to-list 'siren-chatgpt--model-variables var) (set-default var siren-chatgpt-model)) -(defvar siren-openai-api-key nil - "OpenAI API key.") +(defun siren-chatgpt-register-api-key-var (var) + "Register VAR to be updated on `siren-chatgpt-api-key' change. -(defun siren-openai-api-key () - "Return OpenAI API key. -If the key is not already set, try to retrieve it from the auth-source." - (or siren-openai-api-key - (let ((api-key (auth-source-pick-first-password :host "openai.com"))) - (if api-key - (progn - (setq siren-openai-api-key api-key) - siren-openai-api-key) - (error "OpenAI API key not found in auth-source"))))) +VAR should be a symbol representing a variable. When the value of +`siren-chatgpt-api-key' changes, the VAR will be updated +accordingly." + (add-to-list 'siren-chatgpt--api-key-variables var) + (siren-chatgpt--set-api-key)) (provide 'siren-chatgpt) ;;; siren-chatgpt.el ends here diff --git a/modules/ai/siren-gptel.el b/modules/ai/siren-gptel.el index 78c83bf..66c8ac9 100644 --- a/modules/ai/siren-gptel.el +++ b/modules/ai/siren-gptel.el @@ -22,18 +22,16 @@ :custom (gptel-stream t) ;; Requires curl. - (gptel-temperature 1) + (gptel-temperature 1.0) (gptel-use-curl (and (executable-find "curl") t)) :config - ;; Dynamically load the API key after package has loaded. - (setq gptel-api-key (siren-openai-api-key)) + ;; Set and manage API Key and Model via `siren-chatgpt' helpers. + (siren-chatgpt-register-api-key-var 'gptel-api-key) + (siren-chatgpt-register-model-var 'gptel-model) ;; Set default mode to org-mode, must be done after package load. - (setq gptel-default-mode 'org-mode) - - ;; Set model via `siren-chatgpt-model'. - (siren-chatgpt-register-model-var 'gptel-model)) + (setq gptel-default-mode 'org-mode)) (provide 'siren-gptel) ;;; siren-gptel.el ends here diff --git a/modules/ai/siren-openai-chatgpt.el b/modules/ai/siren-openai-chatgpt.el index b94878b..c1ed47f 100644 --- a/modules/ai/siren-openai-chatgpt.el +++ b/modules/ai/siren-openai-chatgpt.el @@ -10,14 +10,15 @@ (use-package openai :straight (:host github :repo "emacs-openai/openai") + :defer t :config - (setq openai-key (siren-openai-api-key))) + (siren-chatgpt-register-api-key-var 'openai-key)) (use-package chatgpt :straight (:host github :repo "emacs-openai/chatgpt") + :defer t :after openai - :custom (chatgpt-max-tokens 2000) (chatgpt-temperature 1.0) @@ -27,6 +28,7 @@ (use-package codegpt :straight (:host github :repo "emacs-openai/codegpt") + :defer t :after openai) (provide 'siren-openai-chatgpt)