πŸ› οΈ Hands-On Lab Session

Build Your First
AI Chat Interface

From zero to a deployed, working AI chatbot in two hours. You will write real code, call real APIs, and share a live URL with the world.

πŸ“… Tuesday, June 9, 2026
πŸ•‘ 14:00 - 16:00
πŸ“ ISU, Strasbourg
πŸ’» Lab Session
🎯

What We Are Building Today

By the end of this two-hour lab, you will have built and deployed a fully functional AI chatbot that runs entirely in the browser. No server, no backend, no frameworks.

πŸ’¬

Chat Interface

A polished dark-theme chat UI with message bubbles, typing indicators, and smooth scrolling

πŸ€–

AI Integration

Connected to Google's Gemini API for real-time, intelligent responses about Earth Observation

🌍

EO Specialization

Custom system prompt making the chatbot an expert assistant for satellite data analysis

πŸš€

Live Deployment

Deployed on GitHub Pages with a real URL you can share with anyone in the world

πŸ’‘
Prerequisites: You should be comfortable with HTML, CSS, and basic JavaScript. You need a GitHub account and a Google account. That is it.
πŸ—οΈ

Architecture: How It All Fits Together

Our chatbot uses a simple client-side architecture. The browser does all the work: capturing user input, calling the AI API, and rendering the response.

πŸ‘€
User
Types a message
β†’
🌐
Browser (JS)
index.html + fetch()
β†’
🧠
Gemini API
generativelanguage.googleapis.com
β†’
πŸ’¬
AI Response
Rendered in chat

Today's Lab Roadmap

  1. Set up API keys (15 min): Get free access to Gemini and Groq
  2. Build the chat UI (40 min): HTML structure, CSS styling, JS message handling
  3. Connect to the AI (35 min): API calls, conversation history, system prompts
  4. Deploy and share (20 min): Push to GitHub, enable Pages, test your live app
  5. Bonus challenges (10 min): Customize and extend your chatbot
πŸ’‘

Step 1: Project Ideation & Prompting

Before we start coding, let's figure out what we are building. Here are three suggested project tracks to get you inspired, but you are absolutely welcome to bring your own idea. The only requirement is that your project combines satellite/Earth observation data with AI.

πŸ›°οΈ Track 1: Parametric Satellite Insurance

A lean, automated insurance platform for farmers. If satellite data (NDVI, soil moisture) detects a drought or flood event triggering a specific threshold, a smart contract automatically issues a payout.

πŸ‡ Track 2: The Alsace CubeSat Dashboard

An AI dashboard tailored for an ISU student-built CubeSat. It augments existing global satellite data with localized low-orbit sensors tuned for regional needs like Alsace wine production or targeted air pollution monitoring.

View the Alsace CubeSat Concept Brochure β†’
🏭 Track 3: EU Green New Deal Compliance

An automated ESG monitoring dashboard designed for Paddock Academy's industrial partners. The AI analyzes Sentinel-2/5P emissions against EU regulations to automatically generate environmental audit reports.

πŸ’‘ Your Own Idea

Have a different problem you want to solve with satellite data and AI? Wildfire monitoring, coastal erosion tracking, urban heat islands, ocean pollution? Pitch it! Any project that combines EO data with an intelligent web application is fair game.

πŸ“
Action Item: Pick one of the tracks above, or propose your own idea. As we build our first AI agent, you will write a custom System Prompt that turns the AI into an expert in your chosen domain.
πŸ”‘

Step 1: Get Your Gemini API Key

Google's Gemini API is free for prototyping. The free tier gives you 15 requests per minute, which is more than enough for development and learning.1

πŸ‡ͺπŸ‡Ί
EU/EEA Notice: Some Gemini API free-tier features have regional restrictions for EU/EEA users. If you encounter issues in Strasbourg, use Groq (slide 5) or Puter.js (slide 21) as alternatives. Check the availability page for the latest status.
1

Open Google AI Studio

Navigate to https://aistudio.google.com/apikey

Sign in with your Google account (the same one you use for Gmail).

2

Create an API Key

Click "Create API Key". You may be asked to create a Google Cloud project. Accept the defaults.

