TOEIC Official Practice

 
Initial Setup (Box connection, API key)
① Box連携

確認中...

② Gemini APIキー(解説生成用・任意)

未入力でも問題演習はできますが、AIによる解説は表示されません。Google AI Studioで無料取得できます。decode-toeicと同じキーを使っている場合は自動で反映されます。有料キーを設定すると、無料枠の上限に達した瞬間だけ自動でそちらに切り替わります(普段は無料キーのみ使用)。AIモデルは基本的に「gemini-3.5-flash-lite(高速・低コスト)」のままで問題ありません。画像・音声生成用など、この画面での解説生成に使えないモデルは選択肢から除いています。

③ 端末間同期用スプレッドシート(任意)

ノートだけでなく、回答履歴・学習時間・連続学習日数・コーチメッセージ履歴・ボトルネックポイント(翻訳画面で強調表示した単語)も、このスプレッドシートを通じて端末間で同期されます(自宅PC・会社PC・スマホ等、どの端末からアクセスしても同じ進捗が見られるようにするためのものです)。

  1. Googleスプレッドシートを新規作成する(1枚のシートでOK。「Notes」「Progress」タブは自動作成されます)。
  2. メニュー「拡張機能」→「Apps Script」を開く。
  3. デフォルトのコードを全て削除し、下のコードを貼り付けて保存。
  4. 右上「デプロイ」→「新しいデプロイ」→種類「ウェブアプリ」。実行ユーザー「自分」、アクセスできるユーザー「全員」に設定してデプロイ。
  5. 発行されたURL(.../execで終わるもの)をコピーし、上の「APPS SCRIPT WEB APP URL」欄に貼り付ける。これを使う全ての端末で同じURLを登録してください。
  6. これでヘッダーの「💾 保存」ボタンを押すと、今開いているノート・回答履歴・学習時間などがこのスプレッドシートに保存され、次回別の端末で開いたときに自動で読み込まれ、その端末のデータとマージ(合算)されます(URL未設定の場合はこの端末のブラウザ内にのみ保存されます)。
  7. 既にURLを設定済みで、コードだけ更新したい場合: Apps Scriptのコードを下の最新版に貼り替えて保存した後、右上「デプロイ」→「デプロイを管理」→鉛筆アイコン→「バージョン」で「新しいバージョン」を選び「デプロイ」。これでURLは変わらないまま新しいコードが反映されます。
function _getSheet(name, headerRow) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName(name); if (!sheet) { sheet = ss.insertSheet(name); sheet.appendRow(headerRow); } return sheet; } function _getNotesSheet() { return _getSheet('Notes', ['key', 'html', 'updatedAt']); } // Progressタブ: 回答履歴・学習時間・連続日数・コーチメッセージ履歴・ボトルネック // ポイント(強調表示した単語)など、ノート以外の進捗データをまとめて保存する // (key列は 'attempts'|'dailyQuestions'|'studyLog'|'coachHistory'|'bottleneckMarks' // の固定5種、json列にその中身をJSON文字列で1つだけ格納する。このApps Script自体は // key名を特に限定しない汎用の実装なので、今後さらに種類が増えてもコード変更は不要)。 function _getProgressSheet() { return _getSheet('Progress', ['key', 'json', 'updatedAt']); } function _getAllRows(sheet) { var last = sheet.getLastRow(); var result = {}; if (last >= 2) { var data = sheet.getRange(2, 1, last - 1, 2).getValues(); for (var i = 0; i < data.length; i++) { if (data[i][0]) result[data[i][0]] = data[i][1]; } } return result; } function _setRowValue(sheet, key, value) { var last = sheet.getLastRow(); if (last >= 2) { var data = sheet.getRange(2, 1, last - 1, 1).getValues(); for (var i = 0; i < data.length; i++) { if (data[i][0] === key) { sheet.getRange(i + 2, 2, 1, 2).setValues([[value, new Date()]]); return; } } } sheet.appendRow([key, value, new Date()]); } function doGet(e) { var action = e.parameter.action; var callback = e.parameter.callback; var result; if (action === 'getNotes') { result = { notes: _getAllRows(_getNotesSheet()) }; } else if (action === 'getProgress') { var rows = _getAllRows(_getProgressSheet()); var progress = {}; for (var key in rows) { try { progress[key] = JSON.parse(rows[key]); } catch (err) { /* 壊れた値は無視 */ } } result = { progress: progress }; } else { result = { error: 'unknown action' }; } var json = JSON.stringify(result); // callbackパラメータが付いている場合はJSONPとして返す(ブラウザからfetch()で // 直接GETすると、Apps ScriptのレスポンスにCORSヘッダーが付かずブロックされる // ことがあるため、scriptタグ経由で読み込むJSONP方式で回避する)。 if (callback) { return ContentService.createTextOutput(callback + '(' + json + ');') .setMimeType(ContentService.MimeType.JAVASCRIPT); } return ContentService.createTextOutput(json).setMimeType(ContentService.MimeType.JSON); } function doPost(e) { var body = JSON.parse(e.postData.contents); if (body.action === 'saveNotes') { var notesSheet = _getNotesSheet(); var notes = body.notes || {}; for (var key in notes) { _setRowValue(notesSheet, key, notes[key]); } return ContentService.createTextOutput(JSON.stringify({ status: 'ok', count: Object.keys(notes).length })) .setMimeType(ContentService.MimeType.JSON); } if (body.action === 'saveProgress') { var progressSheet = _getProgressSheet(); var progress = body.progress || {}; for (var pkey in progress) { _setRowValue(progressSheet, pkey, JSON.stringify(progress[pkey])); } return ContentService.createTextOutput(JSON.stringify({ status: 'ok' })) .setMimeType(ContentService.MimeType.JSON); } return ContentService.createTextOutput(JSON.stringify({ error: 'unknown action' })) .setMimeType(ContentService.MimeType.JSON); }
 

下のリストからテスト・Part・問題を選んで学習を始めてください。音声の再生には、上の「設定」からBox連携でログインしてください。

build …