Using Google Gemini API

As I write this chapter in May 2025, I primarily choose Google Gemini when I use commercial LLM APIs (most of my work involves running local LLM models using Ollama).

Overall, the Google Gemini APIs provide a powerful and easy-to-use tool for developers to integrate advanced language processing capabilities into their applications, and can be a game changer for developers looking to add natural language processing capabilities to their projects.

Google Gemini offers two features that set it apart from other commercial APIs:

  • Supports a one million token context size.
  • Very low cost.

We will look at two ways to access Gemini and we will look at examples for each technique:

  • Use the Python requests library to use Gemini’s REST style interface.
  • Use Google’s Python google-genai package (and we will look at tool use in the same example).

REST Interface

The following example calls the Gemini completion API and stores user chat in a persistent context.

Here is a listing or the source file google-gemini/chat.hy:

 1 (import os)
 2 (import requests)
 3 (import json) ;; Explicitly import json for dumps
 4 
 5 ;; Get API key from environment variable (standard practice)
 6 (setv api-key (os.getenv "GOOGLE_API_KEY"))
 7 
 8 ;; Gemini API endpoint
 9 (setv api-url f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-f\
10 lash:generateContent?key={api-key}")
11 
12 ;; Initialize the chat history (Note: Gemini uses 'user' and 'model')
13 (setv chat-history [])
14 
15 (defn call-gemini [chat-history user-input]
16   "Calls the Gemini API with the chat history and user input using requests."
17 
18   (setv headers {"Content-Type" "application/json"})
19 
20   ;; Build the contents list, correctly alternating roles.
21   (setv contents [])
22   (for [message chat-history]
23     (.append contents message))
24   (.append contents {"role" "user" "parts" [{"text" user-input}]})
25 
26   (setv data {
27               "contents" contents
28               "generationConfig" {
29                                   "maxOutputTokens" 200
30                                   "temperature" 1.2
31                                   }})
32 
33   ;; Use json.dumps to convert the Python/Hy dict to a JSON string
34   (setv response (requests.post api-url :headers headers :data (json.dumps data)))
35 
36   ;; Raise HTTPError for bad responses (4xx or 5xx)
37   (. response raise_for-status)
38 
39   ;; Return the JSON response as a Hy dictionary/list
40   (response.json))
41 
42 ;; --- Main Chat Loop ---
43 (while True
44   ;; Get user input from the console
45   (setv user-input (input "You: "))
46 
47 
48   ;; Call the Gemini API
49   (setv response-data (call-gemini chat-history user-input))
50 
51   ;; Debug print (optional)
52   ;; (print "Raw response data:" response-data)
53 
54   ;; Extract and print the assistant's message
55   ;; Using sequential gets for clarity, assumes expected structure
56   (setv candidates (get response-data "candidates"))
57   (setv first-candidate (get candidates 0))
58   (setv content (get first-candidate "content"))
59   
60   (setv parts (get content "parts"))
61 
62   (setv assistant-message (get (get parts 0) "text"))
63   (print "Assistant:" assistant-message)
64 
65   ;; Append BOTH user and assistant messages to chat history (important for context)
66   (.append chat-history {"role" "user" "parts" [{"text" user-input}]})
67   (.append chat-history {"role" "model" "parts" [{"text" assistant-message}]}))

This example differs from the OpenAI API example in the previous chapter in two ways:

  • It implements a chat (multiple user input conversation) interface.
  • It uses the low level Python requests library since the Google Gemini library has some incompatibilities with the Hy language system.

Here is a sample output showing how the user chat complex is used:

 1 $ uv sync
 2 $ uv run hy chat.hy                    
 3 You: set the value of the variable X to 1 + 7
 4 Assistant: python
 5 X = 1 + 7
 6 
 7 
 8 This code will:
 9 
10 1. **Calculate:**  1 + 7, which results in 8.
11 2. **Assign:** Assign the value 8 to the variable named `X`.
12 
13 You: print the value of X + 3
14 Assistant: python
15 X = 1 + 7  # Make sure X is defined as 8
16 print(X + 3)
17 
18 
19 This code will:
20 
21 1. **Calculate:** Take the current value of X (which is 8) and add 3 to it, resultin\
22 g in 11.
23 2. **Print:** Display the result (11) on the console.
24 
25 You: print the value of X + 3
26 Assistant: python
27 X = 1 + 7  # Make sure X is defined as 8
28 print(X + 3)
29 
30 This code will:
31 
32 1. **Calculate:** Take the current value of `X` (which is 8) and add 3 to it, result\
33 ing in 11.
34 2. **Print:** Display the result (11) on the console.
35 
36 You: 

Using Google’s Python Package to Access Gemini

We use the package google-genai in the example context_url.hy:

 1 (import os)
 2 (import google [genai])
 3 (import json) ;; Explicitly import json for dumps
 4 (import pprint [pprint])
 5 
 6 ;; Set enviroment variable: "GOOGLE_API_KEY"
 7 
 8 (setv client (genai.Client))
 9       
10 (defn context_qa [prompt]
11   "Calls the Gemini API using url_context tool with a prompt containing both a URI a\
12 nd user question"
13 
14   (setv
15     response
16     (client.models.generate_content
17       :model "gemini-2.5-flash"
18       :contents prompt
19       :config {"tools" [{"url_context" {}}]}))
20 
21   (return response.text))
22 
23 (when (= __name__ "__main__")
24   (print
25     (context_qa
26       "https://markwatson.com What musical instruments does Mark Watson play?")))

The tool url_context is called automatically when a URI is present in a user prompt. A prompt can also contain multiple URIs and they are all used in generating text from the input prompt.

The output for this example is:

1 $ uv run hy context_url.hy                                    
2 Mark Watson plays the guitar, didgeridoo, and American Indian flute.

If you want to reuse this example without using tools, just remove the option :config {“tools” [{“url_context” {}}]}.

The GitHub repository for the this Google package also contains useful examples and documentation links: https://github.com/googleapis/python-genai.

Wrap Up for Using the Gemini APIs

There are many good commercial LLM APIs (and I have most of them) but I currently most frequently use Gemini for two reasons: supports a one million token context size and is very low cost.

I discuss Gemini in more detail in another book that you can read online: https://leanpub.com/solo-ai/read.