3

Copy and Save Your Key

Your key will look something like: AIzaSyB...xyz

Copy it and save it somewhere safe (a text file, a note app). You will need it shortly.

⚠️
Keep your key private! Anyone with your API key can make requests on your behalf. Never share it in screenshots, chat messages, or public repositories.
⚑

Step 2: Get Your Groq API Key (Backup)

Groq provides extremely fast inference on open-source models like Llama 3 and Mixtral. We will use it as a backup provider and to demonstrate multi-model support.

1

Open the Groq Console

Navigate to https://console.groq.com/keys

Sign up or log in (you can use your Google or GitHub account).

2

Create an API Key

Click "Create API Key". Name it something like isu-lab.

3

Save It

Your key will look like: gsk_aBcDeFgH...

Copy and store it alongside your Gemini key.

πŸ’‘
Why two providers? Having a backup API means your app keeps working even if one service has an outage. It also teaches you how to design provider-agnostic code.
πŸ§ͺ

Step 3: Test Your API Keys

Before writing any app code, let's verify your keys work. Open your browser's Developer Tools (F12) and go to the Console tab.

Test Gemini in the Browser Console

JavaScript (Browser Console)
// Paste this into your browser console (F12 > Console)
// Replace YOUR_KEY with your actual Gemini API key

const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=YOUR_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    contents: [{ parts: [{ text: 'Hello! What is NDVI in one sentence?' }] }]
  })
});

const data = await response.json();
console.log(data.candidates[0].content.parts[0].text);

Expected Output

Console Output
NDVI (Normalized Difference Vegetation Index) is a measure of
vegetation health derived from satellite imagery by comparing
near-infrared and red light reflectance.
βœ…
If you see a text response, your key works. If you see an error, double-check you copied the full key and that it is activated.
πŸ”’

API Key Security: What You Must Know

In production applications, API keys must never be exposed in client-side code. However, for this learning exercise, we will use client-side keys with appropriate precautions.

Approach Use Case Security Level
Key in JS file (what we do today) Prototyping, learning labs ⚠️ Low
.env file + build tool Local development ⚠️ Medium
Backend proxy server Production web apps βœ… High
Puter.js (no key needed) Quick prototyping βœ… High
🚨
NEVER commit API keys to public GitHub repos! Bots scan GitHub constantly for leaked keys and will abuse them within minutes. Before pushing to GitHub, either remove your key or use a prompt-based input (we will implement this later).

Our Lab Strategy

  • During development: Hardcode the key in your JS file for convenience
  • Before deploying: Implement a prompt that asks the user to enter their own key and saves it to sessionStorage:
    let apiKey = sessionStorage.getItem('gemini_api_key');
    if (!apiKey) {
      apiKey = prompt('Please enter your Gemini API Key:');
      sessionStorage.setItem('gemini_api_key', apiKey);
    }
  • In production: Use a backend proxy or a service like Puter.js that handles keys for you
πŸ“‘

Your First Gemini API Call (Explained)

Let's break down every part of the API call you just ran. Understanding this structure is essential for building the chatbot.

JavaScript
// The API endpoint: model name + action + API key
const API_URL =
  'https://generativelanguage.googleapis.com/v1beta/'  // Base URL
  + 'models/gemini-2.0-flash'                          // Model
  + ':generateContent'                                // Action
  + '?key=' + API_KEY;                                  // Auth

// The request body: an array of conversation turns
const requestBody = {
  contents: [
    {
      role: 'user',           // Who sent this message
      parts: [
        { text: 'What is NDVI?' }  // The message content
      ]
    }
  ]
};

// The response structure
// data.candidates[0].content.parts[0].text  = the AI's reply

Key Concepts

  • contents array: Each element is a "turn" in the conversation (user or model)
  • parts array: A turn can have multiple parts (text, images). We only use text today
  • candidates: The API may return multiple candidate responses; we always use [0]
  • gemini-2.0-flash: The fastest, most cost-effective Gemini model2
πŸ“„

Building the Chat UI: HTML Structure

