最近話題のChatGPT。文章だけでなく、プログラミングコードの生成もできるなど、使いどころがとても多いAIとなっています。

今回はそんなChatGPTを使って、Monacaで使えるアプリを作ってみました。色々なパターンで試してみたので、参考にしてください。

作ったアプリ

今回作ったのはQiitaのAPIを使ってJSONを取得し、その結果を画面に一覧表示するというアプリです。

成功パターン

まず成功したパターンです。これは2つあります。

英語でOnsen UIを使ってリスト表示を行う

入力したプロンプトは以下のようになります。

Using Onsen UI, write a program to retrieve and list Qiita articles via JSON API

ChatGPTは日本語も使えますが、英語でプロンプトを書いた方が情報が多い傾向があります。

この結果として得られたHTMLは以下の通りです。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/onsenui@2.11.2/js/onsenui.min.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/onsenui@2.11.2/css/onsenui.min.css">
  <link rel="stylesheet" href="https://unpkg.com/onsenui@2.11.2/css/onsen-css-components.min.css">
  <script src="app.js"></script>
</head>
<body>
  <ons-navigator id="navigator">
    <ons-page>
      <ons-toolbar>
        <div class="center">Qiita Articles</div>
      </ons-toolbar>
      <ons-button onclick="loadArticles()">Load Articles</ons-button>
      <ons-list id="articlesList">
      </ons-list>
    </ons-page>
  </ons-navigator>
</body>
</html>

そしてJavaScript(app.js)は以下の通りです。

const API_URL = 'https://qiita.com/api/v2/items';

async function loadArticles() {
  try {
    const response = await fetch(API_URL);
    if (!response.ok) {
      throw new Error(`Error fetching data: ${response.status} ${response.statusText}`);
    }
    const articles = await response.json();
    displayArticles(articles);
  } catch (error) {
    console.error(error);
  }
}

function displayArticles(articles) {
  const list = document.getElementById('articlesList');
  list.innerHTML = '';

  for (const article of articles) {
    const listItem = document.createElement('ons-list-item');
    listItem.setAttribute('tappable', true);
    listItem.setAttribute('modifier', 'chevron');
    listItem.setAttribute('onclick', `window.open('${article.url}', '_blank')`);
    listItem.innerHTML = `
      <div class="left">
        <img class="list-item__thumbnail" src="${article.user.profile_image_url}">
      </div>
      <div class="center">
        <span class="list-item__title">${article.title}</span>
        <span class="list-item__subtitle">${article.user.id}</span>
      </div>
    `;
    list.appendChild(listItem);
  }
}

アプリを表示すると、まずボタンだけが表示されます。

そしてボタンをクリックすると、記事が読み込まれます。プロフィール画像が表示されている辺りがポイント高いです。

日本語でOnsen UIを使ってリスト表示を行う

続いてプロンプトに日本語を使った場合です。テキストは以下の通りです。

Onsen UIを使って、Qiita APIで記事を取得してリスト表示するコードを書いてください

この場合のHTMLは以下の通りです。

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.min.css">
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
    <script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/vue-onsenui"></script>
  </head>
  <body>
    <div id="app">
      <template>
        <v-ons-page>
          <v-ons-toolbar>
            <div class="center">Qiita 記事リスト</div>
          </v-ons-toolbar>
          <v-ons-list>
            <v-ons-list-item v-for="item in items" :key="item.id">
              {{ item.title }}
            </v-ons-list-item>
          </v-ons-list>
        </v-ons-page>
      </template>
    </div>
    <script src="app.js"></script>
  </body>
</html>

そしてJavaScriptは以下の通りです。

Vue.use(VueOnsen);

new Vue({
  el: '#app',
  data() {
    return {
      items: []
    };
  },
  created() {
    this.fetchQiitaArticles();
  },
  methods: {
    async fetchQiitaArticles() {
      const response = await fetch('https://qiita.com/api/v2/items');
      const data = await response.json();
      this.items = data;
    }
  }
});

このコードは一見良さそうに見えますが、VueOnsenがなかったり window.Vue.use is not a function といったエラーが出たりして動きませんでした。そこで以下のように書いて、Vueを外しました。

Vueは使わない形にしてください

結果として出力されたHTMLは以下の通りです。

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.min.css">
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
    <script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
  </head>
  <body>
    <ons-page>
      <ons-toolbar>
        <div class="center">Qiita 記事リスト</div>
      </ons-toolbar>
      <ons-list id="qiita-list">
      </ons-list>
    </ons-page>
    <script src="app.js"></script>
  </body>
