Spaces:
Sleeping
Sleeping
TOMOCHIN4 Claude Opus 4.5 commited on
Commit ·
d6a42d4
1
Parent(s): 27a3ba5
fix: getSessionResults カラムインデックス修正 (v1.6.10)
Browse files- row[3]→row[5]: user_answer (F列)
- row[4]→row[7]: is_correct (H列)
- row[5]→row[8]: time_spent (I列)
v1.6.6でAnswersシートに追加した3カラム(subject,category,correct_answer)により
インデックスがずれていた問題を修正
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- .serena/memories/conventions.md +107 -0
- .serena/memories/project_overview.md +87 -0
- .serena/memories/suggested_commands.md +101 -0
- PLAN.md +31 -58
- PLAN_v1.1.md +0 -282
- PLAN_v1.2.md +0 -185
- STATUS.md +24 -23
- __pycache__/app.cpython-310.pyc +0 -0
- docs/GEMINI_STRUCTURED_OUTPUT.txt +540 -0
- docs/GenreMaster.js +431 -0
- docs/dify-prompts.md +299 -0
- gas/.clasp.json +4 -0
- gas/Code.js +3 -3
- gas/DifyService.js +458 -0
- gas/GenreMaster.js +431 -0
- gas/appsscript.json +15 -0
- gas/questiondb_functions.js +789 -0
- gas/setup_dify_properties.js +468 -0
- gas/setup_sheets_v2.js +524 -0
- knowledge/ORIGINAL/中学入試 でる順 ポケでる国語 漢字・熟語 四訂版.md +0 -0
- knowledge/ORIGINAL/合格物語.md +0 -0
- knowledge/ORIGINAL/合格論説文.md +0 -0
- knowledge/ORIGINAL/理科/改訂版 中学入試にでる順 理科 力・運動・電気・光、物質・エネルギー.md +0 -0
- knowledge/ORIGINAL/理科/改訂版 中学入試にでる順 理科 植物・動物・人体、地球・宇宙.md +0 -0
- knowledge/ORIGINAL/社会/中学入試にでる順 地理(改訂版).md +0 -0
- knowledge/ORIGINAL/社会/中学入試にでる順 社会 歴史(改訂版).md +0 -0
- knowledge/ORIGINAL/社会/中学受験 社会 裏ワザテクニック Wチェック問題集 歴史編.md +0 -0
- knowledge/ORIGINAL/社会/中学受験 社会の裏ワザテクニックWチェック問題集 地理編.md +0 -0
- knowledge/ORIGINAL/算数/つまずきやすいところが絶対つまずかない! 小学校6年間の図形の教え方.md +832 -0
- knowledge/ORIGINAL/算数/中学入試 割合と比:食塩水、割合、相当算.md +0 -0
- knowledge/ORIGINAL/算数/中学入試攻略 下克上算数ドリル【速さ編】.md +808 -0
- knowledge/ORIGINAL/算数/四天王寺対策算数.md +0 -0
- knowledge/ORIGINAL/算数/算数出る順文章題.md +0 -0
- log/HF_PROBLEM_LOG.txt +150 -0
- log/LOG.md +52 -270
- src/prompts/__pycache__/question_prompts.cpython-310.pyc +0 -0
- src/prompts/__pycache__/validation_prompts.cpython-310.pyc +0 -0
- src/services/__pycache__/gemini_service.cpython-310.pyc +0 -0
- 超天才クイズv3_GoogleSheets/Answers.html +2 -0
- 超天才クイズv3_GoogleSheets/Evaluations.html +2 -0
- 超天才クイズv3_GoogleSheets/GeneratedQuestions.html +2 -0
- 超天才クイズv3_GoogleSheets/QuestionDatabase.html +0 -0
- 超天才クイズv3_GoogleSheets/Sessions.html +2 -0
- 超天才クイズv3_GoogleSheets/Statistics.html +2 -0
- 超天才クイズv3_GoogleSheets/Summaries.html +2 -0
- 超天才クイズv3_GoogleSheets/Users.html +2 -0
- 超天才クイズv3_GoogleSheets/resources/sheet.css +0 -0
.serena/memories/conventions.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 超天才クイズ V3 - コーディング規約
|
| 2 |
+
|
| 3 |
+
## Python コードスタイル
|
| 4 |
+
|
| 5 |
+
### 命名規則
|
| 6 |
+
- **変数・関数**: `snake_case`
|
| 7 |
+
- **クラス名**: `PascalCase`
|
| 8 |
+
- **定数**: `UPPER_SNAKE_CASE`
|
| 9 |
+
- **プライベートメソッド**: `_leading_underscore`
|
| 10 |
+
|
| 11 |
+
### 型ヒント
|
| 12 |
+
- 関数の引数と戻り値には型ヒントを付ける
|
| 13 |
+
- `typing` モジュールから `List`, `Dict`, `Optional` 等を使用
|
| 14 |
+
|
| 15 |
+
```python
|
| 16 |
+
def generate_questions(
|
| 17 |
+
self,
|
| 18 |
+
subject: str,
|
| 19 |
+
knowledge_base: str,
|
| 20 |
+
count: int = 5
|
| 21 |
+
) -> List[Dict[str, Any]]:
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
### Docstring
|
| 25 |
+
- Google スタイルの docstring を使用
|
| 26 |
+
- モジュール、クラス、メソッドに記述
|
| 27 |
+
|
| 28 |
+
```python
|
| 29 |
+
"""
|
| 30 |
+
モジュール/クラス/関数の説明
|
| 31 |
+
|
| 32 |
+
Args:
|
| 33 |
+
param1: パラメータの説明
|
| 34 |
+
|
| 35 |
+
Returns:
|
| 36 |
+
戻り値の説明
|
| 37 |
+
"""
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
### インポート順序
|
| 41 |
+
1. 標準ライブラリ
|
| 42 |
+
2. サードパーティライブラリ
|
| 43 |
+
3. ローカルモジュール
|
| 44 |
+
|
| 45 |
+
```python
|
| 46 |
+
import os
|
| 47 |
+
import json
|
| 48 |
+
import logging
|
| 49 |
+
|
| 50 |
+
from fastapi import FastAPI
|
| 51 |
+
from pydantic import BaseModel
|
| 52 |
+
|
| 53 |
+
from src.services.gemini_service import GeminiService
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
### ロギング
|
| 57 |
+
- `logging` モジュールを使用
|
| 58 |
+
- モジュールごとに logger を作成
|
| 59 |
+
|
| 60 |
+
```python
|
| 61 |
+
logger = logging.getLogger(__name__)
|
| 62 |
+
logger.info("メッセージ")
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
## JavaScript (GAS) コードスタイル
|
| 66 |
+
|
| 67 |
+
### 命名規則
|
| 68 |
+
- **変数・関数**: `camelCase`
|
| 69 |
+
- **定数**: `UPPER_SNAKE_CASE`
|
| 70 |
+
|
| 71 |
+
### 関数
|
| 72 |
+
- GASの制約により、トップレベル関数として定義
|
| 73 |
+
|
| 74 |
+
## プロジェクト管理
|
| 75 |
+
|
| 76 |
+
### CLAUDE.md に従う
|
| 77 |
+
- PLAN → BUILD → REVIEW → APPLY のサイクル
|
| 78 |
+
- STATUS.md を最優先で確認
|
| 79 |
+
- LOG.md にタイムライン形式で記録
|
| 80 |
+
|
| 81 |
+
### タスク完了時
|
| 82 |
+
1. コード変更をコミット
|
| 83 |
+
2. LOG.md を更新
|
| 84 |
+
3. STATUS.md を必要に応じて更新
|
| 85 |
+
|
| 86 |
+
### コミットメッセージ
|
| 87 |
+
```
|
| 88 |
+
type: 説明(日本語OK)
|
| 89 |
+
|
| 90 |
+
- 詳細1
|
| 91 |
+
- 詳細2
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
type: `feat`, `fix`, `refactor`, `docs`, `test`
|
| 95 |
+
|
| 96 |
+
## 動作検証ルール(必須)
|
| 97 |
+
|
| 98 |
+
### 3点セット確認
|
| 99 |
+
動作検証時は以下の3点を**必ず**確認すること:
|
| 100 |
+
|
| 101 |
+
1. **HF Spaces ログ** - APIレスポンス、エラーログ
|
| 102 |
+
2. **GAS ログ** - 実行ログ、エラー
|
| 103 |
+
3. **Google Spreadsheet** - データが正しく記入されているか
|
| 104 |
+
- URL: https://docs.google.com/spreadsheets/d/10JLP5ds2CNDOEYTxEzDyY82dErbD-InkTeuyzS_w_3U/
|
| 105 |
+
- 確認対象シート: Users, Sessions, QuestionDB, Results 等
|
| 106 |
+
|
| 107 |
+
**重要**: API成功レスポンスだけでは不十分。Spreadsheetへの実データ反映を必ず確認すること。
|
.serena/memories/project_overview.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 超天才クイズ V3 - プロジェクト概要
|
| 2 |
+
|
| 3 |
+
## 目的
|
| 4 |
+
中学受験を目指す生徒向けの4択クイズアプリ。Google Gemini APIを使用して高品質な問題を自動生成する。
|
| 5 |
+
|
| 6 |
+
## 技術スタック
|
| 7 |
+
|
| 8 |
+
### Backend
|
| 9 |
+
- **Python 3.11**
|
| 10 |
+
- **FastAPI** - Web Framework
|
| 11 |
+
- **uvicorn** - ASGI Server
|
| 12 |
+
|
| 13 |
+
### AI/LLM
|
| 14 |
+
- **Google Gemini API** (gemini-2.5-flash)
|
| 15 |
+
- **google-genai SDK** - thinking_budget対応の新SDK
|
| 16 |
+
|
| 17 |
+
### Frontend
|
| 18 |
+
- **Vanilla JS** + **Tailwind CSS**
|
| 19 |
+
- `static/` ディレクトリに配置
|
| 20 |
+
|
| 21 |
+
### Database
|
| 22 |
+
- **Google Sheets** - データ永続化
|
| 23 |
+
- **GAS (Google Apps Script)** - シート操作API
|
| 24 |
+
|
| 25 |
+
### Deployment
|
| 26 |
+
- **HuggingFace Spaces** (Docker SDK)
|
| 27 |
+
- ポート: 7860
|
| 28 |
+
|
| 29 |
+
## アーキテクチャ
|
| 30 |
+
|
| 31 |
+
```
|
| 32 |
+
Frontend (React+Tailwind)
|
| 33 |
+
↓
|
| 34 |
+
HF Spaces (FastAPI + Gemini直接)
|
| 35 |
+
↓
|
| 36 |
+
GAS API (Google Sheets操作)
|
| 37 |
+
↓
|
| 38 |
+
Google Sheets (データ永続化)
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
## ディレクトリ構造
|
| 42 |
+
|
| 43 |
+
```
|
| 44 |
+
/
|
| 45 |
+
├── app.py # メインエントリポイント(FastAPI)
|
| 46 |
+
├── src/
|
| 47 |
+
│ ├── services/ # サービス層
|
| 48 |
+
│ │ ├── gemini_service.py # Gemini API呼び出し
|
| 49 |
+
│ │ ├── gas_client.py # GAS API クライアント
|
| 50 |
+
│ │ ├── auth_service.py # 認証サービス
|
| 51 |
+
│ │ └── questiondb_service.py # 問題DB操作
|
| 52 |
+
│ └── prompts/ # LLMプロンプト
|
| 53 |
+
│ ├── question_prompts.py # 問題生成用
|
| 54 |
+
│ ├── evaluation_prompts.py # 評価用
|
| 55 |
+
│ └── validation_prompts.py # 検証用
|
| 56 |
+
├── gas/ # Google Apps Script
|
| 57 |
+
│ ├── Code.js # メインGASコード
|
| 58 |
+
│ └── *.js # その他GAS関連
|
| 59 |
+
├── static/ # フロントエンド静的ファイル
|
| 60 |
+
├── docs/ # ドキュメント
|
| 61 |
+
├── log/ # 開発ログ
|
| 62 |
+
├── STATUS.md # プロジェクト状態
|
| 63 |
+
└── CLAUDE.md # 開発ガイドライン
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## 主要APIエンドポイント
|
| 67 |
+
|
| 68 |
+
| エンドポイント | メソッド | 説明 |
|
| 69 |
+
|--------------|---------|------|
|
| 70 |
+
| `/api/health` | GET | ヘルスチェック |
|
| 71 |
+
| `/api/register_user` | POST | ユーザー登録 |
|
| 72 |
+
| `/api/login` | POST | ログイン |
|
| 73 |
+
| `/api/generate_questions` | POST | 問題生成(Gemini) |
|
| 74 |
+
| `/api/submit_answers` | POST | 解答提出 |
|
| 75 |
+
| `/api/get_evaluation` | POST | 評価取得 |
|
| 76 |
+
|
| 77 |
+
## 環境変数
|
| 78 |
+
|
| 79 |
+
| 変数名 | 説明 |
|
| 80 |
+
|-------|------|
|
| 81 |
+
| `GEMINI_API_KEY` | Google Gemini API Key |
|
| 82 |
+
| `GAS_API_URL` | Google Apps Script Web App URL |
|
| 83 |
+
|
| 84 |
+
## デプロイ情報
|
| 85 |
+
|
| 86 |
+
- **HF Space**: leave-everything/ChoTensai_V3
|
| 87 |
+
- **GAS デプロイID**: @32 (v1.6.1-test)
|
.serena/memories/suggested_commands.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 超天才クイズ V3 - 推奨コマンド
|
| 2 |
+
|
| 3 |
+
## 開発環境
|
| 4 |
+
|
| 5 |
+
### ローカル起動
|
| 6 |
+
```bash
|
| 7 |
+
# 依存関係インストール
|
| 8 |
+
pip install -r requirements.txt
|
| 9 |
+
|
| 10 |
+
# サーバー起動(ポート7860)
|
| 11 |
+
python app.py
|
| 12 |
+
```
|
| 13 |
+
|
| 14 |
+
### テスト
|
| 15 |
+
```bash
|
| 16 |
+
# Python構文チェック
|
| 17 |
+
python -m py_compile app.py
|
| 18 |
+
python -m py_compile src/services/*.py
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
### Git操作
|
| 22 |
+
```bash
|
| 23 |
+
# ステータス確認
|
| 24 |
+
git status
|
| 25 |
+
git log --oneline -5
|
| 26 |
+
|
| 27 |
+
# 差分確認
|
| 28 |
+
git diff HEAD
|
| 29 |
+
|
| 30 |
+
# コミット
|
| 31 |
+
git add .
|
| 32 |
+
git commit -m "メッセージ"
|
| 33 |
+
git push
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
## GAS (Google Apps Script) 操作
|
| 37 |
+
|
| 38 |
+
### clasp コマンド
|
| 39 |
+
```bash
|
| 40 |
+
cd gas
|
| 41 |
+
|
| 42 |
+
# プッシュ(GASにアップロード)
|
| 43 |
+
clasp push
|
| 44 |
+
|
| 45 |
+
# デプロイ一覧
|
| 46 |
+
clasp deployments
|
| 47 |
+
|
| 48 |
+
# 新規デプロイ
|
| 49 |
+
clasp deploy -d "説明文"
|
| 50 |
+
|
| 51 |
+
# エディタを開く
|
| 52 |
+
clasp open
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
## API テスト
|
| 56 |
+
|
| 57 |
+
### ヘルスチェック
|
| 58 |
+
```bash
|
| 59 |
+
curl http://localhost:7860/api/health
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
### HF Spaces URL
|
| 63 |
+
```bash
|
| 64 |
+
curl https://leave-everything-chotensai-v3.hf.space/api/health
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
## Docker操作
|
| 68 |
+
|
| 69 |
+
### ビルド
|
| 70 |
+
```bash
|
| 71 |
+
docker build -t chotensai-v3 .
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
### 実行
|
| 75 |
+
```bash
|
| 76 |
+
docker run -p 7860:7860 --env-file .env chotensai-v3
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
## ファイルシステム(Linux)
|
| 80 |
+
|
| 81 |
+
```bash
|
| 82 |
+
# ディレクトリ一覧
|
| 83 |
+
ls -la
|
| 84 |
+
|
| 85 |
+
# ファイル検索
|
| 86 |
+
find . -name "*.py"
|
| 87 |
+
|
| 88 |
+
# 内容検索
|
| 89 |
+
grep -r "パターン" src/
|
| 90 |
+
|
| 91 |
+
# ファイル表示
|
| 92 |
+
cat ファイル名
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
## 環境変数
|
| 96 |
+
|
| 97 |
+
`.env` ファイルに以下を設定:
|
| 98 |
+
```
|
| 99 |
+
GEMINI_API_KEY=xxx
|
| 100 |
+
GAS_API_URL=xxx
|
| 101 |
+
```
|
PLAN.md
CHANGED
|
@@ -1,34 +1,26 @@
|
|
| 1 |
-
# PLAN: 超天才クイズ v1.6.
|
| 2 |
|
| 3 |
## 現在のベースライン
|
| 4 |
-
- **バージョン**: v1.6.
|
| 5 |
-
- **状態**:
|
| 6 |
|
| 7 |
---
|
| 8 |
|
| 9 |
-
## v1.6.
|
| 10 |
|
| 11 |
-
###
|
| 12 |
|
| 13 |
-
**
|
| 14 |
-
|
| 15 |
-
|
| 16 |
|
| 17 |
-
**
|
|
|
|
|
|
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|---------|------|
|
| 21 |
-
| `src/prompts/question_prompts.py` | `correct_answer: 1-4` + 位置分散指示追加 |
|
| 22 |
-
| `src/prompts/validation_prompts.py` | 位置偏り検出・選択肢入れ替え指示追加 |
|
| 23 |
-
| `app.py` | `shuffle_choices` → `convert_correct_answer_index`に簡略化 |
|
| 24 |
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
**修正内容**: `src/services/gemini_service.py` の全9箇所を65536に統一
|
| 28 |
-
|
| 29 |
-
### 問題3: シートスキーマ不整合
|
| 30 |
-
|
| 31 |
-
**修正内容**: `gas/setup_sheets_v3.js` 新規作成
|
| 32 |
|
| 33 |
---
|
| 34 |
|
|
@@ -36,63 +28,44 @@
|
|
| 36 |
|
| 37 |
| # | タスク | ファイル | 状態 |
|
| 38 |
|---|--------|---------|------|
|
| 39 |
-
| 1 |
|
| 40 |
-
| 2 |
|
| 41 |
-
| 3 |
|
| 42 |
-
| 4 |
|
| 43 |
-
| 5 |
|
| 44 |
-
| 6 |
|
| 45 |
-
| 7 | GAS
|
| 46 |
-
| 8 |
|
| 47 |
-
| 9 | git commit & push | - |
|
| 48 |
| 10 | E2Eテスト | - | 🔲 待ち |
|
| 49 |
|
| 50 |
---
|
| 51 |
|
| 52 |
## 受入基準
|
| 53 |
|
| 54 |
-
- [ ] 正解位置が
|
| 55 |
- [ ] 正解を選択すると正解と判定される
|
| 56 |
- [ ] SCOREが正しく計算される(例: 8/10 = 80点)
|
| 57 |
- [ ] AI先生アドバイスが表示される
|
| 58 |
|
| 59 |
---
|
| 60 |
|
| 61 |
-
##
|
| 62 |
-
|
| 63 |
-
```javascript
|
| 64 |
-
// GASエディタで以下の関数を実行:
|
| 65 |
-
|
| 66 |
-
// 1. シート削除→初期化を一括実行(推奨)
|
| 67 |
-
resetAndInitialize()
|
| 68 |
-
|
| 69 |
-
// または個別実行:
|
| 70 |
-
// QuestionDatabase以外を削除
|
| 71 |
-
deleteAllSheetsExceptQuestionDB()
|
| 72 |
-
|
| 73 |
-
// 現行スキーマで全シート初期化
|
| 74 |
-
initializeAllSheets()
|
| 75 |
-
```
|
| 76 |
-
|
| 77 |
-
---
|
| 78 |
-
|
| 79 |
-
## デプロイ情報
|
| 80 |
|
| 81 |
-
|
|
| 82 |
-
|------|-----|
|
| 83 |
-
|
|
| 84 |
-
|
|
| 85 |
-
| **Spreadsheet** | `10JLP5ds2CNDOEYTxEzDyY82dErbD-InkTeuyzS_w_3U` |
|
| 86 |
|
| 87 |
---
|
| 88 |
|
| 89 |
## ロールバック手順
|
| 90 |
|
| 91 |
```bash
|
| 92 |
-
# v1.6.
|
| 93 |
-
git revert
|
| 94 |
git push origin main
|
| 95 |
```
|
| 96 |
|
| 97 |
---
|
| 98 |
-
**最終更新**: 2025-12-20
|
|
|
|
| 1 |
+
# PLAN: 超天才クイズ v1.6.9 correct_answer 0-indexed統一
|
| 2 |
|
| 3 |
## 現在のベースライン
|
| 4 |
+
- **バージョン**: v1.6.9
|
| 5 |
+
- **状態**: E2Eテスト待ち
|
| 6 |
|
| 7 |
---
|
| 8 |
|
| 9 |
+
## v1.6.9 修正内容(2025-12-20)
|
| 10 |
|
| 11 |
+
### 修正1: correct_answer を 0-indexed に統一
|
| 12 |
|
| 13 |
+
**問題点**:
|
| 14 |
+
- v1.6.8では1-indexed (1-4) で生成し、Pythonで0-indexed (0-3) に変換していた
|
| 15 |
+
- 変換処理が冗長で、バグの原因になりやすい
|
| 16 |
|
| 17 |
+
**解決策**:
|
| 18 |
+
- Geminiプロンプトで最初から0-indexed (0-3) で生成
|
| 19 |
+
- 変換関数 `convert_correct_answer_index` を削除
|
| 20 |
|
| 21 |
+
### 修正2: temperature を 1.0 に統一
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
全Gemini API呼び出し(9箇所)の temperature を 1.0 に統一
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
---
|
| 26 |
|
|
|
|
| 28 |
|
| 29 |
| # | タスク | ファイル | 状態 |
|
| 30 |
|---|--------|---------|------|
|
| 31 |
+
| 1 | プロンプト: correct_answer 0-3 | question_prompts.py | ✅ 完了 |
|
| 32 |
+
| 2 | プロンプト: correct_answer 0-3 | validation_prompts.py | ✅ 完了 |
|
| 33 |
+
| 3 | スキーマ: ge=0, le=3 | gemini_schemas.py | ✅ 完了 |
|
| 34 |
+
| 4 | 変換関数削除 | app.py | ✅ 完了 |
|
| 35 |
+
| 5 | temperature=1.0 統一 | gemini_service.py | ✅ 完了 |
|
| 36 |
+
| 6 | GAS resetAndInitialize() 実行 | GASエディタ | ✅ 完了 |
|
| 37 |
+
| 7 | GAS再デプロイ (@38) | GASエディタ | ✅ 完了 |
|
| 38 |
+
| 8 | HF Spaces GAS_API_URL 更新 | HF Settings | ✅ 完了 |
|
| 39 |
+
| 9 | git commit & push | - | ✅ 完了 |
|
| 40 |
| 10 | E2Eテスト | - | 🔲 待ち |
|
| 41 |
|
| 42 |
---
|
| 43 |
|
| 44 |
## 受入基準
|
| 45 |
|
| 46 |
+
- [ ] 正解位置が0〜3に分散している
|
| 47 |
- [ ] 正解を選択すると正解と判定される
|
| 48 |
- [ ] SCOREが正しく計算される(例: 8/10 = 80点)
|
| 49 |
- [ ] AI先生アドバイスが表示される
|
| 50 |
|
| 51 |
---
|
| 52 |
|
| 53 |
+
## コミット履歴
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
| コミットID | 内容 |
|
| 56 |
+
|-----------|------|
|
| 57 |
+
| `e93e046` | v1.6.8: 正答位置バグ修正・MAX_OUTPUT_TOKENS統一 |
|
| 58 |
+
| `27a3ba5` | v1.6.9: correct_answer 0-indexed統一・temperature=1.0 |
|
|
|
|
| 59 |
|
| 60 |
---
|
| 61 |
|
| 62 |
## ロールバック手順
|
| 63 |
|
| 64 |
```bash
|
| 65 |
+
# v1.6.8に戻す
|
| 66 |
+
git revert 27a3ba5
|
| 67 |
git push origin main
|
| 68 |
```
|
| 69 |
|
| 70 |
---
|
| 71 |
+
**最終更新**: 2025-12-20 01:00
|
PLAN_v1.1.md
DELETED
|
@@ -1,282 +0,0 @@
|
|
| 1 |
-
# PLAN: 超天才クイズ v1.1 開発計画
|
| 2 |
-
|
| 3 |
-
## 目的
|
| 4 |
-
v1.0の安定版をベースに、問題数増加・難易度調整・品質検証・セキュリティ強化を実施
|
| 5 |
-
|
| 6 |
-
---
|
| 7 |
-
|
| 8 |
-
## 確定要件
|
| 9 |
-
|
| 10 |
-
| # | 機能 | 詳細 |
|
| 11 |
-
|---|------|------|
|
| 12 |
-
| 1 | 問題数変更 | 5問 → **10問/教科** |
|
| 13 |
-
| 2 | 難易度調整 | 早く解けるよう難易度を下げる(ただし簡単すぎない) |
|
| 14 |
-
| 3 | 検証LLM | 同一モデル(Gemini)で問題・解答・解説の整合性・学術的正当性を検証・修正 |
|
| 15 |
-
| 4 | 認証強化 | ユーザー名 + パスワード + 招待コード(新規登録時のみ) |
|
| 16 |
-
|
| 17 |
-
---
|
| 18 |
-
|
| 19 |
-
## 安全策(v1.0.0 ロールバック保証)
|
| 20 |
-
|
| 21 |
-
### 絶対守るルール
|
| 22 |
-
1. **v1.0.0 タグは絶対に削除しない**
|
| 23 |
-
2. **破壊的変更は新ブランチで開発** → `feature/v1.1` ブランチ
|
| 24 |
-
3. **各機能完了ごとにタグ作成** → `v1.1.0-alpha.1` 等
|
| 25 |
-
4. **mainへのマージは全機能テスト後**
|
| 26 |
-
|
| 27 |
-
### ロールバック手順(緊急時)
|
| 28 |
-
```bash
|
| 29 |
-
# v1.0.0 に即座に戻す
|
| 30 |
-
git checkout v1.0.0
|
| 31 |
-
git push -f origin main # HF Spaces を v1.0.0 に戻す
|
| 32 |
-
```
|
| 33 |
-
|
| 34 |
-
---
|
| 35 |
-
|
| 36 |
-
## 実装順序(確定)
|
| 37 |
-
|
| 38 |
-
```
|
| 39 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 40 |
-
│ Phase 0: 開発準備 │
|
| 41 |
-
│ └─ feature/v1.1 ブランチ作成 │
|
| 42 |
-
├─────────────────────────────────────────────────────────────┤
|
| 43 |
-
│ Phase 1: 認証強化(セキュリティ最優先) │
|
| 44 |
-
│ ├─ 1.1 招待コード検証(新規登録時) │
|
| 45 |
-
│ ├─ 1.2 パスワードハッシュ化・保存(GAS) │
|
| 46 |
-
│ ├─ 1.3 ログイン認証(パスワード検証) │
|
| 47 |
-
│ └─ 1.4 フロントエンド対応(パスワード入力UI) │
|
| 48 |
-
├─────────────────────────────────────────────────────────────┤
|
| 49 |
-
│ Phase 2: 問題数・難易度調整 │
|
| 50 |
-
│ ├─ 2.1 問題数を10問に変更(プロンプト・API) │
|
| 51 |
-
│ ├─ 2.2 難易度バランス調整(基本寄りに) │
|
| 52 |
-
│ └─ 2.3 タイムアウト対策(必要に応じて分割生成) │
|
| 53 |
-
├─────────────────────────────────────────────────────────────┤
|
| 54 |
-
│ Phase 3: 検証LLM実装 │
|
| 55 |
-
│ ├─ 3.1 検証プロンプト設計 │
|
| 56 |
-
│ ├─ 3.2 検証サービス実装(GeminiService拡張) │
|
| 57 |
-
│ ├─ 3.3 問題生成フローに検証ステップ追加 │
|
| 58 |
-
│ └─ 3.4 不合格問題の修正ロジック │
|
| 59 |
-
├─────────────────────────────────────────────────────────────┤
|
| 60 |
-
│ Phase 4: 統合テスト・リリース │
|
| 61 |
-
│ ├─ 4.1 E2Eテスト │
|
| 62 |
-
│ ├─ 4.2 v1.1.0 タグ作成 │
|
| 63 |
-
│ └─ 4.3 main マージ・デプロイ │
|
| 64 |
-
└─────────────────────────────────────────────────────────────┘
|
| 65 |
-
```
|
| 66 |
-
|
| 67 |
-
---
|
| 68 |
-
|
| 69 |
-
## Phase 1: 認証強化 詳細設計
|
| 70 |
-
|
| 71 |
-
### 1.1 招待コード検証
|
| 72 |
-
|
| 73 |
-
**実装箇所**: GAS `Code.gs` / Python `app.py`
|
| 74 |
-
|
| 75 |
-
**フロー**:
|
| 76 |
-
```
|
| 77 |
-
[新規登録] → [招待コード入力] → [HF Secret と照合] → [一致すれば登録許可]
|
| 78 |
-
```
|
| 79 |
-
|
| 80 |
-
**HF Secrets 追加**:
|
| 81 |
-
```
|
| 82 |
-
INVITE_CODE=任意の文字列(例: TENSAI2025)
|
| 83 |
-
```
|
| 84 |
-
|
| 85 |
-
### 1.2 パスワードハッシュ化
|
| 86 |
-
|
| 87 |
-
**実装箇所**: Python `app.py`(bcrypt使用)
|
| 88 |
-
|
| 89 |
-
**Users シート 変更**:
|
| 90 |
-
```
|
| 91 |
-
| user_id | username | password_hash | created_at | last_login |
|
| 92 |
-
```
|
| 93 |
-
|
| 94 |
-
**ハッシュ化**: Python側で bcrypt → GASに保存
|
| 95 |
-
|
| 96 |
-
### 1.3 ログイン認証
|
| 97 |
-
|
| 98 |
-
**フロー**:
|
| 99 |
-
```
|
| 100 |
-
[ログイン] → [username + password 送信] → [Python で bcrypt 検証] → [成功/失敗]
|
| 101 |
-
```
|
| 102 |
-
|
| 103 |
-
### 1.4 フロントエンドUI
|
| 104 |
-
|
| 105 |
-
**変更箇所**: `static/index.html`, `static/js/components.js`
|
| 106 |
-
|
| 107 |
-
**新規登録画面**:
|
| 108 |
-
- ユーザー名入力
|
| 109 |
-
- パスワード入力
|
| 110 |
-
- パスワード確認
|
| 111 |
-
- 招待コード入力
|
| 112 |
-
|
| 113 |
-
**ログイン画面**:
|
| 114 |
-
- ユーザー名入力
|
| 115 |
-
- パスワード入力
|
| 116 |
-
|
| 117 |
-
---
|
| 118 |
-
|
| 119 |
-
## Phase 2: 問題数・難易度調整 詳細設計
|
| 120 |
-
|
| 121 |
-
### 2.1 問題数変更
|
| 122 |
-
|
| 123 |
-
**変更箇所**:
|
| 124 |
-
| ファイル | 変更内容 |
|
| 125 |
-
|---------|---------|
|
| 126 |
-
| `question_prompts.py` | 「5問」→「10問」 |
|
| 127 |
-
| `gemini_service.py` | `max_output_tokens` 確認(16384で十分) |
|
| 128 |
-
| フロントエンド | 進捗表示対応(1/10, 2/10...) |
|
| 129 |
-
|
| 130 |
-
### 2.2 難易度バランス調整
|
| 131 |
-
|
| 132 |
-
**現在のプロンプト**:
|
| 133 |
-
> 難易度: 基本、標準、応用をバランスよく混ぜる
|
| 134 |
-
|
| 135 |
-
**変更後**:
|
| 136 |
-
> 難易度配分: 基本4問、標準4問、応用2問
|
| 137 |
-
> ※素早く解ける問題を中心に、ただし考えさせる要素は残す
|
| 138 |
-
|
| 139 |
-
### 2.3 タイムアウト対策
|
| 140 |
-
|
| 141 |
-
**10問生成の見込み時間**: 約40-50秒(5問で20秒 × 2)
|
| 142 |
-
|
| 143 |
-
**対策**:
|
| 144 |
-
- タイムアウトを180秒に延長(現在120秒)
|
| 145 |
-
- 必要に応じて分割生成(5問×2回)
|
| 146 |
-
|
| 147 |
-
---
|
| 148 |
-
|
| 149 |
-
## Phase 3: 検証LLM 詳細設計
|
| 150 |
-
|
| 151 |
-
### 3.1 検証プロンプト設計
|
| 152 |
-
|
| 153 |
-
```
|
| 154 |
-
あなたは中学受験問題の品質検証専門家です。
|
| 155 |
-
|
| 156 |
-
## タスク
|
| 157 |
-
以下の問題を検証し、必要に応じて修正してください。
|
| 158 |
-
|
| 159 |
-
## 検証観点
|
| 160 |
-
1. **正確性**: 正解が本当に正解か(学術的に正しいか)
|
| 161 |
-
2. **整合性**: 問題文・選択肢・解説が矛盾していないか
|
| 162 |
-
3. **明確性**: 問題文が曖昧でないか、一意に解答できるか
|
| 163 |
-
4. **適切性**: 中学受験レベルとして適切か
|
| 164 |
-
|
| 165 |
-
## 入力(生成された問題)
|
| 166 |
-
{questions_json}
|
| 167 |
-
|
| 168 |
-
## 出力形式
|
| 169 |
-
- 問題に問題がなければそのまま返す
|
| 170 |
-
- 修正が必要な場合は修正版を返す
|
| 171 |
-
- 修正箇所には "modified": true を付与
|
| 172 |
-
|
| 173 |
-
```json
|
| 174 |
-
[
|
| 175 |
-
{
|
| 176 |
-
"original_index": 0,
|
| 177 |
-
"modified": false,
|
| 178 |
-
"question": {...}
|
| 179 |
-
},
|
| 180 |
-
{
|
| 181 |
-
"original_index": 1,
|
| 182 |
-
"modified": true,
|
| 183 |
-
"modification_reason": "正解が誤っていたため修正",
|
| 184 |
-
"question": {...修正版...}
|
| 185 |
-
}
|
| 186 |
-
]
|
| 187 |
-
```
|
| 188 |
-
```
|
| 189 |
-
|
| 190 |
-
### 3.2 検証フロー
|
| 191 |
-
|
| 192 |
-
```
|
| 193 |
-
[問題生成LLM]
|
| 194 |
-
↓
|
| 195 |
-
[10問の問題JSON]
|
| 196 |
-
↓
|
| 197 |
-
[検証LLM] ← 検証プロンプト
|
| 198 |
-
↓
|
| 199 |
-
[検証済み問題JSON]
|
| 200 |
-
├─ modified: false → そのまま採用
|
| 201 |
-
└─ modified: true → 修正版を採用
|
| 202 |
-
↓
|
| 203 |
-
[GASに保存]
|
| 204 |
-
```
|
| 205 |
-
|
| 206 |
-
### 3.3 検証パラメータ
|
| 207 |
-
|
| 208 |
-
| パラメータ | 値 | 理由 |
|
| 209 |
-
|-----------|-----|------|
|
| 210 |
-
| temperature | 0.2 | 一貫性重視(検証は創造性不要) |
|
| 211 |
-
| max_output_tokens | 16384 | 10問分の出力 |
|
| 212 |
-
|
| 213 |
-
---
|
| 214 |
-
|
| 215 |
-
## SUBAGENT 分担計画
|
| 216 |
-
|
| 217 |
-
### Phase 1: 認証強化
|
| 218 |
-
| タスク | SUBAGENT | 並列 |
|
| 219 |
-
|--------|----------|------|
|
| 220 |
-
| 1.1 招待コード(Python) | coding-specialist | ✅ |
|
| 221 |
-
| 1.2 パスワードハッシュ(Python) | coding-specialist | ✅ |
|
| 222 |
-
| 1.3 GAS認証API追加 | coding-specialist | ✅ |
|
| 223 |
-
| 1.4 フロントエンドUI | coding-specialist | - |
|
| 224 |
-
|
| 225 |
-
### Phase 2: 問題数・難易度
|
| 226 |
-
| タスク | SUBAGENT | 並列 |
|
| 227 |
-
|--------|----------|------|
|
| 228 |
-
| 2.1 プロンプト修正 | coding-specialist | ✅ |
|
| 229 |
-
| 2.2 API/config修正 | coding-specialist | ✅ |
|
| 230 |
-
| 2.3 フロントエンド進捗表示 | coding-specialist | - |
|
| 231 |
-
|
| 232 |
-
### Phase 3: 検証LLM
|
| 233 |
-
| タスク | SUBAGENT | 並列 |
|
| 234 |
-
|--------|----------|------|
|
| 235 |
-
| 3.1 検証プロンプト作成 | coding-specialist | - |
|
| 236 |
-
| 3.2 検証サービス実装 | coding-specialist | - |
|
| 237 |
-
| 3.3 フロー統合 | coding-specialist | - |
|
| 238 |
-
|
| 239 |
-
### Phase 4: テスト・リリース
|
| 240 |
-
| タスク | SUBAGENT | 並列 |
|
| 241 |
-
|--------|----------|------|
|
| 242 |
-
| 4.1 E2Eテスト | api-request-reporter | - |
|
| 243 |
-
| 4.2 ドキュメント更新 | coding-specialist | - |
|
| 244 |
-
|
| 245 |
-
---
|
| 246 |
-
|
| 247 |
-
## 受入基準
|
| 248 |
-
|
| 249 |
-
| 項目 | 基準 |
|
| 250 |
-
|------|------|
|
| 251 |
-
| **認証** | 招待コードなしで新規登録不可、パスワード不一致でログイン不可 |
|
| 252 |
-
| **問題数** | 1教科10問生成される |
|
| 253 |
-
| **難易度** | 基本4:標準4:応用2 の比率 |
|
| 254 |
-
| **検証** | 明らかな誤りが検証LLMで修正される |
|
| 255 |
-
| **性能** | 10問生成+検証が180秒以内 |
|
| 256 |
-
| **ロールバック** | v1.0.0 に即座に戻せる |
|
| 257 |
-
|
| 258 |
-
---
|
| 259 |
-
|
| 260 |
-
## 主要リスク
|
| 261 |
-
|
| 262 |
-
| リスク | 確度 | Plan B |
|
| 263 |
-
|--------|------|--------|
|
| 264 |
-
| 10問+検証でタイムアウト | Med | 分割生成 or 検証を非同期化 |
|
| 265 |
-
| 既存ユーザーのパスワード移行 | Med | 初回ログイン時にパスワード設定を促す |
|
| 266 |
-
| 検証LLMが過剰に修正 | Low | 検証プロンプト調整 |
|
| 267 |
-
|
| 268 |
-
---
|
| 269 |
-
|
| 270 |
-
## 既存ユーザー移行戦略
|
| 271 |
-
|
| 272 |
-
**問題**: 既存ユーザーはパスワードがない
|
| 273 |
-
|
| 274 |
-
**解決策**: 移行期間を設ける
|
| 275 |
-
1. 既存ユーザーがログイン → パスワード未設定を検知
|
| 276 |
-
2. 「パスワードを設定してください」画面を表示
|
| 277 |
-
3. パスワード設定後、通常利用可能に
|
| 278 |
-
|
| 279 |
-
---
|
| 280 |
-
|
| 281 |
-
**作成日**: 2025-12-12
|
| 282 |
-
**ステータス**: ��定・実装開始準備完了
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PLAN_v1.2.md
DELETED
|
@@ -1,185 +0,0 @@
|
|
| 1 |
-
# PLAN: 超天才クイズ v1.2.0 - 並列化・効率化
|
| 2 |
-
|
| 3 |
-
## 目的
|
| 4 |
-
複数教科選択時のLLM呼び出しを最適化し、処理時間とコストを削減する。
|
| 5 |
-
|
| 6 |
-
## 現状 vs 改善後
|
| 7 |
-
|
| 8 |
-
```
|
| 9 |
-
【現状 v1.1.0】4教科選択時
|
| 10 |
-
問題生成: 直列4回 → 検証: 直列4回 → 評価: 直列5回
|
| 11 |
-
合計: 13回のLLM呼び出し(すべて直列)
|
| 12 |
-
|
| 13 |
-
【改善後 v1.2.0】4教科選択時
|
| 14 |
-
問題生成: 並列4回 → 検証: 1回 → 評価: 1回
|
| 15 |
-
合計: 6回のLLM呼び出し(生成は並列)
|
| 16 |
-
```
|
| 17 |
-
|
| 18 |
-
---
|
| 19 |
-
|
| 20 |
-
# SUBAGENT タスク定義
|
| 21 |
-
|
| 22 |
-
## T1: 問題生成並列化(SUBAGENT-A)
|
| 23 |
-
|
| 24 |
-
### 目的
|
| 25 |
-
`generate_questions`エンドポイントを`asyncio.gather`で並列化
|
| 26 |
-
|
| 27 |
-
### 対象ファイル
|
| 28 |
-
- `app.py` の `generate_questions` 関数
|
| 29 |
-
|
| 30 |
-
### 実装内容
|
| 31 |
-
```python
|
| 32 |
-
# 現状(直列)
|
| 33 |
-
for subject in request.subjects:
|
| 34 |
-
questions = await gemini_service.generate_questions(...)
|
| 35 |
-
validated = await gemini_service.validate_questions(...)
|
| 36 |
-
saved = await gas_client.save_questions(...)
|
| 37 |
-
|
| 38 |
-
# 改善後(並列生成 → 一括検証 → 並列保存)
|
| 39 |
-
async def generate_for_subject(subject):
|
| 40 |
-
kb = knowledge_service.get_knowledge(subject)
|
| 41 |
-
return await gemini_service.generate_questions(subject, kb)
|
| 42 |
-
|
| 43 |
-
# 並列生成
|
| 44 |
-
results = await asyncio.gather(*[generate_for_subject(s) for s in subjects])
|
| 45 |
-
|
| 46 |
-
# 一括検証(T2のvalidate_questions_batchを呼び出し)
|
| 47 |
-
all_questions = flatten(results)
|
| 48 |
-
validated = await gemini_service.validate_questions_batch(all_questions)
|
| 49 |
-
|
| 50 |
-
# 並列保存
|
| 51 |
-
await asyncio.gather(*[gas_client.save_questions(...) for ...])
|
| 52 |
-
```
|
| 53 |
-
|
| 54 |
-
### 受入基準
|
| 55 |
-
- [ ] 4教科選択時、問題生成が並列実行される
|
| 56 |
-
- [ ] 一部教科失敗時も他教科は成功する
|
| 57 |
-
- [ ] ログに並列処理の開始・完了が出力される
|
| 58 |
-
|
| 59 |
-
### 注意事項
|
| 60 |
-
- T2の`validate_questions_batch`メソッドを呼び出す(T2完了後に統合)
|
| 61 |
-
- エラーハンドリング: `return_exceptions=True`で部分失敗対応
|
| 62 |
-
|
| 63 |
-
---
|
| 64 |
-
|
| 65 |
-
## T2: 検証一括化(SUBAGENT-B)
|
| 66 |
-
|
| 67 |
-
### 目的
|
| 68 |
-
全教科の問題(最大40問)を1回のLLM呼び出しで検証
|
| 69 |
-
|
| 70 |
-
### 対象ファイル
|
| 71 |
-
- `src/prompts/validation_prompts.py` - 新規プロンプト追加
|
| 72 |
-
- `src/services/gemini_service.py` - 新規メソッド追加
|
| 73 |
-
|
| 74 |
-
### 実装内容
|
| 75 |
-
|
| 76 |
-
#### validation_prompts.py に追加
|
| 77 |
-
```python
|
| 78 |
-
def get_batch_validation_prompt(questions_by_subject: Dict[str, List[Dict]]) -> str:
|
| 79 |
-
"""複数教科の問題を一括検証するプロンプト"""
|
| 80 |
-
# 全教科の問題をまとめて検証
|
| 81 |
-
# 各問題に subject, index を付与して識別可能にする
|
| 82 |
-
```
|
| 83 |
-
|
| 84 |
-
#### gemini_service.py に追加
|
| 85 |
-
```python
|
| 86 |
-
async def validate_questions_batch(
|
| 87 |
-
self,
|
| 88 |
-
questions_by_subject: Dict[str, List[Dict]]
|
| 89 |
-
) -> Dict[str, List[Dict]]:
|
| 90 |
-
"""複数教科の問題を一括検証"""
|
| 91 |
-
# 1回のLLM呼び出しで全問題を検証
|
| 92 |
-
# 結果を教科別に分解して返却
|
| 93 |
-
```
|
| 94 |
-
|
| 95 |
-
### 受入基準
|
| 96 |
-
- [ ] 40問を1回のLLM呼び出しで検証できる
|
| 97 |
-
- [ ] 検証結果が教科別に分解されて返却される
|
| 98 |
-
- [ ] 単教科の場合も動作する(後方互換)
|
| 99 |
-
|
| 100 |
-
### 注意事項
|
| 101 |
-
- 既存の`validate_questions`は残す(単教科用)
|
| 102 |
-
- `max_output_tokens`を十分確保(40問分の修正結果)
|
| 103 |
-
|
| 104 |
-
---
|
| 105 |
-
|
| 106 |
-
## T3: 評価一括化(SUBAGENT-C)
|
| 107 |
-
|
| 108 |
-
### 目的
|
| 109 |
-
全教科の評価を1回のLLM呼び出しで生成
|
| 110 |
-
|
| 111 |
-
### 対象ファイル
|
| 112 |
-
- `src/prompts/evaluation_prompts.py` - 新規プロンプト追加
|
| 113 |
-
- `src/services/gemini_service.py` - 新規メソッド追加
|
| 114 |
-
|
| 115 |
-
### 実装内容
|
| 116 |
-
|
| 117 |
-
#### evaluation_prompts.py に追加
|
| 118 |
-
```python
|
| 119 |
-
def get_batch_evaluation_prompt(
|
| 120 |
-
results_by_subject: Dict[str, List[Dict]],
|
| 121 |
-
statistics: Dict = None
|
| 122 |
-
) -> str:
|
| 123 |
-
"""複数教科の評価を一括生成するプロンプト"""
|
| 124 |
-
# 全教科の結果をまとめて評価
|
| 125 |
-
# 教科別評価 + 全体評価を1回で生成
|
| 126 |
-
```
|
| 127 |
-
|
| 128 |
-
#### gemini_service.py に追加
|
| 129 |
-
```python
|
| 130 |
-
async def generate_evaluation_batch(
|
| 131 |
-
self,
|
| 132 |
-
session_data: Dict[str, Any]
|
| 133 |
-
) -> Dict[str, Any]:
|
| 134 |
-
"""複数教科の評価を一括生成"""
|
| 135 |
-
# 1回のLLM呼び出しで教科別評価 + 全体評価を生成
|
| 136 |
-
# 結果を構造化して返却
|
| 137 |
-
```
|
| 138 |
-
|
| 139 |
-
### 受入基準
|
| 140 |
-
- [ ] 4教科を1回のLLM呼び出しで評価できる
|
| 141 |
-
- [ ] 教科別評価と全体評価が両方生成される
|
| 142 |
-
- [ ] 単教科の場合も動作する(後方互換)
|
| 143 |
-
|
| 144 |
-
### 注意事項
|
| 145 |
-
- 既存の`generate_evaluation`は残す(後方互換)
|
| 146 |
-
- 出力JSON構造を明確に定義
|
| 147 |
-
|
| 148 |
-
---
|
| 149 |
-
|
| 150 |
-
## T4: 統合・E2Eテスト(MAIN)
|
| 151 |
-
|
| 152 |
-
### 目的
|
| 153 |
-
T1-T3の成果物を統合し、E2Eテストで品質確認
|
| 154 |
-
|
| 155 |
-
### 実施内容
|
| 156 |
-
1. T1-T3のコードをマージ
|
| 157 |
-
2. `app.py`でT2, T3の新メソッドを呼び出すよう統合
|
| 158 |
-
3. E2Eテスト実行
|
| 159 |
-
- 単教科テスト(回帰確認)
|
| 160 |
-
- 複数教科テスト(並��・一括動作確認)
|
| 161 |
-
- 精度検証(検証一括化の品質確認)
|
| 162 |
-
4. v1.2.0タグ作成・デプロイ
|
| 163 |
-
|
| 164 |
-
### 依存
|
| 165 |
-
- T1, T2, T3 すべて完了後に実施
|
| 166 |
-
|
| 167 |
-
---
|
| 168 |
-
|
| 169 |
-
## 期待効果
|
| 170 |
-
|
| 171 |
-
| 指標 | v1.1.0 | v1.2.0 | 改善率 |
|
| 172 |
-
|-----|--------|--------|-------|
|
| 173 |
-
| LLM呼び出し(4教科) | 13回 | 6回 | 54%削減 |
|
| 174 |
-
| 処理時間(推定) | 60秒 | 25秒 | 58%短縮 |
|
| 175 |
-
|
| 176 |
-
## リスクと対策
|
| 177 |
-
|
| 178 |
-
| リスク | 確度 | 対策 |
|
| 179 |
-
|-------|------|------|
|
| 180 |
-
| 検証一括で精度低下 | Medium | マニュアルテストで確認、必要なら分割に戻す |
|
| 181 |
-
| Gemini APIレート制限 | Low | セマフォで同時実行数制限 |
|
| 182 |
-
| 部分失敗時のエラー処理 | Medium | `return_exceptions=True`で成功分のみ返却 |
|
| 183 |
-
|
| 184 |
-
---
|
| 185 |
-
**作成日**: 2025-12-12
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STATUS.md
CHANGED
|
@@ -1,33 +1,34 @@
|
|
| 1 |
-
# プロジェクト: 超天才クイズ v1.6.
|
| 2 |
|
| 3 |
## ステータス概要
|
| 4 |
-
- **現在地**: v1.6.
|
| 5 |
-
- **完成度**:
|
| 6 |
-
- **最新コミット**:
|
| 7 |
-
|
| 8 |
-
## v1.6.
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
|
| 12 |
-
|
|
| 13 |
-
|
|
| 14 |
-
|
|
| 15 |
-
|
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
| 23 |
|
| 24 |
## デプロイ情報
|
| 25 |
|
| 26 |
| 項目 | 値 |
|
| 27 |
|------|-----|
|
| 28 |
| **HF Space** | leave-everything/ChoTensai_V3 |
|
| 29 |
-
| **GAS Version** | @
|
| 30 |
-
| **GAS URL** | `https://script.google.com/macros/s/
|
| 31 |
| **Spreadsheet ID** | `10JLP5ds2CNDOEYTxEzDyY82dErbD-InkTeuyzS_w_3U` |
|
| 32 |
|
| 33 |
## 作業環境
|
|
@@ -38,4 +39,4 @@
|
|
| 38 |
```
|
| 39 |
|
| 40 |
---
|
| 41 |
-
**最終更新**: 2025-12-20
|
|
|
|
| 1 |
+
# プロジェクト: 超天才クイズ v1.6.9
|
| 2 |
|
| 3 |
## ステータス概要
|
| 4 |
+
- **現在地**: v1.6.9 E2Eテスト待ち
|
| 5 |
+
- **完成度**: 98%
|
| 6 |
+
- **最新コミット**: `27a3ba5` (2025-12-20)
|
| 7 |
+
|
| 8 |
+
## v1.6.9 修正内容
|
| 9 |
+
|
| 10 |
+
| 項目 | 変更内容 |
|
| 11 |
+
|------|---------|
|
| 12 |
+
| correct_answer | 0-indexed (0-3) に統一 |
|
| 13 |
+
| index変換関数 | 削除(変換不要) |
|
| 14 |
+
| temperature | 全9箇所を 1.0 に統一 |
|
| 15 |
+
| GAS URL | @38 に更新済み |
|
| 16 |
+
|
| 17 |
+
## 次のアクション
|
| 18 |
+
1. **E2Eテスト**(HF Spaces再起動待ち)
|
| 19 |
+
- ログイン
|
| 20 |
+
- 問題生成
|
| 21 |
+
- 正解判定確認
|
| 22 |
+
- SCORE計算確認
|
| 23 |
+
- AI先生アドバイス表示確認
|
| 24 |
|
| 25 |
## デプロイ情報
|
| 26 |
|
| 27 |
| 項目 | 値 |
|
| 28 |
|------|-----|
|
| 29 |
| **HF Space** | leave-everything/ChoTensai_V3 |
|
| 30 |
+
| **GAS Version** | @38 |
|
| 31 |
+
| **GAS URL** | `https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec` |
|
| 32 |
| **Spreadsheet ID** | `10JLP5ds2CNDOEYTxEzDyY82dErbD-InkTeuyzS_w_3U` |
|
| 33 |
|
| 34 |
## 作業環境
|
|
|
|
| 39 |
```
|
| 40 |
|
| 41 |
---
|
| 42 |
+
**最終更新**: 2025-12-20 01:00
|
__pycache__/app.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/app.cpython-310.pyc and b/__pycache__/app.cpython-310.pyc differ
|
|
|
docs/GEMINI_STRUCTURED_OUTPUT.txt
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<br />
|
| 2 |
+
|
| 3 |
+
You can configure Gemini models to generate responses that adhere to a provided JSON Schema. This capability guarantees predictable and parsable results, ensures format and type-safety, enables the programmatic detection of refusals, and simplifies prompting.
|
| 4 |
+
|
| 5 |
+
Using structured outputs is ideal for a wide range of applications:
|
| 6 |
+
|
| 7 |
+
- **Data extraction:**Pull specific information from unstructured text, like extracting names, dates, and amounts from an invoice.
|
| 8 |
+
- **Structured classification:**Classify text into predefined categories and assign structured labels, such as categorizing customer feedback by sentiment and topic.
|
| 9 |
+
- **Agentic workflows:**Generate structured data that can be used to call other tools or APIs, like creating a character sheet for a game or filling out a form.
|
| 10 |
+
|
| 11 |
+
In addition to supporting JSON Schema in the REST API, the Google GenAI SDKs for Python and JavaScript also make it easy to define object schemas using[Pydantic](https://docs.pydantic.dev/latest/)and[Zod](https://zod.dev/), respectively. The example below demonstrates how to extract information from unstructured text that conforms to a schema defined in code.
|
| 12 |
+
|
| 13 |
+
Recipe ExtractorContent ModerationRecursive Structures
|
| 14 |
+
|
| 15 |
+
This example demonstrates how to extract structured data from text using basic JSON Schema types like`object`,`array`,`string`, and`integer`.
|
| 16 |
+
|
| 17 |
+
### Python
|
| 18 |
+
|
| 19 |
+
from google import genai
|
| 20 |
+
from pydantic import BaseModel, Field
|
| 21 |
+
from typing import List, Optional
|
| 22 |
+
|
| 23 |
+
class Ingredient(BaseModel):
|
| 24 |
+
name: str = Field(description="Name of the ingredient.")
|
| 25 |
+
quantity: str = Field(description="Quantity of the ingredient, including units.")
|
| 26 |
+
|
| 27 |
+
class Recipe(BaseModel):
|
| 28 |
+
recipe_name: str = Field(description="The name of the recipe.")
|
| 29 |
+
prep_time_minutes: Optional[int] = Field(description="Optional time in minutes to prepare the recipe.")
|
| 30 |
+
ingredients: List[Ingredient]
|
| 31 |
+
instructions: List[str]
|
| 32 |
+
|
| 33 |
+
client = genai.Client()
|
| 34 |
+
|
| 35 |
+
prompt = """
|
| 36 |
+
Please extract the recipe from the following text.
|
| 37 |
+
The user wants to make delicious chocolate chip cookies.
|
| 38 |
+
They need 2 and 1/4 cups of all-purpose flour, 1 teaspoon of baking soda,
|
| 39 |
+
1 teaspoon of salt, 1 cup of unsalted butter (softened), 3/4 cup of granulated sugar,
|
| 40 |
+
3/4 cup of packed brown sugar, 1 teaspoon of vanilla extract, and 2 large eggs.
|
| 41 |
+
For the best part, they'll need 2 cups of semisweet chocolate chips.
|
| 42 |
+
First, preheat the oven to 375°F (190°C). Then, in a small bowl, whisk together the flour,
|
| 43 |
+
baking soda, and salt. In a large bowl, cream together the butter, granulated sugar, and brown sugar
|
| 44 |
+
until light and fluffy. Beat in the vanilla and eggs, one at a time. Gradually beat in the dry
|
| 45 |
+
ingredients until just combined. Finally, stir in the chocolate chips. Drop by rounded tablespoons
|
| 46 |
+
onto ungreased baking sheets and bake for 9 to 11 minutes.
|
| 47 |
+
"""
|
| 48 |
+
|
| 49 |
+
response = client.models.generate_content(
|
| 50 |
+
model="gemini-2.5-flash",
|
| 51 |
+
contents=prompt,
|
| 52 |
+
config={
|
| 53 |
+
"response_mime_type": "application/json",
|
| 54 |
+
"response_json_schema": Recipe.model_json_schema(),
|
| 55 |
+
},
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
recipe = Recipe.model_validate_json(response.text)
|
| 59 |
+
print(recipe)
|
| 60 |
+
|
| 61 |
+
### JavaScript
|
| 62 |
+
|
| 63 |
+
import { GoogleGenAI } from "@google/genai";
|
| 64 |
+
import { z } from "zod";
|
| 65 |
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
| 66 |
+
|
| 67 |
+
const ingredientSchema = z.object({
|
| 68 |
+
name: z.string().describe("Name of the ingredient."),
|
| 69 |
+
quantity: z.string().describe("Quantity of the ingredient, including units."),
|
| 70 |
+
});
|
| 71 |
+
|
| 72 |
+
const recipeSchema = z.object({
|
| 73 |
+
recipe_name: z.string().describe("The name of the recipe."),
|
| 74 |
+
prep_time_minutes: z.number().optional().describe("Optional time in minutes to prepare the recipe."),
|
| 75 |
+
ingredients: z.array(ingredientSchema),
|
| 76 |
+
instructions: z.array(z.string()),
|
| 77 |
+
});
|
| 78 |
+
|
| 79 |
+
const ai = new GoogleGenAI({});
|
| 80 |
+
|
| 81 |
+
const prompt = `
|
| 82 |
+
Please extract the recipe from the following text.
|
| 83 |
+
The user wants to make delicious chocolate chip cookies.
|
| 84 |
+
They need 2 and 1/4 cups of all-purpose flour, 1 teaspoon of baking soda,
|
| 85 |
+
1 teaspoon of salt, 1 cup of unsalted butter (softened), 3/4 cup of granulated sugar,
|
| 86 |
+
3/4 cup of packed brown sugar, 1 teaspoon of vanilla extract, and 2 large eggs.
|
| 87 |
+
For the best part, they'll need 2 cups of semisweet chocolate chips.
|
| 88 |
+
First, preheat the oven to 375°F (190°C). Then, in a small bowl, whisk together the flour,
|
| 89 |
+
baking soda, and salt. In a large bowl, cream together the butter, granulated sugar, and brown sugar
|
| 90 |
+
until light and fluffy. Beat in the vanilla and eggs, one at a time. Gradually beat in the dry
|
| 91 |
+
ingredients until just combined. Finally, stir in the chocolate chips. Drop by rounded tablespoons
|
| 92 |
+
onto ungreased baking sheets and bake for 9 to 11 minutes.
|
| 93 |
+
`;
|
| 94 |
+
|
| 95 |
+
const response = await ai.models.generateContent({
|
| 96 |
+
model: "gemini-2.5-flash",
|
| 97 |
+
contents: prompt,
|
| 98 |
+
config: {
|
| 99 |
+
responseMimeType: "application/json",
|
| 100 |
+
responseJsonSchema: zodToJsonSchema(recipeSchema),
|
| 101 |
+
},
|
| 102 |
+
});
|
| 103 |
+
|
| 104 |
+
const recipe = recipeSchema.parse(JSON.parse(response.text));
|
| 105 |
+
console.log(recipe);
|
| 106 |
+
|
| 107 |
+
### Go
|
| 108 |
+
|
| 109 |
+
package main
|
| 110 |
+
|
| 111 |
+
import (
|
| 112 |
+
"context"
|
| 113 |
+
"fmt"
|
| 114 |
+
"log"
|
| 115 |
+
|
| 116 |
+
"google.golang.org/genai"
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
func main() {
|
| 120 |
+
ctx := context.Background()
|
| 121 |
+
client, err := genai.NewClient(ctx, nil)
|
| 122 |
+
if err != nil {
|
| 123 |
+
log.Fatal(err)
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
prompt := `
|
| 127 |
+
Please extract the recipe from the following text.
|
| 128 |
+
The user wants to make delicious chocolate chip cookies.
|
| 129 |
+
They need 2 and 1/4 cups of all-purpose flour, 1 teaspoon of baking soda,
|
| 130 |
+
1 teaspoon of salt, 1 cup of unsalted butter (softened), 3/4 cup of granulated sugar,
|
| 131 |
+
3/4 cup of packed brown sugar, 1 teaspoon of vanilla extract, and 2 large eggs.
|
| 132 |
+
For the best part, they'll need 2 cups of semisweet chocolate chips.
|
| 133 |
+
First, preheat the oven to 375°F (190°C). Then, in a small bowl, whisk together the flour,
|
| 134 |
+
baking soda, and salt. In a large bowl, cream together the butter, granulated sugar, and brown sugar
|
| 135 |
+
until light and fluffy. Beat in the vanilla and eggs, one at a time. Gradually beat in the dry
|
| 136 |
+
ingredients until just combined. Finally, stir in the chocolate chips. Drop by rounded tablespoons
|
| 137 |
+
onto ungreased baking sheets and bake for 9 to 11 minutes.
|
| 138 |
+
`
|
| 139 |
+
config := &genai.GenerateContentConfig{
|
| 140 |
+
ResponseMIMEType: "application/json",
|
| 141 |
+
ResponseJsonSchema: map[string]any{
|
| 142 |
+
"type": "object",
|
| 143 |
+
"properties": map[string]any{
|
| 144 |
+
"recipe_name": map[string]any{
|
| 145 |
+
"type": "string",
|
| 146 |
+
"description": "The name of the recipe.",
|
| 147 |
+
},
|
| 148 |
+
"prep_time_minutes": map[string]any{
|
| 149 |
+
"type": "integer",
|
| 150 |
+
"description": "Optional time in minutes to prepare the recipe.",
|
| 151 |
+
},
|
| 152 |
+
"ingredients": map[string]any{
|
| 153 |
+
"type": "array",
|
| 154 |
+
"items": map[string]any{
|
| 155 |
+
"type": "object",
|
| 156 |
+
"properties": map[string]any{
|
| 157 |
+
"name": map[string]any{
|
| 158 |
+
"type": "string",
|
| 159 |
+
"description": "Name of the ingredient.",
|
| 160 |
+
},
|
| 161 |
+
"quantity": map[string]any{
|
| 162 |
+
"type": "string",
|
| 163 |
+
"description": "Quantity of the ingredient, including units.",
|
| 164 |
+
},
|
| 165 |
+
},
|
| 166 |
+
"required": []string{"name", "quantity"},
|
| 167 |
+
},
|
| 168 |
+
},
|
| 169 |
+
"instructions": map[string]any{
|
| 170 |
+
"type": "array",
|
| 171 |
+
"items": map[string]any{"type": "string"},
|
| 172 |
+
},
|
| 173 |
+
},
|
| 174 |
+
"required": []string{"recipe_name", "ingredients", "instructions"},
|
| 175 |
+
},
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
result, err := client.Models.GenerateContent(
|
| 179 |
+
ctx,
|
| 180 |
+
"gemini-2.5-flash",
|
| 181 |
+
genai.Text(prompt),
|
| 182 |
+
config,
|
| 183 |
+
)
|
| 184 |
+
if err != nil {
|
| 185 |
+
log.Fatal(err)
|
| 186 |
+
}
|
| 187 |
+
fmt.Println(result.Text())
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
### REST
|
| 191 |
+
|
| 192 |
+
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" \
|
| 193 |
+
-H "x-goog-api-key: $GEMINI_API_KEY" \
|
| 194 |
+
-H 'Content-Type: application/json' \
|
| 195 |
+
-X POST \
|
| 196 |
+
-d '{
|
| 197 |
+
"contents": [{
|
| 198 |
+
"parts":[
|
| 199 |
+
{ "text": "Please extract the recipe from the following text.\nThe user wants to make delicious chocolate chip cookies.\nThey need 2 and 1/4 cups of all-purpose flour, 1 teaspoon of baking soda,\n1 teaspoon of salt, 1 cup of unsalted butter (softened), 3/4 cup of granulated sugar,\n3/4 cup of packed brown sugar, 1 teaspoon of vanilla extract, and 2 large eggs.\nFor the best part, they will need 2 cups of semisweet chocolate chips.\nFirst, preheat the oven to 375°F (190°C). Then, in a small bowl, whisk together the flour,\nbaking soda, and salt. In a large bowl, cream together the butter, granulated sugar, and brown sugar\nuntil light and fluffy. Beat in the vanilla and eggs, one at a time. Gradually beat in the dry\ningredients until just combined. Finally, stir in the chocolate chips. Drop by rounded tablespoons\nonto ungreased baking sheets and bake for 9 to 11 minutes." }
|
| 200 |
+
]
|
| 201 |
+
}],
|
| 202 |
+
"generationConfig": {
|
| 203 |
+
"responseMimeType": "application/json",
|
| 204 |
+
"responseJsonSchema": {
|
| 205 |
+
"type": "object",
|
| 206 |
+
"properties": {
|
| 207 |
+
"recipe_name": {
|
| 208 |
+
"type": "string",
|
| 209 |
+
"description": "The name of the recipe."
|
| 210 |
+
},
|
| 211 |
+
"prep_time_minutes": {
|
| 212 |
+
"type": "integer",
|
| 213 |
+
"description": "Optional time in minutes to prepare the recipe."
|
| 214 |
+
},
|
| 215 |
+
"ingredients": {
|
| 216 |
+
"type": "array",
|
| 217 |
+
"items": {
|
| 218 |
+
"type": "object",
|
| 219 |
+
"properties": {
|
| 220 |
+
"name": { "type": "string", "description": "Name of the ingredient."},
|
| 221 |
+
"quantity": { "type": "string", "description": "Quantity of the ingredient, including units."}
|
| 222 |
+
},
|
| 223 |
+
"required": ["name", "quantity"]
|
| 224 |
+
}
|
| 225 |
+
},
|
| 226 |
+
"instructions": {
|
| 227 |
+
"type": "array",
|
| 228 |
+
"items": { "type": "string" }
|
| 229 |
+
}
|
| 230 |
+
},
|
| 231 |
+
"required": ["recipe_name", "ingredients", "instructions"]
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
}'
|
| 235 |
+
|
| 236 |
+
**Example Response:**
|
| 237 |
+
|
| 238 |
+
{
|
| 239 |
+
"recipe_name": "Delicious Chocolate Chip Cookies",
|
| 240 |
+
"ingredients": [
|
| 241 |
+
{
|
| 242 |
+
"name": "all-purpose flour",
|
| 243 |
+
"quantity": "2 and 1/4 cups"
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"name": "baking soda",
|
| 247 |
+
"quantity": "1 teaspoon"
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"name": "salt",
|
| 251 |
+
"quantity": "1 teaspoon"
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"name": "unsalted butter (softened)",
|
| 255 |
+
"quantity": "1 cup"
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"name": "granulated sugar",
|
| 259 |
+
"quantity": "3/4 cup"
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"name": "packed brown sugar",
|
| 263 |
+
"quantity": "3/4 cup"
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"name": "vanilla extract",
|
| 267 |
+
"quantity": "1 teaspoon"
|
| 268 |
+
},
|
| 269 |
+
{
|
| 270 |
+
"name": "large eggs",
|
| 271 |
+
"quantity": "2"
|
| 272 |
+
},
|
| 273 |
+
{
|
| 274 |
+
"name": "semisweet chocolate chips",
|
| 275 |
+
"quantity": "2 cups"
|
| 276 |
+
}
|
| 277 |
+
],
|
| 278 |
+
"instructions": [
|
| 279 |
+
"Preheat the oven to 375°F (190°C).",
|
| 280 |
+
"In a small bowl, whisk together the flour, baking soda, and salt.",
|
| 281 |
+
"In a large bowl, cream together the butter, granulated sugar, and brown sugar until light and fluffy.",
|
| 282 |
+
"Beat in the vanilla and eggs, one at a time.",
|
| 283 |
+
"Gradually beat in the dry ingredients until just combined.",
|
| 284 |
+
"Stir in the chocolate chips.",
|
| 285 |
+
"Drop by rounded tablespoons onto ungreased baking sheets and bake for 9 to 11 minutes."
|
| 286 |
+
]
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
## Streaming
|
| 290 |
+
|
| 291 |
+
You can stream structured outputs, which allows you to start processing the response as it's being generated, without having to wait for the entire output to be complete. This can improve the perceived performance of your application.
|
| 292 |
+
|
| 293 |
+
The streamed chunks will be valid partial JSON strings, which can be concatenated to form the final, complete JSON object.
|
| 294 |
+
|
| 295 |
+
### Python
|
| 296 |
+
|
| 297 |
+
from google import genai
|
| 298 |
+
from pydantic import BaseModel, Field
|
| 299 |
+
from typing import Literal
|
| 300 |
+
|
| 301 |
+
class Feedback(BaseModel):
|
| 302 |
+
sentiment: Literal["positive", "neutral", "negative"]
|
| 303 |
+
summary: str
|
| 304 |
+
|
| 305 |
+
client = genai.Client()
|
| 306 |
+
prompt = "The new UI is incredibly intuitive and visually appealing. Great job. Add a very long summary to test streaming!"
|
| 307 |
+
|
| 308 |
+
response_stream = client.models.generate_content_stream(
|
| 309 |
+
model="gemini-2.5-flash",
|
| 310 |
+
contents=prompt,
|
| 311 |
+
config={
|
| 312 |
+
"response_mime_type": "application/json",
|
| 313 |
+
"response_json_schema": Feedback.model_json_schema(),
|
| 314 |
+
},
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
for chunk in response_stream:
|
| 318 |
+
print(chunk.candidates[0].content.parts[0].text)
|
| 319 |
+
|
| 320 |
+
### JavaScript
|
| 321 |
+
|
| 322 |
+
import { GoogleGenAI } from "@google/genai";
|
| 323 |
+
import { z } from "zod";
|
| 324 |
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
| 325 |
+
|
| 326 |
+
const ai = new GoogleGenAI({});
|
| 327 |
+
const prompt = "The new UI is incredibly intuitive and visually appealing. Great job! Add a very long summary to test streaming!";
|
| 328 |
+
|
| 329 |
+
const feedbackSchema = z.object({
|
| 330 |
+
sentiment: z.enum(["positive", "neutral", "negative"]),
|
| 331 |
+
summary: z.string(),
|
| 332 |
+
});
|
| 333 |
+
|
| 334 |
+
const stream = await ai.models.generateContentStream({
|
| 335 |
+
model: "gemini-2.5-flash",
|
| 336 |
+
contents: prompt,
|
| 337 |
+
config: {
|
| 338 |
+
responseMimeType: "application/json",
|
| 339 |
+
responseJsonSchema: zodToJsonSchema(feedbackSchema),
|
| 340 |
+
},
|
| 341 |
+
});
|
| 342 |
+
|
| 343 |
+
for await (const chunk of stream) {
|
| 344 |
+
console.log(chunk.candidates[0].content.parts[0].text)
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
## Structured outputs with tools
|
| 348 |
+
|
| 349 |
+
| **Preview:** This is a feature available only for the Gemini 3 series models,`gemini-3-pro-preview`and`gemini-3-flash-preview`.
|
| 350 |
+
|
| 351 |
+
Gemini 3 lets you combine Structured Outputs with built-in tools, including[Grounding with Google Search](https://ai.google.dev/gemini-api/docs/google-search),[URL Context](https://ai.google.dev/gemini-api/docs/url-context), and[Code Execution](https://ai.google.dev/gemini-api/docs/code-execution).
|
| 352 |
+
|
| 353 |
+
### Python
|
| 354 |
+
|
| 355 |
+
from google import genai
|
| 356 |
+
from pydantic import BaseModel, Field
|
| 357 |
+
from typing import List
|
| 358 |
+
|
| 359 |
+
class MatchResult(BaseModel):
|
| 360 |
+
winner: str = Field(description="The name of the winner.")
|
| 361 |
+
final_match_score: str = Field(description="The final match score.")
|
| 362 |
+
scorers: List[str] = Field(description="The name of the scorer.")
|
| 363 |
+
|
| 364 |
+
client = genai.Client()
|
| 365 |
+
|
| 366 |
+
response = client.models.generate_content(
|
| 367 |
+
model="gemini-3-pro-preview",
|
| 368 |
+
contents="Search for all details for the latest Euro.",
|
| 369 |
+
config={
|
| 370 |
+
"tools": [
|
| 371 |
+
{"google_search": {}},
|
| 372 |
+
{"url_context": {}}
|
| 373 |
+
],
|
| 374 |
+
"response_mime_type": "application/json",
|
| 375 |
+
"response_json_schema": MatchResult.model_json_schema(),
|
| 376 |
+
},
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
result = MatchResult.model_validate_json(response.text)
|
| 380 |
+
print(result)
|
| 381 |
+
|
| 382 |
+
### JavaScript
|
| 383 |
+
|
| 384 |
+
import { GoogleGenAI } from "@google/genai";
|
| 385 |
+
import { z } from "zod";
|
| 386 |
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
| 387 |
+
|
| 388 |
+
const ai = new GoogleGenAI({});
|
| 389 |
+
|
| 390 |
+
const matchSchema = z.object({
|
| 391 |
+
winner: z.string().describe("The name of the winner."),
|
| 392 |
+
final_match_score: z.string().describe("The final score."),
|
| 393 |
+
scorers: z.array(z.string()).describe("The name of the scorer.")
|
| 394 |
+
});
|
| 395 |
+
|
| 396 |
+
async function run() {
|
| 397 |
+
const response = await ai.models.generateContent({
|
| 398 |
+
model: "gemini-3-pro-preview",
|
| 399 |
+
contents: "Search for all details for the latest Euro.",
|
| 400 |
+
config: {
|
| 401 |
+
tools: [
|
| 402 |
+
{ googleSearch: {} },
|
| 403 |
+
{ urlContext: {} }
|
| 404 |
+
],
|
| 405 |
+
responseMimeType: "application/json",
|
| 406 |
+
responseJsonSchema: zodToJsonSchema(matchSchema),
|
| 407 |
+
},
|
| 408 |
+
});
|
| 409 |
+
|
| 410 |
+
const match = matchSchema.parse(JSON.parse(response.text));
|
| 411 |
+
console.log(match);
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
run();
|
| 415 |
+
|
| 416 |
+
### REST
|
| 417 |
+
|
| 418 |
+
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview:generateContent" \
|
| 419 |
+
-H "x-goog-api-key: $GEMINI_API_KEY" \
|
| 420 |
+
-H 'Content-Type: application/json' \
|
| 421 |
+
-X POST \
|
| 422 |
+
-d '{
|
| 423 |
+
"contents": [{
|
| 424 |
+
"parts": [{"text": "Search for all details for the latest Euro."}]
|
| 425 |
+
}],
|
| 426 |
+
"tools": [
|
| 427 |
+
{"googleSearch": {}},
|
| 428 |
+
{"urlContext": {}}
|
| 429 |
+
],
|
| 430 |
+
"generationConfig": {
|
| 431 |
+
"responseMimeType": "application/json",
|
| 432 |
+
"responseJsonSchema": {
|
| 433 |
+
"type": "object",
|
| 434 |
+
"properties": {
|
| 435 |
+
"winner": {"type": "string", "description": "The name of the winner."},
|
| 436 |
+
"final_match_score": {"type": "string", "description": "The final score."},
|
| 437 |
+
"scorers": {
|
| 438 |
+
"type": "array",
|
| 439 |
+
"items": {"type": "string"},
|
| 440 |
+
"description": "The name of the scorer."
|
| 441 |
+
}
|
| 442 |
+
},
|
| 443 |
+
"required": ["winner", "final_match_score", "scorers"]
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
}'
|
| 447 |
+
|
| 448 |
+
## JSON schema support
|
| 449 |
+
|
| 450 |
+
To generate a JSON object, set the`response_mime_type`in the generation configuration to`application/json`and provide a`response_json_schema`. The schema must be a valid[JSON Schema](https://json-schema.org/)that describes the desired output format.
|
| 451 |
+
|
| 452 |
+
The model will then generate a response that is a syntactically valid JSON string matching the provided schema. When using structured outputs, the model will produce outputs in the same order as the keys in the schema.
|
| 453 |
+
|
| 454 |
+
Gemini's structured output mode supports a subset of the[JSON Schema](https://json-schema.org)specification.
|
| 455 |
+
|
| 456 |
+
The following values of`type`are supported:
|
| 457 |
+
|
| 458 |
+
- **`string`**: For text.
|
| 459 |
+
- **`number`**: For floating-point numbers.
|
| 460 |
+
- **`integer`**: For whole numbers.
|
| 461 |
+
- **`boolean`**: For true/false values.
|
| 462 |
+
- **`object`**: For structured data with key-value pairs.
|
| 463 |
+
- **`array`**: For lists of items.
|
| 464 |
+
- **`null`** : To allow a property to be null, include`"null"`in the type array (e.g.,`{"type": ["string", "null"]}`).
|
| 465 |
+
|
| 466 |
+
These descriptive properties help guide the model:
|
| 467 |
+
|
| 468 |
+
- **`title`**: A short description of a property.
|
| 469 |
+
- **`description`**: A longer and more detailed description of a property.
|
| 470 |
+
|
| 471 |
+
### Type-specific properties
|
| 472 |
+
|
| 473 |
+
**For`object`values:**
|
| 474 |
+
|
| 475 |
+
- **`properties`**: An object where each key is a property name and each value is a schema for that property.
|
| 476 |
+
- **`required`**: An array of strings, listing which properties are mandatory.
|
| 477 |
+
- **`additionalProperties`** : Controls whether properties not listed in`properties`are allowed. Can be a boolean or a schema.
|
| 478 |
+
|
| 479 |
+
**For`string`values:**
|
| 480 |
+
|
| 481 |
+
- **`enum`**: Lists a specific set of possible strings for classification tasks.
|
| 482 |
+
- **`format`** : Specifies a syntax for the string, such as`date-time`,`date`,`time`.
|
| 483 |
+
|
| 484 |
+
**For`number`and`integer`values:**
|
| 485 |
+
|
| 486 |
+
- **`enum`**: Lists a specific set of possible numeric values.
|
| 487 |
+
- **`minimum`**: The minimum inclusive value.
|
| 488 |
+
- **`maximum`**: The maximum inclusive value.
|
| 489 |
+
|
| 490 |
+
**For`array`values:**
|
| 491 |
+
|
| 492 |
+
- **`items`**: Defines the schema for all items in the array.
|
| 493 |
+
- **`prefixItems`**: Defines a list of schemas for the first N items, allowing for tuple-like structures.
|
| 494 |
+
- **`minItems`**: The minimum number of items in the array.
|
| 495 |
+
- **`maxItems`**: The maximum number of items in the array.
|
| 496 |
+
|
| 497 |
+
## Model support
|
| 498 |
+
|
| 499 |
+
The following models support structured output:
|
| 500 |
+
|
| 501 |
+
| Model | Structured Outputs |
|
| 502 |
+
|------------------------|--------------------|
|
| 503 |
+
| Gemini 3 Pro Preview | ✔️ |
|
| 504 |
+
| Gemini 3 Flash Preview | ✔️ |
|
| 505 |
+
| Gemini 2.5 Pro | ✔️ |
|
| 506 |
+
| Gemini 2.5 Flash | ✔️ |
|
| 507 |
+
| Gemini 2.5 Flash-Lite | ✔️ |
|
| 508 |
+
| Gemini 2.0 Flash | ✔️\* |
|
| 509 |
+
| Gemini 2.0 Flash-Lite | ✔️\* |
|
| 510 |
+
|
| 511 |
+
*\* Note that Gemini 2.0 requires an explicit`propertyOrdering`list within the JSON input to define the preferred structure. You can find an example in this[cookbook](https://github.com/google-gemini/cookbook/blob/main/examples/Pdf_structured_outputs_on_invoices_and_forms.ipynb).*
|
| 512 |
+
|
| 513 |
+
## Structured outputs vs. function calling
|
| 514 |
+
|
| 515 |
+
Both structured outputs and function calling use JSON schemas, but they serve different purposes:
|
| 516 |
+
|
| 517 |
+
| Feature | Primary Use Case |
|
| 518 |
+
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
| 519 |
+
| **Structured Outputs** | **Formatting the final response to the user.** Use this when you want the model's*answer*to be in a specific format (e.g., extracting data from a document to save to a database). |
|
| 520 |
+
| **Function Calling** | **Taking action during the conversation.** Use this when the model needs to*ask you*to perform a task (e.g., "get current weather") before it can provide a final answer. |
|
| 521 |
+
|
| 522 |
+
## Best practices
|
| 523 |
+
|
| 524 |
+
- **Clear descriptions:** Use the`description`field in your schema to provide clear instructions to the model about what each property represents. This is crucial for guiding the model's output.
|
| 525 |
+
- **Strong typing:** Use specific types (`integer`,`string`,`enum`) whenever possible. If a parameter has a limited set of valid values, use an`enum`.
|
| 526 |
+
- **Prompt engineering:**Clearly state in your prompt what you want the model to do. For example, "Extract the following information from the text..." or "Classify this feedback according to the provided schema...".
|
| 527 |
+
- **Validation:**While structured output guarantees syntactically correct JSON, it does not guarantee the values are semantically correct. Always validate the final output in your application code before using it.
|
| 528 |
+
- **Error handling:**Implement robust error handling in your application to gracefully manage cases where the model's output, while schema-compliant, may not meet your business logic requirements.
|
| 529 |
+
|
| 530 |
+
## Limitations
|
| 531 |
+
|
| 532 |
+
- **Schema subset:**Not all features of the JSON Schema specification are supported. The model ignores unsupported properties.
|
| 533 |
+
- **Schema complexity:**The API may reject very large or deeply nested schemas. If you encounter errors, try simplifying your schema by shortening property names, reducing nesting, or limiting the number of constraints.
|
| 534 |
+
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
|
docs/GenreMaster.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* ジャンルマスターデータ
|
| 3 |
+
*
|
| 4 |
+
* 中学受験4教科のジャンル分類を定義
|
| 5 |
+
*
|
| 6 |
+
* @version 1.0.0
|
| 7 |
+
* @date 2025-12-07
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
// ============================================================================
|
| 11 |
+
// ジャンルマスターデータ
|
| 12 |
+
// ============================================================================
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* 中学受験4教科のジャンル分類マスターデータ
|
| 16 |
+
* @constant {Object}
|
| 17 |
+
*/
|
| 18 |
+
var GENRE_MASTER = {
|
| 19 |
+
// 国語(8ジャンル)
|
| 20 |
+
jp: {
|
| 21 |
+
subject_id: 'jp',
|
| 22 |
+
subject_name: '国語',
|
| 23 |
+
genres: [
|
| 24 |
+
{
|
| 25 |
+
id: 'JP01',
|
| 26 |
+
name: '漢字・語彙',
|
| 27 |
+
description: '読み書き、四字熟語、慣用句、ことわざ'
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
id: 'JP02',
|
| 31 |
+
name: '文法・言葉のきまり',
|
| 32 |
+
description: '品詞、敬語、文の成分、修飾関係'
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
id: 'JP03',
|
| 36 |
+
name: '物語文読解',
|
| 37 |
+
description: '心情理解、場面把握、人物関係'
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
id: 'JP04',
|
| 41 |
+
name: '説明文・論説文読解',
|
| 42 |
+
description: '要旨、段落構成、筆者の主張'
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
id: 'JP05',
|
| 46 |
+
name: '随筆文読解',
|
| 47 |
+
description: '筆者の体験・感想の読み取り'
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
id: 'JP06',
|
| 51 |
+
name: '詩・韻文',
|
| 52 |
+
description: '詩、短歌、俳句、表現技法'
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
id: 'JP07',
|
| 56 |
+
name: '記述問題',
|
| 57 |
+
description: '理由説明、要約、意見記述'
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
id: 'JP08',
|
| 61 |
+
name: '知識・文学史',
|
| 62 |
+
description: '作家、作品名、文学的常識'
|
| 63 |
+
}
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
|
| 67 |
+
// 算数(10ジャンル)
|
| 68 |
+
math: {
|
| 69 |
+
subject_id: 'math',
|
| 70 |
+
subject_name: '算数',
|
| 71 |
+
genres: [
|
| 72 |
+
{
|
| 73 |
+
id: 'MA01',
|
| 74 |
+
name: '計算',
|
| 75 |
+
description: '四則演算、分数・小数、逆算'
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
id: 'MA02',
|
| 79 |
+
name: '数の性質',
|
| 80 |
+
description: '約数・倍数、素因数分解、規則性'
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
id: 'MA03',
|
| 84 |
+
name: '割合・比',
|
| 85 |
+
description: '割合、比、百分率、歩合'
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
id: 'MA04',
|
| 89 |
+
name: '速さ',
|
| 90 |
+
description: '旅人算、通過算、流水算、時計算'
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
id: 'MA05',
|
| 94 |
+
name: '文章題(その他)',
|
| 95 |
+
description: '濃度、仕事算、ニュートン算、差集め算'
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
id: 'MA06',
|
| 99 |
+
name: '平面図形',
|
| 100 |
+
description: '面積、角度、相似、合同'
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
id: 'MA07',
|
| 104 |
+
name: '立体図形',
|
| 105 |
+
description: '体積、表面積、展開図、切断'
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
id: 'MA08',
|
| 109 |
+
name: '場合の数・確率',
|
| 110 |
+
description: '順列、組み合わせ、確率'
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
id: 'MA09',
|
| 114 |
+
name: 'グラフ・表',
|
| 115 |
+
description: '統計、変化のグラフ、ダイヤグラム'
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
id: 'MA10',
|
| 119 |
+
name: '特殊算',
|
| 120 |
+
description: 'つるかめ算、消去算、過不足算'
|
| 121 |
+
}
|
| 122 |
+
]
|
| 123 |
+
},
|
| 124 |
+
|
| 125 |
+
// 理科(12ジャンル)
|
| 126 |
+
sci: {
|
| 127 |
+
subject_id: 'sci',
|
| 128 |
+
subject_name: '理科',
|
| 129 |
+
genres: [
|
| 130 |
+
{
|
| 131 |
+
id: 'SC01',
|
| 132 |
+
name: '力・運動',
|
| 133 |
+
description: 'てこ、滑車、ばね、浮力、振り子'
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
id: 'SC02',
|
| 137 |
+
name: '電気',
|
| 138 |
+
description: '回路、抵抗、電磁石、発熱'
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
id: 'SC03',
|
| 142 |
+
name: '光・音・熱',
|
| 143 |
+
description: '反射、屈折、レンズ、音の性質'
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
id: 'SC04',
|
| 147 |
+
name: '物質の性質',
|
| 148 |
+
description: '金属、気体、密度、状態変化'
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
id: 'SC05',
|
| 152 |
+
name: '水溶液',
|
| 153 |
+
description: '酸・アルカリ、中和、溶解度'
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
id: 'SC06',
|
| 157 |
+
name: '燃焼・化学変化',
|
| 158 |
+
description: '燃焼、酸化還元、化合'
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
id: 'SC07',
|
| 162 |
+
name: '植物',
|
| 163 |
+
description: 'つくり、光合成、蒸散、分類'
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
id: 'SC08',
|
| 167 |
+
name: '動物',
|
| 168 |
+
description: 'からだのつくり、行動、分類'
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
id: 'SC09',
|
| 172 |
+
name: '人体',
|
| 173 |
+
description: '消化、呼吸、血液循環、感覚器官'
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
id: 'SC10',
|
| 177 |
+
name: '天体',
|
| 178 |
+
description: '太陽、月、星座、地球の運動'
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
id: 'SC11',
|
| 182 |
+
name: '気象',
|
| 183 |
+
description: '天気、気温、湿度、雲、季節風'
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
id: 'SC12',
|
| 187 |
+
name: '地学',
|
| 188 |
+
description: '地層、岩石、火山、地震'
|
| 189 |
+
}
|
| 190 |
+
]
|
| 191 |
+
},
|
| 192 |
+
|
| 193 |
+
// 社会(10ジャンル)
|
| 194 |
+
soc: {
|
| 195 |
+
subject_id: 'soc',
|
| 196 |
+
subject_name: '社会',
|
| 197 |
+
genres: [
|
| 198 |
+
{
|
| 199 |
+
id: 'SO01',
|
| 200 |
+
name: '日本地理(国土・自然)',
|
| 201 |
+
description: '地形、気候、都道府県'
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
id: 'SO02',
|
| 205 |
+
name: '日本地理(産業)',
|
| 206 |
+
description: '農業、工業、水産業、商業'
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
id: 'SO03',
|
| 210 |
+
name: '世界地理',
|
| 211 |
+
description: '大陸、国、貿易、環境問題'
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
id: 'SO04',
|
| 215 |
+
name: '歴史(古代〜平安)',
|
| 216 |
+
description: '旧石器〜平安時代'
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
id: 'SO05',
|
| 220 |
+
name: '歴史(鎌倉〜室町)',
|
| 221 |
+
description: '武士の台頭、文化'
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
id: 'SO06',
|
| 225 |
+
name: '歴史(安土桃山〜江戸)',
|
| 226 |
+
description: '統一、鎖国、元禄・化政文化'
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
id: 'SO07',
|
| 230 |
+
name: '歴史(明治〜現代)',
|
| 231 |
+
description: '近代化、戦争、戦後'
|
| 232 |
+
},
|
| 233 |
+
{
|
| 234 |
+
id: 'SO08',
|
| 235 |
+
name: '公民(政治・憲法)',
|
| 236 |
+
description: '三権分立、選挙、人権'
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
id: 'SO09',
|
| 240 |
+
name: '公民(経済・国際)',
|
| 241 |
+
description: '経済の仕組み、国際機関、SDGs'
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
id: 'SO10',
|
| 245 |
+
name: '時事問題',
|
| 246 |
+
description: '直近1〜2年のニュース'
|
| 247 |
+
}
|
| 248 |
+
]
|
| 249 |
+
}
|
| 250 |
+
};
|
| 251 |
+
|
| 252 |
+
// ============================================================================
|
| 253 |
+
// ヘルパー関数
|
| 254 |
+
// ============================================================================
|
| 255 |
+
|
| 256 |
+
/**
|
| 257 |
+
* ジャンルIDからジャンル情報を取得
|
| 258 |
+
*
|
| 259 |
+
* @param {string} genreId - ジャンルID(例: 'JP01', 'MA05')
|
| 260 |
+
* @returns {Object|null} - ジャンル情報 { id, name, description, subject_id, subject_name } または null
|
| 261 |
+
*
|
| 262 |
+
* @example
|
| 263 |
+
* var genre = getGenreById('JP01');
|
| 264 |
+
* // => { id: 'JP01', name: '漢字・語彙', description: '...', subject_id: 'jp', subject_name: '国語' }
|
| 265 |
+
*/
|
| 266 |
+
function getGenreById(genreId) {
|
| 267 |
+
if (!genreId || typeof genreId !== 'string') {
|
| 268 |
+
return null;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
var upperGenreId = genreId.toUpperCase();
|
| 272 |
+
|
| 273 |
+
// 全教科を検索
|
| 274 |
+
var subjects = ['jp', 'math', 'sci', 'soc'];
|
| 275 |
+
for (var i = 0; i < subjects.length; i++) {
|
| 276 |
+
var subjectId = subjects[i];
|
| 277 |
+
var subjectData = GENRE_MASTER[subjectId];
|
| 278 |
+
var genres = subjectData.genres;
|
| 279 |
+
|
| 280 |
+
for (var j = 0; j < genres.length; j++) {
|
| 281 |
+
var genre = genres[j];
|
| 282 |
+
if (genre.id === upperGenreId) {
|
| 283 |
+
// ジャンル情報に教科情報を追加して返却
|
| 284 |
+
return {
|
| 285 |
+
id: genre.id,
|
| 286 |
+
name: genre.name,
|
| 287 |
+
description: genre.description,
|
| 288 |
+
subject_id: subjectData.subject_id,
|
| 289 |
+
subject_name: subjectData.subject_name
|
| 290 |
+
};
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
return null;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
/**
|
| 299 |
+
* 教科のジャンル一覧を取得
|
| 300 |
+
*
|
| 301 |
+
* @param {string} subjectId - 教科ID(jp, math, sci, soc)
|
| 302 |
+
* @returns {Array} - ジャンル配列(見つからない場合は空配列)
|
| 303 |
+
*
|
| 304 |
+
* @example
|
| 305 |
+
* var genres = getGenresBySubject('jp');
|
| 306 |
+
* // => [{ id: 'JP01', name: '漢字・語彙', ... }, ...]
|
| 307 |
+
*/
|
| 308 |
+
function getGenresBySubject(subjectId) {
|
| 309 |
+
if (!subjectId || typeof subjectId !== 'string') {
|
| 310 |
+
return [];
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
var subjectData = GENRE_MASTER[subjectId.toLowerCase()];
|
| 314 |
+
if (!subjectData) {
|
| 315 |
+
return [];
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
return subjectData.genres;
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
/**
|
| 322 |
+
* 全ジャンル数を取得
|
| 323 |
+
*
|
| 324 |
+
* @returns {number} - 総ジャンル数(40)
|
| 325 |
+
*
|
| 326 |
+
* @example
|
| 327 |
+
* var total = getTotalGenreCount();
|
| 328 |
+
* // => 40
|
| 329 |
+
*/
|
| 330 |
+
function getTotalGenreCount() {
|
| 331 |
+
var count = 0;
|
| 332 |
+
var subjects = ['jp', 'math', 'sci', 'soc'];
|
| 333 |
+
|
| 334 |
+
for (var i = 0; i < subjects.length; i++) {
|
| 335 |
+
var subjectId = subjects[i];
|
| 336 |
+
count += GENRE_MASTER[subjectId].genres.length;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
return count;
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
/**
|
| 343 |
+
* ジャンルIDの検証
|
| 344 |
+
*
|
| 345 |
+
* @param {string} genreId - ジャンルID
|
| 346 |
+
* @returns {boolean} - 有効なジャンルIDかどうか
|
| 347 |
+
*
|
| 348 |
+
* @example
|
| 349 |
+
* isValidGenreId('JP01'); // => true
|
| 350 |
+
* isValidGenreId('XX99'); // => false
|
| 351 |
+
*/
|
| 352 |
+
function isValidGenreId(genreId) {
|
| 353 |
+
return getGenreById(genreId) !== null;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
/**
|
| 357 |
+
* Dify用のジャンルリストを生成(問題生成プロンプト用)
|
| 358 |
+
*
|
| 359 |
+
* @param {string} subjectId - 教科ID(jp, math, sci, soc)
|
| 360 |
+
* @returns {string} - ジャンルリストの文字列(改行区切り)
|
| 361 |
+
*
|
| 362 |
+
* @example
|
| 363 |
+
* var list = getGenreListForDify('jp');
|
| 364 |
+
* // => "JP01: 漢字・語彙(読み書き、四字熟語、慣用句、ことわざ)\n..."
|
| 365 |
+
*/
|
| 366 |
+
function getGenreListForDify(subjectId) {
|
| 367 |
+
var genres = getGenresBySubject(subjectId);
|
| 368 |
+
|
| 369 |
+
if (genres.length === 0) {
|
| 370 |
+
return '';
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
var lines = [];
|
| 374 |
+
for (var i = 0; i < genres.length; i++) {
|
| 375 |
+
var genre = genres[i];
|
| 376 |
+
var line = genre.id + ': ' + genre.name + '(' + genre.description + ')';
|
| 377 |
+
lines.push(line);
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
return lines.join('\n');
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
// ============================================================================
|
| 384 |
+
// テスト関数(GASエディタで実行可能)
|
| 385 |
+
// ============================================================================
|
| 386 |
+
|
| 387 |
+
/**
|
| 388 |
+
* GenreMaster.jsのテスト関数
|
| 389 |
+
* GASエディタで実行して動作確認
|
| 390 |
+
*/
|
| 391 |
+
function testGenreMaster() {
|
| 392 |
+
Logger.log('=== GenreMaster.js テスト開始 ===');
|
| 393 |
+
|
| 394 |
+
// テスト1: ジャンル総数
|
| 395 |
+
var totalCount = getTotalGenreCount();
|
| 396 |
+
Logger.log('テスト1: 総ジャンル数 = ' + totalCount + ' (期待値: 40)');
|
| 397 |
+
|
| 398 |
+
// テスト2: ジャンルID検索
|
| 399 |
+
var genre1 = getGenreById('JP01');
|
| 400 |
+
Logger.log('テスト2: getGenreById("JP01") = ' + JSON.stringify(genre1));
|
| 401 |
+
|
| 402 |
+
var genre2 = getGenreById('MA05');
|
| 403 |
+
Logger.log('テスト2: getGenreById("MA05") = ' + JSON.stringify(genre2));
|
| 404 |
+
|
| 405 |
+
// テスト3: 教科別ジャンル取得
|
| 406 |
+
var jpGenres = getGenresBySubject('jp');
|
| 407 |
+
Logger.log('テスト3: 国語ジャンル数 = ' + jpGenres.length + ' (期待値: 8)');
|
| 408 |
+
|
| 409 |
+
var mathGenres = getGenresBySubject('math');
|
| 410 |
+
Logger.log('テスト3: 算数ジャンル数 = ' + mathGenres.length + ' (期待値: 10)');
|
| 411 |
+
|
| 412 |
+
var sciGenres = getGenresBySubject('sci');
|
| 413 |
+
Logger.log('テスト3: 理科ジャンル数 = ' + sciGenres.length + ' (期待値: 12)');
|
| 414 |
+
|
| 415 |
+
var socGenres = getGenresBySubject('soc');
|
| 416 |
+
Logger.log('テスト3: 社会ジャンル数 = ' + socGenres.length + ' (期待値: 10)');
|
| 417 |
+
|
| 418 |
+
// テスト4: ジャンルID検証
|
| 419 |
+
var valid1 = isValidGenreId('JP01');
|
| 420 |
+
Logger.log('テスト4: isValidGenreId("JP01") = ' + valid1 + ' (期待値: true)');
|
| 421 |
+
|
| 422 |
+
var valid2 = isValidGenreId('XX99');
|
| 423 |
+
Logger.log('テスト4: isValidGenreId("XX99") = ' + valid2 + ' (期待値: false)');
|
| 424 |
+
|
| 425 |
+
// テスト5: Dify用ジャンルリスト生成
|
| 426 |
+
var jpList = getGenreListForDify('jp');
|
| 427 |
+
Logger.log('テスト5: 国語ジャンルリスト(最初の100文字):');
|
| 428 |
+
Logger.log(jpList.substring(0, 100) + '...');
|
| 429 |
+
|
| 430 |
+
Logger.log('=== GenreMaster.js テスト完了 ===');
|
| 431 |
+
}
|
docs/dify-prompts.md
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dify 問題生成LLMプロンプト集
|
| 2 |
+
|
| 3 |
+
**目的**: 4教科の問題生成LLMノードに設定するプロンプト
|
| 4 |
+
**使用方法**: 各教科のプロンプトをコピーして、対応するLLMノードにペースト
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 国語問題生成
|
| 9 |
+
|
| 10 |
+
```
|
| 11 |
+
あなたは中学受験対策の国語問題作成の専門家です。
|
| 12 |
+
|
| 13 |
+
## タスク
|
| 14 |
+
以下の条件に基づき、国語の4択問題を20問生成してください。
|
| 15 |
+
|
| 16 |
+
## ジャンル一覧(必ず以下のジャンルIDを使用)
|
| 17 |
+
- JP01: 漢字・語彙(読み書き、四字熟語、慣用句、ことわざ)
|
| 18 |
+
- JP02: 文法・言葉のきまり(品詞、敬語、文の成分、修飾関係)
|
| 19 |
+
- JP03: 物語文読解(心情理解、場面把握、人物関係)
|
| 20 |
+
- JP04: 説明文・論説文読解(要旨、段落構成、筆者の主張)
|
| 21 |
+
- JP05: 随筆文読解(筆者の体験・感想の読み取り)
|
| 22 |
+
- JP06: 詩・韻文(詩、短歌、俳句、表現技法)
|
| 23 |
+
- JP07: 記述問題(理由説明、要約、意見記述)
|
| 24 |
+
- JP08: 知識・文学史(作家、作品名、文学的常識)
|
| 25 |
+
|
| 26 |
+
## 入力データ
|
| 27 |
+
- **分野別正答率**: {{#1751785054001.statistics#}}
|
| 28 |
+
- **直近20問の履歴**: {{#1751785054001.recent_questions#}}
|
| 29 |
+
|
| 30 |
+
## 条件
|
| 31 |
+
1. **分野構成**: 上記8ジャンルから均等に出題(各2〜3問)
|
| 32 |
+
2. **難易度調整**: 正答率60%未満のジャンルは「基本」レベル、60%以上は「標準」「応用」をミックス
|
| 33 |
+
3. **重複回避**: 直近20問と類似した問題は避ける
|
| 34 |
+
4. **問題形式**: 問題文、4つの選択肢、正解番号(0〜3)、解説を含む
|
| 35 |
+
5. **ジャンルID使用**: categoryフィールドには必ずジャンルID(JP01〜JP08)を使用すること
|
| 36 |
+
|
| 37 |
+
## 出力形式
|
| 38 |
+
**重要**: categoryフィールドには必ずジャンルID(JP01, JP02, JP03, JP04, JP05, JP06, JP07, JP08)を使用してください。
|
| 39 |
+
日本語のジャンル名(「漢字・語彙」等)は使用しないでください。
|
| 40 |
+
|
| 41 |
+
JSON形式で以下の構造で返してください:
|
| 42 |
+
[
|
| 43 |
+
{
|
| 44 |
+
"question_id": "koku_001",
|
| 45 |
+
"category": "JP01",
|
| 46 |
+
"difficulty": "標準",
|
| 47 |
+
"question": "問題文",
|
| 48 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 49 |
+
"correct_answer": 2,
|
| 50 |
+
"explanation": "解説文"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"question_id": "koku_002",
|
| 54 |
+
"category": "JP02",
|
| 55 |
+
"difficulty": "基本",
|
| 56 |
+
"question": "問題文",
|
| 57 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 58 |
+
"correct_answer": 0,
|
| 59 |
+
"explanation": "解説文"
|
| 60 |
+
}
|
| 61 |
+
... (合計20問)
|
| 62 |
+
]
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
## 算数問題生成
|
| 68 |
+
|
| 69 |
+
```
|
| 70 |
+
あなたは中学受験対策の算数問題作成の専門家です。
|
| 71 |
+
|
| 72 |
+
## タスク
|
| 73 |
+
以下の条件に基づき、算数の4択問題を20問生成してください。
|
| 74 |
+
|
| 75 |
+
## ジャンル一覧(必ず以下のジャンルIDを使用)
|
| 76 |
+
- MA01: 計算(四則演算、分数・小数、逆算)
|
| 77 |
+
- MA02: 数の性質(約数・倍数、素因数分解、規則性)
|
| 78 |
+
- MA03: 割合・比(割合、比、百分率、歩合)
|
| 79 |
+
- MA04: 速さ(旅人算、通過算、流水算、時計算)
|
| 80 |
+
- MA05: 文章題(その他)(濃度、仕事算、ニュートン算、差集め算)
|
| 81 |
+
- MA06: 平面図形(面積、角度、相似、合同)
|
| 82 |
+
- MA07: 立体図形(体積、表面積、展開図、切断)
|
| 83 |
+
- MA08: 場合の数・確率(順列、組み合わせ、確率)
|
| 84 |
+
- MA09: グラフ・表(統計、変化のグラフ、ダイヤグラム)
|
| 85 |
+
- MA10: 特殊算(つるかめ算、消去算、過不足算)
|
| 86 |
+
|
| 87 |
+
## 入力データ
|
| 88 |
+
- **分野別正答率**: {{#1751785054001.statistics#}}
|
| 89 |
+
- **直近20問の履歴**: {{#1751785054001.recent_questions#}}
|
| 90 |
+
|
| 91 |
+
## 条件
|
| 92 |
+
1. **分野構成**: 上記10ジャンルから幅広く出題(各1〜3問)
|
| 93 |
+
2. **難易度調整**: 正答率60%未満のジャンルは「基本」レベル、60%以上は「標準」「応用」をミックス
|
| 94 |
+
3. **重複回避**: 直近20問と類似した問題は避ける
|
| 95 |
+
4. **問題形式**: 問題文、4つの選択肢、正解番号(0〜3)、解説を含む
|
| 96 |
+
5. **ジャンルID使用**: categoryフィールドには必ずジャンルID(MA01〜MA10)を使用すること
|
| 97 |
+
|
| 98 |
+
## 出力形式
|
| 99 |
+
**重要**: categoryフィールドには必ずジャンルID(MA01, MA02, MA03, MA04, MA05, MA06, MA07, MA08, MA09, MA10)を使用してください。
|
| 100 |
+
日本語のジャンル名(「平面図形」等)は使用しないでください。
|
| 101 |
+
|
| 102 |
+
JSON形式で以下の構造で返してください:
|
| 103 |
+
[
|
| 104 |
+
{
|
| 105 |
+
"question_id": "san_001",
|
| 106 |
+
"category": "MA01",
|
| 107 |
+
"difficulty": "標準",
|
| 108 |
+
"question": "問題文",
|
| 109 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 110 |
+
"correct_answer": 0,
|
| 111 |
+
"explanation": "解説文"
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"question_id": "san_002",
|
| 115 |
+
"category": "MA06",
|
| 116 |
+
"difficulty": "応用",
|
| 117 |
+
"question": "問題文",
|
| 118 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 119 |
+
"correct_answer": 2,
|
| 120 |
+
"explanation": "解説文"
|
| 121 |
+
}
|
| 122 |
+
... (合計20問)
|
| 123 |
+
]
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
---
|
| 127 |
+
|
| 128 |
+
## 理科問題生成
|
| 129 |
+
|
| 130 |
+
```
|
| 131 |
+
あなたは中学受験対策の理科問題作成の専門家です。
|
| 132 |
+
|
| 133 |
+
## タスク
|
| 134 |
+
以下の条件に基づき、理科の4択問題を20問生成してください。
|
| 135 |
+
|
| 136 |
+
## ジャンル一覧(必ず以下のジャンルIDを使用)
|
| 137 |
+
- SC01: 力・運動(てこ、滑車、ばね、浮力、振り子)
|
| 138 |
+
- SC02: 電気(回路、抵抗、電磁石、発熱)
|
| 139 |
+
- SC03: 光・音・熱(反射、屈折、レンズ、音の性質)
|
| 140 |
+
- SC04: 物質の性質(金属、気体、密度、状態変化)
|
| 141 |
+
- SC05: 水溶液(酸・アルカリ、中和、溶解度)
|
| 142 |
+
- SC06: 燃焼・化学変化(燃焼、酸化還元、化合)
|
| 143 |
+
- SC07: 植物(つくり、光合成、蒸散、分類)
|
| 144 |
+
- SC08: 動物(からだのつくり、行動、分類)
|
| 145 |
+
- SC09: 人体(消化、呼吸、血液循環、感覚器官)
|
| 146 |
+
- SC10: 天体(太陽、月、星座、地球の運動)
|
| 147 |
+
- SC11: 気象(天気、気温、湿度、雲、季節風)
|
| 148 |
+
- SC12: 地学(地層、岩石、火山、地震)
|
| 149 |
+
|
| 150 |
+
## 入力データ
|
| 151 |
+
- **分野別正答率**: {{#1751785054001.statistics#}}
|
| 152 |
+
- **直近20問の履歴**: {{#1751785054001.recent_questions#}}
|
| 153 |
+
|
| 154 |
+
## 条件
|
| 155 |
+
1. **分野構成**: 上記12ジャンルから幅広く出題(各1〜2問)
|
| 156 |
+
2. **難易度調整**: 正答率60%未満のジャンルは「基本」レベル、60%以上は「標準」「応用」をミックス
|
| 157 |
+
3. **重複回避**: 直近20問と類似した問題は避ける
|
| 158 |
+
4. **問題形式**: 問題文、4つの選択肢、正解番号(0〜3)、解説を含む
|
| 159 |
+
5. **ジャンルID使用**: categoryフィールドには必ずジャンルID(SC01〜SC12)を使用すること
|
| 160 |
+
|
| 161 |
+
## 出力形式
|
| 162 |
+
**重要**: categoryフィールドには必ずジャンルID(SC01, SC02, SC03, SC04, SC05, SC06, SC07, SC08, SC09, SC10, SC11, SC12)を使用してください。
|
| 163 |
+
日本語のジャンル名(「力・運動」等)は使用しないでください。
|
| 164 |
+
|
| 165 |
+
JSON形式で以下の構造で返してください:
|
| 166 |
+
[
|
| 167 |
+
{
|
| 168 |
+
"question_id": "rika_001",
|
| 169 |
+
"category": "SC01",
|
| 170 |
+
"difficulty": "標準",
|
| 171 |
+
"question": "問題文",
|
| 172 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 173 |
+
"correct_answer": 1,
|
| 174 |
+
"explanation": "解説文"
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"question_id": "rika_002",
|
| 178 |
+
"category": "SC07",
|
| 179 |
+
"difficulty": "基本",
|
| 180 |
+
"question": "問題文",
|
| 181 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 182 |
+
"correct_answer": 3,
|
| 183 |
+
"explanation": "解説文"
|
| 184 |
+
}
|
| 185 |
+
... (合計20問)
|
| 186 |
+
]
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
---
|
| 190 |
+
|
| 191 |
+
## 社会問題生成
|
| 192 |
+
|
| 193 |
+
```
|
| 194 |
+
あなたは中学受験対策の社会問題作成の専門家です。
|
| 195 |
+
|
| 196 |
+
## タスク
|
| 197 |
+
以下の条件に基づき、社会の4択問題を20問生成してください。
|
| 198 |
+
|
| 199 |
+
## ジャンル一覧(必ず以下のジャンルIDを使用)
|
| 200 |
+
- SO01: 日本地理(国土・自然)(地形、気候、都道府県)
|
| 201 |
+
- SO02: 日本地理(産業)(農業、工業、水産業、商業)
|
| 202 |
+
- SO03: 世界地理(大陸、国、貿易、環境問題)
|
| 203 |
+
- SO04: 歴史(古代〜平安)(旧石器〜平安時代)
|
| 204 |
+
- SO05: 歴史(鎌倉〜室町)(武士の台頭、文化)
|
| 205 |
+
- SO06: 歴史(安土桃山〜江戸)(統一、鎖国、元禄・化政文化)
|
| 206 |
+
- SO07: 歴史(明治〜現代)(近代化、戦争、戦後)
|
| 207 |
+
- SO08: 公民(政治・憲法)(三権分立、選挙、人権)
|
| 208 |
+
- SO09: 公民(経済・国際)(経済の仕組み、国際機関、SDGs)
|
| 209 |
+
- SO10: 時事問題(直近1〜2年のニュース)
|
| 210 |
+
|
| 211 |
+
## 入力データ
|
| 212 |
+
- **分野別正答率**: {{#1751785054001.statistics#}}
|
| 213 |
+
- **直近20問の履歴**: {{#1751785054001.recent_questions#}}
|
| 214 |
+
|
| 215 |
+
## 条件
|
| 216 |
+
1. **分野構成**: 上記10ジャンルから幅広く出題(各1〜3問)
|
| 217 |
+
2. **難易度調整**: 正答率60%未満のジャンルは「基本」レベル、60%以上は「標準」「応用」をミックス
|
| 218 |
+
3. **重複回避**: 直近20問と類似した問題は避ける
|
| 219 |
+
4. **問題形式**: 問題文、4つの選択肢、正解番号(0〜3)、解説を含む
|
| 220 |
+
5. **ジャンルID使用**: categoryフィールドには必ずジャンルID(SO01〜SO10)を使用すること
|
| 221 |
+
|
| 222 |
+
## 出力形式
|
| 223 |
+
**重要**: categoryフィールドには必ずジャンルID(SO01, SO02, SO03, SO04, SO05, SO06, SO07, SO08, SO09, SO10)を使用してください。
|
| 224 |
+
日本語のジャンル名(「日本地理(国土・自然)」等)は使用しないでください。
|
| 225 |
+
|
| 226 |
+
JSON形式で以下の構造で返してください:
|
| 227 |
+
[
|
| 228 |
+
{
|
| 229 |
+
"question_id": "soci_001",
|
| 230 |
+
"category": "SO01",
|
| 231 |
+
"difficulty": "標準",
|
| 232 |
+
"question": "問題文",
|
| 233 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選択肢4"],
|
| 234 |
+
"correct_answer": 2,
|
| 235 |
+
"explanation": "解説文"
|
| 236 |
+
},
|
| 237 |
+
{
|
| 238 |
+
"question_id": "soci_002",
|
| 239 |
+
"category": "SO08",
|
| 240 |
+
"difficulty": "応用",
|
| 241 |
+
"question": "問題文",
|
| 242 |
+
"choices": ["選択肢1", "選択肢2", "選択肢3", "選���肢4"],
|
| 243 |
+
"correct_answer": 1,
|
| 244 |
+
"explanation": "解説文"
|
| 245 |
+
}
|
| 246 |
+
... (合計20問)
|
| 247 |
+
]
|
| 248 |
+
```
|
| 249 |
+
|
| 250 |
+
---
|
| 251 |
+
|
| 252 |
+
## ジャンルID一覧(参照用)
|
| 253 |
+
|
| 254 |
+
| 教科 | ジャンルID | ジャンル名 |
|
| 255 |
+
|------|-----------|-----------|
|
| 256 |
+
| **国語** | JP01 | 漢字・語彙 |
|
| 257 |
+
| | JP02 | 文法・言葉のきまり |
|
| 258 |
+
| | JP03 | 物語文読解 |
|
| 259 |
+
| | JP04 | 説明文・論説文読解 |
|
| 260 |
+
| | JP05 | 随筆文読解 |
|
| 261 |
+
| | JP06 | 詩・韻文 |
|
| 262 |
+
| | JP07 | 記述問題 |
|
| 263 |
+
| | JP08 | 知識・文学史 |
|
| 264 |
+
| **算数** | MA01 | 計算 |
|
| 265 |
+
| | MA02 | 数の性質 |
|
| 266 |
+
| | MA03 | 割合・比 |
|
| 267 |
+
| | MA04 | 速さ |
|
| 268 |
+
| | MA05 | 文章題(その他) |
|
| 269 |
+
| | MA06 | 平面図形 |
|
| 270 |
+
| | MA07 | 立体図形 |
|
| 271 |
+
| | MA08 | 場合の数・確率 |
|
| 272 |
+
| | MA09 | グラフ・表 |
|
| 273 |
+
| | MA10 | 特殊算 |
|
| 274 |
+
| **理科** | SC01 | 力・運動 |
|
| 275 |
+
| | SC02 | 電気 |
|
| 276 |
+
| | SC03 | 光・音・熱 |
|
| 277 |
+
| | SC04 | 物質の性質 |
|
| 278 |
+
| | SC05 | 水溶液 |
|
| 279 |
+
| | SC06 | 燃焼・化学変化 |
|
| 280 |
+
| | SC07 | 植物 |
|
| 281 |
+
| | SC08 | 動物 |
|
| 282 |
+
| | SC09 | 人体 |
|
| 283 |
+
| | SC10 | 天体 |
|
| 284 |
+
| | SC11 | 気象 |
|
| 285 |
+
| | SC12 | 地学 |
|
| 286 |
+
| **社会** | SO01 | 日本地理(国土・自然) |
|
| 287 |
+
| | SO02 | 日本地理(産業) |
|
| 288 |
+
| | SO03 | 世界地理 |
|
| 289 |
+
| | SO04 | 歴史(古代〜平安) |
|
| 290 |
+
| | SO05 | 歴史(鎌倉〜室町) |
|
| 291 |
+
| | SO06 | 歴史(安土桃山〜江戸) |
|
| 292 |
+
| | SO07 | 歴史(明治〜現代) |
|
| 293 |
+
| | SO08 | 公民(政治・憲法) |
|
| 294 |
+
| | SO09 | 公民(経済・国際) |
|
| 295 |
+
| | SO10 | 時事問題 |
|
| 296 |
+
|
| 297 |
+
---
|
| 298 |
+
|
| 299 |
+
**注意**: `{{#1751785054001.statistics#}}` と `{{#1751785054001.recent_questions#}}` は、Difyワークフロー内の変数参照です。実際のノードIDに合わせて調整してください。
|
gas/.clasp.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"scriptId": "1rBj6xUhat3KZ1Iy9WXLdMiRh4CTKqCJHK3G149plkLJsPeuGFa5DuyGX",
|
| 3 |
+
"rootDir": "."
|
| 4 |
+
}
|
gas/Code.js
CHANGED
|
@@ -1468,9 +1468,9 @@ function getSessionResults(sessionId) {
|
|
| 1468 |
|
| 1469 |
if (answerSessionId === sessionId) {
|
| 1470 |
const questionId = row[2]; // question_id
|
| 1471 |
-
const userAnswer = row[
|
| 1472 |
-
const isCorrect = row[
|
| 1473 |
-
const timeTaken = row[
|
| 1474 |
|
| 1475 |
// 対応する問題データを取得
|
| 1476 |
const question = questionsMap[questionId];
|
|
|
|
| 1468 |
|
| 1469 |
if (answerSessionId === sessionId) {
|
| 1470 |
const questionId = row[2]; // question_id
|
| 1471 |
+
const userAnswer = row[5]; // user_answer (F列)
|
| 1472 |
+
const isCorrect = row[7]; // is_correct (H列)
|
| 1473 |
+
const timeTaken = row[8]; // time_spent (I列)
|
| 1474 |
|
| 1475 |
// 対応する問題データを取得
|
| 1476 |
const question = questionsMap[questionId];
|
gas/DifyService.js
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Dify APIサービス
|
| 3 |
+
*
|
| 4 |
+
* Dify Cloudのワークフロー実行APIを呼び出すラッパー
|
| 5 |
+
*
|
| 6 |
+
* @version 1.0.0
|
| 7 |
+
* @date 2025-12-04
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
// ============================================================================
|
| 11 |
+
// 定数定義
|
| 12 |
+
// ============================================================================
|
| 13 |
+
|
| 14 |
+
const DIFY_CONFIG = {
|
| 15 |
+
TIMEOUT: 150000, // 150秒(RAG Knowledge Base利用による処理時間増加対応)
|
| 16 |
+
RESPONSE_MODE: 'blocking',
|
| 17 |
+
USER: 'gas-orchestrator'
|
| 18 |
+
};
|
| 19 |
+
|
| 20 |
+
// 教科マッピング: GAS内部コード → Dify期待値(日本語)
|
| 21 |
+
const SUBJECT_TO_JAPANESE = {
|
| 22 |
+
'jp': '国語',
|
| 23 |
+
'math': '算数',
|
| 24 |
+
'sci': '理科',
|
| 25 |
+
'soc': '社会'
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
+
// 教科コード → Dify出力変数名のマッピング
|
| 29 |
+
const SUBJECT_TO_OUTPUT_KEY = {
|
| 30 |
+
'jp': 'kokugo_questions',
|
| 31 |
+
'math': 'sansu_questions',
|
| 32 |
+
'sci': 'rika_questions',
|
| 33 |
+
'soc': 'shakai_questions'
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
// 教科コード → Dify評価出力変数名のマッピング
|
| 37 |
+
const SUBJECT_TO_EVALUATION_KEY = {
|
| 38 |
+
'jp': 'kokugo_evaluation',
|
| 39 |
+
'math': 'sansu_evaluation',
|
| 40 |
+
'sci': 'rika_evaluation',
|
| 41 |
+
'soc': 'shakai_evaluation'
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
/**
|
| 45 |
+
* Difyの評価出力形式をGAS期待形式に正規化
|
| 46 |
+
*
|
| 47 |
+
* Dify出力形式: {"評価": ["コメント1", "コメント2", ...]}
|
| 48 |
+
* GAS期待形式: {advice, strengths[], weaknesses[], recommended_topics[]}
|
| 49 |
+
*
|
| 50 |
+
* @param {Object} difyEvaluation - Difyから返された評価データ
|
| 51 |
+
* @param {string} subject - 教科ID
|
| 52 |
+
* @returns {Object} - 正規化された評価データ
|
| 53 |
+
*/
|
| 54 |
+
function normalizeEvaluationFormat(difyEvaluation, subject) {
|
| 55 |
+
// 既にGAS期待形式の場合はそのまま返す
|
| 56 |
+
if (difyEvaluation.advice !== undefined) {
|
| 57 |
+
Logger.log('[DifyService] Evaluation already in expected format');
|
| 58 |
+
return difyEvaluation;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
// Dify形式 {"評価": [...]} の場合
|
| 62 |
+
if (difyEvaluation['評価'] && Array.isArray(difyEvaluation['評価'])) {
|
| 63 |
+
const comments = difyEvaluation['評価'];
|
| 64 |
+
Logger.log('[DifyService] Converting Dify format to GAS format: ' + comments.length + ' comments');
|
| 65 |
+
|
| 66 |
+
// コメントを構造化
|
| 67 |
+
// 最初のコメントを総合アドバイス、残りを分類
|
| 68 |
+
const advice = comments[0] || '';
|
| 69 |
+
const strengths = [];
|
| 70 |
+
const weaknesses = [];
|
| 71 |
+
const recommended_topics = [];
|
| 72 |
+
|
| 73 |
+
// 2番目以降のコメントを内容で分類
|
| 74 |
+
for (var i = 1; i < comments.length; i++) {
|
| 75 |
+
var comment = comments[i];
|
| 76 |
+
// 改善・弱点を示すキーワードがあればweaknesses
|
| 77 |
+
if (comment.includes('課題') || comment.includes('弱') || comment.includes('不足') ||
|
| 78 |
+
comment.includes('低い') || comment.includes('0%') || comment.includes('改善')) {
|
| 79 |
+
weaknesses.push(comment);
|
| 80 |
+
}
|
| 81 |
+
// 強み・良い点を示すキーワードがあればstrengths
|
| 82 |
+
else if (comment.includes('強') || comment.includes('得意') || comment.includes('高い') ||
|
| 83 |
+
comment.includes('安定') || comment.includes('良')) {
|
| 84 |
+
strengths.push(comment);
|
| 85 |
+
}
|
| 86 |
+
// それ以外はrecommended_topics
|
| 87 |
+
else {
|
| 88 |
+
recommended_topics.push(comment);
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
return {
|
| 93 |
+
advice: advice,
|
| 94 |
+
strengths: strengths,
|
| 95 |
+
weaknesses: weaknesses,
|
| 96 |
+
recommended_topics: recommended_topics
|
| 97 |
+
};
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
// 不明な形式の場合はそのまま返す(ログ出力)
|
| 101 |
+
Logger.log('[DifyService] Unknown evaluation format: ' + JSON.stringify(Object.keys(difyEvaluation)));
|
| 102 |
+
return {
|
| 103 |
+
advice: JSON.stringify(difyEvaluation),
|
| 104 |
+
strengths: [],
|
| 105 |
+
weaknesses: [],
|
| 106 |
+
recommended_topics: []
|
| 107 |
+
};
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
// ============================================================================
|
| 111 |
+
// Dify API呼び出し関数
|
| 112 |
+
// ============================================================================
|
| 113 |
+
|
| 114 |
+
/**
|
| 115 |
+
* Dify APIの環境変数を取得
|
| 116 |
+
*/
|
| 117 |
+
function getDifyCredentials() {
|
| 118 |
+
const properties = PropertiesService.getScriptProperties();
|
| 119 |
+
const apiUrl = properties.getProperty('DIFY_API_URL');
|
| 120 |
+
const apiKey = properties.getProperty('DIFY_API_KEY');
|
| 121 |
+
|
| 122 |
+
if (!apiUrl || !apiKey) {
|
| 123 |
+
throw new Error('Dify API credentials not configured. Run setDifyProperties() first.');
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
return { apiUrl, apiKey };
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
/**
|
| 130 |
+
* 複数のDify APIリクエストを並列実行
|
| 131 |
+
*
|
| 132 |
+
* @param {Array} requestConfigs - リクエスト設定の配列
|
| 133 |
+
* 各要素: { action: string, subject: string, additionalInputs: Object }
|
| 134 |
+
* @returns {Array} - Dify APIレスポンスの配列(リクエスト順序を保持)
|
| 135 |
+
*/
|
| 136 |
+
function callDifyWorkflowBatch(requestConfigs) {
|
| 137 |
+
try {
|
| 138 |
+
const { apiUrl, apiKey } = getDifyCredentials();
|
| 139 |
+
|
| 140 |
+
Logger.log('[DifyService] callDifyWorkflowBatch: Preparing ' + requestConfigs.length + ' parallel requests');
|
| 141 |
+
|
| 142 |
+
// 各リクエストの設定を作成
|
| 143 |
+
const requests = requestConfigs.map((config, index) => {
|
| 144 |
+
const japaneseSubject = SUBJECT_TO_JAPANESE[config.subject] || config.subject;
|
| 145 |
+
|
| 146 |
+
Logger.log('[DifyService] Request ' + index + ': action=' + config.action + ', subject=' + config.subject + ' (' + japaneseSubject + ')');
|
| 147 |
+
|
| 148 |
+
return {
|
| 149 |
+
url: apiUrl,
|
| 150 |
+
method: 'post',
|
| 151 |
+
contentType: 'application/json',
|
| 152 |
+
headers: {
|
| 153 |
+
'Authorization': 'Bearer ' + apiKey
|
| 154 |
+
},
|
| 155 |
+
payload: JSON.stringify({
|
| 156 |
+
inputs: {
|
| 157 |
+
action: config.action,
|
| 158 |
+
subject: japaneseSubject,
|
| 159 |
+
...config.additionalInputs
|
| 160 |
+
},
|
| 161 |
+
response_mode: DIFY_CONFIG.RESPONSE_MODE,
|
| 162 |
+
user: DIFY_CONFIG.USER
|
| 163 |
+
}),
|
| 164 |
+
muteHttpExceptions: true
|
| 165 |
+
};
|
| 166 |
+
});
|
| 167 |
+
|
| 168 |
+
Logger.log('[DifyService] Sending ' + requests.length + ' parallel requests to Dify API...');
|
| 169 |
+
const startTime = new Date().getTime();
|
| 170 |
+
|
| 171 |
+
// 並列実行
|
| 172 |
+
const responses = UrlFetchApp.fetchAll(requests);
|
| 173 |
+
|
| 174 |
+
const endTime = new Date().getTime();
|
| 175 |
+
Logger.log('[DifyService] All requests completed in ' + ((endTime - startTime) / 1000) + ' seconds');
|
| 176 |
+
|
| 177 |
+
// 結果をパースして返却
|
| 178 |
+
return responses.map((response, index) => {
|
| 179 |
+
const responseCode = response.getResponseCode();
|
| 180 |
+
const responseText = response.getContentText();
|
| 181 |
+
|
| 182 |
+
Logger.log('[DifyService] Response ' + index + ': code=' + responseCode);
|
| 183 |
+
|
| 184 |
+
if (responseCode !== 200) {
|
| 185 |
+
Logger.log('[DifyService] Batch request ' + index + ' failed: ' + responseText.substring(0, 200));
|
| 186 |
+
return {
|
| 187 |
+
error: true,
|
| 188 |
+
code: responseCode,
|
| 189 |
+
message: responseText,
|
| 190 |
+
subject: requestConfigs[index].subject
|
| 191 |
+
};
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
try {
|
| 195 |
+
const parsed = JSON.parse(responseText);
|
| 196 |
+
parsed._subject = requestConfigs[index].subject; // 後で識別するため
|
| 197 |
+
return parsed;
|
| 198 |
+
} catch (parseError) {
|
| 199 |
+
Logger.log('[DifyService] JSON parse error for request ' + index + ': ' + parseError.toString());
|
| 200 |
+
return {
|
| 201 |
+
error: true,
|
| 202 |
+
code: responseCode,
|
| 203 |
+
message: 'JSON parse error: ' + parseError.toString(),
|
| 204 |
+
subject: requestConfigs[index].subject
|
| 205 |
+
};
|
| 206 |
+
}
|
| 207 |
+
});
|
| 208 |
+
|
| 209 |
+
} catch (error) {
|
| 210 |
+
Logger.log('[DifyService] callDifyWorkflowBatch error: ' + error.toString());
|
| 211 |
+
throw error;
|
| 212 |
+
}
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
/**
|
| 216 |
+
* Dify Workflowを実行
|
| 217 |
+
*
|
| 218 |
+
* @param {string} action - アクション(generate_questions, generate_evaluation)
|
| 219 |
+
* @param {string} subject - 教科ID(jp, math, sci, soc)
|
| 220 |
+
* @param {Object} additionalInputs - 追加の入力パラメータ(統計情報など)
|
| 221 |
+
* @returns {Object} - Dify APIレスポンス
|
| 222 |
+
*/
|
| 223 |
+
function callDifyWorkflow(action, subject, additionalInputs = {}) {
|
| 224 |
+
try {
|
| 225 |
+
const { apiUrl, apiKey } = getDifyCredentials();
|
| 226 |
+
|
| 227 |
+
// GASの教科コード(jp, math, sci, soc)を日本語に変換
|
| 228 |
+
const japaneseSubject = SUBJECT_TO_JAPANESE[subject] || subject;
|
| 229 |
+
|
| 230 |
+
Logger.log('[DifyService] callDifyWorkflow: action=' + action + ', subject=' + subject + ' (' + japaneseSubject + ')');
|
| 231 |
+
|
| 232 |
+
// リクエストペイロード(subjectは日本語に変換して送信)
|
| 233 |
+
const payload = {
|
| 234 |
+
inputs: {
|
| 235 |
+
action: action,
|
| 236 |
+
subject: japaneseSubject,
|
| 237 |
+
...additionalInputs
|
| 238 |
+
},
|
| 239 |
+
response_mode: DIFY_CONFIG.RESPONSE_MODE,
|
| 240 |
+
user: DIFY_CONFIG.USER
|
| 241 |
+
};
|
| 242 |
+
|
| 243 |
+
// HTTPリクエストオプション
|
| 244 |
+
const options = {
|
| 245 |
+
method: 'post',
|
| 246 |
+
contentType: 'application/json',
|
| 247 |
+
headers: {
|
| 248 |
+
'Authorization': 'Bearer ' + apiKey
|
| 249 |
+
},
|
| 250 |
+
payload: JSON.stringify(payload),
|
| 251 |
+
muteHttpExceptions: true
|
| 252 |
+
};
|
| 253 |
+
|
| 254 |
+
Logger.log('[DifyService] Sending request to Dify API...');
|
| 255 |
+
const response = UrlFetchApp.fetch(apiUrl, options);
|
| 256 |
+
const responseCode = response.getResponseCode();
|
| 257 |
+
const responseText = response.getContentText();
|
| 258 |
+
|
| 259 |
+
Logger.log('[DifyService] Response code: ' + responseCode);
|
| 260 |
+
|
| 261 |
+
if (responseCode !== 200) {
|
| 262 |
+
Logger.log('[DifyService] Error response: ' + responseText);
|
| 263 |
+
throw new Error('Dify API error: ' + responseCode + ' - ' + responseText);
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
const responseData = JSON.parse(responseText);
|
| 267 |
+
Logger.log('[DifyService] Success: workflow_run_id=' + (responseData.workflow_run_id || 'N/A'));
|
| 268 |
+
|
| 269 |
+
return responseData;
|
| 270 |
+
|
| 271 |
+
} catch (error) {
|
| 272 |
+
Logger.log('[DifyService] Error: ' + error.toString());
|
| 273 |
+
throw error;
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
/**
|
| 278 |
+
* 問題生成APIを呼び出し
|
| 279 |
+
*
|
| 280 |
+
* @param {string} subject - 教科ID
|
| 281 |
+
* @param {Object} statistics - ユーザー統計(オプション)
|
| 282 |
+
* @param {Array} recentQuestions - 直近の問題リスト(オプション)
|
| 283 |
+
* @returns {Array} - 生成された問題配列
|
| 284 |
+
*/
|
| 285 |
+
function generateQuestionsFromDify(subject, statistics = {}, recentQuestions = []) {
|
| 286 |
+
try {
|
| 287 |
+
Logger.log('[DifyService] generateQuestionsFromDify: subject=' + subject);
|
| 288 |
+
|
| 289 |
+
const response = callDifyWorkflow('generate_questions', subject, {
|
| 290 |
+
statistics: JSON.stringify(statistics),
|
| 291 |
+
recent_questions: JSON.stringify(recentQuestions)
|
| 292 |
+
});
|
| 293 |
+
|
| 294 |
+
// Difyレスポンスから問題データを抽出
|
| 295 |
+
// response.data.outputs から教科別の出力変数を取得
|
| 296 |
+
if (response.data && response.data.outputs) {
|
| 297 |
+
const outputs = response.data.outputs;
|
| 298 |
+
|
| 299 |
+
// エラーレスポンスチェック
|
| 300 |
+
if (outputs.action_error) {
|
| 301 |
+
throw new Error('Dify action error: ' + outputs.action_error);
|
| 302 |
+
}
|
| 303 |
+
if (outputs.subject_error_questions) {
|
| 304 |
+
throw new Error('Dify subject error: ' + outputs.subject_error_questions);
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
// 教科別の出力変数名を取得(例: kokugo_questions, sansu_questions)
|
| 308 |
+
const outputKey = SUBJECT_TO_OUTPUT_KEY[subject];
|
| 309 |
+
if (!outputKey) {
|
| 310 |
+
throw new Error('Invalid subject code: ' + subject);
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
Logger.log('[DifyService] Looking for output key: ' + outputKey);
|
| 314 |
+
|
| 315 |
+
// 教科別の出力変数から問題データを取得
|
| 316 |
+
if (outputs[outputKey]) {
|
| 317 |
+
const questionsData = outputs[outputKey];
|
| 318 |
+
|
| 319 |
+
// JSON文字列の場合はパース
|
| 320 |
+
if (typeof questionsData === 'string') {
|
| 321 |
+
Logger.log('[DifyService] Parsing JSON string from ' + outputKey);
|
| 322 |
+
const parsed = JSON.parse(questionsData);
|
| 323 |
+
|
| 324 |
+
// { questions: [...] } 形式の場合
|
| 325 |
+
if (parsed.questions && Array.isArray(parsed.questions)) {
|
| 326 |
+
Logger.log('[DifyService] Successfully parsed ' + parsed.questions.length + ' questions');
|
| 327 |
+
return parsed.questions;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
// 直接配列の場合
|
| 331 |
+
if (Array.isArray(parsed)) {
|
| 332 |
+
Logger.log('[DifyService] Successfully parsed ' + parsed.length + ' questions (array format)');
|
| 333 |
+
return parsed;
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
// 既にオブジェクト/配列の場合
|
| 338 |
+
if (Array.isArray(questionsData)) {
|
| 339 |
+
Logger.log('[DifyService] Got ' + questionsData.length + ' questions (array format)');
|
| 340 |
+
return questionsData;
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
if (questionsData.questions && Array.isArray(questionsData.questions)) {
|
| 344 |
+
Logger.log('[DifyService] Got ' + questionsData.questions.length + ' questions (object format)');
|
| 345 |
+
return questionsData.questions;
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
Logger.log('[DifyService] Output key "' + outputKey + '" not found in outputs: ' + JSON.stringify(Object.keys(outputs)));
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
throw new Error('Invalid response format from Dify: questions data not found');
|
| 353 |
+
|
| 354 |
+
} catch (error) {
|
| 355 |
+
Logger.log('[DifyService] generateQuestionsFromDify error: ' + error.toString());
|
| 356 |
+
throw error;
|
| 357 |
+
}
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
/**
|
| 361 |
+
* 評価生成APIを呼び出し
|
| 362 |
+
*
|
| 363 |
+
* @param {string} subject - 教科ID(jp, math, sci, soc, または 'overall')
|
| 364 |
+
* @param {Object} statistics - ユーザー統計(教科別正答率など)
|
| 365 |
+
* @param {Array} results - 解答結果配列(各問題の正誤結果)
|
| 366 |
+
* @param {Object} subjectEvaluations - 教科別評価(overallの場合のみ使用、オプション)
|
| 367 |
+
* @returns {Object} - 生成された評価
|
| 368 |
+
*
|
| 369 |
+
* レスポンスフォーマット:
|
| 370 |
+
* 教科別評価: { subject, advice, strengths[], weaknesses[], recommended_topics[] }
|
| 371 |
+
* 全体評価: { overall_advice, strengths[], weaknesses[], next_steps[] }
|
| 372 |
+
*/
|
| 373 |
+
function generateEvaluationFromDify(subject, statistics, results, subjectEvaluations = null) {
|
| 374 |
+
try {
|
| 375 |
+
Logger.log('[DifyService] generateEvaluationFromDify: subject=' + subject);
|
| 376 |
+
|
| 377 |
+
// 追加の入力パラメータ
|
| 378 |
+
const additionalInputs = {
|
| 379 |
+
statistics: JSON.stringify(statistics),
|
| 380 |
+
results: JSON.stringify(results)
|
| 381 |
+
};
|
| 382 |
+
|
| 383 |
+
// 全体評価の場合、教科別評価も渡す
|
| 384 |
+
if (subject === 'overall' && subjectEvaluations) {
|
| 385 |
+
Logger.log('[DifyService] Adding subject_evaluations to overall evaluation');
|
| 386 |
+
additionalInputs.subject_evaluations = JSON.stringify(subjectEvaluations);
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
const response = callDifyWorkflow('generate_evaluation', subject, additionalInputs);
|
| 390 |
+
|
| 391 |
+
// Difyレスポンスから評価データを抽出
|
| 392 |
+
if (response.data && response.data.outputs) {
|
| 393 |
+
const outputs = response.data.outputs;
|
| 394 |
+
|
| 395 |
+
// エラーレスポンスチェック
|
| 396 |
+
if (outputs.action_error) {
|
| 397 |
+
throw new Error('Dify action error: ' + outputs.action_error);
|
| 398 |
+
}
|
| 399 |
+
if (outputs.subject_error_evaluation) {
|
| 400 |
+
throw new Error('Dify subject error: ' + outputs.subject_error_evaluation);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
// 全体評価の場合
|
| 404 |
+
if (subject === 'overall') {
|
| 405 |
+
if (outputs.overall_evaluation) {
|
| 406 |
+
const evaluationData = outputs.overall_evaluation;
|
| 407 |
+
|
| 408 |
+
// JSON文字列の場合はパース
|
| 409 |
+
if (typeof evaluationData === 'string') {
|
| 410 |
+
Logger.log('[DifyService] Parsing overall_evaluation JSON string');
|
| 411 |
+
const parsed = JSON.parse(evaluationData);
|
| 412 |
+
Logger.log('[DifyService] Overall evaluation generated successfully');
|
| 413 |
+
return parsed;
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
// 既にオブジェクトの場合
|
| 417 |
+
Logger.log('[DifyService] Overall evaluation generated successfully (object format)');
|
| 418 |
+
return evaluationData;
|
| 419 |
+
}
|
| 420 |
+
} else {
|
| 421 |
+
// 教科別評価の場合
|
| 422 |
+
const evaluationKey = SUBJECT_TO_EVALUATION_KEY[subject];
|
| 423 |
+
if (!evaluationKey) {
|
| 424 |
+
throw new Error('Invalid subject code for evaluation: ' + subject);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
Logger.log('[DifyService] Looking for evaluation key: ' + evaluationKey);
|
| 428 |
+
|
| 429 |
+
if (outputs[evaluationKey]) {
|
| 430 |
+
const evaluationData = outputs[evaluationKey];
|
| 431 |
+
let parsed;
|
| 432 |
+
|
| 433 |
+
// JSON文字列の場合はパース
|
| 434 |
+
if (typeof evaluationData === 'string') {
|
| 435 |
+
Logger.log('[DifyService] Parsing JSON string from ' + evaluationKey);
|
| 436 |
+
parsed = JSON.parse(evaluationData);
|
| 437 |
+
} else {
|
| 438 |
+
// 既にオブジェクトの場合
|
| 439 |
+
parsed = evaluationData;
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
// Difyの出力形式 {"評価": [...]} をGAS期待形式に変換
|
| 443 |
+
const normalized = normalizeEvaluationFormat(parsed, subject);
|
| 444 |
+
Logger.log('[DifyService] Evaluation generated successfully for ' + subject);
|
| 445 |
+
return normalized;
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
Logger.log('[DifyService] Evaluation key "' + evaluationKey + '" not found in outputs: ' + JSON.stringify(Object.keys(outputs)));
|
| 449 |
+
}
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
throw new Error('Invalid response format from Dify: evaluation data not found');
|
| 453 |
+
|
| 454 |
+
} catch (error) {
|
| 455 |
+
Logger.log('[DifyService] generateEvaluationFromDify error: ' + error.toString());
|
| 456 |
+
throw error;
|
| 457 |
+
}
|
| 458 |
+
}
|
gas/GenreMaster.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* ジャンルマスターデータ
|
| 3 |
+
*
|
| 4 |
+
* 中学受験4教科のジャンル分類を定義
|
| 5 |
+
*
|
| 6 |
+
* @version 1.0.0
|
| 7 |
+
* @date 2025-12-07
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
// ============================================================================
|
| 11 |
+
// ジャンルマスターデータ
|
| 12 |
+
// ============================================================================
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* 中学受験4教科のジャンル分類マスターデータ
|
| 16 |
+
* @constant {Object}
|
| 17 |
+
*/
|
| 18 |
+
var GENRE_MASTER = {
|
| 19 |
+
// 国語(8ジャンル)
|
| 20 |
+
jp: {
|
| 21 |
+
subject_id: 'jp',
|
| 22 |
+
subject_name: '国語',
|
| 23 |
+
genres: [
|
| 24 |
+
{
|
| 25 |
+
id: 'JP01',
|
| 26 |
+
name: '漢字・語彙',
|
| 27 |
+
description: '読み書き、四字熟語、慣用句、ことわざ'
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
id: 'JP02',
|
| 31 |
+
name: '文法・言葉のきまり',
|
| 32 |
+
description: '品詞、敬語、文の成分、修飾関係'
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
id: 'JP03',
|
| 36 |
+
name: '物語文読解',
|
| 37 |
+
description: '心情理解、場面把握、人物関係'
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
id: 'JP04',
|
| 41 |
+
name: '説明文・論説文読解',
|
| 42 |
+
description: '要旨、段落構成、筆者の主張'
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
id: 'JP05',
|
| 46 |
+
name: '随筆文読解',
|
| 47 |
+
description: '筆者の体験・感想の読み取り'
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
id: 'JP06',
|
| 51 |
+
name: '詩・韻文',
|
| 52 |
+
description: '詩、短歌、俳句、表現技法'
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
id: 'JP07',
|
| 56 |
+
name: '記述問題',
|
| 57 |
+
description: '理由説明、要約、意見記述'
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
id: 'JP08',
|
| 61 |
+
name: '知識・文学史',
|
| 62 |
+
description: '作家、作品名、文学的常識'
|
| 63 |
+
}
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
|
| 67 |
+
// 算数(10ジャンル)
|
| 68 |
+
math: {
|
| 69 |
+
subject_id: 'math',
|
| 70 |
+
subject_name: '算数',
|
| 71 |
+
genres: [
|
| 72 |
+
{
|
| 73 |
+
id: 'MA01',
|
| 74 |
+
name: '計算',
|
| 75 |
+
description: '四則演算、分数・小数、逆算'
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
id: 'MA02',
|
| 79 |
+
name: '数の性質',
|
| 80 |
+
description: '約数・倍数、素因数分解、規則性'
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
id: 'MA03',
|
| 84 |
+
name: '割合・比',
|
| 85 |
+
description: '割合、比、百分率、歩合'
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
id: 'MA04',
|
| 89 |
+
name: '速さ',
|
| 90 |
+
description: '旅人算、通過算、流水算、時計算'
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
id: 'MA05',
|
| 94 |
+
name: '文章題(その他)',
|
| 95 |
+
description: '濃度、仕事算、ニュートン算、差集め算'
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
id: 'MA06',
|
| 99 |
+
name: '平面図形',
|
| 100 |
+
description: '面積、角度、相似、合同'
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
id: 'MA07',
|
| 104 |
+
name: '立体図形',
|
| 105 |
+
description: '体積、表面積、展開図、切断'
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
id: 'MA08',
|
| 109 |
+
name: '場合の数・確率',
|
| 110 |
+
description: '順列、組み合わせ、確率'
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
id: 'MA09',
|
| 114 |
+
name: 'グラフ・表',
|
| 115 |
+
description: '統計、変化のグラフ、ダイヤグラム'
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
id: 'MA10',
|
| 119 |
+
name: '特殊算',
|
| 120 |
+
description: 'つるかめ算、消去算、過不足算'
|
| 121 |
+
}
|
| 122 |
+
]
|
| 123 |
+
},
|
| 124 |
+
|
| 125 |
+
// 理科(12ジャンル)
|
| 126 |
+
sci: {
|
| 127 |
+
subject_id: 'sci',
|
| 128 |
+
subject_name: '理科',
|
| 129 |
+
genres: [
|
| 130 |
+
{
|
| 131 |
+
id: 'SC01',
|
| 132 |
+
name: '力・運動',
|
| 133 |
+
description: 'てこ、滑車、ばね、浮力、振り子'
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
id: 'SC02',
|
| 137 |
+
name: '電気',
|
| 138 |
+
description: '回路、抵抗、電磁石、発熱'
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
id: 'SC03',
|
| 142 |
+
name: '光・音・熱',
|
| 143 |
+
description: '反射、屈折、レンズ、音の性質'
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
id: 'SC04',
|
| 147 |
+
name: '物質の性質',
|
| 148 |
+
description: '金属、気体、密度、状態変化'
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
id: 'SC05',
|
| 152 |
+
name: '水溶液',
|
| 153 |
+
description: '酸・アルカリ、中和、溶解度'
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
id: 'SC06',
|
| 157 |
+
name: '燃焼・化学変化',
|
| 158 |
+
description: '燃焼、酸化還元、化合'
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
id: 'SC07',
|
| 162 |
+
name: '植物',
|
| 163 |
+
description: 'つくり、光合成、蒸散、分類'
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
id: 'SC08',
|
| 167 |
+
name: '動物',
|
| 168 |
+
description: 'からだのつくり、行動、分類'
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
id: 'SC09',
|
| 172 |
+
name: '人体',
|
| 173 |
+
description: '消化、呼吸、血液循環、感覚器官'
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
id: 'SC10',
|
| 177 |
+
name: '天体',
|
| 178 |
+
description: '太陽、月、星座、地球の運動'
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
id: 'SC11',
|
| 182 |
+
name: '気象',
|
| 183 |
+
description: '天気、気温、湿度、雲、季節風'
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
id: 'SC12',
|
| 187 |
+
name: '地学',
|
| 188 |
+
description: '地層、岩石、火山、地震'
|
| 189 |
+
}
|
| 190 |
+
]
|
| 191 |
+
},
|
| 192 |
+
|
| 193 |
+
// 社会(10ジャンル)
|
| 194 |
+
soc: {
|
| 195 |
+
subject_id: 'soc',
|
| 196 |
+
subject_name: '社会',
|
| 197 |
+
genres: [
|
| 198 |
+
{
|
| 199 |
+
id: 'SO01',
|
| 200 |
+
name: '日本地理(国土・自然)',
|
| 201 |
+
description: '地形、気候、都道府県'
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
id: 'SO02',
|
| 205 |
+
name: '日本地理(産業)',
|
| 206 |
+
description: '農業、工業、水産業、商業'
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
id: 'SO03',
|
| 210 |
+
name: '世界地理',
|
| 211 |
+
description: '大陸、国、貿易、環境問題'
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
id: 'SO04',
|
| 215 |
+
name: '歴史(古代〜平安)',
|
| 216 |
+
description: '旧石器〜平安時代'
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
id: 'SO05',
|
| 220 |
+
name: '歴史(鎌倉〜室町)',
|
| 221 |
+
description: '武士の台頭、文化'
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
id: 'SO06',
|
| 225 |
+
name: '歴史(安土桃山〜江戸)',
|
| 226 |
+
description: '統一、鎖国、元禄・化政文化'
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
id: 'SO07',
|
| 230 |
+
name: '歴史(明治〜現代)',
|
| 231 |
+
description: '近代化、戦争、戦後'
|
| 232 |
+
},
|
| 233 |
+
{
|
| 234 |
+
id: 'SO08',
|
| 235 |
+
name: '公民(政治・憲法)',
|
| 236 |
+
description: '三権分立、選挙、人権'
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
id: 'SO09',
|
| 240 |
+
name: '公民(経済・国際)',
|
| 241 |
+
description: '経済の仕組み、国際機関、SDGs'
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
id: 'SO10',
|
| 245 |
+
name: '時事問題',
|
| 246 |
+
description: '直近1〜2年のニュース'
|
| 247 |
+
}
|
| 248 |
+
]
|
| 249 |
+
}
|
| 250 |
+
};
|
| 251 |
+
|
| 252 |
+
// ============================================================================
|
| 253 |
+
// ヘルパー関数
|
| 254 |
+
// ============================================================================
|
| 255 |
+
|
| 256 |
+
/**
|
| 257 |
+
* ジャンルIDからジャンル情報を取得
|
| 258 |
+
*
|
| 259 |
+
* @param {string} genreId - ジャンルID(例: 'JP01', 'MA05')
|
| 260 |
+
* @returns {Object|null} - ジャンル情報 { id, name, description, subject_id, subject_name } または null
|
| 261 |
+
*
|
| 262 |
+
* @example
|
| 263 |
+
* var genre = getGenreById('JP01');
|
| 264 |
+
* // => { id: 'JP01', name: '漢字・語彙', description: '...', subject_id: 'jp', subject_name: '国語' }
|
| 265 |
+
*/
|
| 266 |
+
function getGenreById(genreId) {
|
| 267 |
+
if (!genreId || typeof genreId !== 'string') {
|
| 268 |
+
return null;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
var upperGenreId = genreId.toUpperCase();
|
| 272 |
+
|
| 273 |
+
// 全教科を検索
|
| 274 |
+
var subjects = ['jp', 'math', 'sci', 'soc'];
|
| 275 |
+
for (var i = 0; i < subjects.length; i++) {
|
| 276 |
+
var subjectId = subjects[i];
|
| 277 |
+
var subjectData = GENRE_MASTER[subjectId];
|
| 278 |
+
var genres = subjectData.genres;
|
| 279 |
+
|
| 280 |
+
for (var j = 0; j < genres.length; j++) {
|
| 281 |
+
var genre = genres[j];
|
| 282 |
+
if (genre.id === upperGenreId) {
|
| 283 |
+
// ジャンル情報に教科情報を追加して返却
|
| 284 |
+
return {
|
| 285 |
+
id: genre.id,
|
| 286 |
+
name: genre.name,
|
| 287 |
+
description: genre.description,
|
| 288 |
+
subject_id: subjectData.subject_id,
|
| 289 |
+
subject_name: subjectData.subject_name
|
| 290 |
+
};
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
return null;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
/**
|
| 299 |
+
* 教科のジャンル一覧を取得
|
| 300 |
+
*
|
| 301 |
+
* @param {string} subjectId - 教科ID(jp, math, sci, soc)
|
| 302 |
+
* @returns {Array} - ジャンル配列(見つからない場合は空配列)
|
| 303 |
+
*
|
| 304 |
+
* @example
|
| 305 |
+
* var genres = getGenresBySubject('jp');
|
| 306 |
+
* // => [{ id: 'JP01', name: '漢字・語彙', ... }, ...]
|
| 307 |
+
*/
|
| 308 |
+
function getGenresBySubject(subjectId) {
|
| 309 |
+
if (!subjectId || typeof subjectId !== 'string') {
|
| 310 |
+
return [];
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
var subjectData = GENRE_MASTER[subjectId.toLowerCase()];
|
| 314 |
+
if (!subjectData) {
|
| 315 |
+
return [];
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
return subjectData.genres;
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
/**
|
| 322 |
+
* 全ジャンル数を取得
|
| 323 |
+
*
|
| 324 |
+
* @returns {number} - 総ジャンル数(40)
|
| 325 |
+
*
|
| 326 |
+
* @example
|
| 327 |
+
* var total = getTotalGenreCount();
|
| 328 |
+
* // => 40
|
| 329 |
+
*/
|
| 330 |
+
function getTotalGenreCount() {
|
| 331 |
+
var count = 0;
|
| 332 |
+
var subjects = ['jp', 'math', 'sci', 'soc'];
|
| 333 |
+
|
| 334 |
+
for (var i = 0; i < subjects.length; i++) {
|
| 335 |
+
var subjectId = subjects[i];
|
| 336 |
+
count += GENRE_MASTER[subjectId].genres.length;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
return count;
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
/**
|
| 343 |
+
* ジャンルIDの検証
|
| 344 |
+
*
|
| 345 |
+
* @param {string} genreId - ジャンルID
|
| 346 |
+
* @returns {boolean} - 有効なジャンルIDかどうか
|
| 347 |
+
*
|
| 348 |
+
* @example
|
| 349 |
+
* isValidGenreId('JP01'); // => true
|
| 350 |
+
* isValidGenreId('XX99'); // => false
|
| 351 |
+
*/
|
| 352 |
+
function isValidGenreId(genreId) {
|
| 353 |
+
return getGenreById(genreId) !== null;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
/**
|
| 357 |
+
* Dify用のジャンルリストを生成(問題生成プロンプト用)
|
| 358 |
+
*
|
| 359 |
+
* @param {string} subjectId - 教科ID(jp, math, sci, soc)
|
| 360 |
+
* @returns {string} - ジャンルリストの文字列(改行区切り)
|
| 361 |
+
*
|
| 362 |
+
* @example
|
| 363 |
+
* var list = getGenreListForDify('jp');
|
| 364 |
+
* // => "JP01: 漢字・語彙(読み書き、四字熟語、慣用句、ことわざ)\n..."
|
| 365 |
+
*/
|
| 366 |
+
function getGenreListForDify(subjectId) {
|
| 367 |
+
var genres = getGenresBySubject(subjectId);
|
| 368 |
+
|
| 369 |
+
if (genres.length === 0) {
|
| 370 |
+
return '';
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
var lines = [];
|
| 374 |
+
for (var i = 0; i < genres.length; i++) {
|
| 375 |
+
var genre = genres[i];
|
| 376 |
+
var line = genre.id + ': ' + genre.name + '(' + genre.description + ')';
|
| 377 |
+
lines.push(line);
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
return lines.join('\n');
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
// ============================================================================
|
| 384 |
+
// テスト関数(GASエディタで実行可能)
|
| 385 |
+
// ============================================================================
|
| 386 |
+
|
| 387 |
+
/**
|
| 388 |
+
* GenreMaster.jsのテスト関数
|
| 389 |
+
* GASエディタで実行して動作確認
|
| 390 |
+
*/
|
| 391 |
+
function testGenreMaster() {
|
| 392 |
+
Logger.log('=== GenreMaster.js テスト開始 ===');
|
| 393 |
+
|
| 394 |
+
// テスト1: ジャンル総数
|
| 395 |
+
var totalCount = getTotalGenreCount();
|
| 396 |
+
Logger.log('テスト1: 総ジャンル数 = ' + totalCount + ' (期待値: 40)');
|
| 397 |
+
|
| 398 |
+
// テスト2: ジャンルID検索
|
| 399 |
+
var genre1 = getGenreById('JP01');
|
| 400 |
+
Logger.log('テスト2: getGenreById("JP01") = ' + JSON.stringify(genre1));
|
| 401 |
+
|
| 402 |
+
var genre2 = getGenreById('MA05');
|
| 403 |
+
Logger.log('テスト2: getGenreById("MA05") = ' + JSON.stringify(genre2));
|
| 404 |
+
|
| 405 |
+
// テスト3: 教科別ジャンル取得
|
| 406 |
+
var jpGenres = getGenresBySubject('jp');
|
| 407 |
+
Logger.log('テスト3: 国語ジャンル数 = ' + jpGenres.length + ' (期待値: 8)');
|
| 408 |
+
|
| 409 |
+
var mathGenres = getGenresBySubject('math');
|
| 410 |
+
Logger.log('テスト3: 算数ジャンル数 = ' + mathGenres.length + ' (期待値: 10)');
|
| 411 |
+
|
| 412 |
+
var sciGenres = getGenresBySubject('sci');
|
| 413 |
+
Logger.log('テスト3: 理科ジャンル数 = ' + sciGenres.length + ' (期待値: 12)');
|
| 414 |
+
|
| 415 |
+
var socGenres = getGenresBySubject('soc');
|
| 416 |
+
Logger.log('テスト3: 社会ジャンル数 = ' + socGenres.length + ' (期待値: 10)');
|
| 417 |
+
|
| 418 |
+
// テスト4: ジャンルID検証
|
| 419 |
+
var valid1 = isValidGenreId('JP01');
|
| 420 |
+
Logger.log('テスト4: isValidGenreId("JP01") = ' + valid1 + ' (期待値: true)');
|
| 421 |
+
|
| 422 |
+
var valid2 = isValidGenreId('XX99');
|
| 423 |
+
Logger.log('テスト4: isValidGenreId("XX99") = ' + valid2 + ' (期待値: false)');
|
| 424 |
+
|
| 425 |
+
// テスト5: Dify用ジャンルリスト生成
|
| 426 |
+
var jpList = getGenreListForDify('jp');
|
| 427 |
+
Logger.log('テスト5: 国語ジャンルリスト(最初の100文字):');
|
| 428 |
+
Logger.log(jpList.substring(0, 100) + '...');
|
| 429 |
+
|
| 430 |
+
Logger.log('=== GenreMaster.js テスト完了 ===');
|
| 431 |
+
}
|
gas/appsscript.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"timeZone": "Asia/Tokyo",
|
| 3 |
+
"dependencies": {
|
| 4 |
+
},
|
| 5 |
+
"exceptionLogging": "STACKDRIVER",
|
| 6 |
+
"runtimeVersion": "V8",
|
| 7 |
+
"oauthScopes": [
|
| 8 |
+
"https://www.googleapis.com/auth/script.external_request",
|
| 9 |
+
"https://www.googleapis.com/auth/spreadsheets"
|
| 10 |
+
],
|
| 11 |
+
"webapp": {
|
| 12 |
+
"executeAs": "USER_DEPLOYING",
|
| 13 |
+
"access": "ANYONE_ANONYMOUS"
|
| 14 |
+
}
|
| 15 |
+
}
|
gas/questiondb_functions.js
ADDED
|
@@ -0,0 +1,789 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* QuestionDatabase機能
|
| 3 |
+
*
|
| 4 |
+
* 機能:
|
| 5 |
+
* - 事前生成された「回答させたい答え」をGoogle Sheetsで管理
|
| 6 |
+
* - 問題生成時に使用回数が少ないものからランダムに選択
|
| 7 |
+
*
|
| 8 |
+
* シート名: QuestionDatabase
|
| 9 |
+
*
|
| 10 |
+
* スキーマ(8カラム):
|
| 11 |
+
* A: answer_id (string) - 一意ID (例: jp_001, math_042)
|
| 12 |
+
* B: subject (string) - 教科コード (jp, math, sci, soc)
|
| 13 |
+
* C: category (string) - ジャンルID (例: JP01, MA03, SC07)
|
| 14 |
+
* D: answer (string) - 回答させたい答え
|
| 15 |
+
* E: question_hint (string) - 設問方針
|
| 16 |
+
* F: difficulty (string) - 基本/標準/応用
|
| 17 |
+
* G: source_context (string) - 教材での使用例
|
| 18 |
+
* H: usage_count (number) - 使用回数(初期値0)
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
// ==================== 定数定義 ====================
|
| 22 |
+
|
| 23 |
+
const QUESTIONDB_SHEET_NAME = 'QuestionDatabase';
|
| 24 |
+
|
| 25 |
+
const QUESTIONDB_COLUMNS = {
|
| 26 |
+
ANSWER_ID: 1, // A列
|
| 27 |
+
SUBJECT: 2, // B列
|
| 28 |
+
CATEGORY: 3, // C列
|
| 29 |
+
ANSWER: 4, // D列
|
| 30 |
+
QUESTION_HINT: 5, // E列
|
| 31 |
+
DIFFICULTY: 6, // F列
|
| 32 |
+
SOURCE_CONTEXT: 7, // G列
|
| 33 |
+
USAGE_COUNT: 8 // H列
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
const QUESTIONDB_HEADER = [
|
| 37 |
+
'answer_id',
|
| 38 |
+
'subject',
|
| 39 |
+
'category',
|
| 40 |
+
'answer',
|
| 41 |
+
'question_hint',
|
| 42 |
+
'difficulty',
|
| 43 |
+
'source_context',
|
| 44 |
+
'usage_count'
|
| 45 |
+
];
|
| 46 |
+
|
| 47 |
+
/**
|
| 48 |
+
* ジャンル構成定義(各教科10問)
|
| 49 |
+
*
|
| 50 |
+
* 国語: JP01(4), JP02(2), JP03-06各1 = 10問
|
| 51 |
+
* 算数: MA01-MA10 各1問 = 10問
|
| 52 |
+
* 理科: SC01-SC10 各1問 = 10問
|
| 53 |
+
* 社会: SO01-SO10 各1問 = 10問
|
| 54 |
+
*/
|
| 55 |
+
const GENRE_CONFIG = {
|
| 56 |
+
"jp": {"JP01": 4, "JP02": 2, "JP03": 1, "JP04": 1, "JP05": 1, "JP06": 1},
|
| 57 |
+
"math": {"MA01": 1, "MA02": 1, "MA03": 1, "MA04": 1, "MA05": 1, "MA06": 1, "MA07": 1, "MA08": 1, "MA09": 1, "MA10": 1},
|
| 58 |
+
"sci": {"SC01": 1, "SC02": 1, "SC03": 1, "SC04": 1, "SC05": 1, "SC06": 1, "SC07": 1, "SC08": 1, "SC09": 1, "SC10": 1},
|
| 59 |
+
"soc": {"SO01": 1, "SO02": 1, "SO03": 1, "SO04": 1, "SO05": 1, "SO06": 1, "SO07": 1, "SO08": 1, "SO09": 1, "SO10": 1}
|
| 60 |
+
};
|
| 61 |
+
|
| 62 |
+
// ==================== ユーティリティ関数 ====================
|
| 63 |
+
|
| 64 |
+
/**
|
| 65 |
+
* QuestionDatabaseシートを取得(なければ作成)
|
| 66 |
+
* @returns {GoogleAppsScript.Spreadsheet.Sheet}
|
| 67 |
+
*/
|
| 68 |
+
function getQuestionDatabaseSheet_() {
|
| 69 |
+
const ss = SpreadsheetApp.getActiveSpreadsheet();
|
| 70 |
+
let sheet = ss.getSheetByName(QUESTIONDB_SHEET_NAME);
|
| 71 |
+
|
| 72 |
+
if (!sheet) {
|
| 73 |
+
sheet = ss.insertSheet(QUESTIONDB_SHEET_NAME);
|
| 74 |
+
// ヘッダー行を設定
|
| 75 |
+
sheet.getRange(1, 1, 1, QUESTIONDB_HEADER.length).setValues([QUESTIONDB_HEADER]);
|
| 76 |
+
sheet.getRange(1, 1, 1, QUESTIONDB_HEADER.length).setFontWeight('bold');
|
| 77 |
+
sheet.setFrozenRows(1);
|
| 78 |
+
|
| 79 |
+
Logger.log('QuestionDatabaseシートを新規作成しました');
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
return sheet;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/**
|
| 86 |
+
* 行データをオブジェクトに変換
|
| 87 |
+
* @param {Array} row - スプレッドシートの行データ
|
| 88 |
+
* @returns {Object}
|
| 89 |
+
*/
|
| 90 |
+
function rowToQuestionObject_(row) {
|
| 91 |
+
return {
|
| 92 |
+
answer_id: row[0] || '',
|
| 93 |
+
subject: row[1] || '',
|
| 94 |
+
category: row[2] || '',
|
| 95 |
+
answer: row[3] || '',
|
| 96 |
+
question_hint: row[4] || '',
|
| 97 |
+
difficulty: row[5] || '',
|
| 98 |
+
source_context: row[6] || '',
|
| 99 |
+
usage_count: row[7] || 0
|
| 100 |
+
};
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
/**
|
| 104 |
+
* オブジェクトを行データに変換
|
| 105 |
+
* @param {Object} obj - 問題データオブジェクト
|
| 106 |
+
* @returns {Array}
|
| 107 |
+
*/
|
| 108 |
+
function questionObjectToRow_(obj) {
|
| 109 |
+
return [
|
| 110 |
+
obj.answer_id || '',
|
| 111 |
+
obj.subject || '',
|
| 112 |
+
obj.category || '',
|
| 113 |
+
obj.answer || '',
|
| 114 |
+
obj.question_hint || '',
|
| 115 |
+
obj.difficulty || '',
|
| 116 |
+
obj.source_context || '',
|
| 117 |
+
obj.usage_count || 0
|
| 118 |
+
];
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
// ==================== メインAPI ====================
|
| 122 |
+
|
| 123 |
+
/**
|
| 124 |
+
* 教科を指定してランダムに答えを取得
|
| 125 |
+
*
|
| 126 |
+
* アルゴリズム:
|
| 127 |
+
* 1. subject で絞り込み
|
| 128 |
+
* 2. usage_count の最小値を取得
|
| 129 |
+
* 3. 最小値のレコードに絞り込み
|
| 130 |
+
* 4. その中からランダムに count 件抽出
|
| 131 |
+
*
|
| 132 |
+
* @param {string} subject - 教科コード (jp, math, sci, soc)
|
| 133 |
+
* @param {number} count - 取得件数
|
| 134 |
+
* @returns {Array<Object>} 取得した答えデータの配列
|
| 135 |
+
*
|
| 136 |
+
* @example
|
| 137 |
+
* // 国語から3件取得
|
| 138 |
+
* const answers = get_random_answers('jp', 3);
|
| 139 |
+
* console.log(answers);
|
| 140 |
+
* // [
|
| 141 |
+
* // { answer_id: 'jp_001', subject: 'jp', category: 'JP01', answer: '漢字', ... },
|
| 142 |
+
* // { answer_id: 'jp_042', subject: 'jp', category: 'JP02', answer: '文法', ... },
|
| 143 |
+
* // ...
|
| 144 |
+
* // ]
|
| 145 |
+
*/
|
| 146 |
+
function get_random_answers(subject, count) {
|
| 147 |
+
try {
|
| 148 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 149 |
+
const lastRow = sheet.getLastRow();
|
| 150 |
+
|
| 151 |
+
if (lastRow <= 1) {
|
| 152 |
+
Logger.log('QuestionDatabaseにデータがありません');
|
| 153 |
+
return [];
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
// 全データを取得(ヘッダー行を除く)
|
| 157 |
+
const dataRange = sheet.getRange(2, 1, lastRow - 1, QUESTIONDB_HEADER.length);
|
| 158 |
+
const allData = dataRange.getValues();
|
| 159 |
+
|
| 160 |
+
// subjectで絞り込み
|
| 161 |
+
const filteredData = allData
|
| 162 |
+
.map((row, index) => ({ row, originalIndex: index + 2 })) // 行番号を保持(2行目から)
|
| 163 |
+
.filter(item => item.row[QUESTIONDB_COLUMNS.SUBJECT - 1] === subject);
|
| 164 |
+
|
| 165 |
+
if (filteredData.length === 0) {
|
| 166 |
+
Logger.log(`教科コード '${subject}' のデータが見つかりませんでした`);
|
| 167 |
+
return [];
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// usage_countの最小値を取得
|
| 171 |
+
const usageCounts = filteredData.map(item => item.row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0);
|
| 172 |
+
const minUsageCount = Math.min(...usageCounts);
|
| 173 |
+
|
| 174 |
+
Logger.log(`教科 '${subject}' の最小使用回数: ${minUsageCount}`);
|
| 175 |
+
|
| 176 |
+
// 最小値のレコードに絞り込み
|
| 177 |
+
const minUsageData = filteredData.filter(
|
| 178 |
+
item => (item.row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0) === minUsageCount
|
| 179 |
+
);
|
| 180 |
+
|
| 181 |
+
Logger.log(`最小使用回数のレコード数: ${minUsageData.length}`);
|
| 182 |
+
|
| 183 |
+
// ランダムに count 件抽出
|
| 184 |
+
const selectedCount = Math.min(count, minUsageData.length);
|
| 185 |
+
const shuffled = minUsageData.sort(() => Math.random() - 0.5);
|
| 186 |
+
const selected = shuffled.slice(0, selectedCount);
|
| 187 |
+
|
| 188 |
+
// オブジェクト形式に変換
|
| 189 |
+
const results = selected.map(item => rowToQuestionObject_(item.row));
|
| 190 |
+
|
| 191 |
+
Logger.log(`${selectedCount}件の答えを取得しました`);
|
| 192 |
+
return results;
|
| 193 |
+
|
| 194 |
+
} catch (error) {
|
| 195 |
+
Logger.log(`get_random_answers エラー: ${error.message}`);
|
| 196 |
+
throw error;
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
/**
|
| 201 |
+
* ジャンル構成に基づいて問題を取得(v1.6.3新規)
|
| 202 |
+
*
|
| 203 |
+
* 各ジャンル内でusage_countが最小のレコードからランダムに指定数を抽出
|
| 204 |
+
* これにより全ジャンルから均等に出題され、同じ問題の繰り返しを防ぐ
|
| 205 |
+
*
|
| 206 |
+
* @param {Array<string>} subjects - 教科コードの配列 (例: ["jp", "math", "sci", "soc"])
|
| 207 |
+
* @returns {Array<Object>} 取得した問題データの配列(全教科分を結合)
|
| 208 |
+
*
|
| 209 |
+
* @example
|
| 210 |
+
* const questions = get_questions_by_genre_config(["jp", "math"]);
|
| 211 |
+
* // 国語10問 + 算数10問 = 20問が返る
|
| 212 |
+
*/
|
| 213 |
+
function get_questions_by_genre_config(subjects) {
|
| 214 |
+
try {
|
| 215 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 216 |
+
const lastRow = sheet.getLastRow();
|
| 217 |
+
|
| 218 |
+
if (lastRow <= 1) {
|
| 219 |
+
Logger.log('QuestionDatabaseにデータがありません');
|
| 220 |
+
return [];
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
// 全データを取得(ヘッダー行を除く)
|
| 224 |
+
const dataRange = sheet.getRange(2, 1, lastRow - 1, QUESTIONDB_HEADER.length);
|
| 225 |
+
const allData = dataRange.getValues();
|
| 226 |
+
|
| 227 |
+
const results = [];
|
| 228 |
+
|
| 229 |
+
// 各教科を処理
|
| 230 |
+
for (const subject of subjects) {
|
| 231 |
+
const genreConfig = GENRE_CONFIG[subject];
|
| 232 |
+
|
| 233 |
+
if (!genreConfig) {
|
| 234 |
+
Logger.log(`未知の教科コード: ${subject} - スキップ`);
|
| 235 |
+
continue;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
Logger.log(`教科 '${subject}' を処理中...`);
|
| 239 |
+
|
| 240 |
+
// 各ジャンルを処理
|
| 241 |
+
for (const [genre, count] of Object.entries(genreConfig)) {
|
| 242 |
+
// このジャンルのレコードを抽出
|
| 243 |
+
const genreData = allData
|
| 244 |
+
.map((row, index) => ({ row, originalIndex: index + 2 }))
|
| 245 |
+
.filter(item =>
|
| 246 |
+
item.row[QUESTIONDB_COLUMNS.SUBJECT - 1] === subject &&
|
| 247 |
+
item.row[QUESTIONDB_COLUMNS.CATEGORY - 1] === genre
|
| 248 |
+
);
|
| 249 |
+
|
| 250 |
+
if (genreData.length === 0) {
|
| 251 |
+
Logger.log(`ジャンル '${genre}' のデータがありません`);
|
| 252 |
+
continue;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
// usage_countの最小値を取得
|
| 256 |
+
const usageCounts = genreData.map(item => item.row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0);
|
| 257 |
+
const minUsageCount = Math.min(...usageCounts);
|
| 258 |
+
|
| 259 |
+
// 最小値のレコードに絞り込み
|
| 260 |
+
const minUsageData = genreData.filter(
|
| 261 |
+
item => (item.row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0) === minUsageCount
|
| 262 |
+
);
|
| 263 |
+
|
| 264 |
+
// ランダムに指定数を抽出
|
| 265 |
+
const selectedCount = Math.min(count, minUsageData.length);
|
| 266 |
+
const shuffled = minUsageData.sort(() => Math.random() - 0.5);
|
| 267 |
+
const selected = shuffled.slice(0, selectedCount);
|
| 268 |
+
|
| 269 |
+
// オブジェクト形式に変換して結果に追加
|
| 270 |
+
for (const item of selected) {
|
| 271 |
+
results.push(rowToQuestionObject_(item.row));
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
Logger.log(`ジャンル '${genre}': ${selectedCount}/${count}問取得(最小usage_count: ${minUsageCount})`);
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
Logger.log(`合計 ${results.length} 問を取得しました`);
|
| 279 |
+
return results;
|
| 280 |
+
|
| 281 |
+
} catch (error) {
|
| 282 |
+
Logger.log(`get_questions_by_genre_config エラー: ${error.message}`);
|
| 283 |
+
throw error;
|
| 284 |
+
}
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
/**
|
| 288 |
+
* 指定した答えIDの使用回数を+1する
|
| 289 |
+
*
|
| 290 |
+
* @param {Array<string>} answerIds - 答えIDの配列
|
| 291 |
+
* @returns {Object} 更新結果 { success: true, updated_count: number }
|
| 292 |
+
*
|
| 293 |
+
* @example
|
| 294 |
+
* // 2件の使用回数を更新
|
| 295 |
+
* const result = update_usage_count(['jp_001', 'jp_042']);
|
| 296 |
+
* console.log(result); // { success: true, updated_count: 2 }
|
| 297 |
+
*/
|
| 298 |
+
function update_usage_count(answerIds) {
|
| 299 |
+
try {
|
| 300 |
+
if (!Array.isArray(answerIds) || answerIds.length === 0) {
|
| 301 |
+
Logger.log('answer_ids が空または無効です');
|
| 302 |
+
return { success: false, updated_count: 0, error: 'Invalid answer_ids' };
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 306 |
+
const lastRow = sheet.getLastRow();
|
| 307 |
+
|
| 308 |
+
if (lastRow <= 1) {
|
| 309 |
+
Logger.log('QuestionDatabaseにデータがありません');
|
| 310 |
+
return { success: false, updated_count: 0, error: 'No data' };
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
// 全データを取得
|
| 314 |
+
const dataRange = sheet.getRange(2, 1, lastRow - 1, QUESTIONDB_HEADER.length);
|
| 315 |
+
const allData = dataRange.getValues();
|
| 316 |
+
|
| 317 |
+
let updatedCount = 0;
|
| 318 |
+
|
| 319 |
+
// answer_id でマッチする行を探して usage_count を +1
|
| 320 |
+
allData.forEach((row, index) => {
|
| 321 |
+
const answerId = row[QUESTIONDB_COLUMNS.ANSWER_ID - 1];
|
| 322 |
+
|
| 323 |
+
if (answerIds.includes(answerId)) {
|
| 324 |
+
const currentUsage = row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0;
|
| 325 |
+
const newUsage = currentUsage + 1;
|
| 326 |
+
|
| 327 |
+
// usage_count セルを更新
|
| 328 |
+
const rowNumber = index + 2; // ヘッダー行を考慮
|
| 329 |
+
sheet.getRange(rowNumber, QUESTIONDB_COLUMNS.USAGE_COUNT).setValue(newUsage);
|
| 330 |
+
|
| 331 |
+
Logger.log(`${answerId} の使用回数を ${currentUsage} → ${newUsage} に更新`);
|
| 332 |
+
updatedCount++;
|
| 333 |
+
}
|
| 334 |
+
});
|
| 335 |
+
|
| 336 |
+
Logger.log(`合計 ${updatedCount} 件の使用回数を更新しました`);
|
| 337 |
+
|
| 338 |
+
return {
|
| 339 |
+
success: true,
|
| 340 |
+
updated_count: updatedCount
|
| 341 |
+
};
|
| 342 |
+
|
| 343 |
+
} catch (error) {
|
| 344 |
+
Logger.log(`update_usage_count エラー: ${error.message}`);
|
| 345 |
+
return {
|
| 346 |
+
success: false,
|
| 347 |
+
updated_count: 0,
|
| 348 |
+
error: error.message
|
| 349 |
+
};
|
| 350 |
+
}
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
/**
|
| 354 |
+
* 答えデータを一括挿入(初期データ投入用)
|
| 355 |
+
*
|
| 356 |
+
* @param {Array<Object>} answers - 答えデータの配列
|
| 357 |
+
* @returns {Object} 挿入結果 { success: true, inserted_count: number }
|
| 358 |
+
*
|
| 359 |
+
* @example
|
| 360 |
+
* const answers = [
|
| 361 |
+
* {
|
| 362 |
+
* answer_id: 'jp_001',
|
| 363 |
+
* subject: 'jp',
|
| 364 |
+
* category: 'JP01',
|
| 365 |
+
* answer: '漢字',
|
| 366 |
+
* question_hint: '部首を手がかりに意味を推測させる',
|
| 367 |
+
* difficulty: '基本',
|
| 368 |
+
* source_context: '小学3年生の漢字学習',
|
| 369 |
+
* usage_count: 0
|
| 370 |
+
* },
|
| 371 |
+
* ...
|
| 372 |
+
* ];
|
| 373 |
+
* const result = bulk_insert_answers(answers);
|
| 374 |
+
*/
|
| 375 |
+
function bulk_insert_answers(answers) {
|
| 376 |
+
try {
|
| 377 |
+
if (!Array.isArray(answers) || answers.length === 0) {
|
| 378 |
+
Logger.log('answers が空または無効です');
|
| 379 |
+
return { success: false, inserted_count: 0, error: 'Invalid answers' };
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 383 |
+
const lastRow = sheet.getLastRow();
|
| 384 |
+
|
| 385 |
+
// オブジェクト配列を行データに変換
|
| 386 |
+
const rows = answers.map(obj => questionObjectToRow_(obj));
|
| 387 |
+
|
| 388 |
+
// データを一括挿入
|
| 389 |
+
const startRow = lastRow + 1;
|
| 390 |
+
const range = sheet.getRange(startRow, 1, rows.length, QUESTIONDB_HEADER.length);
|
| 391 |
+
range.setValues(rows);
|
| 392 |
+
|
| 393 |
+
Logger.log(`${rows.length} 件のデータを挿入しました(行 ${startRow} ~ ${startRow + rows.length - 1})`);
|
| 394 |
+
|
| 395 |
+
return {
|
| 396 |
+
success: true,
|
| 397 |
+
inserted_count: rows.length
|
| 398 |
+
};
|
| 399 |
+
|
| 400 |
+
} catch (error) {
|
| 401 |
+
Logger.log(`bulk_insert_answers エラー: ${error.message}`);
|
| 402 |
+
return {
|
| 403 |
+
success: false,
|
| 404 |
+
inserted_count: 0,
|
| 405 |
+
error: error.message
|
| 406 |
+
};
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
// ==================== 管理用ユーティリティ ====================
|
| 411 |
+
|
| 412 |
+
/**
|
| 413 |
+
* QuestionDatabaseの統計情報を取得
|
| 414 |
+
*
|
| 415 |
+
* @returns {Object} 統計情報
|
| 416 |
+
*/
|
| 417 |
+
function getQuestionDatabaseStats() {
|
| 418 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 419 |
+
const lastRow = sheet.getLastRow();
|
| 420 |
+
|
| 421 |
+
if (lastRow <= 1) {
|
| 422 |
+
return {
|
| 423 |
+
total_count: 0,
|
| 424 |
+
subjects: {}
|
| 425 |
+
};
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
const dataRange = sheet.getRange(2, 1, lastRow - 1, QUESTIONDB_HEADER.length);
|
| 429 |
+
const allData = dataRange.getValues();
|
| 430 |
+
|
| 431 |
+
const stats = {
|
| 432 |
+
total_count: allData.length,
|
| 433 |
+
subjects: {}
|
| 434 |
+
};
|
| 435 |
+
|
| 436 |
+
allData.forEach(row => {
|
| 437 |
+
const subject = row[QUESTIONDB_COLUMNS.SUBJECT - 1];
|
| 438 |
+
const category = row[QUESTIONDB_COLUMNS.CATEGORY - 1];
|
| 439 |
+
const usageCount = row[QUESTIONDB_COLUMNS.USAGE_COUNT - 1] || 0;
|
| 440 |
+
|
| 441 |
+
if (!stats.subjects[subject]) {
|
| 442 |
+
stats.subjects[subject] = {
|
| 443 |
+
count: 0,
|
| 444 |
+
categories: {},
|
| 445 |
+
total_usage: 0,
|
| 446 |
+
min_usage: Infinity,
|
| 447 |
+
max_usage: 0
|
| 448 |
+
};
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
stats.subjects[subject].count++;
|
| 452 |
+
stats.subjects[subject].total_usage += usageCount;
|
| 453 |
+
stats.subjects[subject].min_usage = Math.min(stats.subjects[subject].min_usage, usageCount);
|
| 454 |
+
stats.subjects[subject].max_usage = Math.max(stats.subjects[subject].max_usage, usageCount);
|
| 455 |
+
|
| 456 |
+
if (!stats.subjects[subject].categories[category]) {
|
| 457 |
+
stats.subjects[subject].categories[category] = 0;
|
| 458 |
+
}
|
| 459 |
+
stats.subjects[subject].categories[category]++;
|
| 460 |
+
});
|
| 461 |
+
|
| 462 |
+
Logger.log('QuestionDatabase統計情報:');
|
| 463 |
+
Logger.log(JSON.stringify(stats, null, 2));
|
| 464 |
+
|
| 465 |
+
return stats;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
/**
|
| 469 |
+
* 指定した教科のデータを全削除
|
| 470 |
+
*
|
| 471 |
+
* @param {string} subject - 教科コード (jp, math, sci, soc)
|
| 472 |
+
* @returns {Object} 削除結果 { success: true, deleted_count: number }
|
| 473 |
+
*/
|
| 474 |
+
function deleteBySubject(subject) {
|
| 475 |
+
try {
|
| 476 |
+
if (!subject) {
|
| 477 |
+
Logger.log('subject が指定されていません');
|
| 478 |
+
return { success: false, deleted_count: 0, error: 'subject required' };
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 482 |
+
const lastRow = sheet.getLastRow();
|
| 483 |
+
|
| 484 |
+
if (lastRow <= 1) {
|
| 485 |
+
Logger.log('QuestionDatabaseにデータがありません');
|
| 486 |
+
return { success: true, deleted_count: 0 };
|
| 487 |
+
}
|
| 488 |
+
|
| 489 |
+
// 全データを取得
|
| 490 |
+
const dataRange = sheet.getRange(2, 1, lastRow - 1, QUESTIONDB_HEADER.length);
|
| 491 |
+
const allData = dataRange.getValues();
|
| 492 |
+
|
| 493 |
+
// 削除対象の行番号を特定(後ろから削除するため逆順)
|
| 494 |
+
const rowsToDelete = [];
|
| 495 |
+
allData.forEach((row, index) => {
|
| 496 |
+
if (row[QUESTIONDB_COLUMNS.SUBJECT - 1] === subject) {
|
| 497 |
+
rowsToDelete.push(index + 2); // ヘッダー行を考慮
|
| 498 |
+
}
|
| 499 |
+
});
|
| 500 |
+
|
| 501 |
+
// 後ろから削除(行番号がずれないように)
|
| 502 |
+
rowsToDelete.reverse().forEach(rowNum => {
|
| 503 |
+
sheet.deleteRow(rowNum);
|
| 504 |
+
});
|
| 505 |
+
|
| 506 |
+
Logger.log(`教科 '${subject}' の ${rowsToDelete.length} 件を削除しました`);
|
| 507 |
+
|
| 508 |
+
return {
|
| 509 |
+
success: true,
|
| 510 |
+
deleted_count: rowsToDelete.length
|
| 511 |
+
};
|
| 512 |
+
|
| 513 |
+
} catch (error) {
|
| 514 |
+
Logger.log(`deleteBySubject エラー: ${error.message}`);
|
| 515 |
+
return {
|
| 516 |
+
success: false,
|
| 517 |
+
deleted_count: 0,
|
| 518 |
+
error: error.message
|
| 519 |
+
};
|
| 520 |
+
}
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
/**
|
| 524 |
+
* QuestionDatabaseシートにヘッダ行を追加
|
| 525 |
+
*
|
| 526 |
+
* @returns {Object} 結果 { success: true, message: string }
|
| 527 |
+
*/
|
| 528 |
+
function addQuestionDatabaseHeader() {
|
| 529 |
+
try {
|
| 530 |
+
const ss = SpreadsheetApp.getActiveSpreadsheet();
|
| 531 |
+
let sheet = ss.getSheetByName(QUESTIONDB_SHEET_NAME);
|
| 532 |
+
|
| 533 |
+
if (!sheet) {
|
| 534 |
+
// シートがない場合は作成
|
| 535 |
+
sheet = ss.insertSheet(QUESTIONDB_SHEET_NAME);
|
| 536 |
+
Logger.log('QuestionDatabaseシートを新規作成しました');
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
// ヘッダー行を設定(既存データがある場合は行1に挿入)
|
| 540 |
+
const firstRow = sheet.getRange(1, 1, 1, QUESTIONDB_HEADER.length);
|
| 541 |
+
const currentFirstRow = firstRow.getValues()[0];
|
| 542 |
+
|
| 543 |
+
// 既にヘッダーがあるかチェック
|
| 544 |
+
if (currentFirstRow[0] === 'answer_id') {
|
| 545 |
+
return {
|
| 546 |
+
success: true,
|
| 547 |
+
message: 'Header already exists'
|
| 548 |
+
};
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
// ヘッダーがない場合、行1に挿入
|
| 552 |
+
if (currentFirstRow[0] !== '' && currentFirstRow[0] !== 'answer_id') {
|
| 553 |
+
// データがある場合は行を挿入
|
| 554 |
+
sheet.insertRowBefore(1);
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
// ヘッダーを設定
|
| 558 |
+
sheet.getRange(1, 1, 1, QUESTIONDB_HEADER.length).setValues([QUESTIONDB_HEADER]);
|
| 559 |
+
sheet.getRange(1, 1, 1, QUESTIONDB_HEADER.length).setFontWeight('bold');
|
| 560 |
+
sheet.setFrozenRows(1);
|
| 561 |
+
|
| 562 |
+
Logger.log('QuestionDatabaseヘッダ行を追加しました');
|
| 563 |
+
|
| 564 |
+
return {
|
| 565 |
+
success: true,
|
| 566 |
+
message: 'Header added successfully'
|
| 567 |
+
};
|
| 568 |
+
|
| 569 |
+
} catch (error) {
|
| 570 |
+
Logger.log(`addQuestionDatabaseHeader エラー: ${error.message}`);
|
| 571 |
+
return {
|
| 572 |
+
success: false,
|
| 573 |
+
error: error.message
|
| 574 |
+
};
|
| 575 |
+
}
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
/**
|
| 579 |
+
* 全データのusage_countをリセット(開発/テスト用)
|
| 580 |
+
*
|
| 581 |
+
* @returns {Object} リセット結果
|
| 582 |
+
*/
|
| 583 |
+
function resetAllUsageCount() {
|
| 584 |
+
const sheet = getQuestionDatabaseSheet_();
|
| 585 |
+
const lastRow = sheet.getLastRow();
|
| 586 |
+
|
| 587 |
+
if (lastRow <= 1) {
|
| 588 |
+
Logger.log('QuestionDatabaseにデータがありません');
|
| 589 |
+
return { success: false, message: 'No data' };
|
| 590 |
+
}
|
| 591 |
+
|
| 592 |
+
const usageCountRange = sheet.getRange(2, QUESTIONDB_COLUMNS.USAGE_COUNT, lastRow - 1, 1);
|
| 593 |
+
const zeros = Array(lastRow - 1).fill([0]);
|
| 594 |
+
usageCountRange.setValues(zeros);
|
| 595 |
+
|
| 596 |
+
Logger.log(`${lastRow - 1} 件の usage_count を 0 にリセットしました`);
|
| 597 |
+
|
| 598 |
+
return {
|
| 599 |
+
success: true,
|
| 600 |
+
reset_count: lastRow - 1
|
| 601 |
+
};
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
// ==================== Web API エンドポイント ====================
|
| 605 |
+
|
| 606 |
+
/**
|
| 607 |
+
* doPost エンドポイント(既存のコードに統合用)
|
| 608 |
+
*
|
| 609 |
+
* アクション一覧:
|
| 610 |
+
* - get_random_answers: ランダムに答えを取得
|
| 611 |
+
* - update_usage_count: 使用回数を更新
|
| 612 |
+
* - bulk_insert_answers: 一括挿入
|
| 613 |
+
*
|
| 614 |
+
* 使用例:
|
| 615 |
+
*
|
| 616 |
+
* // get_random_answers
|
| 617 |
+
* POST https://script.google.com/macros/s/.../exec
|
| 618 |
+
* {
|
| 619 |
+
* "action": "get_random_answers",
|
| 620 |
+
* "subject": "jp",
|
| 621 |
+
* "count": 3
|
| 622 |
+
* }
|
| 623 |
+
*
|
| 624 |
+
* // update_usage_count
|
| 625 |
+
* POST https://script.google.com/macros/s/.../exec
|
| 626 |
+
* {
|
| 627 |
+
* "action": "update_usage_count",
|
| 628 |
+
* "answer_ids": ["jp_001", "jp_042"]
|
| 629 |
+
* }
|
| 630 |
+
*
|
| 631 |
+
* // bulk_insert_answers
|
| 632 |
+
* POST https://script.google.com/macros/s/.../exec
|
| 633 |
+
* {
|
| 634 |
+
* "action": "bulk_insert_answers",
|
| 635 |
+
* "answers": [
|
| 636 |
+
* {
|
| 637 |
+
* "answer_id": "jp_001",
|
| 638 |
+
* "subject": "jp",
|
| 639 |
+
* "category": "JP01",
|
| 640 |
+
* "answer": "漢字",
|
| 641 |
+
* "question_hint": "部首を手がかりに",
|
| 642 |
+
* "difficulty": "基本",
|
| 643 |
+
* "source_context": "小学3年生",
|
| 644 |
+
* "usage_count": 0
|
| 645 |
+
* }
|
| 646 |
+
* ]
|
| 647 |
+
* }
|
| 648 |
+
*/
|
| 649 |
+
function handleQuestionDatabaseAction(action, params) {
|
| 650 |
+
switch (action) {
|
| 651 |
+
case 'get_random_answers':
|
| 652 |
+
return get_random_answers(params.subject, params.count || 1);
|
| 653 |
+
|
| 654 |
+
case 'get_random_questions':
|
| 655 |
+
// Python互換: get_questions_by_configと同じだが、レスポンス形式を調整
|
| 656 |
+
try {
|
| 657 |
+
const questions = get_questions_by_genre_config(params.subjects || []);
|
| 658 |
+
return {
|
| 659 |
+
success: true,
|
| 660 |
+
data: {
|
| 661 |
+
questions: questions
|
| 662 |
+
}
|
| 663 |
+
};
|
| 664 |
+
} catch (error) {
|
| 665 |
+
return {
|
| 666 |
+
success: false,
|
| 667 |
+
error: error.message
|
| 668 |
+
};
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
case 'get_questions_by_config':
|
| 672 |
+
// v1.6.3: ジャンル構成に基づく問題取得
|
| 673 |
+
return get_questions_by_genre_config(params.subjects || []);
|
| 674 |
+
|
| 675 |
+
case 'update_usage_count':
|
| 676 |
+
return update_usage_count(params.answer_ids || []);
|
| 677 |
+
|
| 678 |
+
case 'bulk_insert_answers':
|
| 679 |
+
return bulk_insert_answers(params.answers || []);
|
| 680 |
+
|
| 681 |
+
case 'get_stats':
|
| 682 |
+
return getQuestionDatabaseStats();
|
| 683 |
+
|
| 684 |
+
case 'reset_usage':
|
| 685 |
+
return resetAllUsageCount();
|
| 686 |
+
|
| 687 |
+
case 'delete_by_subject':
|
| 688 |
+
return deleteBySubject(params.subject);
|
| 689 |
+
|
| 690 |
+
case 'add_header':
|
| 691 |
+
return addQuestionDatabaseHeader();
|
| 692 |
+
|
| 693 |
+
default:
|
| 694 |
+
return {
|
| 695 |
+
success: false,
|
| 696 |
+
error: `Unknown action: ${action}`
|
| 697 |
+
};
|
| 698 |
+
}
|
| 699 |
+
}
|
| 700 |
+
|
| 701 |
+
// ==================== テスト用関数 ====================
|
| 702 |
+
|
| 703 |
+
/**
|
| 704 |
+
* テスト用: サンプルデータを挿入
|
| 705 |
+
*/
|
| 706 |
+
function testInsertSampleData() {
|
| 707 |
+
const sampleData = [
|
| 708 |
+
{
|
| 709 |
+
answer_id: 'jp_001',
|
| 710 |
+
subject: 'jp',
|
| 711 |
+
category: 'JP01',
|
| 712 |
+
answer: '憂鬱',
|
| 713 |
+
question_hint: '気分が晴れない様子を表す漢字',
|
| 714 |
+
difficulty: '標準',
|
| 715 |
+
source_context: '中学国語教科書',
|
| 716 |
+
usage_count: 0
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
answer_id: 'jp_002',
|
| 720 |
+
subject: 'jp',
|
| 721 |
+
category: 'JP01',
|
| 722 |
+
answer: '慈悲',
|
| 723 |
+
question_hint: '思いやりの心を表す熟語',
|
| 724 |
+
difficulty: '基本',
|
| 725 |
+
source_context: '小学6年生',
|
| 726 |
+
usage_count: 0
|
| 727 |
+
},
|
| 728 |
+
{
|
| 729 |
+
answer_id: 'jp_003',
|
| 730 |
+
subject: 'jp',
|
| 731 |
+
category: 'JP02',
|
| 732 |
+
answer: 'である',
|
| 733 |
+
question_hint: '断定の助動詞',
|
| 734 |
+
difficulty: '基本',
|
| 735 |
+
source_context: '中学文法',
|
| 736 |
+
usage_count: 0
|
| 737 |
+
},
|
| 738 |
+
{
|
| 739 |
+
answer_id: 'math_001',
|
| 740 |
+
subject: 'math',
|
| 741 |
+
category: 'MA01',
|
| 742 |
+
answer: '平方根',
|
| 743 |
+
question_hint: '2乗してその数になる数',
|
| 744 |
+
difficulty: '標準',
|
| 745 |
+
source_context: '中学3年数学',
|
| 746 |
+
usage_count: 0
|
| 747 |
+
}
|
| 748 |
+
];
|
| 749 |
+
|
| 750 |
+
const result = bulk_insert_answers(sampleData);
|
| 751 |
+
Logger.log('サンプルデータ挿入結果:');
|
| 752 |
+
Logger.log(JSON.stringify(result, null, 2));
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
/**
|
| 756 |
+
* テスト用: get_random_answers のテスト
|
| 757 |
+
*/
|
| 758 |
+
function testGetRandomAnswers() {
|
| 759 |
+
const answers = get_random_answers('jp', 2);
|
| 760 |
+
Logger.log('取得した答え:');
|
| 761 |
+
Logger.log(JSON.stringify(answers, null, 2));
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
/**
|
| 765 |
+
* テスト用: update_usage_count のテスト
|
| 766 |
+
*/
|
| 767 |
+
function testUpdateUsageCount() {
|
| 768 |
+
const result = update_usage_count(['jp_001', 'jp_002']);
|
| 769 |
+
Logger.log('更新結果:');
|
| 770 |
+
Logger.log(JSON.stringify(result, null, 2));
|
| 771 |
+
}
|
| 772 |
+
|
| 773 |
+
/**
|
| 774 |
+
* テスト用: get_questions_by_genre_config のテスト(v1.6.3)
|
| 775 |
+
*/
|
| 776 |
+
function testGetQuestionsByGenreConfig() {
|
| 777 |
+
const questions = get_questions_by_genre_config(['jp', 'math']);
|
| 778 |
+
Logger.log(`取得した問題数: ${questions.length}`);
|
| 779 |
+
|
| 780 |
+
// ジャンル別の内訳を表示
|
| 781 |
+
const genreCounts = {};
|
| 782 |
+
for (const q of questions) {
|
| 783 |
+
const key = `${q.subject}/${q.category}`;
|
| 784 |
+
genreCounts[key] = (genreCounts[key] || 0) + 1;
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
Logger.log('ジャンル別内訳:');
|
| 788 |
+
Logger.log(JSON.stringify(genreCounts, null, 2));
|
| 789 |
+
}
|
gas/setup_dify_properties.js
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Dify環境変数設定スクリプト
|
| 3 |
+
*
|
| 4 |
+
* Google Apps ScriptのScriptPropertiesに、Dify API統合に必要な環境変数を設定・管理します。
|
| 5 |
+
*
|
| 6 |
+
* 主要機能:
|
| 7 |
+
* - Dify API URL・API Keyの設定
|
| 8 |
+
* - 設定値の取得・確認
|
| 9 |
+
* - Dify APIへの接続テスト
|
| 10 |
+
* - 環境変数のクリア(デバッグ用)
|
| 11 |
+
*
|
| 12 |
+
* @version 1.0.0
|
| 13 |
+
* @date 2025-11-10
|
| 14 |
+
*/
|
| 15 |
+
|
| 16 |
+
// ============================================================================
|
| 17 |
+
// 定数定義
|
| 18 |
+
// ============================================================================
|
| 19 |
+
|
| 20 |
+
/**
|
| 21 |
+
* 環境変数のキー名
|
| 22 |
+
*/
|
| 23 |
+
const PROPERTY_KEYS = {
|
| 24 |
+
DIFY_API_URL: 'DIFY_API_URL',
|
| 25 |
+
DIFY_API_KEY: 'DIFY_API_KEY',
|
| 26 |
+
SPREADSHEET_ID: 'SPREADSHEET_ID'
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
// ============================================================================
|
| 30 |
+
// 環境変数設定関数
|
| 31 |
+
// ============================================================================
|
| 32 |
+
|
| 33 |
+
/**
|
| 34 |
+
* Dify関連の環境変数をScriptPropertiesに設定します
|
| 35 |
+
*
|
| 36 |
+
* 設定される環境変数:
|
| 37 |
+
* - DIFY_API_URL: Difyワークフロー実行エンドポイント
|
| 38 |
+
* - DIFY_API_KEY: Dify APIキー
|
| 39 |
+
* - SPREADSHEET_ID: Google SheetsのスプレッドシートID(確認用)
|
| 40 |
+
*
|
| 41 |
+
* 実行方法:
|
| 42 |
+
* 1. Apps Scriptエディタでこのファイルを開く
|
| 43 |
+
* 2. 関数 setDifyProperties を選択して実行
|
| 44 |
+
* 3. 実行ログで結果を確認
|
| 45 |
+
*
|
| 46 |
+
* 注意:
|
| 47 |
+
* - 実際の値を設定する際は、以下のダミー値を実際の値に置き換えてください
|
| 48 |
+
* - API Keyは機密情報のため、取り扱いに注意してください
|
| 49 |
+
*
|
| 50 |
+
* @returns {void}
|
| 51 |
+
*
|
| 52 |
+
* @example
|
| 53 |
+
* // 実行例(Apps Scriptエディタで実行)
|
| 54 |
+
* setDifyProperties();
|
| 55 |
+
* // ログ出力: 「✅ Dify環境変数の設定が完了しました」
|
| 56 |
+
*/
|
| 57 |
+
function setDifyProperties() {
|
| 58 |
+
try {
|
| 59 |
+
const properties = PropertiesService.getScriptProperties();
|
| 60 |
+
|
| 61 |
+
// ========================================================================
|
| 62 |
+
// 【重要】実際の値に置き換えてください
|
| 63 |
+
// ========================================================================
|
| 64 |
+
|
| 65 |
+
// Dify Cloud のワークフロー実行エンドポイント
|
| 66 |
+
// 例: 'https://api.dify.ai/v1/workflows/run'
|
| 67 |
+
const DIFY_API_URL = 'https://api.dify.ai/v1/workflows/run';
|
| 68 |
+
|
| 69 |
+
// Dify Cloud のAPI Key(ワークフロー作成後に取得)
|
| 70 |
+
// 例: 'app-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
| 71 |
+
const DIFY_API_KEY = 'app-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
|
| 72 |
+
|
| 73 |
+
// Google SheetsのスプレッドシートID(既存、確認用)
|
| 74 |
+
// 既にCode.jsで定義されている値
|
| 75 |
+
const SPREADSHEET_ID = '1xlyaDpCrg4M-epbQ-KqemjpDeabxBjZ7aVCvRgRLazE';
|
| 76 |
+
|
| 77 |
+
// ========================================================================
|
| 78 |
+
// 環境変数の設定
|
| 79 |
+
// ========================================================================
|
| 80 |
+
|
| 81 |
+
properties.setProperty(PROPERTY_KEYS.DIFY_API_URL, DIFY_API_URL);
|
| 82 |
+
properties.setProperty(PROPERTY_KEYS.DIFY_API_KEY, DIFY_API_KEY);
|
| 83 |
+
properties.setProperty(PROPERTY_KEYS.SPREADSHEET_ID, SPREADSHEET_ID);
|
| 84 |
+
|
| 85 |
+
Logger.log('✅ Dify環境変数の設定が完了しました');
|
| 86 |
+
Logger.log('');
|
| 87 |
+
Logger.log('設定内容:');
|
| 88 |
+
Logger.log(' DIFY_API_URL: ' + DIFY_API_URL);
|
| 89 |
+
Logger.log(' DIFY_API_KEY: ' + maskApiKey(DIFY_API_KEY));
|
| 90 |
+
Logger.log(' SPREADSHEET_ID: ' + SPREADSHEET_ID);
|
| 91 |
+
Logger.log('');
|
| 92 |
+
Logger.log('次のステップ: getDifyProperties() を実行して設定を確認してください');
|
| 93 |
+
|
| 94 |
+
} catch (error) {
|
| 95 |
+
Logger.log('❌ エラー: Dify環境変数の設定に失敗しました');
|
| 96 |
+
Logger.log('詳細: ' + error.toString());
|
| 97 |
+
throw new Error('環境変数の設定に失敗しました: ' + error.toString());
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// ============================================================================
|
| 102 |
+
// 環境変数取得関数
|
| 103 |
+
// ============================================================================
|
| 104 |
+
|
| 105 |
+
/**
|
| 106 |
+
* 設定されたDify環境変数を取得・確認します
|
| 107 |
+
*
|
| 108 |
+
* 取得する環境変数:
|
| 109 |
+
* - DIFY_API_URL: Difyワークフロー実行エンドポイント
|
| 110 |
+
* - DIFY_API_KEY: Dify APIキー(マスク表示)
|
| 111 |
+
* - SPREADSHEET_ID: Google SheetsのスプレッドシートID
|
| 112 |
+
*
|
| 113 |
+
* 実行方法:
|
| 114 |
+
* 1. Apps Scriptエディタでこのファイルを開く
|
| 115 |
+
* 2. 関数 getDifyProperties を選択して実行
|
| 116 |
+
* 3. 実行ログで設定内容を確認
|
| 117 |
+
*
|
| 118 |
+
* @returns {Object} 環境変数のオブジェクト
|
| 119 |
+
* @returns {string} returns.DIFY_API_URL - Dify API URL
|
| 120 |
+
* @returns {string} returns.DIFY_API_KEY - Dify API Key
|
| 121 |
+
* @returns {string} returns.SPREADSHEET_ID - スプレッドシートID
|
| 122 |
+
*
|
| 123 |
+
* @example
|
| 124 |
+
* // 実行例(Apps Scriptエディタで実行)
|
| 125 |
+
* const props = getDifyProperties();
|
| 126 |
+
* // ログ出力: 各環境変数の値
|
| 127 |
+
*
|
| 128 |
+
* @example
|
| 129 |
+
* // コード内での使用例
|
| 130 |
+
* const props = getDifyProperties();
|
| 131 |
+
* const apiUrl = props.DIFY_API_URL;
|
| 132 |
+
* const apiKey = props.DIFY_API_KEY;
|
| 133 |
+
*/
|
| 134 |
+
function getDifyProperties() {
|
| 135 |
+
try {
|
| 136 |
+
const properties = PropertiesService.getScriptProperties();
|
| 137 |
+
|
| 138 |
+
const difyApiUrl = properties.getProperty(PROPERTY_KEYS.DIFY_API_URL);
|
| 139 |
+
const difyApiKey = properties.getProperty(PROPERTY_KEYS.DIFY_API_KEY);
|
| 140 |
+
const spreadsheetId = properties.getProperty(PROPERTY_KEYS.SPREADSHEET_ID);
|
| 141 |
+
|
| 142 |
+
Logger.log('📋 Dify環境変数の取得結果:');
|
| 143 |
+
Logger.log('');
|
| 144 |
+
Logger.log(' DIFY_API_URL: ' + (difyApiUrl || '(未設定)'));
|
| 145 |
+
Logger.log(' DIFY_API_KEY: ' + (difyApiKey ? maskApiKey(difyApiKey) : '(未設定)'));
|
| 146 |
+
Logger.log(' SPREADSHEET_ID: ' + (spreadsheetId || '(未設定)'));
|
| 147 |
+
Logger.log('');
|
| 148 |
+
|
| 149 |
+
// 未設定の項目をチェック
|
| 150 |
+
const missingKeys = [];
|
| 151 |
+
if (!difyApiUrl) missingKeys.push('DIFY_API_URL');
|
| 152 |
+
if (!difyApiKey) missingKeys.push('DIFY_API_KEY');
|
| 153 |
+
if (!spreadsheetId) missingKeys.push('SPREADSHEET_ID');
|
| 154 |
+
|
| 155 |
+
if (missingKeys.length > 0) {
|
| 156 |
+
Logger.log('⚠️ 未設定の環境変数があります: ' + missingKeys.join(', '));
|
| 157 |
+
Logger.log('setDifyProperties() を実行して設定してください');
|
| 158 |
+
} else {
|
| 159 |
+
Logger.log('✅ すべての環境変数が設定されています');
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
return {
|
| 163 |
+
DIFY_API_URL: difyApiUrl,
|
| 164 |
+
DIFY_API_KEY: difyApiKey,
|
| 165 |
+
SPREADSHEET_ID: spreadsheetId
|
| 166 |
+
};
|
| 167 |
+
|
| 168 |
+
} catch (error) {
|
| 169 |
+
Logger.log('❌ エラー: Dify環境変数の取得に失敗しました');
|
| 170 |
+
Logger.log('詳細: ' + error.toString());
|
| 171 |
+
throw new Error('環境変数の取得に失敗しました: ' + error.toString());
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
// ============================================================================
|
| 176 |
+
// Dify接続テスト関数
|
| 177 |
+
// ============================================================================
|
| 178 |
+
|
| 179 |
+
/**
|
| 180 |
+
* Dify APIへの接続テストを実行します
|
| 181 |
+
*
|
| 182 |
+
* テスト内容:
|
| 183 |
+
* - 環境変数の存在確認
|
| 184 |
+
* - Dify API URLへのHTTPリクエスト送信
|
| 185 |
+
* - レスポンスステータスの確認
|
| 186 |
+
*
|
| 187 |
+
* 実行方法:
|
| 188 |
+
* 1. setDifyProperties() を実行して環境変数を設定
|
| 189 |
+
* 2. Apps Scriptエディタでこのファイルを開く
|
| 190 |
+
* 3. 関数 testDifyConnection を選択して実行
|
| 191 |
+
* 4. 実行ログで接続テスト結果を確認
|
| 192 |
+
*
|
| 193 |
+
* 注意:
|
| 194 |
+
* - 実際のDify Cloudアカウントとワークフロー作成が必要です
|
| 195 |
+
* - API Keyが正しく設定されていることを確認してください
|
| 196 |
+
*
|
| 197 |
+
* @returns {Object} テスト結果のオブジェクト
|
| 198 |
+
* @returns {boolean} returns.success - テスト成功フラグ
|
| 199 |
+
* @returns {string} returns.message - テスト結果メッセージ
|
| 200 |
+
* @returns {Object} returns.response - APIレスポンス(成功時)
|
| 201 |
+
*
|
| 202 |
+
* @example
|
| 203 |
+
* // 実行例(Apps Scriptエディタで実行)
|
| 204 |
+
* testDifyConnection();
|
| 205 |
+
* // ログ出力: 「✅ Dify API接続テスト成功」または「❌ 接続テスト失敗」
|
| 206 |
+
*/
|
| 207 |
+
function testDifyConnection() {
|
| 208 |
+
try {
|
| 209 |
+
Logger.log('🔄 Dify API接続テストを開始します...');
|
| 210 |
+
Logger.log('');
|
| 211 |
+
|
| 212 |
+
// 環境変数の取得
|
| 213 |
+
const properties = PropertiesService.getScriptProperties();
|
| 214 |
+
const difyApiUrl = properties.getProperty(PROPERTY_KEYS.DIFY_API_URL);
|
| 215 |
+
const difyApiKey = properties.getProperty(PROPERTY_KEYS.DIFY_API_KEY);
|
| 216 |
+
|
| 217 |
+
// 環境変数の存在確認
|
| 218 |
+
if (!difyApiUrl || !difyApiKey) {
|
| 219 |
+
Logger.log('❌ エラー: 環境変数が未設定です');
|
| 220 |
+
Logger.log('setDifyProperties() を実行して環境変数を設定してください');
|
| 221 |
+
return {
|
| 222 |
+
success: false,
|
| 223 |
+
message: '環境変数が未設定です'
|
| 224 |
+
};
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
Logger.log('環境変数の確認: ✅');
|
| 228 |
+
Logger.log(' DIFY_API_URL: ' + difyApiUrl);
|
| 229 |
+
Logger.log(' DIFY_API_KEY: ' + maskApiKey(difyApiKey));
|
| 230 |
+
Logger.log('');
|
| 231 |
+
|
| 232 |
+
// テスト用のリクエストペイロード
|
| 233 |
+
const testPayload = {
|
| 234 |
+
inputs: {
|
| 235 |
+
subject: '算数',
|
| 236 |
+
category: '四則計算',
|
| 237 |
+
test: true
|
| 238 |
+
},
|
| 239 |
+
response_mode: 'blocking',
|
| 240 |
+
user: 'gas-test-user'
|
| 241 |
+
};
|
| 242 |
+
|
| 243 |
+
// HTTPリクエストオプション
|
| 244 |
+
const options = {
|
| 245 |
+
method: 'post',
|
| 246 |
+
contentType: 'application/json',
|
| 247 |
+
headers: {
|
| 248 |
+
'Authorization': 'Bearer ' + difyApiKey
|
| 249 |
+
},
|
| 250 |
+
payload: JSON.stringify(testPayload),
|
| 251 |
+
muteHttpExceptions: true // エラーレスポンスも取得するため
|
| 252 |
+
};
|
| 253 |
+
|
| 254 |
+
Logger.log('🌐 Dify APIへリクエストを送信中...');
|
| 255 |
+
Logger.log('URL: ' + difyApiUrl);
|
| 256 |
+
Logger.log('');
|
| 257 |
+
|
| 258 |
+
// Dify APIへのリクエスト送信
|
| 259 |
+
const response = UrlFetchApp.fetch(difyApiUrl, options);
|
| 260 |
+
const responseCode = response.getResponseCode();
|
| 261 |
+
const responseText = response.getContentText();
|
| 262 |
+
|
| 263 |
+
Logger.log('📥 レスポンスを受信しました');
|
| 264 |
+
Logger.log('ステータスコード: ' + responseCode);
|
| 265 |
+
Logger.log('');
|
| 266 |
+
|
| 267 |
+
// レスポンスの解析
|
| 268 |
+
if (responseCode === 200) {
|
| 269 |
+
const responseData = JSON.parse(responseText);
|
| 270 |
+
Logger.log('✅ Dify API接続テスト成功');
|
| 271 |
+
Logger.log('');
|
| 272 |
+
Logger.log('レスポンス内容:');
|
| 273 |
+
Logger.log(JSON.stringify(responseData, null, 2));
|
| 274 |
+
|
| 275 |
+
return {
|
| 276 |
+
success: true,
|
| 277 |
+
message: '接続テスト成功',
|
| 278 |
+
response: responseData
|
| 279 |
+
};
|
| 280 |
+
|
| 281 |
+
} else {
|
| 282 |
+
Logger.log('❌ Dify API接続テスト失敗');
|
| 283 |
+
Logger.log('ステータスコード: ' + responseCode);
|
| 284 |
+
Logger.log('エラー内容: ' + responseText);
|
| 285 |
+
Logger.log('');
|
| 286 |
+
Logger.log('考えられる原因:');
|
| 287 |
+
Logger.log(' 1. DIFY_API_URL が正しくない');
|
| 288 |
+
Logger.log(' 2. DIFY_API_KEY が正しくない');
|
| 289 |
+
Logger.log(' 3. Difyワークフローがまだ作成されていない');
|
| 290 |
+
Logger.log(' 4. Difyワークフローが公開されていない');
|
| 291 |
+
|
| 292 |
+
return {
|
| 293 |
+
success: false,
|
| 294 |
+
message: '接続テスト失敗(ステータスコード: ' + responseCode + ')',
|
| 295 |
+
error: responseText
|
| 296 |
+
};
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
} catch (error) {
|
| 300 |
+
Logger.log('❌ エラー: Dify API接続テストでエラーが発生しました');
|
| 301 |
+
Logger.log('詳細: ' + error.toString());
|
| 302 |
+
Logger.log('');
|
| 303 |
+
Logger.log('考えられる原因:');
|
| 304 |
+
Logger.log(' 1. ネットワーク接続エラー');
|
| 305 |
+
Logger.log(' 2. URLが不正(例: プロトコル未指定)');
|
| 306 |
+
Logger.log(' 3. Apps Scriptの外部API接続権限が不足');
|
| 307 |
+
|
| 308 |
+
return {
|
| 309 |
+
success: false,
|
| 310 |
+
message: '接続テスト中にエラーが発生しました: ' + error.toString()
|
| 311 |
+
};
|
| 312 |
+
}
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
// ============================================================================
|
| 316 |
+
// 環境変数クリア関数(デバッグ用)
|
| 317 |
+
// ============================================================================
|
| 318 |
+
|
| 319 |
+
/**
|
| 320 |
+
* 設定されたDify環境変数をクリアします(デバッグ用)
|
| 321 |
+
*
|
| 322 |
+
* 削除される環境変数:
|
| 323 |
+
* - DIFY_API_URL
|
| 324 |
+
* - DIFY_API_KEY
|
| 325 |
+
* - SPREADSHEET_ID
|
| 326 |
+
*
|
| 327 |
+
* 実行方法:
|
| 328 |
+
* 1. Apps Scriptエディタでこのファイルを開く
|
| 329 |
+
* 2. 関数 clearDifyProperties を選択して実行
|
| 330 |
+
* 3. 実行ログで削除結果を確認
|
| 331 |
+
*
|
| 332 |
+
* 注意:
|
| 333 |
+
* - この操作は元に戻せません
|
| 334 |
+
* - 誤って実行しないように注意してください
|
| 335 |
+
* - 本番環境では使用しないでください
|
| 336 |
+
*
|
| 337 |
+
* @returns {void}
|
| 338 |
+
*
|
| 339 |
+
* @example
|
| 340 |
+
* // 実行例(Apps Scriptエディタで実行)
|
| 341 |
+
* clearDifyProperties();
|
| 342 |
+
* // ログ出力: 「✅ Dify環境変数のクリアが完了しました」
|
| 343 |
+
*/
|
| 344 |
+
function clearDifyProperties() {
|
| 345 |
+
try {
|
| 346 |
+
const properties = PropertiesService.getScriptProperties();
|
| 347 |
+
|
| 348 |
+
Logger.log('🔄 Dify環境変数のクリアを開始します...');
|
| 349 |
+
Logger.log('');
|
| 350 |
+
|
| 351 |
+
// 削除前の確認
|
| 352 |
+
const before = getDifyPropertiesInternal(properties);
|
| 353 |
+
Logger.log('削除前の設定:');
|
| 354 |
+
Logger.log(' DIFY_API_URL: ' + (before.DIFY_API_URL ? '設定あり' : '設定なし'));
|
| 355 |
+
Logger.log(' DIFY_API_KEY: ' + (before.DIFY_API_KEY ? '設定あり' : '設定なし'));
|
| 356 |
+
Logger.log(' SPREADSHEET_ID: ' + (before.SPREADSHEET_ID ? '設定あり' : '設定なし'));
|
| 357 |
+
Logger.log('');
|
| 358 |
+
|
| 359 |
+
// 環境変数の削除
|
| 360 |
+
properties.deleteProperty(PROPERTY_KEYS.DIFY_API_URL);
|
| 361 |
+
properties.deleteProperty(PROPERTY_KEYS.DIFY_API_KEY);
|
| 362 |
+
properties.deleteProperty(PROPERTY_KEYS.SPREADSHEET_ID);
|
| 363 |
+
|
| 364 |
+
Logger.log('✅ Dify環境変数のクリアが完了しました');
|
| 365 |
+
Logger.log('');
|
| 366 |
+
Logger.log('削除された環境変数:');
|
| 367 |
+
Logger.log(' - DIFY_API_URL');
|
| 368 |
+
Logger.log(' - DIFY_API_KEY');
|
| 369 |
+
Logger.log(' - SPREADSHEET_ID');
|
| 370 |
+
Logger.log('');
|
| 371 |
+
Logger.log('再設定する場合: setDifyProperties() を実行してください');
|
| 372 |
+
|
| 373 |
+
} catch (error) {
|
| 374 |
+
Logger.log('❌ エラー: Dify環境変数のクリアに失敗しました');
|
| 375 |
+
Logger.log('詳細: ' + error.toString());
|
| 376 |
+
throw new Error('環境変数のクリアに失敗しました: ' + error.toString());
|
| 377 |
+
}
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
// ============================================================================
|
| 381 |
+
// ユーティリティ関数
|
| 382 |
+
// ============================================================================
|
| 383 |
+
|
| 384 |
+
/**
|
| 385 |
+
* API Keyをマスク表示します(セキュリティ対策)
|
| 386 |
+
*
|
| 387 |
+
* 例: 'app-abc123xyz789' → 'app-abc***xyz789'
|
| 388 |
+
*
|
| 389 |
+
* @param {string} apiKey - API Key
|
| 390 |
+
* @returns {string} マスク表示されたAPI Key
|
| 391 |
+
* @private
|
| 392 |
+
*/
|
| 393 |
+
function maskApiKey(apiKey) {
|
| 394 |
+
if (!apiKey || apiKey.length < 10) {
|
| 395 |
+
return '***';
|
| 396 |
+
}
|
| 397 |
+
const prefix = apiKey.substring(0, 7);
|
| 398 |
+
const suffix = apiKey.substring(apiKey.length - 6);
|
| 399 |
+
return prefix + '***' + suffix;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
/**
|
| 403 |
+
* 環境変数を取得します(内部用、ログ出力なし)
|
| 404 |
+
*
|
| 405 |
+
* @param {PropertiesService.Properties} properties - Propertiesオブジェクト
|
| 406 |
+
* @returns {Object} 環境変数のオブジェクト
|
| 407 |
+
* @private
|
| 408 |
+
*/
|
| 409 |
+
function getDifyPropertiesInternal(properties) {
|
| 410 |
+
return {
|
| 411 |
+
DIFY_API_URL: properties.getProperty(PROPERTY_KEYS.DIFY_API_URL),
|
| 412 |
+
DIFY_API_KEY: properties.getProperty(PROPERTY_KEYS.DIFY_API_KEY),
|
| 413 |
+
SPREADSHEET_ID: properties.getProperty(PROPERTY_KEYS.SPREADSHEET_ID)
|
| 414 |
+
};
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
// ============================================================================
|
| 418 |
+
// 使用例・実行手順
|
| 419 |
+
// ============================================================================
|
| 420 |
+
|
| 421 |
+
/**
|
| 422 |
+
* 【実行手順】
|
| 423 |
+
*
|
| 424 |
+
* 1. 環境変数の設定
|
| 425 |
+
* - setDifyProperties() を実行
|
| 426 |
+
* - 事前に関数内のダミー値を実際の値に置き換えてください
|
| 427 |
+
*
|
| 428 |
+
* 2. 設定の確認
|
| 429 |
+
* - getDifyProperties() を実行
|
| 430 |
+
* - 実行ログで設定内容を確認してください
|
| 431 |
+
*
|
| 432 |
+
* 3. 接続テスト
|
| 433 |
+
* - testDifyConnection() を実行
|
| 434 |
+
* - Dify APIへの接続が成功するか確認してください
|
| 435 |
+
*
|
| 436 |
+
* 4. 環境変数のクリア(必要な場合のみ)
|
| 437 |
+
* - clearDifyProperties() を実行
|
| 438 |
+
* - 誤って実行しないように注意してください
|
| 439 |
+
*
|
| 440 |
+
* 【Code.jsでの使用例】
|
| 441 |
+
*
|
| 442 |
+
* ```javascript
|
| 443 |
+
* // 環境変数の取得
|
| 444 |
+
* const properties = PropertiesService.getScriptProperties();
|
| 445 |
+
* const DIFY_API_URL = properties.getProperty('DIFY_API_URL');
|
| 446 |
+
* const DIFY_API_KEY = properties.getProperty('DIFY_API_KEY');
|
| 447 |
+
*
|
| 448 |
+
* // Dify APIへのリクエスト送信
|
| 449 |
+
* function callDifyAPI(inputs) {
|
| 450 |
+
* const options = {
|
| 451 |
+
* method: 'post',
|
| 452 |
+
* contentType: 'application/json',
|
| 453 |
+
* headers: {
|
| 454 |
+
* 'Authorization': 'Bearer ' + DIFY_API_KEY
|
| 455 |
+
* },
|
| 456 |
+
* payload: JSON.stringify({
|
| 457 |
+
* inputs: inputs,
|
| 458 |
+
* response_mode: 'blocking',
|
| 459 |
+
* user: 'gas-orchestrator'
|
| 460 |
+
* }),
|
| 461 |
+
* muteHttpExceptions: true
|
| 462 |
+
* };
|
| 463 |
+
*
|
| 464 |
+
* const response = UrlFetchApp.fetch(DIFY_API_URL, options);
|
| 465 |
+
* return JSON.parse(response.getContentText());
|
| 466 |
+
* }
|
| 467 |
+
* ```
|
| 468 |
+
*/
|
gas/setup_sheets_v2.js
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* サイクル1.2.5: Google Sheets拡張(7シート構成への移行)
|
| 3 |
+
*
|
| 4 |
+
* このスクリプトは「超天才クイズDB」を4シート構成から7シート構成に自動拡張します。
|
| 5 |
+
*
|
| 6 |
+
* 実行方法:
|
| 7 |
+
* 1. Apps Scriptエディタで本ファイルを開く
|
| 8 |
+
* 2. setupSheetsV2関数を選択
|
| 9 |
+
* 3. 実行ボタンをクリック
|
| 10 |
+
* 4. ログで結果を確認
|
| 11 |
+
*
|
| 12 |
+
* 仕様:
|
| 13 |
+
* - 新規シート作成: Answers, Statistics, Evaluations(各ヘッダー + サンプルデータ)
|
| 14 |
+
* - 既存シート更新: Questions, Knowledge_Baseに`category`列追加
|
| 15 |
+
* - 安全機能: 既存シートチェック、重複チェック、エラーハンドリング
|
| 16 |
+
*
|
| 17 |
+
* 参照:
|
| 18 |
+
* - docs/data-model.md v2.0
|
| 19 |
+
* - docs/sheets-setup-manual-v2.md
|
| 20 |
+
*
|
| 21 |
+
* バージョン: 1.0
|
| 22 |
+
* 作成日: 2025-11-10
|
| 23 |
+
*/
|
| 24 |
+
|
| 25 |
+
// Note: SPREADSHEET_IDはCode.jsで定義済みのためここでは宣言しない
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* メイン関数: Google Sheetsを7シート構成に拡張
|
| 29 |
+
*/
|
| 30 |
+
function setupSheetsV2() {
|
| 31 |
+
try {
|
| 32 |
+
Logger.log('=== Google Sheets拡張開始(v2.0: 7シート構成) ===');
|
| 33 |
+
|
| 34 |
+
// スプレッドシート取得(Code.jsで定義されたSPREADSHEET_IDを使用)
|
| 35 |
+
var spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
|
| 36 |
+
Logger.log('スプレッドシート取得成功: ' + spreadsheet.getName());
|
| 37 |
+
|
| 38 |
+
// 既存シート確認
|
| 39 |
+
Logger.log('\n--- 既存シート確認 ---');
|
| 40 |
+
checkExistingSheets(spreadsheet);
|
| 41 |
+
|
| 42 |
+
// 新規シート作成(3シート)
|
| 43 |
+
Logger.log('\n--- 新規シート作成 ---');
|
| 44 |
+
createAnswersSheet(spreadsheet);
|
| 45 |
+
createStatisticsSheet(spreadsheet);
|
| 46 |
+
createEvaluationsSheet(spreadsheet);
|
| 47 |
+
|
| 48 |
+
// 既存シート更新(2シート)
|
| 49 |
+
Logger.log('\n--- 既存シート更新 ---');
|
| 50 |
+
updateQuestionsSheet(spreadsheet);
|
| 51 |
+
updateKnowledgeBaseSheet(spreadsheet);
|
| 52 |
+
|
| 53 |
+
Logger.log('\n=== Google Sheets拡張完了! ===');
|
| 54 |
+
Logger.log('結果: 7シート構成に拡張成功');
|
| 55 |
+
Logger.log('次のステップ: Google Sheetsを開いて7シート全て存在することを確認してください');
|
| 56 |
+
|
| 57 |
+
} catch (error) {
|
| 58 |
+
Logger.log('\n❌ エラー発生: ' + error.message);
|
| 59 |
+
Logger.log('スタックトレース: ' + error.stack);
|
| 60 |
+
throw error;
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
/**
|
| 65 |
+
* 既存シート確認
|
| 66 |
+
*/
|
| 67 |
+
function checkExistingSheets(spreadsheet) {
|
| 68 |
+
var sheets = spreadsheet.getSheets();
|
| 69 |
+
Logger.log('現在のシート数: ' + sheets.length);
|
| 70 |
+
|
| 71 |
+
for (var i = 0; i < sheets.length; i++) {
|
| 72 |
+
Logger.log(' - ' + sheets[i].getName());
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// 必須シート確認(Users, Sessions, Questions, Knowledge_Base)
|
| 76 |
+
var requiredSheets = ['Users', 'Sessions', 'Questions', 'Knowledge_Base'];
|
| 77 |
+
for (var j = 0; j < requiredSheets.length; j++) {
|
| 78 |
+
var sheet = spreadsheet.getSheetByName(requiredSheets[j]);
|
| 79 |
+
if (!sheet) {
|
| 80 |
+
throw new Error('必須シート「' + requiredSheets[j] + '」が存在しません。サイクル1.2を先に実行してください。');
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
Logger.log('必須シート(4シート)確認完了');
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/**
|
| 87 |
+
* Answersシート作成
|
| 88 |
+
*/
|
| 89 |
+
function createAnswersSheet(spreadsheet) {
|
| 90 |
+
var sheetName = 'Answers';
|
| 91 |
+
|
| 92 |
+
// 既存チェック
|
| 93 |
+
if (spreadsheet.getSheetByName(sheetName)) {
|
| 94 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既に存在します。スキップします。');
|
| 95 |
+
return;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
Logger.log(sheetName + 'シートを作成中...');
|
| 99 |
+
|
| 100 |
+
// シート作成
|
| 101 |
+
var sheet = spreadsheet.insertSheet(sheetName);
|
| 102 |
+
|
| 103 |
+
// ヘッダー行(1行目)
|
| 104 |
+
var headers = [
|
| 105 |
+
'answer_id',
|
| 106 |
+
'session_id',
|
| 107 |
+
'question_id',
|
| 108 |
+
'user_answer',
|
| 109 |
+
'is_correct',
|
| 110 |
+
'time_taken',
|
| 111 |
+
'answered_at'
|
| 112 |
+
];
|
| 113 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 114 |
+
|
| 115 |
+
// サンプルデータ(2行)
|
| 116 |
+
var sampleData = [
|
| 117 |
+
['ans-sample-001', 'session-sample-001', 'q-sample-001', 0, true, 12, '2025-11-04T10:31:15Z'],
|
| 118 |
+
['ans-sample-002', 'session-sample-001', 'q-sample-002', 2, false, 18, '2025-11-04T10:31:33Z']
|
| 119 |
+
];
|
| 120 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 121 |
+
|
| 122 |
+
Logger.log('✅ ' + sheetName + 'シート作成完了(ヘッダー + サンプルデータ2行)');
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
/**
|
| 126 |
+
* Statisticsシート作成
|
| 127 |
+
*/
|
| 128 |
+
function createStatisticsSheet(spreadsheet) {
|
| 129 |
+
var sheetName = 'Statistics';
|
| 130 |
+
|
| 131 |
+
// 既存チェック
|
| 132 |
+
if (spreadsheet.getSheetByName(sheetName)) {
|
| 133 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既に存在します。スキップします。');
|
| 134 |
+
return;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
Logger.log(sheetName + 'シートを作成中...');
|
| 138 |
+
|
| 139 |
+
// シート作成
|
| 140 |
+
var sheet = spreadsheet.insertSheet(sheetName);
|
| 141 |
+
|
| 142 |
+
// ヘッダー行(1行目)
|
| 143 |
+
var headers = [
|
| 144 |
+
'stat_id',
|
| 145 |
+
'user_id',
|
| 146 |
+
'subject',
|
| 147 |
+
'category',
|
| 148 |
+
'total_attempted',
|
| 149 |
+
'correct_count',
|
| 150 |
+
'accuracy_rate',
|
| 151 |
+
'last_updated'
|
| 152 |
+
];
|
| 153 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 154 |
+
|
| 155 |
+
// サンプルデータ(3行)
|
| 156 |
+
var sampleData = [
|
| 157 |
+
['stat-001', 'sample-user-001', '国語', '漢字・語彙', 20, 16, 0.80, '2025-11-04T10:45:00Z'],
|
| 158 |
+
['stat-002', 'sample-user-001', '国語', '物語文読解', 15, 9, 0.60, '2025-11-04T10:45:00Z'],
|
| 159 |
+
['stat-003', 'sample-user-001', '算数', '平面図形', 10, 4, 0.40, '2025-11-04T10:45:00Z']
|
| 160 |
+
];
|
| 161 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 162 |
+
|
| 163 |
+
Logger.log('✅ ' + sheetName + 'シート作成完了(ヘッダー + サンプルデータ3行)');
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
/**
|
| 167 |
+
* Evaluationsシート作成
|
| 168 |
+
*/
|
| 169 |
+
function createEvaluationsSheet(spreadsheet) {
|
| 170 |
+
var sheetName = 'Evaluations';
|
| 171 |
+
|
| 172 |
+
// 既存チェック
|
| 173 |
+
if (spreadsheet.getSheetByName(sheetName)) {
|
| 174 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既に存在します。スキップします。');
|
| 175 |
+
return;
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
Logger.log(sheetName + 'シートを作成中...');
|
| 179 |
+
|
| 180 |
+
// シート作成
|
| 181 |
+
var sheet = spreadsheet.insertSheet(sheetName);
|
| 182 |
+
|
| 183 |
+
// ヘッダー行(1行目)
|
| 184 |
+
var headers = [
|
| 185 |
+
'eval_id',
|
| 186 |
+
'session_id',
|
| 187 |
+
'subject_evaluations',
|
| 188 |
+
'overall_evaluation',
|
| 189 |
+
'created_at'
|
| 190 |
+
];
|
| 191 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 192 |
+
|
| 193 |
+
// サンプルデータ(1行)
|
| 194 |
+
// JSON形式のデータは文字列として扱う(Google Sheetsは型なし)
|
| 195 |
+
var sampleData = [
|
| 196 |
+
[
|
| 197 |
+
'eval-001',
|
| 198 |
+
'session-sample-001',
|
| 199 |
+
'{"国語":["漢字・語彙は80%の正答率で安定"],"算数":["計算力が優れています"]}',
|
| 200 |
+
'["今回は合計29/40(72.5%)"]',
|
| 201 |
+
'2025-11-04T10:46:00Z'
|
| 202 |
+
]
|
| 203 |
+
];
|
| 204 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 205 |
+
|
| 206 |
+
Logger.log('✅ ' + sheetName + 'シート作成完了(ヘッダー + サンプルデータ1行)');
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
/**
|
| 210 |
+
* Questionsシート更新(category列追加)
|
| 211 |
+
*/
|
| 212 |
+
function updateQuestionsSheet(spreadsheet) {
|
| 213 |
+
var sheetName = 'Questions';
|
| 214 |
+
|
| 215 |
+
Logger.log(sheetName + 'シートを更新中...');
|
| 216 |
+
|
| 217 |
+
// シート取得
|
| 218 |
+
var sheet = spreadsheet.getSheetByName(sheetName);
|
| 219 |
+
if (!sheet) {
|
| 220 |
+
throw new Error(sheetName + 'シートが存在しません');
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
// 現在のヘッダー行確認
|
| 224 |
+
var lastColumn = sheet.getLastColumn();
|
| 225 |
+
if (lastColumn === 0) {
|
| 226 |
+
Logger.log('⚠️ ' + sheetName + 'シートが空です。列追加をスキップします。');
|
| 227 |
+
return;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
var headers = sheet.getRange(1, 1, 1, lastColumn).getValues()[0];
|
| 231 |
+
Logger.log('現在のヘッダー: ' + headers.join(', '));
|
| 232 |
+
|
| 233 |
+
// category列が既に存在するかチェック
|
| 234 |
+
var categoryIndex = headers.indexOf('category');
|
| 235 |
+
if (categoryIndex !== -1) {
|
| 236 |
+
Logger.log('⚠️ category列は既に存在します(列' + (categoryIndex + 1) + ')。スキップします。');
|
| 237 |
+
return;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
// D列(subjectの次)に新規列を挿入
|
| 241 |
+
// 想定: A=question_id, B=session_id, C=subject, D=(新規category), E=difficulty(元のD)...
|
| 242 |
+
var insertPosition = 4; // D列(1-indexed)
|
| 243 |
+
sheet.insertColumnBefore(insertPosition);
|
| 244 |
+
|
| 245 |
+
// D1にヘッダー「category」を追加
|
| 246 |
+
sheet.getRange(1, insertPosition).setValue('category');
|
| 247 |
+
|
| 248 |
+
// D2にサンプルデータを追加(既存のサンプルデータがある場合)
|
| 249 |
+
var lastRow = sheet.getLastRow();
|
| 250 |
+
if (lastRow >= 2) {
|
| 251 |
+
sheet.getRange(2, insertPosition).setValue('漢字・語彙');
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
Logger.log('✅ ' + sheetName + 'シート更新完了(D列にcategory追加)');
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
/**
|
| 258 |
+
* Knowledge_Baseシート更新(category列追加)
|
| 259 |
+
*/
|
| 260 |
+
function updateKnowledgeBaseSheet(spreadsheet) {
|
| 261 |
+
var sheetName = 'Knowledge_Base';
|
| 262 |
+
|
| 263 |
+
Logger.log(sheetName + 'シートを更新中...');
|
| 264 |
+
|
| 265 |
+
// シート取得
|
| 266 |
+
var sheet = spreadsheet.getSheetByName(sheetName);
|
| 267 |
+
if (!sheet) {
|
| 268 |
+
throw new Error(sheetName + 'シートが存在しません');
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
// 現在のヘッダー行確認
|
| 272 |
+
var lastColumn = sheet.getLastColumn();
|
| 273 |
+
if (lastColumn === 0) {
|
| 274 |
+
Logger.log('⚠️ ' + sheetName + 'シートが空です。列追加をスキップします。');
|
| 275 |
+
return;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
var headers = sheet.getRange(1, 1, 1, lastColumn).getValues()[0];
|
| 279 |
+
Logger.log('現在のヘッダー: ' + headers.join(', '));
|
| 280 |
+
|
| 281 |
+
// category列が既に存在するかチェック
|
| 282 |
+
var categoryIndex = headers.indexOf('category');
|
| 283 |
+
if (categoryIndex !== -1) {
|
| 284 |
+
Logger.log('⚠️ category列は既に存在します(列' + (categoryIndex + 1) + ')。スキップします。');
|
| 285 |
+
return;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
// C列(subjectの次)に新規列を挿入
|
| 289 |
+
// 想定: A=kb_id, B=subject, C=(新規category), D=grade(元のC)...
|
| 290 |
+
var insertPosition = 3; // C列(1-indexed)
|
| 291 |
+
sheet.insertColumnBefore(insertPosition);
|
| 292 |
+
|
| 293 |
+
// C1にヘッダー「category」を追加
|
| 294 |
+
sheet.getRange(1, insertPosition).setValue('category');
|
| 295 |
+
|
| 296 |
+
// C2にサンプルデータを追加(既存のサンプルデータがある場合)
|
| 297 |
+
var lastRow = sheet.getLastRow();
|
| 298 |
+
if (lastRow >= 2) {
|
| 299 |
+
sheet.getRange(2, insertPosition).setValue('植物の成長');
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
Logger.log('✅ ' + sheetName + 'シート更新完了(C列にcategory追加)');
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
/**
|
| 306 |
+
* 空シート初期化関数: Sessions, Questions, Knowledge_Baseシートが空の場合に初期データを投入
|
| 307 |
+
*
|
| 308 |
+
* 実行方法:
|
| 309 |
+
* 1. Apps Scriptエディタで本ファイルを開く
|
| 310 |
+
* 2. initializeEmptySheets関数を選択
|
| 311 |
+
* 3. 実行ボタンをクリック
|
| 312 |
+
* 4. ログで結果を確認
|
| 313 |
+
*
|
| 314 |
+
* 処理内容:
|
| 315 |
+
* - Sessionsシート: ヘッダー + サンプルデータ1行
|
| 316 |
+
* - Questionsシート: ヘッダー(category列含む) + サンプルデータ1行
|
| 317 |
+
* - Knowledge_Baseシート: ヘッダー(category列含む) + サンプルデータ1行
|
| 318 |
+
*
|
| 319 |
+
* 安全機能:
|
| 320 |
+
* - シートが既にデータを持つ場合はスキップ
|
| 321 |
+
* - エラーハンドリング
|
| 322 |
+
* - 詳細ログ出力
|
| 323 |
+
*/
|
| 324 |
+
function initializeEmptySheets() {
|
| 325 |
+
try {
|
| 326 |
+
Logger.log('=== 空シート初期化開始 ===');
|
| 327 |
+
|
| 328 |
+
// スプレッドシート取得(Code.jsで定義されたSPREADSHEET_IDを使用)
|
| 329 |
+
var spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
|
| 330 |
+
Logger.log('スプレッドシート取得成功: ' + spreadsheet.getName());
|
| 331 |
+
|
| 332 |
+
// 各シートの初期化
|
| 333 |
+
Logger.log('\n--- シート初期化処理 ---');
|
| 334 |
+
initializeSessionsSheet(spreadsheet);
|
| 335 |
+
initializeQuestionsSheet(spreadsheet);
|
| 336 |
+
initializeKnowledgeBaseSheet(spreadsheet);
|
| 337 |
+
|
| 338 |
+
Logger.log('\n=== 空シート初期化完了! ===');
|
| 339 |
+
Logger.log('結果: 3シート(Sessions, Questions, Knowledge_Base)の初期化が完了しました');
|
| 340 |
+
Logger.log('次のステップ: Google Sheetsを開いて各シートにヘッダーとサンプルデータが存在することを確認してください');
|
| 341 |
+
|
| 342 |
+
} catch (error) {
|
| 343 |
+
Logger.log('\n❌ エラー発生: ' + error.message);
|
| 344 |
+
Logger.log('スタックトレース: ' + error.stack);
|
| 345 |
+
throw error;
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
/**
|
| 350 |
+
* Sessionsシート初期化
|
| 351 |
+
*/
|
| 352 |
+
function initializeSessionsSheet(spreadsheet) {
|
| 353 |
+
var sheetName = 'Sessions';
|
| 354 |
+
|
| 355 |
+
Logger.log(sheetName + 'シートを確認中...');
|
| 356 |
+
|
| 357 |
+
// シート取得
|
| 358 |
+
var sheet = spreadsheet.getSheetByName(sheetName);
|
| 359 |
+
if (!sheet) {
|
| 360 |
+
Logger.log('⚠️ ' + sheetName + 'シートが存在しません。スキップします。');
|
| 361 |
+
return;
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
// 既存データ確認(空シートかどうか)
|
| 365 |
+
var lastRow = sheet.getLastRow();
|
| 366 |
+
if (lastRow > 0) {
|
| 367 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既にデータを持っています(' + lastRow + '行)。スキップします。');
|
| 368 |
+
return;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
Logger.log(sheetName + 'シートを初期化中...');
|
| 372 |
+
|
| 373 |
+
// ヘッダー行(1行目)
|
| 374 |
+
var headers = [
|
| 375 |
+
'session_id',
|
| 376 |
+
'user_id',
|
| 377 |
+
'subjects',
|
| 378 |
+
'start_time',
|
| 379 |
+
'end_time',
|
| 380 |
+
'total_score',
|
| 381 |
+
'completed'
|
| 382 |
+
];
|
| 383 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 384 |
+
|
| 385 |
+
// サンプルデータ(1行)
|
| 386 |
+
var sampleData = [
|
| 387 |
+
['session-sample-001', 'sample-user-001', '["国語","算数"]', '2025-11-04T10:30:00Z', '2025-11-04T10:45:00Z', 29, true]
|
| 388 |
+
];
|
| 389 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 390 |
+
|
| 391 |
+
Logger.log('✅ ' + sheetName + 'シート初期化完了(ヘッダー + サンプルデータ1行)');
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
/**
|
| 395 |
+
* Questionsシート初期化(category列含む)
|
| 396 |
+
*/
|
| 397 |
+
function initializeQuestionsSheet(spreadsheet) {
|
| 398 |
+
var sheetName = 'Questions';
|
| 399 |
+
|
| 400 |
+
Logger.log(sheetName + 'シートを確認中...');
|
| 401 |
+
|
| 402 |
+
// シート取得
|
| 403 |
+
var sheet = spreadsheet.getSheetByName(sheetName);
|
| 404 |
+
if (!sheet) {
|
| 405 |
+
Logger.log('⚠️ ' + sheetName + 'シートが存在しません。スキップします。');
|
| 406 |
+
return;
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
// 既存データ確認(空シートかどうか)
|
| 410 |
+
var lastRow = sheet.getLastRow();
|
| 411 |
+
if (lastRow > 0) {
|
| 412 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既にデータを持っています(' + lastRow + '行)。スキップします。');
|
| 413 |
+
return;
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
Logger.log(sheetName + 'シートを初期化中...');
|
| 417 |
+
|
| 418 |
+
// ヘッダー行(1行目)- category列を含む
|
| 419 |
+
var headers = [
|
| 420 |
+
'question_id',
|
| 421 |
+
'session_id',
|
| 422 |
+
'subject',
|
| 423 |
+
'category',
|
| 424 |
+
'difficulty',
|
| 425 |
+
'question_text',
|
| 426 |
+
'choices',
|
| 427 |
+
'correct_answer',
|
| 428 |
+
'explanation',
|
| 429 |
+
'created_at'
|
| 430 |
+
];
|
| 431 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 432 |
+
|
| 433 |
+
// サンプルデータ(1行)
|
| 434 |
+
var sampleData = [
|
| 435 |
+
[
|
| 436 |
+
'q-sample-001',
|
| 437 |
+
'session-sample-001',
|
| 438 |
+
'国語',
|
| 439 |
+
'漢字・語彙',
|
| 440 |
+
'標準',
|
| 441 |
+
'次の漢字の読みを選びなさい:「成就」',
|
| 442 |
+
'["じょうじゅ","せいしゅう","せいじゅ","じょうしゅう"]',
|
| 443 |
+
0,
|
| 444 |
+
'「成就」は「じょうじゅ」と読みます。',
|
| 445 |
+
'2025-11-04T10:31:00Z'
|
| 446 |
+
]
|
| 447 |
+
];
|
| 448 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 449 |
+
|
| 450 |
+
Logger.log('✅ ' + sheetName + 'シート初期化完了(ヘッダー(category列含む) + サンプルデータ1行)');
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
/**
|
| 454 |
+
* Knowledge_Baseシート初期化(category列含む)
|
| 455 |
+
*/
|
| 456 |
+
function initializeKnowledgeBaseSheet(spreadsheet) {
|
| 457 |
+
var sheetName = 'Knowledge_Base';
|
| 458 |
+
|
| 459 |
+
Logger.log(sheetName + 'シートを確認中...');
|
| 460 |
+
|
| 461 |
+
// シート取得
|
| 462 |
+
var sheet = spreadsheet.getSheetByName(sheetName);
|
| 463 |
+
if (!sheet) {
|
| 464 |
+
Logger.log('⚠️ ' + sheetName + 'シートが存在しません。スキップします。');
|
| 465 |
+
return;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
// 既存データ確認(空シートかどうか)
|
| 469 |
+
var lastRow = sheet.getLastRow();
|
| 470 |
+
if (lastRow > 0) {
|
| 471 |
+
Logger.log('⚠️ ' + sheetName + 'シートは既にデータを持っています(' + lastRow + '行)。スキップします。');
|
| 472 |
+
return;
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
Logger.log(sheetName + 'シートを初期化中...');
|
| 476 |
+
|
| 477 |
+
// ヘッダー行(1行目)- category列を含む
|
| 478 |
+
var headers = [
|
| 479 |
+
'kb_id',
|
| 480 |
+
'subject',
|
| 481 |
+
'category',
|
| 482 |
+
'grade',
|
| 483 |
+
'content',
|
| 484 |
+
'difficulty',
|
| 485 |
+
'usage_count',
|
| 486 |
+
'last_used'
|
| 487 |
+
];
|
| 488 |
+
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
|
| 489 |
+
|
| 490 |
+
// サンプルデータ(1行)
|
| 491 |
+
var sampleData = [
|
| 492 |
+
[
|
| 493 |
+
'kb-sample-001',
|
| 494 |
+
'理科',
|
| 495 |
+
'植物の成長',
|
| 496 |
+
5,
|
| 497 |
+
'種子が発芽するためには、水・空気・適切な温度が必要である。',
|
| 498 |
+
2,
|
| 499 |
+
5,
|
| 500 |
+
'2025-11-04T09:00:00Z'
|
| 501 |
+
]
|
| 502 |
+
];
|
| 503 |
+
sheet.getRange(2, 1, sampleData.length, headers.length).setValues(sampleData);
|
| 504 |
+
|
| 505 |
+
Logger.log('✅ ' + sheetName + 'シート初期化完了(ヘッダー(category列含む) + サンプルデータ1行)');
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
/**
|
| 509 |
+
* テスト関数: setupSheetsV2の動作確認
|
| 510 |
+
*/
|
| 511 |
+
function testSetupSheetsV2() {
|
| 512 |
+
Logger.log('=== テスト実行: setupSheetsV2 ===');
|
| 513 |
+
setupSheetsV2();
|
| 514 |
+
Logger.log('=== テスト完了 ===');
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
/**
|
| 518 |
+
* テスト関数: initializeEmptySheetsの動作確認
|
| 519 |
+
*/
|
| 520 |
+
function testInitializeEmptySheets() {
|
| 521 |
+
Logger.log('=== テスト実行: initializeEmptySheets ===');
|
| 522 |
+
initializeEmptySheets();
|
| 523 |
+
Logger.log('=== テスト完了 ===');
|
| 524 |
+
}
|
knowledge/ORIGINAL/中学入試 でる順 ポケでる国語 漢字・熟語 四訂版.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/合格物語.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/合格論説文.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/理科/改訂版 中学入試にでる順 理科 力・運動・電気・光、物質・エネルギー.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/理科/改訂版 中学入試にでる順 理科 植物・動物・人体、地球・宇宙.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/社会/中学入試にでる順 地理(改訂版).md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/社会/中学入試にでる順 社会 歴史(改訂版).md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/社会/中学受験 社会 裏ワザテクニック Wチェック問題集 歴史編.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/社会/中学受験 社会の裏ワザテクニックWチェック問題集 地理編.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/算数/つまずきやすいところが絶対つまずかない! 小学校6年間の図形の教え方.md
ADDED
|
@@ -0,0 +1,832 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 図形の教え方(小学校6年間)
|
| 2 |
+
|
| 3 |
+
[CHUNK]
|
| 4 |
+
## 図形学習のつまずき解消と本書の目的
|
| 5 |
+
本書は、小学校算数における図形問題でつまずきやすい子どもたちに向けて、苦手意識を克服し、図形問題の解き方を習得できるよう構成されている。プロ家庭教師の経験に基づき、図形問題が苦手な子どもの特徴を分析し、克服のための具体的なアプローチを提示する。図形問題はセンスや才能ではなく、正しい方法と訓練で誰でも解けるようになることを強調する。
|
| 6 |
+
|
| 7 |
+
[CHUNK]
|
| 8 |
+
## 図形問題克服の重要性と身体感覚の活用
|
| 9 |
+
センスや才能に頼らず、図形問題は正しいアプローチと訓練で克服可能である。特に、道具の正しい使い方や、図形をかく、折る、切る、ひっくり返すといった身体感覚が重要となる。低学年のうちにこれらの経験を積むことが望ましい。経験を言葉で表現することで、知識として定着を促す。
|
| 10 |
+
|
| 11 |
+
[CHUNK]
|
| 12 |
+
## 身の回りの形を通じた学習と本書の活用
|
| 13 |
+
身の回りの形を通して、お子さんと楽しくコミュニケーションをとることが重要。「折り紙をななめに折ったら三角形になったね」「きゅうりをまっすぐ切ったら、切り口はぜんぶ丸だね」などの声かけが効果的。高学年でも遅すぎることはなく、中学、高校の数学につながる。本書は教科書の応用問題が解けるようになることを目標に、図形問題に強くなるヒントを提供する。
|
| 14 |
+
|
| 15 |
+
[CHUNK]
|
| 16 |
+
## 本書を通じた親子の成長と良好な関係構築
|
| 17 |
+
本書を通して、親御さんがお子さんとともに、問題が解ける喜びや達成感を味わい、親子の良好な関係が育まれることを願っている。教科書の応用問題が解けるようになることを目標に、図形問題に強くなるヒントを随所にちりばめた。ぜひ、参考にしてください。
|
| 18 |
+
|
| 19 |
+
# 小学校6年間の図形の教え方
|
| 20 |
+
|
| 21 |
+
[CHUNK]
|
| 22 |
+
## 図形学習の導入と苦手意識克服
|
| 23 |
+
図形問題が苦手な子どもは多い。図形問題を解く力は、身の回りの図形を実際に見て、触って、手を動かす経験で伸ばせる。行き詰まったら、問題から離れ、日常生活で図形に親しむ機会を増やそう。
|
| 24 |
+
図形が得意な子は、つみきや折り紙が好きで、身の回りにある形に気づきやすい。苦手な子は、図形と自分との関わりを感じにくく、面積の公式などを暗記に頼りがちである。
|
| 25 |
+
|
| 26 |
+
[CHUNK]
|
| 27 |
+
## 図形学習における親の役割と教え方のコツ
|
| 28 |
+
図形を教える際は、子どもの中から答えを引き出すことを重視する。自分で答えが出せた経験は自信につながり、解き方の手順も身につく。どんな小さなことでも褒めて、子どものやる気を引き出す。
|
| 29 |
+
結論を一方的に説明するのではなく、「〇〇の公式は覚えてる?」「□□って何だっけ?」と優しく問いかけながら、一緒に考える姿勢が大切。コミュニケーションを取りながら進めることで、図形学習を楽しいものにし、苦手意識を克服する。
|
| 30 |
+
|
| 31 |
+
[CHUNK]
|
| 32 |
+
## 日常生活での図形との触れ合い方
|
| 33 |
+
身の回りにあるものの形を探す(例:将棋の駒は五角形、傘は八角形)。トランプのマークが線対称であることを見つけるなど、遊びの中で図形の性質に触れる。
|
| 34 |
+
自分の体を使って角度を作る(例:座って足を何度まで開けるか)。料理の手伝いを通して、かさの感覚を養う(例:鍋に1Lの水を入れてくれる?)。本書p.14の「お助けアイテム」も参考に。
|
| 35 |
+
公式や手順を丸暗記するのではなく、「なぜそうなるのか」の背景を理解することが重要。感動したことや自分で気づいたことは忘れずに、応用問題にも生かせるようにする。
|
| 36 |
+
|
| 37 |
+
[CHUNK]
|
| 38 |
+
## 作図が苦手な子へのアプローチ
|
| 39 |
+
作図ができるようになると図形全般の理解度が高まる。まずは身近な道具や身の回りのものを使って、手を動かすことから始める。
|
| 40 |
+
対称な図形の感覚を養うには、折り紙を折って切って広げるのが効果的。好きな形を簡単につくれる点、ひっくり返したり裏返したりと図形を実際に動かせる点も優れている。頭の中で図形を動かして考える練習になる。
|
| 41 |
+
|
| 42 |
+
[CHUNK]
|
| 43 |
+
## 作図練習のステップ
|
| 44 |
+
直線を引く練習:定規は目盛りのない面を上にし、利き手と反対の手でしっかり押さえる。定規が動かないように、5~10本、30cmくらいの線を引く。
|
| 45 |
+
コンパス選び:針がしっかり刺さるものを選ぶ。コンパスを使えばきれいな円が自分でかけるという経験は、自信に��ながる。
|
| 46 |
+
図形をなぞってかく:問題集などに載っている図を上からなぞらせる。三角形や四角形、円から始め、複合図形や立体の見取り図など、複雑な図を何度もなぞって自分のものにする。慣れてきたら、図を見ながらノートにかく練習もする。
|
| 47 |
+
|
| 48 |
+
[CHUNK]
|
| 49 |
+
## 親御さんの不安解消と図形学習サポート
|
| 50 |
+
「図形が苦手」「算数が苦手」「応用問題が苦手」という親御さんも大丈夫。本書には、親子で図形に親しみ、図形の問題が得意になるヒントが多数ある。
|
| 51 |
+
本書には、多くの子どもが納得できる解説が書かれているため、親御さんもすんなり理解できる。難しく感じる場合は、前の学年にもどって、基本から1つずつ理解していくとよい。
|
| 52 |
+
|
| 53 |
+
[CHUNK]
|
| 54 |
+
## 図形問題克服のためのアイテム
|
| 55 |
+
図形を身近に感じ、問題をすらすら解けるようにする道具を紹介。勉強のときだけでなく、ふだんの生活や遊びの中に取り入れる。
|
| 56 |
+
定規・メジャー:長さの単位に慣れる。子どもの身長、手の大きさ、指の長さなどを測る。
|
| 57 |
+
三角定規:平行や垂直な線を引く。直角三角形の典型的な見本として覚えておく。
|
| 58 |
+
分度器:角度を測る。家の中のいろいろなものを測ってみる。
|
| 59 |
+
|
| 60 |
+
[CHUNK]
|
| 61 |
+
## 図形学習をサポートするアイテム(続き)
|
| 62 |
+
コンパス:円をかく。作図のときにも頻繁に使用。円をたくさんかいてコンパスの扱いに慣れる。
|
| 63 |
+
計量カップ・計量スプーン:かさや重さの単位を実感。1Lのペットボトルに水を入れて、1kgの重さを体感させる。
|
| 64 |
+
折り紙:折ったり、切ったり、楽しみながら図形の性質を身につける。三角形、四角形、角度、対称な図形など、活用方法は無限。
|
| 65 |
+
空き箱:立体の感覚をつかむ。ティッシュペーパーの空き箱は、開いて展開図にできるなど活用しやすい。
|
| 66 |
+
方眼用紙:正確な図形の感覚を身につけるために便利。5mm方眼がおすすめだが、ノートのマス目を利用してもOK。
|
| 67 |
+
|
| 68 |
+
[CHUNK]
|
| 69 |
+
## 単位の理解:視覚的アプローチの重要性
|
| 70 |
+
単位は、「何倍の関係か」を視覚的に身につけることが重要。
|
| 71 |
+
牛乳パックはサイコロ1000個分:1辺の長さ1cm (1cm³=1mL) の市販のサイコロを1個用意し、1000個集めると牛乳パック1個の大きさ(1000cm³)になることを視覚的に理解させる。計量カップ (200mL)で、空の牛乳パックに水を入れ、5杯でいっぱいになることを確認するのも効果的。
|
| 72 |
+
|
| 73 |
+
[CHUNK]
|
| 74 |
+
## 水の体積と重さの関係を体感する
|
| 75 |
+
水の体積と重さの関係を実感させる:計量カップをのせた状態で0gに合わせたはかりを使って、水の重さを実際に確かめる。
|
| 76 |
+
100mL (100cm³) の水の重さが100gということが確認できたら、「実は重さの単位は水の重さを基準に決められているんだって」と声かけを。理科の勉強にも役立つ、とても大切な感覚が身につく。
|
| 77 |
+
単位の変換をするときは、0がいくつ増える・減る関係か、イメージがわくようになるとよい。
|
| 78 |
+
|
| 79 |
+
[CHUNK]
|
| 80 |
+
## 単位換算の注意点と練習問題
|
| 81 |
+
単位換算では、かくれた「0」を見逃さないように注意する。
|
| 82 |
+
例:1L50mL = (1050)mL。上下にケタをそろえて筆算を書くように伝え、かくれた100の位の「0」を見せて意識させる。方眼ノートを使ってみるのも効果的。
|
| 83 |
+
単位の変換をするときは、0がいくつ増える・減る関係か、イメージがわくようになるとよい。
|
| 84 |
+
|
| 85 |
+
# 小学校算数つまずきポイント解決ナレッジベース
|
| 86 |
+
|
| 87 |
+
[CHUNK]
|
| 88 |
+
## 2年生: くり下がりのある単位の計算 (cm, mm)
|
| 89 |
+
2年生でつまずきやすい、くり下がりのある単位の計算(例:3cm2mm - 1cm7mm)について解説します。前提として、1m=100cm、1cm=10mmといった基本的な単位の知識が定着している必要があります。本質的な理解のため、最初はmmに変換して計算し、慣れてきたらcmとmmのまま計算する方法を練習します。mmに直して計算する際は、3cm2mmを32mm、1cm7mmを17mmに変換し、32mm - 17mm = 15mm = 1cm5mmと計算します。cmとmmのまま筆算する場合は、位を揃えて書き、1cmを10mmとして繰り下げて計算します。
|
| 90 |
+
|
| 91 |
+
[CHUNK]
|
| 92 |
+
## 2年生: くり下がりのある単位の計算練習と指導のポイント
|
| 93 |
+
cmとmmのまま筆算する場合は、位を揃えて書き、1cmを10mmとして繰り下げて計算します。単位換算の練習として、「3cmは何mm?」「3cm2mmは何mm?」といった質問を投げかけ、基本的な単位間の関係を理解させることが重要です。いきなり「3cm2mmは何mm?」と聞くのではなく、「1cmは���mm?」「1mは何cm?」「1kgは何g?」といった基本的な単位間の関係を声かけしながら練習することがポイントです。練習問題として、5cm4mm-3cm6mm、1m45cm-77cm、2kg300g-1kg600g、5L3dL-3L7dL、3m7cm-89cmなどが考えられます。
|
| 94 |
+
|
| 95 |
+
[CHUNK]
|
| 96 |
+
## 2年生: 間に0が入る単位の変換 (m, cm)
|
| 97 |
+
2年生でつまずきやすい、間に0が入る単位の変換(例:3m7cm = cm)について解説します。長さ、かさ、重さの単位の変換が定着していないと、見たままの数字で答えてしまうことがあります。1m=100cmということがしっかり定着していないと、省略されている0に気づけず「3m7cm=37cm」といったミスをしてしまいます。3m7cm = 37cm ?という誤答に対して、3と7の間の0に気づいていないことを指摘します。
|
| 98 |
+
|
| 99 |
+
[CHUNK]
|
| 100 |
+
## 2年生: 単位変換の指導と練習問題
|
| 101 |
+
3m7cm = 37cm ?という誤答に対して、3と7の間の0に気づいていないことを指摘します。「3mは何cm?」の声かけとケタをそろえた書き方を習慣づけることで、あわててミスすることがなくなります。3m = 300cm、7cmをたてにそろえて書く練習をします。方眼ノートを使うと、そろえて書きやすいでしょう。「3mは300cm」と書いて、「7cm」も書いて、目で見て確認します。その中で「ケタをそろえる」を習慣にするのが最大のポイントです。練習問題として、4m8cm=( )cm、12m5cm=( )cm、4L80mL=( )mL、105cm=( )m( )cm、3075mL =( )L( )mLなどが考えられます。
|
| 102 |
+
|
| 103 |
+
[CHUNK]
|
| 104 |
+
## 6年生: 水のかさ、重さ、体積の変換 (L, mL, cm³)
|
| 105 |
+
6年生でつまずきやすい、水のかさ、重さ、体積の変換(例:水1L500mLの重さ)について解説します。ものの重さは水を基準に決まっていて、水1mLの重さを1gとしています。つまり体積の単位を正しく知っておくことで、水の重さがわかるようになります。cm³とL(リットル)、dL(デシリットル)、mL(ミリリットル) の関係がわかっていないと、まちがえてしまいます。1L500mLの重さは何gか?という問題に対して、1Lは何mLだったっけ?という疑問が生じます。
|
| 106 |
+
|
| 107 |
+
[CHUNK]
|
| 108 |
+
## 6年生: 体積と重さの関係理解と練習問題
|
| 109 |
+
1L500mLの重さは何gか?という問題に対して、1Lは何mLだったっけ?という疑問が生じます。1cm³と1mLは同じ量です。そして1Lは1000mL (1000cm³)です。だから1L500mLは1500 cm³ (mL) となることを確認します。体積と重さの変換を、くり返し質問することが重要です。かさから体積、重さから体積、体積から重さと何度もくり返し質問して、答えてもらうようにしましょう。1Lのペットボトルに水を入れて、量と重さを確認するのもよいでしょう。水1cm³ = 1g、1000cm³ = 1000g、1L = 1kgという関係を理解させます。「重さの単位は水を基準に決められている」と伝えると、多くの子どもが「へ~そうなんだ!」とおどろきます。そんなおどろきが、忘れない記憶のもとになります。練習問題として、次の量の水の重さは何gですか。980mL、2L400mL、1200 cm³、1L3dL、2.5Lなどが出題できます。
|
| 110 |
+
|
| 111 |
+
[CHUNK]
|
| 112 |
+
## 図形の性質: 分度器と角度の理解
|
| 113 |
+
図形の性質の理解におけるつまずきを解消します。分度器の性質、使い方、「1周の角=360°」を理解することが重要です。まずは「かいてみて確かめる」ことを習慣にしましょう。例として、正方形の対称の軸はいくつありますか?という問題を通して、図形を実際に描いてみることで理解を深めます。対称の軸とは、1つの図形を2つの同じ形に分ける線のことですが、まずは「かいてみてごらん」という声かけを。そしてさらに声かけで正しい考え方、気づきに導いてあげましょう。
|
| 114 |
+
|
| 115 |
+
[CHUNK]
|
| 116 |
+
## 図形の性質: 角度の測定と練習問題
|
| 117 |
+
正方形の対称の軸を求める問題を通して、図形を実際に描いてみることで理解を深めます。「ちょっとかいてみてごらん」といった声かけをすることで、子どもたちは自ら考え、試行錯誤することができます。正五角形・正六角形の対称の軸を全部かいてみましょう。角度の問題では、「平行線→同じ大きさの角ができる」ということをおさえておきましょう。また、拡大図・縮図では、「1つの点(線)を固定してかく」ことが、作図のポイントです。角度の大きさの概算を問う問題を通して、角度の感覚を養います。
|
| 118 |
+
|
| 119 |
+
[CHUNK]
|
| 120 |
+
## 4年生: 直角より大きな角の理解
|
| 121 |
+
4年生でつまずきやすい、直角より大きな角(鈍角)の理解について解説します。例として、鈍角の角度を求める、水���より大きな角度を求める問題を取り上げます。「角」というのは、とがっているもの、開き方がせまいものだけではありません。90°(直角)や180°(水平)をこえる角もあることがつかめるようにしましょう。90°をこえる角を「角」と考えられない場合、鈍角(90°より大きく開いた角)を角として考えられず、どう測ったらよいかがわからないことがあります。
|
| 122 |
+
|
| 123 |
+
[CHUNK]
|
| 124 |
+
## 4年生: 鈍角の測定と指導のポイント
|
| 125 |
+
90°をこえる角を「角」と考えられない場合、鈍角(90°より大きく開いた角)を角として考えられず、どう測ったらよいかがわからないことがあります。「とがっていなくても角だよ」と声かけをすることが重要です。とがっているものだけが角ではないことを伝えます。分度器をあてて、90°より大きい角も分度器で測れること (180°まで測れること)を、確認しましょう。180°より大きい角が測れない場合、「1周360°」 という感覚が身についていないと、大きさの測り方がわかりません。分度器よりも大きな角の測り方がわからない場合は、「ぐるんと1周で360°なんだよ」と声かけをしてあげましょう。小さいほうの角を測るということに自分で気づけるとよいですね。練習問題として、様々な角度の角の大きさを分度器で測る問題に取り組みましょう。
|
| 126 |
+
|
| 127 |
+
# 図形問題最適化ナレッジベース
|
| 128 |
+
|
| 129 |
+
[CHUNK]
|
| 130 |
+
## 角度計算の基本と交差する直線
|
| 131 |
+
角度計算の基本は、交わる直線や平行線における角の性質理解にある。一つの角の大きさがわかれば、分度器を使わずに他の角も計算可能。隣り合う角や対応する角の関係性を把握することが重要。見た目だけで判断せず、理屈に基づいた考え方を養う。角度を測る際は分度器を使用し、54°の角と隣接する角の合計が180°になることを確認する。
|
| 132 |
+
|
| 133 |
+
[CHUNK]
|
| 134 |
+
## 交差する直線における角度の求め方
|
| 135 |
+
54°の角と隣接する角の合計が180°になることを確認する。180°から54°を引いて隣接する角が126°であることを導く。対頂角は等しいという性質を利用し、向かい合う角も54°であることを確認する。平行線においては、他の直線と同じ角度で交わるため、離れた場所でも同じ大きさの角を見つけられる。
|
| 136 |
+
|
| 137 |
+
[CHUNK]
|
| 138 |
+
## 平行線と角度の関係
|
| 139 |
+
平行線においては、他の直線と同じ角度で交わるため、離れた場所でも同じ大きさの角を見つけられる。角度を求める際は、既知の角から順に全ての角を求めることで混乱を防ぐ。分度器を用いて実際に角度を測り、合わせて180°になる角を確認する。平行線が他の直線と交わる際にできる角の関係性を理解する。
|
| 140 |
+
|
| 141 |
+
[CHUNK]
|
| 142 |
+
## 平行線と角度の関係の応用
|
| 143 |
+
平行線が他の直線と交わる際にできる角の関係性を理解することで、未知の角を求める。例えば、110°の角がある場合、その隣の角は180° - 110° = 70°となる。平行線の性質から、対応する角も70°となるため、さらに隣の角は180° - 70° = 110°と計算できる。
|
| 144 |
+
|
| 145 |
+
[CHUNK]
|
| 146 |
+
## 平行と垂直な直線の作図
|
| 147 |
+
平行な直線や垂直な直線を作図する際、三角定規を適切に使用することが重要。特に、斜めになっている直線に対して作図を行う場合、三角定規の使い方が理解度を左右する。目分量で線を引くのではなく、三角定規を用いて正確に作図する習慣を身につける。平行線や垂直線を作図する際は、2つの三角定規を使用する。
|
| 148 |
+
|
| 149 |
+
[CHUNK]
|
| 150 |
+
## 三角定規を用いた平行線作図
|
| 151 |
+
平行線を作図する際は、三角定規の直角部分を基準となる直線に合わせ、もう一枚の三角定規を添える。その後、基準となる三角定規を固定したまま、もう一枚の三角定規をスライドさせることで平行線を作図する。三角定規の直角部分を上手に活用することで、平行な直線を簡単に引けることを体験させる。
|
| 152 |
+
|
| 153 |
+
[CHUNK]
|
| 154 |
+
## 三角定規を用いた垂直線作図
|
| 155 |
+
三角定規の直角部分を基準となる直線に合わせ、もう一枚の三角定規を直角に添えることで垂直線を作図する。三角定規を繰り返し練習することで、作図スキルを向上させる。平行線と垂直線の見分け方では、「見た目」だけで判断せず、三角定規を用いて実際に角度を測り、垂直であるかを確認する。
|
| 156 |
+
|
| 157 |
+
[CHUNK]
|
| 158 |
+
## 平行・垂直な直線の見分け方
|
| 159 |
+
平行・垂直な直線の見分け方では、「見た目」だけで判断せず、三角定規を用いて実���に角度を測り、垂直であるかを確認する。方眼を利用して直線の傾きを確認し、平行であるかを判断する。例えば、直線が右に1マス、下に2マス傾いている場合、別の直線も同じ傾きであれば平行である。
|
| 160 |
+
|
| 161 |
+
[CHUNK]
|
| 162 |
+
## 方眼を用いた平行の確認
|
| 163 |
+
直線が右に1マス、下に2マス傾いている場合、別の直線も同じ傾きであれば平行である。平行な直線を見つける際は、方眼のマス目を数えて傾きを比較する。垂直な直線を見つける際は、三角定規を当てて直角になっているか確認する。
|
| 164 |
+
|
| 165 |
+
[CHUNK]
|
| 166 |
+
## 拡大図・縮図の基本
|
| 167 |
+
拡大図・縮図は、元の図形と同じ形で、すべての辺の長さを一定の割合で拡大または縮小した図形。作図の際には、まず一つの頂点を固定し、そこから各頂点への距離を拡大または縮小する。拡大図や縮図を作成する際、どの頂点を固定するかを最初に決めることが重要。
|
| 168 |
+
|
| 169 |
+
[CHUNK]
|
| 170 |
+
## 拡大図・縮図の作図手順
|
| 171 |
+
拡大図や縮図を作成する際、どの頂点を固定するかを最初に決めることが重要。左下の頂点を固定し、他の頂点までの距離を測り、指定された倍率で拡大または縮小する。コンパスを用いて各頂点の位置を決定し、最後に各頂点を線で結ぶ。拡大図や縮図は、元の図形と形が同じであることが重要。
|
| 172 |
+
|
| 173 |
+
[CHUNK]
|
| 174 |
+
## 拡大図・縮図における辺と角の関係
|
| 175 |
+
拡大図・縮図では、対応する角の大きさは常に等しい。辺の長さは拡大率または縮小率に応じて変化するが、図形の形状は変わらない。拡大図・縮図の問題を解く際には、元の図形と拡大・縮小された図形が「全く同じ形」であることを意識する。
|
| 176 |
+
|
| 177 |
+
[CHUNK]
|
| 178 |
+
## 拡大図・縮図の応用問題
|
| 179 |
+
拡大図・縮図の問題では、辺の長さだけでなく、角の大きさも問われる。例えば、三角形ABCの縮図である三角形DEFにおいて、辺DEの長さが与えられた場合、対応する辺ABの長さを求める。角Eの大きさは、対応する角Bの大きさと等しくなる。
|
| 180 |
+
|
| 181 |
+
# 小学校6年間の図形の教え方
|
| 182 |
+
|
| 183 |
+
[CHUNK]
|
| 184 |
+
## 線対称・点対称な図形の理解と作図のポイント
|
| 185 |
+
小学校6年生で学ぶ線対称・点対称な図形について、特に点対称な図形が苦手な児童が多い。点対称とは何かを丁寧に説明し、理解を深める必要がある。線対称な図形は比較的容易に作図できる。点対称な図形を作図する際には、対応する点を正確にとらえることが重要となる。線対称では、対称の軸に対して同じ長さになっているかを意識することが重要。
|
| 186 |
+
|
| 187 |
+
[CHUNK]
|
| 188 |
+
## 点対称図形の作図: 対応点の特定と線での連結
|
| 189 |
+
線対称な図形は正しくかける子が多いのですが、点対称な図形になると、かけない子がグッと増えます。点対称がどういうことかをしっかり説明してあげましょう。点対称図形を作図する際は、対応する点を一つ一つ丁寧に見つけ、線で結ぶことが重要。各点に記号をふり、質問を重ねることで、対応点を見つけやすくする。すべての点を見つけたら、順番に線でつなぎ、図形を完成させる。
|
| 190 |
+
|
| 191 |
+
[CHUNK]
|
| 192 |
+
## 点対称図形の作図における注意点とアドバイス
|
| 193 |
+
点対称図形をかくのが少し手ごわいですが、「対称の中心までの長さが等しくなる点」を先にかいて、それを結ぶようアドバイスしてあげましょう。点対称では、1つ1つていねいに点をとらないと、線対称と混在してしまうところがあります。線対称みたいに、かんたんにできればいいんだけど……。落ち着いて、まず点をとってみようね。鏡に映したみたいになればいいのかな……? その通り! 長さをよく確認しながらかこうね。
|
| 194 |
+
|
| 195 |
+
[CHUNK]
|
| 196 |
+
## 正多角形と対称性の理解: 線対称と点対称の識別
|
| 197 |
+
正多角形と対称性について学習する。正三角形の対称軸の数や、点対称となる多角形を見つける問題に取り組む。形を見て考えることが大切だが、表にまとめた結果からわかることもある。自分で対称の軸が引けない場合は、正多角形の紙を用意して、折ってみせるとよい。正多角形はすべて線対称であり、辺・頂点の数が偶数のものは点対称でもある。
|
| 198 |
+
|
| 199 |
+
[CHUNK]
|
| 200 |
+
## 正多角形の対称軸の数え方と回転による確認
|
| 201 |
+
正多角形の線対称の「対称の軸」の本数がわからない。辺・頂点の数が多い図形になると混乱するので、まずは正三角形や正方形で、見て確かめることから始めましょう。正三角形は線対称な図形だね。でも対称の���は何本だろう……? 1本はわかるけど……。ほかにもありそうだね。図形を実際に回転させてみる。紙にかいて切り取ってもよいですし、本を持って上下をさかさまにしてもよいでしょう。目で見て確認することがポイントです。
|
| 202 |
+
|
| 203 |
+
[CHUNK]
|
| 204 |
+
## 正多角形の対称性のまとめと練習問題
|
| 205 |
+
180°まわしたらもとの図とぴったり重なるのが点対称だね! 正五角形は無理みたい。正六角形は重なるね! 辺・頂点の数と同じ数だけ対称の軸があることを確認する。正三角形(辺・頂点の数が3)、正方形(辺・頂点の数が4) を使って、対称の軸の数が辺・頂点の数と同じだけあることを確かめましょう。頂点の多い正多角形でも同じことになると納得できれば素晴らしいですね。
|
| 206 |
+
|
| 207 |
+
[CHUNK]
|
| 208 |
+
## 対称の中心と対応点の特定: 平行四辺形を例に
|
| 209 |
+
点対称図形には、必ず「対称の中心」 と 「対応する点」があります。自分で見つけられるようにしましょう。点対称図形の「対称の中心」を目分量で答える。対称の中心の見つけ方がわからず、「だいたい」で答えてしまうことがあります。このあたり? だいたいこのあたりかな……? わかりやすい「対応する点」を結ぶ。わかりやすい「対応する点」を結んで、その交点を調べることで「対称の中心」を見つけることができる。
|
| 210 |
+
|
| 211 |
+
[CHUNK]
|
| 212 |
+
## 対称の中心の見つけ方と対応点の関係性
|
| 213 |
+
「点Aはくるんと180°まわると、どこにくる?」と声かけをして「対応する点」を見つけられるよう促しましょう。どの点とどの点が対応してるかな? AとCかな? あとはBとD? そう! どの点も、対称の中心から等しい距離にあるんだよね? じゃあ、こう? その通り! 対応する点どうしを結んで交わったところが対称の中心だね! つねに対称の中心を探す。まずは対称の中心を見つけないと、対応する点は特定できません。点対称では対称の中心が重要だということを伝えましょう。
|
| 214 |
+
|
| 215 |
+
[CHUNK]
|
| 216 |
+
## 対応点の特定: 対称の中心からの距離と方向
|
| 217 |
+
180° 「くるん」とまわしたとき、どのあたりにくるかっていうことだよね。ちょうど反対側にくるね。何に対して反対なのかな? あ! 「対称の中心」だ! わかりやすく見つけられる「対応する点」から「対称の中心」を見つけることもできるし、「対称の中心」から「対応する点」を見つけることもできます。大切なのは「だいたい」で済まさないことです。
|
| 218 |
+
|
| 219 |
+
# 小学校算数_図形_RAG最適化
|
| 220 |
+
|
| 221 |
+
[CHUNK]
|
| 222 |
+
## 単位換算の基本と「単位のはしご」の概念
|
| 223 |
+
単位換算は、L(リットル)、mL(ミリリットル)、kg(キログラム)、g(グラム)など、体積や重さを別の単位に変換する際に重要。1kg = 1000gのような関係を利用。単位換算を容易にするツールとして「単位のはしご」を紹介。特に1000倍で単位が変わる体積や重さに有効。7マスの「はしご」を利用し、単位を視覚的に変換。
|
| 224 |
+
単位のはしごは、体積や重さの単位換算を容易にする視覚的ツール。1000倍で単位が変わる場合に特に有効。
|
| 225 |
+
|
| 226 |
+
[CHUNK]
|
| 227 |
+
## 「単位のはしご」を使った体積と重さの単位換算
|
| 228 |
+
「単位のはしご」は、体積(KL, L, mL)や重さ(t, kg, g)の単位換算に適用可能。例として、14850gをkgに変換するケースを提示。1kg=1000gの関係から、14.85kgと算出。はしご上で小数点位置を調整することで、単位換算を視覚的にサポート。1L=10dLのような関係も考慮し、必要に応じてdLを追記。長さ(mm, cm, m, km)や面積(mm², cm², m², a, ha, km²)でも同様の「単位のはしご」が作成可能。
|
| 229 |
+
長さや面積、水のかさと重さの単位換算にも「単位のはしご」は応用可能。
|
| 230 |
+
|
| 231 |
+
[CHUNK]
|
| 232 |
+
## 三角形と四角形の学習導入と作図の基本
|
| 233 |
+
part3では、身近な三角形と四角形を通して図形の知識を深める。三角形・四角形の性質や面積など、図形問題の基礎を習得。作図の基本として、コンパスと分度器の適切な使用法を解説。例として、定規、コンパス、分度器の中から、三角形作図に必要な道具を選択する問題。角度情報がない場合、定規とコンパスを使用。
|
| 234 |
+
三角形と四角形の学習では、図形問題の基礎を習得し、コンパスと分度器の適切な使用法を理解する。
|
| 235 |
+
|
| 236 |
+
[CHUNK]
|
| 237 |
+
## コンパスを用いた作図と四角形の性質理解
|
| 238 |
+
コンパスは、長さの取得に利用。10cmの辺を描いた後、コンパスで8cmと6cmの長さを設定し、交点を結んで三角形を作図。長さが既知の場合は定規とコンパス、角度が既知の���合は定規と分度器を使用。四角形の性質理解では、特徴の少ない順(台形→平行四辺形→長方形→ひし形→正方形)に確認。
|
| 239 |
+
コンパスは長さの取得に利用し、四角形の性質は特徴の少ない順に確認することで効率的に理解する。
|
| 240 |
+
|
| 241 |
+
[CHUNK]
|
| 242 |
+
## 四角形の分類と特徴、複合図形の面積計算
|
| 243 |
+
各四角形(台形、平行四辺形、長方形、ひし形、正方形)の特徴を整理。例えば、平行四辺形は2組の辺が平行で長さが等しい。長方形は4つの角が全て直角。ひし形は対角線が垂直に交わる。複合図形の面積を求める際は、足し算だけでなく引き算も利用。全体から不要部分を引くことで計算を簡略化。
|
| 244 |
+
四角形は特徴の少ない順に分類し、複合図形の面積計算は引き算も利用することで簡略化する。
|
| 245 |
+
|
| 246 |
+
[CHUNK]
|
| 247 |
+
## 複合図形の面積計算例と三角形の合同条件
|
| 248 |
+
複合図形の面積計算例として、複雑な図形を長方形と三角形に分割し、それぞれの面積を足し合わせる方法と、長方形から不要な三角形を引く方法を比較。三角形の合同条件(2辺とその間の角、2角とその間の辺、3辺)を提示。合同条件に基づき、図形が合同であるかを判断。
|
| 249 |
+
複合図形の面積計算は、分割して足す方法と全体から引く方法を比較検討。三角形の合同条件を理解し、図形の合同判断を行う。
|
| 250 |
+
|
| 251 |
+
[CHUNK]
|
| 252 |
+
## 二等辺三角形の作図と平行四辺形の作図
|
| 253 |
+
二等辺三角形の作図では、コンパスを使用。指定された辺の長さ(例:8cm、6cm、6cm)で三角形を作図。定規のみでの作図は困難。平行四辺形の作図では、4点目を試行錯誤で決定。平行四辺形になる点を複数試し、平行四辺形の性質を理解。
|
| 254 |
+
二等辺三角形の作図にはコンパスを使用し、平行四辺形の作図は試行錯誤を通して理解を深める。
|
| 255 |
+
|
| 256 |
+
[CHUNK]
|
| 257 |
+
## 平行四辺形の作図と試行錯誤の重要性
|
| 258 |
+
平行四辺形の作図では、与えられた3点から4つ目の点を決定。試行錯誤を通じて、平行四辺形を完成させる。試行錯誤力は算数の重要な要素。平行四辺形にならない場合でも、手を動かして試すことが重要。
|
| 259 |
+
平行四辺形の作図は試行錯誤を通して理解を深め、試行錯誤力を養う。
|
| 260 |
+
|
| 261 |
+
# 図形の教え方
|
| 262 |
+
|
| 263 |
+
[CHUNK]
|
| 264 |
+
## 四角形の対角線と類推
|
| 265 |
+
四角形の対角線から四角形を類推する問題。対角線の端点を結び四角形を完成させる。微妙な図形は四角形の性質から考える。対角線から四角形をイメージできない場合は、与えられた対角線の端を結んでみる。
|
| 266 |
+
|
| 267 |
+
[CHUNK]
|
| 268 |
+
## 対角線の特徴と四角形の関係
|
| 269 |
+
与えられた対角線の端を結び四角形を完成させる。四角形とその対角線をかいて確認する。対角線とあるから、それぞれの端を結ぶ。四角形は対角線から読み取れる。各四角形の特徴を整理し復習する。向きのイメージで形を覚えている場合、向きだけでなく対角線の特徴を考える。
|
| 270 |
+
|
| 271 |
+
[CHUNK]
|
| 272 |
+
## 四角形の対角線と特徴の整理
|
| 273 |
+
向きだけでなく対角線の特徴を考える。次の図のような対角線をもつ四角形はどんな四角形か考える。四角形の特徴を表にまとめる問題。実際に四角形をかいてみて、辺の長さ、角の大きさ、対角線の長さや交わり方などを思い出してみることが大切。
|
| 274 |
+
|
| 275 |
+
[CHUNK]
|
| 276 |
+
## 四角形の特徴の整理と図形
|
| 277 |
+
それぞれの四角形について、特徴がわかりやすい図がないと、うまくかけない。教科書や参考書の図を参考に、いろいろな四角形の図を子どもにかかせ、特徴を言い合ってみる。四角形の名前、特徴をまとめる。2本の対角線が垂直に交わるか、長さが等しいか、まん中で交わるか、角がすべて直角か、向かい合った辺が平行か、辺の長さがすべて等しいかなどを確認する。
|
| 278 |
+
|
| 279 |
+
[CHUNK]
|
| 280 |
+
## 四角形の特徴と図形の分類
|
| 281 |
+
四角形の特徴をまとめる。図のア〜エにあてはまる四角形を考える。四角形、1組の辺が平行、2組の辺が平行、角がすべて直角、4本の辺の長さが等しいなどの条件から図形を特定する。
|
| 282 |
+
|
| 283 |
+
[CHUNK]
|
| 284 |
+
## 長方形の面積を求める
|
| 285 |
+
L字形やコの字形の図形の面積を求める問題。「切り分けて求める」発想に加え、「いらないところを引く」発想も重要。大きな四角形からいらない部分を引く発想ができない場合、「引き算」に抵抗があると「切り分けて求める」となりがち。問題によっては手間が多くまちがいやすくなる。
|
| 286 |
+
|
| 287 |
+
[CHUNK]
|
| 288 |
+
## 面積計算の工夫
|
| 289 |
+
手間が多くまちがいやすくなる場合がある。計算し���すい形に変える。「切り分けて求める」ができたら、「いらないものを引く」という発想を促す。上と下に切り分けたり、右と左で考えたり、他の方法があるか検討する。
|
| 290 |
+
|
| 291 |
+
[CHUNK]
|
| 292 |
+
## 図形の面積計算
|
| 293 |
+
確かに「切り分けて足し算」でも正解が出せる問題は多いが、「いらないものを引く」という考え方は、ほかの問題でもよく使うので知っておくとよい。次の図の面積を求める。
|
| 294 |
+
|
| 295 |
+
[CHUNK]
|
| 296 |
+
## 三角形・平行四辺形の高さ
|
| 297 |
+
鈍角になると高さがわからなくなる場合、「底辺と同じ高さのところから、いちばん高いところまで」と考えるようにする。方眼上でどの部分を数えれば高さになるのかわかっていない場合は、平行四辺形の面積の公式は、底辺×高さ。底辺が3cmだとすると、ななめのところが高さかな?と考える。
|
| 298 |
+
|
| 299 |
+
[CHUNK]
|
| 300 |
+
## 図形の高さの考え方
|
| 301 |
+
底辺と同じ高さのところから、いちばん高いところまでが「高さ」と伝える。図形単体で考えるのではなく、底辺を延長する考え方が必要。声かけをして、気づかせてあげる。底辺と同じ高さのところ」つまり底辺の延長線上から頂点までの垂直な線が高さ。
|
| 302 |
+
|
| 303 |
+
[CHUNK]
|
| 304 |
+
## 高さの確認と面積計算
|
| 305 |
+
底辺と同じ高さのところから、いちばんてっぺんまでが「高さ」と確認する。次の図の面積を求める。底辺は4cmで高さも4cm?底辺の年と辺の交差するところを数えている場合、高さは底辺のところから垂直にいちばん高いところまでと教える。
|
| 306 |
+
|
| 307 |
+
[CHUNK]
|
| 308 |
+
## 面積から三角形の高さや辺の長さを求める
|
| 309 |
+
「底辺×高さ→面積」の1方向だけでなく、面積の公式を逆に計算して求める練習を、くり返し行う。公式は「あてはめて答えを出すもの」と思っていて、「わかっていることを書き込んで、未知数を求める」ということができない場合がある。
|
| 310 |
+
|
| 311 |
+
[CHUNK]
|
| 312 |
+
## 面積からの逆算
|
| 313 |
+
面積(答え)はわかっているんだよね?」と声かけをする。面積の公式は「面積を求めるときにだけ使うもの」と思っている子どもは多い。声かけをし、答えを書き込んだ公式を書いてみてあげる。三角形の面積を求める公式は底辺×高さ÷2=面積と教える。
|
| 314 |
+
|
| 315 |
+
[CHUNK]
|
| 316 |
+
## 公式の逆算と面積計算
|
| 317 |
+
小学生にとって、式は「=」の右の答えを出すためのもの」という認識。答えがわかっている式の逆算を一緒に練習して、考え方をマスターさせる。次の図の□にあてはまる数を求める。
|
| 318 |
+
|
| 319 |
+
# 小学校算数図形問題集
|
| 320 |
+
|
| 321 |
+
[CHUNK]
|
| 322 |
+
## 複合図形の面積:道の面積の求め方(四角形内)
|
| 323 |
+
四角形の中の道の面積を求める問題。道の部分の面積は、縦横の重なりがあるため、工夫が必要。糸口を見つけるには、図を移動させるなど、工夫して面積を楽に求める発想が重要。
|
| 324 |
+
道の端への移動による等積変形を利用し、全体から道以外の部分を引く方法が有効。例: 全体(8m×15m)から道以外の部分(6m×13m)を引く。
|
| 325 |
+
冗長な説明を削除し、簡潔な表現に修正。
|
| 326 |
+
|
| 327 |
+
[CHUNK]
|
| 328 |
+
## 複合図形の面積:平行四辺形を含む道の面積
|
| 329 |
+
前のチャンクから50トークンの重複:道の端への移動による等積変形を利用し、全体から道以外の部分を引く方法が有効。例: 全体(8m×15m)から道以外の部分(6m×13m)を引く。
|
| 330 |
+
平行四辺形と長方形が混ざった図形の面積問題。底辺と高さが同じ長方形と平行四辺形は面積が同じであることに着目。長方形の「たて」は平行四辺形の「高さ」にあたる。
|
| 331 |
+
図形を自在に動かすことで、問題を簡略化。底辺と高さを変えなければ面積は変わらない。
|
| 332 |
+
|
| 333 |
+
[CHUNK]
|
| 334 |
+
## 合同な図形:合同の定義と見つけ方
|
| 335 |
+
まったく同じ形・大きさの図形を「合同」と定義。ピッタリと重なるものが合同。裏返しの場合も含む。
|
| 336 |
+
「だいたいの形」が似ているだけで合同と判断しないよう注意。合同=同じ形という認識では不十分。
|
| 337 |
+
辺の長さや角度を書き込むことで、より正確に判断可能。2つの辺とその間の角が同じなら、同じ三角形。直角三角形がわかりやすい。
|
| 338 |
+
|
| 339 |
+
[CHUNK]
|
| 340 |
+
## 合同な図形:合同な図形の見つけ方(続き)
|
| 341 |
+
前のチャンクから50トークンの重複:辺の長さや角度を書き込むことで、より正確に判断可能。2つの辺とその間の角が同じなら、同じ三角形。直角三角形がわかりやすい。
|
| 342 |
+
方眼を活用し、長さを書き込むことで、より正確に合同な図形を見つける。
|
| 343 |
+
「だいたい」で判断せず、具体的な数値で確認することが重要。
|
| 344 |
+
|
| 345 |
+
[CHUNK]
|
| 346 |
+
## 合同な三角形の作図:作図条件の理解
|
| 347 |
+
合同な三角形を作図するには、三角形の合同条件を覚えることが不可欠。条件によって使用する道具が異なる。
|
| 348 |
+
三角形の合同条件が不明確だと、どの道具をどう使えば良いか判断できない。
|
| 349 |
+
三角形の合同条件(3辺相等、2辺夾角相等、2角夾辺相等)を理解させることが重要。
|
| 350 |
+
|
| 351 |
+
[CHUNK]
|
| 352 |
+
## 合同な三角形の作図:作図手順と道具の選択
|
| 353 |
+
前のチャンクから50トークンの重複:三角形の合同条件(3辺相等、2辺夾角相等、2角夾辺相等)を理解させることが重要。
|
| 354 |
+
合同条件に応じて、定規、コンパス、分度器を適切に使い分ける。角度がわかっている場合は分度器、長さのみの場合はコンパスを使用。
|
| 355 |
+
作図手順を具体的に解説。例:底辺を引く→分度器で角度を測る→定規で線を引く。
|
| 356 |
+
|
| 357 |
+
[CHUNK]
|
| 358 |
+
## 三角形の角度:重なりから角度を求める方針
|
| 359 |
+
三角形の重なりから角度を求める問題。不要な角まで求めてしまう誤りを防ぐため、解法の方針を定めることが重要。
|
| 360 |
+
三角形の内角の和や外角の性質など、どの知識を使うか事前に考える。
|
| 361 |
+
「わかる角度」を書き込むだけでなく、必要な角度を絞り込む。
|
| 362 |
+
|
| 363 |
+
[CHUNK]
|
| 364 |
+
## 三角形の角度:解法と知識の活用
|
| 365 |
+
前のチャンクから50トークンの重複:「わかる角度」を書き込むだけでなく、必要な角度を絞り込む。
|
| 366 |
+
必要な角度を特定し、三角形の内角の和(180°)や外角の定理を活用。
|
| 367 |
+
例:三角形DECの内角から角イを求め、角イから角アを求める。
|
| 368 |
+
|
| 369 |
+
# 小学校6年間の図形の教え方
|
| 370 |
+
|
| 371 |
+
[CHUNK]
|
| 372 |
+
## ワークの答え (p.51-75): 図形問題の解答と解説
|
| 373 |
+
|
| 374 |
+
p.51: 中点と垂直に関する問題。図形の中点を求め、垂直な線を見つける。
|
| 375 |
+
p.53: アとエの図形が該当する問題。図形の形状を識別する。
|
| 376 |
+
p.55: 図形の辺の長さを測定し、指定された図形を作成する。図形の辺の長さと形状を理解する。
|
| 377 |
+
p.57: 図形内の指定された位置に頂点を配置し、線で接続する。頂点の位置と線の接続方法を理解する。
|
| 378 |
+
p.59: 平行四辺形、長方形、正方形を識別する。四角形の特性を理解する。
|
| 379 |
+
p.61: 台形、平行四辺形、長方形、ひし形を識別する。四角形の特性を理解する。
|
| 380 |
+
p.63: 図形の面積を計算する。面積の計算方法を適用する。
|
| 381 |
+
p.65: 図形の面積を計算する。単位換算も含む。面積の計算と単位換算を理解する。
|
| 382 |
+
|
| 383 |
+
[CHUNK]
|
| 384 |
+
## 図形の面積計算と形状識別 (p.67-75): 解答と解説 (重複50トークン)
|
| 385 |
+
p.67: 図形の辺の長さを計算する。図形の辺の長さの計算方法を理解する。
|
| 386 |
+
p.69: 図形の面積を計算する。単位換算も含む。面積の計算と単位換算を理解する。
|
| 387 |
+
p.71: アとエ、イとオ、カとクの図形を識別する。図形の形状を識別する。
|
| 388 |
+
p.73: 指定された条件で図形を作成する。分度器と定規の使用方法を理解する。
|
| 389 |
+
p.75: 角度を計算する。角度の計算方法を理解する。
|
| 390 |
+
p.76: 指定された条件で図形を作成する。図形の作成方法を理解する。
|
| 391 |
+
p.77: 図形の面積を計算する。複雑な図形の面積計算方法を理解する。
|
| 392 |
+
|
| 393 |
+
[CHUNK]
|
| 394 |
+
## 三角形・四角形の復習と角の合計 (p.76-80): 図形問題の解答と解説 (重複50トークン)
|
| 395 |
+
p.76: 図形の頂点を指定された位置に配置し、線で接続する。これにより、様々な四角形を作成する。
|
| 396 |
+
p.77: 複雑な図形の面積を計算する。補助線を利用して、図形を分割し、面積を計算する。角度を計算する問題も含む。
|
| 397 |
+
p.78-79: 図形問題の解答。様々な図形の特性を理解し、問題を解決する。
|
| 398 |
+
p.80: コラム: ☆形の角の合計は常に一定であることを解説。三角形の外角の性質を利用して証明する。
|
| 399 |
+
|
| 400 |
+
[CHUNK]
|
| 401 |
+
## 円の基本要素と円周の理解 (p.82-84): 円の定義と円周率 (重複50トークン)
|
| 402 |
+
p.82: 円の基本要素(半径、直径、中心、円周、面積)を定義する。円の各部分の関係性を理解する。
|
| 403 |
+
p.83: 円を8つ折りにする方法とコンパスを使った円の描き方を説明する。円の作成方法を理解する。
|
| 404 |
+
p.84: 円周の長さを実際に測って体感する方法を説明する。円周率(約3.14)を導入する。円周と直径の関係を理解する。
|
| 405 |
+
|
| 406 |
+
[CHUNK]
|
| 407 |
+
## 円の面積とコンパスの使い方 (p.84-87): 円の面積計算と作図 (重複50トークン)
|
| 408 |
+
p.84: 円の面積を求めるために、円を細かく分割して四角形に近似する方法を説明する。円の面積の公式(半径×半径×3.14)を導出する。
|
| 409 |
+
p.85: 円周の長さと直線の長さを比較する��題。円周の概念を理解する。
|
| 410 |
+
p.86: コンパスを使って円をかく方法をステップごとに説明する。コンパスの選び方や準備についても解説する。
|
| 411 |
+
p.87: コンパスを使って実際に円をかく練習問題。指定された点を中心に、指定された半径の円をかく。
|
| 412 |
+
|
| 413 |
+
# 小学校算数図形問題 RAG最適化ナレッジベース
|
| 414 |
+
|
| 415 |
+
[CHUNK]
|
| 416 |
+
## 3年生: 円と四角形 - 半径から長方形の辺を求める
|
| 417 |
+
半径3cmの円が長方形に内接している時、長方形の辺長を求める問題。円の半径と長方形の辺の関係理解が重要。半径は円の中心からどの方向へ引いても同じ長さである点を理解させる。半径が斜めに示されている場合に、縦横の辺との関係を見つけ出すのが難しい。
|
| 418 |
+
|
| 419 |
+
[CHUNK]
|
| 420 |
+
## 3年生: 円と四角形 - 直径と補助線による辺長特定
|
| 421 |
+
半径3cmの円が内接する長方形の辺長を求める。円の直径が長方形の辺と一致することに気づかせる。補助線として、円の中心を通る縦横の線を引き、直径を視覚的に捉えやすくする。直径は半径の2倍であるため、半径から直径を計算する。
|
| 422 |
+
|
| 423 |
+
[CHUNK]
|
| 424 |
+
## 3年生: 円と四角形 - 具体例と演習問題
|
| 425 |
+
半径3cmの円が縦に2つ、横に3つ並んで長方形に内接している場合、縦の長さは直径6cmの2倍で12cm、横の長さは直径の3倍で18cmとなる。半径4cmの円が4つ内接する長方形の縦の長さ、指定された点間の距離を求める演習問題。図形問題は手を動かし、試行錯誤を通じて解法を発見させることが重要。
|
| 426 |
+
|
| 427 |
+
[CHUNK]
|
| 428 |
+
## 5年生: 円と三角形 - 半径を用いた正三角形の作図
|
| 429 |
+
半径2cmの円を利用し、一辺2cmの正三角形を作図する問題。円の半径はどこも同じ長さであるという性質を活用。コンパスを用いて円周上に点を取ることで正三角形を作図できることを体感的に理解する。定規のみで正三角形を作図しようとする誤りを防ぐため、コンパスの使用に慣れさせる。
|
| 430 |
+
|
| 431 |
+
[CHUNK]
|
| 432 |
+
## 5年生: 円と三角形 - コンパスを用いた花びら模様の作図
|
| 433 |
+
半径2cmの円を利用した正三角形作図。円周上にコンパスの針を置き、同じ半径で円を描くことで花びらのような模様を作る。模様の各交点が正三角形の頂点となることを理解する。円とコンパスの性質理解を促し、今後の図形学習への応用力を養う。
|
| 434 |
+
|
| 435 |
+
[CHUNK]
|
| 436 |
+
## 5年生: 円と三角形 - 花びら模様と正三角形の関係
|
| 437 |
+
花びら模様の中心の円に着目すると、内部に6つの正三角形が存在する。円周上の点から半径2cmで半円を描き、元の円との交点を結ぶことで正三角形を作図できる。円とコンパスを用いた作図を通して、図形の性質を視覚的に理解させることが重要。二等辺三角形を作図する演習問題。
|
| 438 |
+
|
| 439 |
+
[CHUNK]
|
| 440 |
+
## 5年生: 円周 - 円周から直径を求める
|
| 441 |
+
円周の長さが30cmの円の半径を概数で求める問題。円周率(3.14)を用いて円周から直径を求める計算。割り算よりも掛け算の関係で理解を深める。「直径×3.14=円周」という関係式を理解させ、既知の情報から未知の情報を導き出す思考力を養う。
|
| 442 |
+
|
| 443 |
+
[CHUNK]
|
| 444 |
+
## 5年生: 円周 - 関係式と質問による理解促進
|
| 445 |
+
円周から直径を求める問題。「直径×3.14=円周」の関係式に既知の円周の長さを代入し、直径を求める式を導き出す。質問形式で子供の知識を引き出し、能動的な問題解決を促す。直径を求めるために割り算が必要となることを理解させる。
|
| 446 |
+
|
| 447 |
+
[CHUNK]
|
| 448 |
+
## 5年生: 円周 - 概数計算と演習問題
|
| 449 |
+
円周から求めた直径を概数で表す。10分の1の位までの概数を求めるには、100分の1の位まで計算し四捨五入する。円周の長さが37.68cmの円の直径を求める演習問題。計算スキルだけでなく、問題文の意味を理解し、適切な公式を選択する能力も重要。
|
| 450 |
+
|
| 451 |
+
[CHUNK]
|
| 452 |
+
## 5年生: おうぎ形のまわりの長さ - 基本概念
|
| 453 |
+
中心角が90°や180°のおうぎ形の周りの長さを求める問題。おうぎ形の弧の長さと半径(または直径)を足し合わせる必要がある。90°は円周の1/4、180°は円周の1/2であるという理解が前提。周りの長さの意味を理解していないと、弧の長さのみを計算して終わってしまう。
|
| 454 |
+
|
| 455 |
+
[CHUNK]
|
| 456 |
+
## 5年生: おうぎ形のまわりの長さ - 計算手順と視覚化
|
| 457 |
+
おうぎ形の周りの長さを求める際、計算の順序を意識させることが重要。弧の長さを計算しただけで終わらないように、計算を始める前に全体の流れを確認する。弧の部分を波線、直径や半径を直線でなぞり、視覚的に区別することで、足し��れを防ぐ。
|
| 458 |
+
|
| 459 |
+
[CHUNK]
|
| 460 |
+
## 5年生: おうぎ形のまわりの長さ - 計算例と演習問題
|
| 461 |
+
中心角90°のおうぎ形の場合、弧の長さは (直径)×3.14÷4 で求められる。求めた弧の長さに半径2つ分の長さを足すことで、周りの長さを算出する。中心角60°のおうぎ形の周りの長さを求める演習問題。図形問題は、視覚的な補助と丁寧な計算が重要。
|
| 462 |
+
|
| 463 |
+
[CHUNK]
|
| 464 |
+
## 5年生: 半円組み合わせ図形の周りの長さ - 全体像把握の重要性
|
| 465 |
+
複数の半円を組み合わせた図形の周りの長さを求める問題。一度に計算しようとせず、個々の半円に分割して考える。各半円の直径と半径を正確に把握し、それぞれの弧の長さを計算する。複雑な図形を単純化し、一つずつ解決していく能力が求められる。
|
| 466 |
+
|
| 467 |
+
[CHUNK]
|
| 468 |
+
## 5年生: 半円組み合わせ図形の周りの長さ - 式の可視化と計算
|
| 469 |
+
個々の半円の周りの長さを式で表現する。各半円の直径を基に、円周の半分の長さを計算する。計算過程を可視化することで、誤りを減らす。各半円の式を縦に揃えて書き、同じ種類の数(3.14など)をまとめて計算する。
|
| 470 |
+
|
| 471 |
+
[CHUNK]
|
| 472 |
+
## 5年生: 半円組み合わせ図形の周りの長さ - 計算効率化と分配法則
|
| 473 |
+
各半円の周の長さを足し合わせる。3.14を各項に分配し、計算を効率化する。分配法則を理解することで、より複雑な計算もスムーズに行えるようになる。複数の半円を組み合わせた図形の周りの長さを求める演習問題。
|
| 474 |
+
|
| 475 |
+
# 図形の教え方
|
| 476 |
+
|
| 477 |
+
[CHUNK]
|
| 478 |
+
## 半円・おうぎ形組み合わせ問題:基本と計算ミス対策
|
| 479 |
+
小学校6年生で学習する半円やおうぎ形を組み合わせた図形の面積問題について解説。計算ミスを防ぐために、式をまとめて3.14のかけ算を1回にすること、3.14にかける数を小さくすることの重要性を説明。分配法則の逆利用で計算を効率化。
|
| 480 |
+
|
| 481 |
+
[CHUNK]
|
| 482 |
+
## 分配法則の逆利用と計算例:半円・おうぎ形組み合わせ問題
|
| 483 |
+
分配法則の逆利用(例:2×10+3×10=(2+3)×10=50円)を解説。複雑な図形の面積計算例として、12×12×3.14÷2 - 8×8×3.14÷2 + 4×4×3.14÷2 = (72-32+8)×3.14 = 48×3.14 = 150.72cm² を提示。式をまとめることで計算が容易になることを示す。
|
| 484 |
+
|
| 485 |
+
[CHUNK]
|
| 486 |
+
## 図形問題応用:半径の異なる円の面積の和
|
| 487 |
+
半径6cmの円と8cmの円の面積の和が、半径何cmの円の面積と等しいかを問う問題。6×6×3.14 + 8×8×3.14 = (36+64)×3.14 = 100×3.14 より、半径10cmの円と等しいことを解説。
|
| 488 |
+
|
| 489 |
+
[CHUNK]
|
| 490 |
+
## 正方形とおうぎ形組み合わせ問題:図形分解と線分図の活用
|
| 491 |
+
正方形とおうぎ形を組み合わせた図形の面積問題について、図を分解して考えることの重要性を解説。1辺が8cmの正方形内の特定部分の面積を求める例題を通して、線分図を使った考え方を練習する。
|
| 492 |
+
|
| 493 |
+
[CHUNK]
|
| 494 |
+
## 線分図による長さの算出:正方形とおうぎ形組み合わせ問題
|
| 495 |
+
線分図を用いて、複雑な図形内の線分の長さを求める方法を解説。AからC、DからB、CからDまでの長さをABから他の線分を引くことで算出する。例:AからCまで = AB - CB = 10 - 7 = 3cm。
|
| 496 |
+
|
| 497 |
+
[CHUNK]
|
| 498 |
+
## 線分図の応用:線分の分割と組み合わせによる問題解決
|
| 499 |
+
ABの中点をEとしたとき、CからE、EからDの長さを線分図で求める。CからDまでの長さはCE+DEで計算。わかっていることを3つの線に分け、AD + CB - AB = CD の関係からCDの長さを求める。
|
| 500 |
+
|
| 501 |
+
[CHUNK]
|
| 502 |
+
## 図形問題の解法:線分図で理解した知識の応用
|
| 503 |
+
線分図で理解した考え方を実際の図形問題に応用する。正方形、三角形、おうぎ形に図形を分割し、それぞれの面積を求める。8cmの正方形、三角形、おうぎ形を組み合わせた図形の面積を計算する例を示す。
|
| 504 |
+
|
| 505 |
+
[CHUNK]
|
| 506 |
+
## 図形面積計算:複数の解法アプローチ
|
| 507 |
+
複数の解法で同一の図形問題(正方形とおうぎ形の組み合わせ)を解く。64 - 50.24 = 13.76cm²、64 - 13.76×2 = 36.48cm²、50.24 - 32 = 18.24cm²、18.24 + 18.24 = 36.48cm²、50.24 + 50.24 - 64 = 36.48cm² など、異なるアプローチで同じ答えが得られることを示す。
|
| 508 |
+
|
| 509 |
+
[CHUNK]
|
| 510 |
+
## 図形問題演習:色を塗った部分の面積を求める
|
| 511 |
+
20cmの正方形内に配置された図形の、色を塗った部分の面積を求める演習問題。線分図で考え方を練習した後、同様の問題に応用する。
|
| 512 |
+
|
| 513 |
+
[CHUNK]
|
| 514 |
+
## 円の復習:円周と面積の計算
|
| 515 |
+
円の復習として、様々な図形の円周の長さと面積を求める問題。半径や直径が与えられた円、半円、扇形などについて、それぞれの円周の長さと面積を計算する。
|
| 516 |
+
|
| 517 |
+
[CHUNK]
|
| 518 |
+
## 図形の面積計算:複合図形
|
| 519 |
+
複合図形において、特定の部分(例:斜線部分)の面積を求める問題。正方形や扇形など、複数の図形が組み合わさった図形について、指定された部分の面積を計算する。
|
| 520 |
+
|
| 521 |
+
[CHUNK]
|
| 522 |
+
## 円の比較と応用:円周と面積の倍数計算
|
| 523 |
+
半径の異なる円(例:半径8cmの円と半径4cmの円)の円周や面積の倍数を計算する問題。文中の空欄に数字を埋める形式で、円の性質を理解する。
|
| 524 |
+
|
| 525 |
+
[CHUNK]
|
| 526 |
+
## 図形の割合:正方形と内接円
|
| 527 |
+
正方形と内接円の関係について、文中の空欄に数字を埋める形式で理解を深める。左の円の面積は、色を塗ってある正方形の面積の約何倍か、正方形の面積が80cm²のとき、中にきっちり入っている円の面積はいくらか、といった問題に取り組む。
|
| 528 |
+
|
| 529 |
+
[CHUNK]
|
| 530 |
+
## 解答:図形問題の解答
|
| 531 |
+
p.85からp.103までのワークの解答を示す。円周、面積、複合図形の面積など、様々な図形問題の解答を一覧で提示。
|
| 532 |
+
|
| 533 |
+
[CHUNK]
|
| 534 |
+
## 解答詳細:図形問題の解答と解説
|
| 535 |
+
p.104とp.105の円の復習問題の解答と解説。円周の長さ、面積、複合図形の面積などを求める計算過程を詳細に説明。図形問題の理解を深める。
|
| 536 |
+
|
| 537 |
+
[CHUNK]
|
| 538 |
+
## 解答詳細:図形問題の解答と解説(続き)
|
| 539 |
+
p.107の図形問題の解答と解説。正方形と円の複合図形における面積計算、円周の長さなどを求める過程を詳細に説明。図形問題の理解を深める。
|
| 540 |
+
|
| 541 |
+
# 小学校算数図形問題RAG最適化ナレッジベース
|
| 542 |
+
|
| 543 |
+
[CHUNK]
|
| 544 |
+
## 円の模様作りと図形観察の導入
|
| 545 |
+
コンパスを使った円の模様作りは、図形への興味を引き出す導入として効果的。同じ半径の円を重ねて描くことで、美しい模様が生まれる。模様作りを通して、図形の規則性や対称性への気づきを促す。半円を組み合わせた図形の円周を調べる活動も、図形観察の基礎となる。模様作りの手順: (1)半径2cmの円を描く。(2)コンパスの幅を変えずに円周上に針を置いて別の円を描く。(3)交点を中心にさらに円を描き、繰り返す。完成した模様から、図形的な特徴(花びらのような形)を発見させる。
|
| 546 |
+
|
| 547 |
+
[CHUNK]
|
| 548 |
+
## 図形観察と円周の関係性
|
| 549 |
+
模様作りを通して、図形の規則性や対称性への気づきを促す。半円を組み合わせた図形の円周を調べる活動も、図形観察の基礎となる。半円を組み合わせた図形の円周の長さを求める問題を通して、円周率の理解を深める。図形の周りの長さを求める際、半径の異なる半円を組み合わせることで、計算の複雑さを増し、応用力を養う。最終的に、最も大きな円の円周と等しくなるという結論を導き出す。
|
| 550 |
+
|
| 551 |
+
[CHUNK]
|
| 552 |
+
## 半円組み合わせ図形の円周計算
|
| 553 |
+
図形の周りの長さを求める際、半径の異なる半円を組み合わせることで、計算の複雑さを増し、応用力を養う。最終的に、最も大きな円の円周と等しくなるという結論を導き出す。例:半径6cm, 4cm, 2cmの半円を組み合わせた図形の周りの長さは、12×3.14で計算できる。計算過程を示すことで、理解を助ける。12×3.14+2+8×3.14+2+4×3.14+2 = (6+4+2)×3.14 = 12×3.14。
|
| 554 |
+
|
| 555 |
+
[CHUNK]
|
| 556 |
+
## 立体の見取り図の描き方とポイント
|
| 557 |
+
空間認識力を養うには、見取り図の作成が不可欠。見取り図を描く際のポイントは、平行線を意識すること。方眼紙を利用して、見取り図の描き方を段階的に習得する。手順:(1)正面の長方形を描く。(2)方眼の格子の点を数えながら平行線を引く。(3)各頂点を線で結ぶ。慣れてきたらフリーハンドで描く練習をする。
|
| 558 |
+
|
| 559 |
+
[CHUNK]
|
| 560 |
+
## 見取り図の応用と斜め線の練習
|
| 561 |
+
各頂点を線で結ぶ。慣れてきたらフリーハンドで描く練習をする。斜め線の傾きを変えることで、様々な方向から見た立体を描く練習をする。見える部分は実線、見えない部分は点線で表現する。立方体の見取り図を例に、斜め線の引き方、実線と点線の使い分けを練習する。
|
| 562 |
+
|
| 563 |
+
[CHUNK]
|
| 564 |
+
## 底面と高さの関係理解
|
| 565 |
+
立体図形の体積を理解するためには、底面と高さの関係を理解することが重要。底面と高さは見る方向によって変わることを、具体例を通して理解する。ティッシュペーパーの箱など身近な物を使って、底面を変えた場合に高さがどう変わるかを確認する。牛乳パックを例に、体積の目安を把握することも有効。
|
| 566 |
+
|
| 567 |
+
[CHUNK]
|
| 568 |
+
## 体積計算における工夫
|
| 569 |
+
牛乳パックを例に、体積の目安を把握することも有効。体積計算では、計算の順序��工夫することで、計算を簡単にすることができる。例:5×15÷2×20の計算を、5×15×(20÷2)とすることで、計算が容易になる。3つの数字のかけ算では、順序を工夫することで計算ミスを減らせる。
|
| 570 |
+
|
| 571 |
+
[CHUNK]
|
| 572 |
+
## 直方体の体積と辺の長さの関係
|
| 573 |
+
直方体の体積から辺の長さを求める問題を通して、体積の理解を深める。□を使った式を立てて計算する方法と、底面積から高さを求める方法を習得する。交換法則を利用して計算を簡単にする方法も有効。例:8×□×15=1080という式を、8×15×□=1080と変形することで、計算が容易になる。
|
| 574 |
+
|
| 575 |
+
[CHUNK]
|
| 576 |
+
## 高さから底面を見つける
|
| 577 |
+
交換法則を利用して計算を簡単にする方法も有効。例:8×□×15=1080という式を、8×15×□=1080と変形することで、計算が容易になる。高さが与えられた場合に、どの面が底面になるかを判断する練習をする。底面に色を塗ることで、視覚的に理解を助ける。体積がわかっている直方体で、辺の長さを求める練習問題に取り組む。
|
| 578 |
+
|
| 579 |
+
# 小学校6年間の図形の教え方
|
| 580 |
+
|
| 581 |
+
[CHUNK]
|
| 582 |
+
## 直方体の体積:複雑な立体の攻略
|
| 583 |
+
直方体を取り除いたり、はり合わせたりする問題では、どちらの考え方でも良いという安心感が重要。体積の基本は(たて)×(よこ)×(高さ)だが、(底面積)×(高さ)も理解することで、立体図形への理解が深まる。複雑な立体に対して抵抗感をなくすため、手順を一つずつ確認し、体感させることが重要。
|
| 584 |
+
|
| 585 |
+
[CHUNK]
|
| 586 |
+
## 複雑な立体の体積:計算手順と教え方
|
| 587 |
+
抵抗感をなくすため、手順を一つずつ確認し、体感させることが重要。「はり合わせ」「取りのぞき」の2つの解法を提示し、両方で解けることを伝える。図に直接書き込み、解く道筋を視覚的に示すことが効果的。例として、複雑な立体を分割し、各部分の体積を計算して合計する方法を示す。
|
| 588 |
+
|
| 589 |
+
[CHUNK]
|
| 590 |
+
## 複雑な立体の体積:計算例と底面積の活用
|
| 591 |
+
各部分の体積を計算して合計する方法を示す。例えば、底面積を分割して考え、それぞれの面積を計算し、合計することで全体の底面積を求める。体積は(底面積)×(高さ)で計算できることを再確認する。
|
| 592 |
+
|
| 593 |
+
[CHUNK]
|
| 594 |
+
## 体積と容積:違いの理解と問題解決
|
| 595 |
+
体積と容積はどちらも「かさ」を表すが、体積は「そのもの自体のかさ」、容積は「入れ物に入るもののかさ」を指す。厚さのある入れ物の場合、体積と容積の違いを理解することが重要。容積を求める際に体積を答えてしまう間違いを防ぐ必要がある。
|
| 596 |
+
|
| 597 |
+
[CHUNK]
|
| 598 |
+
## 体積と容積:計算と単位換算
|
| 599 |
+
容積を求める際に体積を答えてしまう間違いを防ぐ必要がある。体積と容積の問題では、「内のり」の寸法を図に書き込ませることが有効。板の厚さを考慮して内側の寸法を計算し、容積を求める。体積の単位はcm³、容積の単位はmL、Lなどを使用し、単位換算の理解も重要。
|
| 600 |
+
|
| 601 |
+
[CHUNK]
|
| 602 |
+
## 体積と容積:単位換算と板の体積
|
| 603 |
+
mL、Lなどを使用し、単位換算の理解も重要。1mL=1cm³であることを理解し、Lとcm³の相互換算ができるようにする。木の板の体積がどこを指すか理解することも重要。直方体全体の体積から容積を引くことで、木の板の体積を求められることを説明する。
|
| 604 |
+
|
| 605 |
+
[CHUNK]
|
| 606 |
+
## いろいろな立体の体積:底面の見つけ方
|
| 607 |
+
底面を見つけて体積を求める問題では、(底面積)×(高さ)=(体積)の公式を活用する。立体を水平にスライスした際に、どの高さでも切り口が同じになるかを理解させることが重要。図の下の部分が底面だと思い込んでしまうケースがあるので注意が必要。
|
| 608 |
+
|
| 609 |
+
[CHUNK]
|
| 610 |
+
## 立体の体積:底面と高さの特定
|
| 611 |
+
図の下の部分が底面だと思い込んでしまうケースがあるので注意が必要。つみきなどを用いて、実際に触れながら形を確認すると理解が深まる。底面となる面に色をつけさせ、その面を底面にして立体を立てて考える練習をする。
|
| 612 |
+
|
| 613 |
+
[CHUNK]
|
| 614 |
+
## 立体の体積:底面の確認と体積計算
|
| 615 |
+
立体を立てて考える練習をする。立てたときに、どの高さで水平に切っても底面積と同じ形・大きさになるかを確認する。底面と高さを特定できれば、(底面積)×(高さ)で体積を計算できる。
|
| 616 |
+
|
| 617 |
+
# 小学校6年間の図形の教え方
|
| 618 |
+
|
| 619 |
+
[CHUNK]
|
| 620 |
+
## 立体の理解:展開図とパターン認識
|
| 621 |
+
[CHUNK]識別子
|
| 622 |
+
立体把握の重要性:展開図のパターン認識、斜め立体の体積計算。身近な物を活用。
|
| 623 |
+
展開図の学習:ティ���シュ箱の展開で基本を理解。切る位置で形状変化。立方体の展開図は何種類?
|
| 624 |
+
6種類程度の予想に対し、実際は11種類存在することを示す。
|
| 625 |
+
50トークン重複:実際は11種類存在することを示す。
|
| 626 |
+
[CHUNK]
|
| 627 |
+
## 立方体の展開図の種類とパターン
|
| 628 |
+
[CHUNK]識別子
|
| 629 |
+
立方体の展開図の種類:[1-4-1]型(6種)、[1-3-2]型(3種)、[2-2-2]型(1種)、[3-3]型(1種)。
|
| 630 |
+
[1-4-1]型:1段目に1個、2段目に4個、3段目に1個。回転・反転で重複排除。
|
| 631 |
+
[1-3-2]型:1個、3個、2個の順。2段目と3段目の形状固定。
|
| 632 |
+
[2-2-2]型、[3-3]型:各1種類。
|
| 633 |
+
50トークン重複:各1種類。[2-2-2]型、[3-3]型は各1種類。
|
| 634 |
+
[CHUNK]
|
| 635 |
+
## 斜め立体の体積:10円硬貨の積み重ね
|
| 636 |
+
[CHUNK]識別子
|
| 637 |
+
斜め立体の体積:通常の体積計算との関連性。
|
| 638 |
+
問題提起:斜めになった立体の体積の求め方。
|
| 639 |
+
アプローチ:10円硬貨の積み重ねによる視覚的な理解。
|
| 640 |
+
50トークン重複:視覚的な理解。
|
| 641 |
+
[CHUNK]
|
| 642 |
+
## 円柱の体積と斜め変形
|
| 643 |
+
[CHUNK]識別子
|
| 644 |
+
円柱による体積計算:(底面積)×(高さ)で体積を求める。
|
| 645 |
+
斜め変形:積み重ねた硬貨をずらす。高さは変わらない。
|
| 646 |
+
結論:斜めになった立体の体積も(底面積)×(高さ)で計算可能。
|
| 647 |
+
50トークン重複:(底面積)×(高さ)で計算可能。
|
| 648 |
+
[CHUNK]
|
| 649 |
+
## 具体例:円柱と斜め円柱の体積計算
|
| 650 |
+
[CHUNK]識別子
|
| 651 |
+
円柱の体積計算例:底面積3×3=9cm²、高さ12cm、体積9×12=108cm³。
|
| 652 |
+
斜め円柱の体積計算例:底面積2×2×3.14=12.56cm²、高さ12cm、体積12.56×12=150.72cm³。
|
| 653 |
+
50トークン重複:体積12.56×12=150.72cm³。
|
| 654 |
+
[CHUNK]
|
| 655 |
+
## 図形問題演習:まとめワーク
|
| 656 |
+
[CHUNK]識別子
|
| 657 |
+
まとめワーク:part2~part5の復習問題。
|
| 658 |
+
図形学習の総仕上げ。
|
| 659 |
+
間違えた問題は該当単元に戻って復習。
|
| 660 |
+
50トークン重複:該当単元に戻って復習。
|
| 661 |
+
[CHUNK]
|
| 662 |
+
## 計算問題:単位換算と四則演算
|
| 663 |
+
[CHUNK]識別子
|
| 664 |
+
単位・図形の性質/三角形・四角形
|
| 665 |
+
計算問題:単位換算を含む四則演算。kg, g, m, cm, L, dL等の単位。
|
| 666 |
+
例:2kg300g+7kg800g, 3m22cm-1m85cm, 3L2dL-2L6dL, 4kg70g-2kg300g, 2m48cm+1m55cm
|
| 667 |
+
50トークン重複:2m48cm+1m55cm
|
| 668 |
+
[CHUNK]
|
| 669 |
+
## 単位換算と水の重さ
|
| 670 |
+
[CHUNK]識別子
|
| 671 |
+
単位換算:kg→g, m→cm, L→dL, L→mLの換算。
|
| 672 |
+
例:3kg20g = g, 6m5cm = cm, 3L7dL = dL, 4L20mL = mL, 3.7L = mL
|
| 673 |
+
水の重さ:2L (kg) = ( )kg, 1630mL (g) = ( )g, 850cm³ (kg) = ( )kg, 3L4dL (g) = ( )g, 1L480mL (kg·g) = ( )kg( )g
|
| 674 |
+
50トークン重複:1L480mL (kg·g) = ( )kg( )g
|
| 675 |
+
[CHUNK]
|
| 676 |
+
## 角の測定と図形の作図
|
| 677 |
+
[CHUNK]識別子
|
| 678 |
+
角の測定:分度器による角度測定。
|
| 679 |
+
図形の作図:平行線、垂直線の作図。
|
| 680 |
+
50トークン重複:平行線、垂直線の作図。
|
| 681 |
+
[CHUNK]
|
| 682 |
+
## 角の大きさの計算
|
| 683 |
+
[CHUNK]識別子
|
| 684 |
+
角度計算:平行線における角度計算。
|
| 685 |
+
例:ア、イ、ウの角度を求める。
|
| 686 |
+
50トークン重複:ア、イ、ウの角度を求める。
|
| 687 |
+
[CHUNK]
|
| 688 |
+
## 図形の対称性:線対称と点対称
|
| 689 |
+
[CHUNK]識別子
|
| 690 |
+
図形の対称性:線対称な直線、点対称な図形を見つける。
|
| 691 |
+
50トークン重複:点対称な図形を見つける。
|
| 692 |
+
[CHUNK]
|
| 693 |
+
## 図形の拡大と縮小
|
| 694 |
+
[CHUNK]識別子
|
| 695 |
+
図形の拡大・縮小:三角形の2倍の拡大図、1/2の縮図。
|
| 696 |
+
50トークン重複:三角形の2倍の拡大図、1/2の縮図。
|
| 697 |
+
[CHUNK]
|
| 698 |
+
## 対称軸と点対称性の識別
|
| 699 |
+
[CHUNK]識別子
|
| 700 |
+
図形の対称性:線対称の軸、点対称の中心を作図。
|
| 701 |
+
50トークン重複:点対称の中心を作図。
|
| 702 |
+
[CHUNK]
|
| 703 |
+
## 正多角形の対称性
|
| 704 |
+
[CHUNK]識別子
|
| 705 |
+
正多角形の対称性:正方形、正五角形、正六角形、正七角形、正八角形について、対称軸の本数と点対称性の有無を答える。
|
| 706 |
+
50トークン重複:対称軸の本数と点対称性の有無を答える。
|
| 707 |
+
[CHUNK]
|
| 708 |
+
## 平行四辺形の点対称性
|
| 709 |
+
[CHUNK]識別子
|
| 710 |
+
平行四辺形の点対称性:対称の中心を作図。点Pに対応する点を作図。
|
| 711 |
+
50トークン重複:点Pに対応する点を作図。
|
| 712 |
+
[CHUNK]
|
| 713 |
+
## 図形の面積計算
|
| 714 |
+
[CHUNK]識別子
|
| 715 |
+
図形の面積:複合図形の面積計算。長方形から一部を切り取った図形、道幅のある土地の面積。
|
| 716 |
+
50トークン重複:道幅のある土地の面積。
|
| 717 |
+
[CHUNK]
|
| 718 |
+
## 円周の長さと面積
|
| 719 |
+
[CHUNK]識別子
|
| 720 |
+
円:円周の長さと面積を求める。
|
| 721 |
+
50トークン重複:円周の長さと面積を求める。
|
| 722 |
+
[CHUNK]
|
| 723 |
+
## 複合図形の円周と面積
|
| 724 |
+
[CHUNK]識別子
|
| 725 |
+
複合図形:円の一部を含む複合図形の円周の長さと面積を求める。
|
| 726 |
+
50トークン重複:円の一部を含む複合図形の円周の長さと面積を求める。
|
| 727 |
+
|
| 728 |
+
# 小学校6年間の図形の教え方
|
| 729 |
+
|
| 730 |
+
[CHUNK]
|
| 731 |
+
## 立体の体積:台形底面の直方体
|
| 732 |
+
図のような立体の体積を求��る。台形ABCDを底面としたとき、高さは?体積は?台形ABCDを底面とすると、高さは3cm。体積は底面積x高さで求められる。底面積は台形の面積の公式(上底+下底)x高さ÷2で計算。
|
| 733 |
+
|
| 734 |
+
[CHUNK]
|
| 735 |
+
## 台形底面の直方体の体積計算
|
| 736 |
+
高さは何cmですか。体積はいくつになりますか。底面積は(5+8)x3÷2=19.5cm²。体積は19.5cm²x3cm=58.5cm³。したがって、高さは3cm、体積は58.5cm³。
|
| 737 |
+
|
| 738 |
+
[CHUNK]
|
| 739 |
+
## 立体の体積:高さが24cmの直方体
|
| 740 |
+
次の立体の体積を求める。高さをCK=24cmとすると、底面積は?体積は?高さをCKの24cmと考えると、底面の面積は?体積はいくつになりますか。
|
| 741 |
+
|
| 742 |
+
[CHUNK]
|
| 743 |
+
## 底面積と体積の計算:高さ24cmの直方体
|
| 744 |
+
底面積は(6+16)x4÷2=44cm²。体積は44cm²x24cm=1056cm³。したがって、底面積は44cm²、体積は1056cm³。
|
| 745 |
+
|
| 746 |
+
[CHUNK]
|
| 747 |
+
## 木の板で作った直方体の入れ物:容積と水面の高さ
|
| 748 |
+
厚さ1cmの木の板で直方体の入れ物を作る。容積は?42dLの水を入れた時の水面の高さは?入れ物の容積は何cmですか。また、何dLですか。水面の高さは、入れ物の外側の底から何cmですか。
|
| 749 |
+
|
| 750 |
+
[CHUNK]
|
| 751 |
+
## 直方体の入れ物の容積と水面の高さの計算
|
| 752 |
+
入れ物の内側の寸法は、縦37-2=35cm、横22-2=20cm、高さ21-1=20cm。容積は35cmx20cmx20cm=14000cm³=14dL。水42dL=4200cm³。水面の高さは4200cm³÷700cm²=6cm。底板の厚みを足して6+1=7cm。
|
| 753 |
+
|
| 754 |
+
[CHUNK]
|
| 755 |
+
## 体積と単位換算
|
| 756 |
+
次の□にあてはまる数を入れましょう。1L=□dL=□cm³、34000cm³=□dL=□L、0.37L=□dL=□cm³。
|
| 757 |
+
|
| 758 |
+
[CHUNK]
|
| 759 |
+
## L, dL, cm³の単位換算
|
| 760 |
+
1L=10dL=1000cm³、34000cm³=3400dL=34L、0.37L=3.7dL=370cm³。単位換算は、1L=10dL=1000cm³の関係を利用する。
|
| 761 |
+
|
| 762 |
+
[CHUNK]
|
| 763 |
+
## 図形の対称の中心
|
| 764 |
+
まず、対角線の交点から対称の中心を求めます。対称の中心を通って、向かい側の辺と交差するところが、対応する点です。
|
| 765 |
+
|
| 766 |
+
[CHUNK]
|
| 767 |
+
## 図形のまわりの長さと面積の計算
|
| 768 |
+
(まわりの長さ) 37.68cm。半円を組み合わせた図形のまわりの長さは、いちばん大きな半径の円の円周と等しくなります。12×3.14=37.68。
|
| 769 |
+
|
| 770 |
+
[CHUNK]
|
| 771 |
+
## 半径2cmの円周の計算
|
| 772 |
+
(まわりの長さ)25.12cm。半径2cmの円の円周2つ分。4×3.14×2=25.12。
|
| 773 |
+
|
| 774 |
+
[CHUNK]
|
| 775 |
+
## 1辺4cmの正方形の面積
|
| 776 |
+
(面積)16cm²。1辺4cmの正方形と同じ面積。4×4=16。
|
| 777 |
+
|
| 778 |
+
[CHUNK]
|
| 779 |
+
## 図形の面積計算:円と正方形の組み合わせ
|
| 780 |
+
(面積)75.36cm²。6×6×3.14÷2+4×4×3.14÷2-2×2×3.14÷2=18×3.14+8×3.14-2×3.14=(18+8-2)×3.14=24×3.14=75.36。
|
| 781 |
+
|
| 782 |
+
[CHUNK]
|
| 783 |
+
## 立体の体積計算:複合図形
|
| 784 |
+
①472cm²。(12+16)×24-(12×6+16×8)=472。②180m²。(12-2)×(20-2)=180。
|
| 785 |
+
|
| 786 |
+
[CHUNK]
|
| 787 |
+
## 図形の周りの長さの計算
|
| 788 |
+
① (まわりの長さ) 35.7cm。20×3.14÷4+10×2=15.7+20=35.7。
|
| 789 |
+
|
| 790 |
+
[CHUNK]
|
| 791 |
+
## 図形の面積の計算
|
| 792 |
+
(面積)78.5cm²。10×10×3.14÷4=78.5。
|
| 793 |
+
|
| 794 |
+
[CHUNK]
|
| 795 |
+
## 図形の周りの長さの計算:円と線分の組み合わせ
|
| 796 |
+
①24.84。6×3.14÷2+12×3.14÷4+6=3×3.14+3×3.14+6=6×3.14+6=24.84。
|
| 797 |
+
|
| 798 |
+
[CHUNK]
|
| 799 |
+
## 図形の周りの長さの計算:円と線分の組み合わせ
|
| 800 |
+
②33.12。8×3.14+4×2=25.12+8=33.12。
|
| 801 |
+
|
| 802 |
+
[CHUNK]
|
| 803 |
+
## 拡大図と縮図
|
| 804 |
+
2倍の拡大図、1/2の縮図。
|
| 805 |
+
|
| 806 |
+
[CHUNK]
|
| 807 |
+
## 立体の体積計算
|
| 808 |
+
①8。(3+5)×3+2×8=8×3+2×8=96。②112。8×16-4×4=128-16=112。
|
| 809 |
+
|
| 810 |
+
[CHUNK]
|
| 811 |
+
## 立体の体積計算:直方体
|
| 812 |
+
①14000、140。(37-2)×(22-2)×(21-1)=35×20×20=14000。
|
| 813 |
+
|
| 814 |
+
[CHUNK]
|
| 815 |
+
## 立体の体積計算:直方体(内側)
|
| 816 |
+
②7。内のりの底面積:(37-2)×(22-2)=35×20=700cm²。容積は42dLだから、4200cm³。4200÷700=6cm。これに底の板の厚みを加えると、6+1=7。
|
| 817 |
+
|
| 818 |
+
[CHUNK]
|
| 819 |
+
## 単位換算:Lとcm³
|
| 820 |
+
①10、1000。②340、34。③3.7、370。
|
| 821 |
+
|
| 822 |
+
[CHUNK]
|
| 823 |
+
## 平行な直線と垂直な直線
|
| 824 |
+
(平行な直線)と、と。(垂直な直線) おとか。
|
| 825 |
+
|
| 826 |
+
[CHUNK]
|
| 827 |
+
## 正多角形の対称の軸
|
| 828 |
+
正多角形の対称の軸は、辺(角)の数と同じだけあります。ア 4本、イ 5本、ウ 6本、エ 7本、オ 8本。
|
| 829 |
+
|
| 830 |
+
[CHUNK]
|
| 831 |
+
## 点対称な図形
|
| 832 |
+
点対称な図形は、辺(角)の数が偶数のものです。②ア、ウ、オ。
|
knowledge/ORIGINAL/算数/中学入試 割合と比:食塩水、割合、相当算.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/算数/中学入試攻略 下克上算数ドリル【速さ編】.md
ADDED
|
@@ -0,0 +1,808 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 中学入試攻略 下克上算数ドリル【速さ編】
|
| 2 |
+
|
| 3 |
+
[CHUNK]
|
| 4 |
+
## はじめに: 単元特化型問題集の紹介
|
| 5 |
+
この本は、中学受験算数の速さに特化した問題集です。一般的な問題集と異なり、特定の単元(速さ、旅人算、流水算、列車算、時計算)に焦点を当てています。ご家族と一緒に、自分1人で問題を解く力を身につけることを目指します。
|
| 6 |
+
|
| 7 |
+
[CHUNK]
|
| 8 |
+
## 他の問題集との違い: 手書きメモと解法ステップ
|
| 9 |
+
自分1人で問題を解く力を身につける。本書の特色は、手書きの計算メモをそのまま掲載し、先生が目の前で解説しているような安心感を提供します。計算メモをSTEP1からSTEP4で表し、解く順番を分かりやすく解説。関連する言葉や数字を同じ色で表現し、理解を促進します。
|
| 10 |
+
|
| 11 |
+
[CHUNK]
|
| 12 |
+
## 解説の理解度向上と本書の構成
|
| 13 |
+
解く順番を分かりやすく解説。関連する言葉や数字を同じ色で表現し、理解を促進します。本書は、まず問題に挑戦し、わからなかったポイントを後半で確認する構成を採用。定着力とスピードを重視しています。対象者は、中学受験生、速さを学び直したい中学生、保護者です。
|
| 14 |
+
|
| 15 |
+
[CHUNK]
|
| 16 |
+
## 著者紹介と中学受験の経験
|
| 17 |
+
定着力とスピードを重視しています。対象者は、中学受験生、速さを学び直したい中学生、保護者です。著者は山下晃平。中学受験に全敗した経験から、小学生向けの解説ノートを作成し、早稲田大学の附属高校に合格。現在はロジカルスクールの講師を務めています。
|
| 18 |
+
|
| 19 |
+
[CHUNK]
|
| 20 |
+
## 目次: 本書の構成要素
|
| 21 |
+
現在はロジカルスクールの講師を務めています。本書は問題集(p4-18)、解説(p19-74)、算数が得意になるポイント(p74-86)で構成されています。基本問題に特化しており、レベルの高い問題は「さんすうがく」のサイトで無料で提供しています。
|
| 22 |
+
|
| 23 |
+
[CHUNK]
|
| 24 |
+
## 追加問題と問題1: 旅人算
|
| 25 |
+
基本問題に特化しており、レベルの高い問題は「さんすうがく」のサイトで無料で提供しています。
|
| 26 |
+
**問題1**: 8km離れたA町とB町から太郎くんと次郎くんがそれぞれ分速50m、分速100mの速さで向かい合って同時に出発。出会うのは何分後か。
|
| 27 |
+
|
| 28 |
+
[CHUNK]
|
| 29 |
+
## 問題2と3: 反対方向へ進む場合と追いつき問題
|
| 30 |
+
**問題1**: 8km離れたA町とB町から太郎くんと次郎くんがそれぞれ分速50m、分速100mの速さで向かい合って同時に出発。出会うのは何分後か。
|
| 31 |
+
**問題2**: 周囲480mの池を兄弟が反対方向に進む。兄は分速80m、弟は分速40m。何分後に出会うか。
|
| 32 |
+
**問題3**: 弟が家を出て10分後、兄が自転車で追う。弟は毎分70m、兄は分速170m。兄は何分後に追いつくか。
|
| 33 |
+
|
| 34 |
+
[CHUNK]
|
| 35 |
+
## 問題4と5: 池の周回と追いつき問題
|
| 36 |
+
**問題3**: 弟が家を出て10分後、兄が自転車で追う。弟は毎分70m、兄は分速170m。兄は何分後に追いつくか。
|
| 37 |
+
**問題4**: 周囲3600mの池をA,B,Cが周回。Aは毎分120m、Bは毎分90m、Cは毎分60m。AがCと出会い引き返すとBと何分後に出会うか。
|
| 38 |
+
**問題5**: 弟が毎分80mで出発後、25分後に兄が毎分180mで追う。兄は何分後に追いつくか。
|
| 39 |
+
|
| 40 |
+
[CHUNK]
|
| 41 |
+
## 問題6と7: 池の周回と速さの比
|
| 42 |
+
**問題5**: 弟が毎分80mで出発後、25分後に兄が毎分180mで追う。兄は何分後に追いつくか。
|
| 43 |
+
**問題6**: 周囲500mの池をAとBが反対/同じ方向に回る。反対方向では50秒、同じ方向では125秒で出会う。それぞれの速さは。
|
| 44 |
+
**問題7**: 64km離れたP,Q間をA,Bが往復。4時間後に出会い、Aは2時間24分後にQに着く。速さの比とBの速さを求めよ。
|
| 45 |
+
|
| 46 |
+
[CHUNK]
|
| 47 |
+
## 問題8と9: 家からの出発と追いつき問題
|
| 48 |
+
**問題7**: 64km離れたP,Q間をA,Bが往復。4時間後に出会い、Aは2時間24分後にQに着く。速さの比とBの速さを求めよ。
|
| 49 |
+
**問題8**: 3.2km離れたA,Bの家。Bが7時に出発し、Aが7時2分に出発。Aは毎分50m、Bは毎分100m。何分後に出会うか。
|
| 50 |
+
**問題9**: 兄は毎分75m、弟は毎分55m。弟は9時に出発、兄は9時4分に出発。兄は何分後に追いつくか。
|
| 51 |
+
|
| 52 |
+
[CHUNK]
|
| 53 |
+
## 問題10と11: 池の周回と出会い時間
|
| 54 |
+
**問題9**: 兄は毎分75m、弟は毎分55m。弟は9時に出発、兄は9時4分に出発。兄は何分後に追いつくか。
|
| 55 |
+
**問題10**: 周囲1800mの池をA,Bが周回。同じ方向に3時間後、反対方向に30分後に出会う。A,Bそれぞれの速さは。
|
| 56 |
+
**問題11**: Aは30分、Bは20分で池を一周。反対方向に進むと何分後に出会うか。
|
| 57 |
+
|
| 58 |
+
[CHUNK]
|
| 59 |
+
## 問題12と13: ロケットと新幹線
|
| 60 |
+
**問題11**: Aは30分、Bは20分で池を一周。反対方向に進むと何分後に出会うか。
|
| 61 |
+
**問題12**: 秒速25.2kmのロケットが1分20秒で進む距離を、時速168kmの新幹線は何時間かかるか。
|
| 62 |
+
**問題13**: 6kmの坂道、行きは毎時6km、帰りは毎時12km。往復の平均速度は。
|
| 63 |
+
|
| 64 |
+
[CHUNK]
|
| 65 |
+
## 問題14と15: 速さの変化と出会い
|
| 66 |
+
**問題13**: 6kmの坂道、行きは毎時6km、帰りは毎時12km。往復の平均速度は。
|
| 67 |
+
**問題14**: 2.1kmの道のりを、最初は毎分50m、途中から毎分70mで歩き34分。速さを変えたのは何分後か。
|
| 68 |
+
**問題15**: 1km離れたA,Bを太郎は分速45m、次郎は分速80mで出発。どこで出会うか。
|
| 69 |
+
|
| 70 |
+
[CHUNK]
|
| 71 |
+
## 問題16と17: 追いつきと往復運動
|
| 72 |
+
**問題15**: 1km離れたA,Bを太郎は分速45m、次郎は分速80mで出発。どこで出会うか。
|
| 73 |
+
**問題16**: Aが分速64mで出発後、Bが分速80mで追う。何分後に追いつくか。
|
| 74 |
+
**問題17**: 1.2km離れたA,B間をA君は分速70m、B君は分速50mで往復。2回目に出会うのは何分後か。
|
| 75 |
+
|
| 76 |
+
[CHUNK]
|
| 77 |
+
## 問題18と19: 遅れて出発と競争
|
| 78 |
+
**問題17**: 1.2km離れたA,B間をA君は分速70m、B君は分速50mで往復。2回目に出会うのは何分後か。
|
| 79 |
+
**問題18**: Aは分速150mで出発後、忘れ物に気づいたBが車で追う。Bが出発して9分後に出会う。Bは何分後に出発したか。
|
| 80 |
+
**問題19**: 100m走で兄は18秒、妹は20秒。50m走で兄がゴール時、妹は何m後ろか。
|
| 81 |
+
|
| 82 |
+
[CHUNK]
|
| 83 |
+
## 問題20: 一定速度と出会い
|
| 84 |
+
**問題19**: 100m走で兄は18秒、妹は20秒。50m走で兄がゴール時、妹は何m後ろか。
|
| 85 |
+
**問題20**: Q,R間でA,Bが一定速度で出発。20分後に出会い、Aは16分後にRに着く。Bは出発から何分後にQに着くか。
|
| 86 |
+
|
| 87 |
+
# 速さに関する問題集
|
| 88 |
+
|
| 89 |
+
[CHUNK]
|
| 90 |
+
## A君とB君の速さの比
|
| 91 |
+
|
| 92 |
+
A君が4歩あるく間にB君は7歩あるきます。またA君が3歩であるくきょりをB君は6歩で歩きます。A君とB君の速さの比を求めなさい。A君の歩数比と距離比から速さの比を算出。A君の4歩はB君の7歩に相当し、A君の3歩の距離はB君の6歩に相当。速さの比は歩数比と距離比の積で計算。
|
| 93 |
+
|
| 94 |
+
[CHUNK]
|
| 95 |
+
## 水夫の川下り・川上り問題
|
| 96 |
+
|
| 97 |
+
ある水夫が 35km あるところを5時間で下りました。同じところを上るのに7時間かかりました。次の問いに答えなさい。(1) 上りの速さは毎時何kmですか。(2) 下りの速さは毎時何kmですか。下りと上りの時間と距離からそれぞれの速さを計算。下りは5時間で35kmなので、速さは35km/5h。上りは7時間で35kmなので、速さは35km/7h。
|
| 98 |
+
|
| 99 |
+
[CHUNK]
|
| 100 |
+
## 川を往復する船の問題
|
| 101 |
+
|
| 102 |
+
ある川に沿って33km はなれたP町、Q町があります。この間をA、Bの2せきの船が往復しています。Aの船は上りに11時間かかり、下りに3時間かかります。またBの船は6時間かかって上ります。(1)Aの船の上り、下りの速さはそれぞれ毎時何km ですか。(2) 川の速さは毎時何kmですか。(3)Bの船の上りの速さは、毎時何km ですか。(4)Bの船は PQ 町を下るのに何時間かかりますか。A船の上り下りの時間と距離から速さを計算し、川の速さを求める。B船の上り時間から速さを計算し、川の速さを用いて下り時間を求める。
|
| 103 |
+
|
| 104 |
+
[CHUNK]
|
| 105 |
+
## 水夫の川往復問題と流速の計算
|
| 106 |
+
|
| 107 |
+
A、Bの2人の水夫がいます。長さが90kmの川を往復するのにAは上りに15時間かかり、下りに9時間かかりました。Bは上りに18時間かかりました。(1) この川の流速は毎時何km ですか。(2)Aの静水時の速さは毎時何kmですか。(3)Bの下りの速さは毎時何kmですか。(4) この川をBが下るには何時間かかりますか。Aの上り下りの時間と距離から、流速と静水時の速さを計算。Bの上り時間と流速から、Bの静水時の速さと下り時間を計算。
|
| 108 |
+
|
| 109 |
+
[CHUNK]
|
| 110 |
+
## 船の川上り・川下り問題と流速・静水時の速さの計算
|
| 111 |
+
|
| 112 |
+
ある船が川を 144km 上るのに12時間かかり、下るのに8時間かかりました。以下の問いに答えなさい。(1) この川の流れの速さは毎時何kmですか。(2) 船の静水時の速さは毎時何kmですか。上りと下りの時間と距離から、それぞれの速さを計算。流速と静水時の速さを連立方程式で求める。上りの速さ=静水時の速さ-流速、下りの速さ=静水時の速さ+流速。
|
| 113 |
+
|
| 114 |
+
[CHUNK]
|
| 115 |
+
## 静水をこぐ人の速さと川の流れの問題
|
| 116 |
+
|
| 117 |
+
静水をこぐ速さが毎時10.5kmの人が3時間で36km こぎおりました。このとき、以下の問いに答えなさい。(1) 流れの速さは、毎時何kmですか。(2) 上りの速さは、毎時何km ですか。(3)この川を5時間かけて上ると何km進みますか。下りの速さと時間から、流れの速さを計算。静水時の速さから流れの速��を引いて、上りの速さを計算。上りの速さと時間から、上る距離を計算。
|
| 118 |
+
|
| 119 |
+
[CHUNK]
|
| 120 |
+
## 川の流れと船の速度に関する問題
|
| 121 |
+
|
| 122 |
+
流れの速さが毎時3kmの川を、60kmこぎ上るのに10時間かかりました。この川を 24km こぎ下りるのに何時間かかりますか。上りの速さと流れの速さから、静水時の速さを計算。静水時の速さと流れの速さから、下りの速さを計算。下りの速さと距離から、下る時間を計算。
|
| 123 |
+
|
| 124 |
+
[CHUNK]
|
| 125 |
+
## 川の流れと船の速度に関する問題2
|
| 126 |
+
|
| 127 |
+
ある船が70kmの川を上るのに7時間かかり、同じところを下るのに2時間20分かかりました。以下の問いに答えなさい。(1) この船の下りの速さは毎時何kmですか。(2)この川の流速は船の静水時の速さの何倍ですか。上りと下りの時間と距離から、それぞれの速さを計算。流速と静水時の速さを求め、流速が静水時の速さの何倍かを計算。
|
| 128 |
+
|
| 129 |
+
[CHUNK]
|
| 130 |
+
## プールの流水問題
|
| 131 |
+
|
| 132 |
+
1周280mのプールでAは流れと同じ向きに泳いで1周すると3分30秒かかり、流れと反対方向に泳いで1周すると4分40秒かかります。このときAが静水時に進む速さは毎分何mですか。流れに沿った時と逆らった時の時間から、Aの速さと流れの速さを計算。Aの静水時の速さを求める。
|
| 133 |
+
|
| 134 |
+
[CHUNK]
|
| 135 |
+
## 静水時の船の速さと川の流れの問題
|
| 136 |
+
|
| 137 |
+
静水では毎時12km で走る船Aと、毎時16kmで走る船Bがあります。川の下流から上流まで走るとき、Aは10時間、Bは6時間40分かかります。川の流れは毎時何kmですか。AとBの上りの時間と静水時の速さから、川の流れの速さを計算。AとBの速さの差と時間の差から、川の流れを求める。
|
| 138 |
+
|
| 139 |
+
[CHUNK]
|
| 140 |
+
## プールでの流水とうき輪の問題
|
| 141 |
+
|
| 142 |
+
一定の速さで水が流れている1周240mのプールがあります。Aはスタートの位置から水の流れに乗って泳ぎ始めます。それと同時にスタートした位置からうき輪を流したところ、ちょうどAが3周進んだときにうき輪に追いつきました。またAが流れに逆らって泳いだところ、1周泳ぐのに12分かかりました。このとき、以下の問いに答えなさい。ただしAの静水時の速さは一定であるとします。(1) プールの水の流れる速さは毎分何mですか。(2)Aが流れに乗って泳いだとき、1周するのにかかる時間は何分ですか。Aが流れに逆らって泳いだ時間から、Aの静水時の速さを計算。Aが3周泳いだ時間とうき輪が流れた時間が等しいことから、水の流れる速さを計算。Aが流れに乗って泳いだ時の速さから、1周する時間を計算。
|
| 143 |
+
|
| 144 |
+
[CHUNK]
|
| 145 |
+
## 川下りと上りの時間変化問題
|
| 146 |
+
|
| 147 |
+
ある船が 105kmの川を下るのに7時間かかりました。元のところへもどるとき、流れの速さが2倍になったので、11時間40分かかりました。(1) この船の下りの速さは毎時何kmですか。(2) 流速が2倍になった時の上りの速さは毎時何kmですか。(3) この船の静水時のときの速さは毎時何km ですか。下りの時間と距離から、下りの速さを計算。流れの速さが2倍になった時の上りの時間から、上りの速さを計算。静水時の速さと流れの速さを求める。
|
| 148 |
+
|
| 149 |
+
[CHUNK]
|
| 150 |
+
## 川の上り下り問題と流水変化
|
| 151 |
+
|
| 152 |
+
川に沿って 27km はなれてP町、Q町があります。ある船がQ町を出発してP町まで上るのに4時間半かかり、下る時は流水が2倍になったので1時間で下りました。この船の静水時の速さは毎時何km ですか。上りと下りの時間と距離から、上りと下りの速さを計算。流水が2倍になった時の下りの速さから、流水の速さを計算。静水時の速さを求める。
|
| 153 |
+
|
| 154 |
+
[CHUNK]
|
| 155 |
+
## 川の流れと船の速度変化問題
|
| 156 |
+
|
| 157 |
+
ある船が川を 48km 下ったところ8時間かかりました。その後、流速が下るときの2倍になったため同じところを上るのに下った時の2倍の時間がかかりました。この船の静水時の速さは毎時何kmですか。下りの時間と距離から、下りの速さを計算。流速が2倍になった時の上りの時間から、上りの速さを計算。静水時の速さを求める。
|
| 158 |
+
|
| 159 |
+
[CHUNK]
|
| 160 |
+
## 川の上り下り問題と流速変化
|
| 161 |
+
|
| 162 |
+
川にそって39km はなれたP町とQ町があります。ある船がQ町を出発してP町まで上るのに13時間かかり、下る時は流速が上りのときの4倍になったので3時間で下ることができました。この船の静水時の速さは毎時何kmですか。上りの時間と距離から、上りの速さを計算。流速が4倍になった時の下りの時間から、下りの速さを計算。静水時の速さを求める。
|
| 163 |
+
|
| 164 |
+
[CHUNK]
|
| 165 |
+
## 川の往復問���
|
| 166 |
+
|
| 167 |
+
ある船が川上にあるP町とそこから 45km はなれたQ町を往復するのに、上りは9時間、下りは5時間かかりました。(1) 上りの速さは毎時何kmですか。(2) 下りの速さは毎時何kmですか。(3) 船が静水を進むときの速さは毎時何kmですか。上りと下りの時間と距離から、それぞれの速さを計算。静水時の速さを求める。
|
| 168 |
+
|
| 169 |
+
[CHUNK]
|
| 170 |
+
## 川の上り下り問題と静水時の速さ
|
| 171 |
+
|
| 172 |
+
ある船が川上にあるA町とそこから 135km はなれたB町の間を往復するのに、上りは15時間、下りは5時間かかります。(1) 上りの速さは毎時何kmですか。(2) 下りの速さは毎時何km ですか。(3) 船の静水時のときの速さは毎時何km ですか。上りと下りの時間と距離から、それぞれの速さを計算。静水時の速さを求める。
|
| 173 |
+
|
| 174 |
+
[CHUNK]
|
| 175 |
+
## 船の出会い問題
|
| 176 |
+
|
| 177 |
+
静水時の速さが毎時4kmの船A、毎時7kmの船Bがあります。55km はなれた川上のP町をA船が、川下のQ町をB船が向かい合って同時に進みます。A、B両船は出発してから何時間何分後に出会いますか。AとBの速さの和から、出会うまでの時間を計算。
|
| 178 |
+
|
| 179 |
+
[CHUNK]
|
| 180 |
+
## 船の追いつき問題
|
| 181 |
+
|
| 182 |
+
A、Bの2せきの船があります。静水を進む速さはAは毎時40km、Bは毎時20kmです。今 240kmの川を同時にAは川上から、Bは下流の川下から向かい合って進みます。Bはと中で出会った後、16時間たってAの出発地点にとう着することができました。この川の流速は毎時何kmですか。AとBの速さの和から出会うまでの距離を計算。Aが出発地点に戻るまでの時間と距離から、川の流速を計算。
|
| 183 |
+
|
| 184 |
+
[CHUNK]
|
| 185 |
+
## 川の流れと船の速度問題
|
| 186 |
+
|
| 187 |
+
流水の速さが一定の川があります。この川を静水時の速さが一定の船が往復するとき、上りの速さは毎時20km、下りの速さが28km でした。(1) この川の流れの速さは毎時何kmですか。(2) この船の静水時の速さは毎時何kmですか。上りと下りの速さから、川の流れの速さと船の静水時の速さを計算。
|
| 188 |
+
|
| 189 |
+
[CHUNK]
|
| 190 |
+
## 流水の速さが変化する川の問題
|
| 191 |
+
|
| 192 |
+
流水の速さが一定の川があります。この川を静水時の速さが一定の船が往復するとき、上りの速さは毎時24km、下るときは川の速さが5倍になったので、速さが毎時42kmになりました。(1) この川の速さは毎時何kmですか。(2) この船の静水時の速さは、毎時何kmですか。上りと下りの速さから、川の流れの速さと船の静水時の速さを計算。
|
| 193 |
+
|
| 194 |
+
[CHUNK]
|
| 195 |
+
## プールでの速度問題
|
| 196 |
+
|
| 197 |
+
(1) プールで毎分 75mの速さで泳ぐ人が、毎分15mの速さで流れるプールの上流に向かって120m泳ぐには、何分かかりますか。(2) 20m先のプールサイドを歩いているBくんが毎分30mで歩いているとき、Aくんが泳いでBくんに追いつくのは何秒後ですか。ただし、A君はプールと反対向きで進むとします。Aが上流に向かって泳ぐ速さから、120m泳ぐ時間を計算。AとBの速さの差から、追いつくまでの時間を計算。
|
| 198 |
+
|
| 199 |
+
[CHUNK]
|
| 200 |
+
## 静水時の速さが一定の船の問題
|
| 201 |
+
|
| 202 |
+
ある川を静水時の速さが一定の船で80km 下るのに5時間、20km 上るのに2時間半かかりました。この川の流れの速さは毎時何kmですか。下りと上りの時間と距離から、それぞれの速さを計算。川の流れの速さを計算。
|
| 203 |
+
|
| 204 |
+
[CHUNK]
|
| 205 |
+
## 川下り問題
|
| 206 |
+
|
| 207 |
+
ある船が105kmの川を下るのに7時間かかりました。元のところへもどるとき、流れの速さが2倍になったので、11時間40分かかりました。(1) この船の下りの速さは毎時何kmですか。(2) 流速が2倍になった時の上りの速さは毎時何kmですか。(3) この船の静水時の速さは毎時何kmですか。下りの時間と距離から、下りの速さを計算。流れの速さが2倍になった時の上りの時間から、上りの速さを計算。静水時の速さと流れの速さを求める。
|
| 208 |
+
|
| 209 |
+
[CHUNK]
|
| 210 |
+
## 列車のトンネル通過問題
|
| 211 |
+
|
| 212 |
+
ある列車は 840mのトンネルをぬけるのに60秒かかり、466mの橋をわたるのに38秒かかります。列車の長さは何mですか。トンネル通過と橋の通過の時間差から、列車の速さを計算。列車の速さと時間から、列車の長さを計算。
|
| 213 |
+
|
| 214 |
+
[CHUNK]
|
| 215 |
+
## 列車の速度問題
|
| 216 |
+
|
| 217 |
+
長さ450m の列車が、線路ぎわに立っている人の前を9秒で通過しました。この列車の速さは毎時何kmですか。列車の長さと時間から、列車の速さを計算。単位を変換して、毎時何kmで表す。
|
| 218 |
+
|
| 219 |
+
[CHUNK]
|
| 220 |
+
## 列車のトンネル通過問題2
|
| 221 |
+
|
| 222 |
+
一定の速さで走る列車が長さ700mのトンネルを32秒で、電柱の前を4秒で、それぞれ通過しまし��。この列車の長さは何mですか。電柱の前を通過する時間から、列車の速さを計算。列車の速さとトンネル通過時間から、列車の長さを計算。
|
| 223 |
+
|
| 224 |
+
[CHUNK]
|
| 225 |
+
## 列車のトンネル通過問題3
|
| 226 |
+
|
| 227 |
+
長さ120m、時速48.6kmの列車がトンネルに入ってから、列車は40秒間トンネルに完全にかくれていました。このトンネルの長さは何mですか。列車の速さを秒速に変換。トンネルにかくれている時間と列車の速さから、トンネルの長さを計算。
|
| 228 |
+
|
| 229 |
+
[CHUNK]
|
| 230 |
+
## 列車のすれ違い問題
|
| 231 |
+
|
| 232 |
+
長さ120m、時速180kmのA列車と、長さ210m、時速216kmのB列車が、出会ってからすれちがい終わるまでに何秒かかりますか。AとBの速さの和を計算。AとBの長さの和を計算。速さと距離から、すれ違いにかかる時間を計算。
|
| 233 |
+
|
| 234 |
+
[CHUNK]
|
| 235 |
+
## 列車の追い越し問題
|
| 236 |
+
|
| 237 |
+
時速108kmと時速72km で走る電車があります。この列車がそれぞれ反対方向に走るとすれちがうのに10秒かかります。この列車が同じ向きに走ったとき、早い方の列車がおそい方の列車を追いぬくのに何秒かかりますか。すれ違う時間と速さから、列車の長さを計算。同じ向きに走る時の速さの差から、追い抜く時間を計算。
|
| 238 |
+
|
| 239 |
+
[CHUNK]
|
| 240 |
+
## 列車の追い越し問題2
|
| 241 |
+
|
| 242 |
+
長さ150m、時速90kmのA列車が、長さ120mのB列車に追いついてから追いこし終わるまでに30秒かかりました。B列車の速さは毎時何kmですか。AとBの長さの和を計算。AとBの速さの差を計算。速さの差と時間から、Bの速さを計算。
|
| 243 |
+
|
| 244 |
+
[CHUNK]
|
| 245 |
+
## 列車のトンネル通過と追い越し問題
|
| 246 |
+
|
| 247 |
+
速さが19秒で長さが300mの長きょり列車A、速さ毎秒16m で長さ 360mの長きょり列車Bがあります。以下の問いに答えなさい。(1) 列車Aがトンネルを通り抜けるのに12分かかりました。トンネルの長さは何m ですか。(2) 列車Aが列車Bに追いついてから追いこすまでに何秒かかりますか。Aの速さと時間から、トンネルの長さを計算。AとBの速さの差から、追い越す時間を計算。
|
| 248 |
+
|
| 249 |
+
[CHUNK]
|
| 250 |
+
## 電車の通過問題
|
| 251 |
+
|
| 252 |
+
長さ 500m の電車が秒速20mで走っています。以下の問いに答えなさい。(1) この電車がふみきりで待っている太郎くんの前を通過し始めてから通過し終わるまでに何秒かかりますか。(2) この電車が長さ300m の橋をわたり始めてからわたり終わるまでに何秒かかりますか。電車の長さと速さから、太郎くんの前を通過する時間を計算。電車の長さと橋の長さを足し、速さから通過時間を計算。
|
| 253 |
+
|
| 254 |
+
[CHUNK]
|
| 255 |
+
## 時計の角度問題
|
| 256 |
+
|
| 257 |
+
7時51分のとき、時計の長針と短針がつくる小さい方の角度の大きさは何度ですか。7時51分における長針と短針の位置を計算し、角度を求める。
|
| 258 |
+
|
| 259 |
+
[CHUNK]
|
| 260 |
+
## 時計の重なり問題
|
| 261 |
+
|
| 262 |
+
4時と5時の間で、時計の長針と短針が重なる時刻は4時何分ですか。長針と短針の速さの差から、重なる時間を計算。
|
| 263 |
+
|
| 264 |
+
[CHUNK]
|
| 265 |
+
## 時計の角度問題2
|
| 266 |
+
|
| 267 |
+
3時と4時の間で、長針と短針の作る角度が30度になる時はそれぞれ3時何分ですか。長針と短針の速さの差から、30度になる時間を計算。
|
| 268 |
+
|
| 269 |
+
[CHUNK]
|
| 270 |
+
## 特殊な時計の問題
|
| 271 |
+
|
| 272 |
+
ある特別な時計は長針が30秒で1周、短針が2分で1周します。今、長身と短針が反対方向をさして一直線になっています。時計の長針と短針が最初に重なるのは今から何秒後ですか。長針と短針の速さの差から、重なる時間を計算。
|
| 273 |
+
|
| 274 |
+
[CHUNK]
|
| 275 |
+
## 時計の直角問題
|
| 276 |
+
|
| 277 |
+
10時と11時の間で、時計の長針と短針のつくる角が直角になることがあります。2回目に直角になるのは10時何分ですか。長針と短針の速さの差から、直角になる時間を計算。
|
| 278 |
+
|
| 279 |
+
[CHUNK]
|
| 280 |
+
## 時計の重なり問題3
|
| 281 |
+
|
| 282 |
+
時計の長針と短針が2時と3時の間でちょうど重なっています。このとき、以下の問いに答えなさい。(1) このときの時間は2時何分ですか。(2) その後長針と短針が文字ばんのめもりの6をはさんで等しい角度になっている時刻は2時何分ですか。長針と短針の速さの差から、重なる時間を計算。長針と短針が反対側になる時間を計算。
|
| 283 |
+
|
| 284 |
+
[CHUNK]
|
| 285 |
+
## 時計の角度問題4
|
| 286 |
+
|
| 287 |
+
時計の針が5時10分をさしています。このとき、以下の問いに答えなさい。(1) 長針と短針が作る角度で小さいものは何度ですか。(2) 長針が短針を追いこしてから作る角度が90度となるのは5時何分ですか。5時10分における長針と短針の位置を計算し、角度を求める。長針が短針を追い越してから90度になる時間を計算。
|
| 288 |
+
|
| 289 |
+
# 速さ編ドリル
|
| 290 |
+
|
| 291 |
+
[CHUNK]
|
| 292 |
+
## 太郎と次郎の出会い:8kmを分速50mと100mで向かい合う
|
| 293 |
+
8km離れたA町とB町から太郎と次郎がそれぞれ分速50m、100mで向かい合って出発。出会うまでの時間を求める。単位をmに統一し、8km=8100mとする。2人は1分で150m近づくため、8100m÷150m/分=54分後に出会う。面積図による解法も参照。
|
| 294 |
+
|
| 295 |
+
[CHUNK]
|
| 296 |
+
## 池の周回:480mの池を反対方向に進む兄弟の出会い
|
| 297 |
+
周囲480mの池を兄弟が反対方向に進む。兄は分速80m、弟は分速40m。出会うまでの時間を求める。2人は1分で120m近づくため、480m÷120m/分=4分後に出会う。池を円で図示し、反対方向の矢印で示す。面積図による解法も参照。
|
| 298 |
+
|
| 299 |
+
[CHUNK]
|
| 300 |
+
## 弟を追う兄:10分後に自転車で出発、追いつくまでの時間
|
| 301 |
+
弟が家を出て10分後、兄が自転車で追いかける。弟は分速70m、兄は分速170m。兄が出発して追いつくまでの時間を求める。弟は10分で700m進む。兄は毎分100mずつ近づくので、700m÷100m/分=7分後。線分図で距離と速さを視覚化。
|
| 302 |
+
|
| 303 |
+
[CHUNK]
|
| 304 |
+
## 周回池:A,B,Cが反対方向に進む、AとCが出会った後AがBに出会う時間
|
| 305 |
+
周囲3600mの池をA,B,Cが周回。Aは毎分120m、Bは毎分90m、Cは毎分60m。AがCと出会い、その後AがBに出会うまでの時間を求める。AとCは20分後に出会う。AとBは20分で600m離れる。AがBに向かうと毎分210m近づくので、600m÷210m/分=20/7分後。円で図示し、各人物の速度と方向を示す。
|
| 306 |
+
|
| 307 |
+
[CHUNK]
|
| 308 |
+
## 兄が弟を追う:25分後に出発、追いつくまでの時間
|
| 309 |
+
弟が毎分80mで出発後、25分後に兄が毎分180mで追いかける。兄が追いつくまでの時間を求める。弟は25分で2000m進む。兄は毎分100mずつ近づくので、2000m÷100m/分=20分後。線分図で距離と速さを視覚化。
|
| 310 |
+
|
| 311 |
+
[CHUNK]
|
| 312 |
+
## 池の周回:AとBが反対/同じ方向に進む速さを求める
|
| 313 |
+
1周500mの池をAとBが周回。反対方向では50秒、同じ方向では125秒で出会う。AとBの速さを求める。反対方向ではA+B、同じ方向ではA-Bの速さで計算。A+B=10m/秒、A-B=4m/秒。A=7m/秒、B=3m/秒。円で図示し、各人物の速度と方向を示す。
|
| 314 |
+
|
| 315 |
+
[CHUNK]
|
| 316 |
+
## 2地点間の移動:AとBの速さの比とBの速さを求める
|
| 317 |
+
64km離れたP,Q間をAとBが移動。AはPからQへ、BはQからPへ。4時間後に出会い、Aはその後2時間24分でQに到着。AとBの速さの比とBの速さを求める。A:B=5:3、B=6km/時。線分図で距離と時間を視覚化。
|
| 318 |
+
|
| 319 |
+
[CHUNK]
|
| 320 |
+
## 家から家へ:AとBが出発、出会うまでの時間を求める
|
| 321 |
+
AとBの家は3.2km離れている。Bは7時に出発、Aは7時2分に出発。Aは毎分50m、Bは毎分100m。出会うまでの時間を求める。Bは2分で200m進む。残りは3000m。2人は毎分150m近づくので、3000m÷150m/分=20分後。線分図で距離と時間を視覚化。
|
| 322 |
+
|
| 323 |
+
[CHUNK]
|
| 324 |
+
## 弟を追う兄:4分後に出発、追いつくまでの時間を求める
|
| 325 |
+
弟は毎分75m、兄は毎分55mで歩く。弟は9時に出発、兄は9時4分に出発。兄が出発して追いつくまでの時間を求める。弟は4分で220m進む。兄は毎分20mずつ近づくので、220m÷20m/分=11分後。線分図で距離と時間を視覚化。
|
| 326 |
+
|
| 327 |
+
[CHUNK]
|
| 328 |
+
## 池の周回:AとBが同じ/反対方向に進む速さを求める
|
| 329 |
+
周囲1800mの池をAとBが周回。同じ方向では3時間、反対方向では30分で出会う。AとBの速さを求める。同じ方向ではA-B、反対方向ではA+Bの速さで計算。A-B=10m/分、A+B=60m/分。A=35m/分、B=25m/分。円で図示し、各人物の速度と方向を示す。
|
| 330 |
+
|
| 331 |
+
# 速さ編ドリル - RAG最適化
|
| 332 |
+
|
| 333 |
+
[CHUNK]
|
| 334 |
+
## 池の周回:反対方向への進行と出会い
|
| 335 |
+
ある池をAは30分、Bは20分で一周する。AとBが反対方向に進むとき、出会うまでの時間は?解答は12分。池の周りの長さもAとBの速さも不明なため、「仮定」を利用。池の周りを30と20の最小公倍数60と仮定。Aの速さは60÷30=2/分、Bは60÷20=3/分。反対方向なので、近づく速さは2+3=5/分。出会う時間は60÷5=12分。
|
| 336 |
+
|
| 337 |
+
[CHUNK]
|
| 338 |
+
## 池の周回:反対方向への進行と出会い(重複)
|
| 339 |
+
解答は12分。池の周りの長さもAとBの速さも不明なため、「仮定」を利用。池の周りを30と20の最小公倍数60と仮定。Aの速さは60÷30=2/分、Bは60÷20=3/分。反対方向なので、近づく速さは2+3=5/分。出会う時間は60÷5=12分。最小公倍数で仮定すると計算が容易。
|
| 340 |
+
|
| 341 |
+
[CHUNK]
|
| 342 |
+
## ロケットと新幹線:時間計算
|
| 343 |
+
秒速25.2kmのロケットが1分20秒で進む距離を、時速168kmの新幹線で移動するのにかかる時間は?解答は12時間。秒速25.2kmは1秒で25.2km進む速さ。1分20秒は80秒。ロケットは80秒で25.2km/秒×80秒=2016km進む。新幹線は時速168kmなの��、2016km÷168km/時=12時間。
|
| 344 |
+
|
| 345 |
+
[CHUNK]
|
| 346 |
+
## ロケットと新幹線:時間計算(重複)
|
| 347 |
+
解答は12時間。秒速25.2kmは1秒で25.2km進む速さ。1分20秒は80秒。ロケットは80秒で25.2km/秒×80秒=2016km進む。新幹線は時速168kmなので、2016km÷168km/時=12時間。計算ミスを防ぐため単位を秒に統一。面積図で視覚的に理解。
|
| 348 |
+
|
| 349 |
+
[CHUNK]
|
| 350 |
+
## 坂道の往復:平均速度の計算
|
| 351 |
+
6kmの坂道、行きは毎時6km、帰りは毎時12kmの速さで往復。往復の平均速度は何km/時?解答は8km/時。往復の平均速度を求めるには、合計距離と合計時間が必要。距離の合計は6km×2=12km。行きは6km÷6km/時=1時間、帰りは6km÷12km/時=0.5時間。合計時間は1+0.5=1.5時間。平均速度は12km÷1.5時間=8km/時。
|
| 352 |
+
|
| 353 |
+
[CHUNK]
|
| 354 |
+
## 坂道の往復:平均速度の計算(重複)
|
| 355 |
+
解答は8km/時。往復の平均速度を求めるには、合計距離と合計時間が必要。距離の合計は6km×2=12km。行きは6km÷6km/時=1時間、帰りは6km÷12km/時=0.5時間。合計時間は1+0.5=1.5時間。平均速度は12km÷1.5時間=8km/時。単位を時間で統一。面積図で視覚的に理解。
|
| 356 |
+
|
| 357 |
+
[CHUNK]
|
| 358 |
+
## 距離と速さ:速度変化時の時間計算
|
| 359 |
+
2.1kmの道のり、最初は毎分50m、途中から毎分70mで歩き、合計34分。速さを変えたのは何分後?解答は14分後。50m/分で進む時間を○分、70m/分で進む時間を□分と仮定。合計距離は2100m。緑の四角形は70m/分で34分進んだ距離=2380m。青の四角形の面積は2380m-2100m=280m。
|
| 360 |
+
|
| 361 |
+
[CHUNK]
|
| 362 |
+
## 距離と速さ:速度変化時の時間計算(重複)
|
| 363 |
+
解答は14分後。50m/分で進む時間を○分、70m/分で進む時間を□分と仮定。合計距離は2100m。緑の四角形は70m/分で34分進んだ距離=2380m。青の四角形の面積は2380m-2100m=280m。青の四角形の縦は70m/分-50m/分=20m/分。横(時間)は280m÷20m/分=14分。
|
| 364 |
+
|
| 365 |
+
[CHUNK]
|
| 366 |
+
## 向かい合う移動:出会う場所の特定
|
| 367 |
+
1km離れたA,B地点間を、太郎は分速45mでAから、次郎は分速80mでBから同時に出発。出会うのはAから何m?解答は360m。二人の距離と速さを線分図で示す。単位をmに統一。二人が近づく速さは45m/分+80m/分=125m/分。出会うまでの時間は1000m÷125m/分=8分。
|
| 368 |
+
|
| 369 |
+
[CHUNK]
|
| 370 |
+
## 向かい合う移動:出会う場所の特定(重複)
|
| 371 |
+
解答は360m。二人の距離と速さを線分図で示す。単位をmに統一。二人が近づく速さは45m/分+80m/分=125m/分。出会うまでの時間は1000m÷125m/分=8分。太郎はAから45m/分×8分=360m進んだ地点で出会う。速さの単位を揃えることが重要。
|
| 372 |
+
|
| 373 |
+
[CHUNK]
|
| 374 |
+
## 追いかけ:追いつく時間
|
| 375 |
+
Aが分速64mで出発してから8分後、Bが分速80mでAを追跡。Aは出発から何分後に追いつかれる?解答は40分後。AとBの出発時間のずれを考慮。Aが8分で進んだ距離は64m/分×8分=512m。BがAに近づく速さは80m/分-64m/分=16m/分。Bが追いつくまでの時間は512m÷16m/分=32分。
|
| 376 |
+
|
| 377 |
+
[CHUNK]
|
| 378 |
+
## 追いかけ:追いつく時間(重複)
|
| 379 |
+
解答は40分後。Aが8分で進んだ距離は64m/分×8分=512m。BがAに近づく速さは80m/分-64m/分=16m/分。Bが追いつくまでの時間は512m÷16m/分=32分。Aが出発してから追いつかれるまでの時間は32分+8分=40分。問題文をよく読み、問われていることを正確に把握。
|
| 380 |
+
|
| 381 |
+
[CHUNK]
|
| 382 |
+
## 往復運動:2回目の出会い
|
| 383 |
+
1.2km離れたA,B間をA君は分速70mでPから、B君は分速50mでQから向かい合って出発しPQ間を往復。2回目の出会いは何分後?解答は30分後。1.2km=1200m。1回目に出会うまでの時間は1200m÷(70m/分+50m/分)=10分。
|
| 384 |
+
|
| 385 |
+
[CHUNK]
|
| 386 |
+
## 往復運動:2回目の出会い(重複)
|
| 387 |
+
解答は30分後。1.2km=1200m。1回目に出会うまでの時間は1200m÷(70m/分+50m/分)=10分。2回目に出会うまでに2人は合計1200m×2=2400m多く進む必要。2400m÷120m/分=20分。2回目の出会いは10分+20分=30分後。
|
| 388 |
+
|
| 389 |
+
[CHUNK]
|
| 390 |
+
## 自転車と車:追いつく時間
|
| 391 |
+
Aは分速150mで自転車、Bは時速30kmの車でAを追う。BはAの何分後に出発?B出発9分後に追いつく。解答は21分後。速さの単位を統一。30km/時=500m/分。Bが9分で進む距離は500m/分×9分=4500m。
|
| 392 |
+
|
| 393 |
+
[CHUNK]
|
| 394 |
+
## 自転車と車:追いつく時間(重複)
|
| 395 |
+
解答は21分後。速さの単位を統一。30km/時=500m/分。Bが9分で進む距離は500m/分×9分=4500m。Aが4500m進む時間は4500m÷150m/分=30分。BはAより30分-9分=21分遅れて出発。線分図で視覚的に理解。
|
| 396 |
+
|
| 397 |
+
[CHUNK]
|
| 398 |
+
## 短距離走:ゴール時の距離差
|
| 399 |
+
100m走、兄18秒、妹20秒。50m走で兄がゴール時、妹は何m後方?解答は5m。距離を半分にすると時間も半分。兄は50mを9秒、妹は10秒。兄がゴール時、妹はあと1秒。妹は20秒で100m、1秒で5m。
|
| 400 |
+
|
| 401 |
+
[CHUNK]
|
| 402 |
+
## 短距離走:���ール時の距離差(重複)
|
| 403 |
+
解答は5m。距離を半分にすると時間も半分。兄は50mを9秒、妹は10秒。兄がゴール時、妹はあと1秒。妹は20秒で100m、1秒で5m。兄ゴール時、妹は5m後方。工夫して計算量を削減。
|
| 404 |
+
|
| 405 |
+
[CHUNK]
|
| 406 |
+
## 向かい合う移動:出会いと到達
|
| 407 |
+
Q,R間でA,Bが向かい合い出発、20分後に出会い、Aは16分後にR着。Bは出発から何分後にQ着?解答は25分後。Bが20分で進む距離=Aが16分で進む距離。Bの速さを4/分と仮定。Aの速さは(4/分*20分)/16分=5/分。
|
| 408 |
+
|
| 409 |
+
[CHUNK]
|
| 410 |
+
## 向かい合う移動:出会いと到達(重複)
|
| 411 |
+
解答は25分後。Bが20分で進む距離=Aが16分で進む距離。Bの速さを4/分と仮定。Aの速さは(4/分*20分)/16分=5/分。Aが20分で進む距離は5/分*20分=100。BがQに着くまでの時間は100/(4/分)=25分。
|
| 412 |
+
|
| 413 |
+
# 速さに関する問題集
|
| 414 |
+
|
| 415 |
+
[CHUNK]
|
| 416 |
+
## A君とB君の速さの比を求める問題
|
| 417 |
+
A君が4歩あるく間にB君は7歩あるきます。またA君が3歩である距離をB君は6歩で歩きます。A君とB君の速さの比を求めます。A君が4歩あるく時間を28と仮定すると、A君、B君それぞれの1歩あるく時間の比は7:4。ふたりの進む距離を6として、線分図を書くとふたりの歩幅の比は、2:1。A君とB君の速さの比は7×2:4×1=14:4=7:2。
|
| 418 |
+
|
| 419 |
+
[CHUNK]
|
| 420 |
+
## A君とB君の速さの比
|
| 421 |
+
A君とB君の速さの比は1歩あるく時間の比×歩幅の比で求める。A君が4歩あるく時間を28と仮定すると、A君、B君それぞれの1歩あるく時間の比は7:4。ふたりの進む距離を6として、線分図を書くとふたりの歩幅の比は、2:1。A君とB君の速さの比は7×2:4×1=14:4=7:2。
|
| 422 |
+
|
| 423 |
+
[CHUNK]
|
| 424 |
+
## 川の流れに乗る船の速さに関する問題
|
| 425 |
+
ある水夫が35km あるところを5時間で下りました。同じところを上るのに7時間かかりました。上りの速さ、下りの速さ、川の速さ、船の静水時の速さを求めます。上りは7時間かかるので、35km÷7時間=5km/時。下りは5時間なので、35km÷5時間=7km/時。速さの線分図より、川の速さは1km/時、船の静水時の速さは6km/時。
|
| 426 |
+
|
| 427 |
+
[CHUNK]
|
| 428 |
+
## 川の流れに乗る船の速さ
|
| 429 |
+
川の流れに乗る船の速さは、川の速さについても考える必要。川上に進むときはゆっくり、川下に進むときは早くなる。35kmの道のりを7時間かけて進むので、上るときの速さは35km÷7時間=5km/時。同じように川を下るときの速さを計算すると、35km÷5時間=7km/時。速さの線分図より、川の速さは1km/時、船の静水時の速さは6km/時。
|
| 430 |
+
|
| 431 |
+
[CHUNK]
|
| 432 |
+
## 川を往復する船の速さに関する問題
|
| 433 |
+
ある川に沿って33km離れたP町、Q町があります。この間をA、Bの2隻の船が往復。Aの船は上りに11時間、下りに3時間。Bの船は6時間かかって上ります。Aの船の上り、下りの速さ、川の速さ、Bの船の上りの速さ、Bの船の下りの速さを求めます。Aの上り3km/時、下り11km/時。川の速さは4km/時。Bの上り5.5km/時、下り13.5km/時。
|
| 434 |
+
|
| 435 |
+
[CHUNK]
|
| 436 |
+
## 川を往復する船の速さの計算
|
| 437 |
+
33kmの川を上るまでに11時間かかっているので、33km÷11時間=3km/時。下るときは3時間なので、33km÷3時間=11km/時。川を上ったり下ったりする問題では川の速さを考える。川の速さを①とすると、②=8km/時。川の速さ×2=8km/時なので、川の速さは4km/時。Bの上るときに進む速さは33km÷6時間=5.5km/時。下りの速さは、5.5km/時+8km/時=13.5km/時。
|
| 438 |
+
|
| 439 |
+
[CHUNK]
|
| 440 |
+
## 川を往復する水夫の速さに関する問題
|
| 441 |
+
A、Bの2人の水夫がいます。長さが90kmの川を往復するのにAは上りに15時間、下りに9時間。Bは上りに18時間かかりました。川の流速、Bの静水時の速さ、Bの下りの速さ、Bが下る時間を求めます。川の流速は2km/時、Bの静水時の速さは7km/時、Bの下りの速さは9km/時、Bが下る時間は10時間。
|
| 442 |
+
|
| 443 |
+
[CHUNK]
|
| 444 |
+
## 川を往復する水夫の速さの計算
|
| 445 |
+
90kmの川を上るまでに15時間かかっているので、90km÷15時間=6km/時。下るときは9時間なので、90km÷9時間=10km/時。川を上ったり下ったりする問題では川の速さを考える。川の速さ×2=4km/時なので、川の速さは2km/時。Bが上るときの速さは90km÷18時間=5km/時。Bの静水時の速さは5km/時+2km/時=7km/時。Bの下るときの速さは7km/時+2km/時=9km/時。Bが下る時間は90km÷9km/時=10時間。
|
| 446 |
+
|
| 447 |
+
[CHUNK]
|
| 448 |
+
## 川を上り下りする船の問題
|
| 449 |
+
ある船が川を144km上るのに12時間かかり、下るのに8時間かかりました。川の流れの速さと船の静水時の速さを求めます。川の流れの速さは3km/時、船の静水時の速さは15km/時。
|
| 450 |
+
|
| 451 |
+
[CHUNK]
|
| 452 |
+
## 川を上り下りする船の速さの計算
|
| 453 |
+
川の長さ、上���までの時間、下るまでの時間が分かっているので、上るときの速さと下るときの速さを求める。144km÷12時間=12km/時(上るときの速さ)、144km÷8時間=14km/時(下るときの速さ)。上るときの速さと下るときの速さが分かったら、「速さの線分図」を書く。川の速さを1として、計算する。川の速さを1と仮定すると2=4km/時を計算。よって川の速さの1は4km/時÷2=2km/時。下に進むときの速さ=静水時の速さ+川の速さなので、14km/時=静水時の速さ+2km/時。静水時の速さ=14km/時-2km/時となり、12km/時。
|
| 454 |
+
|
| 455 |
+
[CHUNK]
|
| 456 |
+
## 川をこぎおりる人の速さに関する問題
|
| 457 |
+
静水をこぐ速さが毎時10.5kmの人が3時間で36kmこぎおりました。流れの速さ、上りの速さ、5時間かけて上ると何km進むかを求めます。流れの速さは1.5km/時、上りの速さは9km/時、5時間かけて上ると45km進む。
|
| 458 |
+
|
| 459 |
+
[CHUNK]
|
| 460 |
+
## 川をこぎおりる人の速さの計算
|
| 461 |
+
静水時の速さが10.5km/時、3時間で36kmを下ったことが分かっているので、36km÷3時間=12km/時と下りの速さが12km/時とわかる。下に進むときの速さ=静水時の速さ+川の速さなので、下に進むときの速さ一静水時の速さ=川の速さと考えられる。よって川の速さは、12km/時-10.5km/時=1.5km/時。上に進むときの速さ=静水時の速さー川の速さなので、上に進むときの速さ=10.5km/時-1.5km/時となり、9km/時。上に進むときの速さ(9km/時)で5時間進むので進む距離は、9km/時×5時間=45km。
|
| 462 |
+
|
| 463 |
+
[CHUNK]
|
| 464 |
+
## 川をこぎ上る時間の問題
|
| 465 |
+
流れの速さが毎時3kmの川を、60kmこぎ上るのに10時間かかりました。この川を24kmこぎ下りるのに何時間かかりますか。2時間。
|
| 466 |
+
|
| 467 |
+
[CHUNK]
|
| 468 |
+
## 川をこぎ上る時間の計算
|
| 469 |
+
60kmの距離を10時間かけて上るので、60km÷10時間=6km/時。静水時の速さ=上るときの速さ+川の速さと考えることができるので、静水時の速さ=6km/時+3km/時で9km/時。下るときの速さ=静水時の速さ(9km/時)+川の速さ(3km/時)で12km/時と分かります。24km下るときの時間は、24km÷下るときの速さで求めることができるので、24km÷12km/時=2時間。
|
| 470 |
+
|
| 471 |
+
[CHUNK]
|
| 472 |
+
## 川を上る船の問題
|
| 473 |
+
ある船が70kmの川を上るのに7時間かかり、同じところを下るのに2時間20分かかりました。船の下りの速さと川の流速は船の静水時の速さの何倍かを求めます。下りの速さは30km/時、川の流速は船の静水時の速さの1/2倍。
|
| 474 |
+
|
| 475 |
+
[CHUNK]
|
| 476 |
+
## 川を上る船の速さの計算
|
| 477 |
+
70kmの道のりを2時間20分かけて下るので、70km÷7/3時間=70km×3/7時間で30km/時と計算。この船は70kmの道のりを上るのに7時間かけているので、70km÷7時間=10km/時。船が上に進むときの速さ=静水時の速さ―川の速さ、下に進むときの速さ=静水時の速さ+川の速さ。川の速さを①とすると、下に進むときの速さー上に進むときの速さ=2(川の速さ×2)となる。30km/時-10km/時=20km/時、20km/時=2(川の速さ×2)なので川の速さ=10km/時と分かります。静水時の速さは10km/時+10km/時=20km/時なので、川の速さ(10km/時)は静水時の速さ(20km/時)の1/2倍と求める。
|
| 478 |
+
|
| 479 |
+
[CHUNK]
|
| 480 |
+
## プールで泳ぐ速さの問題
|
| 481 |
+
1周280mのプールでAは流れと同じ向きに泳いで1周すると3分30秒かかり、流れと反対方向に泳いで1周すると4分40秒かかります。Aが静水時に進む速さは毎分何mですか。70m/分。
|
| 482 |
+
|
| 483 |
+
[CHUNK]
|
| 484 |
+
## プールで泳ぐ速さの計算
|
| 485 |
+
30秒=1/2分なので、3分30秒=3.5分となり、7/2分と書きかえる。280m÷7/2分=80m/分。40秒=2/3分となり、4分40秒=4と2/3分、14/3分と考える。280m÷14/3分=60m/分。流れと反対方向に進む速さ=静水時の速さーブールの速さ、流れと同じ方法に進む速さ=静水時の速さ+ブールの速さなので、プールの速さを1とすると、流れと同じ方法に進む速さー流れと反対方向に進む速さ=2(ブールの速さ×2)となる。80m/分-60m/分=2(ブールの速さ×2)なので2=20m/分。プールの速さは20m/分÷2=10m/分と計算。静水時の速さ=流れと反対方向に進む速さ+プールの速さで60m/分+10m/分=70m/分。
|
| 486 |
+
|
| 487 |
+
[CHUNK]
|
| 488 |
+
## 川を下流から上流へ走る船の問題
|
| 489 |
+
静水では毎時12kmで走る船Aと、毎時16kmで走る船Bがあります。川の下流から上流まで走るとき、Aは10時間、Bは6時間40分かかります。川の流れは毎時何kmですか。4km/時。
|
| 490 |
+
|
| 491 |
+
[CHUNK]
|
| 492 |
+
## 川を下流から上流へ走る船の速さの計算
|
| 493 |
+
40分=2/3時間と考えることができるので、上に上るときにかかる時間の比は10時間:6と2/3時間となり、10:20/3、両辺を×3して、30:20=3:2と求める。走る時間が短ければ短いほど、走る速さが���やいと考えることができる。静水時の速さが12km/時、16km/時と分かっているので、上るときの速さ=静水時の速さ―川の速さと仮定)なので、12km/時= 2+1、16km/時= 3+1と考える。3 - 2 = 1 がAとBの静水時の差の4km/時であることが分かります。16km/時(Bの静水時の速さ)-12km時の静水時の速さ)=4km/時。12km/時= 2 +1なので12km/時=8km/時+1となり、川の速さの1=4km/時。
|
| 494 |
+
|
| 495 |
+
# 速さ編ドリル - 流水算
|
| 496 |
+
|
| 497 |
+
[CHUNK]
|
| 498 |
+
## 流水算の基本:一定速度のプールでのAと浮き輪の出会い
|
| 499 |
+
一定速度で水が流れる1周240mのプールで、Aが流れに乗って泳ぎ始め、同時に浮き輪を流した。Aが3周したとき浮き輪に追いつき、流れに逆らうと1周12分かかる。プールの流速は毎分40mで、Aが流れに乗ると1周2分24秒。Aが3周進む時間とうき輪が2周する時間が同じであることに着目し、速さの比から流速を求める。
|
| 500 |
+
|
| 501 |
+
[CHUNK]
|
| 502 |
+
## プールの流速計算とAのラップタイム:流水算の応用
|
| 503 |
+
Aが3周したとき浮き輪に追いつき、流れに逆らうと1周12分かかる。プールの流速は毎分40m。Aが流れに乗ると1周2分24秒。Aが3周進む時間とうき輪が2周する時間が同じであることに着目し、Aの静水時速さを計算。流れに乗った時の速さ(静水時+流速)で240mを割ることでラップタイムを算出。
|
| 504 |
+
|
| 505 |
+
[CHUNK]
|
| 506 |
+
## 川下りと上り:流速変化時の船の速さ計算
|
| 507 |
+
ある船が105kmの川を下るのに7時間、元の場所に戻るのに流速が2倍になり11時間40分かかった。下りの速さは毎時15km、流速2倍時の上り速度は毎時9km、船の静水時速さは毎時13km。下りと上りの速さの差から流速を逆算し、静水時速さを求める。
|
| 508 |
+
|
| 509 |
+
[CHUNK]
|
| 510 |
+
## 流速変化時の船の速さ計算:上り下りの時間変化
|
| 511 |
+
ある船が105kmの川を下るのに7時間かかりました。元のところへもどるとき、流れの速さが2倍になったので、11時間40分かかりました。下りの速さは毎時15km。上りの速さは毎時9km。静水時の速さは毎時13km。上りと下りの速さの差から流速の変化を捉え、静水時の速さを算出する。
|
| 512 |
+
|
| 513 |
+
[CHUNK]
|
| 514 |
+
## 川の上り下り:流速が変化するケース
|
| 515 |
+
川に沿って27km離れたP町とQ町があり、ある船がQ町からP町へ上るのに4時間半、下る時は流速が2倍になり1時間で下った。船の静水時速さは毎時13km。上りと下りの時間からそれぞれの速さを計算し、流速の変化を考慮して静水時速さを求める。
|
| 516 |
+
|
| 517 |
+
[CHUNK]
|
| 518 |
+
## 流速変化時の静水時速さ:流水算の応用
|
| 519 |
+
川に沿って27km離れたP町とQ町があり、ある船がQ町からP町へ上るのに4時間半、下る時は流速が2倍になり1時間で下った。船の静水時速さは毎時13km。上りと下りの速さの差から流速を計算し、静水時速さを求める。流速の変化を線分図で視覚化し、計算を簡略化。
|
| 520 |
+
|
| 521 |
+
[CHUNK]
|
| 522 |
+
## 川下り:流速が2倍になった場合の上り時間
|
| 523 |
+
ある船が川を48km下るのに8時間、その後流速が2倍になり同じ距離を上るのに下りの2倍の時間がかかった。船の静水時速さは毎時5km。下りと上りの時間からそれぞれの速さを計算し、流速の変化を考慮して静水時速さを求める。
|
| 524 |
+
|
| 525 |
+
[CHUNK]
|
| 526 |
+
## 流速変化時の静水時速さ:上り下りの時間と速さ
|
| 527 |
+
ある船が川を48km下るのに8時間、その後流速が2倍になり同じ距離を上るのに下りの2倍の時間がかかった。船の静水時速さは毎時5km。下りと上りの速さの差から流速を計算し、静水時速さを求める。流速の変化を線分図で視覚化し、計算を簡略化。
|
| 528 |
+
|
| 529 |
+
[CHUNK]
|
| 530 |
+
## 川の上り下り:流速が4倍になるケース
|
| 531 |
+
川に沿って39km離れたP町とQ町があり、ある船がQ町からP町へ上るのに13時間、下る時は流速が上りの4倍になり3時間で下った。船の静水時速さは毎時5km。上りと下りの時間からそれぞれの速さを計算し、流速の変化を考慮して静水時速さを求める。
|
| 532 |
+
|
| 533 |
+
[CHUNK]
|
| 534 |
+
## 流速変化時の静水時速さ:流速4倍のケース
|
| 535 |
+
川に沿って39km離れたP町とQ町があり、ある船がQ町からP町へ上るのに13時間、下る時は流速が上りの4倍になり3時間で下った。船の静水時速さは毎時5km。上りと下りの速さの差から流速を計算し、静水時速さを求める。流速の変化を線分図で視覚化し、計算を簡略化。
|
| 536 |
+
|
| 537 |
+
[CHUNK]
|
| 538 |
+
## 川の往復:上り下りの時間と速さから静水時速さを求める
|
| 539 |
+
ある船が川上にあるP町とそこから45km離れたQ町を往復するのに、上りは9時間、下りは5時間かかった。上りの速さは毎時5km、下りの速さは毎時9km、船の静水時速さは毎時7km。上��と下りの時間からそれぞれの速さを計算し、静水時速さを求める。
|
| 540 |
+
|
| 541 |
+
[CHUNK]
|
| 542 |
+
## 上り下りの時間と速さ:静水時速さの計算
|
| 543 |
+
ある船が川上にあるP町とそこから45km離れたQ町を往復するのに、上りは9時間、下りは5時間かかった。上りの速さは毎時5km、下りの速さは毎時9km、船の静水時速さは毎時7km。上りと下りの速さの差から流速を計算し、静水時速さを求める。流速の変化を線分図で視覚化し、計算を簡略化。
|
| 544 |
+
|
| 545 |
+
[CHUNK]
|
| 546 |
+
## 川の往復:上り下りの時間から静水時速さを算出
|
| 547 |
+
ある船が川上にあるA町とそこから135km離れたB町の間を往復するのに、上りは15時間、下りは5時間かかった。上りの速さは毎時9km、下りの速さは毎時27km、船の静水時速さは毎時18km。上りと下りの時間からそれぞれの速さを計算し、静水時速さを求める。
|
| 548 |
+
|
| 549 |
+
[CHUNK]
|
| 550 |
+
## 上り下りの時間と速さ:静水時速さの計算と線分図
|
| 551 |
+
ある船が川上にあるA町とそこから135km離れたB町の間を往復するのに、上りは15時間、下りは5時間かかった。上りの速さは毎時9km、下りの速さは毎時27km、船の静水時速さは毎時18km。上りと下りの速さの差から流速を計算し、静水時速さを求める。線分図で視覚化。
|
| 552 |
+
|
| 553 |
+
[CHUNK]
|
| 554 |
+
## 川での出会い:静水時速さが異なる2隻の船
|
| 555 |
+
静水時速さが毎時4kmの船Aと毎時7kmの船Bが、55km離れた川上のP町と川下のQ町から向かい合って同時に進む。A、B両船は出発してから5時間後に出会う。2隻の船が近づく速さを計算し、出会うまでの時間を求める。
|
| 556 |
+
|
| 557 |
+
[CHUNK]
|
| 558 |
+
## 2隻の船の出会い:流水算と旅人算の融合
|
| 559 |
+
静水時速さが毎時4kmの船Aと毎時7kmの船Bが、55km離れた川上のP町と川下のQ町から向かい合って同時に進む。A、B両船は出発してから5時間後に出会う。2隻の船の相対速度を計算し、出会うまでの時間を求める。川の流れを考慮した旅人算。
|
| 560 |
+
|
| 561 |
+
[CHUNK]
|
| 562 |
+
## 川での出会い:出会い後の時間経過
|
| 563 |
+
静水時速さが毎時40kmの船Aと毎時20kmの船Bが、240kmの川を向かい合って進む。Bは出会った後、16時間たってAの出発地点に到着。川の流速は毎時8km。出会うまでの時間とBの速さから流速を計算。
|
| 564 |
+
|
| 565 |
+
[CHUNK]
|
| 566 |
+
## 出会い後の時間経過:流速の計算
|
| 567 |
+
静水時速さが毎時40kmの船Aと毎時20kmの船Bが、240kmの川を向かい合って進む。Bは出会った後、16時間たってAの出発地点に到着。川の流速は毎時8km。出会うまでの時間とBの速さから流速を計算。線分図で視覚化。
|
| 568 |
+
|
| 569 |
+
[CHUNK]
|
| 570 |
+
## 流水の速さが一定の川:上り下りの速さから流速と静水時速さを求める
|
| 571 |
+
流水の速さが一定の川で、静水時の速さが一定の船が往復する。上りの速さは毎時20km、下りの速さは毎時28km。川の流れの速さは毎時4km、船の静水時の速さは毎時24km。上りと下りの速さの差から流速を計算。
|
| 572 |
+
|
| 573 |
+
[CHUNK]
|
| 574 |
+
## 流水算:上り下りの速さから流速と静水時速さを計算
|
| 575 |
+
流水の速さが一定の川で、静水時の速さが一定の船が往復する。上りの速さは毎時20km、下りの速さは毎時28km。川の流れの速さは毎時4km、船の静水時の速さは毎時24km。線分図で視覚化。
|
| 576 |
+
|
| 577 |
+
# 下克上算数ドリル【速さ編】
|
| 578 |
+
|
| 579 |
+
[CHUNK]
|
| 580 |
+
## 流水算の基本:上りと下りの速さ
|
| 581 |
+
流水算では、川の流れがある状況での船の動きを扱います。船が川を上るとき、船の速度は静水時の速度から川の流れの速度を引いたものになります。逆に、船が川を下るときは、静水時の速度に川の流れの速度を加えたものが実際の速度となります。上りと下りの速さの違いを理解することが、流水算を解く上で重要です。問題文を読み解き、上りと下りの状況を正確に把握しましょう。
|
| 582 |
+
|
| 583 |
+
[CHUNK]
|
| 584 |
+
## 流水の速さが変化する場合の解法
|
| 585 |
+
川の流れの速さが一定でない場合、問題は複雑になります。例えば、川の流れの速さが変化する場合には、それぞれの区間における速さを個別に計算する必要があります。川の流れの速さが変化するタイミングや、それぞれの速度を正確に把握し、線分図やグラフを用いて視覚的に整理することが有効です。変化する速さを考慮して、上り下りの速さを計算しましょう。
|
| 586 |
+
|
| 587 |
+
[CHUNK]
|
| 588 |
+
## 流水の速さ変化と線分図の活用
|
| 589 |
+
川の流れの速さが変化する問題では、線分図が非常に役立ちます。線分図を用いることで、船の速度、川の流れの速度、そしてそれらの関係性を視覚的に捉えることができます。特に、川の流れの速さが変化する場合には、��れぞれの区間ごとに線分図を作成し、変化を明確にすることが重要です。線分図を活用して、問題の状況を整理しましょう。
|
| 590 |
+
|
| 591 |
+
[CHUNK]
|
| 592 |
+
## 静水時の速さの計算
|
| 593 |
+
流水算において、静水時の速さを求めることは基本的なスキルです。静水時の速さは、上りの速さと下りの速さの平均値として計算できます。例えば、上りの速さが毎時24km、下りの速さが毎時42kmの場合、静水時の速さは(24 + 42) / 2 = 33km/時となります。静水時の速さを正確に計算し、問題解決に役立てましょう。
|
| 594 |
+
|
| 595 |
+
[CHUNK]
|
| 596 |
+
## 静水時の速さ計算と応用
|
| 597 |
+
静水時の速さを求める問題では、上りと下りの速さの関係を理解することが重要です。上りの速さは「静水時の速さ - 川の流れの速さ」、下りの速さは「静水時の速さ + 川の流れの速さ」で表されます。これらの関係式を用いることで、静水時の速さや川の流れの速さを求めることができます。問題文から必要な情報を抽出し、関係式を適切に適用しましょう。
|
| 598 |
+
|
| 599 |
+
[CHUNK]
|
| 600 |
+
## プールでの流水算:反対方向への移動
|
| 601 |
+
プールでの流水算は、川での流水算と同様に考えることができます。プールの場合、流れの速さを考慮して、人が反対方向に泳ぐ場合を考えます。人が流れに逆らって泳ぐ場合、その人の速度は、静水時の速度から流れの速度を引いたものになります。反対方向への移動距離と時間を計算する際には、この速度を考慮する必要があります。
|
| 602 |
+
|
| 603 |
+
[CHUNK]
|
| 604 |
+
## プールでの流水算:追いつき問題
|
| 605 |
+
プールでの流水算では、追いつき問題も頻出です。例えば、A君が泳いでB君に追いつく場合、A君の速度からB君の速度を引いたものが、A君がB君に近づく相対速度となります。この相対速度を用いて、追いつくまでの時間を計算します。追いつき問題では、相対速度の概念を理解し、正確に計算することが重要です。
|
| 606 |
+
|
| 607 |
+
[CHUNK]
|
| 608 |
+
## 列車算の基本:トンネル通過問題
|
| 609 |
+
列車算では、列車がトンネルや橋を通過する問題を扱います。列車がトンネルを通過する場合、列車が完全にトンネルを通過するためには、列車の長さとトンネルの長さを合わせた距離を移動する必要があります。この距離を列車の速度で割ることで、通過にかかる時間を計算できます。図を描いて状況を整理し、正確に計算しましょう。
|
| 610 |
+
|
| 611 |
+
[CHUNK]
|
| 612 |
+
## 列車算:トンネル通過と橋の通過
|
| 613 |
+
列車算では、トンネル通過問題と橋の通過問題を組み合わせた問題も出題されます。これらの問題を解くためには、それぞれの状況における列車の移動距離を正確に把握する必要があります。トンネル通過時には「トンネルの長さ + 列車の長さ」、橋の通過時には「橋の長さ + 列車の長さ」が移動距離となります。それぞれの距離を正確に計算し、問題解決に役立てましょう。
|
| 614 |
+
|
| 615 |
+
[CHUNK]
|
| 616 |
+
## 列車算:すれ違い問題
|
| 617 |
+
列車算では、列車同士がすれ違う問題を扱います。列車がすれ違う場合、それぞれの列車の速度を足し合わせたものが、相対速度となります。すれ違いにかかる時間は、それぞれの列車の長さを足し合わせた距離を、相対速度で割ることで計算できます。すれ違い問題では、相対速度の概念を理解し、正確に計算することが重要です。
|
| 618 |
+
|
| 619 |
+
# 中学受験算数ドリル:速さ編
|
| 620 |
+
|
| 621 |
+
[CHUNK]
|
| 622 |
+
## 51. 追いつき追い越し問題の解法
|
| 623 |
+
長さ150m、時速90kmのA列車が、長さ120mのB列車に追いついてから追いこし終わるまでに30秒かかった。B列車の速さを求める。A列車の秒速は25m/秒。A列車がB列車を追い越すには、A列車の先頭がB列車の後尾にきてから、A列車の後尾がB列車の先頭に来るまで、つまりA列車がB列車よりも270m多く進む必要がある。A列車は30秒で270m多く進むので、A列車はB列車より9m/秒早い。B列車の秒速は25m/秒-9m/秒=16m/秒。B列車の時速は57.6km/時。
|
| 624 |
+
|
| 625 |
+
[CHUNK]
|
| 626 |
+
## 51. 追いつき追い越し問題の計算と単位換算
|
| 627 |
+
A列車は30秒で270mだけ多くB列車よりも早く走ることが分かりますので、270m÷30秒=9m/秒でA列車はB列車よりも9m/秒早いことが計算できますね。B列車の秒速は25m/秒-9m/秒=16m/秒となります。問題で聞かれていることは時速なので、16m/秒を時速になおしましょう。1分=60秒なので、16m/秒×60秒=960m/分。1時間=60分なので、960m/分×60分=57600m/時(57.6km/時)と求められました。
|
| 628 |
+
|
| 629 |
+
[CHUNK]
|
| 630 |
+
## 52. トンネル通過と追いつき追い越し問題
|
| 631 |
+
速さ19m/秒、長さ300mのA列車が、速さ16m/秒、長さ360mのB列車について。(1)A列車がトンネルを通り抜けるのに12分かかった。トンネルの長さは?(2)A列車がB列車に追いついてから追いこすまでの時間は?(1)13380m (2)220秒。A列車がトンネルに入るからぬけるまでに12分かかっています。12分=720秒なので列車Aは720秒で、19m/秒×720秒=13680m進む。13680mはトンネルの長さ+列車Aの長さなので、トンネルの長さは13680m-300m=13380m。
|
| 632 |
+
|
| 633 |
+
[CHUNK]
|
| 634 |
+
## 52. 追いつき追い越し計算と図解
|
| 635 |
+
秒速19mの列車Aが16m/秒の列車Bに追いついてから追いぬくまでに、660m近づく必要がある。2つの列車は19m/秒と16m/秒なので、同じ方向に進むと1秒間で3mずつ近づきます。列車Aは追いぬくまでに、660m近づく必要があり、2つの列車は1秒間で3mずつ近づきますので、660m÷3m/秒=220秒かかることが求められました!
|
| 636 |
+
|
| 637 |
+
[CHUNK]
|
| 638 |
+
## 53. 電車の通過時間計算
|
| 639 |
+
長さ500mの電車が秒速20mで走る。(1)踏切で待つ太郎くんの前を通過し始めてから通過し終わるまでの時間。(2)長さ300mの橋を渡り始めてから渡り終わるまでの時間。(1)25秒 (2)40秒。太郎くんの前を通り過ぎるまでにこの列車が何m進まないといけないのかを考えてきましょう。踏切を通り過ぎるまでに、この列車は500mだけ前に進む必要がある。
|
| 640 |
+
|
| 641 |
+
[CHUNK]
|
| 642 |
+
## 53. 通過距離と時間の計算
|
| 643 |
+
踏切を通り過ぎるまで列車の先頭が踏切の前を通ってから、列車の後尾が踏切を通るまで、となります。つまり、500mを20m/秒の速さで進む必要があるので500m÷20m/秒=25秒となります。今度は300mの橋を渡るときの様子を考えてみましょう。300mの橋を渡る列車の頭が橋を通ってから列車の後ろが橋を通り過ぎるまで、となります。図を書いていくと、この列車が300m+500m=800m進んでいく必要があります。
|
| 644 |
+
|
| 645 |
+
[CHUNK]
|
| 646 |
+
## 53. 橋の通過時間計算
|
| 647 |
+
800m÷20m/秒=40秒なので、列車が橋を通り過ぎるまでに40秒かかることが計算できました。
|
| 648 |
+
|
| 649 |
+
[CHUNK]
|
| 650 |
+
## 54. 時計の角度計算:7時51分
|
| 651 |
+
7時51分のとき、時計の長針と短針がつくる小さい方の角度の大きさは何度ですか。解答:70.5°。時計算の問題では長針(長い針) と短針 (短い針) がそれぞれ進む速さをとらえることが大切です。まずは長針の進む速さを考えてみましょう。長針は1時間 (60分)で360° (1回転) することが分かります。よって1分間で進む角度は360°÷60分=6°/分と計算できますね。
|
| 652 |
+
|
| 653 |
+
[CHUNK]
|
| 654 |
+
## 54. 長針と短針の角度計算
|
| 655 |
+
同じように短針の進む速さを考えてみましょう。短針は12時間(720分)で360° (1回転) しますので、1時間で進む角度は30℃。360+12時間=30/。よって1分間で進む角度は30°÷60分=0.5 /分と計算できます。7時51分のときの角度を計算する前に7時のときの長針と短針の角度を考えてみましょう。長針は12の位置にあり、ここを0°と考えると短針は30/時×7時間=210° 進んでいます。なので7時の時点では2つの針は210 はなれていることが分かります。
|
| 656 |
+
|
| 657 |
+
[CHUNK]
|
| 658 |
+
## 54. 時計の角度計算:7時51分の詳細
|
| 659 |
+
最後に、7時51分のときをイメージしてみます。長針と短針はそれぞれ7時の場所から51分分だけ進みます。短針は0.5°/分なので、0.5°/分×51分=25.5° 進みます。長針は6°/分なので、6°/分×51分=306° 進みます。時計の図を書きながら計算していくと、306 -25.5-210 =70.5" と求めることができました。
|
| 660 |
+
|
| 661 |
+
[CHUNK]
|
| 662 |
+
## 55. 長針と短針が重なる時刻
|
| 663 |
+
4時と5時の間で、時計の長針と短針が重なる時刻は4時何分ですか。解答:4時21分。今回は時計の長針と短針が重なる時間を求める問題でした。旅人算のようにはなれた場所にいる長針と短針が重なるときと考えてみましょう。時計の問題では2つの針のきょりは角度で表すことができます。つまり長針と短針が重なる時間=長針と短針の間が0になるということです。長針と短針がそれぞれ進む速さを計算してみます。
|
| 664 |
+
|
| 665 |
+
[CHUNK]
|
| 666 |
+
## 55. 長針と短針の速度と角度
|
| 667 |
+
長針は1時間(60分)で360° (1回転) するので6°/分。短針は12時間(720分)で360° (1回転)しますので0.5°/分。長針との進む速さについては、1つ前の問題から解いてみるとより分かりやすいですよ!4時から5時の間で2つの針が重なる時間なので、4時の時点での長針と短針の間の角度を計算しましょう。長針は12の位置にあり、ここを0と考えると短針は30°/時×4時間=120°進んでいます。
|
| 668 |
+
|
| 669 |
+
[CHUNK]
|
| 670 |
+
## 55. 長針と短針が重なる時間の計算
|
| 671 |
+
4時の時点で120° はなれていることが分かりま��。長針と短針が同じ方向に進むとき、2つの針は1分間で6° -0.5 =5.5° 近づきます。4時の時点で120° はなれているので、120°÷5.5°/分=21分と計算出来ました!
|
| 672 |
+
|
| 673 |
+
[CHUNK]
|
| 674 |
+
## 56. 長針と短針の角度が30度になる時刻
|
| 675 |
+
3時と4時の間で、長針と短針の作る角度が30度になる時はそれぞれ3時何分ですか。解答:3時10分、3時21分。今回の問題、実は答えが二つあることに気づきましたか? 問題をときながら気づいてもOKですし、問題文にも「それぞれ」 何時何分ですか?と聞いているのでよく読んでいれば分かりますね。3時から4時までの間ですので、まずは3時の時点を考えましょう。このとき、長針と短針は90℃はなれています。
|
| 676 |
+
|
| 677 |
+
[CHUNK]
|
| 678 |
+
## 56. 長針と短針の速度と角度変化
|
| 679 |
+
長針は6°/分。短針は0.5°/分の速さでしたね!この2つの針は1分間で6° -0.5 =5.5° 近づきます。線分図を書いてみて、長針と短針のはなれているきょりと速さを書きこんでみましょう。まず1回目に30° ができるときを考えてみましょう。線分図では長針と短針は90° はなれていますが、長針が短針よりも60° だけ多く進むと、2つの針の間の角度が30° になることがわかると思います。
|
| 680 |
+
|
| 681 |
+
[CHUNK]
|
| 682 |
+
## 56. 長針と短針の角度が30度になる時間の計算
|
| 683 |
+
よって60° ÷5.5°/分=10 ・/分=10分と計算することができます。次に2回目に30°ができるときについて考えてみましょう。2回目に30°になるときは、長針と短針を追いこして、30℃先に進んだときになります。(線分図にイメージ図を書いています。)つまり、3時の時点から長針は短針よりも120° 多く進めば2回目に30°を作ることができます。よって120° +5.5°/分=21 分と求めることができました。
|
| 684 |
+
|
| 685 |
+
[CHUNK]
|
| 686 |
+
## 57. 特殊な時計の針の重なり
|
| 687 |
+
ある特別な時計は長針が30秒で1周、短針が2分で1周する。長針と短針が反対方向をさして一直線になっている時、長針と短針が最初に重なるのは今から何秒後ですか。解答:20秒。この問題は普通の時計算と比べて、長針と短針の進む速さがちがいますので気をつけましょう!まずは問題文から長針と短針がそれぞれ進む速さを計算していきましょう。長針は30秒かけて1周しますので、30秒で360° 進むことが分かります。よって長針は360°÷30秒=12°/秒と計算できますね。
|
| 688 |
+
|
| 689 |
+
[CHUNK]
|
| 690 |
+
## 57. 特殊な時計の針の速度と角度
|
| 691 |
+
短針は2分で1周しますので、2分で360° 進むことになります。2分=120秒なので、360°÷120秒=3秒と分かりますね。長針と短針が反対方向を指しているので、2つの針の間の角度は360°の半分の180°となります。この2つの針は時計のように動きますので、2つの針は同じ方向に進みます。長針と短針を線分図になおして、出会うまでの時間を計算しましょう。
|
| 692 |
+
|
| 693 |
+
[CHUNK]
|
| 694 |
+
## 57. 特殊な時計の針が重なる時間の計算
|
| 695 |
+
線分図に、長針 (12°/秒) と短針 (3°/秒)そして180° を書きこみましょう。長針と短針は1秒で12° -3° 9° となりますので、9°/秒の速さで近づきます。面積図を書いて計算すると、180°÷9°/秒=20秒で20秒後に重なると分かります!
|
| 696 |
+
|
| 697 |
+
[CHUNK]
|
| 698 |
+
## 58. 長針と短針が直角になる時刻
|
| 699 |
+
10時と11時の間で、時計の長針と短針のつくる角が直角になることがあります。2回目に直角になるのは10時何分ですか。解答:10時38分。56 を解いてからこの解説を読むとよりわかりやすいと思います!まずは10時のときの2つの長針と短針のはなれている角度を計算しましょう。10時のとき、2つの針は60℃はなれています。ここから2つの針の角度が90°になるときを計算しましょう。
|
| 700 |
+
|
| 701 |
+
[CHUNK]
|
| 702 |
+
## 58. 長針と短針の速度と角度変化
|
| 703 |
+
長針は6°/分。短針は0.5°/分の速さになります。よって、この2つの針は1分間で6° -0.5 =5.5° 近づきます。線分図を書いてみて、長針と短針のはなれている角度と速さを書きこんでみましょう。まず1回目に90° ができるときを考えてみましょう。線分図では長針と短針は60° はなれていますが、長針が短針よりも30° だけ多く進むと、2つの針の間の角度が90° になることがわかると思います。
|
| 704 |
+
|
| 705 |
+
[CHUNK]
|
| 706 |
+
## 58. 長針と短針が直角になる時間の計算
|
| 707 |
+
よって30° ÷5.5°/分=5分と計算することができます。次に2回目に90° ができるときについて考えてみましょう。2回目に90°になるときは、長針と短針を追いこして、90°先に進んだときになります。(線分図にイメージ図を書いています。)つまり、10時の時���から長針は短針よりも210°多く進めば2回目に90°を作ることができます。よって210° ÷5.5°/分=38 分と求めることができました。
|
| 708 |
+
|
| 709 |
+
[CHUNK]
|
| 710 |
+
## 59. 長針と短針が重なる時刻と等しい角度になる時刻
|
| 711 |
+
時計の長針と短針が2時と3時の間でちょうど重なっている。このとき、以下の問いに答えなさい。(1) このときの時間は2時何分ですか。(2)その後長針と短針が文字ばんのめもりの6をはさんで等しい角度になっている時刻は2時何分ですか。解答:(1)2時10分 (2)2時46分。かなりむずかしい問題でした。特に (2) はよく MEMO と一緒によく読んでみてください!
|
| 712 |
+
|
| 713 |
+
[CHUNK]
|
| 714 |
+
## 59. 長針と短針の重なる時間の計算
|
| 715 |
+
(1) 2時のときの長針と短針のはなれている角度は60°です。また長針は6/分、短針は0.5分の速さで進みますのでこれを線分図に書きこんで、針が重なる時間を計算しましょう。MEMO のように線分図を書いて、2つの針が重なる時間を計算します。2つの針は1分間で6-0.5 =5.5 近づきます。重なる=2つの針の間の角度が0になるときなので、60° +5.5°/分=10分の時間に重なることが分かりました。(ここまではいつもの問題と同じでした。)
|
| 716 |
+
|
| 717 |
+
[CHUNK]
|
| 718 |
+
## 59. 等しい角度になる時刻の計算
|
| 719 |
+
(2) 問題文で書かれている状況について考えてみましょう。6のめもりは時計の真ん中にあるので、時計を半分にしたときに、長針と短針の2つの角度(MEMOの青と紫)が同じになる時間を求めることができればOKです。時間を求めたいので口分として計算していきます。短針の角度は2時の時点で120 でどんどん小さくなるので、120-0.5/分×口分と考えることができます。同じように長針の角度は2時の時点では0なので、6/分×分から180引いた、6/分×分~180℃になります!
|
| 720 |
+
|
| 721 |
+
[CHUNK]
|
| 722 |
+
## 59. 等しい角度になる時刻の計算:詳細
|
| 723 |
+
短針の角度=長針の角度になる時間を知りたいので、120-0.5/分×口分=6/分×口分-180 を計算すれば答えが出せます。線分図を書いてこの式を表してみました。線分図を書いて「差」に注目してみましょう。すると、180°-0.5/分×口分=6°/分×口分-120°と式をかき変えることができます。この式を工夫して整理してみます。
|
| 724 |
+
300°=6°/分×口分+0.5分×分
|
| 725 |
+
180°=6°/分×口分-120° +0.5分×口分
|
| 726 |
+
२
|
| 727 |
+
300(6/分+0.5/分)×分
|
| 728 |
+
?
|
| 729 |
+
両辺に+120
|
| 730 |
+
よって300÷6.5°/分=46分と計算することができました。
|
| 731 |
+
|
| 732 |
+
[CHUNK]
|
| 733 |
+
## 60. 長針と短針が作る角度と追い越し後の角度
|
| 734 |
+
時計の針が5時10分をさしています。このとき、以下の問いに答えなさい。(1) 長針と短針が作る角度で小さいものは何度ですか。(2) 長針が短針を追いこしてから作る角度が90度となるのは5時何分ですか。解答:(1) 95° (2)5時43分。5時10分のときの長針と短針の2つの角度を求めるために、まずは5時のときの角度を計算しましょう。(長針は6/分、短針は0.5/分の速さで進みます。)
|
| 735 |
+
|
| 736 |
+
[CHUNK]
|
| 737 |
+
## 60. 長針と短針の角度計算
|
| 738 |
+
5時のとき、長針は12の位置にいるので角度を0°と考えてみましょう。すると、短針は5の位置にあるので30°/時×5時間=150° はなれていることが分かります。5時10分の角度を求めたいので、5時から10分で長針と短針が進む角度を計算しましょう。長針は6°/分×10分=60°、短針は0.5/分×10分=5 なので、時計の図を書いて2つの針の間の角度を、150°+5 -60° =95° と解いていきましょう。
|
| 739 |
+
|
| 740 |
+
[CHUNK]
|
| 741 |
+
## 60. 追い越し後の角度計算
|
| 742 |
+
線分図を書いて、問題文で聞かれている2つの針が90°になるときを考えてみましょう。長針は6°/分。短針は0.5/分の速さで進むので、2つの針は1分間で6° -0.5 =5.5° 近づきます。線分図を書いてみて、長針と短針のはなれている角度 (150°) と速さを書いていきます。長針が短針を追いこして90°になるとき、長針は短針よりも240° (はなれている 150°+90°) 多く進む必要があります。2つの針は1分間で5.5 近づくので、長針が短針を追いこして90°240°÷5.5°/分=43分となり、5時43分と求められることができます。
|
| 743 |
+
|
| 744 |
+
# 下克上算数ドリル【速さ編】
|
| 745 |
+
|
| 746 |
+
[CHUNK]
|
| 747 |
+
## 面積図の活用:四角形の性質で問題を視覚的に解く
|
| 748 |
+
面積図は、算数の解法の一つで、四角形の面積(たて×横)の性質を利用する。速さの問題では、縦を速さ、横を時間、面積を進んだ距離として表現する。例えば、1分で30m進む人が5分で進む距離は、30m/分×5分=150mで計算できる。面積図はケアレスミスを減らし、問題を正確に解くために有効。特に算数が苦手な場合や学習初期段階では、図を描くことで見直しが容易になり、理解が深まる。速さ、時間、距離の関係を視覚的に捉え、複雑な問題への対応力を高める。面積図の利用は、問題解決の基礎を固める上で重要。
|
| 749 |
+
|
| 750 |
+
[CHUNK]
|
| 751 |
+
## 面積図の種類と活用:速さ、割合、個数問題への応用
|
| 752 |
+
面積図は、速さだけでなく、割合や個数に関する問題にも応用可能。速さの問題では、1分あたりの進む距離と時間を掛けて総距離を求める。例えば、1分で60m進む人が5分で進む距離は、60m/分×5分=300mとなる。割合の問題では、全体を四角形で表し、その一部を塗りつぶすことで割合を視覚化する。個数の問題では、1個あたりの価格と個数を掛けて合計金額を求める。例えば、1個200円の商品を3個購入した場合、200円/個×3個=600円となる。面積図は、問題の種類に応じて柔軟に活用できる。
|
| 753 |
+
|
| 754 |
+
[CHUNK]
|
| 755 |
+
## 線分図の基本:問題文の情報を整理し視覚化
|
| 756 |
+
線分図は、問題文中の数値や数量関係を線で表すことで、問題を解きやすくする算数の解法。例えば、600円の商品と300円の商品を購入した場合、それぞれの金額を線で表現し、合計金額を視覚的に示す。線分図は、比の性質を理解する上でも役立ち、問題解決の糸口を見つけやすくする。面積図と並び、算数の問題で頻繁に使用される。線分図は、問題文の情報を整理し、数量関係を明確にするための強力なツール。
|
| 757 |
+
|
| 758 |
+
[CHUNK]
|
| 759 |
+
## 線分図の種類と活用:和差算、旅人算への応用
|
| 760 |
+
線分図は、和差算や旅人算など、様々な問題に応用可能。和差算では、りんごとバナナの値段を線で表し、それぞれの値段と合計金額を比較することで、それぞれの値段を求める。旅人算では、2人が同じ方向または反対方向に進む状況を線で表し、それぞれの進む距離や速さの関係を視覚的に捉える。特に、2人が出会うまでの時間や距離を求める問題で有効。線分図は、複雑な状況を整理し、問題解決を容易にする。
|
| 761 |
+
|
| 762 |
+
[CHUNK]
|
| 763 |
+
## 比の基本:数量や速さの比較
|
| 764 |
+
比は、2つの数量を比較するための表現方法で、○:□のように表す。例えば、2cmと4cmの長さを比較する場合、2:4と表現できる。比は、前項と後項で構成され、それぞれ比較される数量を表す。比を用いることで、異なる単位の数量を相対的に比較することが可能。比は、算数における重要な概念であり、様々な問題解決に役立つ。
|
| 765 |
+
|
| 766 |
+
[CHUNK]
|
| 767 |
+
## 比と線分図:視覚的な表現で理解を深める
|
| 768 |
+
比は、線分図と組み合わせて使用することで、視覚的に理解を深めることができる。例えば、500円と1000円の金額を比較する場合、それぞれの金額を線分の長さで表し、比率を視覚的に示す。線分図を用いることで、比の関係を直感的に捉えることが可能。比の値を線分図上に表現する際は、実際の数量と区別するために記号を用いることが重要。比と線分図の組み合わせは、問題解決の精度を高める。
|
| 769 |
+
|
| 770 |
+
[CHUNK]
|
| 771 |
+
## 逆比の理解:面積一定条件下の縦横比
|
| 772 |
+
逆比は、面積が一定の場合に、縦と横の長さの比が逆になる関係。例えば、面積が15の長方形において、縦の長さが3の場合、横の長さは5となる。一方、縦の長さが5の場合、横の長さは3となる。このとき、縦の長さの比が3:5であるのに対し、横の長さの比は5:3となる。このように、ある条件が一定の場合に、2つの要素の比が逆になる関係を逆比と呼ぶ。逆比の理解は、複雑な問題を解く上で重要。
|
| 773 |
+
|
| 774 |
+
[CHUNK]
|
| 775 |
+
## 逆比の応用:速さの問題への適用
|
| 776 |
+
逆比は、速さの問題に応用できる。例えば、同じ距離を進む場合、速さの比と時間の比は逆比の関係になる。時速3kmの人が15km進むのに5時間かかるのに対し、時速5kmの人が15km進むのに3時間かかる。このとき、速さの比が3:5であるのに対し、時間の比は5:3となる。逆比の関係を理解することで、速さの問題を効率的に解くことができる。面積図を丁寧に書くことで、逆比の関係を視覚的に捉えることも可能。
|
| 777 |
+
|
| 778 |
+
[CHUNK]
|
| 779 |
+
## 仮定法の活用:問題解決の糸口を見つける
|
| 780 |
+
仮定法は、問題を解く際に、ある条件を仮定して考える方法。例えば、「もし○○が□□だったら〜」というように、具体的な数値を仮定して問題を解き進める。AくんがBくんより3倍速く走る場合、Aくんが15分で走る距離をBくんが何分で走れるかを考える際、Aくんの速さを①/分と仮定する��、Bくんの速さは③/分となる。仮定法を用いることで、複雑な問題も簡略化し、解決の糸口を見つけやすくなる。
|
| 781 |
+
|
| 782 |
+
[CHUNK]
|
| 783 |
+
## 仮定法の応用:仕事算への展開
|
| 784 |
+
仮定法は、仕事算にも応用できる。例えば、ある仕事量を1人が何時間で終わらせるかを考える際、1時間あたりの仕事量を①と仮定する。仮定法を用いることで、複数人が共同で仕事をする場合や、仕事の進捗状況を把握する際に役立つ。仕事算では、全体の仕事量を1と仮定し、各人の仕事量を分数で表すことが多い。仮定法は、問題解決の柔軟性を高め、様々な算数問題に対応できる。
|
| 785 |
+
|
| 786 |
+
[CHUNK]
|
| 787 |
+
## 流水算の基本:川の流れを考慮した速さの計算
|
| 788 |
+
流水算は、川の流れがある状況下での船の速さを扱う問題。川の流れに逆らって進む場合、船の速さは静水時の速さから川の流れの速さを引いたものになる。一方、川の流れに乗って進む場合、船の速さは静水時の速さに川の流れの速さを足したものになる。流水算では、川の流れの向きと速さを考慮して、船の実際の速さを計算する必要がある。流水算は、速さの問題の中でも特に複雑で、注意が必要。
|
| 789 |
+
|
| 790 |
+
[CHUNK]
|
| 791 |
+
## 流水算の解法:線分図の活用
|
| 792 |
+
流水算を解く上で、線分図の活用が有効。川上に向かう場合と川下に向かう場合で、船の速さが異なるため、それぞれの状況を線分図で表現する。例えば、静水時の速さが75m/分、川の速さが15m/分の場合、川上に向かう速さは60m/分、川下に向かう速さは90m/分となる。線分図を用いることで、速さの関係を視覚的に捉え、計算ミスを防ぐことができる。流水算は、線分図を丁寧に書くことが重要。
|
| 793 |
+
|
| 794 |
+
[CHUNK]
|
| 795 |
+
## 列車算の解法:問題文の正確な理解
|
| 796 |
+
列車算は、列車が通過する時間や距離を計算する問題。問題文を注意深く読み、何が問われているかを正確に理解することが重要。列車が黄色い小人の前を通過する状況を例に、通過開始から通過終了までの時間や、列車が見えなくなってから出始めるまでの時間など、問われる内容によって計算方法が異なる。問題文の理解不足は、誤答につながるため、注意が必要。
|
| 797 |
+
|
| 798 |
+
[CHUNK]
|
| 799 |
+
## 列車算の応用:すれ違いと追い越しの計算
|
| 800 |
+
列車算では、列車同士がすれ違う場合や追い越す場合の計算も重要。列車がすれ違う場合、それぞれの列車の長さの合計が、すれ違いに要する距離となる。一方、列車が追い越す場合、速い列車が遅い列車よりもどれだけ長く進む必要があるかを考慮する。列車算では、列車の長さや速さ、進行方向などを正確に把握し、適切な計算を行う必要がある。図を描くことで、状況を整理しやすくなる。
|
| 801 |
+
|
| 802 |
+
[CHUNK]
|
| 803 |
+
## 時計算の基本:長針と短針の速さの理解
|
| 804 |
+
時計算は、時計の針の角度や位置関係を扱う問題。長針と短針は、それぞれ異なる速さで回転しており、長針は1時間で360度、短針は12時間で360度回転する。時計算では、長針と短針のそれぞれの速さを正確に把握し、角度や時間の計算を行う必要がある。長針と短針の速さの差を理解することが、時計算の問題を解く上で重要。
|
| 805 |
+
|
| 806 |
+
[CHUNK]
|
| 807 |
+
## 時計算の応用:角度と時間の計算
|
| 808 |
+
時計算では、特定の時刻における長針と短針の角度や、針が重なる時刻などを計算する。例えば、4時の場合、長針は12の位置、短針は4の位置にあり、その間の角度は120度となる。長針と短針が重なる時刻を求めるには、それぞれの針の速さの差を利用する。時計算は、線分図を用いることで、針の動きを視覚的に捉え、問題を解きやすくなる。時計算は、算数の応用問題として頻出。
|
knowledge/ORIGINAL/算数/四天王寺対策算数.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
knowledge/ORIGINAL/算数/算数出る順文章題.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
log/HF_PROBLEM_LOG.txt
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Logs
|
| 3 |
+
|
| 4 |
+
build
|
| 5 |
+
container
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
===== Application Startup at 2025-12-19 14:57:58 =====
|
| 10 |
+
|
| 11 |
+
INFO:src.services.gemini_service:Gemini API initialized with model: gemini-2.5-flash (google-genai SDK)
|
| 12 |
+
INFO:src.services.gas_client:GAS API URL configured
|
| 13 |
+
INFO: Started server process [1]
|
| 14 |
+
INFO: Waiting for application startup.
|
| 15 |
+
INFO: Application startup complete.
|
| 16 |
+
INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
|
| 17 |
+
INFO: 10.16.43.133:52881 - "GET / HTTP/1.1" 200 OK
|
| 18 |
+
INFO: 10.16.43.133:52881 - "GET /js/mockData.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 19 |
+
INFO: 10.16.43.133:9055 - "GET /js/sessionManager.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 20 |
+
INFO: 10.16.12.39:50195 - "GET /css/style.css HTTP/1.1" 200 OK
|
| 21 |
+
INFO: 10.16.12.39:9636 - "GET /js/config.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 22 |
+
INFO: 10.16.12.39:63870 - "GET /js/apiClient.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 23 |
+
INFO: 10.16.12.39:9636 - "GET / HTTP/1.1" 200 OK
|
| 24 |
+
INFO: 10.16.43.133:9055 - "GET /css/style.css HTTP/1.1" 304 Not Modified
|
| 25 |
+
INFO: 10.16.12.39:9636 - "GET /js/config.js?v=20251211-4 HTTP/1.1" 304 Not Modified
|
| 26 |
+
INFO: 10.16.12.39:63870 - "GET /js/apiClient.js?v=20251211-4 HTTP/1.1" 304 Not Modified
|
| 27 |
+
INFO: 10.16.43.133:52881 - "GET /js/mockData.js?v=20251211-4 HTTP/1.1" 304 Not Modified
|
| 28 |
+
INFO: 10.16.43.133:44835 - "GET /js/sessionManager.js?v=20251211-4 HTTP/1.1" 304 Not Modified
|
| 29 |
+
INFO: 10.16.43.133:44835 - "GET /js/components.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 30 |
+
INFO: 10.16.12.39:63870 - "GET /js/icons.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 31 |
+
INFO: 10.16.12.39:54085 - "GET / HTTP/1.1" 200 OK
|
| 32 |
+
INFO: 10.16.43.133:42873 - "GET / HTTP/1.1" 200 OK
|
| 33 |
+
INFO: 10.16.43.133:42873 - "GET /css/style.css HTTP/1.1" 200 OK
|
| 34 |
+
INFO: 10.16.43.133:54170 - "GET /js/sessionManager.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 35 |
+
INFO: 10.16.43.133:42873 - "GET /js/mockData.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 36 |
+
INFO: 10.16.12.39:49461 - "GET /js/config.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 37 |
+
INFO: 10.16.12.39:9600 - "GET /js/apiClient.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 38 |
+
INFO: 10.16.43.133:46734 - "GET /js/apiClient.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 39 |
+
INFO: 10.16.12.39:50630 - "GET /css/style.css HTTP/1.1" 200 OK
|
| 40 |
+
INFO: 10.16.12.39:5865 - "GET /js/config.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 41 |
+
INFO: 10.16.43.133:60018 - "GET /js/mockData.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 42 |
+
INFO: 10.16.12.39:37658 - "GET /js/sessionManager.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 43 |
+
INFO: 10.16.43.133:60018 - "GET /js/components.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 44 |
+
INFO: 10.16.12.39:5865 - "GET /js/icons.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 45 |
+
INFO: 10.16.43.133:59360 - "GET / HTTP/1.1" 200 OK
|
| 46 |
+
INFO: 10.16.43.133:59360 - "GET /js/mockData.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 47 |
+
INFO: 10.16.43.133:9340 - "GET /js/config.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 48 |
+
INFO: 10.16.12.39:46214 - "GET /css/style.css HTTP/1.1" 200 OK
|
| 49 |
+
INFO: 10.16.12.39:46214 - "GET /js/sessionManager.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 50 |
+
INFO: 10.16.12.39:54735 - "GET /js/apiClient.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 51 |
+
INFO: 10.16.43.133:9340 - "GET /js/icons.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 52 |
+
INFO: 10.16.12.39:54735 - "GET /js/components.js?v=20251211-4 HTTP/1.1" 200 OK
|
| 53 |
+
INFO:__main__:register_user: Invite code verified for user 'tomohiro'
|
| 54 |
+
INFO:__main__:register_user: Password hashed for user 'tomohiro'
|
| 55 |
+
INFO:src.services.gas_client:Calling GAS API: register_user
|
| 56 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 57 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLgBRTjim8fmZX83XACHA57SZHe6Ket7vHnF9qZPCMxfyEYmqiFc7_FW93ZhghguYwelLFZsa4ox0RHfzeMSLKpVLxXFvDAQQsvDN01IfBciZI6NgKwX3iH2WQTjrVu5b_xfuwW46t2CO5gSzxT_wpkH6G3UH6pv6XND4gSaxMW3PI5N-llo6lR-ym-CC7Pk9B8wLOydGHSOv5c0eFdmz2dL682NjFjsacqfb645b5nBrPsqbURr8zpL5t8EgS3yR0wapq5gqUy3hHNFSWQvWpDIl2zDdA&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 58 |
+
INFO:src.services.gas_client:GAS API response: success=success
|
| 59 |
+
INFO: 10.16.12.39:4994 - "POST /api/register_user HTTP/1.1" 200 OK
|
| 60 |
+
INFO:src.services.gas_client:Calling GAS API: start_session
|
| 61 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 62 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLgADS8ldWGTuvuqy3kdar_FOxPLO4IxStOcgtjlrns5cwHaqKqj7Fe2-y8JcnYP3GMqE0LaKzBoHpMaZwcmhBcEXi9jgEZm8yj6nEaIqRtChTLDoEa_SUiV8sDzlo_MPeOaYR8mtcwiBKC0VBaInoH9bzProYf1grF5LPTKgVsRtagbxAdrm7np_boLhSASchuymP4uBSA8pDaLRcKZL6aa38FPuisTFKAQevPainvDnqZlA2Sl7tfXWQLnAMHASIptLPBC1uXvxlkxn8fB2CSRmWPOcw&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 63 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 64 |
+
INFO: 10.16.43.133:57096 - "POST /api/start_session HTTP/1.1" 200 OK
|
| 65 |
+
INFO:__main__:generate_questions: Starting QuestionDB-driven generation for 1 subjects: ['jp']
|
| 66 |
+
INFO:src.services.gas_client:Calling GAS API: get_statistics
|
| 67 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 68 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLhv6xWiIhQnoiD71PF2eECxGQRbyggFlJKtedCNrXUUleyQn_Zsjivhi_P59WjhP825lC_-4XxmlRr1CkcYE6Q1Vw6l2gE4J0E4ayqBG69_fs7KAeP0Dj406aPJc6k0NIDh5jebxwvi36ESTRTSTBqoh0ej8TmEGgnNdaCzR11sjIEuw8HyS0BX4mKfrzr-v-TLDazp6Ve2lfOGBzRY0zEZZuxWMeno4olDDYyUbnNvzJMjc4l9Ex2iaCMZVv4OtR_EB2T7zp23pBGOom8e8vUiuJ2BcQ&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 69 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 70 |
+
INFO:__main__:generate_questions: Got priority_genres for 0 subjects
|
| 71 |
+
INFO:src.services.gas_client:Calling GAS API: get_question_summaries
|
| 72 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 73 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLjuVCZVoVs6pBjrpdfu8gjm0zwThehVxlYiKA89ofibc3IGIOMrQZlBUkvSjeZEaq5sAbC67elR8RmaZW_WFnci_Om4Yltj1FE2GB6KjUfJcpQD7NiEQ1gAfjVHZX8TpFR4-Kr1rRhaiOnY1FEpw5h_Uu9PnUm4_2Z6nbYpxTbCwVRVvnTCKZ9psh1nOjt43ybDoXh_zml4i9AjRJp4mPQQ6isHnaZcNZJkeg-w9BlHjvXY8rnahLAVrjISgdXQwY9c01CU2zxx9dAmcQUAFlUBHcz20g&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 74 |
+
INFO:src.services.gas_client:GAS API response: success=False
|
| 75 |
+
INFO:__main__:generate_questions: Got 0 exclude keywords
|
| 76 |
+
INFO:__main__:generate_questions: Fetching questions from QuestionDB
|
| 77 |
+
INFO:src.services.questiondb_service:get_questions_from_db: Requesting questions for 1 subjects
|
| 78 |
+
INFO:src.services.gas_client:get_random_questions: Requesting 10 questions per subject for 1 subjects
|
| 79 |
+
INFO:src.services.gas_client:Calling GAS API: get_random_questions
|
| 80 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 81 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLi97-y13VSVIiM77gpvxxauM_dRl2uzCrRRRQlEo2Um3P9AX4RpDBlBDYSjgMGAD5fSfqVlBb0_w5-gqv72vN_jLOrZqpvyhIo-E0EyhL_wzTVlQvJPCFNn36LHJ4LEi8HJH4zRlF43YH1qUTJ5jw9a-rktuTv8KNm6ZmxQfvEBi6fp7_q-N4hfU6jcMUbFS8gfgc-dPMYLFGI99kiZ1TBOTzDd-Y7bU85ftz_GT__QpoqVB1kyACkmuQFqkHgaFdkGw_jCgMgePhkJi7RpDzrrYUbidQ&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 82 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 83 |
+
INFO:src.services.questiondb_service:get_questions_from_db: Retrieved 10 questions from DB (grouped into 1 subjects)
|
| 84 |
+
INFO:src.services.questiondb_service:get_questions_from_db: Generating questions via single LLM call for 1 subjects
|
| 85 |
+
INFO:src.services.gemini_service:Batch generating questions for 1 subjects: ['jp']
|
| 86 |
+
INFO:google_genai.models:AFC is enabled with max remote calls: 10.
|
| 87 |
+
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent "HTTP/1.1 200 OK"
|
| 88 |
+
INFO:src.services.gemini_service:Generated 10 questions for jp
|
| 89 |
+
INFO:src.services.questiondb_service:get_questions_from_db: Generated 10 questions for jp
|
| 90 |
+
INFO:__main__:generate_questions: Retrieved 10 questions from DB
|
| 91 |
+
INFO:src.services.gas_client:save_questions: Sending request - session_id=74e4c2b9-ae75-4718-af1e-975025d189b2, subject=jp, questions_count=10
|
| 92 |
+
INFO:src.services.gas_client:Calling GAS API: save_questions
|
| 93 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 94 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLhf2TdCciPCy3wqQrkQqXGFwKTQlQVr_NJPgW6f79zSNB9RnGLZg8B4n2UmJnSVYMFXSk2IMoA83P8_ZiduYd_FO9mpGo_xxwglXn4uASgZEs6QWNAoPrFKEG5ym6D_6IdasjSyuwbz1fjJn4yIejBMuJsDmq4R2LtQUrcVH2xHvrELd97DxERitJ7FOX_U-RHo7CCi-MBbxVCUvvV7t6ak4WmdiYRPJ6xv3sgAWRgvkB4O_PIu0-8yBUnNsPR5CURl1phv_sngFKunxiFZdyHg1OqLkA&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 95 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 96 |
+
INFO:src.services.gas_client:save_questions: Response received - success=True, returned_question_count=10, question_ids=['2b17f034-2f9c-41bc-88b2-caca2c9851b1', '481685c5-3ffe-43e7-9240-3ca8aae39324', 'af14c3b1-1c25-421f-b220-ae395a175211', '98f94418-8160-47e6-8a47-dae2b7f8edb8', 'f74eaf74-6285-4631-b224-59637a010ca5']...
|
| 97 |
+
INFO:__main__:generate_questions: Saved 10 questions for 'jp'
|
| 98 |
+
INFO:__main__:generate_questions: Question save summary - total_subjects=1
|
| 99 |
+
INFO:__main__:generate_questions: Saved summary - subject=jp, saved_count=10
|
| 100 |
+
INFO:__main__:generate_questions: All questions saved - total_count=10
|
| 101 |
+
INFO:__main__:generate_questions: Background summary generation task created
|
| 102 |
+
INFO:__main__:generate_questions: Completed with 10 total questions
|
| 103 |
+
INFO: 10.16.43.133:57096 - "POST /api/generate_questions HTTP/1.1" 200 OK
|
| 104 |
+
INFO:__main__:background_summary_generation: Starting for session_id=74e4c2b9-ae75-4718-af1e-975025d189b2
|
| 105 |
+
INFO:__main__:background_summary_generation: Generating summary for jp (10 questions)
|
| 106 |
+
INFO:src.services.gemini_service:Generating summary for subject: jp (10 questions)
|
| 107 |
+
INFO:google_genai.models:AFC is enabled with max remote calls: 10.
|
| 108 |
+
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent "HTTP/1.1 200 OK"
|
| 109 |
+
INFO:src.services.gemini_service:Summary generated for jp: 10 keywords, 10 topics
|
| 110 |
+
INFO:__main__:background_summary_generation: Saving summary for jp to GAS
|
| 111 |
+
INFO:src.services.gas_client:save_summary: Saving summary for session_id=74e4c2b9-ae75-4718-af1e-975025d189b2, subject=jp
|
| 112 |
+
INFO:src.services.gas_client:Calling GAS API: save_summary
|
| 113 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 114 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLgbJIajXfh0XLIFPZME9mGMe0fp3ulwaH60L1l0T1vVSxsCgeEUfhb0P5avPxVXFZLdhrUvWbI1HPbK4A3vGNnXJ1x_l0RqKqpw1Vh2d_O5Z8Z9Uv_awFAvXPdT_E4BuWrMO8iD6zY1ftAdADpwa5gJhm3oh-CbjNRiaD4g5eWEdA96gvhiyoZPdhr0PHIIgmsJNd0Cb8ATQ_jKQBnJNgHrnI2pD0qhxmkqVXIRlQP76B_Z5gPZzctEcklIwJyeYuSfYOX8TgxcRtHuF2P0xfa-_pm_fg&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 115 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 116 |
+
INFO:__main__:background_summary_generation: Summary saved successfully for jp
|
| 117 |
+
INFO:__main__:background_summary_generation: Completed for session_id=74e4c2b9-ae75-4718-af1e-975025d189b2
|
| 118 |
+
INFO:src.services.gas_client:Calling GAS API: submit_answers
|
| 119 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 120 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLhDKWqENpleMTaSYh6rYv2ddDQ2ZhgXwM5XYScAR-7Nt-SjJt-QPKk1eEFrKYU-c_ks8mvtobmnhoUItsAb4RfiWbvUMhH18NbYJ_h1myVWh3-wsO22jo8ZdS_JUCZkgE9tC_sbpJ3RLWDE66acrRhRbmfIVJgo-JWyfVm8C8AovzXsF2gGZRUYf40CCXBzEYBM-qHPU-7ETQww3rX-voXjM-tbkKqAqhxULKSr4AJ4y-ZoaNeP4D5MG279uaQGzFAFWzWzetvSzf4y7nM5NapF3d0-qw&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 121 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 122 |
+
INFO: 10.16.12.39:52745 - "POST /api/submit_answers HTTP/1.1" 200 OK
|
| 123 |
+
INFO:src.services.gas_client:Calling GAS API: get_statistics
|
| 124 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 125 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLjHR94RynKgeEKwm81k6LhLoQgHaSWjh_cNRu6GX2485eNauiaIiVA-HQTLnwOxvRnhnSi_0gjCXDgbUfpHyQKzWk00xgZpXgukzhYusVc0gh69wfAo4au0QHvxKxwMPikWpdyh_pneXAyD79mRkPqZNRsfQAtNJ6nwIiAYULks33uoespqc-EWmV2JOww618_57MPDOPzLmbwLVeBjSE_qYOr2ODpzYb3vHC553JWzsvWWstGGxntGEx3JHDMMZ93HKA91m2gZlyh0jNrF_jdsSxj7eA&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 126 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 127 |
+
INFO: 10.16.43.133:40992 - "POST /api/get_statistics HTTP/1.1" 200 OK
|
| 128 |
+
INFO:__main__:get_evaluation: Fetching session results for 74e4c2b9-ae75-4718-af1e-975025d189b2
|
| 129 |
+
INFO:src.services.gas_client:Calling GAS API: get_session_results
|
| 130 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 131 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLhXvjftrPz_n8-kPKxEkwlNy8c4G3D45BRScpWmAREuf3OW3KBGSHH_MrHkbQN7W6i94MSD9B3mgPUCfnk-ZDmJmRXNwNkSOft-zWtzvPU8izv3UcSrhaCfkOHZgSjSU_1S5wI7L_-uqNxufUJ9FvaJQAuNw0dQJzugKYSqcoADRkmPgEiMg4ScVmQ-FxtHJcLx0J3D_W4Q6Je6-pjnwIThefgytk8naSpDdOaaBfLvB2MGvRBinGD2DnVK2G3plmCdFmo4cv2KfC0Qx5H3g8BsantZwQ&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 132 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 133 |
+
INFO:__main__:get_evaluation: Session data received: True
|
| 134 |
+
INFO:src.services.gas_client:Calling GAS API: check_summary_status
|
| 135 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 136 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLhwNbJQ3r3TENEVnsio-cx9fSyqLPpSAbYio1g0ofFNWGT9os3ITYh8_QR19h0gr3zeBM9NkUl_zFm5tv6k0xoy17ORN9YRaecoudtsO5rFBY3j6p46Txl4acNSKgs_GPYHUbiO13p3U4z4OhWG_aNkSNgc2CUzHsXoAINk4s_wH9pTVwkKtC_kg6YgUH4zEbsrdUGvWi_rloRCuYyc7bQMSgpQVClqBmKAjB2tXm2AfV8uyAMaBGljoH8TI0eG_HmNnhTw1BTTRSVoDQqdi61fmMJy0A&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 137 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 138 |
+
INFO:__main__:get_evaluation: Summary status - completed: None, count: None
|
| 139 |
+
INFO:__main__:get_evaluation: Transformed data - subjects: ['jp'], total_results: 10
|
| 140 |
+
INFO:__main__:get_evaluation: Generating batch evaluation via Gemini
|
| 141 |
+
INFO:src.services.gemini_service:Single subject detected, using structured output evaluation
|
| 142 |
+
INFO:google_genai.models:AFC is enabled with max remote calls: 10.
|
| 143 |
+
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent "HTTP/1.1 200 OK"
|
| 144 |
+
INFO:__main__:get_evaluation: Generated 1 evaluations (including overall)
|
| 145 |
+
INFO:src.services.gas_client:Calling GAS API: save_evaluations
|
| 146 |
+
INFO:httpx:HTTP Request: POST https://script.google.com/macros/s/AKfycbyZlXUFTTWALmcGaVeB_vjvExOdiZ7tKPVO6ltahQrg2ypKJW2899MMoOjDEJOc-QMG/exec "HTTP/1.1 302 Moved Temporarily"
|
| 147 |
+
INFO:httpx:HTTP Request: GET https://script.googleusercontent.com/macros/echo?user_content_key=AehSKLga20SnVs0X02Z0ksG8hLxq8gAJq0RudHX78eXRUMppXPtD05-lXJpINR7vktOYsV6STJNJvjAQbtnXRvciEMeHesr_6n4VhwtsJEKl9W-eTuQn49hWlwLx9ur95PuuohYz_plM5zQl5swJ-SIOCGPvWj7Y3qVq0CnalRNJHICNz9L10td3Ph-CWjrVrG-Cik23QhATPVXu_eVUbCeMyfsYUMljDAwegccA8UwOr4K74--iiNNKERgA2q1PGwiaHsebJxFnBZsPRuDqNQkQokQZNBJ2zA&lib=MOdRsF8MegeT6-0UsFwBOzTOUKBviU6ON "HTTP/1.1 200 OK"
|
| 148 |
+
INFO:src.services.gas_client:GAS API response: success=True
|
| 149 |
+
INFO:__main__:get_evaluation: Save result: True
|
| 150 |
+
INFO: 10.16.43.133:40992 - "POST /api/get_evaluation HTTP/1.1" 200 OK
|
log/LOG.md
CHANGED
|
@@ -1,8 +1,39 @@
|
|
| 1 |
# 開発ログ
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
## v1.6.8 正答位置バグ修正・シートリセット
|
| 4 |
|
| 5 |
-
### 2025-12-20 00:30 - v1.6.8 実装完了
|
| 6 |
|
| 7 |
#### 問題の根本原因
|
| 8 |
**SCORE 0/0 の原因**: `shuffle_choices()`関数のインデックス変換バグ
|
|
@@ -13,34 +44,20 @@
|
|
| 13 |
#### 実施作業
|
| 14 |
|
| 15 |
| ファイル | 変更内容 |
|
| 16 |
-
|---------|---------
|
| 17 |
| `src/prompts/question_prompts.py` | `correct_answer: 1-4` + 位置分散指示追加 |
|
| 18 |
| `src/prompts/validation_prompts.py` | 位置偏り検出・選択肢入れ替え指示追加 |
|
| 19 |
| `src/services/gemini_service.py` | 全9箇所の`max_output_tokens`を65536に統一 |
|
| 20 |
-
| `app.py` | `shuffle_choices` → `convert_correct_answer_index`に簡略化
|
| 21 |
| `gas/setup_sheets_v3.js` | シート削除・初期化関数を新規作成 |
|
| 22 |
|
| 23 |
-
#### 完成したもの
|
| 24 |
-
- ✅ 生成プロンプト修正
|
| 25 |
-
- ✅ 検証プロンプト修正
|
| 26 |
-
- ✅ MAX_OUTPUT_TOKENS統一
|
| 27 |
-
- ✅ index変換関数実装
|
| 28 |
-
- ✅ GASシート初期化関数作成
|
| 29 |
-
- ✅ clasp push完了
|
| 30 |
-
|
| 31 |
#### ステータス
|
| 32 |
- ✅ コード修正完了
|
| 33 |
- ✅ clasp push完了
|
| 34 |
-
-
|
| 35 |
-
-
|
| 36 |
-
-
|
| 37 |
-
-
|
| 38 |
-
|
| 39 |
-
#### 次回開始時の指針
|
| 40 |
-
1. GASエディタで `resetAndInitialize()` 実行(シートリセット)
|
| 41 |
-
2. GAS再デプロイ(@37)
|
| 42 |
-
3. git commit & push
|
| 43 |
-
4. E2Eテスト
|
| 44 |
|
| 45 |
---
|
| 46 |
|
|
@@ -62,11 +79,6 @@
|
|
| 62 |
- AI先生アドバイスは正常に表示
|
| 63 |
- SCOREが0/0 → GAS側 or スコア計算ロジックに問題あり
|
| 64 |
|
| 65 |
-
#### 次の調査ポイント
|
| 66 |
-
1. Answersシートの内容確認(is_correct列の値)
|
| 67 |
-
2. get_session_resultsの返却データ確認
|
| 68 |
-
3. フロントエンドのスコア計算ロジック確認
|
| 69 |
-
|
| 70 |
---
|
| 71 |
|
| 72 |
## v1.6.7 Gemini Structured Output導入
|
|
@@ -88,38 +100,12 @@ Gemini の **Structured Output** 機能を使用し、`response_json_schema` パ
|
|
| 88 |
- SubjectEvaluationSchema: 教科別評価用
|
| 89 |
- OverallEvaluationSchema: 全体評価用
|
| 90 |
- BatchEvaluationSchema: 一括評価用
|
| 91 |
-
- get_list_schema(): 配列スキーマ生成ヘルパー
|
| 92 |
|
| 93 |
2. `src/services/gemini_service.py` 更新
|
| 94 |
- generate_summary: SummarySchema適用
|
| 95 |
- generate_questions_batch: QuestionSchema配列適用
|
| 96 |
- generate_evaluation_batch: BatchEvaluationSchema適用
|
| 97 |
|
| 98 |
-
#### 技術詳細
|
| 99 |
-
```python
|
| 100 |
-
# Before: JSONをリクエストするだけ
|
| 101 |
-
config=types.GenerateContentConfig(
|
| 102 |
-
response_mime_type="application/json"
|
| 103 |
-
)
|
| 104 |
-
|
| 105 |
-
# After: スキーマでJSON構造を保証
|
| 106 |
-
config=types.GenerateContentConfig(
|
| 107 |
-
response_mime_type="application/json",
|
| 108 |
-
response_json_schema=SummarySchema.model_json_schema()
|
| 109 |
-
)
|
| 110 |
-
```
|
| 111 |
-
|
| 112 |
-
#### ステータス
|
| 113 |
-
- ✅ Pydanticスキーマ作成完了
|
| 114 |
-
- ✅ gemini_service.py更新完了
|
| 115 |
-
- ✅ 構文チェック・インポートテスト完了
|
| 116 |
-
- ✅ git commit & push完了(`e643381`)
|
| 117 |
-
- 🔲 E2Eテスト待ち
|
| 118 |
-
|
| 119 |
-
#### コミット情報
|
| 120 |
-
- コミットID: `e643381`
|
| 121 |
-
- ロールバック: `git revert e643381`
|
| 122 |
-
|
| 123 |
---
|
| 124 |
|
| 125 |
## v1.6.6 SCORE・AI評価バグ修正
|
|
@@ -135,236 +121,32 @@ config=types.GenerateContentConfig(
|
|
| 135 |
**問題1: SCORE 0/10**
|
| 136 |
- Answersシートのカラムがずれていた
|
| 137 |
- `gas/Code.js` `handleSubmitAnswers` で `subject`, `category`, `correct_answer` が保存されていなかった
|
| 138 |
-
- ヘッダーは10列だが、実際には7列しか書き込んでいなかった
|
| 139 |
|
| 140 |
**問題2: AI先生アドバイス非表示**
|
| 141 |
- ログ: `ERROR:src.services.gemini_service:Evaluation JSON parse error`
|
| 142 |
- `src/prompts/evaluation_prompts.py` のJSON例に日本語テキストが含まれ、Geminiが不正なJSONを生成
|
| 143 |
|
| 144 |
-
#### 実施作業
|
| 145 |
-
1. `gas/Code.js` 行681-692: answerRowに3カラム追加
|
| 146 |
-
- `subject || ''`
|
| 147 |
-
- `category || ''`
|
| 148 |
-
- `correctAnswer`
|
| 149 |
-
2. `src/prompts/evaluation_prompts.py` 行184-198: JSON例をプレースホルダに変更
|
| 150 |
-
- 日本語テキスト → 英語プレースホルダ
|
| 151 |
-
3. GASデプロイ: @36(同じデプロイID維持)
|
| 152 |
-
4. git commit & push: `bba4cd7`
|
| 153 |
-
|
| 154 |
-
#### 修正内容
|
| 155 |
-
|
| 156 |
-
**gas/Code.js (行681-692)**:
|
| 157 |
-
```javascript
|
| 158 |
-
const answerRow = [
|
| 159 |
-
answerId, // answer_id
|
| 160 |
-
sessionId, // session_id
|
| 161 |
-
questionId, // question_id
|
| 162 |
-
subject || '', // subject ← 追加
|
| 163 |
-
category || '', // category ← 追加
|
| 164 |
-
userAnswer, // user_answer
|
| 165 |
-
correctAnswer, // correct_answer ← 追加
|
| 166 |
-
isCorrect, // is_correct
|
| 167 |
-
timeTaken, // time_spent
|
| 168 |
-
answeredAt // submitted_at
|
| 169 |
-
];
|
| 170 |
-
```
|
| 171 |
-
|
| 172 |
-
**src/prompts/evaluation_prompts.py (行184-198)**:
|
| 173 |
-
- JSON例の日本語テキストをプレースホルダに変更
|
| 174 |
-
|
| 175 |
-
#### ステータス
|
| 176 |
-
- ✅ gas/Code.js修正完了
|
| 177 |
-
- ✅ evaluation_prompts.py修正完了
|
| 178 |
-
- ✅ GASデプロイ完了(@36)
|
| 179 |
-
- ✅ git commit完了(`bba4cd7`)
|
| 180 |
-
- 🔲 E2Eテスト待ち
|
| 181 |
-
|
| 182 |
-
#### コミット情報
|
| 183 |
-
- コミットID: `bba4cd7`
|
| 184 |
-
- ロールバック: `git revert bba4cd7`
|
| 185 |
-
|
| 186 |
-
#### 次回開始時の指針
|
| 187 |
-
- 次のタスク: E2Eテスト(ブラウザで全フロー確認)
|
| 188 |
-
- URL: https://leave-everything-chotensai-v3.hf.space
|
| 189 |
-
- HF Spaces再起動待ち(約1-2分)
|
| 190 |
-
- 確認ポイント:
|
| 191 |
-
- SCOREが正しく計算されるか
|
| 192 |
-
- AI先生アドバイスが表示されるか
|
| 193 |
-
- Answersシートに10列すべて保存されるか
|
| 194 |
-
|
| 195 |
---
|
| 196 |
|
| 197 |
-
##
|
| 198 |
-
|
| 199 |
-
### 2025-12-19 22:00 - 選択肢シャッフル機能実装 ✅
|
| 200 |
-
|
| 201 |
-
#### 問題概要
|
| 202 |
-
- **症状**: 正解が常に同じ位置(例: 常に選択肢1)になり、SCORE 0/10問題が発生
|
| 203 |
-
- **原因**: 選択肢がシャッフルされておらず、正解位置が固定されていた
|
| 204 |
-
|
| 205 |
-
#### 実施作業
|
| 206 |
-
1. `app.py`: `random`モジュールをインポート
|
| 207 |
-
2. `app.py`: `shuffle_choices`関数を実装
|
| 208 |
-
- 選択肢配列をランダムシャッフル
|
| 209 |
-
- 正解の選択肢を追跡し、新しいインデックスに`correct_answer`を更新
|
| 210 |
-
- 型チェック・範囲外チェックによるエラーハンドリング
|
| 211 |
-
3. `generate_questions`内で各問題に`shuffle_choices`を適用(行388)
|
| 212 |
-
|
| 213 |
-
#### 修正内容(app.py)
|
| 214 |
-
- 行12: `import random` 追加
|
| 215 |
-
- 行256-290: `shuffle_choices`関数実装
|
| 216 |
-
- 行388: 問題データ集約時にシャッフル適用
|
| 217 |
-
|
| 218 |
-
#### ステータス
|
| 219 |
-
- ✅ app.py修正完了
|
| 220 |
-
- ✅ 構文チェック完了
|
| 221 |
-
- ✅ git commit完了(`2b25b87`)
|
| 222 |
-
|
| 223 |
-
#### コミット情報
|
| 224 |
-
- コミットID: `2b25b87`
|
| 225 |
-
- ロールバック: `git revert 2b25b87`
|
| 226 |
-
|
| 227 |
-
---
|
| 228 |
-
|
| 229 |
-
## v1.6.4 フロントエンド表示バグ修正
|
| 230 |
-
|
| 231 |
-
### 2025-12-19 21:30 - generate_questions レスポンスデータ修正 ✅
|
| 232 |
-
|
| 233 |
-
#### 問題概要
|
| 234 |
-
- **症状**: v1.6.3修正後も問題生成後UIが白くなる
|
| 235 |
-
- **原因**: GAS save_questionsのレスポンスにchoices, correct_answer, subject_nameが欠落
|
| 236 |
-
|
| 237 |
-
#### 実施作業
|
| 238 |
-
1. `app.py` generate_questions修正
|
| 239 |
-
- 元のGemini生成データ(questions_by_subject)を使用
|
| 240 |
-
- GASから返った question_id をマージ
|
| 241 |
-
- subject_name を追加
|
| 242 |
-
|
| 243 |
-
#### ステータス
|
| 244 |
-
- ✅ app.py修正完了
|
| 245 |
-
- ✅ git push完了(`40d4b97`)
|
| 246 |
-
|
| 247 |
-
---
|
| 248 |
-
|
| 249 |
-
## v1.6.3 バグ修正完了
|
| 250 |
-
|
| 251 |
-
### 2025-12-19 20:10 - GASシート参照バグ修正・save_evaluations追加 ✅
|
| 252 |
-
|
| 253 |
-
#### 問題概要
|
| 254 |
-
- **症状1**: 問題生成後UIが白くなって動かない
|
| 255 |
-
- **症状2**: シートに40問記録されていない(ログでは成功)
|
| 256 |
-
|
| 257 |
-
#### 原因分析
|
| 258 |
-
1. **getSessionResults()のシート参照不整合**: GeneratedQuestionsに保存するが、Questionsを参照していた
|
| 259 |
-
2. **save_evaluationsエンドポイント未実装**: GAS側に存在せず"Unknown action"エラー
|
| 260 |
-
3. **フロントエンドエラーハンドリング不足**: APIエラー時にUI更新されず白画面
|
| 261 |
-
|
| 262 |
-
#### 実施作業
|
| 263 |
-
1. `gas/Code.js` - getSessionResults(): シート参照をGENERATED_QUESTIONSに変更、カラムマッピング修正
|
| 264 |
-
2. `gas/Code.js` - handleSaveEvaluations(): 新規実装、Evaluationsシートへ保存
|
| 265 |
-
3. `gas/Code.js` - doPost switch: save_evaluationsケース追加
|
| 266 |
-
4. `static/js/components.js` - ResultScreen: エラーハンドリング追加
|
| 267 |
-
5. GASデプロイ: @32 → @34(v1.6.3)
|
| 268 |
-
|
| 269 |
-
#### ステータス
|
| 270 |
-
- ✅ GAS修正完了
|
| 271 |
-
- ✅ フロントエンド修正完了
|
| 272 |
-
- ✅ GASデプロイ完了(@34)
|
| 273 |
-
|
| 274 |
-
---
|
| 275 |
-
|
| 276 |
-
## v1.6.2 Phase 2完了
|
| 277 |
-
|
| 278 |
-
### 2025-12-19 15:10 - 全API復旧確認完了 ✅
|
| 279 |
-
|
| 280 |
-
#### 実施作業
|
| 281 |
-
Phase 2として全HF APIエンドポイントのテストを実施
|
| 282 |
-
|
| 283 |
-
**テスト結果**:
|
| 284 |
-
| エンドポイント | ステータス | レスポンスタイム |
|
| 285 |
-
|--------------|----------|---------------|
|
| 286 |
-
| /api/start_session | ✅ 200 OK | 3.5秒 |
|
| 287 |
-
| /api/generate_questions | ✅ 200 OK | 77秒(10問生成) |
|
| 288 |
-
| /api/submit_answers | ✅ 200 OK | 6.9秒 |
|
| 289 |
-
| /api/get_evaluation | ✅ 200 OK | 7.8秒 |
|
| 290 |
-
|
| 291 |
-
#### ステータス
|
| 292 |
-
- ✅ API全機能復旧完了
|
| 293 |
-
|
| 294 |
-
---
|
| 295 |
-
|
| 296 |
-
## v1.6.1 復旧作業
|
| 297 |
-
|
| 298 |
-
### 2025-12-19 14:30 - 認証機能バグ修正完了 ✅
|
| 299 |
-
|
| 300 |
-
#### 問題の原因
|
| 301 |
-
**app.py 210行目のバグ**:
|
| 302 |
-
```python
|
| 303 |
-
# 修正前(バグ)
|
| 304 |
-
data = result.get("data", {})
|
| 305 |
-
if not data.get("found"): # ← "found"はdataオブジェクト内にない!
|
| 306 |
-
|
| 307 |
-
# 修正後(正常)
|
| 308 |
-
if not result.get("found"): # ← resultの直下にfoundがある
|
| 309 |
-
data = result.get("data", {})
|
| 310 |
-
```
|
| 311 |
-
|
| 312 |
-
#### ステータス
|
| 313 |
-
- ✅ 修正完了
|
| 314 |
-
- ✅ デプロイ完了
|
| 315 |
-
- ✅ テスト合格
|
| 316 |
-
|
| 317 |
-
#### コミット情報
|
| 318 |
-
- コミットID: `e13a47f`
|
| 319 |
-
|
| 320 |
-
---
|
| 321 |
-
|
| 322 |
-
### 2025-12-19 08:20 - 開発環境整理・一本化完了 ✅
|
| 323 |
-
|
| 324 |
-
#### 完成したもの
|
| 325 |
-
- ✅ 超天才クイズv3フォルダに一本化
|
| 326 |
-
- ✅ Gitリポジトリ有効
|
| 327 |
-
- ✅ v1.6.1にリセット
|
| 328 |
-
- ✅ GAS @32デプロイ
|
| 329 |
-
|
| 330 |
-
---
|
| 331 |
-
|
| 332 |
-
## v1.6.1 安定版確定
|
| 333 |
-
|
| 334 |
-
### 2025-12-18 - v1.6.1 安定版としてタグ付け ✅
|
| 335 |
-
|
| 336 |
-
#### v1.6.1 の機能状態
|
| 337 |
-
| 機能 | ステータス |
|
| 338 |
-
|------|---------|
|
| 339 |
-
| 認証(ログイン/新規登録) | ✅ |
|
| 340 |
-
| 問題生成(QuestionDB駆動) | ✅ |
|
| 341 |
-
| 全ジャンル網羅 | ✅ |
|
| 342 |
-
| GAS API連携 | ✅ |
|
| 343 |
-
| AI先生アドバイス | ✅ |
|
| 344 |
-
| 問題UI | ✅ |
|
| 345 |
-
|
| 346 |
-
---
|
| 347 |
-
|
| 348 |
-
## v1.6.0 QuestionDB駆動導入
|
| 349 |
|
| 350 |
-
###
|
|
|
|
| 351 |
|
| 352 |
-
###
|
| 353 |
-
-
|
| 354 |
-
- QuestionDB(Sheets)からの問題取得に一本化
|
| 355 |
-
- 4教科×400問 = 1,600問のデータベース構築
|
| 356 |
|
| 357 |
-
###
|
| 358 |
-
-
|
| 359 |
|
| 360 |
-
|
|
|
|
| 361 |
|
| 362 |
-
##
|
|
|
|
| 363 |
|
| 364 |
-
### v1.
|
| 365 |
-
-
|
| 366 |
-
- KnowledgeBase駆動問題生成
|
| 367 |
-
- GAS連携基盤
|
| 368 |
|
| 369 |
---
|
| 370 |
-
**最終更新**: 2025-12-
|
|
|
|
| 1 |
# 開発ログ
|
| 2 |
|
| 3 |
+
## v1.6.9 correct_answer 0-indexed統一・temperature統一
|
| 4 |
+
|
| 5 |
+
### 2025-12-20 01:00 - v1.6.9 実装完了 ✅
|
| 6 |
+
|
| 7 |
+
#### 問題点(v1.6.8の課題)
|
| 8 |
+
1. **冗長な変換処理**: 1-indexed (Gemini) → 0-indexed (Frontend) の変換が不要
|
| 9 |
+
2. **temperature不統一**: 0.2〜0.7までバラバラだった
|
| 10 |
+
|
| 11 |
+
#### 実施作業
|
| 12 |
+
|
| 13 |
+
| ファイル | 変更内容 |
|
| 14 |
+
|---------|---------|
|
| 15 |
+
| `src/prompts/question_prompts.py` | correct_answer: 0-3 に変更 |
|
| 16 |
+
| `src/prompts/validation_prompts.py` | correct_answer: 0-3 に変更 |
|
| 17 |
+
| `src/models/gemini_schemas.py` | ge=0, le=3 に変更 |
|
| 18 |
+
| `app.py` | `convert_correct_answer_index` 関数削除 |
|
| 19 |
+
| `src/services/gemini_service.py` | 全9箇所 temperature=1.0 に統一 |
|
| 20 |
+
|
| 21 |
+
#### ステータス
|
| 22 |
+
- ✅ correct_answer 0-indexed 統一
|
| 23 |
+
- ✅ 変換関数削除
|
| 24 |
+
- ✅ temperature=1.0 統一
|
| 25 |
+
- ✅ git commit & push (`27a3ba5`)
|
| 26 |
+
- 🔲 E2Eテスト待ち
|
| 27 |
+
|
| 28 |
+
#### コミット情報
|
| 29 |
+
- コミットID: `27a3ba5`
|
| 30 |
+
- ロールバック: `git revert 27a3ba5`
|
| 31 |
+
|
| 32 |
+
---
|
| 33 |
+
|
| 34 |
## v1.6.8 正答位置バグ修正・シートリセット
|
| 35 |
|
| 36 |
+
### 2025-12-20 00:30 - v1.6.8 実装完了 ✅
|
| 37 |
|
| 38 |
#### 問題の根本原因
|
| 39 |
**SCORE 0/0 の原因**: `shuffle_choices()`関数のインデックス変換バグ
|
|
|
|
| 44 |
#### 実施作業
|
| 45 |
|
| 46 |
| ファイル | 変更内容 |
|
| 47 |
+
|---------|---------
|
| 48 |
| `src/prompts/question_prompts.py` | `correct_answer: 1-4` + 位置分散指示追加 |
|
| 49 |
| `src/prompts/validation_prompts.py` | 位置偏り検出・選択肢入れ替え指示追加 |
|
| 50 |
| `src/services/gemini_service.py` | 全9箇所の`max_output_tokens`を65536に統一 |
|
| 51 |
+
| `app.py` | `shuffle_choices` → `convert_correct_answer_index`に簡略化 |
|
| 52 |
| `gas/setup_sheets_v3.js` | シート削除・初期化関数を新規作成 |
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
#### ステータス
|
| 55 |
- ✅ コード修正完了
|
| 56 |
- ✅ clasp push完了
|
| 57 |
+
- ✅ GASエディタで`resetAndInitialize()`実行完了
|
| 58 |
+
- ✅ GAS再デプロイ完了(@38)
|
| 59 |
+
- ✅ HF Spaces GAS_API_URL更新完了
|
| 60 |
+
- ✅ git commit完了 (`e93e046`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
---
|
| 63 |
|
|
|
|
| 79 |
- AI先生アドバイスは正常に表示
|
| 80 |
- SCOREが0/0 → GAS側 or スコア計算ロジックに問題あり
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
---
|
| 83 |
|
| 84 |
## v1.6.7 Gemini Structured Output導入
|
|
|
|
| 100 |
- SubjectEvaluationSchema: 教科別評価用
|
| 101 |
- OverallEvaluationSchema: 全体評価用
|
| 102 |
- BatchEvaluationSchema: 一括評価用
|
|
|
|
| 103 |
|
| 104 |
2. `src/services/gemini_service.py` 更新
|
| 105 |
- generate_summary: SummarySchema適用
|
| 106 |
- generate_questions_batch: QuestionSchema配列適用
|
| 107 |
- generate_evaluation_batch: BatchEvaluationSchema適用
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
---
|
| 110 |
|
| 111 |
## v1.6.6 SCORE・AI評価バグ修正
|
|
|
|
| 121 |
**問題1: SCORE 0/10**
|
| 122 |
- Answersシートのカラムがずれていた
|
| 123 |
- `gas/Code.js` `handleSubmitAnswers` で `subject`, `category`, `correct_answer` が保存されていなかった
|
|
|
|
| 124 |
|
| 125 |
**問題2: AI先生アドバイス非表示**
|
| 126 |
- ログ: `ERROR:src.services.gemini_service:Evaluation JSON parse error`
|
| 127 |
- `src/prompts/evaluation_prompts.py` のJSON例に日本語テキストが含まれ、Geminiが不正なJSONを生成
|
| 128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
---
|
| 130 |
|
| 131 |
+
## 過去バージョン
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
+
### v1.6.5 選択肢シャッフル機能追加
|
| 134 |
+
- 2025-12-19 22:00 実装完了
|
| 135 |
|
| 136 |
+
### v1.6.4 フロントエンド表示バグ修正
|
| 137 |
+
- 2025-12-19 21:30 実装完了
|
|
|
|
|
|
|
| 138 |
|
| 139 |
+
### v1.6.3 バグ修正完了
|
| 140 |
+
- 2025-12-19 20:10 GASシート参照バグ修正
|
| 141 |
|
| 142 |
+
### v1.6.2 Phase 2完了
|
| 143 |
+
- 2025-12-19 15:10 全API復旧確認完了
|
| 144 |
|
| 145 |
+
### v1.6.1 復旧作業
|
| 146 |
+
- 2025-12-19 14:30 認証機能バグ修正完了
|
| 147 |
|
| 148 |
+
### v1.6.0 QuestionDB駆動導入
|
| 149 |
+
- 2025-12-17 QuestionDB駆動問題生成 実装完了
|
|
|
|
|
|
|
| 150 |
|
| 151 |
---
|
| 152 |
+
**最終更新**: 2025-12-20 01:00
|
src/prompts/__pycache__/question_prompts.cpython-310.pyc
CHANGED
|
Binary files a/src/prompts/__pycache__/question_prompts.cpython-310.pyc and b/src/prompts/__pycache__/question_prompts.cpython-310.pyc differ
|
|
|
src/prompts/__pycache__/validation_prompts.cpython-310.pyc
CHANGED
|
Binary files a/src/prompts/__pycache__/validation_prompts.cpython-310.pyc and b/src/prompts/__pycache__/validation_prompts.cpython-310.pyc differ
|
|
|
src/services/__pycache__/gemini_service.cpython-310.pyc
CHANGED
|
Binary files a/src/services/__pycache__/gemini_service.cpython-310.pyc and b/src/services/__pycache__/gemini_service.cpython-310.pyc differ
|
|
|
超天才クイズv3_GoogleSheets/Answers.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s4{border-right:none;background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s3{background-color:#ffffff;text-align:center;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{background-color:#ffffff;text-align:right;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="1601009777C0" style="width:100px;" class="column-headers-background">A</th><th id="1601009777C1" style="width:100px;" class="column-headers-background">B</th><th id="1601009777C2" style="width:100px;" class="column-headers-background">C</th><th id="1601009777C3" style="width:100px;" class="column-headers-background">D</th><th id="1601009777C4" style="width:100px;" class="column-headers-background">E</th><th id="1601009777C5" style="width:100px;" class="column-headers-background">F</th><th id="1601009777C6" style="width:100px;" class="column-headers-background">G</th><th id="1601009777C7" style="width:100px;" class="column-headers-background">H</th><th id="1601009777C8" style="width:100px;" class="column-headers-background">I</th><th id="1601009777C9" style="width:100px;" class="column-headers-background">J</th></tr></thead><tbody><tr style="height: 20px"><th id="1601009777R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">answer_id</td><td class="s0" dir="ltr">session_id</td><td class="s0" dir="ltr">question_id</td><td class="s0" dir="ltr">subject</td><td class="s0" dir="ltr">category</td><td class="s0" dir="ltr">user_answer</td><td class="s0 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">correct_answer</div></td><td class="s0" dir="ltr">is_correct</td><td class="s0" dir="ltr">time_spent</td><td class="s0" dir="ltr">submitted_at</td></tr><tr style="height: 20px"><th id="1601009777R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">62e614b2-45b6-483c-85d7-f2b651fa4824</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">2b17f034-2f9c-41bc-88b2-caca2c9851b1</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3" dir="ltr">TRUE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.088Z</div></td></tr><tr style="height: 20px"><th id="1601009777R2" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">3</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">39be28cf-da02-48ab-a8d5-29b648b9bd50</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">481685c5-3ffe-43e7-9240-3ca8aae39324</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">1</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.167Z</div></td></tr><tr style="height: 20px"><th id="1601009777R3" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">4</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">31167b8f-0ba2-4437-af74-22fc3f0d4fe4</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">af14c3b1-1c25-421f-b220-ae395a175211</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">2</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.306Z</div></td></tr><tr style="height: 20px"><th id="1601009777R4" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">5</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">19d26d7d-7bfb-429a-86ad-b6485d0f2648</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">98f94418-8160-47e6-8a47-dae2b7f8edb8</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">3</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.437Z</div></td></tr><tr style="height: 20px"><th id="1601009777R5" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">6</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">a9d32f11-f7be-4868-b9de-564ed36227fa</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">f74eaf74-6285-4631-b224-59637a010ca5</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP03</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3" dir="ltr">TRUE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.603Z</div></td></tr><tr style="height: 20px"><th id="1601009777R6" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">7</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">66d1b3c3-3c48-4121-9ff1-4707d32499bd</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">0421ead4-e5bf-419b-b43f-9bdc08d63bc8</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP04</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">2</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.732Z</div></td></tr><tr style="height: 20px"><th id="1601009777R7" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">8</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">c1952795-fb89-49f4-bd7a-46181b7b897f</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">7d601fc3-8def-4511-84ec-2f6ee50e2096</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP05</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">1</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:03.955Z</div></td></tr><tr style="height: 20px"><th id="1601009777R8" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">9</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">8befc0b5-7669-4345-a2d9-cff1379f718b</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">a10aa39e-a71e-43a4-8f8a-088a319d0099</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP06</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">3</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:04.078Z</div></td></tr><tr style="height: 20px"><th id="1601009777R9" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">10</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">c8ff8508-3ab8-4b7b-af05-31e773cd436f</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">1450cbc2-27b4-436a-b140-80e8f967dc43</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP02</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">1</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:04.201Z</div></td></tr><tr style="height: 20px"><th id="1601009777R10" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">11</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">1a3fc466-e6d2-4e89-bd99-27b11145b45f</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">bd0caa3a-8808-4044-a40b-6becab73f660</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP02</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">2</td><td class="s3" dir="ltr">FALSE</td><td class="s2" dir="ltr">0</td><td class="s4 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:04.321Z</div></td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/Evaluations.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{border-right:none;background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="617903561C0" style="width:100px;" class="column-headers-background">A</th><th id="617903561C1" style="width:100px;" class="column-headers-background">B</th><th id="617903561C2" style="width:100px;" class="column-headers-background">C</th><th id="617903561C3" style="width:100px;" class="column-headers-background">D</th><th id="617903561C4" style="width:100px;" class="column-headers-background">E</th><th id="617903561C5" style="width:100px;" class="column-headers-background">F</th><th id="617903561C6" style="width:100px;" class="column-headers-background">G</th><th id="617903561C7" style="width:100px;" class="column-headers-background">H</th></tr></thead><tbody><tr style="height: 20px"><th id="617903561R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">evaluation_id</td><td class="s0" dir="ltr">session_id</td><td class="s0" dir="ltr">subject</td><td class="s0" dir="ltr">advice</td><td class="s0" dir="ltr">strengths</td><td class="s0" dir="ltr">weaknesses</td><td class="s0 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">recommended_topics</div></td><td class="s0" dir="ltr">created_at</td></tr><tr style="height: 20px"><th id="617903561R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">40e734c1-c8bc-4784-877c-338fdf5775cc</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">今回の国語のテストでは、全問正解という素晴らしい結果でしたね!日頃の努力が実を結び、基礎から応用まで幅広い知識がしっかりと身についていることが分かります。この調子で、さらに深い学びを目指して、自信を持って次のステップに進んでいきましょう。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["漢字の読み書きと語彙力","熟語の構造理解","文章内容の正確な把握","文法・表現技法の知識","幅広い国語の知識をバランス良く習得"]</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["今回のテスト範囲においては、特に苦手な分野は見当たりませんでした。非常に高いレベルで理解できています。"]</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["より複雑な接続語や指示語を使った長文読解","心情や主題を深く読み取る記述問題の練習","多様なジャンル(随筆、詩、論説文など)の文章読解","故事成語やことわざの背景知識の学習","難易度の高い四字熟語や慣用句の習得"]</div></td><td class="s2 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:25.071Z</div></td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/GeneratedQuestions.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s3{border-right:none;background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{background-color:#ffffff;text-align:right;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="248679721C0" style="width:100px;" class="column-headers-background">A</th><th id="248679721C1" style="width:100px;" class="column-headers-background">B</th><th id="248679721C2" style="width:100px;" class="column-headers-background">C</th><th id="248679721C3" style="width:100px;" class="column-headers-background">D</th><th id="248679721C4" style="width:100px;" class="column-headers-background">E</th><th id="248679721C5" style="width:100px;" class="column-headers-background">F</th><th id="248679721C6" style="width:100px;" class="column-headers-background">G</th><th id="248679721C7" style="width:100px;" class="column-headers-background">H</th><th id="248679721C8" style="width:100px;" class="column-headers-background">I</th><th id="248679721C9" style="width:100px;" class="column-headers-background">J</th></tr></thead><tbody><tr style="height: 20px"><th id="248679721R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">question_id</td><td class="s0" dir="ltr">session_id</td><td class="s0" dir="ltr">subject</td><td class="s0" dir="ltr">genre_id</td><td class="s0" dir="ltr">answer</td><td class="s0" dir="ltr">question_text</td><td class="s0" dir="ltr">choices</td><td class="s0 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">correct_answer</div></td><td class="s0" dir="ltr">difficulty</td><td class="s0" dir="ltr">created_at</td></tr><tr style="height: 20px"><th id="248679721R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">2b17f034-2f9c-41bc-88b2-caca2c9851b1</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「つきっきりで妹の【看病】をする」の【看病】の正しい読み方を次の中から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["かんびょう","かんぴょう","かんみょう","かんぼう"]</div></td><td class="s2" dir="ltr">0</td><td class="s1" dir="ltr">easy</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R2" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">3</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">481685c5-3ffe-43e7-9240-3ca8aae39324</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「お気に入りの詩を【ろうどく】する」のカタカナ部分を漢字で正しく書きなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["浪読","朗読","廊読","郎読"]</div></td><td class="s2" dir="ltr">1</td><td class="s1" dir="ltr">easy</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R3" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">4</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">af14c3b1-1c25-421f-b220-ae395a175211</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「チームを優勝に【みちび】く」のひらがな部分を漢字で正しく書きなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["道く","誘く","導く","引く"]</div></td><td class="s2" dir="ltr">2</td><td class="s1" dir="ltr">easy</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R4" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">5</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">98f94418-8160-47e6-8a47-dae2b7f8edb8</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「誕生会に【招待】される」の【招待】の正しい読み方を次の中から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["そうたい","しょだい","しょおたい","しょうたい"]</div></td><td class="s2" dir="ltr">3</td><td class="s1" dir="ltr">easy</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R5" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">6</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">f74eaf74-6285-4631-b224-59637a010ca5</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP03</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「不足分を【おぎな】う」のように、「補う」の正しい送り仮名を含むものを次から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["補う","補なう","補うう","補おなう"]</div></td><td class="s2" dir="ltr">0</td><td class="s1" dir="ltr">medium</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R6" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">7</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">0421ead4-e5bf-419b-b43f-9bdc08d63bc8</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP04</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">以下の文章で、筆者は俳優がリアリティを追求することで最終的にどうなると述べていますか。最も適切なものを次から選びなさい。撮影現場では、「こういう時って、どれくらいの声で生徒を注意しますか?」「こんな言葉遣いをしますか?」などと俳優のみなさんからいろいろな質問をされます。撮影に立ち会って感じたのは、リアリティを追求する姿勢でした。その結果、俳優たちがだんだん本当の塾講師に見えてくるのです。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["演技が不自然になる","観客が共感できなくなる","本当の役柄に近づく","撮影現場の雰囲気が悪くなる"]</div></td><td class="s2" dir="ltr">2</td><td class="s1" dir="ltr">medium</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R7" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">8</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">7d601fc3-8def-4511-84ec-2f6ee50e2096</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP05</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「園長先生は【感慨】深げに言ったものだ」の【感慨】と同じような意味で使われる言葉を次の中から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["無関心","感動","興奮","冷淡"]</div></td><td class="s2" dir="ltr">1</td><td class="s1" dir="ltr">medium</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R8" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">9</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">a10aa39e-a71e-43a4-8f8a-088a319d0099</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP06</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「『鳩』が平和の【象徴】として用いられる」のように、抽象的な概念を具体的なもので表す技法の名称として適切なものを次から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["擬人化","反復法","対比","象徴"]</div></td><td class="s2" dir="ltr">3</td><td class="s1" dir="ltr">medium</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R9" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">10</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">1450cbc2-27b4-436a-b140-80e8f967dc43</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP02</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「無事」という熟語は、上の字が打ち消しの意味を表している漢字で構成されています。これと同じ組み立て方の熟語を次の中から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["着席","非表示","読書","開閉"]</div></td><td class="s2" dir="ltr">1</td><td class="s1" dir="ltr">hard</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr><tr style="height: 20px"><th id="248679721R10" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">11</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">bd0caa3a-8808-4044-a40b-6becab73f660</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP02</td><td></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">「指名」という熟語は、下の字が上の字の目的語になっている熟語です。これと同じ組み立て方の熟語を次の中から選びなさい。</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["上下","親切","登山","希望"]</div></td><td class="s2" dir="ltr">2</td><td class="s1" dir="ltr">hard</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:30.813Z</div></td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/QuestionDatabase.html
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
超天才クイズv3_GoogleSheets/Sessions.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s3{background-color:#ffffff;text-align:center;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{background-color:#ffffff;text-align:right;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="896978663C0" style="width:100px;" class="column-headers-background">A</th><th id="896978663C1" style="width:100px;" class="column-headers-background">B</th><th id="896978663C2" style="width:100px;" class="column-headers-background">C</th><th id="896978663C3" style="width:100px;" class="column-headers-background">D</th><th id="896978663C4" style="width:100px;" class="column-headers-background">E</th><th id="896978663C5" style="width:100px;" class="column-headers-background">F</th><th id="896978663C6" style="width:100px;" class="column-headers-background">G</th></tr></thead><tbody><tr style="height: 20px"><th id="896978663R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">session_id</td><td class="s0" dir="ltr">user_id</td><td class="s0" dir="ltr">subjects</td><td class="s0" dir="ltr">start_time</td><td class="s0" dir="ltr">end_time</td><td class="s0" dir="ltr">total_score</td><td class="s0" dir="ltr">completed</td></tr><tr style="height: 20px"><th id="896978663R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">2025-12-19T15:57:52.877Z</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">2025-12-19T15:59:04.637Z</div></td><td class="s1" dir="ltr">["jp"]</td><td class="s2" dir="ltr">20</td><td class="s3" dir="ltr">TRUE</td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/Statistics.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s3{border-right:none;background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{background-color:#ffffff;text-align:right;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="311998549C0" style="width:100px;" class="column-headers-background">A</th><th id="311998549C1" style="width:100px;" class="column-headers-background">B</th><th id="311998549C2" style="width:100px;" class="column-headers-background">C</th><th id="311998549C3" style="width:100px;" class="column-headers-background">D</th><th id="311998549C4" style="width:100px;" class="column-headers-background">E</th><th id="311998549C5" style="width:100px;" class="column-headers-background">F</th><th id="311998549C6" style="width:100px;" class="column-headers-background">G</th><th id="311998549C7" style="width:100px;" class="column-headers-background">H</th></tr></thead><tbody><tr style="height: 20px"><th id="311998549R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">stat_id</td><td class="s0" dir="ltr">user_id</td><td class="s0" dir="ltr">subject</td><td class="s0" dir="ltr">category</td><td class="s0 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">total_attempted</div></td><td class="s0" dir="ltr">correct_count</td><td class="s0" dir="ltr">accuracy_rate</td><td class="s0" dir="ltr">last_updated</td></tr><tr style="height: 20px"><th id="311998549R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">4c07e2a0-44b0-4f9e-9393-106ec59c607f</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP01</td><td class="s2" dir="ltr">4</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">0.25</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr><tr style="height: 20px"><th id="311998549R2" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">3</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">7e59fae2-83ca-48b1-88d2-f3c110f8a346</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP03</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">1</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr><tr style="height: 20px"><th id="311998549R3" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">4</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">9dffde73-0d03-45b6-8561-4ec871a8390a</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP04</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr><tr style="height: 20px"><th id="311998549R4" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">5</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">fe958c71-c6b3-4f53-beab-218d80fc8f1a</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP05</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr><tr style="height: 20px"><th id="311998549R5" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">6</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">655c5b12-2148-443b-a2a8-d634765262d4</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP06</td><td class="s2" dir="ltr">1</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr><tr style="height: 20px"><th id="311998549R6" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">7</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">e7314858-ff3e-4720-803e-b75b7d470c1f</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s1" dir="ltr">jp</td><td class="s1" dir="ltr">JP02</td><td class="s2" dir="ltr">2</td><td class="s2" dir="ltr">0</td><td class="s2" dir="ltr">0</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:59:05.828Z</div></td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/Summaries.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s1{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{border-right:none;background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="118338144C0" style="width:100px;" class="column-headers-background">A</th><th id="118338144C1" style="width:100px;" class="column-headers-background">B</th><th id="118338144C2" style="width:100px;" class="column-headers-background">C</th><th id="118338144C3" style="width:100px;" class="column-headers-background">D</th><th id="118338144C4" style="width:100px;" class="column-headers-background">E</th><th id="118338144C5" style="width:100px;" class="column-headers-background">F</th><th id="118338144C6" style="width:100px;" class="column-headers-background">G</th></tr></thead><tbody><tr style="height: 20px"><th id="118338144R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">summary_id</td><td class="s0" dir="ltr">session_id</td><td class="s0" dir="ltr">subject</td><td class="s0" dir="ltr">keywords</td><td class="s0" dir="ltr">topics</td><td class="s0" dir="ltr">summary</td><td class="s0" dir="ltr">created_at</td></tr><tr style="height: 20px"><th id="118338144R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">316d3395-d250-4490-8b45-bba72afa058d</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">74e4c2b9-ae75-4718-af1e-975025d189b2</div></td><td class="s1" dir="ltr">jp</td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["かんびょう","朗読","導く","しょうたい","補う","本当の役柄に近づく","感動","象徴","非表示","登山"]</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">["漢字の読み「看病」","漢字の書き取り「ろうどく」","漢字の書き取り「みちびく」","漢字の読み「招待」","送り仮名「補う」","文章読解(俳優のリアリティ追求)","語句の意味「感慨」","表現技法「象徴」","熟語の組み立て(無事・非表示)","熟語の組み立て(指名・登山)"]</div></td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">漢字の読み書き、送り仮名、語句の意味、表現技法、熟語、読解</div></td><td class="s2 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">2025-12-19T15:58:40.591Z</div></td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/Users.html
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><link type="text/css" rel="stylesheet" href="resources/sheet.css" >
|
| 2 |
+
<style type="text/css">.ritz .waffle a { color: inherit; }.ritz .waffle .s3{background-color:#ffffff;text-align:left;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s1{border-right:none;background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s2{border-left:none;background-color:#ffffff;}.ritz .waffle .s0{background-color:#ffffff;text-align:left;font-weight:bold;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}.ritz .waffle .s4{background-color:#ffffff;text-align:right;color:#000000;font-family:Arial;font-size:10pt;vertical-align:bottom;white-space:nowrap;direction:ltr;padding:2px 3px 2px 3px;}</style><div class="ritz grid-container" dir="ltr"><table class="waffle" cellspacing="0" cellpadding="0"><thead><tr><th class="row-header freezebar-origin-ltr"></th><th id="412839741C0" style="width:100px;" class="column-headers-background">A</th><th id="412839741C1" style="width:100px;" class="column-headers-background">B</th><th id="412839741C2" style="width:100px;" class="column-headers-background">C</th><th id="412839741C3" style="width:100px;" class="column-headers-background">D</th><th id="412839741C4" style="width:100px;" class="column-headers-background">E</th><th id="412839741C5" style="width:100px;" class="column-headers-background">F</th><th id="412839741C6" style="width:100px;" class="column-headers-background">G</th><th id="412839741C7" style="width:100px;" class="column-headers-background">H</th></tr></thead><tbody><tr style="height: 20px"><th id="412839741R0" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">1</div></th><td class="s0" dir="ltr">user_id</td><td class="s0" dir="ltr">username</td><td class="s0" dir="ltr">created_at</td><td class="s0" dir="ltr">total_sessions</td><td class="s1 softmerge" dir="ltr"><div class="softmerge-inner" style="width:198px;left:-1px">total_questions</div></td><td class="s2"></td><td class="s2"></td><td></td></tr><tr style="height: 20px"><th id="412839741R1" style="height: 20px;" class="row-headers-background"><div class="row-header-wrapper" style="line-height: 20px">2</div></th><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">3594f518-42ee-4e74-afec-f4878b000f5e</div></td><td class="s3" dir="ltr">tomohiro</td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">$2b$12$UI/K0AfbjjGB20UktU6ZVuBH4JeoA6AyvksfkxexSi3SUelNiElT2</div></td><td class="s3 softmerge" dir="ltr"><div class="softmerge-inner" style="width:97px;left:-1px">2025-12-19T15:52:57.853Z</div></td><td class="s4" dir="ltr">1</td><td class="s4" dir="ltr">10</td><td class="s4" dir="ltr">0</td><td class="s3" dir="ltr">{}</td></tr></tbody></table></div>
|
超天才クイズv3_GoogleSheets/resources/sheet.css
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|