Every chat interface has three core components: a message container, an input field, and a send button. Let's build the HTML skeleton.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">
  <title>EO Chat Assistant</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

  <!-- Header -->
  <header>
    <h1>πŸ›°οΈ EO Chat Assistant</h1>
    <p>Ask me anything about Earth Observation</p>
  </header>

  <!-- Messages container: all chat bubbles go here -->
  <main id="chat-messages">
    <!-- Messages will be inserted by JavaScript -->
  </main>

  <!-- Input area: fixed at the bottom -->
  <footer>
    <form id="chat-form">
      <input type="text"
             id="user-input"
             placeholder="Ask about NDVI, Sentinel-2, land cover..."
             autocomplete="off"
             required>
      <button type="submit">Send</button>
    </form>
  </footer>

  <script src="app.js"></script>
</body>
</html>
πŸ’‘
Tip: Create two files in your project folder: index.html (above), style.css (next slide), and app.js (later). Keeping them separate is good practice for any project.
🎨

CSS: Dark Theme Chat Styling

We will style our chat with a dark theme that matches the course aesthetic. The key is styling user bubbles (right-aligned, colored) differently from AI bubbles (left-aligned, neutral).

CSS (style.css)
/* Reset and base */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: 'Segoe UI', system-ui, sans-serif;
  background: #050a18;
  color: #f9fafb;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

header {
  text-align: center;
  padding: 1.5rem;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}

header h1 { font-size: 1.5rem; }
header p  { color: #9ca3af; font-size: 0.9rem; }

/* Messages area */
#chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Message bubbles */
.message {
  max-width: 75%;
  padding: 0.9rem 1.2rem;
  border-radius: 16px;
  font-size: 0.95rem;
  line-height: 1.6;
}

.message.user {
  background: #10b981;
  color: white;
  align-self: flex-end;
  border-bottom-right-radius: 4px;
}

.message.ai {
  background: rgba(255,255,255,0.06);
  color: #e5e7eb;
  align-self: flex-start;
  border-bottom-left-radius: 4px;
}

The full CSS continues on the next slide with input styling and animations.

βš™οΈ

JavaScript: Message Handling

The JavaScript handles three tasks: capturing input, rendering messages, and auto-scrolling to the latest message.

JavaScript (app.js, part 1)
// ---- DOM Elements ----
const chatMessages = document.getElementById('chat-messages');
const chatForm     = document.getElementById('chat-form');
const userInput    = document.getElementById('user-input');

// ---- Render a message bubble ----
function addMessage(text, sender) {
  const div = document.createElement('div');
  div.className = `message ${sender}`;  // 'user' or 'ai'
  div.textContent = text;
  chatMessages.appendChild(div);

  // Auto-scroll to the bottom
  chatMessages.scrollTop = chatMessages.scrollHeight;

  return div;  // Return so we can update it later
}

// ---- Handle form submission ----
chatForm.addEventListener('submit', async (e) => {
  e.preventDefault();

  const message = userInput.value.trim();
  if (!message) return;

  // 1. Show user message
  addMessage(message, 'user');
  userInput.value = '';

  // 2. Show typing indicator
  const typingDiv = addMessage('Thinking...', 'ai');

  // 3. Call the AI (we'll implement this next!)
  const reply = await getAIResponse(message);
  typingDiv.textContent = reply;
});
πŸ’‘
Pattern: Show the user message immediately, then display a placeholder "Thinking..." message, then replace it with the AI response. This keeps the UI responsive even if the API takes a few seconds.
⏳

Typing Indicators and Loading States

A polished chat app shows visual feedback while the AI is "thinking." Let's add an animated typing indicator and proper input disabling.

CSS (add to style.css)
/* Typing indicator animation */
.typing-indicator {
  display: flex;
  gap: 4px;
  padding: 0.8rem 1.2rem;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  background: #9ca3af;
  border-radius: 50%;
  animation: bounce 1.4s infinite ease-in-out;
}

.typing-indicator span:nth-child(1) {
  animation-delay: 0s;
}
.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}
.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes bounce {
  0%, 80%, 100% { transform: scale(0); }
  40%              { transform: scale(1.0); }
}

