1
0
Fork 0

Merge branch 'interactive-lang-engine-choice'

This commit is contained in:
Bram Schoenmakers 2024-01-15 16:35:47 +01:00
commit f054879d37
Signed by: bram
GPG key ID: 0CCD19DFDC63258F
2 changed files with 200 additions and 75 deletions

View file

@ -27,11 +27,16 @@ The FastGPT functionality has only one command: =kagi-fastgpt-shell=. This opens
** Universal Summarizer
- =kagi-summarize-buffer= :: Summarizes the content of a buffer and displays it in a separate buffer.
- =kagi-summarize-region= :: Similarly, the text inside the region is summarized and shown in a separate buffer.
- =kagi-summarize-buffer= :: Summarizes the content of a buffer.
- =kagi-summarize-region= :: Similarly, the text inside the region is summarized.
- =kagi-summarize-url= :: Prompts for a URL of which a summary is composed and displayed.
- =kagi-summarize= :: Function to retrieve a summary from a text or URL, to be used from Lisp code.
The summarize commands accept a single universal prefix, which allows you to:
- insert the summary at point;
- choose a (different) target language;
- choose which summary engine to use.
Note that texts submitted to Kagi are subject to their [[https://kagi.com/privacy#Summarizer][Privacy Policy]].
* Installation and configuration
@ -116,6 +121,8 @@ The code to generate the table of configuration items was inspired by an idea of
** Examples of custom functions
The =kagi-summarize= function allows you to summarize texts or URLs from Emacs Lisp.
By overriding a variable with a =let= construct you can (temporarily) deviate from the default / configured value. A few examples are shown below:
*** Language override
@ -129,6 +136,8 @@ To obtain a Dutch summary of a video you may want to define the following functi
(kagi-summarize text-or-url)))
#+end_src
Note that, when you invoke the summarizer functionality interactively, you can also temporarily choose a different target language with the universal prefix (=C-u=) on one of the =kagi-summarize-*= commands.
*** Caching override
The [[https://help.kagi.com/kagi/api/summarizer.html][Summarizer API]] comes with the following note:
@ -184,6 +193,16 @@ If you recognize this confusion, you may want to add the following line to your
* Changelog
** 0.3pre
*** New
The summarizer commands =kagi-summarize-*= now accept a universal prefix. This allows you to:
- insert the summary at point (instead of a separate buffer);
- choose a different target language;
- choose a different summarizer engine.
** 0.2
*** Breaking changes

252
kagi.el
View file

@ -81,57 +81,63 @@ on dummy data."
:type '(choice string function)
:group 'kagi)
(defvar kagi--summarizer-engines
'(("agnes" . "Friendly, descriptive, fast summary.")
("cecil" . "Formal, technical, analytical summary.")
("daphne" . "Informal, creative, friendly summary.")
("muriel" . "Best-in-class summary using Kagi's enterprise-grade model (at different pricing)."))
"List of Kagi Summarizer engines.
See `kagi-summarizer-engine' for a brief description per engine.")
(defcustom kagi-summarizer-engine "cecil"
"Which summary engine to use.
- cecil :: Friendly, descriptive, fast summary.
- agnes :: Formal, technical, analytical summary.
- daphne :: Informal, creative, friendly summary.
- muriel :: Best-in-class summary using Kagi's enterprise-grade model.
Note that the muriel model is enterprise grade and has different
pricing. Refer to the API documentation for more info at
https://help.kagi.com/kagi/api/summarizer.html."
:type '(choice
(const "agnes")
(const "cecil")
(const "daphne")
(const "muriel"))
:type (append '(choice)
(mapcar (lambda (engine) `(const :doc ,(cdr engine) ,(car engine)))
kagi--summarizer-engines))
:group 'kagi)
(defvar kagi--summarizer-languages '(("Document language" . nil)
("Bulgarian [BG]" . "BG")
("Czech [CZ]" . "CZ")
("Danish [DA]" . "DA")
("German [DE]" . "DE")
("Greek [EL]" . "EL")
("English [EN]" . "EN")
("Spanish [ES]" . "ES")
("Estonian [ET]" . "ET")
("Finnish [FI]" . "FI")
("French [FR]" . "FR")
("Hungarian [HU]" . "HU")
("Indonesian [ID]" . "ID")
("Italian [IT]" . "IT")
("Japanese [JA]" . "JA")
("Korean [KO]" . "KA")
("Lithuanian [LT]" . "LT")
("Latvian [LV]" . "LV")
("Norwegian [NB]" . "NB")
("Dutch [NL]" . "NL")
("Polish [PL]" . "PL")
("Portuguese [PT]" . "PT")
("Romanian [RO]" . "RO")
("Russian [RU]" . "RU")
("Slovak [SK]" . "SK")
("Slovenian [SL]" . "SL")
("Swedish [SV]" . "SV")
("Turkish [TR]" . "TR")
("Ukrainian [UK]" . "UK")
("Chinese (simplified) [ZH]" . "ZH"))
"Supported languages by the Kagi Universal Summarizer.")
(defcustom kagi-summarizer-default-language nil
"Default target language of the summary."
:type '(choice
(const :tag "Document language" nil)
(const :tag "Bulgarian" "BG")
(const :tag "Czech" "CZ")
(const :tag "Danish" "DA")
(const :tag "German" "DE")
(const :tag "Greek" "EL")
(const :tag "English" "EN")
(const :tag "Spanish" "ES")
(const :tag "Estonian" "ET")
(const :tag "Finnish" "FI")
(const :tag "French" "FR")
(const :tag "Hungarian" "HU")
(const :tag "Indonesian" "ID")
(const :tag "Italian" "IT")
(const :tag "Japanese" "JA")
(const :tag "Korean" "KO")
(const :tag "Lithuanian" "LT")
(const :tag "Latvian" "LV")
(const :tag "Norwegian" "NB")
(const :tag "Dutch" "NL")
(const :tag "Polish" "PL")
(const :tag "Portuguese" "PT")
(const :tag "Romanian" "RO")
(const :tag "Russian" "RU")
(const :tag "Slovak" "SK")
(const :tag "Slovenian" "SL")
(const :tag "Swedish" "SV")
(const :tag "Turkish" "TR")
(const :tag "Ukrainian" "UK")
(const :tag "Chinese (simplified)" "ZH"))
:type (append '(choice)
(mapcar (lambda (lang) `(const :tag ,(car lang) ,(cdr lang)))
kagi--summarizer-languages))
:group 'kagi)
(defcustom kagi-summarizer-cache t
@ -307,7 +313,6 @@ list of conses."
(when kagi-summarizer-default-language
`(("target_language" . ,kagi-summarizer-default-language)))))
(defconst kagi--summarizer-min-input-words 50
"The minimal amount of words that the text input should have.")
@ -339,6 +344,11 @@ list of conses."
(text-mode)
(display-buffer buffer-name)))
(defun kagi--insert-summary (summary)
"Insert the SUMMARY at point."
(save-excursion
(insert (substring-no-properties summary))))
(defun kagi--process-prompt (prompt)
"Submit a PROMPT to FastGPT and process the API response.
@ -397,45 +407,135 @@ Returns a formatted string to be displayed by the shell."
(string-match-p (rx (seq bos "http" (? "s") "://" (+ (not space)) eos)) s))
;;;###autoload
(defun kagi-summarize (text-or-url)
"Return the summary of the given TEXT-OR-URL."
(if-let* ((response (if (kagi--url-p text-or-url)
(kagi--call-url-summarizer text-or-url)
(kagi--call-text-summarizer text-or-url)))
(parsed-response (json-parse-string response))
(output (kagi--gethash parsed-response "data" "output")))
(kagi--format-output output)
(if-let ((firsterror (aref (kagi--gethash parsed-response "error") 0)))
(error (format "%s (%s)"
(gethash "msg" firsterror)
(gethash "code" firsterror)))
(error "An error occurred while requesting a summary"))))
(defun kagi-summarize (text-or-url &optional language engine)
"Return the summary of the given TEXT-OR-URL.
LANGUAGE is a supported two letter abbreviation of the language,
as defined in `kagi--summarizer-languages'. When nil, the target
is automatically determined.
ENGINE is the name of a supported summarizer engine, as
defined in `kagi--summarizer-engines'."
(let* ((kagi-summarizer-default-language
(upcase (or language kagi-summarizer-default-language)))
(kagi-summarizer-engine
(downcase (or engine kagi-summarizer-engine))))
(if-let* ((response (if (kagi--url-p text-or-url)
(kagi--call-url-summarizer text-or-url)
(kagi--call-text-summarizer text-or-url)))
(parsed-response (json-parse-string response))
(output (kagi--gethash parsed-response "data" "output")))
(kagi--format-output output)
(if-let ((firsterror (aref (kagi--gethash parsed-response "error") 0)))
(error (format "%s (%s)"
(gethash "msg" firsterror)
(gethash "code" firsterror)))
(error "An error occurred while requesting a summary")))))
(defun kagi--get-summarizer-parameters (&optional prompt-insert-p)
"Return a list of interactively obtained summarizer parameters.
Not all commands need to insert a summary, so only prompt for
this when PROMPT-INSERT-P is non-nil."
(append
(list
(and prompt-insert-p
(equal current-prefix-arg '(4))
(y-or-n-p "Insert summary at point?")))
(list
(when (equal current-prefix-arg '(4))
(alist-get
(completing-read (format-prompt "Output language" "")
kagi--summarizer-languages nil t)
kagi--summarizer-languages
(or kagi-summarizer-default-language "EN")
nil
#'string=)))
(list
(when (equal current-prefix-arg '(4))
(completing-read (format-prompt "Engine" "")
kagi--summarizer-engines nil t kagi-summarizer-engine)))))
;;;###autoload
(defun kagi-summarize-buffer (buffer)
"Summarize the BUFFER's content and show it in a new window."
(interactive "b")
(with-current-buffer buffer
(kagi--display-summary
(kagi-summarize (buffer-string))
(kagi--summary-buffer-name (buffer-name)))))
(defun kagi-summarize-buffer (buffer &optional insert language engine)
"Summarize the BUFFER's content and show it in a new window.
By default, the summary is shown in a new buffer.
When INSERT is non-nil, the summary will be inserted at point. In
case the current buffer is read-only, the summary will be shown
in a separate buffer anyway.
LANGUAGE is a supported two letter abbreviation of the language,
as defined in `kagi--summarizer-languages'. When nil, the target
is automatically determined.
ENGINE is the name of a supported summarizer engine, as
defined in `kagi--summarizer-engines'.
With a single universal prefix argument (`C-u'), the user is
prompted whether the summary has to be inserted at point, which
target LANGUAGE to use and which summarizer ENGINE to use."
(interactive (cons
(read-buffer (format-prompt "Buffer" "") nil t)
(kagi--get-summarizer-parameters t)))
(let ((summary (with-current-buffer buffer
(kagi-summarize (buffer-string) language engine)))
(summary-buffer-name (with-current-buffer buffer
(kagi--summary-buffer-name (buffer-name)))))
(if (and insert (not buffer-read-only))
(kagi--insert-summary summary)
(kagi--display-summary summary summary-buffer-name))))
;;;###autoload
(defun kagi-summarize-region (begin end)
(defun kagi-summarize-region (begin end &optional language engine)
"Summarize the region's content marked by BEGIN and END positions.
Shows the summary in a new window."
(interactive "r")
The summary is always shown in a new buffer.
LANGUAGE is a supported two letter abbreviation of the language,
as defined in `kagi--summarizer-languages'. When nil, the target
is automatically determined.
ENGINE is the name of a supported summarizer engine, as
defined in `kagi--summarizer-engines'.
With a single universal prefix argument (`C-u'), the user is
prompted for which target LANGUAGE to use and which summarizer
ENGINE to use."
(interactive (append
(list (region-beginning) (region-end))
(kagi--get-summarizer-parameters)))
(kagi--display-summary
(kagi-summarize (buffer-substring-no-properties begin end))
(kagi-summarize (buffer-substring-no-properties begin end)
language
engine)
(kagi--summary-buffer-name (buffer-name))))
;;;###autoload
(defun kagi-summarize-url (url)
(defun kagi-summarize-url (url &optional insert language engine)
"Show the summary of the content behind the given URL.
According to the API documentation, the following media types are
supported:
By default, the summary is shown in a new buffer.
When INSERT is non-nil, the summary will be inserted at point. In
case the current buffer is read-only, the summary will be shown
in a separate buffer anyway.
LANGUAGE is a supported two letter abbreviation of the language,
as defined in `kagi--summarizer-languages'. When nil, the target
is automatically determined.
ENGINE is the name of a supported summarizer engine, as
defined in `kagi--summarizer-engines'.
With a single universal prefix argument (`C-u'), the user is
prompted whether the summary has to be inserted at point, which
target LANGUAGE to use and which summarizer ENGINE to use.
According to the Kagi API documentation, the following media
types are supported:
- Text web pages, articles, and forum threads
- PDF documents (.pdf)
@ -444,10 +544,16 @@ supported:
- Audio files (mp3/wav)
- YouTube URLs
- Scanned PDFs and images (OCR)"
(interactive "sURL: ")
(kagi--display-summary
(kagi-summarize url)
(kagi--summary-buffer-name (kagi--get-domain-name url))))
(interactive
(cons
(read-string (format-prompt "URL" ""))
(kagi--get-summarizer-parameters t)))
(let ((summary (kagi-summarize url language engine)))
(if (and insert (not buffer-read-only))
(kagi--insert-summary summary)
(kagi--display-summary
summary
(kagi--summary-buffer-name (kagi--get-domain-name url))))))
(provide 'kagi)