1
0
Fork 0

Merge branch 'translate'

This commit is contained in:
Bram Schoenmakers 2024-01-26 18:02:55 +01:00
commit f9fd1d294a
Signed by: bram
GPG key ID: 0CCD19DFDC63258F
2 changed files with 134 additions and 47 deletions

View file

@ -23,7 +23,10 @@ Both functions are accessed through an [[https://help.kagi.com/kagi/api/overview
** FastGPT ** FastGPT
The FastGPT functionality has only one command: =kagi-fastgpt-shell=. This opens a shell buffer in a new window where prompts can be typed. Kagi FastGPT typically returns output based on actual search results. When point is on one of the listed URLs, press =C-c RET= to open it. - =kagi-fastgpt-shell= :: Opens a shell buffer in a new window where prompts can be typed. This Kagi FastGPT typically returns output based on actual search results. When point is on one of the listed URLs, press =C-c RET= to open it.
- =kagi-fastgpt-prompt= :: Enter a prompt in the minibuffer and show the result in a separate buffer. With a universal prefix (=C-u=), the result is inserted at point.
- =kagi-fastgpt= :: Function to retrieve a FastGPT response, to be used from Lisp code.
- =kagi-translate= :: This command translates strings or complete buffers to another language (including programming languages).
** Universal Summarizer ** Universal Summarizer

168
kagi.el
View file

@ -101,42 +101,54 @@ https://help.kagi.com/kagi/api/summarizer.html."
kagi--summarizer-engines)) kagi--summarizer-engines))
:group 'kagi) :group 'kagi)
(defvar kagi--summarizer-languages '(("Document language" . nil) (defvar kagi--languages '(("Bulgarian" . "BG")
("Bulgarian [BG]" . "BG") ("Czech" . "CZ")
("Czech [CZ]" . "CZ") ("Danish" . "DA")
("Danish [DA]" . "DA") ("German" . "DE")
("German [DE]" . "DE") ("Greek" . "EL")
("Greek [EL]" . "EL") ("English" . "EN")
("English [EN]" . "EN") ("Spanish" . "ES")
("Spanish [ES]" . "ES") ("Estonian" . "ET")
("Estonian [ET]" . "ET") ("Finnish" . "FI")
("Finnish [FI]" . "FI") ("French" . "FR")
("French [FR]" . "FR") ("Hungarian" . "HU")
("Hungarian [HU]" . "HU") ("Indonesian" . "ID")
("Indonesian [ID]" . "ID") ("Italian" . "IT")
("Italian [IT]" . "IT") ("Japanese" . "JA")
("Japanese [JA]" . "JA") ("Korean" . "KO")
("Korean [KO]" . "KO") ("Lithuanian" . "LT")
("Lithuanian [LT]" . "LT") ("Latvian" . "LV")
("Latvian [LV]" . "LV") ("Norwegian" . "NB")
("Norwegian [NB]" . "NB") ("Dutch" . "NL")
("Dutch [NL]" . "NL") ("Polish" . "PL")
("Polish [PL]" . "PL") ("Portuguese" . "PT")
("Portuguese [PT]" . "PT") ("Romanian" . "RO")
("Romanian [RO]" . "RO") ("Russian" . "RU")
("Russian [RU]" . "RU") ("Slovak" . "SK")
("Slovak [SK]" . "SK") ("Slovenian" . "SL")
("Slovenian [SL]" . "SL") ("Swedish" . "SV")
("Swedish [SV]" . "SV") ("Turkish" . "TR")
("Turkish [TR]" . "TR") ("Ukrainian" . "UK")
("Ukrainian [UK]" . "UK") ("Chinese (simplified)" . "ZH"))
("Chinese (simplified) [ZH]" . "ZH")) "Supported languages by the Kagi LLM.")
(defvar kagi--summarizer-languages (append
'(("Document language" . nil)
kagi--languages))
"Supported languages by the Kagi Universal Summarizer.") "Supported languages by the Kagi Universal Summarizer.")
(defvar kagi--language-history nil)
(defcustom kagi-summarizer-default-language nil (defcustom kagi-summarizer-default-language nil
"Default target language of the summary." "Default target language of the summary.
The value should be a string of two characters representing the
language. See variable `kagi--summarizer-languages' for the list
of language codes."
:type (append '(choice) :type (append '(choice)
(mapcar (lambda (lang) `(const :tag ,(car lang) ,(cdr lang))) (mapcar (lambda (lang)
`(const :tag ,(format "%s [%s]" (car lang) (cdr lang))
,(cdr lang)))
kagi--summarizer-languages)) kagi--summarizer-languages))
:group 'kagi) :group 'kagi)
@ -343,8 +355,7 @@ list of conses."
(defun kagi--display-summary (summary buffer-name) (defun kagi--display-summary (summary buffer-name)
"Display the SUMMARY in a buffer called BUFFER-NAME." "Display the SUMMARY in a buffer called BUFFER-NAME."
(with-current-buffer (get-buffer-create buffer-name) (with-current-buffer (generate-new-buffer-name buffer-name)
(erase-buffer)
(insert summary) (insert summary)
(goto-char 0) (goto-char 0)
(text-mode) (text-mode)
@ -355,16 +366,23 @@ list of conses."
(save-excursion (save-excursion
(insert (substring-no-properties summary)))) (insert (substring-no-properties summary))))
(defun kagi--process-prompt (prompt) (defun kagi-fastgpt (prompt)
"Submit a PROMPT to FastGPT and process the API response. "Submit a PROMPT to FastGPT and return a formatted response string."
Returns a formatted string to be displayed by the shell."
(let* ((response (kagi--call-fastgpt prompt)) (let* ((response (kagi--call-fastgpt prompt))
(parsed-response (json-parse-string response)) (parsed-response (json-parse-string response))
(output (kagi--gethash parsed-response "data" "output")) (output (kagi--gethash parsed-response "data" "output"))
(references (kagi--gethash parsed-response "data" "references"))) (references (kagi--gethash parsed-response "data" "references")))
(format "%s\n\n%s" (kagi--format-output output) (kagi--format-references references)))) (format "%s\n\n%s" (kagi--format-output output) (kagi--format-references references))))
(defun kagi--fastgpt-display-result (result)
"Display the RESULT of a FastGPT prompt in a new buffer."
(let ((buffer-name (generate-new-buffer-name "*fastgpt-result*")))
(with-current-buffer (get-buffer-create buffer-name)
(save-excursion
(insert result))
(text-mode)
(display-buffer buffer-name))))
(defvar kagi-fastgpt--config (defvar kagi-fastgpt--config
(make-shell-maker-config (make-shell-maker-config
:name "FastGPT" :name "FastGPT"
@ -372,7 +390,7 @@ Returns a formatted string to be displayed by the shell."
:execute-command :execute-command
(lambda (command _history callback error-callback) (lambda (command _history callback error-callback)
(condition-case err (condition-case err
(funcall callback (kagi--process-prompt command) nil) (funcall callback (kagi-fastgpt-prompt command) nil)
(json-parse-error (funcall error-callback (json-parse-error (funcall error-callback
(format "Could not parse the server response %s" (cdr err)))) (format "Could not parse the server response %s" (cdr err))))
(error (funcall error-callback (format "An error occurred during the request %s" (cdr err))))))) (error (funcall error-callback (format "An error occurred during the request %s" (cdr err)))))))
@ -386,6 +404,67 @@ Returns a formatted string to be displayed by the shell."
(interactive) (interactive)
(shell-maker-start kagi-fastgpt--config)) (shell-maker-start kagi-fastgpt--config))
;;;###autoload
(defun kagi-fastgpt-prompt (prompt &optional insert)
"Feed the given PROMPT to FastGPT.
If INSERT is non-nil, the response is inserted at point.
Otherwise, show the result in a separate buffer."
(interactive "sfastgpt> \nP")
(let ((result (kagi-fastgpt prompt)))
(if (and insert (not buffer-read-only))
(save-excursion
(insert result))
(kagi--fastgpt-display-result result))))
(defun kagi--read-language (prompt)
"Read a language from the minibuffer interactively.
PROMPT is passed to the corresponding parameters of
`completing-read', refer to its documentation for more info."
(completing-read prompt kagi--languages
nil
nil
nil
kagi--language-history
"English"))
(defun kagi-translate (text target-language &optional source-language interactive-p)
"Translate the TEXT to TARGET-LANGUAGE using FastGPT.
With a single universal prefix, also prompt for the SOURCE-LANGUAGE.
When INTERACTIVE-P is nil, the translation is returned as a string.
When non-nil, the translation is shown in the echo area when the
result is short, otherwise it is displayed in a new buffer."
(interactive
(list (if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(let ((buffer-or-text (read-buffer (format-prompt "Buffer name or text" nil))))
(cond ((get-buffer buffer-or-text)
(with-current-buffer buffer-or-text
(buffer-string)))
((< 0 (length buffer-or-text)) buffer-or-text)
(t (error "No buffer or text entered")))))
(kagi--read-language (format-prompt "Target language" nil))
(when (equal current-prefix-arg '(4))
(kagi--read-language (format-prompt "Source language" nil)))
t))
(let* ((prompt (format "Translate the following text %sto %s:
%s"
(if source-language
(format "from %s " source-language)
"")
target-language
text))
(result (string-trim (kagi-fastgpt prompt)))
(result-lines (length (string-lines result))))
(cond ((and interactive-p (eql result-lines 1)) (message result))
((and interactive-p (> result-lines 1)) (kagi--fastgpt-display-result result))
(t result))))
;;; Summarizer ;;; Summarizer
(defun kagi--get-domain-name (url) (defun kagi--get-domain-name (url)
@ -456,13 +535,18 @@ this when PROMPT-INSERT-P is non-nil."
(y-or-n-p "Insert summary at point?"))) (y-or-n-p "Insert summary at point?")))
(list (list
(when (equal current-prefix-arg '(4)) (when (equal current-prefix-arg '(4))
(let ((language-table (mapcar (lambda (lang)
(cons
(format "%s [%s]" (car lang) (cdr lang))
(cdr lang)))
kagi--summarizer-languages)))
(alist-get (alist-get
(completing-read (format-prompt "Output language" "") (completing-read (format-prompt "Output language" "")
kagi--summarizer-languages nil t) language-table nil t nil kagi--language-history)
kagi--summarizer-languages language-table
(or kagi-summarizer-default-language "EN") (or kagi-summarizer-default-language "EN")
nil nil
#'string=))) #'string=))))
(list (list
(when (equal current-prefix-arg '(4)) (when (equal current-prefix-arg '(4))
(completing-read (format-prompt "Engine" "") (completing-read (format-prompt "Engine" "")