emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/gptel 5159a773a0 011/273: gptel: Use text-property based d


From: ELPA Syncer
Subject: [nongnu] elpa/gptel 5159a773a0 011/273: gptel: Use text-property based delimiting
Date: Wed, 1 May 2024 10:01:26 -0400 (EDT)

branch: elpa/gptel
commit 5159a773a03446e6764cd62830e56a6d1729154e
Author: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmagalur@gmail.com>

    gptel: Use text-property based delimiting
    
    gptel.el (gptel--prompt-markers, gptel-send, gptel--create-prompt,
    gptel--numberize): Switch from using markers to text-properties to
    distinguish queries from responses. The former method was very brittle.
    Remove `gptel--prompt-markers', add the function `gptel--create-prompt'
    and the variable `gptel--num-messages-to-send'. This variable limits the
    context of the conversation that is sent with each request.
---
 gptel.el | 75 +++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 53 insertions(+), 22 deletions(-)

diff --git a/gptel.el b/gptel.el
index 5220bfef12..3e423bd9bd 100644
--- a/gptel.el
+++ b/gptel.el
@@ -57,6 +57,7 @@
 (require 'aio)
 (require 'json)
 (require 'map)
+(require 'text-property-search)
 
 (defcustom gptel-api-key nil
   "An OpenAI API key (string).
@@ -82,7 +83,6 @@ When set to nil, it is inserted all at once.
   :group 'gptel
   :type 'boolean)
 
-(defvar-local gptel--prompt-markers nil)
 (defvar gptel-default-session "*ChatGPT*")
 (defvar gptel-default-mode (if (featurep 'markdown-mode)
                                'markdown-mode
@@ -90,30 +90,19 @@ When set to nil, it is inserted all at once.
 (defvar gptel-prompt-string "### ")
 
 (aio-defun gptel-send ()
+(defvar-local gptel--num-messages-to-send nil)
+
+(defsubst gptel--numberize (val)
+  "Ensure VAL is a number."
+  (if (stringp val) (string-to-number val) val))
+
   "Submit this prompt to ChatGPT."
   (interactive)
   (message "Querying ChatGPT...")
-  (unless (and gptel--prompt-markers
-               (equal (marker-position (car gptel--prompt-markers))
-                      (point-max)))
-    (push (set-marker (make-marker) (point-max))
-          gptel--prompt-markers))
   (setf (nth 1 header-line-format)
         (propertize " Waiting..." 'face 'warning))
   (let* ((gptel-buffer (current-buffer))
-         (full-prompt
-          (save-excursion
-            (goto-char (point-min))
-            (cl-loop with role = "user"
-                     for (pm rm . _) on gptel--prompt-markers
-                     collect
-                     (list :role role
-                           :content
-                           (string-trim (buffer-substring-no-properties (or rm 
(point-min)) pm)
-                                        "[*# \t\n\r]+"))
-                     into prompts
-                     do (setq role (if (equal role "user") "assistant" "user"))
-                     finally return (nreverse prompts))))
+         (full-prompt (gptel--create-prompt))
          (response (aio-await
                     (funcall
                      (if (and gptel-use-curl (require 'gptel-curl nil t))
@@ -124,6 +113,7 @@ When set to nil, it is inserted all at once.
     (if content-str
             (with-current-buffer gptel-buffer
               (save-excursion
+                (put-text-property 0 (length content-str) 'gptel 'response 
content-str)
                 (message "Querying ChatGPT... done.")
                 (goto-char (point-max))
                 (display-buffer (current-buffer)
@@ -133,15 +123,56 @@ When set to nil, it is inserted all at once.
                 (if gptel-playback
                     (gptel--playback (current-buffer) content-str (point))
                   (insert content-str))
-                (push (set-marker (make-marker) (point))
-                      gptel--prompt-markers)
                 (insert "\n\n" gptel-prompt-string)
                 (unless gptel-playback
                   (setf (nth 1 header-line-format)
                         (propertize " Ready" 'face 'success)))))
           (setf (nth 1 header-line-format)
                 (propertize (format " Response Error: %s" status-str)
-                            'face 'error)))))
+                            'face 'error))))))
+
+(defun gptel--create-prompt ()
+  "Return a full conversation prompt from the contents of this buffer.
+
+If `gptel--num-messages-to-send' is set, limit to that many
+recent exchanges.
+
+If the region is active limit the prompt to the region contents
+instead."
+  (save-excursion
+    (save-restriction
+      (when (use-region-p)
+        (narrow-to-region (region-beginning) (region-end)))
+      (goto-char (point-max))
+      (let ((max-entries (and gptel--num-messages-to-send
+                              (* 2 (gptel--numberize
+                                    gptel--num-messages-to-send))))
+            (prop) (prompts))
+        (while (and
+                (or (not max-entries) (>= max-entries 0))
+                (setq prop (text-property-search-backward
+                            'gptel 'response
+                            (when (get-char-property (max (point-min) (1- 
(point)))
+                                                     'gptel)
+                              t))))
+          (push (list :role (if (prop-match-value prop) "assistant" "user")
+                      :content
+                      (string-trim
+                       (buffer-substring-no-properties (prop-match-beginning 
prop)
+                                                       (prop-match-end prop))
+                       "[*# \t\n\r]+"))
+                prompts)
+          (and max-entries (cl-decf max-entries)))
+        (cons (list :role "system"
+                    :content
+                    (concat
+                     (when (eq major-mode 'org-mode)
+                       (concat
+                        "In this conversation, format your responses as in an 
org-mode buffer in Emacs."
+                        " Do NOT use Markdown. I repeat, use org-mode markup 
and not markdown.\n"))
+                     gptel--system-message))
+              prompts)))))
+
 
 (aio-defun gptel--get-response (prompts)
   "Fetch response for PROMPTS from ChatGPT.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]