Many more llama improvement

This commit is contained in:
Jeremy Dormitzer 2024-05-23 13:28:24 -04:00
parent e91b1d6480
commit cdd674fdcd

View File

@ -34,6 +34,14 @@
(defvar llama-chat-prompt-symbol "> "
"The symbol used to indicate the user's input in the chat buffer.")
(defvar llama-chat-default-name "*llama-chat*"
"The default name for the chat buffer.")
(defvar llama-chat-default-initial-prompt-args
'("Briefly greet the user without mentioning your name and ask how you can help."
:context "You are a helpful AI assistant running inside the Emacs text editor.")
"The arguments for the default initial chat prompt.")
(defvar-local llama-current-chat-prompt nil
"Chat prompt object for the current buffer.")
@ -129,7 +137,7 @@
(set-marker llama-ai-response-end-marker llama-ai-response-begin-marker)))
(goto-char llama-user-input-begin-marker))
(defun llama-chat-buffer (name prompt &optional provider)
(cl-defun llama-chat-buffer (name prompt &key provider callback)
(let ((buffer (get-buffer-create name)))
(with-current-buffer buffer
(unless (eq major-mode 'llama-chat-mode)
@ -139,7 +147,13 @@
llama-current-chat-prompt
(current-buffer)
llama-ai-response-begin-marker
#'llama-ai-response-finished-callback)))
(lambda ()
(let ((ai-response (buffer-substring-no-properties
llama-ai-response-begin-marker
llama-ai-response-end-marker)))
(llama-ai-response-finished-callback)
(when callback
(funcall callback ai-response)))))))
buffer))
(defun llama-chat-send ()
@ -199,14 +213,13 @@
(goto-char found)
(beginning-of-line))))
(defun llama-chat ()
(defun llama-chat (&optional callback)
"Start a chat with the AI."
(interactive)
(pop-to-buffer (llama-chat-buffer
"*llama-chat*"
(llm-make-chat-prompt
"Briefly greet the user without mentioning your name and ask how you can help."
:context "You are a helpful AI assistant running inside the Emacs text editor."))))
llama-chat-default-name
(apply #'llm-make-chat-prompt llama-chat-default-initial-prompt-args)
:callback callback)))
(defun llama-doctor()
"Start a psycotherapy session with the AI."
@ -231,5 +244,104 @@
"[[" #'llama-chat-previous-prompt
"]]" #'llama-chat-next-prompt))
(cl-defun llama-send-string-to-chat (name string &key user-visible-string callback initial-prompt)
"Send STRING to the chat named NAME.
If USER-VISIBLE-STRING is provided, display that in the chat buffer instead of the original string.
If CALLBACK is provided, call it with the AI response when it's available.
If a chat buffer with the given name isn't found, a new one is created using INITIAL-PROMPT, which defaults one made using to `llama-chat-default-initial-prompt-args'."
(cl-flet ((do-send (&rest _)
(with-current-buffer name
(delete-region llama-user-input-begin-marker llama-user-input-end-marker)
(save-excursion
(goto-char llama-user-input-begin-marker)
(insert (or user-visible-string string)))
(llm-chat-prompt-append-response llama-current-chat-prompt string)
(save-excursion
(let ((inhibit-read-only t))
(goto-char llama-user-input-end-marker)
(insert (propertize "\n\n" 'read-only t))
(set-marker llama-ai-response-begin-marker (point))))
(llama-chat-streaming-to-chat-buffer llama-llm-provider
llama-current-chat-prompt
(current-buffer)
llama-ai-response-begin-marker
(lambda ()
(let ((ai-response (buffer-substring-no-properties
llama-ai-response-begin-marker
llama-ai-response-end-marker)))
(llama-ai-response-finished-callback)
(when callback
(funcall callback ai-response))))))))
(if (get-buffer name)
(do-send)
(llama-chat-buffer name
(or initial-prompt
(apply #'llm-make-chat-prompt llama-chat-default-initial-prompt-args))
:callback #'do-send))))
(defun llama-ask-region (start end prompt &optional name)
"Ask the AI in buffer NAME the PROMPT about the region between START and END.
NAME defaults to `llama-chat-default-name'."
(interactive (list (region-beginning)
(region-end)
(read-string "Prompt: ")
(if current-prefix-arg
(read-string "Chat buffer: ")
llama-chat-default-name)))
(let ((input (format "%s\n%s" (buffer-substring-no-properties start end) prompt)))
(llama-send-string-to-chat
(or name llama-chat-default-name)
input)
(display-buffer (or name llama-chat-default-name))))
(defun llama-ask-buffer (buffer prompt &optional name)
"Ask the AI in buffer NAME the PROMPT about the BUFFER (interactively, the current buffer).
NAME defaults to `llama-chat-default-name'."
(interactive (list (current-buffer)
(read-string "Prompt: ")
(if current-prefix-arg
(read-string "Chat buffer: ")
llama-chat-default-name)))
(let ((input (format "%s\n%s" (buffer-substring-no-properties (point-min) (point-max)) prompt)))
(llama-send-string-to-chat
(or name llama-chat-default-name)
input)
(display-buffer (or name llama-chat-default-name))))
(defun llama-replace-in-region (start end prompt &optional name)
"Replace the region between START and END with the AI's response to PROMPT (require confirmation)."
(interactive (list (region-beginning)
(region-end)
(read-string "Prompt: ")
(if current-prefix-arg
(read-string "Chat buffer: ")
llama-chat-default-name)))
(let ((buffer (current-buffer))
(input (format "Generate replacement text for the following INPUT given the PROMPT. In your response, delimit the suggested replacement with the markers <REPLACE> and </REPLACE>.
INPUT: %s
PROMPT: %s" (buffer-substring-no-properties start end) prompt)))
(llama-send-string-to-chat
(or name llama-chat-default-name)
input
:callback (lambda (response)
(let ((replacement (with-temp-buffer
(insert response)
(goto-char (point-min))
(let ((start (search-forward "<REPLACE>" nil t))
(end (search-forward "</REPLACE>" nil t)))
(when (and start end)
(buffer-substring-no-properties start (- end 10)))))))
(if replacement
(when (y-or-n-p (format "Replace region with AI suggestion? %s" replacement))
(with-current-buffer buffer
(delete-region start end)
(insert replacement)))
(message "AI did not generate a valid replacement.")))))
(display-buffer (or name llama-chat-default-name))))
(provide 'llama)
;;; llama.el ends here