✍️

生成AIで実現する"私専用の学び空間" 〜パーソナライズ教育の未来〜

2024/10/25に公開

生成AIで実現する"私専用の学び空間" 〜パーソナライズ教育の未来〜

今回は、学びが早く楽しくなるために生成AIを活用して「私だけの教材」を作る方法を紹介します。

自分の好きなシチュエーションを題材にしたTOEIC文法問題を生成AIに生成してもらい、さらに生成してもらった問題を解くことができるアプリも生成AIに作成してもらう方法も紹介します。

作成するTOEIC問題アプリ画面例

1. なぜ「私だけの教材」が必要なのか?

従来の「一斉学習」や「画一的な教材」では、個々の学習者のニーズを十分に満たすことが難しいです。私たち一人一人が持つ興味、理解度、学習スタイルは千差万別だからです。

ここで生成AIの特性を生かして、「私だけの教材」を作ることが非常に有効です。

「私だけの教材」を使うことで、以下のような利点が得られます:

  1. 完全オーダーメイド: 自分の興味、レベル、目標に100%マッチした内容を学べる
  2. 進度に合わせた調整: 自分の理解度に応じて、教材の難易度を柔軟に変更できる
  3. 豊富な学習素材: 飽きることなく、常に新鮮で自分に関連する教材で学習できる
  4. 即時フィードバック: 質問への迅速な回答や、詳細な解説をその場で得られる
  5. モチベーション維持: 自分の興味に沿った題材で、学習意欲を持続的に保てる

これらの要素により、学びが速く、そして何より楽しくなります。

2. 生成AIで「私だけの教材」を作ってみよう!

では、実際に皆さん自身が生成AIを活用して、「私だけの教材」を作る方法を紹介します。
ここでは、ChatGPTなどのチャットインターフェースを使用することを前提に、誰でも簡単に試せる手順を説明します。

2.1 基本的なプロンプトの構造

TOEIC学習を例に、自分専用の問題を生成するための基本的なプロンプト構造を紹介します。

#パラメータ設定
カテゴリ名 = {param1}  
問題数 = {param2}  
目標スコア = {param3}   
シチュエーション = {param4}   

以下の形式に従って、TOEICの{カテゴリ名}に関する問題を{問題数}個生成してください。
ただし、問題のレベルは{目標スコア}点相当であり、かつ「{シチュエーション}」にマッチするような英文を活用した問題にしてください。
各問題は、文中の空欄に入る適切な選択肢を選択する形式にしてください。
問題文と選択肢の間に空行を入れてください。

explanationには、以下のフォーマットに従い、フレンドリーで寄り添った優しい口調で、初学者でもわかりやすい丁寧な説明を心がけ、具体例を交えて解説してください。
また、該当問題を解く上で押さえるべき秘訣(テクニック)を1つ簡潔に提示してください。

重要: 以下の既存の問題と同じ、または酷似した問題は生成しないでください。
===
{既に作成済みの問題画あればここに張り付けておく}
===
#explanationのフォーマット:
## 日本語訳
ここに問題英文の日本語訳を記載する。

## 各選択肢の意味
ここに選択肢の意味を記載する。

## 単語の意味
ここに選択肢以外でTOEIC試験で重要な用語の意味を捕捉説明する。

## 解説
ここに解説を記載する。

## 解法のポイント
この問題を解くための秘訣、ポイントを出来るだけ具体的に記載する。

出力形式:
1. 問題文(空欄には '___' を使用)
A) 選択肢A
B) 選択肢B
C) 選択肢C
D) 選択肢D

正解: [正解の選択肢]

explanation:
[上記のフォーマットに従った説明]

2. [次の問題...]

2.2 プロンプトの実行方法

まずは、以下の3ステップで先ほどのプロンプトを生成AIに投げてみましょう。

  1. 生成AI(ChatGPTなど)のチャット画面を開きます。

  2. 上記のプロンプト構造をコピーし、{param1} から{param4}の値を設定します。

    • [カテゴリ名]: 問題の種類を指定する。例えば「品詞問題(2つの名詞、名詞の単数形と複数形、復号名詞)
    • [問題数]: 生成したい問題の数(例:5)
    • [目標スコア]: あなたの目標とするTOEICスコア(例:700, 800, 900など)
    • [シチュエーション]: あなたの興味や状況に合わせたシチュエーション(例:「海外旅行」、「ゲームに関する話題」、「日本料理」など)
  3. 変更したプロンプトをチャットに貼り付けて送信します。

例として以下の設定でプロンプトを投げてみます。

#パラメータ設定
カテゴリ名 = 品詞問題②(2つの名詞、名詞の単数形と複数形、復号名詞)
問題数 = 1
目標スコア = 700
シチュエーション = 宇宙の話題

シチュエーションにより具体的な情報を記載すれば、自分が好きな話題にマッチした問題を生成することができます。(例:xxアニメの名シーン、xxゲームに関する話題)

ただし、著作権侵害の可能性を考慮して、ゲームタイトル、キャラクター名等の具体的な情報を使った問題文を生成させた場合は、完全に私的な使用に留めたほうがよいです。

以下は生成AIの回答例です。

承知いたしました。宇宙の話題に関連し、TOEIC 700点相当の品詞問題(2つの名詞、名詞の単数形と複数形、復号名詞)を1問生成いたします。

1. The recent discovery of a new ___ in a distant galaxy has excited astronomers, who believe it could provide valuable insights into the early stages of cosmic evolution.

A) phenomenon
B) phenomena
C) phenomenons
D) phenomenas

正解: A) phenomenon

explanation:
## 日本語訳
遠い銀河で最近発見された新しい現象は、宇宙進化の初期段階について貴重な洞察を提供する可能性があると考える天文学者たちを興奮させています。

## 各選択肢の意味
A) phenomenon: 現象(単数形)
B) phenomena: 現象(複数形)
C) phenomenons: 現象(不規則な複数形、一般的ではない)
D) phenomenas: 現象(誤った複数形)

## 単語の意味
- discovery: 発見
- distant: 遠い
- galaxy: 銀河
- astronomer: 天文学者
- valuable: 貴重な
- insight: 洞察
- cosmic evolution: 宇宙進化

## 解説
この問題では、文脈から単数形が適切であることがわかります。「a new ___」という表現が使われていることから、単数形が求められています。「phenomenon」は不規則な複数形を持つ名詞で、その複数形は「phenomena」です。

正解は A) phenomenon です。これは「現象」を意味する単数形です。B) phenomena は複数形で、ここでは適切ではありません。C) phenomenons は一般的ではない不規則な複数形で、通常は使用しません。D) phenomenas は完全に誤った形です。

## 解法のポイント
不規則な複数形を持つ名詞に注意しましょう。「-on」で終わる単語(例:phenomenon, criterion)は、多くの場合「-a」で終わる複数形(phenomena, criteria)を持ちます。また、「a/an + 名詞」の形があれば、その名詞は必ず単数形になることを覚えておくと良いでしょう。この問題では「a new ___」という表現が単数形を示す重要な手がかりとなっています。