/* Disable input while AI is responding */
input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
JavaScript (typing indicator helper)
function showTypingIndicator() {
  const div = document.createElement('div');
  div.className = 'message ai typing-indicator';
  div.id = 'typing';
  div.innerHTML = '<span></span><span></span><span></span>';
  chatMessages.appendChild(div);
  chatMessages.scrollTop = chatMessages.scrollHeight;
}

function removeTypingIndicator() {
  const el = document.getElementById('typing');
  if (el) el.remove();
}
πŸ“¦

The Complete Chat Application

Here is the complete, runnable app.js file. This includes everything: DOM handling, API calls, conversation history, and the typing indicator. Copy this into your project.

JavaScript (app.js, complete)
// =============================================
// EO Chat Assistant - Complete Application
// =============================================

// ---- Configuration ----
const API_KEY = prompt('Enter your Gemini API key:');
const API_URL = 'https://generativelanguage.googleapis.com/v1beta/'
  + 'models/gemini-2.0-flash:generateContent?key=' + API_KEY;

// ---- System prompt: makes the AI an EO expert ----
const SYSTEM_PROMPT = `You are an Earth Observation assistant
for university students. You help with satellite data,
remote sensing concepts (NDVI, SAR, spectral bands),
and tools like Google Earth Engine. Be concise and
include practical examples when possible.`;

// ---- Conversation history ----
const history = [];

// ---- DOM Elements ----
const chatMessages = document.getElementById('chat-messages');
const chatForm     = document.getElementById('chat-form');
const userInput    = document.getElementById('user-input');

// ---- Add a message to the chat ----
function addMessage(text, sender) {
  const div = document.createElement('div');
  div.className = `message ${sender}`;
  div.textContent = text;
  chatMessages.appendChild(div);
  chatMessages.scrollTop = chatMessages.scrollHeight;
  return div;
}

// ---- Call the Gemini API ----
async function getAIResponse(userMessage) {
  // Add user message to history
  history.push({
    role: 'user',
    parts: [{ text: userMessage }]
  });

  try {
    const res = await fetch(API_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        system_instruction: {
          parts: [{ text: SYSTEM_PROMPT }]
        },
        contents: history
      })
    });

    const data = await res.json();
    const reply = data.candidates[0]
                       .content.parts[0].text;

    // Add AI reply to history
    history.push({
      role: 'model',
      parts: [{ text: reply }]
    });

    return reply;
  } catch (err) {
    return 'Sorry, something went wrong: ' + err.message;
  }
}

// ---- Form submission handler ----
chatForm.addEventListener('submit', async (e) => {
  e.preventDefault();
  const msg = userInput.value.trim();
  if (!msg) return;

  addMessage(msg, 'user');
  userInput.value = '';
  userInput.disabled = true;

  const placeholder = addMessage('Thinking...', 'ai');
  const reply = await getAIResponse(msg);

  placeholder.textContent = reply;
  userInput.disabled = false;
  userInput.focus();
});

// ---- Welcome message ----
addMessage(
  'Hello! πŸ›°οΈ I am your Earth Observation assistant. '
  + 'Ask me about NDVI, Sentinel-2, land cover '
  + 'classification, or any remote sensing topic!',
  'ai'
);
❓

Quiz: Chat UI Fundamentals

Q1: In our chat app, why do we use display: flex with flex-direction: column on the #chat-messages container?
A To make the chat messages scroll horizontally
B To stack messages vertically and allow align-self to position user vs. AI bubbles on different sides
C To make the messages appear in reverse chronological order
D To enable CSS Grid layout on the child elements
βœ… Correct! Flexbox column layout lets us stack messages top-to-bottom, while align-self: flex-end pushes user messages to the right and align-self: flex-start keeps AI messages on the left.
❌ Not quite. Flexbox column gives us vertical stacking, and crucially, it enables align-self on individual items to push user messages right and AI messages left.
Q2: Why do we set chatMessages.scrollTop = chatMessages.scrollHeight after adding a message?
A To clear all previous messages from the container
B To animate the new message with a slide-in effect
C To automatically scroll the container to the bottom so the newest message is visible
D To calculate the total height of the messages for layout purposes
βœ… Correct! Setting scrollTop to scrollHeight scrolls the container to the very bottom, ensuring the user always sees the latest message without manual scrolling.
❌ Not quite. scrollTop = scrollHeight forces the scroll position to the bottom of the container, keeping the latest message visible automatically.
πŸ“€

