-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaimacs.el
More file actions
145 lines (123 loc) · 5.1 KB
/
aimacs.el
File metadata and controls
145 lines (123 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
;;; aimacs.el -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2023 Maxim P
;;
;; Author: Maxim P <putintsev@gmail.com>
;; Maintainer: Maxim P <putintsev@gmail.com>
;; Created: September 10, 2023
;; Modified: September 10, 2023
;; Version: 0.0.1
;; Keywords: chat gpt
;; Homepage: https://github.com/mput/aimacs
;; Package-Requires: ((emacs "25.1"))
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;;
;;
;;; Code:
(require 'request)
(defmacro aimacs-comment (&rest body)
"Comment out one or more s-expressions."
nil)
(defun aimacs-create-and-show-res (buf-name body mode)
(message "mode: %s" mode)
(let ((b (get-buffer-create buf-name)))
(with-current-buffer b
(erase-buffer)
(insert body)
(goto-char 0)
(when mode
(funcall mode)))
(display-buffer b)))
(ignore-errors
(load-env-vars "~/projects/personal/aimacs/.env")
(set-popup-rule! "^\\*aimacs.*" :size 0.4 :side 'bottom :select nil :quit nil))
(setq aimacs-oai-comp-api-base "https://api.openai.com/v1/chat/completions")
(setq aimacs-api-key (getenv "GPT_API_KEY"))
(setq aimacs-model "gpt-3.5-turbo")
(setq aimacs-model "gpt-4")
(setq aimacs-templates
'(((name . "markdown grammar correction")
(system . "You will be provided with text which is a part of software documentation, and your task is to proofread it.
Provide the result in markdown format while trying to preserve the markup, first put the corrected version, and then place diff as markdown comment.
")
(user . "{{region}}")
(result-mode . markdown-mode))
((name . "clojure efficiency improvements")
(system . "You will be provided with a piece of Clojure code, and your task is to provide ideas for efficiency improvements.")
(user . "{{region}}")
(result-mode . clojure-mode))
((name . "clojure bug haunt")
(system . "You will be provided with a piece of Clojure code, and your task is to find and fix bugs in it.")
(user . "{{region}}")
(result-mode . clojure-mode))
((name . "parse unstructored data to EDN")
(system . "You will be provided with unstructured data, and your task is to parse it into EDN format.")
(user . "{{region}}"))
((name . "code explainer")
(system . "You will be provided with a piece of code, and your task is to explain it in a concise way.")
(user . "{{region}}"))))
(defun aimacs-replace-in-template (s s-region s-buffer)
(with-temp-buffer
(insert s)
(goto-char (point-min))
(while (re-search-forward "{{\\(.*\\)}}" nil t)
(let* ((match (match-string-no-properties 1))
(replace (pcase match
("region" s-region)
("buffer" s-buffer)
(_ ""))))
(replace-match replace nil "\\")))
(buffer-substring (point-min) (point-max))))
(defun aimacs-resolve-template (tname)
(let* ((rec (assoc `(name . ,tname) aimacs-templates #'equal))
(region (if (region-active-p)
(buffer-substring (region-beginning) (region-end))
""))
(buffer (buffer-substring (point-min) (point-max))))
(mapcar (lambda (p)
(cons (car p)
(if (stringp (cdr p))
(aimacs-replace-in-template (cdr p) region buffer)
(cdr p))))
rec)))
(defun aimacs-query-and-show (t-name)
(let* ((template (aimacs-resolve-template t-name))
(messages (->> '(system user)
(mapcar (lambda (n)
(let ((v (alist-get n template)))
(when v
`((role . ,n)
(content . , v))))))
(remq nil)))
(res-mode (alist-get 'result-mode template)))
(request aimacs-oai-comp-api-base
:type "POST"
:headers `(("Content-Type" . "application/json")
("Authorization" . ,(format "Bearer %s" aimacs-api-key)))
:data (json-encode `((model . ,aimacs-model)
(messages . ,messages)))
:parser 'json-read
:success (cl-function
(lambda (&key data &allow-other-keys)
(let ((res (->> (aref (alist-get 'choices data) 0)
(alist-get 'message)
(alist-get 'content))))
(aimacs-create-and-show-res (format "*aimacs-%s*" (random 1000)) res res-mode))))
:error (cl-function
(lambda (&rest args &key error-thrown &key response &allow-other-keys)
(aimacs-create-and-show-res
(format "*aimacs-error-%s*" (random 1000))
(format ":error %S\n:body %s"
error-thrown
(ignore-errors (json-encode (request-response-data response))))
'json-mode))))))
(defun aimacs-complete ()
(interactive)
(aimacs-query-and-show (completing-read "Specify Template: "
(mapcar (lambda (v) (alist-get 'name v) ) aimacs-templates))))
(provide 'aimacs)
;;; aimacs.el ends here