2.3 疑問点を追加で質問してみる

チャット形式で生成AIを活用する場合のメリットは、続けて会話できる点です。
先ほど回答してもらった問題に対して追加の質問を投げてみましょう。

私の質問

phenomena: 現象(複数形)を使う例文を1つ挙げてください。

生成AIの回答例

もちろんです。「phenomena」を使用した例文を挙げさせていただきます。



例文: Various atmospheric phenomena, such as auroras and rainbows, have fascinated humans for centuries.

日本語訳: オーロラや虹のような様々な大気現象は、何世紀にもわたって人々を魅了してきました。

この文では、「phenomena」が複数形で使用されています。「various」(様々な)という形容詞が使われていることや、具体例として「auroras and rainbows」(オーロラと虹)という複数の現象が挙げられていることから、複数形の「phenomena」の使用が適切となっています。

この例文は、自然現象という宇宙に関連するトピックを扱っており、先ほどの問題の文脈とも一致しています。

このように疑問点や追加の質問があった際に、会話形式で生成AIとコミュニケーションをとることで追加の質問に対して即座にフィードバックしてもらえるのが生成AIの素晴らしい点です。

生成AIを活用することで、市販されてる書籍等の勉強商材では提供されない大きな付加価値を提供してくれます。

3. TOEICアプリで体験する「私だけの教材」

では、先ほどのTOEIC問題を生成するプロンプトを活用したアプリを開発してみましょう。
今回は、アプリ開発の知識がない人でも簡単にTOEIC問題を解けるアプリを作成する手順を紹介します。

ステップ1(要件定義書を作成してもらう)

まずは、作成したいTOEIC問題アプリの要件を生成AIに伝えて要件定義書を作成してもらいましょう。
いきなり「●●のアプリを作って」というより、最初に作りたいことを伝えて要件定義書を作成してもらうことでこちらが意図した要件を生成AIが正確に把握しているか確認することができます。

以下は、サンプルの指示内容です。
要件は適宜修正してもらえばOKです。
#プロンプトは先ほどの問題生成プロンプトそのままの情報です。

以下の#プロンプトは、あなたがTOEICの問題を生成するための指示内容です。

#依頼事項
このプロンプトを使ってあなたが出力した出力内容を利用して、ローカルPC上でhtmlとCSSとJavascriptだけで動くTOEIC問題アプリを作成してほしいです。
まずは、#要件の概要を満たす要件定義書を作成してください。

#要件の概要

##  目的
- TOEICテスト対策のための練習問題を提供するhtmlだけで動くローカルアプリケーション
- 問題の難易度や分野別の学習機会の提供

## 対象ユーザー
- TOEICテスト受験予定者
- ビジネス英語力の向上を目指す学習者

## 機能要件

- 問題出題機能
   - シチュエーション設定の表示
   - 問題文の提示
   - 複数選択肢の提供
   - 進捗状況のプログレスバー表示

- 採点・フィードバック機能
   - 「回答確認」ボタンを押した際に「正解、不正解」を判定して表示する機能
   - 詳細な解説の提供
   - 正解の表示
   - スコアの集計

## ナビゲーション機能
   - 次の問題への移動
   - クイズの再開/リスタート
   - 結果の表示

## デザイン
- デザイン要素
   - モダンで見やすいUI/UX
   - レスポンシブデザイン
   - アニメーションによる視覚的フィードバック
   - 解説欄は見出しごとに統一感のある背景色をつける。文字は白色を希望。
   - 全体的にダーク系で人にとって視覚的に見やすい配色の組み合わせを適用。

## 操作性
   - 直感的な選択肢の選択
   - クリアな進行状況の表示
   - シンプルな操作フロー
   - 適切なボタン配置

## サンプルデータ
  - サンプルで3問問題文と回答データを生成して繰み込んでください。

#プロンプト
=================
#パラメータ設定
カテゴリ名 = {param1}  
問題数 = {param2}  
目標スコア = {param3}   
シチュエーション = {param4}   

以下の形式に従って、TOEICの{カテゴリ名}に関する問題を{問題数}個生成してください。
ただし、問題のレベルは{目標スコア}点相当であり、かつ「{シチュエーション}」にマッチするような英文を活用した問題にしてください。
各問題は、文中の空欄に入る適切な選択肢を選択する形式にしてください。
問題文と選択肢の間に空行を入れてください。

explanationには、以下のフォーマットに従い、フレンドリーで寄り添った優しい口調で、初学者でもわかりやすい丁寧な説明を心がけ、具体例を交えて解説してください。
また、該当問題を解く上で押さえるべき秘訣(テクニック)を1つ簡潔に提示してください。

重要: 以下の既存の問題と同じ、または酷似した問題は生成しないでください。
===
{既に作成済みの問題画あればここに張り付けておく}
===
#explanationのフォーマット:
## 日本語訳
ここに問題英文の日本語訳を記載する。

## 各選択肢の意味
ここに選択肢の意味を記載する。

## 単語の意味
ここに選択肢以外でTOEIC試験で重要な用語の意味を捕捉説明する。

## 解説
ここに解説を記載する。

## 解法のポイント
この問題を解くための秘訣、ポイントを出来るだけ具体的に記載する。

出力形式:
1. 問題文(空欄には '___' を使用)
A) 選択肢A
B) 選択肢B
C) 選択肢C
D) 選択肢D

正解: [正解の選択肢]

explanation:
[上記のフォーマットに従った説明]

2. [次の問題...]
=================

以下はClaudeで実行した際のに出力例です。

生成AIが作成した要件定義書の例

# TOEICテスト対策アプリケーション要件定義書

## 1. プロジェクト概要

### 1.1 プロジェクトの目的
- ローカル環境で動作するTOEICテスト対策用Webアプリケーションの開発
- HTML/CSS/JavaScriptのみで実装される自己完結型アプリケーション
- 効果的な学習体験の提供による学習者のTOEICスコア向上支援

### 1.2 対象ユーザー
- TOEICテスト受験予定者
- ビジネス英語力の向上を目指す学習者
- 英語学習初級者から中級者

## 2. 機能要件

### 2.1 問題出題機能
#### 2.1.1 問題表示
- シチュエーション説明の表示
- 問題文の表示(英文)
- 4つの選択肢(A~D)の表示
- 現在の問題番号/総問題数の表示
- プログレスバーによる進捗表示

#### 2.1.2 回答機能
- ラジオボタンによる選択肢の選択
- 選択した回答のハイライト表示
- 回答確定ボタンの提供

### 2.2 採点・フィードバック機能
#### 2.2.1 採点機能
- 回答の正誤判定
- 正解・不正解の視覚的フィードバック
- 累計スコアの計算と表示