The sendMessage() Function: Deep Dive

The getAIResponse() function is the heart of our application. Let's examine each step of the API request lifecycle.

JavaScript (annotated)
async function getAIResponse(userMessage) {

  // STEP 1: Add the user's message to the conversation history.
  // This array grows with each exchange, giving the AI
  // context about previous turns in the conversation.
  history.push({
    role: 'user',
    parts: [{ text: userMessage }]
  });

  // STEP 2: Send the ENTIRE conversation history to the API.
  // The model has no memory between calls, so we must
  // send all previous messages every time.
  const res = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      system_instruction: {
        parts: [{ text: SYSTEM_PROMPT }]
      },
      contents: history  // All messages so far
    })
  });

  // STEP 3: Parse the JSON response and extract the text.
  const data = await res.json();
  const reply = data.candidates[0].content.parts[0].text;

  // STEP 4: Add the AI's reply to history so the next
  // request includes it as context.
  history.push({
    role: 'model',
    parts: [{ text: reply }]
  });

  return reply;
}
πŸ’‘
Key Insight: LLMs are stateless. Each API call is independent. The model does not "remember" your previous messages unless you explicitly send them in the contents array. This is why we maintain a history array on the client side.
🌊

Streaming vs. Non-Streaming Responses

The Gemini API supports two response modes. Understanding the difference helps you build better user experiences.3

Feature Non-Streaming (what we use) Streaming
Endpoint :generateContent :streamGenerateContent
Response Full text arrives at once Text arrives chunk by chunk
User Experience Wait, then see full answer See text appear word by word
Time to First Token Longer (waits for full generation) Shorter (starts immediately)
Complexity Simple: one fetch() call Requires reading a stream

Streaming Example (Bonus)

JavaScript (streaming version)
// Streaming: change the endpoint and read chunks
const streamURL = API_URL.replace(
  'generateContent',
  'streamGenerateContent'
) + '&alt=sse';  // append with & since ?key= is already present

const res = await fetch(streamURL, { /* same options */ });
const reader = res.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  // Parse and append each chunk to the message div
}
πŸ’‘
For today's lab, we use the simpler non-streaming approach. Streaming is a great "next step" challenge to try on your own!
πŸ“œ

Managing Conversation History

The history array is what gives our chatbot the ability to have multi-turn conversations. Without it, every message would be treated as an isolated question.

How History Grows Over a Conversation

JSON (conversation history structure)
// After 2 exchanges, history looks like this:
[
  { "role": "user",  "parts": [{ "text": "What is NDVI?" }] },
  { "role": "model", "parts": [{ "text": "NDVI stands for..." }] },
  { "role": "user",  "parts": [{ "text": "How do I calculate it?" }] },
  { "role": "model", "parts": [{ "text": "NDVI = (NIR - Red)..." }] }
]

Important Considerations

  • Token limits: Every model has a context window (Gemini 2.0 Flash supports up to 1 million tokens). Very long conversations may need to be truncated.4
  • Cost: Longer histories mean more tokens per request. On the free tier, this is mainly a speed concern.
  • Relevance: Old messages may confuse the model. Some apps keep only the last N messages.
JavaScript (optional: limit history length)
// Keep only the last 20 messages to control token usage
const MAX_HISTORY = 20;
if (history.length > MAX_HISTORY) {
  history.splice(0, history.length - MAX_HISTORY);
}
🧠

System Prompts: Shaping Your AI's Personality

The system prompt (also called "system instruction") tells the AI how to behave. It is sent with every request but is invisible to the user. This is how you turn a general-purpose LLM into a specialized assistant.5

Our EO System Prompt

