Lesson 16 Google Gemini
Theme:

Lab Guide — Google Gemini

Three exercises covering the Gemini SDK, multimodal inputs, and cross-provider comparison with Claude.

Setup: Open lab.pdf in Jupyter. You need a GOOGLE_API_KEY (from Google AI Studio) and an ANTHROPIC_API_KEY in your .env file. Install the SDKs: pip install google-generativeai anthropic.

📥 Lab Notebooks

⬇ lab.pdf ⬇ lab_answer.pdf
API key: Get a free Google AI Studio key at aistudio.google.com/apikey. The free tier allows up to 500 requests per day with Gemini 2.5 Flash — more than enough for this lab.

Exercise 1 — Your First Gemini Call

EX 1

Set up the Gemini SDK and generate text

Configure the google-generativeai SDK, create a model instance, and make your first API call.

  1. Import the SDK and configure it with your API key:
    import google.generativeai as genai
    from dotenv import load_dotenv
    import os
    
    load_dotenv()
    genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
  2. Create a GenerativeModel instance for gemini-2.5-flash:
    model = genai.GenerativeModel("gemini-2.5-flash")
  3. Send a simple text generation request:
    response = model.generate_content("Explain the difference between TCP and UDP in 3 sentences.")
    print(response.text)
  4. Inspect the token usage metadata:
    print(f"Input tokens:  {response.usage_metadata.prompt_token_count}")
    print(f"Output tokens: {response.usage_metadata.candidates_token_count}")
    print(f"Total tokens:  {response.usage_metadata.total_token_count}")
  5. Try passing generation_config to control temperature and max output tokens:
    response = model.generate_content(
        "Write a haiku about machine learning.",
        generation_config=genai.GenerationConfig(
            temperature=0.9,
            max_output_tokens=100,
        ),
    )
    print(response.text)
Key difference from Claude/OpenAI: Gemini uses a GenerativeModel object that you create once, then call generate_content() on repeatedly. Claude and OpenAI pass the model name to each API call instead.

Checkpoint: You can make a successful Gemini API call, print the response text, and view token usage metadata.

Exercise 2 — Multimodal Input (Image + Text)

EX 2

Analyse an image using Gemini’s vision capabilities

Use Gemini’s native multimodal support to describe and analyse an image alongside a text prompt.

  1. Download or use a sample image. You can use any JPEG/PNG file or load one from a URL:
    import urllib.request
    
    # Download a sample image
    url = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png"
    urllib.request.urlretrieve(url, "sample_image.png")
  2. Upload the file and send it with a text prompt:
    uploaded_file = genai.upload_file("sample_image.png")
    
    response = model.generate_content([
        "Describe what you see in this image in detail. "
        "Include colours, objects, and any text visible.",
        uploaded_file,
    ])
    print(response.text)
  3. Try different analysis prompts on the same image:
    • "What text is visible in this image?"
    • "If this image were used in a presentation, what topic would it illustrate?"
    • "Describe the mood or emotion this image conveys."
  4. Compare token usage for image inputs versus text-only inputs. Note how many tokens the image consumes:
    print(f"Tokens used for image prompt: {response.usage_metadata.prompt_token_count}")
    # Compare with a text-only prompt of similar complexity
  5. (Optional) Try loading an image directly from bytes using PIL:
    from PIL import Image
    
    img = Image.open("sample_image.png")
    response = model.generate_content([
        "What colours dominate this image?",
        img,
    ])
    print(response.text)

Checkpoint: Gemini accurately describes your image content. You can see the token cost of image inputs in the usage metadata.

Exercise 3 — Cross-Provider Comparison (Gemini vs Claude)

EX 3

Run the same prompts on Gemini and Claude, compare results

Build a comparison harness that sends identical prompts to both Gemini Flash and Claude Sonnet, then evaluates the results side by side.

  1. Set up both clients:
    import google.generativeai as genai
    import anthropic
    import time
    
    genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
    gemini_model = genai.GenerativeModel("gemini-2.5-flash")
    claude_client = anthropic.Anthropic()
  2. Define 5 test prompts covering different capabilities:
    prompts = [
        "Write a Python function that checks if a string is a valid IPv4 address.",
        "Explain quantum entanglement to a 10-year-old.",
        "Summarise the pros and cons of microservices vs monoliths.",
        "Write a short poem about a lonely lighthouse.",
        "What are the three most important factors when choosing a database?",
    ]
  3. Write a comparison function that records response text, token usage, and latency for each provider:
    def compare_models(prompt):
        # Gemini call
        t0 = time.time()
        g_resp = gemini_model.generate_content(prompt)
        g_time = time.time() - t0
    
        # Claude call
        t0 = time.time()
        c_resp = claude_client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}],
        )
        c_time = time.time() - t0
    
        return {
            "prompt": prompt,
            "gemini_text": g_resp.text,
            "gemini_tokens": g_resp.usage_metadata.total_token_count,
            "gemini_time": round(g_time, 2),
            "claude_text": c_resp.content[0].text,
            "claude_tokens": c_resp.usage.input_tokens + c_resp.usage.output_tokens,
            "claude_time": round(c_time, 2),
        }
  4. Run all 5 prompts and display the results in a formatted comparison
  5. Add streaming support for Gemini and observe the output arriving in chunks:
    # Gemini streaming
    response = gemini_model.generate_content(
        "Explain recursion step by step.",
        stream=True,
    )
    for chunk in response:
        print(chunk.text, end="", flush=True)
    print()  # newline after streaming completes
Tip: Pay attention to differences in response style. Gemini tends to use more structured formatting (headers, bullet points) while Claude often produces more flowing prose. Neither is inherently better — it depends on the use case.

Checkpoint: A table or formatted output showing side-by-side results for all 5 prompts with token counts and response times for both providers.

Bonus challenge: If you also have an OpenAI key, extend the comparison to include GPT-4o as a third provider. This gives you a full three-way comparison across the major LLM APIs — excellent preparation for Lesson 17 on open-source models.