Skip to content

Commit 973e6b1

Browse files
committed
Add src
1 parent 7ed4eb4 commit 973e6b1

File tree

3 files changed

+151
-2
lines changed

3 files changed

+151
-2
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ dist/
1515
# packaging
1616
*-autoloads.el
1717
*-pkg.el
18+
19+
# ignore internal test
20+
_test/

google-gemini-content.el

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
;;; google-gemini-content.el --- Create generate content with Google Gemini API -*- lexical-binding: t; -*-
2+
3+
;; Copyright (C) 2024 Shen, Jen-Chieh
4+
5+
;; This file is not part of GNU Emacs.
6+
7+
;; This program is free software: you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation, either version 3 of the License, or
10+
;; (at your option) any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;; You should have received a copy of the GNU General Public License
18+
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
20+
;;; Commentary:
21+
;;
22+
;; Create generate content with Google Gemini API.
23+
;;
24+
25+
;;; Code:
26+
27+
(require 'google-gemini)
28+
29+
;;
30+
;;; API
31+
32+
;;;###autoload
33+
(cl-defun google-gemini-generate-content ( contents callback
34+
&key
35+
(content-type "application/json"))
36+
"Send generate content request."
37+
(request (format "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=%s"
38+
google-gemini-key)
39+
:type "POST"
40+
:headers (google-gemini--headers content-type)
41+
:data (google-gemini--json-encode
42+
`(("contents" . ,contents)))
43+
:parser 'json-read
44+
:complete (cl-function
45+
(lambda (&key data &allow-other-keys)
46+
(funcall callback data)))))
47+
48+
;;
49+
;;; Application
50+
51+
;;;###autoload
52+
(defun google-gemini-say ()
53+
"Start making a conversation to Google Gemini."
54+
(interactive)
55+
)
56+
57+
(provide 'google-gemini-content)
58+
;;; google-gemini-content.el ends here

google-gemini.el

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
;; Maintainer: JenChieh <jcs090218@gmail.com>
77
;; URL: https://github.com/emacs-openai/google-gemini
88
;; Version: 0.1.0
9-
;; Package-Requires: ((emacs "26.1"))
9+
;; Package-Requires: ((emacs "26.1") (request "0.3.0"))
1010
;; Keywords: comm google gemini
1111

1212
;; This file is not part of GNU Emacs.
@@ -31,7 +31,95 @@
3131

3232
;;; Code:
3333

34-
;; Happy coding! ;)
34+
(require 'auth-source)
35+
(require 'cl-lib)
36+
(require 'let-alist)
37+
(require 'pcase)
38+
(require 'pp)
39+
(require 'json)
40+
41+
(require 'request)
42+
43+
(defgroup google-gemini nil
44+
"Elisp library for the Google Gemini API."
45+
:prefix "google-gemini-"
46+
:group 'comm
47+
:link '(url-link :tag "Repository" "https://github.com/emacs-openai/google-gemini"))
48+
49+
;;
50+
;;; Logger
51+
52+
(defvar google-gemini--show-log nil
53+
"Get more information from the program.")
54+
55+
(defun google-gemini--log (fmt &rest args)
56+
"Debug message like function `message' with same argument FMT and ARGS."
57+
(when google-gemini--show-log
58+
(apply 'message fmt args)))
59+
60+
;;
61+
;;; Request
62+
63+
(defvar google-gemini-key ""
64+
"Variable storing the gemini key or a function name to retrieve it.
65+
66+
The function should take no arguments and return a string containing the key.
67+
68+
A function, `google-gemini-key-auth-source', that retrieves the key from
69+
auth-source is provided for convenience.")
70+
71+
(defcustom google-gemini-base-url "googleapis.com"
72+
"The base URL for Google Gemini API requests."
73+
:type 'string
74+
:group 'google-gemini)
75+
76+
;;;###autoload
77+
(defun google-gemini-key-auth-source (&optional base-url)
78+
"Retrieve the Google Gemini API key from auth-source given a BASE-URL.
79+
If BASE-URL is not specified, it defaults to `google-gemini-base-url'."
80+
(if-let ((auth-info
81+
(auth-source-search :max 1
82+
:host (or (url-host (url-generic-parse-url (or base-url google-gemini-base-url)))
83+
google-gemini-base-url)
84+
:require '(:user :secret))))
85+
(funcall (plist-get (car auth-info) :secret))
86+
(error "Google Gemini API key not found in auth-source")))
87+
88+
(defun google-gemini--alist-omit-null (alist)
89+
"Omit null value or empty string in ALIST."
90+
(cl-remove-if (lambda (pair)
91+
(let ((value (cdr pair)))
92+
(or (null value) ; ignore null
93+
(and (stringp value) ; ignore empty string
94+
(string-empty-p value)))))
95+
alist))
96+
97+
(defun google-gemini--headers (content-type)
98+
"Construct request headers.
99+
100+
Arguments CONTENT-TYPE are common request headers."
101+
(google-gemini--alist-omit-null
102+
`(("Content-Type" . ,content-type)
103+
,(if (or (null key)
104+
(string-empty-p key))
105+
""
106+
(pcase openai-key-type
107+
(:bearer `("Authorization" . ,(concat "Bearer " key)))
108+
(:azure-api `("api-key" . ,key))
109+
(_ (user-error "Invalid key type: %s"
110+
openai-key-type))))
111+
)))
112+
113+
(defun google-gemini--json-encode (object)
114+
"Wrapper for function `json-encode' but it remove nil value before
115+
constructing JSON data.
116+
117+
The argument OBJECT is an alist that can be construct to JSON data; see function
118+
`json-encode' for the detials."
119+
(let* ((object (google-gemini--alist-omit-null object))
120+
(encoded (json-encode object)))
121+
(google-gemini--log "[ENCODED]: %s" encoded)
122+
encoded))
35123

36124
(provide 'google-gemini)
37125
;;; google-gemini.el ends here

0 commit comments

Comments
 (0)