JavaScript
const SYSTEM_PROMPT = `You are an Earth Observation assistant
for university students at the International Space University.

Your expertise includes:
- Satellite remote sensing (Sentinel-2, Landsat, MODIS)
- Vegetation indices (NDVI, EVI, SAVI)
- Land cover classification and change detection
- Google Earth Engine and geospatial Python libraries
- SAR (Synthetic Aperture Radar) fundamentals

Rules:
1. Be concise but thorough
2. Include formulas when discussing indices
3. Suggest practical code examples when relevant
4. If unsure, say so honestly
5. Always cite the satellite or sensor being discussed`;

Tips for Effective System Prompts

  • Be specific: "You are an EO assistant" is better than "You are a helpful assistant"
  • Define scope: List what topics the AI should and should not cover
  • Set format rules: "Be concise," "Use bullet points," "Include code examples"
  • Add constraints: "If you don't know, say so" prevents hallucinations
🎯
Challenge: After the lab, try customizing the system prompt for a specific EO topic you are interested in, such as flood monitoring, urban heat islands, or deforestation tracking.
❓

Quiz: Gemini API Concepts

Q3: What does the contents array in the Gemini API request body represent?
A A list of all available Gemini models
B The system prompt instructions for the model
C The conversation history: an ordered sequence of user and model message turns
D A list of file attachments to include in the response
βœ… Correct! The contents array holds the full conversation history. Each element has a role ("user" or "model") and parts containing the message text. The model uses this to understand context.
❌ Not quite. The contents array is the conversation history (turns with "user" and "model" roles). System instructions go in the separate system_instruction field.
πŸš€

Deploy to GitHub Pages

GitHub Pages gives you free hosting for static websites. Since our chat app is pure HTML/CSS/JS (no server needed), it deploys perfectly.

1

Initialize and Push Your Repository

Open a terminal in your project folder and run:

Bash (Terminal)
# Initialize a git repository
git init
git add .
git commit -m "feat: initial EO chat assistant"

# Create the repository on GitHub (use GitHub CLI or web UI)
# Then link and push:
git remote add origin https://github.com/YOUR_USER/eo-chat.git
git push -u origin main
2

Enable GitHub Pages

Go to your repository on GitHub → SettingsPages. Under "Source," select main branch and / (root) folder. Click Save.

3

Visit Your Live Site!

After a minute or two, your app will be live at:
https://YOUR_USER.github.io/eo-chat/

⚠️
Before pushing: Make sure your code uses prompt() for the API key (as shown in our complete app.js) instead of a hardcoded key. This way, each user enters their own key and nothing secret gets committed.
⚑

Bonus: Puter.js (Zero-Config AI)

Puter.js is an open-source library that gives you free, unlimited AI access with no API keys required. It handles authentication and billing for you. Here is how simple it is:6

HTML (complete Puter.js chat, 30 lines)
<!DOCTYPE html>
<html>
<head>
  <title>EO Chat (Puter.js)</title>
  <script src="https://js.puter.com/v2/"></script>
</head>
<body>
  <h2>πŸ›°οΈ EO Chat (Puter.js)</h2>
  <div id="chat"></div>
  <input id="input" placeholder="Ask about EO...">
  <button onclick="ask()">Send</button>

  <script>
    async function ask() {
      const input = document.getElementById('input');
      const chat  = document.getElementById('chat');

      chat.innerHTML += `<p><b>You:</b> ${input.value}</p>`;

      // That's it! No API key needed!
      const response = await puter.ai.chat(
        input.value
      );

      chat.innerHTML += `<p><b>AI:</b> ${response.message.content}</p>`;
      input.value = '';
    }
  </script>
</body>
</html>

When to Use Each Approach

Approach Best For Trade-offs
Direct API (Gemini/Groq) Full control, model selection, streaming Requires API key management
Puter.js Quick prototyping, demos, hackathons Less control over model choice
πŸŽ“

Summary of Big Ideas & Glossary

1

AI APIs Are Just HTTP Requests

Calling an AI model is the same as calling any web API: send JSON via fetch(), receive JSON back. No magic, just HTTP.

2

LLMs Are Stateless

The model has no memory between calls. You must send the entire conversation history with every request to maintain context.

3

System Prompts Shape Behavior

