2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MarkdownAIで、昨日と今日の天気を比較できるアプリを作った

Last updated at Posted at 2025-02-08

はじめに

ようやく長い猛暑が終わったと思っていたら、2月に入ってからとても寒い日が続いて大変ですね。
温度や天気に対する感覚があまりないので、「今日の最高気温は11度です」と言われても、結局寒いのか暑いのか分からず、外に出ると「寒っ!」となって困っています。

そこで、今日の天気予報だけでなく、昨日の天気と比較して、「昨日より厚着をしたら良いんだな」「薄着のほうが良いんだな」と判断できるような、簡単なアプリを作ってみました。

スクリーンショット 2025-02-08 15.34.18.png

今日は昨日より暑い?寒い?(東京の天気)

MarkdownAI

今回はMarkdownAIというサービスを使ってみることにしました。
MarkdownAIは、Markdown記法を使って簡単にWebサイトを作成・公開できるサービスです。
Notionのようにサクッとコンテンツを公開することができますが、HTML/CSSやJavaScriptにも対応しているので見た目にも機能にもこだわったアプリを作ることが可能。
さらに、簡単にチャットボットを作ることができるロボットAI機能や、画像生成AIによって生成した画像をサクッと挿入できる機能もあって、全部無料

Streamlitなども良いですが、MarkdownAIはもっと手軽で良いですね。

スクリプト

スクリーンショット 2025-02-08 15.43.51.png

Markdown部分

書き始めはMarkdownから。シンプルに、次のように記述するだけで済んでいます。

# 今日は昨日より暑い?寒い?
## (東京の天気)

画像生成AI部分

Insertから「AI Image」を選択することで、簡単に画像生成と画像の挿入を行うことができました。
今回は、アプリのバナー的な、アイキャッチ的な画像を作って挿し込むことにしました。

スクリーンショット 2025-02-08 15.43.52.png
スクリーンショット 2025-02-08 15.46.01.png

プロンプトはシンプルに、様々な天気のロゴとしました。
生成されたのは次の画像。シンプルで良い感じです。

Javascript部分

昨日の天気のデータはこちらから、今日・明日の天気のデータはこちらから、ありがたく使わせていただきました。
私が住んでいる東京の天気を知りたく、実際に取得するデータのURLはそれぞれ次のものです。

<script>
    async function fetchWeatherData() {
        const pastData = await fetch("https://api.cultivationdata.net/past?prec=44&no=47662")
            .then(res => res.json())
            .catch(() => null);

        const forecastData = await fetch("https://weather.tsukumijima.net/api/forecast/city/130010")
            .then(res => res.json())
            .catch(() => null);

        if (pastData) {
            displayWeather('yesterday', formatPastData(pastData));
        }

        if (forecastData) {
            displayWeather('today', formatForecastData(forecastData, 0));
            displayWeather('tomorrow', formatForecastData(forecastData, 1));
        }
    }

    function formatPastData(data) {
        const cityData = Object.values(data)[0];
        const rawDate = Object.keys(cityData)[0];
        const weatherData = Object.values(cityData)[0];
        const date = new Date(rawDate);
        const formattedDate = date.toISOString().split('T')[0];

        return {
            date: formattedDate,
            dayOfWeek: ['', '', '', '', '', '', ''][date.getDay()],
            maxTemp: parseFloat(weatherData["最高気温"]).toFixed(1),
            minTemp: parseFloat(weatherData["最低気温"]).toFixed(1),
            precipitation: weatherData["合計降水量"] === "--" ? "0.0mm" : `${weatherData["合計降水量"]}mm`
        };
    }

    function formatForecastData(data, index) {
        const forecast = data.forecasts[index];
        const date = new Date(forecast.date);
        const temp = forecast.temperature;

        const formatTemp = (tempValue) => {
            if (!tempValue || isNaN(parseFloat(tempValue.celsius))) {
                return "--";
            }
            return parseFloat(tempValue.celsius).toFixed(1);
        };

        return {
            date: forecast.date,
            dayOfWeek: ['', '', '', '', '', '', ''][date.getDay()],
            maxTemp: formatTemp(temp.max),
            minTemp: formatTemp(temp.min),
            precipitation: forecast.chanceOfRain ? 
                Math.max(
                    parseInt(forecast.chanceOfRain["06-12"] || 0),
                    parseInt(forecast.chanceOfRain["12-18"] || 0)
                ) + "%" : "N/A",
            image: forecast.image
        };
    }

    function displayWeather(elementId, data) {
        const titles = {
            yesterday: '昨日',
            today: '今日',
            tomorrow: '明日'
        };

        const imageHtml = data.image ? 
            `<img src="${data.image.url}" alt="${data.image.title}">` :
            '<div class="placeholder-image"></div>';

        document.getElementById(elementId).innerHTML = `
            <h2>${titles[elementId]}
                <span class="date-label">${data.date} ${data.dayOfWeek}</span>
            </h2>
            ${imageHtml}
            <div class="weather-info">
                <p>最高気温: ${data.maxTemp}℃</p>
                <p>最低気温: ${data.minTemp}℃</p>
                <p>${elementId === 'yesterday' ? '降水量' : '降水確率'}: ${data.precipitation}</p>
            </div>
        `;
    }

    fetchWeatherData();
</script>

CSS部分

少しだけアプリっぽくするために、見た目を整形しています。

<style>
    body {
        text-align: center;
    }
    #yesterday, #today, #tomorrow {
        margin: 10px;
        padding: 10px;
        border: 1px solid #ccc;
        display: inline-block;
        width: 250px;
        height: 300px;
        vertical-align: top;
    }
    #today {
        background-color: #e6f3ff;
    }
    h1 {
        font-size: 1.4em;
    }
    h2 {
        font-size: 1.2em;
        margin: 10px 0;
    }
    .date-label {
        font-size: 0.9em;
        display: block;
    }
    .weather-info p {
        margin: 5px 0;
    }
    .placeholder-image {
        width: 100px;
        height: 100px;
        margin: 10px auto;
        background-color: #f8f8f8;
    }
    img {
        margin: 10px auto;
        width: 100px;
        height: 100px;
        display: block;
    }
</style>

おわりに

これで簡単に、昨日と今日(と明日)の天気を比較できるアプリを作って公開することができました。
これで簡単に外出時の服装を決めることができそうです〜。

また、チャットボット機能を使って、今日のおすすめの服装を提案してくれるアプリにしても良かったなあと思っています。

(とはいえしばらくはずっと寒いでしょうから、ひたすら厚着でしょうね)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?