kagi.el README
**************

1 Introduction
**************

This Emacs package provides the following functionalities from the Kagi
search engine (https://www.kagi.com):

FastGPT
     Kagi's LLM offering, as a shell inspired by xenodium's
     chatgpt-shell (https://github.com/xenodium/chatgpt-shell).
Universal Summarizer
     Summarizes texts, webpages, videos, and more.

   Both functions are accessed through Kagi's APIs
(https://help.kagi.com/kagi/api/overview.html).  Before a call can be
made, some setup should be done on the Kagi website (see below).

2 Commands and functions
************************

2.1 FastGPT
===========

‘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.  This function can also be used from Lisp code.

   kagi.el has some functions that use FastGPT to perform certain
operations on text:

‘kagi-translate’
     Translates strings or complete buffers to another language
     (including programming languages).
‘kagi-proofread’
     Proofreads a string or buffer.
‘kagi-fastgpt-prompt-definition’
     Returns the definition of a word.

2.2 Universal Summarizer
========================

‘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;
   • choose which summary format to use (prose or bullet list);
   • opt-out from caching at Kagi for confidential content.

   Note that texts submitted to Kagi are subject to their Privacy Policy
(https://kagi.com/privacy#Summarizer).

3 Installation and configuration
********************************

kagi.el is available on MELPA (https://melpa.org/#/kagi) and MELPA
Stable (https://stable.melpa.org/#/kagi).

   To install from Git, clone with:

     git clone https://codeberg.org/bram85/kagi.el.git /path/to/kagi.el

   kagi.el has two dependencies (both available on MELPA):
   • markdown-mode (https://melpa.org/#/markdown-mode) to apply
     formatting of the Markdown responses in FastGPT;
   • shell-maker (https://melpa.org/#/shell-maker) to provide a shell
     interface for FastGPT.

   You may want to load and configure the package with ‘use-package’,
for example put the following in your Emacs init file:

     (use-package kagi
       :ensure t
       :custom
       (kagi-api-token "ABCDEF")
       ;; or use a function, e.g. with the password-store package:
       (kagi-api-token (lambda () (password-store-get "Kagi/API")))

       ;; Universal Summarizer settings
       (kagi-summarizer-engine "cecil")
       (kagi-summarizer-default-language "EN")
       (kagi-summarizer-cache t))

   The API token can be supplied directly as a string, but you could
write a lambda to retrieve the token from a more secure location (e.g.
with the combination of pass(1) (https://passwordstore.org/) and the
_password-store_ package that comes with it).

3.1 Kagi API setup
==================

In order to use the Kagi API, follow these steps:

  1. Create a Kagi account at kagi.com (https://www.kagi.com) if you
     haven't done so already.  An account is free, and comes with 100
     trial searches.
  2. In your account settings (https://kagi.com/settings?p=billing_api),
     put a balance for the API part (note that this is a separate
     balance than the subscription).  The recommendation is to start
     with a one-time charge of $5.  Check the pricing for the FastGPT
     API (https://help.kagi.com/kagi/api/fastgpt.html#pricing) and the
     Summarizer API
     (https://help.kagi.com/kagi/api/summarizer.html#pricing) for the
     actual costs.
  3. In the API portal (https://kagi.com/settings?p=api), create an API
     token.  Put the result in ‘kagi-api-token’ (or write a function to
     access it securely).

3.2 Configuration settings
==========================

Custom variable                          Description
---------------------------------------------------------------------------------------------------
kagi-api-token                           The Kagi API token.
kagi-fastgpt-api-url                     The Kagi FastGPT API entry point.
kagi-fastgpt-welcome-function            A function returning a welcome string.
kagi-summarizer-api-url                  The Kagi Summarizer API entry point.
kagi-summarizer-cache                    Determines whether the Summarizer should cache results.
kagi-summarizer-default-language         Default target language of the summary.
kagi-summarizer-default-summary-format   The summary format that should be returned.
kagi-summarizer-engine                   Which summary engine to use.

3.3 Defining your own prompts
=============================

kagi.el comes with a macro to define your own prompts easily:
‘define-kagi-fastgpt-prompt’.  When the prompt contains the placeholder
‘%s’, it will be replaced with the region or an interactively used word.

   An example usage of this macro comes by default with this package:

     (define-kagi-fastgpt-prompt kagi-fastgpt-prompt-definition
                                 "Define the following word: %s"
                                 "Definition")

   The first argument is the name of the command that will be defined.
The second argument the prompt that will be sent.  The third argument is
optional and gives your prompt a user-visible name.  It will be shown
when calling ‘kagi-fastgpt-prompt’ interactively.

   The defined prompt becomes a typical Emacs command that takes one
argument to fill the placeholder.  You could bind the prompt command to
a key, use it to integrate with Embark (see below) or to list all your
prompts with a Hydra.

   The prompt string may also be a function that returns the prompt
string.  The function may take one argument: whether the command was
called interactively or not.  This can be used to alter the prompt based
on how the command was called.  E.g.  a non-interactive version could
contain an instruction to say either _Yes_ or _No_.  See
‘kagi-proofread’ for an example:

     (define-kagi-fastgpt-prompt kagi-proofread
                                 (lambda (interactive-p)
                                   (format "Proofread the following text. %s

     %%s" (if interactive-p "" "Say OK if there are no issues.")))
                                 "Proofread")

   Note the ‘%%s’ notation, ‘format’ turns it into ‘%s’ which becomes
the prompt placeholder.

3.4 Org Babel support
=====================

‘kagi-fastgpt-prompt’ can also be used from Org mode with source blocks.
Make sure to initialize the package as described below.

   With ‘use-package’:

     (use-package ob-kagi-fastgpt
       :ensure nil  ; provided by the kagi package
       :after org
       :config
       (ob-kagi-fastgpt-setup))

   Or, without ‘use-package’:

     (require 'ob-kagi-fastgpt)
     (ob-kagi-fastgpt-setup)

   Then create a source block with 'language' ‘kagi-fastgpt’:

     #+begin_src kagi-fastgpt
       Can Kagi FastGPT be used in Org mode?
     #+end_src

   Press ‘C-c C-c’ (‘org-babel-execute-src-block’) inside this block to
obtain the result below the prompt.  By default, the responses are
cached in your document; the same prompt text won't trigger a second API
request.  Use the header argument ‘:cache no’ to refresh the response
for each block execution.

3.5 Embark integration
======================

The kagi.el package can be integrated with Embark
(https://github.com/oantolin/embark).  Use it to easily summarize,
translate or proofread a buffer, region or a URL.  It can also be used
to call your custom prompts with ‘define-kagi-fastgpt-prompt’.

   In order to be consistent with all keymaps, and to avoid clashes, the
functionality is behind the _K_ prefix key.  For example, press _K s_ to
invoke the summarize functionality.

     (defmacro embark-kagi-map (name &rest keys)
       "Macro for defining a keymap for accessing Kagi functionality through Embark."
       `(defvar-keymap ,name
          :doc "Keymap for accessing Kagi functionality with Embark."
          :parent nil
          ,@keys))

     (embark-kagi-map embark-kagi-buffer-map
                      "p" #'kagi-proofread
                      "s" #'kagi-summarize-buffer
                      "t" #'kagi-translate)
     (keymap-set embark-buffer-map "K" embark-kagi-buffer-map)

     (embark-kagi-map embark-kagi-region-map
                      "d" #'kagi-fastgpt-prompt-definition
                      "p" #'kagi-proofread
                      "s" #'kagi-summarize-region
                      "t" #'kagi-translate)
     (keymap-set embark-region-map "K" embark-kagi-region-map)

     (embark-kagi-map embark-kagi-url-map
                      "s" #'kagi-summarize-url)
     (keymap-set embark-url-map "K" embark-kagi-url-map)

3.6 FastGPT shell key bindings
==============================

Since the FastGPT shell inherits from ‘comint-mode’ indirectly, many key
bindings are also inherited.  Enter the ‘help’ command in the shell to
get more info, or run ‘describe-keymap’ on ‘fastgpt-shell-mode-map’.

   One of those bindings is ‘C-c C-o’, which flushes the last output.
However, this binding is used in ‘org-mode’ to open a URL an point.
Typical FastGPT results include URLs, so one may be tempted to type ‘C-c
C-o’ to browse the URL, only to have the output erased (which you can
undo, actually).

   If you recognize this confusion, you may want to add the following
line to your configuration file to shadow the ‘comint-mode’ binding with
something more appropriate:

     (add-hook 'fastgpt-shell-mode-hook
               (lambda ()
                 (keymap-set fastgpt-shell-mode-map "C-c C-o" #'browse-url-at-point)))

   Because the ‘fastgpt-shell-mode-map’ only becomes available when
‘kagi-fastgpt-shell’ has been invoked, the keybinding is done in a mode
hook.

4 Development
*************

kagi.el comes with some unit tests, written with buttercup
(https://github.com/jorgenschaefer/emacs-buttercup/) and can be executed
in a controlled Cask (https://github.com/cask/cask/) environment:

  1. ‘git clone https://github.com/cask/cask/’
  2. ‘make -C cask install’
  3. Run ‘cask’ in the kagi.el directory to setup the environment.
  4. Run the tests with ‘cask exec buttercup -L .’

   There's also a justfile (https://github.com/casey/just) which allows
you to execute ‘just test’ to compile the Emacs Lisp source and run the
unit tests afterwards in one go.

   Needless to say, the tests won't make actual API calls.  Otherwise it
wouldn't be unit tests.

5 Changelog
***********

The full changelog can be found in README.org.

5.1 0.6pre
==========

5.1.1 Breaking changes
----------------------

   • Obsoleted faces ‘kagi-bold’, ‘kagi-italic’ and ‘kagi-code’ in favor
     of formatting by markdown-mode.

5.1.2 New
---------

   • Full support for markdown syntax returned by FastGPT, by using the
     markdown-mode (https://github.com/jrblevin/markdown-mode) package.
   • Show a welcome message when starting the FastGPT shell
     (‘kagi-fastgpt-shell’).  This can be customized with
     ‘kagi-fastgpt-welcome-function’, a variable with a function that
     returns a welcome string.

5.1.3 Fixes
-----------

   • Prompts defined with ‘define-kagi-fastgpt-prompt’ wouldn't always
     work when expanding ‘%s’ placeholders (possibly resulting in ‘Lisp
     error: (args-out-of-range 0 7)’).

5.1.4 Misc
----------

   • Minor refactoring in the code calling the FastGPT API.

5.2 0.5
=======

5.2.1 Breaking changes
----------------------

   • Removed function ‘kagi-fastgpt’ as announced in the 0.4 changelog.

5.2.2 New
---------

   • The ‘define-kagi-fastgpt-prompt’ macro allows you to define your
     own prompts, that may contain a placeholder to fill in relevant
     text.

   • The macro is used to (re)define commands:
        • ‘kagi-fastgpt-prompt-definition’: Define the a word.
        • ‘kagi-proofread’ is now defined with the macro.

   • Org Babel support was added.

   • ‘kagi-summarize’ has a ‘no-cache’ parameter to opt out from caching
     at Kagi's side.

   • ‘kagi-summarize-buffer’ and ‘kagi-summarize-region’ also have a
     ‘no-cache’ parameter which can be toggled interactively when called
     with the universal prefix.

   • Add support for traditional Chinese as a possible summary language.

5.2.3 Fixes
-----------

   • Changed ‘kagi-proofread’ to get more useful results.
   • Fixed language code for Czech summaries.
   • Handle error responses when calling the FastGPT API.

6 References
************

   • Kagi FastGPT API (https://help.kagi.com/kagi/api/fastgpt.html)
   • Kagi Universal Summarizer API
     (https://help.kagi.com/kagi/api/summarizer.html)
   • xenodium's chatgpt-shell
     (https://github.com/xenodium/chatgpt-shell), which also provides
     shell-maker required by the FastGPT shell.

7 Contact
*********

   • Issue reports: Codeberg
     (https://codeberg.org/bram85/kagi.el/issues)
   • Mastodon: @bram85@emacs.ch (https://emacs.ch/@bram85)
   • Mail: see ‘git log’.