A well-crafted system prompt transforms a generic model into a domain-specific assistant. Prompt engineering is a core AI skill.

4

Security Is Non-Negotiable

Never expose API keys in production code. Use backend proxies, environment variables, or key-free services like Puter.js.

5

Static Sites Are Powerful

A pure HTML/CSS/JS application with client-side API calls can be deployed for free on GitHub Pages with zero infrastructure.

Glossary of Key Terms

API Key
A secret token that authenticates your application with an API service, controlling access and usage tracking.
REST API
Representational State Transfer API: a web service architecture using standard HTTP methods (GET, POST) and JSON data exchange.
JSON
JavaScript Object Notation: a lightweight data format using key-value pairs, widely used for API communication.
Streaming
A response mode where the server sends data in chunks as it is generated, enabling real-time display of partial results.
System Prompt
Hidden instructions sent with every API call that define the AI's role, expertise, behavior rules, and response format.
GitHub Pages
A free static site hosting service by GitHub that serves HTML/CSS/JS directly from a repository's branch.
Deployment
The process of making an application available to users, typically by uploading code to a hosting service.
Context Window
The maximum number of tokens (words and subwords) a model can process in a single request, including input and output.
Token
The smallest unit of text processed by an LLM. Roughly 1 token = 0.75 words in English. Used for billing and context limits.

References

  1. [1] Google. "Gemini API Pricing." Google AI for Developers, 2025. https://ai.google.dev/pricing
  2. [2] Google. "Gemini API Reference: generateContent." Google AI for Developers, 2025. https://ai.google.dev/api/generate-content
  3. [3] Google. "Streaming with the Gemini API." Google AI for Developers, 2025. https://ai.google.dev/gemini-api/docs/text-generation
  4. [4] Google. "Gemini Models: Context Window." Google AI for Developers, 2025. https://ai.google.dev/gemini-api/docs/models
  5. [5] Google. "System Instructions." Gemini API Docs, 2025. https://ai.google.dev/gemini-api/docs/system-instructions
  6. [6] Puter. "Free Unlimited AI." Puter.js Documentation, 2025. https://docs.puter.com/tutorials/free-unlimited-ai
  7. [7] GitHub. "GitHub Pages Documentation." GitHub Docs, 2025. https://docs.github.com/en/pages
  8. [8] Groq. "Groq API Documentation." Groq Console, 2025. https://console.groq.com/docs
🌟 Pioneer Profile
πŸ‘€

Geoffrey Hinton

Godfather of AI

His pioneering work on artificial neural networks and deep learning laid the foundation for modern LLMs.

🌍 Local to Global

Global Data, Local Impact

Applying EO to Community Challenges

Earth Observation provides a macroscopic view of environmental trends, but its true power lies in downscaling this data to affect local policy and design, such as urban planning and sustainable workplaces.

πŸ“
Texas Connection: In Texas, EO data is used to monitor the Edwards Aquifer depletion and track the expansion of urban heat islands across the Dallas-Fort Worth metroplex.
πŸ—ΊοΈ
πŸ€” Geographic Inquiry

Regional Decisions Scenario

Scenario: Automating Spatial Analysis

Your team needs to process thousands of unstructured reports on workplace well-being and map them to physical office locations.

Your Task:

  • Design an LLM prompt to extract location entities.
  • Map the sentiment to physical coordinates.
πŸ“š Summary

Big Ideas & Glossary

Summary of Big Ideas

  • Data is only as valuable as its application.
  • Space technology has direct terrestrial benefits.

Glossary of Terms

Earth Observation
Gathering information about Earth via remote sensing.
πŸ“ Knowledge Check

Auto-Graded Quiz

What does an LLM API primarily return when given a prompt?
A
A direct SQL database query
B
A probabilistic prediction of the next tokens (text)
C
A rendered HTML web page
βœ… Correct! LLMs generate text by predicting the next most likely tokens based on the prompt.
❌ Incorrect. The right answer was B. LLMs generate text by predicting the next most likely tokens based on the prompt.

πŸ“ Daily Reflection

What was your biggest takeaway from this session, and how does it apply to the TERRA project? Write your response below. Your instructor will review this to track your progress.