{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "12c67844-4b4e-4c1f-b7f4-9c2c6f2189c7",
      "metadata": {
        "id": "12c67844-4b4e-4c1f-b7f4-9c2c6f2189c7"
      },
      "source": [
        "## LLM(Gemini)を利用したMoodle XML（小テスト）の作成\n",
        "\n",
        "Moodleの問題バンクにインポートできるMoodle XMLファイルが作成されます。\n",
        "\n",
        "以下のセルのコードを上から順番に実行します。なにかエラーが生じたら、対処し、そのセルを再実行してから、進んでください。\n",
        "\n",
        "注：AIが生成したテスト問題の内容が間違っていないか、最終確認は必ず行ってください。"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Google Colab のシークレットを読み込みます\n",
        "# これを実行する前に、左端の鍵アイコンをクリックし、「新しいシークレットを追加」で、\n",
        "# geminikey という名前でGemini APIキーの値を保存しておいてください。\n",
        "from google.colab import userdata\n",
        "geminikey = userdata.get('geminikey')"
      ],
      "metadata": {
        "id": "L8vi7vAqdOtx"
      },
      "id": "L8vi7vAqdOtx",
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f3833624-7e3f-4d8d-8131-065a9835c0a2",
      "metadata": {
        "id": "f3833624-7e3f-4d8d-8131-065a9835c0a2"
      },
      "outputs": [],
      "source": [
        "import google.generativeai as genai\n",
        "genai.configure(api_key=geminikey)\n",
        "\n",
        "gemini_model = 'gemini-1.5-flash-latest'\n",
        "#gemini_model = 'gemini-1.5-pro-latest'\n",
        "\n",
        "model = genai.GenerativeModel(\n",
        "    gemini_model,\n",
        "    generation_config=genai.types.GenerationConfig(\n",
        "        temperature=1.0\n",
        "    )\n",
        ")\n",
        "#https://ai.google.dev/pricing"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0adc9793-7217-4ec4-8c61-bde13068941b",
      "metadata": {
        "id": "0adc9793-7217-4ec4-8c61-bde13068941b"
      },
      "source": [
        "### 生成する教材における学習目標を指定する"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6ba7f222-3712-488e-b5e8-a19c5db1fde8",
      "metadata": {
        "id": "6ba7f222-3712-488e-b5e8-a19c5db1fde8",
        "tags": []
      },
      "outputs": [],
      "source": [
        "data1 = input(\"学習目標は何ですか？（最後にエンターキーを）\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d562daf0-3166-40ab-a564-e6e6b008ea98",
      "metadata": {
        "id": "d562daf0-3166-40ab-a564-e6e6b008ea98"
      },
      "source": [
        "### プレーンテキスト形式で小テスト質問を生成"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "40861cbc-f468-4c26-b55d-8c465a3146e7",
      "metadata": {
        "id": "40861cbc-f468-4c26-b55d-8c465a3146e7",
        "tags": []
      },
      "outputs": [],
      "source": [
        "prompt1 = f'''\n",
        "あなたはオンラインテストの開発者です。\n",
        "「{data1}」という学習目標に到達しているかどうかを測定できる４択問題を８問作成してください。\n",
        "正解の選択肢も示してください。\n",
        "各問題は、下の＜問題フォーマットの例＞のようなフォーマットで書いてください。\n",
        "\n",
        "＜問題フォーマットの例＞\n",
        "1. AI技術の基礎に対する理解とは別に、「教育・リテラシーの原則」で強調されるべきはどれですか。\n",
        "A) ステークホルダーとともに国際コンセンサスを遵守すること\n",
        "B) 格差と分断の防止を、関係者の利益も考慮しつつ行うこと\n",
        "C) 自動化だけでなく安全性も重視した行動を心がけること\n",
        "D) データの有効利用を最大限図ること\n",
        "正解: B) 格差と分断の防止を、関係者の利益も考慮しつつ行うこと\n",
        "解説: 教育・リテラシーの原則では、AIに関する知識と理解の平等な提供やリテラシー向上を通じて、格差と分断の予防が重要視される。\n",
        "'''\n",
        "messages = [\n",
        "    {'role':'user', 'parts': [prompt1]}\n",
        "]\n",
        "response = model.generate_content(messages)\n",
        "res1 = response.candidates[0].content.parts[0].text.strip()\n",
        "print(res1)\n",
        "\n",
        "#with open('quiz1.txt', 'w') as f:\n",
        "    #print(res1, file=f)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40e68b2b-cbee-4d4a-8e93-74ede7c37024",
      "metadata": {
        "id": "40e68b2b-cbee-4d4a-8e93-74ede7c37024"
      },
      "source": [
        "### 小テスト問題のテキストに基づき Moodle XML を生成"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "30294bf4-80fe-4f59-9660-ae7c6bddb68a",
      "metadata": {
        "id": "30294bf4-80fe-4f59-9660-ae7c6bddb68a"
      },
      "outputs": [],
      "source": [
        "prompt2 = '''\n",
        "今のすべての問題を一連のデータとして（問題ごとに分けずに） 以下のような Moodle XML 形式で出力してください。選択肢の句点は削除してください。\n",
        "\n",
        "  <question type=\"multichoice\">\n",
        "    <name>\n",
        "      <text>問いの要約</text>\n",
        "    </name>\n",
        "    <questiontext format=\"html\">\n",
        "      <text><![CDATA[問いの文章をここに書く。]]></text>\n",
        "    </questiontext>\n",
        "    <shuffleanswers>true</shuffleanswers>\n",
        "    <answer fraction=\"0\">\n",
        "      <text>不正解</text>\n",
        "    </answer>\n",
        "    <answer fraction=\"100\">\n",
        "      <text>正解</text>\n",
        "    </answer>\n",
        "    <answer fraction=\"0\">\n",
        "      <text>不正解</text>\n",
        "    </answer>\n",
        "    <answer fraction=\"0\">\n",
        "      <text>不正解</text>\n",
        "    </answer>\n",
        "    <generalfeedback>\n",
        "      <text><![CDATA[全般に対するフィードバック]]></text>\n",
        "    </generalfeedback>\n",
        "  </question>\n",
        "'''\n",
        "\n",
        "messages = [\n",
        "        {\"role\": \"user\",  \"parts\": [prompt1]},\n",
        "        {\"role\": \"model\", \"parts\": [res1]},\n",
        "        {\"role\": \"user\",  \"parts\": [prompt2]},\n",
        "]\n",
        "response = model.generate_content(messages)\n",
        "res2 = response.candidates[0].content.parts[0].text.strip()\n",
        "print(res2)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "prompt3 = '''\n",
        "以下のように直してください。\n",
        "・<quiz> から開始する\n",
        "・選択肢番号があれば削除\n",
        "・正解の選択肢の配点は 100 になっている\n",
        "・問題名（<name><text> と </text></name> の間）は、問いの文章を10文字程度で要約したもの\n",
        "・各問題に対して1つだけ、</questiontext> の後に、200文字程度の「全般的なフィードバック」を <generalfeedback><text> と </text></generalfeedback> で囲って書く\n",
        "・「全般的なフィードバック」には、参考となるWikipediaページなどのリンクが target=_BLANK の指定付きで含まれている\n",
        "・各問題に対して <shuffleanswers>true</shuffleanswers> を指定する\n",
        "・[CDATA[ に対応する ]] がちゃんと書かれている\n",
        "'''\n",
        "\n",
        "messages = [\n",
        "        {\"role\": \"user\",  \"parts\": [prompt2]},\n",
        "        {\"role\": \"model\", \"parts\": [res2]},\n",
        "        {\"role\": \"user\",  \"parts\": [prompt3]},\n",
        "]\n",
        "response = model.generate_content(messages)\n",
        "res3 = response.candidates[0].content.parts[0].text.strip()\n",
        "#print(res3)\n",
        "\n",
        "xml_file = 'moodle-quiz-questions01.xml'\n",
        "res3 = res3.replace(\"```xml\", '').replace(\"```\", '')\n",
        "with open(xml_file, 'w') as f:\n",
        "    print(res3, file=f)\n",
        "\n",
        "print(\"Moodleの問題バンクにインポートできるMoodle XMLファイルが生成されました。\")\n",
        "print(f\"左端のフォルダアイコンをクリックし、生成された {xml_file} というファイルを見つけてダウンロードしてください。\")\n",
        "print(\"そのXMLファイルを Moodleの問題バンクの画面でインポートすると小テスト問題が作成されます。\")"
      ],
      "metadata": {
        "id": "I3KWEJN6P7Zm"
      },
      "id": "I3KWEJN6P7Zm",
      "execution_count": null,
      "outputs": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.13"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}