{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fJXPuMBgsO_I"
      },
      "source": [
        "# RAG using Langchain"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "J189g9PHscOJ"
      },
      "source": [
        "## Packages loading & import"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LztGdoQClLDK"
      },
      "outputs": [],
      "source": [
        "!pip install \"langchain-core>=0.2.0,<0.3.0\" \\\n",
        "             \"langchain>=0.2.0,<0.3.0\" \\\n",
        "             \"langchain-community>=0.2.0,<0.3.0\" \\\n",
        "             \"langchain-huggingface>=0.0.3,<0.1.0\" \\\n",
        "             \"langchain-chroma>=0.1.0,<0.2.0\" \\\n",
        "             \"langchain-ollama>=0.1.0,<0.2.0\" \\\n",
        "             \"langchain-text-splitters>=0.2.0,<0.3.0\" \\\n",
        "             \"transformers>=4.39.0\" \\\n",
        "             \"accelerate>=0.28.0\" \\\n",
        "             \"sentence-transformers\" \\\n",
        "             rank-bm25 \\\n",
        "             huggingface_hub \\\n",
        "             tqdm \\\n",
        "             beautifulsoup4"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "R7fVDp_MSM6d"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import json\n",
        "import bs4\n",
        "import nltk\n",
        "import torch\n",
        "import pickle\n",
        "import numpy as np\n",
        "\n",
        "# from pyserini.index import IndexWriter\n",
        "# from pyserini.search import SimpleSearcher\n",
        "from numpy.linalg import norm\n",
        "from rank_bm25 import BM25Okapi\n",
        "from nltk.tokenize import word_tokenize\n",
        "\n",
        "from langchain_community.llms import Ollama\n",
        "from langchain.chains.combine_documents import create_stuff_documents_chain\n",
        "from langchain.chains import create_retrieval_chain\n",
        "from langchain.vectorstores import Chroma\n",
        "from sentence_transformers import SentenceTransformer\n",
        "from langchain_huggingface import HuggingFaceEmbeddings\n",
        "from langchain_community.embeddings import JinaEmbeddings\n",
        "from langchain.text_splitter import RecursiveCharacterTextSplitter, TokenTextSplitter\n",
        "from langchain.docstore.document import Document\n",
        "from langchain_core.prompts import ChatPromptTemplate\n",
        "from langchain_community.document_loaders import WebBaseLoader\n",
        "from transformers import AutoModel, AutoModelForCausalLM, AutoTokenizer\n",
        "\n",
        "from tqdm import tqdm"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KZaXzYlMakAa"
      },
      "outputs": [],
      "source": [
        "nltk.download('punkt')\n",
        "nltk.download('punkt_tab')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_rqtezQ8shF0"
      },
      "source": [
        "## Hugging face login\n",
        "- Please apply the model first: https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct\n",
        "- If you haven't been granted access to this model, you can use other LLM model that doesn't have to apply.\n",
        "- You must save the hf token otherwise you need to regenrate the token everytime.\n",
        "- When using Ollama, no login is required to access and utilize the llama model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Wr0_DNixrDT8"
      },
      "outputs": [],
      "source": [
        "from huggingface_hub import login\n",
        "\n",
        "hf_token = \"Put your Hugging Face Access Token Key Here\"\n",
        "login(token=hf_token, add_to_git_credential=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zfN6G4fzr8CG"
      },
      "outputs": [],
      "source": [
        "!huggingface-cli whoami"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DMtZo6OVsUP5"
      },
      "source": [
        "## TODO1: Set up the environment of Ollama"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PhZ_q0V4ciJc"
      },
      "source": [
        "### Introduction to Ollama\n",
        "- Ollama is a platform designed for running and managing large language models (LLMs) directly **on local devices**, providing a balance between performance, privacy, and control.\n",
        "- There are also other tools support users to manage LLM on local devices and accelerate it like *vllm*, *Llamafile*, *GPT4ALL*...etc."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xv8QM9xj3oUL"
      },
      "source": [
        "### Launch colabxterm"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "Y9agmoxFd7um"
      },
      "outputs": [],
      "source": [
        "# TODO1-1: You should install colab-xterm and launch it.\n",
        "# Write your commands here."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "wVQMKksD6y4K",
        "outputId": "b07a3ee0-b0d6-453a-b49c-142c56e7c4ee"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            ">>> Installing ollama to /usr/local\n",
            ">>> Downloading Linux amd64 bundle\n",
            "############################################################################################# 100.0%\n",
            ">>> Creating ollama user...\n",
            ">>> Adding ollama user to video group...\n",
            ">>> Adding current user to ollama group...\n",
            ">>> Creating ollama systemd service...\n",
            "\u001b[1m\u001b[31mWARNING:\u001b[m systemd is not running\n",
            "\u001b[1m\u001b[31mWARNING:\u001b[m Unable to detect NVIDIA/AMD GPU. Install lspci or lshw to automatically detect and install GPU dependencies.\n",
            ">>> The Ollama API is now available at 127.0.0.1:11434.\n",
            ">>> Install complete. Run \"ollama\" from the command line.\n"
          ]
        }
      ],
      "source": [
        "# TODO1-2: You should install Ollama.\n",
        "# You may need root privileges if you use a local machine instead of Colab."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "10NK09FKd_th"
      },
      "outputs": [],
      "source": [
        "%xterm"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jbj5MMnh8Htl"
      },
      "outputs": [],
      "source": [
        "# TODO1-3: Pull Llama3.2:1b via Ollama and start the Ollama service in the xterm\n",
        "# Write your commands in the xterm"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "22kvHBerCCqm"
      },
      "source": [
        "## Ollama testing\n",
        "You can test your Ollama status with the following cells."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "v_hBBGBOnH4P"
      },
      "outputs": [],
      "source": [
        "# Setting up the model that this tutorial will use\n",
        "MODEL = \"llama3.2:1b\" # https://ollama.com/library/llama3.2:3b\n",
        "EMBED_MODEL = \"jinaai/jina-embeddings-v2-base-en\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T2sq6FoDWjVl"
      },
      "outputs": [],
      "source": [
        "# Initialize an instance of the Ollama model\n",
        "llm = Ollama(model=MODEL)\n",
        "# Invoke the model to generate responses\n",
        "response = llm.invoke(\"What is the capital of Taiwan?\")\n",
        "print(response)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "X5ndgmF6wYHY"
      },
      "source": [
        "## Build a simple RAG system by using LangChain"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Lzul2yQR5q4I"
      },
      "source": [
        "### TODO2: Load the cat-facts dataset and prepare the retrieval database"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RJLNgILQ55UH"
      },
      "outputs": [],
      "source": [
        "!wget https://huggingface.co/ngxson/demo_simple_rag_py/resolve/main/cat-facts.txt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "aMWMylYS-XRM"
      },
      "outputs": [],
      "source": [
        "# TODO2-1: Load the cat-facts dataset (as `refs`, which is a list of strings for all the cat facts)\n",
        "# Write your code here"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V66CXJr1BAu0"
      },
      "outputs": [],
      "source": [
        "from langchain_core.documents import Document\n",
        "docs = [Document(page_content=doc, metadata={\"id\": i}) for i, doc in enumerate(refs)]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NmPvFlGxe-mr"
      },
      "outputs": [],
      "source": [
        "# Create an embedding model\n",
        "model_kwargs = {'trust_remote_code': True}\n",
        "encode_kwargs = {'normalize_embeddings': False}\n",
        "embeddings_model = HuggingFaceEmbeddings(\n",
        "    model_name=EMBED_MODEL,\n",
        "    model_kwargs=model_kwargs,\n",
        "    encode_kwargs=encode_kwargs\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A3Rn4z4siC6e"
      },
      "outputs": [],
      "source": [
        "# TODO2-2: Prepare the retrieval database\n",
        "# You should create a Chroma vector store.\n",
        "# search_type can be “similarity” (default), “mmr”, or “similarity_score_threshold”\n",
        "vector_store = Chroma.from_documents(\n",
        "    # Write your code here\n",
        ")\n",
        "retriever = vector_store.as_retriever(\n",
        "    # Write your code here\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZmtvJMdH61Y4"
      },
      "source": [
        "### Prompt setting"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-oar4tEQONkl"
      },
      "outputs": [],
      "source": [
        "# TODO3: Set up the `system_prompt` and configure the prompt.\n",
        "system_prompt = # Write your code here\n",
        "prompt = ChatPromptTemplate.from_messages(\n",
        "    [\n",
        "        (\"system\", system_prompt),\n",
        "        (\"human\", \"{input}\"),\n",
        "    ]\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rG9tEFr8wvLX"
      },
      "source": [
        "- For the vectorspace, the common algorithm would be used like Faiss, Chroma...(https://python.langchain.com/docs/integrations/vectorstores/) to deal with the extreme huge database."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yVbi3irCUQn9"
      },
      "outputs": [],
      "source": [
        "# TODO4: Build and run the RAG system\n",
        "# TODO4-1: Load the QA chain\n",
        "# You should create a chain for passing a list of Documents to a model.\n",
        "question_answer_chain = # Write your code here\n",
        "\n",
        "# TODO4-2: Create retrieval chain\n",
        "# You should create retrieval chain that retrieves documents and then passes them on.\n",
        "chain = # Write your code here\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OLn0u3E-UwTK"
      },
      "outputs": [],
      "source": [
        "# Question (queries) and answer pairs\n",
        "# Write your code here\n",
        "# Please load the questions_answers.txt file and prepare the `queries` and `answers` lists.\n",
        "queries = [\n",
        "# Questions queries\n",
        "]\n",
        "answers = [\n",
        "# Corresponding answers\n",
        "]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6fLKCHWkizlr"
      },
      "outputs": [],
      "source": [
        "for i, query in tqdm(enumerate(queries), total=len(queries)):\n",
        "    # TODO4-3: Run the RAG system\n",
        "    response = # Write your code here\n",
        "    # The following lines perform evaluations.\n",
        "    # if the answer shows up in your response, the response is considered correct.\n",
        "    # Compute recall@1, recall@5 and Accuracy.\n",
        "    # Store the questions, ground-truths and answers in a json file.\n",
        "\n",
        "# TODO5: Improve to let the LLM correctly answer the ten questions."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "gpuType": "T4",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
