Skip to content

Weather Demo (Vue.js)

This demo showcases a weather tool that uses the Open-Meteo API to fetch and display weather information. You can interact with the tool using natural language to get weather forecasts for different locations.



No weather data available. Use the get_weather tool to fetch weather information for a location.
Ask the AI to get the weather for a specific location (e.g., "What's the weather in New York?").

Code

vue
<template>
  <div class="weather-demo">
    <tool name="get_weather" description="Get the current weather for a location" @call="getWeather" return>
      <prop name="location" type="string" description="The location to get the weather for." required />
    </tool>
    <context name="weather_data">
      {{ weatherDataContext }}
    </context>
    <div v-if ="!weather && !loading && !error" class="no-weather">
      <em>
        Ask the AI to get the weather for a specific location (e.g., "What's the weather in New York?").
      </em>
    </div>
    <div v-if="loading" class="loading">Loading...</div>
    <div v-if="error" class="error">{{ error }}</div>
    <div v-if="weather" class="weather-display">
      <h2>Weather in {{ weather.city }}, {{ weather.country }}</h2>
      <div class="current-weather">
        <div class="weather-icon">
          <span class="weather-icon">{{ getWeatherIcon(weather.current.weather_code) }}</span>
        </div>
        <div class="weather-details">
          <p class="temperature">{{ weather.current.temperature_2m }}°C</p>
          <p class="condition">{{ getWeatherDescription(weather.current.weather_code) }}</p>
        </div>
      </div>
      <h3>7-Day Forecast</h3>
      <div class="forecast">
        <div v-for="(day, index) in weather.daily.time" :key="day" class="forecast-day">
          <p class="date">{{ new Date(day).toLocaleDateString('en-US', { weekday: 'short' }) }}</p>
          <span class="forecast-icon">{{ getWeatherIcon(weather.daily.weather_code[index]) }}</span>
          <p class="temp-range">
            {{ weather.daily.temperature_2m_max[index] }}° / {{ weather.daily.temperature_2m_min[index] }}°
          </p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

const weather = ref(null);
const loading = ref(false);
const error = ref(null);

const weatherDataContext = computed(() => {
  if (!weather.value) {
    return "No weather data available. Use the get_weather tool to fetch weather information for a location.";
  }
  return `Current weather in ${weather.value.city}, ${weather.value.country}: ${weather.value.current.temperature_2m}°C and ${getWeatherDescription(weather.value.current.weather_code)}.`;
});

async function getWeather(event) {
  const { location } = event.detail;
  loading.value = true;
  error.value = null;

  try {
    const geoResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${location}`);
    const geoData = await geoResponse.json();

    if (!geoData.results || geoData.results.length === 0) {
      throw new Error("Location not found.");
    }

    const { latitude, longitude, name, country } = geoData.results[0];

    const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto`);
    const weatherData = await weatherResponse.json();
    
    weather.value = { ...weatherData, city: name, country };

    event.target.dispatchEvent(new CustomEvent('return', { detail: weatherData }));
  } catch (e) {
    error.value = e.message;
    event.target.dispatchEvent(new CustomEvent('return', { detail: { error: e.message } }));
  } finally {
    loading.value = false;
  }
}

function getWeatherIcon(code) {
  const icons = {
    0: '☀️', // Clear sky
    1: '🌤️',      // Mainly clear
    2: '☁️',          // Partly cloudy
    3: '☁️',         // Overcast
    45: '🌫️',      // Fog
    48: '🌫️',      // Depositing rime fog
    51: '🌦️',  // Drizzle, light
    53: '🌦️',  // Drizzle, moderate
    55: '🌦️',  // Drizzle, dense
    61: '🌧️',     // Rain, slight
    63: '🌧️',     // Rain, moderate
    65: '🌧️',// Rain, heavy
    80: '🌧️',     // Showers, slight
    81: '🌧️',     // Showers, moderate
    82: '🌧️',// Showers, violent
    95: '⛈️', // Thunderstorm
  };
  return icons[code] || '❓';
}

function getWeatherDescription(code) {
    const descriptions = {
        0: 'Clear sky',
        1: 'Mainly clear',
        2: 'Partly cloudy',
        3: 'Overcast',
        45: 'Fog',
        48: 'Depositing rime fog',
        51: 'Light drizzle',
        53: 'Moderate drizzle',
        55: 'Dense drizzle',
        61: 'Slight rain',
        63: 'Moderate rain',
        65: 'Heavy rain',
        80: 'Slight showers',
        81: 'Moderate showers',
        82: 'Violent showers',
        95: 'Thunderstorm',
    };
    return descriptions[code] || 'Unknown';
}
</script>

<style scoped>
.weather-demo {
  font-family: sans-serif;
  max-width: 600px;
  margin: auto;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.loading, .error {
  text-align: center;
  padding: 20px;
  font-size: 1.2em;
}
.error {
  color: #d9534f;
}
.weather-display {
  text-align: center;
}
.current-weather {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 20px;
}
.weather-icon span {
  font-size: 4em;
  margin-right: 20px;
}
.temperature {
  font-size: 2.5em;
  font-weight: bold;
  margin: 0;
}
.condition {
  font-size: 1.2em;
  color: #666;
  margin: 0;
}
.forecast {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
}
.forecast-day {
  text-align: center;
}
.forecast-day .forecast-icon {
  font-size: 2em;
  margin: 10px 0;
}

h2 {
  margin-top: 0;
  border: none;
}
</style>

Released under the MIT License.