[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/ellama 3bd6acccd3 02/53: begin ellama implementation
From: |
ELPA Syncer |
Subject: |
[elpa] externals/ellama 3bd6acccd3 02/53: begin ellama implementation |
Date: |
Sun, 17 Dec 2023 18:57:56 -0500 (EST) |
branch: externals/ellama
commit 3bd6acccd3ec203e7b7fdb28b11cbfd7ad33d217
Author: Sergey Kostyaev <s.kostyaev@omp.ru>
Commit: Sergey Kostyaev <s.kostyaev@omp.ru>
begin ellama implementation
---
ellama.el | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 246 insertions(+)
diff --git a/ellama.el b/ellama.el
new file mode 100644
index 0000000000..7320e737ae
--- /dev/null
+++ b/ellama.el
@@ -0,0 +1,246 @@
+;;; ellama.el --- Ollama client
+
+;; Copyright (C) 2023 Sergey Kostyaev
+
+;; Author: Sergey Kostyaev <sskostyaev@gmail.com>
+;; URL: http://github.com/s-kostyaev/ellama
+;; Keywords: help local tools
+;; Package-Requires: ((emacs "27.1"))
+;; Version: 0.1.0
+;; Created: 8th Oct 2023
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Ellama is ollama client for Emacs
+;;
+
+;;; Code:
+
+(require 'json)
+
+(defgroup ellama nil
+ "Ollama client for Emacs."
+ :group 'ellama)
+
+(defcustom ellama-url "http://localhost:11434/api/generate" "Url to call
ollama."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-curl-executable (executable-find "curl") "Path to curl
executable."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-model "mistral" "Model to use ollama with."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-buffer "*ellama*" "Default ellama buffer."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-always-show-buffer nil "Always show ellama buffer."
+ :group 'ellama
+ :type 'boolean)
+
+(defcustom ellama-user-nick "User" "User nick in logs."
+ :grop 'ellama
+ :type 'string)
+
+(defcustom ellama-assistant-nick "Ellama" "Assistant nick in logs."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-buffer-mode 'markdown-mode "Major mode for ellama logs."
+ :group 'ellama
+ :type 'function)
+
+(defcustom ellama-language "Russian" "Language for ellama translation."
+ :group 'ellama
+ :type 'string)
+
+(defcustom ellama-template nil "Template to use with ollama instead of
default."
+ :group 'ellama
+ :type 'string)
+
+(defvar ellama-context nil "Context that contains ellama conversation memory.")
+
+(defvar ellama--unprocessed-data nil)
+
+(defvar ellama--request nil)
+
+(make-local-variable 'ellama-context)
+(make-local-variable 'ellama--unprocessed-data)
+(make-local-variable 'ellama--request)
+
+(defun ellama--filter (proc string)
+ "Filter function for ellama curl process.
+Filter PROC output STRING."
+ (when (buffer-live-p (process-buffer proc))
+ (with-current-buffer (process-buffer proc)
+ (let ((moving (= (point) (process-mark proc))))
+ (save-excursion
+ ;; Insert the text, advancing the process marker.
+ (goto-char (process-mark proc))
+ (when ellama--unprocessed-data
+ (setq string (concat ellama--unprocessed-data string)))
+ (condition-case nil
+ (progn
+ (mapc (lambda (s)
+ (when-let ((data
+ (json-parse-string s :object-type 'plist)))
+ (when-let ((context (plist-get data :context)))
+ (setq ellama-context context))
+ (when-let ((response (plist-get data :response)))
+ (insert response))))
+ (split-string string "\n" t))
+ (setq ellama--unprocessed-data nil)
+ (set-marker (process-mark proc) (point))
+ (if moving (goto-char (process-mark proc))))
+ (error (setq ellama--unprocessed-data
+ (car (last (split-string string "\n" t)))))))))))
+
+(defun ellama-query (prompt &rest args)
+ "Query ellama for PROMPT.
+
+ARGS contains keys for fine control.
+
+:buffer BUFFER -- BUFFER is the buffer (or `buffer-name') to insert ollama
reply
+in. Default value is `ellama-buffer'.
+
+:display BOOL -- If BOOL, show BUFFER to user.
+Default value is `ellama-always-show-buffer'.
+
+:log BOOL -- If BOOL, show conversation between user and ellama, prefixed with
+nicks.
+
+:model MODEL -- MODEL that ollama should use to generate answer. Default value
+is `ellama-model'.
+
+:memory BOOL -- If BOOL, enable conversation memory.
+
+:system SYSTEM -- SYSTEM message for prompt MODEL. If not set, default value
+inside ollama will be used. May not work for some models, see
+https://github.com/jmorganca/ollama/issues/693 - :template can help you in that
+case.
+
+:temperature TEMPERATURE -- set MODEL temperature to TEMPERATURE. If not set,
+ default value inside ollama will be used.
+
+:template TEMPLATE -- TEMPLATE to use with ollama MODEL instead of ollama's
+default. Default value is `ellama-template'."
+ (let ((buffer (or (plist-get args :buffer) ellama-buffer))
+ (display (or (plist-get args :display) ellama-always-show-buffer))
+ (log (plist-get args :log))
+ (model (or (plist-get args :model) ellama-model))
+ (memory (plist-get args :memory))
+ (system (plist-get args :system))
+ (temperature (plist-get args :temperature))
+ (template (or (plist-get args :template) ellama-template)))
+ (when (not (bufferp buffer))
+ (create-file-buffer buffer)
+ (with-current-buffer buffer
+ (if ellama-buffer-mode
+ (funcall ellama-buffer-mode))))
+ (when display
+ (display-buffer buffer))
+ (when log
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-max))
+ (insert "## " ellama-user-nick ":\n" prompt "\n\n"
+ "## " ellama-assistant-nick ":\n"))))
+ (let ((sentinel (if log
+ (lambda (proc event)
+ (when (string= event "finished\n")
+ (with-current-buffer (process-buffer proc)
+ (save-excursion
+ (goto-char (point-max))
+ (insert "\n\n")))))
+ (lambda (_ _) nil))))
+ (with-current-buffer buffer
+ (setq ellama--request (list :model model :prompt prompt))
+ (when (and memory ellama-context)
+ (setq ellama--request (plist-put ellama--request :context
ellama-context)))
+ (when system
+ (setq ellama--request (plist-put ellama--request :system system)))
+ (when temperature
+ (setq ellama--request (plist-put ellama--request :options
+ (list :temperature temperature))))
+ (when template
+ (setq ellama--request (plist-put ellama--request :template template)))
+ ;; (message "request: %s" (json-encode-plist ellama--request))
+ (make-process
+ :buffer buffer
+ :name "ellama"
+ :command (list
+ ellama-curl-executable
+ "-X" "POST" ellama-url "-d"
+ (json-encode-plist ellama--request))
+ :filter 'ellama--filter
+ :sentinel sentinel)))))
+
+;;;###autoload
+(defun ellama-ask ()
+ "Ask ellama about something."
+ (interactive)
+ (let ((prompt (read-string "Ask ellama: ")))
+ (ellama-query prompt :display t :log t :memory t)))
+
+;;;###autoload
+(defun ellama-ask-about ()
+ "Ask ellama about selected region or current buffer."
+ (interactive)
+ (let ((input (read-string "Ask ellama about this text: "))
+ (text (if (region-active-p)
+ (buffer-substring-no-properties (region-beginning)
(region-end))
+ (buffer-substring-no-properties (point-min) (point-max)))))
+ (ellama-query
+ (format "Regarding the following text, %s:\n%s" input text)
+ :display t :log t :memory t)))
+
+(defun ellama-instant (prompt)
+ "Prompt ellama for PROMPT to reply instantly."
+ (ellama-query prompt :display t :buffer (make-temp-name ellama-buffer)))
+
+;;;###autoload
+(defun ellama-translate ()
+ "Ask ellama to translate selected region or word at point."
+ (interactive)
+ (if (region-active-p)
+ (ellama-instant
+ (format "Translate the following text to %s:\n%s"
+ ellama-language
+ (buffer-substring-no-properties (region-beginning)
(region-end))))
+ (ellama-instant
+ (format "Translate %s to %s" (thing-at-point 'word) ellama-language))))
+
+;;;###autoload
+(defun ellama-define-word ()
+ "Find definition of current word."
+ (interactive)
+ (ellama-instant (format "Define %s" (thing-at-point 'word))))
+
+;;;###autoload
+(defun ellama-summarize ()
+ "Summarize selected region of current buffer."
+ (interactive)
+ (let ((text (if (region-active-p)
+ (buffer-substring-no-properties (region-beginning)
(region-end))
+ (buffer-substring-no-properties (point-min) (point-max)))))
+ (ellama-instant (format "Summarize the following text:\n%s" text))))
+
+(provide 'ellama)
+;;; ellama.el ends here.
- [elpa] branch externals/ellama created (now 11f601db8e), ELPA Syncer, 2023/12/17
- [elpa] externals/ellama 3bd6acccd3 02/53: begin ellama implementation,
ELPA Syncer <=
- [elpa] externals/ellama 547ca3a266 07/53: silence url retrieve, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama 3d3fa91206 04/53: add ellama change commands, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama f1fbb33521 03/53: add code review command, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama c14dad0065 05/53: add make list and make table commands, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama b9fe2ebdaa 06/53: add ellama-summarize-webpage function, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama 8bd196068a 08/53: add functions to work with code, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama a1112d64a0 09/53: improve ask about template, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama 00b8ddd155 19/53: fix for use libxml-parse-html-region, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama bfac7db4ef 27/53: Create melpa.yml, ELPA Syncer, 2023/12/17
- [elpa] externals/ellama 963843016b 14/53: add ellama-ask-about gif and fix typos, ELPA Syncer, 2023/12/17