</html>

そしてJavaScriptは以下の通りです。

document.addEventListener("DOMContentLoaded", () => {
  fetchQiitaArticles();
});

async function fetchQiitaArticles() {
  const response = await fetch("https://qiita.com/api/v2/items");
  const data = await response.json();
  const qiitaList = document.getElementById("qiita-list");

  data.forEach(item => {
    const listItem = document.createElement("ons-list-item");
    listItem.innerText = item.title;
    qiitaList.appendChild(listItem);
  });
}

結果は次の通りです。アプリを表示するといきなり一覧が表示されます。英語版と異なり、画像はありません。また、 DOMContentLoaded を使っていますがOnsen UIなので ons.ready を使って欲しかったです。

後、出力された内容ではUTF-8指定がなかったので、ヘッダーの文字列が文字化けしてしまいました。これは別途追記しています。

うまくいかなったパターン

続いてうまくいかなかったパターンです。これはFramework7を使ったプロンプトです。

Framework7を使って、Qiitaの記事をJSON APIで取得して一覧表示するプログラムを書いてください

これの実行結果として出力されたのが以下のHTMLです。これは src/components/qiita-posts.html というファイル名で保存するように指示されます。

<!-- src/components/qiita-posts.html -->
<template>
  <div class="list">
    <ul>
      {{#each posts}}
        <li>
          <a href="{{url}}" target="_blank" class="item-link item-content">
            <div class="item-inner">
              <div class="item-title">{{title}}</div>
            </div>
          </a>
        </li>
      {{/each}}
    </ul>
  </div>
</template>
<script>
  export default (props, { $f7, $on }) => {
    const [posts, setPosts] = $f7.$reactive([]);

    $on("page:init", async () => {
      const fetchedPosts = await fetchQiitaPosts();
      setPosts(fetchedPosts);
    });

    return $render;
  };
</script>

さらに src/pages/home.f7.html というファイルを以下の内容で作成します。

<!-- src/pages/home.f7.html -->
<template>
  <div class="page" data-name="home">
    <div class="navbar">
      <div class="navbar-inner">
        <div class="title">Qiita Posts</div>
      </div>
    </div>
    <div class="page-content">
      <qiita-posts></qiita-posts>
    </div>
  </div>
</template>
<script>
  import QiitaPosts from "../components/qiita-posts.html";
  export default {
    components: {
      QiitaPosts,
    },
  };
</script>

最後に src/js/app.js に以下の関数を追加します。

async function fetchQiitaPosts() {
  const response = await fetch("https://qiita.com/api/v2/items?page=1&per_page=20");
  const json = await response.json();
  return json;
}

このコードの面白いところは f7.htmlというFramework7専用の書き方に沿っていることです。また、 $f7.$reactive というのを使っていますが、これは存在しないように思います。Vue辺りの使い方が混ざっているように見えます。

利用時の注意点

ChatGPTの現状のデータが2021年9月あたりまでとなっている点に注意が必要です。その後に出てきた技術や、バージョンアップには追従していない可能性が高いです。特にFramework7は先日バージョン8が出たばかりなので、 CDNの最新版JavaScriptやCSSを読み込む形では動かない可能性が高いです。

これはReactやVueなど、バージョンアップが頻繁なライブラリでも同様のことが言えそうです。そうした意味においてはOnsen UIの書き方は長く変わっていませんので、ChatGPTの提示するコードは問題なく動作するようです。

プロンプトを英語で書くか、日本語で書くかはどちらでも良さそうです。今回は日本語の場合は英語ほどリッチなUIにはなりませんでしたが、別な時に実行すればまた違う結果が得られるでしょう。

ChatGPT3.5と4については、確実に4を使った方が良いです。結果の優秀さは確実に上がっていますので、3.5よりも適切なコードが得られるはずです。もちろん、そのコードが望んだとおりの動きになっているかは要確認です。

まとめ

ChatGPTの出力するコードは、ネットで探してから自分の望んだ形にするというステップを省略してくれます。もちろん、その出力結果の精査は個人にかかってきますが、最初のたたき台になるコードを手軽に手に入るのはありがたいです。

ちょっとしたデモアプリやサンプルレベルのコードであればChatGPTでも十分というケースは多そうです。