#### 2.2.2 解説表示
- 問題の日本語訳表示
- 各選択肢の意味説明
- 重要単語の解説
- 詳細な解説文
- 解法のポイント提示

### 2.3 ナビゲーション機能
- 次の問題へ進むボタン
- 問題一覧への戻るボタン
- クイズのリスタートボタン
- 結果確認画面への遷移

## 3. デザイン要件

### 3.1 全体デザイン
- ダークモードベースの配色
- コントラストの高い読みやすい文字表示
- モダンでクリーンなデザイン
- レスポンシブ対応(PC・タブレット・スマートフォン)

### 3.2 カラースキーム
#### 3.2.1 基本配色
- 背景色:ダークグレー (#1a1a1a)
- メインテキスト:白色 (#ffffff)
- アクセントカラー:ブルー (#3498db)

#### 3.2.2 解説セクションの配色
- 日本語訳セクション:深いブルー (#2c3e50)
- 選択肢解説セクション:深いパープル (#8e44ad)
- 単語解説セクション:深いグリーン (#27ae60)
- 解説セクション:深いレッド (#c0392b)
- 解法ポイントセクション:深いオレンジ (#d35400)

### 3.3 アニメーション要素
- 選択肢選択時のホバーエフェクト
- 正誤判定時のフェードイン/アウト
- プログレスバーのスムーズな更新
- 画面遷移時のトランジション効果

## 4. サンプルデータ仕様

### 4.1 問題データ構造

{
  questionNumber: Number,
  situation: String,
  question: String,
  choices: Array[4],
  correctAnswer: String,
  explanation: {
    translation: String,
    choiceExplanations: Array[4],
    vocabulary: Array,
    detailed: String,
    point: String
  }
}


### 4.2 サンプル問題数
- 初期実装時:3問
- 各問題は異なるビジネスシチュエーションを想定

## 5. 技術要件

### 5.1 開発言語・技術
- HTML5
- CSS3
- Vanilla JavaScript(フレームワーク不使用)

### 5.2 ファイル構成
- index.html(メインHTML)
- styles.css(スタイルシート)
- script.js(JavaScriptロジック)
- questions.js(問題データ)

### 5.3 動作環境
- モダンWebブラウザ(Chrome, Firefox, Safari, Edge最新版)
- ローカル環境での実行(サーバー不要)
- オフライン動作対応

## 6. 制約事項
- 外部ライブラリの不使用
- サーバーサイド処理の不使用
- ローカルストレージのみを使用したデータ保存

ステップ2(要件定義書の修正)

生成AIが回答した要件定義書を確認し、自分が意図した要件が正確に伝わっているかチェックしましょう。
たとえば、今回の例だと「採点機能」のところが以下の記載になっていますが、「正解・不正解の視覚的フィードバック」が具体的にどんな視覚的フィードバックか不明瞭なため生成AIが勝手に考えて機能を作ってしまいます。

### 2.2 採点・フィードバック機能
#### 2.2.1 採点機能
- 回答の正誤判定
- 正解・不正解の視覚的フィードバック
- 累計スコアの計算と表示

以下の様に具体的な要件を伝えることでより正確なアプリを生成してくれるようになります。

回答機能に以下を追加してください。
「判定」ボタンを押した際に、画面に「正解の選択肢と、選んだ選択肢が正解か、不正解かのメッセージを表示する機能」

追加の指示出しをすると、要件定義書を修正してくれます。

今回は以下の様に要件定義書をアップデートしてくれました。

#### 2.1.2 回答機能
- ラジオボタンによる選択肢の選択
- 選択した回答のハイライト表示
- 「判定」ボタンの提供
- 判定ボタン押下時の動作:
  1. 正解の選択肢を明確に表示
  2. ユーザーが選択した回答の正誤判定結果を表示
  3. 正解の場合:「正解です!」などの励ましメッセージを表示
  4. 不正解の場合:「不正解です。正解は[選択肢]です。」というメッセージを表示
- 判定結果の視覚的フィードバック:
  - 正解の選択肢を緑色でハイライト
  - 不正解を選択した場合、その選択肢を赤色でハイライト
- 「次の問題へ」ボタンの表示(判定後のみ)

### 2.2 採点・フィードバック機能
#### 2.2.1 採点機能
- 回答の正誤判定
- 正解・不正解の視覚的フィードバック
- 累計スコアの計算と表示
- 各問題の正誤履歴の保持と表示

ステップ3(開発を依頼)

要件がより具体的に生成AIに伝わったところで実際に開発を依頼します。

OKです。この要件定義書を満たすアプリを作成してください。
作成したすべてのhtmlコードを省略せず回答してください。

ちなみに、生成コードの情報が多くて途中で回答が切れてしまった場合は「続きを回答してください。」と依頼を出すと途中から回答してくれます。

今回の依頼で生成してくれたhtml全文の例

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TOEIC Practice App</title>
    <style>
        :root {
            --background-dark: #1a1a1a;
            --text-light: #ffffff;
            --accent-blue: #3498db;
            --correct-green: #2ecc71;
            --incorrect-red: #e74c3c;
            --section-blue: #2c3e50;
            --section-purple: #8e44ad;
            --section-green: #27ae60;
            --section-red: #c0392b;
            --section-orange: #d35400;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--background-dark);
            color: var(--text-light);
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
        }

        .progress-container {
            margin: 20px 0;
        }

        .progress-bar {
            width: 100%;
            height: 10px;
            background-color: #333;
            border-radius: 5px;
            overflow: hidden;
        }

        .progress-fill {
            height: 100%;
            background-color: var(--accent-blue);
            transition: width 0.3s ease;
        }

        .question-container {
            background-color: #2a2a2a;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
        }

        .situation {
            color: var(--accent-blue);
            margin-bottom: 15px;
            font-style: italic;
        }

        .question {
            margin-bottom: 20px;
            font-size: 1.1em;
        }

        .choices {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .choice-label {
            display: flex;
            align-items: center;
            padding: 10px;
            background-color: #333;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .choice-label:hover {
            background-color: #444;
        }

        .choice-label.correct {
            background-color: var(--correct-green);
        }

        .choice-label.incorrect {
            background-color: var(--incorrect-red);
        }

        .choice-input {
            margin-right: 10px;
        }

        .button-container {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }

        button {
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1em;
            transition: background-color 0.3s ease;
        }

        .judge-btn {
            background-color: var(--accent-blue);
            color: white;
        }

        .next-btn {
            background-color: var(--section-green);
            color: white;
            display: none;
        }

        .restart-btn {
            background-color: var(--section-orange);
            color: white;
            display: none;
        }

        button:hover {
            opacity: 0.9;
        }

        button:disabled {
            background-color: #666;
            cursor: not-allowed;
        }

        .feedback {
            margin-top: 20px;
            padding: 15px;
            border-radius: 5px;
            display: none;
        }

        .explanation {
            margin-top: 20px;
            display: none;
        }

        .explanation section {
            padding: 15px;
            margin-bottom: 10px;
            border-radius: 5px;
        }

        .translation {
            background-color: var(--section-blue);
        }

        .choices-meaning {
            background-color: var(--section-purple);
        }

        .vocabulary {
            background-color: var(--section-green);
        }

        .detailed {
            background-color: var(--section-red);
        }

        .point {
            background-color: var(--section-orange);
        }

        .score-display {
            text-align: right;
            margin-bottom: 20px;
            font-size: 1.2em;
        }

        @media (max-width: 600px) {
            .container {
                padding: 10px;
            }

            .question-container {
                padding: 15px;
            }

            .button-container {
                flex-direction: column;
            }

            button {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>TOEIC Practice</h1>
        </div>

        <div class="score-display">
            Score: <span id="score">0</span> / <span id="total-questions">3</span>
        </div>

        <div class="progress-container">
            <div class="progress-bar">
                <div class="progress-fill" style="width: 0%"></div>
            </div>
            <div style="text-align: right;">Question: <span id="current-question">1</span>/3</div>
        </div>

        <div class="question-container">
            <div class="situation" id="situation"></div>
            <div class="question" id="question"></div>
            <div class="choices" id="choices"></div>
        </div>

        <div class="button-container">
            <button class="judge-btn" id="judge-btn">判定</button>
            <button class="next-btn" id="next-btn">次の問題</button>
            <button class="restart-btn" id="restart-btn">最初からやり直す</button>
        </div>

        <div class="feedback" id="feedback"></div>

        <div class="explanation" id="explanation">
            <section class="translation">
                <h3>日本語訳</h3>
                <div id="translation"></div>
            </section>
            <section class="choices-meaning">
                <h3>各選択肢の意味</h3>
                <div id="choices-meaning"></div>
            </section>
            <section class="vocabulary">
                <h3>単語の意味</h3>
                <div id="vocabulary"></div>
            </section>
            <section class="detailed">
                <h3>解説</h3>
                <div id="detailed"></div>
            </section>
            <section class="point">
                <h3>解法のポイント</h3>
                <div id="point"></div>
            </section>
        </div>
    </div>

    <script>
        // サンプル問題データ
        const questions = [
            {
                questionNumber: 1,
                situation: "ビジネスミーティングの場面",
                question: "The project manager ___ all team members to submit their progress reports by the end of this week.",
                choices: [
                    "requires",
                    "requiring",
                    "required",
                    "has required"
                ],
                correctAnswer: "has required",
                explanation: {
                    translation: "プロジェクトマネージャーは全てのチームメンバーに今週末までに進捗報告書を提出するように要求している。",
                    choiceExplanations: [
                        "A) requires: 現在形",
                        "B) requiring: 現在分詞",
                        "C) required: 過去形/過去分詞",
                        "D) has required: 現在完了形"
                    ],
                    vocabulary: [
                        "progress report: 進捗報告書",
                        "submit: 提出する",
                        "by the end of: 〜までに"
                    ],
                    detailed: "この文では、「要求している」という現在までの継続的な動作を表現する必要があります。現在完了形(has/have + 過去分詞)は、過去に始まり現在まで影響が続いている動作を表現するのに適しています。",
                    point: "ビジネス文書では、指示や要求を表現する際に現在完了形がよく使用されます。特に期限を示す表現(by the end of...)と共に使われることが多いです。"
                }
            },
            {
                questionNumber: 2,
                situation: "オフィスでの電話対応の場面",
                question: "I'm sorry, but Mr. Smith is ___ in another meeting. Would you like to leave a message?",
                choices: [
                    "currently",
                    "present",
                    "lately",
                    "timely"
                ],
                correctAnswer: "currently",
                explanation: {
                    translation: "申し訳ありませんが、スミスさんは現在別の会議中です。メッセージを残されますか?",
                    choiceExplanations: [
                        "A) currently: 現在、今",
                        "B) present: 出席している、現在の",
                        "C) lately: 最近",
                        "D) timely: 時宜を得た、適時の"
                    ],
                    vocabulary: [
                        "leave a message: メッセージを残す",
                        "in a meeting: 会議中で",
                        "would you like to: 〜されませんか(丁寧な提案)"
                    ],
                    detailed: "電話対応での「今、会議中です」という状況を説明する際には、「currently(現在)」が最も適切です。「currently」は「今まさに」という意味を持ち、一時的な状況を説明する際によく使用されます。",
                    point: "ビジネス英語での電話応対では、相手の状況を説明する際に、明確で丁寧な表現を使うことが重要です。「currently」は正式な表現として広く受け入れられています。"
                }
            },
            {
                questionNumber: 3,
                situation: "企業の採用面接の場面",
                question: "The successful candidate must have ___ experience in project management and team leadership.",
                choices: [
                    "extensive",
                    "extended",
                    "extending",
                    "extent"
                ],
                correctAnswer: "extensive",
                explanation: {
                    translation: "適任者はプロジェクトマネジメントとチームリーダーシップにおいて豊富な経験を持っていなければなりません。",
                    choiceExplanations: [
                        "A) extensive: 広範な、豊富な",
                        "B) extended: 延長された、長引いた",
                        "C) extending: 延長している",
                        "D) extent: 程度、範囲(名詞)"
                    ],
                    vocabulary: [
                        "successful candidate: 適任者",
                        "project management: プロジェクト管理",
                        "team leadership: チームリーダーシップ"
                    ],
                    detailed: "求人や資格要件を述べる際、「extensive experience(豊富な経験)」は一般的な表現です。「extensive」は形容詞として「広範な、包括的な」という意味を持ち、経験の質と量の両方を示唆します。",
                    point: "求人関連の英文では、「extensive」「comprehensive」「thorough」などの形容詞が経験やスキルを修飾する際によく使用されます。これらの使い分けを覚えておくと、ビジネス文書の理解に役立ちます。"
                }
            }
        ];

        let currentQuestionIndex = 0;
        let score = 0;
        let hasAnswered = false;

        // DOM要素の取得
        const situationElement = document.getElementById('situation');
        const questionElement = document.getElementById('question');
        const choicesElement = document.getElementById('choices');
        const judgeButton = document.getElementById('judge-btn');
        const nextButton = document.getElementById('next-btn');
        const restartButton = document.getElementById('restart-btn');
        const feedbackElement = document.getElementById('feedback');
        const explanationElement = document.getElementById('explanation');
        const progressFill = document.querySelector('.progress-fill');
        const currentQuestionDisplay = document.getElementById('current-question');
        const scoreDisplay = document.getElementById('score');

        // 問題を表示する関数
        function displayQuestion() {
            const question = questions[currentQuestionIndex];
            situationElement.textContent = question.situation;
            questionElement.textContent = question.question;
            choicesElement.innerHTML = '';
            
            question.choices.forEach((choice, index) => {
                const label = document.createElement('label');
                label.className = 'choice-label';
                
                const input = document.createElement('input');
                input.type = 'radio';
                input.name = 'choice';
                input.value = choice;
                input.className = 'choice-input';
                
                const span = document.createElement('span');
                span.textContent = `${String.fromCharCode(65 + index)}) ${choice}`;
                
                label.appendChild(input);
                label.appendChild(span);
                choicesElement.appendChild(label);
            });

            // UI状態の更新
            judgeButton.style.display = 'block';
            nextButton.style.display = 'none';
            feedbackElement.style.display = 'none';
            explanationElement.style.display = 'none';
            hasAnswered = false;

            // プログレスバーの更新
            const progress = ((currentQuestionIndex + 1) / questions.length) * 100;
            progressFill.style.width = `${progress}%`;
            currentQuestionDisplay.textContent = currentQuestionIndex + 1;
            
            judgeButton.disabled = false;
        }

        // 解答を判定する関数
        function judgeAnswer() {
            if (hasAnswered) return;

            const selectedInput = document.querySelector('input[name="choice"]:checked');
            if (!selectedInput) {
                alert('選択肢を選んでください。');
                return;
            }

            const question = questions[currentQuestionIndex];
            const isCorrect = selectedInput.value === question.correctAnswer;
            hasAnswered = true;

            // 選択肢のスタイル更新
            document.querySelectorAll('.choice-label').forEach(label => {
                const input = label.querySelector('input');
                if (input.value === question.correctAnswer) {
                    label.classList.add('correct');
                } else if (input.value === selectedInput.value && !isCorrect) {
                    label.classList.add('incorrect');
                }
            });

            // フィードバック表示
            feedbackElement.style.display = 'block';
            feedbackElement.style.backgroundColor = isCorrect ? 
                'rgba(46, 204, 113, 0.2)' : 'rgba(231, 76, 60, 0.2)';
            feedbackElement.innerHTML = isCorrect ?
                '<p>正解です!</p>' :
                `<p>不正解です。正解は "${question.correctAnswer}" です。</p>`;

            // 解説の表示
            displayExplanation(question.explanation);

            // スコアの更新
            if (isCorrect) {
                score++;
                scoreDisplay.textContent = score;
            }

            // ボタンの表示制御
            judgeButton.style.display = 'none';
            if (currentQuestionIndex < questions.length - 1) {
                nextButton.style.display = 'block';
            } else {
                restartButton.style.display = 'block';
            }
        }

        // 解説を表示する関数
        function displayExplanation(explanation) {
            explanationElement.style.display = 'block';
            document.getElementById('translation').textContent = explanation.translation;
            document.getElementById('choices-meaning').innerHTML = 
                explanation.choiceExplanations.join('<br>');
            document.getElementById('vocabulary').innerHTML = 
                explanation.vocabulary.join('<br>');
            document.getElementById('detailed').textContent = explanation.detailed;
            document.getElementById('point').textContent = explanation.point;
        }

        // 次の問題へ進む関数
        function nextQuestion() {
            currentQuestionIndex++;
            displayQuestion();
            
            // 選択肢のスタイルをリセット
            document.querySelectorAll('.choice-label').forEach(label => {
                label.classList.remove('correct', 'incorrect');
            });
        }

        // クイズをリスタートする関数
        function restartQuiz() {
            currentQuestionIndex = 0;
            score = 0;
            scoreDisplay.textContent = score;
            displayQuestion();
            restartButton.style.display = 'none';
            
            // 選択肢のスタイルをリセット
            document.querySelectorAll('.choice-label').forEach(label => {
                label.classList.remove('correct', 'incorrect');
            });
        }

        // イベントリスナーの設定
        judgeButton.addEventListener('click', judgeAnswer);
        nextButton.addEventListener('click', nextQuestion);
        restartButton.addEventListener('click', restartQuiz);

        // 初期表示
        displayQuestion();
    </script>
</body>
</html>

上記コードをsample.htmlといった名称のファイルにコピペしてブラウザでファイルを開くとTOEIC問題を解くアプリが起動できます。

ステップ4(カスタマイズ)

現状だと、サンプルのTOEIC問題がhtmlコード内に直接設定されています。
最初に紹介したTOEIC問題作成プロンプトを使って生成AIに作ってもらった問題をこのアプリで解けるようにカスタマイズしてみましょう。

今回は、先ほど作成してもらったhtmlベースのアプリを以下のような設計に修正してもらいます。

・TOEIC問題のデータをhtmlとは別ファイル(question.js)に定義するようにする。
・question.jsをhtmlファイルから読み込むようにする。

では、修正の指示出しをしましょう。

#htmlはTOEIC問題アプリです。
このアプリに対して以下の要件を満たすように#htmlコードを修正してください。
修正後の全htmlコードと、question.jsにはサンプルで3つ問題データを生成して下さい。

#要件
・TOEIC問題のデータをhtmlとは別ファイル(question.js)に定義するようにする。
・question.jsをhtmlファイルから読み込むようにする

#html
===
{ここにhtmlコードをすべて張り付けておく}
===

生成AIの回答例

修正後のコード例

question.js

// サンプル問題データ
const questions = [
    {
        questionNumber: 1,
        situation: "ビジネスミーティングの場面",
        question: "The project manager ___ all team members to submit their progress reports by the end of this week.",
        choices: [
            "requires",
            "requiring",
            "required",
            "has required"
        ],
        correctAnswer: "has required",
        explanation: {
            translation: "プロジェクトマネージャーは全てのチームメンバーに今週末までに進捗報告書を提出するように要求している。",
            choiceExplanations: [
                "A) requires: 現在形",
                "B) requiring: 現在分詞",
                "C) required: 過去形/過去分詞",
                "D) has required: 現在完了形"
            ],
            vocabulary: [
                "progress report: 進捗報告書",
                "submit: 提出する",
                "by the end of: 〜までに"
            ],
            detailed: "この文では、「要求している」という現在までの継続的な動作を表現する必要があります。現在完了形(has/have + 過去分詞)は、過去に始まり現在まで影響が続いている動作を表現するのに適しています。",
            point: "ビジネス文書では、指示や要求を表現する際に現在完了形がよく使用されます。特に期限を示す表現(by the end of...)と共に使われることが多いです。"
        }
    },
    {
        questionNumber: 2,
        situation: "オフィスでの電話対応の場面",
        question: "I'm sorry, but Mr. Smith is ___ in another meeting. Would you like to leave a message?",
        choices: [
            "currently",
            "present",
            "lately",
            "timely"
        ],
        correctAnswer: "currently",
        explanation: {
            translation: "申し訳ありませんが、スミスさんは現在別の会議中です。メッセージを残されますか?",
            choiceExplanations: [
                "A) currently: 現在、今",
                "B) present: 出席している、現在の",
                "C) lately: 最近",
                "D) timely: 時宜を得た、適時の"
            ],
            vocabulary: [
                "leave a message: メッセージを残す",
                "in a meeting: 会議中で",
                "would you like to: 〜されませんか(丁寧な提案)"
            ],
            detailed: "電話対応での「今、会議中です」という状況を説明する際には、「currently(現在)」が最も適切です。「currently」は「今まさに」という意味を持ち、一時的な状況を説明する際によく使用されます。",
            point: "ビジネス英語での電話応対では、相手の状況を説明する際に、明確で丁寧な表現を使うことが重要です。「currently」は正式な表現として広く受け入れられています。"
        }
    },
    {
        questionNumber: 3,
        situation: "企業の採用面接の場面",
        question: "The successful candidate must have ___ experience in project management and team leadership.",
        choices: [
            "extensive",
            "extended",
            "extending",
            "extent"
        ],
        correctAnswer: "extensive",
        explanation: {
            translation: "適任者はプロジェクトマネジメントとチームリーダーシップにおいて豊富な経験を持っていなければなりません。",
            choiceExplanations: [
                "A) extensive: 広範な、豊富な",
                "B) extended: 延長された、長引いた",
                "C) extending: 延長している",
                "D) extent: 程度、範囲(名詞)"
            ],
            vocabulary: [
                "successful candidate: 適任者",
                "project management: プロジェクト管理",
                "team leadership: チームリーダーシップ"
            ],
            detailed: "求人や資格要件を述べる際、「extensive experience(豊富な経験)」は一般的な表現です。「extensive」は形容詞として「広範な、包括的な」という意味を持ち、経験の質と量の両方を示唆します。",
            point: "求人関連の英文では、「extensive」「comprehensive」「thorough」などの形容詞が経験やスキルを修飾する際によく使用されます。これらの使い分けを覚えておくと、ビジネス文書の理解に役立ちます。"
        }
    }
];

html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TOEIC Practice App</title>
    <style>
        :root {
            --background-dark: #1a1a1a;
            --text-light: #ffffff;
            --accent-blue: #3498db;
            --correct-green: #2ecc71;
            --incorrect-red: #e74c3c;
            --section-blue: #2c3e50;
            --section-purple: #8e44ad;
            --section-green: #27ae60;
            --section-red: #c0392b;
            --section-orange: #d35400;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: var(--background-dark);
            color: var(--text-light);
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
        }

        .progress-container {
            margin: 20px 0;
        }

        .progress-bar {
            width: 100%;
            height: 10px;
            background-color: #333;
            border-radius: 5px;
            overflow: hidden;
        }

        .progress-fill {
            height: 100%;
            background-color: var(--accent-blue);
            transition: width 0.3s ease;
        }

        .question-container {
            background-color: #2a2a2a;
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
        }

        .situation {
            color: var(--accent-blue);
            margin-bottom: 15px;
            font-style: italic;
        }

        .question {
            margin-bottom: 20px;
            font-size: 1.1em;
        }

        .choices {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .choice-label {
            display: flex;
            align-items: center;
            padding: 10px;
            background-color: #333;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .choice-label:hover {
            background-color: #444;
        }

        .choice-label.correct {
            background-color: var(--correct-green);
        }

        .choice-label.incorrect {
            background-color: var(--incorrect-red);
        }

        .choice-input {
            margin-right: 10px;
        }

        .button-container {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }

        button {
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1em;
            transition: background-color 0.3s ease;
        }

        .judge-btn {
            background-color: var(--accent-blue);
            color: white;
        }

        .next-btn {
            background-color: var(--section-green);
            color: white;
            display: none;
        }

        .restart-btn {
            background-color: var(--section-orange);
            color: white;
            display: none;
        }

        button:hover {
            opacity: 0.9;
        }

        button:disabled {
            background-color: #666;
            cursor: not-allowed;
        }

        .feedback {
            margin-top: 20px;
            padding: 15px;
            border-radius: 5px;
            display: none;
        }

        .explanation {
            margin-top: 20px;
            display: none;
        }

        .explanation section {
            padding: 15px;
            margin-bottom: 10px;
            border-radius: 5px;
        }

        .translation {
            background-color: var(--section-blue);
        }

        .choices-meaning {
            background-color: var(--section-purple);
        }

        .vocabulary {
            background-color: var(--section-green);
        }

        .detailed {
            background-color: var(--section-red);
        }

        .point {
            background-color: var(--section-orange);
        }

        .score-display {
            text-align: right;
            margin-bottom: 20px;
            font-size: 1.2em;
        }

        @media (max-width: 600px) {
            .container {
                padding: 10px;
            }

            .question-container {
                padding: 15px;
            }

            .button-container {
                flex-direction: column;
            }

            button {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>TOEIC Practice</h1>
        </div>

        <div class="score-display">
            Score: <span id="score">0</span> / <span id="total-questions">3</span>
        </div>

        <div class="progress-container">
            <div class="progress-bar">
                <div class="progress-fill" style="width: 0%"></div>
            </div>
            <div style="text-align: right;">Question: <span id="current-question">1</span>/3</div>
        </div>

        <div class="question-container">
            <div class="situation" id="situation"></div>
            <div class="question" id="question"></div>
            <div class="choices" id="choices"></div>
        </div>

        <div class="button-container">
            <button class="judge-btn" id="judge-btn">判定</button>
            <button class="next-btn" id="next-btn">次の問題</button>
            <button class="restart-btn" id="restart-btn">最初からやり直す</button>
        </div>

        <div class="feedback" id="feedback"></div>

        <div class="explanation" id="explanation">
            <section class="translation">
                <h3>日本語訳</h3>
                <div id="translation"></div>
            </section>
            <section class="choices-meaning">
                <h3>各選択肢の意味</h3>
                <div id="choices-meaning"></div>
            </section>
            <section class="vocabulary">
                <h3>単語の意味</h3>
                <div id="vocabulary"></div>
            </section>
            <section class="detailed">
                <h3>解説</h3>
                <div id="detailed"></div>
            </section>
            <section class="point">
                <h3>解法のポイント</h3>
                <div id="point"></div>
            </section>
        </div>
    </div>

    <!-- 問題データを読み込む -->
    <script src="./questions.js"></script>
    <!-- アプリケーションのロジック -->
    <script>
        let currentQuestionIndex = 0;
        let score = 0;
        let hasAnswered = false;

        // DOM要素の取得
        const situationElement = document.getElementById('situation');
        const questionElement = document.getElementById('question');
        const choicesElement = document.getElementById('choices');
        const judgeButton = document.getElementById('judge-btn');
        const nextButton = document.getElementById('next-btn');
        const restartButton = document.getElementById('restart-btn');
        const feedbackElement = document.getElementById('feedback');
        const explanationElement = document.getElementById('explanation');
        const progressFill = document.querySelector('.progress-fill');
        const currentQuestionDisplay = document.getElementById('current-question');
        const scoreDisplay = document.getElementById('score');

        // 問題を表示する関数
        function displayQuestion() {
            const question = questions[currentQuestionIndex];
            situationElement.textContent = question.situation;
            questionElement.textContent = question.question;
            choicesElement.innerHTML = '';
            
            question.choices.forEach((choice, index) => {
                const label = document.createElement('label');
                label.className = 'choice-label';
                
                const input = document.createElement('input');
                input.type = 'radio';
                input.name = 'choice';
                input.value = choice;
                input.className = 'choice-input';
                
                const span = document.createElement('span');
                span.textContent = `${String.fromCharCode(65 + index)}) ${choice}`;
                
                label.appendChild(input);
                label.appendChild(span);
                choicesElement.appendChild(label);
            });

            // UI状態の更新
            judgeButton.style.display = 'block';
            nextButton.style.display = 'none';
            feedbackElement.style.display = 'none';
            explanationElement.style.display = 'none';
            hasAnswered = false;

            // プログレスバーの更新
            const progress = ((currentQuestionIndex + 1) / questions.length) * 100;
            progressFill.style.width = `${progress}%`;
            currentQuestionDisplay.textContent = currentQuestionIndex + 1;
            
            judgeButton.disabled = false;
        }

        // 解答を判定する関数
        function judgeAnswer() {
            if (hasAnswered) return;

            const selectedInput = document.querySelector('input[name="choice"]:checked');
            if (!selectedInput) {
                alert('選択肢を選んでください。');
                return;
            }

            const question = questions[currentQuestionIndex];
            const isCorrect = selectedInput.value === question.correctAnswer;
            hasAnswered = true;

            // 選択肢のスタイル更新
            document.querySelectorAll('.choice-label').forEach(label => {
                const input = label.querySelector('input');
                if (input.value === question.correctAnswer) {
                    label.classList.add('correct');
                } else if (input.value === selectedInput.value && !isCorrect) {
                    label.classList.add('incorrect');
                }
            });

            // フィードバック表示
            feedbackElement.style.display = 'block';
            feedbackElement.style.backgroundColor = isCorrect ? 
                'rgba(46, 204, 113, 0.2)' : 'rgba(231, 76, 60, 0.2)';
            feedbackElement.innerHTML = isCorrect ?
                '<p>正解です!</p>' :
                `<p>不正解です。正解は "${question.correctAnswer}" です。</p>`;

            // 解説の表示
            displayExplanation(question.explanation);

            // スコアの更新
            if (isCorrect) {
                score++;
                scoreDisplay.textContent = score;
            }

            // ボタンの表示制御
            judgeButton.style.display = 'none';
            if (currentQuestionIndex < questions.length - 1) {
                nextButton.style.display = 'block';
            } else {
                restartButton.style.display = 'block';
            }
        }

        // 解説を表示する関数
        function displayExplanation(explanation) {
            explanationElement.style.display = 'block';
            document.getElementById('translation').textContent = explanation.translation;
            document.getElementById('choices-meaning').innerHTML = 
                explanation.choiceExplanations.join('<br>');
            document.getElementById('vocabulary').innerHTML = 
                explanation.vocabulary.join('<br>');
            document.getElementById('detailed').textContent = explanation.detailed;
            document.getElementById('point').textContent = explanation.point;
        }

        // 次の問題へ進む関数
        function nextQuestion() {
            currentQuestionIndex++;
            displayQuestion();
            
            // 選択肢のスタイルをリセット
            document.querySelectorAll('.choice-label').forEach(label => {
                label.classList.remove('correct', 'incorrect');
            });
        }

        // クイズをリスタートする関数
        function restartQuiz() {
            currentQuestionIndex = 0;
            score = 0;
            scoreDisplay.textContent = score;
            displayQuestion();
            restartButton.style.display = 'none';
            
            // 選択肢のスタイルをリセット
            document.querySelectorAll('.choice-label').forEach(label => {
                label.classList.remove('correct', 'incorrect');
            });
        }

        // イベントリスナーの設定
        judgeButton.addEventListener('click', judgeAnswer);
        nextButton.addEventListener('click', nextQuestion);
        restartButton.addEventListener('click', restartQuiz);

        // 初期表示
        displayQuestion();
    </script>
</body>
</html>

上記2ファイル(html,js)を同じフォルダ内に配置してhtmlを開けばquestion.js(問題データ)をロードしてくれるようになります。

ステップ5(問題生成プロンプトの修正)

アプリが出来上がったので、最初に紹介したTOEIC問題の作成プロンプトに「出力フォーマット」を追加して、このアプリで使う問題データ(question.js)のフォーマットで出力してもらうように修正しましょう。

修正後のプロンプト

#パラメータ設定
カテゴリ名 = {param1}  
問題数 = {param2}  
目標スコア = {param3}   
シチュエーション = {param4}   

以下の形式に従って、TOEICの{カテゴリ名}に関する問題を{問題数}個生成してください。
ただし、問題のレベルは{目標スコア}点相当であり、かつ「{シチュエーション}」にマッチするような英文を活用した問題にしてください。
各問題は、文中の空欄に入る適切な選択肢を選択する形式にしてください。
問題文と選択肢の間に空行を入れてください。

explanationには、以下のフォーマットに従い、フレンドリーで寄り添った優しい口調で、初学者でもわかりやすい丁寧な説明を心がけ、具体例を交えて解説してください。
また、該当問題を解く上で押さえるべき秘訣(テクニック)を1つ簡潔に提示してください。

重要: 以下の既存の問題と同じ、または酷似した問題は生成しないでください。
===
{既に作成済みの問題画あればここに張り付けておく}
===
#explanationのフォーマット:
## 日本語訳
ここに問題英文の日本語訳を記載する。

## 各選択肢の意味
ここに選択肢の意味を記載する。

## 単語の意味
ここに選択肢以外でTOEIC試験で重要な用語の意味を捕捉説明する。

## 解説
ここに解説を記載する。

## 解法のポイント
この問題を解くための秘訣、ポイントを出来るだけ具体的に記載する。

出力形式:
1. 問題文(空欄には '___' を使用)
A) 選択肢A
B) 選択肢B
C) 選択肢C
D) 選択肢D

正解: [正解の選択肢]

explanation:
[上記のフォーマットに従った説明]

#出力フォーマット
const questions = [
    {
        questionNumber: "問題番号(整数)",
        situation: "問題の状況設定(例:ビジネスミーティング、電話対応、面接など)",
        question: "問題文(空欄には ___ を使用。文法問題の場合は適切な動詞や形容詞などが入る空欄を含める)",
        choices: [
            "選択肢A(文法問題の場合は異なる形式や時制を提示)",
            "選択肢B(問題の文脈に関連する別の表現)",
            "選択肢C(紛らわしい類似表現)",
            "選択肢D(文脈に合う可能性のある別の表現)"
        ],
        correctAnswer: "正解となる選択肢(上記の選択肢の中から1つ)",
        explanation: {
            translation: "問題文の日本語訳(ビジネスシーンに即した自然な訳文)",
            choiceExplanations: [
                "選択肢Aの説明(品詞や用法を含む)",
                "選択肢Bの説明(品詞や用法を含む)",
                "選択肢Cの説明(品詞や用法を含む)",
                "選択肢Dの説明(品詞や用法を含む)"
            ],
            vocabulary: [
                "重要な語句1: 日本語訳と用例",
                "重要な語句2: 日本語訳と用例",
                "重要な語句3: 日本語訳と用例"
            ],
            detailed: "解説文(なぜその答えが正解なのか、文法的または状況的な説明を含める)",
            point: "学習ポイント(この問題から学ぶべき重要な文法規則やビジネス英語の使用法)"
        }
    }
];


2. [次の問題...]

以下の出力フォーマットを追加しただけです。

#出力フォーマット
const questions = [
    {
        questionNumber: "問題番号(整数)",
        situation: "問題の状況設定(例:ビジネスミーティング、電話対応、面接など)",
        question: "問題文(空欄には ___ を使用。文法問題の場合は適切な動詞や形容詞などが入る空欄を含める)",
        choices: [
            "選択肢A(文法問題の場合は異なる形式や時制を提示)",
            "選択肢B(問題の文脈に関連する別の表現)",
            "選択肢C(紛らわしい類似表現)",
            "選択肢D(文脈に合う可能性のある別の表現)"
        ],
        correctAnswer: "正解となる選択肢(上記の選択肢の中から1つ)",
        explanation: {
            translation: "問題文の日本語訳(ビジネスシーンに即した自然な訳文)",
            choiceExplanations: [
                "選択肢Aの説明(品詞や用法を含む)",
                "選択肢Bの説明(品詞や用法を含む)",
                "選択肢Cの説明(品詞や用法を含む)",
                "選択肢Dの説明(品詞や用法を含む)"
            ],
            vocabulary: [
                "重要な語句1: 日本語訳と用例",
                "重要な語句2: 日本語訳と用例",
                "重要な語句3: 日本語訳と用例"
            ],
            detailed: "解説文(なぜその答えが正解なのか、文法的または状況的な説明を含める)",
            point: "学習ポイント(この問題から学ぶべき重要な文法規則やビジネス英語の使用法)"
        }
    }
];


2. [次の問題...]

これで、上記のプロンプトで問題データを生成してもらいその内容をquestion.jsに張り付ければ生成AIに作成してもらった問題をhtmlアプリ上で解くことが可能になります。

試しに以下のような設定で問題を作成してもらいました。

#パラメータ設定
カテゴリ名 = 品詞問題(動詞)
問題数 = 2
目標スコア = 700   
シチュエーション = かわいい子猫と戯れる子供たち

生成された問題データ

const questions = [
    {
        questionNumber: 1,
        situation: "子猫と遊ぶ子供たち",
        question: "The children ___ with the playful kittens in the garden, making everyone smile at the heartwarming scene.",
        choices: [
            "are delighting",
            "delight",
            "delighted",
            "have delighted"
        ],
        correctAnswer: "are delighting",
        explanation: {
            translation: "子供たちは庭で遊び盛りの子猫たちと遊んでいて、その心温まる光景に皆が笑顔になっています。",
            choiceExplanations: [
                "are delighting: 現在進行形 - 今まさに進行中の動作を表す",
                "delight: 現在形 - 習慣的な動作や一般的な事実を表す",
                "delighted: 過去分詞 - 受動態や形容詞として使用",
                "have delighted: 現在完了形 - 過去から現在までの経験や結果を表す"
            ],
            vocabulary: [
                "playful: 遊び好きな、はしゃぎやすい (例: The playful puppy jumped around)",
                "heartwarming: 心温まる (例: It was a heartwarming story)",
                "scene: 光景、場面 (例: It was a beautiful scene)"
            ],
            detailed: "この問題では、「今まさに目の前で起きている動作」を表現する必要があります。子供たちが子猫と遊んでいる様子は、質問文の時点でまさに進行中の動作なので、現在進行形 'are delighting' が最適です。'making everyone smile' という分詞構文が後に続いていることからも、その場で起きている出来事であることがわかります。",
            point: "現在進行形と単純現在形の使い分けがポイントです!目の前で実際に起きていることを描写する時は、現在進行形を使いましょう。"
        }
    },
    {
        questionNumber: 2,
        situation: "子猫と遊ぶ子供たち",
        question: "Little Sarah ___ to catch the tiny kitten's tail, but the clever pet always manages to keep it just out of reach.",
        choices: [
            "tries",
            "trying",
            "tried",
            "has tried"
        ],
        correctAnswer: "tries",
        explanation: {
            translation: "小さなサラは子猫のしっぽを捕まえようとしますが、賢い子猫はいつもうまくしっぽを手の届かないところに保っています。",
            choiceExplanations: [
                "tries: 現在形 - 繰り返し行われる動作や習慣を表す",
                "trying: 現在分詞 - 進行形の一部または分詞として使用",
                "tried: 過去形 - 過去の一回限りの動作を表す",
                "has tried: 現在完了形 - 過去から現在までの経験を表す"
            ],
            vocabulary: [
                "manage to: 何とか~する (例: He managed to finish the work)",
                "keep out of reach: 手の届かないところに保つ",
                "clever: 賢い、利口な (例: She is a clever student)"
            ],
            detailed: "この文では、繰り返し起こる習慣的な動作を表現しています。'always manages' という表現が使われていることから、これが繰り返し起こる状況であることがわかります。そのため、習慣を表す現在形 'tries' が最も適切です。",
            point: "文中に 'always'(いつも)のような頻度を表す副詞があれば、それは習慣的な動作を表していることが多く、現在形が使われやすいことを覚えておきましょう!"
        }
    }
];

アプリ画面例

5. 「私だけの教材」がもたらす学びの革新

「私だけの教材」を使った学習は、TOEICに限らず、あらゆる学習分野で革新を起こす可能性を秘めています:

  • プログラミング学習: 自分の業界や興味に基づいた実践的なコーディング課題を作成
  • 語学学習: 自分の職業や目標に特化した、リアルな会話シミュレーションを体験
  • 資格試験対策: 自分の弱点を分析し、苦手分野を集中的に強化する問題セットを作成
  • 社内研修: 自分のスキルセットと職責に完全にマッチした、カスタム研修プログラムを開発

6. まとめ:あなたの学びを速く、楽しくする時

生成AIを活用した「私だけの教材」は、単なる学習の効率化を超えて、私たち一人一人の潜在能力を最大限に引き出す可能性を秘めています。学びが速くなるだけでなく、何より楽しくなることで、持続的な成長と自己実現をサポートします。

今回ご紹介したプロンプトと手法を使って、ぜひ皆さん自身の「私だけの教材」を作ってみてください。そして、その経験を職場や日常生活のさまざまな場面で応用してみてください。

Accenture Japan (有志)

Discussion