[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/gptel c9795fe9e8 060/273: gptel: org support for streaming
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/gptel c9795fe9e8 060/273: gptel: org support for streaming WIP |
Date: |
Wed, 1 May 2024 10:01:42 -0400 (EDT) |
branch: elpa/gptel
commit c9795fe9e8f2d0eed530027a5d3cde84cc1dd7fc
Author: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
gptel: org support for streaming WIP
* gptel.el (gptel--convert-playback-markdown->org): New converter
for markdown->org that works on text chunks while maintaining the
parse state until the text stream is finished.
* gptel-curl.el (gptel--insert-response-stream,
gptel-curl-get-response): When using `gptel-playback' and
requesting ChatGPT's responses in org-mode, run the above
converter on the received response. This works by storing the
converter and associated state as a closure in the async info
plist that is supplied along with the response, and running it
repeatedly on each chunk of text in the response stream before it
is inserted into the buffer.
FIXME: Note that `gptel-response-filter-functions' is currently
ignored if using `gptel-stream'.
---
gptel-curl.el | 18 ++++++++++++++----
gptel.el | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/gptel-curl.el b/gptel-curl.el
index e6ca0dd299..9c07d7113d 100644
--- a/gptel-curl.el
+++ b/gptel-curl.el
@@ -59,6 +59,8 @@ PROMPTS is the data to send, TOKEN is a unique identifier."
(push (format "-d%s" data) args)
(nreverse (cons url args))))
+;;TODO: The :transformer argument here is an alternate implementation of
+;;`gptel-response-filter-functions'. The two need to be unified.
;;;###autoload
(defun gptel-curl-get-response (info &optional callback)
"Retrieve response to prompt in INFO.
@@ -83,7 +85,13 @@ the response is inserted into the current buffer after
point."
:callback (or callback
(if gptel-playback
#'gptel--insert-response-stream
- #'gptel--insert-response)))
+ #'gptel--insert-response))
+ :transformer (when (or (eq gptel-default-mode
'org-mode)
+ (eq (buffer-local-value
+ 'major-mode
+ (plist-get info
:gptel-buffer))
+ 'org-mode))
+
(gptel--convert-playback-markdown->org)))
info))
(if gptel-playback
(progn (set-process-sentinel process #'gptel-curl--cleanup-stream)
@@ -122,7 +130,8 @@ See `gptel--url-get-response' for details."
(status-str (plist-get response :status))
(gptel-buffer (plist-get info :gptel-buffer))
(start-marker (plist-get info :insert-marker))
- (tracking-marker (plist-get info :tracking-marker)))
+ (tracking-marker (plist-get info :tracking-marker))
+ (transformer (plist-get info :transformer)))
(if content-str
(with-current-buffer gptel-buffer
(save-excursion
@@ -134,8 +143,9 @@ See `gptel--url-get-response' for details."
(set-marker-insertion-type tracking-marker t)
(plist-put info :tracking-marker tracking-marker))
- (setq content-str (gptel--transform-response
- content-str gptel-buffer))
+ (when transformer
+ (setq content-str (funcall transformer content-str)))
+
(put-text-property 0 (length content-str) 'gptel 'response
content-str)
(goto-char tracking-marker)
(insert content-str)))
diff --git a/gptel.el b/gptel.el
index a1836b5589..18ed080db3 100644
--- a/gptel.el
+++ b/gptel.el
@@ -550,6 +550,58 @@ elements."
(insert "/")))))))
(buffer-string)))
+(defun gptel--convert-playback-markdown->org ()
+ ""
+ (let ((in-src-block)
+ (temp-buf (generate-new-buffer-name "*gptel-temp*"))
+ (start-pt (make-marker)))
+ (lambda (str)
+ (let ((noop-p))
+ (with-current-buffer (get-buffer-create temp-buf)
+ (save-excursion (goto-char (point-max))
+ (insert str))
+ (when (marker-position start-pt) (goto-char start-pt))
+ (save-excursion
+ (while (re-search-forward "`\\|\\*\\{1,2\\}\\|_" nil t)
+ (pcase (match-string 0)
+ ("`"
+ (cond
+ ((looking-at "``")
+ (backward-char 1)
+ (delete-char 3)
+ (if in-src-block
+ (progn (insert "#+end_src")
+ (setq in-src-block nil))
+ (insert "#+begin_src ")
+ (setq in-src-block t)))
+ ((looking-at "`\\|$")
+ (setq noop-p t)
+ (set-marker start-pt (1- (point)))
+ (unless (eobp) (forward-char 1)))
+ ((not in-src-block) (replace-match "="))))
+ ((and "**" (guard (not in-src-block)))
+ (cond
+ ((looking-at "\\*\\(?:[[:word:]]\\|\s\\)")
+ (delete-char 1))
+ ((looking-back "\\(?:[[:word:]]\\|\s\\)\\*\\{2\\}"
+ (max (- (point) 3) (point-min)))
+ (backward-delete-char 1))))
+ ((and (or "_" "*") (guard (not in-src-block)))
+ (when (save-match-data
+ (save-excursion
+ (backward-char 2)
+ (or
+ (looking-at
+
"[^[:space:][:punct:]\n]\\(?:_\\|\\*\\)\\(?:[[:space:][:punct:]]\\|$\\)")
+ (looking-at
+
"\\(?:[[:space:][:punct:]]\\)\\(?:_\\|\\*\\)\\([^[:space:][:punct:]]\\|$\\)"))))
+ (backward-delete-char 1)
+ (insert "/"))))))
+ (if noop-p
+ (buffer-substring (point) start-pt)
+ (prog1 (buffer-substring (point) (point-max))
+ (set-marker start-pt (point-max)))))))))
+
(defun gptel--playback (buf content-str start-pt)
"Playback CONTENT-STR in BUF.
- [nongnu] elpa/gptel 53ee34653e 252/273: gptel-openai: Typo in gptel--json-read, (continued)
- [nongnu] elpa/gptel 53ee34653e 252/273: gptel-openai: Typo in gptel--json-read, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel f2fd2b13b0 257/273: gptel-org: Move response transform code for Org, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel e994a443d3 262/273: README: add OpenRouter instructions (#282), ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 7b6e3c5900 260/273: gptel: Release v0.8.5, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 4d4b61af94 259/273: gptel-transient: More robust dry-run commands, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 70889ad95c 263/273: gptel-gemini: Add Gemini 1.5 (#284), ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 4273f067e8 271/273: gptel-org: Improve stream converter, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel c319966997 272/273: gptel-org: Further improve stream converter, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 040baad910 034/273: gptel: Remove aio dependency, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 1828dd3fa4 050/273: gptel: Set "waiting" state after sending the prompt, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel c9795fe9e8 060/273: gptel: org support for streaming WIP,
ELPA Syncer <=
- [nongnu] elpa/gptel 644fc1de2f 118/273: gptel-transient: Handle empty input when setting temperature, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 3c01477c37 129/273: gptel: api-key shenanigans, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 644e341244 141/273: Add multiline prefixes & AI response prefixes (#142), ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel a202911009 148/273: gptel: Add post-stream hook, scroll commands, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel c3ca4fd0a0 158/273: gptel-transient: Set suffix-state explicitly for directives, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 0fce1d86d1 171/273: README: fix typo (#168), ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel 92a8c0bdac 183/273: gptel: letrec expansion error in Emacs 27.2, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel b34e217bbf 182/273: README: Mention gptel-request, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel d2f56c62a0 193/273: gptel-transient: Allow redirection to any buffer, ELPA Syncer, 2024/05/01
- [nongnu] elpa/gptel bf994c0765 204/273: gptel: Add response regeneration, history and ediff, ELPA Syncer, 2024/05/01