{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "## Getting to Main directory\n", "import os\n", "os.chdir(\"../\")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# !pip install -r requirements.txt" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from typing import Dict, TypedDict\n", "from langgraph.graph import StateGraph, END, START #Importing StateGraph, END, and START from langgraph.graph to define and manage state transitions within a conversational or generative AI workflow.\n", "from langchain_core.prompts import ChatPromptTemplate\n", "from langchain_google_genai import ChatGoogleGenerativeAI\n", "\n", "from IPython.display import display, Image, Markdown\n", "from langchain_core.runnables.graph import MermaidDrawMethod # to visualize the graph of langgraph node and edges\n", "from dotenv import load_dotenv\n", "import os\n", "\n", "# Load environment variables from a .env file to access sensitive information\n", "load_dotenv()\n", "\n", "# Set the Gemini API key for authentication with Google Generative AI services\n", "GOOGLE_API_KEY = os.environ[\"GOOGLE_API_KEY\"] = os.getenv('GOOGLE_API_KEY')\n", "# HF_TOKEN = os.environ[\"HF_TOKEN\"] = os.getenv('HF_TOKEN')\n", "# GEN_MODEL_ID = \"deepseek-ai/deepseek-vl-1.3b-chat\"\n", "\n", "# Instantiate a chat model using Google's Gemini-1.5-flash with specified configurations\n", "# - verbose=True enables detailed output logs for debugging\n", "# - temperature=0.5 controls the creativity level in responses (lower values make responses more deterministic)\n", "llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-flash\",\n", " verbose=True,\n", " temperature=0.5,\n", " google_api_key=os.getenv(\"GOOGLE_API_KEY\"))\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from langchain.chains.question_answering import load_qa_chain\n", "from langchain.prompts import PromptTemplate" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "from langchain.vectorstores import FAISS\n", "from langchain_google_genai import GoogleGenerativeAIEmbeddings\n", "import google.generativeai as genai\n", "\n", "genai.configure(api_key=GOOGLE_API_KEY)\n", "embeddings = GoogleGenerativeAIEmbeddings(model=\"models/embedding-001\")" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from sklearn.metrics.pairwise import cosine_similarity\n", "\n", "class DocumentRetriever:\n", " def __init__(self, index_path, embeddings, top_k=7, k=25):\n", " \"\"\"\n", " Initializes the retriever by loading the FAISS index and setting up embeddings.\n", "\n", " :param index_path: Path to the local FAISS index.\n", " :param embeddings: An embeddings object with an embed_documents method.\n", " :param k: Number of nearest neighbors to retrieve (for the FAISS retriever).\n", " \"\"\"\n", " self.index_path = index_path\n", " self.embeddings = embeddings\n", " self.k = k\n", " self.top_k = top_k\n", " # Load the FAISS index as a retriever\n", " self.faiss_retriever = self._load_faiss_index()\n", "\n", " def _load_faiss_index(self):\n", " \"\"\"\n", " Loads the FAISS index using the given embeddings.\n", " \"\"\"\n", " retriever = (\n", " FAISS.load_local(\n", " self.index_path,\n", " self.embeddings,\n", " allow_dangerous_deserialization=True\n", " )\n", " .as_retriever(search_kwargs={\"k\": self.k})\n", " )\n", " return retriever\n", "\n", " def embed_documents(self, doc_strings):\n", " \"\"\"\n", " Embeds a list of document strings and returns a numpy array of vectors.\n", " \"\"\"\n", " vectors = self.embeddings.embed_documents(doc_strings)\n", " return np.array(vectors)\n", "\n", " def embed_query(self, query):\n", " \"\"\"\n", " Embeds the user query and returns a 2D numpy array.\n", " \"\"\"\n", " # Ensure query is embedded as a list, then get the first (and only) vector.\n", " query_vector = self.embeddings.embed_documents([query])[0]\n", " return np.array(query_vector).reshape(1, -1)\n", "\n", " def compute_similarity(self, query_vector, doc_vectors):\n", " \"\"\"\n", " Computes cosine similarity between the query vector and document vectors.\n", " \"\"\"\n", " # Returns a 1D array of similarity scores.\n", " return cosine_similarity(query_vector, doc_vectors)[0]\n", "\n", " def rerank_documents(self, user_query):\n", " \"\"\"\n", " Reranks documents based on cosine similarity to the user query.\n", "\n", " :param doc_strings: List of document strings.\n", " :param user_query: The query string to compare against.\n", " :return: Tuple of (reranked_docs, similarity_scores, reranked_indices)\n", " \"\"\"\n", " docs = self.faiss_retriever.invoke(user_query)\n", " # print(user_query)\n", " # print(doc_strings)\n", " # Get embeddings for documents and query\n", " doc_strings = [doc.page_content for doc in docs if len(doc.page_content)>200]\n", " # print(\"Checkpoint 1: Starting reranking process.\")\n", " doc_vectors = self.embed_documents(doc_strings)\n", " # print(\"Checkpoint 2: Documents embedded.\")\n", " query_vector = self.embed_query(user_query)\n", " # print(\"Checkpoint 3: Query embedded.\")\n", "\n", " # Compute similarity scores between query and all documents\n", " similarity_scores = self.compute_similarity(query_vector, doc_vectors)\n", " # print(\"Checkpoint 4: Similarity scores computed.\")\n", " \n", " # Rerank document indices by descending similarity\n", " reranked_indices = np.argsort(similarity_scores)[::-1]\n", " # print(\"Checkpoint 5: Indices reranked.\")\n", " reranked_docs = [doc_strings[i] for i in reranked_indices]\n", " # reranked_info = [doc_strings[i] for i in reranked_indices]\n", " reranked_docs = reranked_docs[:self.top_k]\n", " # print(\"Checkpoint 6: Top k documents selected.\")\n", " # return reranked_docs, similarity_scores, reranked_indices\n", " return reranked_docs\n", "\n", " def pretty_print_docs(self, docs):\n", " \"\"\"\n", " Pretty print the retrieved documents.\n", " \n", " :param docs: List of documents to print.\n", " \"\"\"\n", " for i, doc in enumerate(docs, start=1):\n", " print(f\"Document {i}:\")\n", " print(doc)\n", " print(\"-\" * 40)\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Document 1:\n", "must identify what further evidence shall be brought on record at trial that could not be brought on record at the stage of summary judgment; and (f) the reply must state why, in light of the evidence or material on record if any, the Court should not proceed to summary judgment.\n", "----------------------------------------\n", "Document 2:\n", "comply with any order passed in a case management hearing, the court may, levy costs for such non-compliance; foreclose the non-complainant party’s right to file a \u0000 d a v i t s , c o n d u c t c r o s s examinations of witnesses, file written submissions, address oral arguments or make further arguments in trial; or, dismiss the plaint or allow the suit where such non-compliance is wilful, repeated and imposition of costs is not adequate to ensure compliance.vi. Parties are required to submit written arguments, 4 weeks prior to commencing oral arguments, followed by revised written arguments, if any, within 1 week of completion of oral arguments. Arguments are required to be closed no later than 6 months from the date of the first case management meeting. Judgment is required to be pronounced within 90 days of conclusion of arguments.186 Summary Suits in Civil Proceedings under Order 37 of the CPC\n", "----------------------------------------\n", "Document 3:\n", "commercial causes to be tried as an ordinary suit. Leave to defend may be unconditional, or conditional upon deposit by the defendant of the whole, or part of the claim amount. If no defence is made out, the court may pass summary judgment on the suit.19Summary Judgments under the Commercial Courts ActA party may apply for a summary judgment, at any time after the writ of summons is served on the defendant but prior to framing of issues.may make its decision without recording oral evidence.The court may pass such orders as deemed fit including:The court may give a summary judgment against a plainti\u0000 or defendant, if the court considers that, (a) the plainti\u0000 has no real prospect of succeeding in its claim or the defendant has no real prospect of successfully defending the claim; and (b) there is no other compelling reason why the claim should not be disposed of before recording of oral evidence.I.judgment on the claim;ii. conditional order;\n", "----------------------------------------\n", "Document 4:\n", "A plainti\u0000 may file a summary suit for monetary claims upon negotiable instruments (such as bills of exchange, hundis and promissory notes), or for recovery of debt or liquidated demand arising on a written contract, or on a guarantee. No relief other than amonetary decree may be claimed in such a suit. Where any other relief is sought, the plainti\u0000 must file a regular civil suit under ordinary civil procedure.Where a suit is instituted as a summary suit, the defendant is not entitled to6 Order 37, Rules 1-3 are set out in the End Note.26 2023 © Cyril Amarchand MangaldasGuide to Litigation in Indiadefend as a matter of right, but must apply to the court for leave to defend and while so applying, be able to establish a prima facie defence in his favour. If he / she establishes a defence to the satisfaction of the court, the defendant is granted leave to defend and the summary suit is transferred to the list of\n", "----------------------------------------\n", "Document 5:\n", "In light of the spread of the Covid-19 pandemic, the Supreme Court in exercise of its powers under Article 142 of the Constitution suspended the period of limitation for all claims for nearly 24 months, thereby permitting such claims to be brought even after the strict period of limitation had lapsed, subject to certain rules for the calculation of such limitation.Guide to Litigation in India10Civil Proceedings against the State\n", "----------------------------------------\n", "Document 6:\n", "Additionally, Order 1 Rule 8 of the CPC enables a group of plainti\u0000s to collectively file a civil suit, with the permission of the court, in a representative capacity for the benefit of a group or class of persons having a common interest in the subject matter of the suit. This provision is an exception to the general rule that all persons interested in a suit should be made parties thereto.A decree passed by the court is binding on all interested persons forming part of the group or class.7 Section 245(3) of the Companies Act read with Rule 2 of the National Company Law Tribunal (Second Amendment) Rules, 2019\n", "----------------------------------------\n", "Document 7:\n", "Meaning(iv) impose such other conditions, including providing security for restitution of losses that any party is likely to suffer during the pendency of the suit, as the Court may deem fit in its discretion; and (b) specify the consequences of the failure to comply with the conditional order, including passing a judgment against the party that have not complied with the conditional order.8. Power to impose costs.—The Court may make an order for payment of costs in an application for summary judgment in accordance with the provisions of sections 35 and 35A of the Code.Note: Order 13-A provides however, that an application for summary judgment under shall not be made in a suit in respect of any Commercial Dispute that is originally filed as a summary suit under Order 37.A Summons issued in prescribed form by the court calling upon the defendant to enter appearance and file its written statement of defence within the stipulated time.\n", "----------------------------------------\n" ] } ], "source": [ "\n", "# Initialize the retriever with the FAISS index location\n", "doc_retriever = DocumentRetriever(\"faiss_index\", embeddings)\n", "\n", "user_query = \"Tell me about: Summary Suits in Civil Proceedings under Order 37 of the CPC \"\n", "\n", "# Rerank documents based on cosine similarity\n", "re_ranked_docs = doc_retriever.rerank_documents(user_query)\n", "\n", "doc_retriever.pretty_print_docs(re_ranked_docs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'DocumentRetriever' object has no attribute 'retrieve'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_16636\\2991123615.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 64\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 65\u001b[0m \u001b[1;31m# Retrieve documents and print them\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 66\u001b[1;33m \u001b[0mdocuments\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfaiss_retriever\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mretrieve\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_query\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 67\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 68\u001b[0m \u001b[1;31m# Create the summarization pipeline with the retriever.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mAttributeError\u001b[0m: 'DocumentRetriever' object has no attribute 'retrieve'" ] } ], "source": [ "import os\n", "# Ensure you import ChatGoogleGenerativeAI from its appropriate library.\n", "# For example:\n", "# from your_llm_library import ChatGoogleGenerativeAI\n", "\n", "class DocSummarizerPipeline:\n", " def __init__(self, model=\"gemini-1.5-flash\", temperature=0.5, verbose=True, google_api_key=None):\n", " \"\"\"\n", " Initialize the document summarization pipeline.\n", "\n", " :param model: The LLM model identifier for summarization.\n", " :param temperature: The generation temperature.\n", " :param verbose: Enable verbose logging for the LLM.\n", " :param google_api_key: Google API key; if None, it's read from the environment.\n", " \"\"\"\n", " if google_api_key is None:\n", " google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n", " \n", " self.llm = ChatGoogleGenerativeAI(\n", " model=model,\n", " verbose=verbose,\n", " temperature=temperature,\n", " google_api_key=google_api_key\n", " )\n", " \n", " def summarize_docs(self, docs, query):\n", " \"\"\"\n", " Summarize the retrieved documents based on the query and generate insightful bullet points.\n", "\n", " :param docs: List of document objects (each expected to have a 'page_content' attribute or string representation).\n", " :param query: The query string to focus the summary.\n", " :return: The generated summary with bullet points.\n", " \"\"\"\n", " # Combine the content of all documents.\n", " combined_text = \"\\n\\n\".join(getattr(doc, \"page_content\", str(doc)) for doc in docs)\n", " prompt = (\n", " \"You are an assistant that summarizes text. Given the following content:\\n\\n\"\n", " f\"{combined_text}\\n\\n\"\n", " f\"Summarize the content based on the query: \\\"{query}\\\".\\n\\n\"\n", " \"Instructions:\\n\"\n", " \"1. Provide a brief overall summary of the content.\\n\"\n", " \"2. Extract the key content required to answer the query and list it in clear bullet points.\\n\"\n", " \"3. Finally, provide only the final coherent answer that integrates these bullet points, without showing any intermediate steps.\"\n", " \"Finally, just answer the final coheren explaination without the 1st and 2nd step responses\"\n", " )\n", " print(prompt)\n", " response = self.llm.invoke(prompt)\n", " return response.content\n", " \n", " \n", "if __name__ == \"__main__\":\n", " # Assume 'embeddings' is defined and imported from your embedding model.\n", " # Example:\n", " # from your_embeddings_module import MyEmbeddings\n", " # embeddings = MyEmbeddings(...)\n", "\n", " # Initialize your DocumentRetriever (provided in your existing code).\n", " faiss_retriever = DocumentRetriever(\"faiss_index\", embeddings, k=8)\n", " \n", " \n", " # Define the user query.\n", " user_query = \"What is the job of Labour Courts and Industrial Tribunals \"\n", "\n", " \n", " # Retrieve documents and print them\n", " documents = faiss_retriever.retrieve(user_query)\n", " \n", " # Create the summarization pipeline with the retriever.\n", " doc_summarize = DocSummarizerPipeline()\n", " \n", " # Process the query: retrieve documents and generate the summary.\n", " result = doc_summarize.summarize_docs(documents,user_query)\n", " \n", " print(\"Summary and Insights:\")\n", " print(result)\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'result' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_16636\\2443047140.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'result' is not defined" ] } ], "source": [ "print(result)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3mHere's a summary of the steps involved in filing a lawsuit in India:\n", "\n", "1. **Consult a lawyer:** This is the crucial first step. A lawyer will advise you on the merits of your case, the appropriate court to file in, and the necessary legal procedures.\n", "\n", "2. **Determine jurisdiction:** The court's jurisdiction depends on the subject matter of the dispute, the amount of the claim, and the location of the defendant.\n", "\n", "3. **Drafting the plaint:** The plaint is the initial document that sets out the plaintiff's claims and the relief sought. It must contain all the essential facts of the case, including the cause of action, the relevant dates, and the details of the parties involved. It also needs to specify the relevant laws and attach supporting documents.\n", "\n", "4. **Filing the plaint:** The plaint, along with the required court fees and supporting documents, must be filed in the appropriate court.\n", "\n", "5. **Court fees:** The court fees are calculated based on the value of the claim. Failure to pay the correct fees can result in delays or rejection of the plaint.\n", "\n", "6. **Serving the summons:** After the plaint is filed, the court issues a summons to the defendant, informing them of the lawsuit and requiring them to appear in court.\n", "\n", "7. **Written statement:** The defendant files a written statement in response to the plaint, admitting or denying the allegations.\n", "\n", "8. **Framing of issues:** The court identifies the key disputed points that need to be decided during the trial.\n", "\n", "9. **Evidence and arguments:** Both parties present evidence, including witness testimonies and documents, to support their claims. They then present their legal arguments based on the evidence and applicable laws.\n", "\n", "10. **Judgment:** After considering the evidence and arguments, the court delivers its judgment.\n", "\n", "11. **Execution:** If the judgment is in favor of the plaintiff, they can apply for execution to enforce the court's order. This can involve attaching the defendant's assets or other measures.\n", "\n", "\n", "It's important to remember that this is a simplified overview. The actual process can be complex and may vary depending on the specifics of the case and the relevant laws. Always consult with a lawyer for advice tailored to your specific situation. They can guide you through each step, ensuring that your rights are protected and that you follow the correct legal procedures.\n", "\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", "Web Based Response \n", "Here's a summary of the steps involved in filing a lawsuit in India:\n", "\n", "1. **Consult a lawyer:** This is the crucial first step. A lawyer will advise you on the merits of your case, the appropriate court to file in, and the necessary legal procedures.\n", "\n", "2. **Determine jurisdiction:** The court's jurisdiction depends on the subject matter of the dispute, the amount of the claim, and the location of the defendant.\n", "\n", "3. **Drafting the plaint:** The plaint is the initial document that sets out the plaintiff's claims and the relief sought. It must contain all the essential facts of the case, including the cause of action, the relevant dates, and the details of the parties involved. It also needs to specify the relevant laws and attach supporting documents.\n", "\n", "4. **Filing the plaint:** The plaint, along with the required court fees and supporting documents, must be filed in the appropriate court.\n", "\n", "5. **Court fees:** The court fees are calculated based on the value of the claim. Failure to pay the correct fees can result in delays or rejection of the plaint.\n", "\n", "6. **Serving the summons:** After the plaint is filed, the court issues a summons to the defendant, informing them of the lawsuit and requiring them to appear in court.\n", "\n", "7. **Written statement:** The defendant files a written statement in response to the plaint, admitting or denying the allegations.\n", "\n", "8. **Framing of issues:** The court identifies the key disputed points that need to be decided during the trial.\n", "\n", "9. **Evidence and arguments:** Both parties present evidence, including witness testimonies and documents, to support their claims. They then present their legal arguments based on the evidence and applicable laws.\n", "\n", "10. **Judgment:** After considering the evidence and arguments, the court delivers its judgment.\n", "\n", "11. **Execution:** If the judgment is in favor of the plaintiff, they can apply for execution to enforce the court's order. This can involve attaching the defendant's assets or other measures.\n", "\n", "\n", "It's important to remember that this is a simplified overview. The actual process can be complex and may vary depending on the specifics of the case and the relevant laws. Always consult with a lawyer for advice tailored to your specific situation. They can guide you through each step, ensuring that your rights are protected and that you follow the correct legal procedures.\n" ] } ], "source": [ "from langgraph.graph import StateGraph, END, START\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_google_genai import ChatGoogleGenerativeAI\n", "from IPython.display import display, Image, Markdown\n", "from langchain_core.runnables.graph import MermaidDrawMethod\n", "from langchain_community.tools import DuckDuckGoSearchResults\n", "from langchain.agents import create_tool_calling_agent\n", "from langchain.agents import AgentExecutor\n", "\n", "\n", "\n", "class WebSearchAgent:\n", " \n", " def __init__(self):\n", " # Initialize the chat model, prompt template, and search tools using LangGraph.\n", " self.model = ChatGoogleGenerativeAI(model=\"gemini-1.5-pro\")\n", " self.tools = [DuckDuckGoSearchResults()]\n", " self.prompt = ChatPromptTemplate.from_messages(\n", " [\n", " (\"system\", \"Provide a detailed answer based on web search for:\"),\n", " (\"human\", \"{input}\"),\n", " MessagesPlaceholder(\"agent_scratchpad\"), # This placeholder is required!\n", " ])\n", " \n", " def web_based_response(self, user_input):\n", " \"\"\"\n", " Sets up an agent with tool access, executes a tutorial-style response based on the user query,\n", " and saves the response to a markdown file.\n", " \"\"\"\n", " # Create an agent that can call tools (i.e. DuckDuckGo search) during processing.\n", " agent = create_tool_calling_agent(self.model, self.tools, self.prompt)\n", " agent_executor = AgentExecutor(agent=agent, tools=self.tools, verbose=True)\n", " response = agent_executor.invoke({\"input\": user_input})\n", " \n", " # Save and display the response as a markdown file.\n", " output = str(response.get('output')).replace(\"```markdown\", \"\").strip()\n", "\n", " return output\n", "\n", "# Example usage:\n", "if __name__ == \"__main__\":\n", " agent = WebSearchAgent()\n", " user_query = \"What are the steps involved in filing a lawsuit in India?\"\n", " output = agent.web_based_response(user_query)\n", " print(f\"Web Based Response \\n{output}\")\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "class IntermediateStateResponseEvaluator:\n", " def __init__(self, llm=llm, response_length_threshold: int = 50):\n", " \"\"\"\n", " Initialize the response evaluator with an LLM.\n", " \n", " Args:\n", " llm: An instance of an LLM that supports asynchronous invocation (e.g., ChatOpenAI).\n", " response_length_threshold: Minimum number of characters required in the response.\n", " \"\"\"\n", " self.llm = llm\n", " self.response_length_threshold = response_length_threshold\n", "\n", " def is_response_sufficient(self, query: str, response: str) -> str:\n", " \"\"\"\n", " Use the LLM to judge whether a previously generated response is sufficiently\n", " complete and correct for the given query.\n", " \n", " Args:\n", " query: The original user query.\n", " response: The LLM-generated response that needs evaluation.\n", " \n", " Returns:\n", " \"yes\" if the LLM judges the response as sufficient, \"no\" otherwise.\n", " \"\"\"\n", " # Quick check on response length\n", " if not response or len(response.strip()) < self.response_length_threshold:\n", " return \"no\"\n", "\n", " # Construct the evaluation prompt\n", " prompt = (\n", " \"You are an expert evaluator. Given the following question and the generated answer, \"\n", " \"determine if the answer sufficiently and correctly addresses the question in simple way. \"\n", " \"Answer with only 'yes' or 'no'.\\n\\n\"\n", " f\"Question: {query}\\n\\n\"\n", " f\"Generated Answer: {response}\\n\\n\"\n", " \"Is the answer sufficiently complete and correct?\"\n", " )\n", "\n", " # Invoke the LLM asynchronously\n", " evaluation = self.llm.invoke([{\"role\": \"user\", \"content\": prompt}])\n", " # print(evaluation)\n", " judgment = evaluation.content.strip().lower()\n", " \n", " # Expect the LLM to return either a clear \"yes\" or \"no\"\n", " return \"yes\" if \"yes\" in judgment else \"no\"\n", "\n", "\n", "# Example usage:\n", "# (Make sure you run this inside an async context)\n", "# For example, using ChatOpenAI as your LLM:\n", "#\n", "# from langchain.chat_models import ChatOpenAI\n", "# llm = ChatOpenAI(model=\"gpt-4\", temperature=0)\n", "#\n", "# evaluator = IntermediateStateResponseEvaluator()\n", "# query = \"What are the best practices for saving money?\"\n", "# generated_response = \"A good approach is to automate your savings and budget your expenses.\"\n", "# #\n", "# # In an async context, you would do:\n", "# # import asyncio\n", "# result = evaluator.is_response_sufficient(query, generated_response)\n", "# print(\"Is the response sufficient?\", result)\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "class State(TypedDict):\n", " query: str\n", " docs: str\n", " response: str\n", " is_response_sufficient: str" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "from langgraph.graph import StateGraph, END, START\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_google_genai import ChatGoogleGenerativeAI\n", "from IPython.display import display, Image, Markdown\n", "from langchain_core.runnables.graph import MermaidDrawMethod\n", "from langchain_community.tools import DuckDuckGoSearchResults\n", "from langchain.agents import create_tool_calling_agent\n", "from langchain.agents import AgentExecutor\n", "\n", "\n", "def faiss_content_retriever(state: State)-> State:\n", " print(\"\\nEntering faiss_content_retriever\")\n", " # Initialize the retriever with the FAISS index location\n", " doc_retriever = DocumentRetriever(\"faiss_index\", embeddings)\n", "\n", " # Rerank documents based on cosine similarity\n", " re_ranked_docs = doc_retriever.rerank_documents(state[\"query\"])\n", "\n", " # print(f\"\\nRetrieved documents: {re_ranked_docs}\")\n", " \n", " return {\"docs\": re_ranked_docs}\n", " \n", "def grounded_response(state: State)-> State:\n", " print(\"\\nEntering grounded_response\")\n", " # Create the summarization pipeline with the retriever.\n", " doc_summarize = DocSummarizerPipeline()\n", " \n", " # Process the query: retrieve documents and generate the summary.\n", " result = doc_summarize.summarize_docs(state[\"docs\"],state[\"query\"])\n", " print(f\"\\nGenerated response: {result}\")\n", " \n", " return {\"response\": result}\n", "\n", "\n", "def response_judge(state: State)-> State:\n", " print(\"\\nEntering response_judge\")\n", " evaluator = IntermediateStateResponseEvaluator()\n", " query = state[\"query\"] \n", " generated_response = state[\"response\"] \n", " \n", " result = evaluator.is_response_sufficient(query, generated_response)\n", " print(f\"\\nResponse sufficient: {result}\")\n", " \n", " return {\"is_response_sufficient\": result}\n", "\n", "def web_response(state: State)-> State:\n", " print(f\"\"\"\\n\\nweb_response state check\\n-{state[\"is_response_sufficient\"]}\\n-\"\"\")\n", " print(\"\\n\\nRetrived Docs weren't suitable to answer, so going for web search\")\n", " print(\"\\nEntering web_response\")\n", " agent = WebSearchAgent()\n", " user_query = state[\"query\"]\n", " output = agent.web_based_response(user_query)\n", " # print(f\"\\nWeb search response: {output}\")\n", "\n", " return {\"response\": output}\n", "\n", "# Define a conditional function that inspects the state\n", "# def route_from_response_judge(state):\n", "# print(\"check routing\",state.get(\"is_response_sufficient\", \"no\"),\"\\n\",state[\"is_response_sufficient\"])\n", "# # If web search is needed, return \"no\"; otherwise return \"yes\"\n", "# if state.get(\"is_response_sufficient\", \"no\"):\n", "# return \"no\"\n", "# return \"yes\"\n", "\n", "def route_from_response_judge(state):\n", " if state.get(\"is_response_sufficient\") == \"yes\":\n", " print (\"returning -yes\")\n", " \n", " return \"yes\" # Correct the return value here as well\n", " print (\"returning -no\")\n", " return \"no\"\n", "# Create the workflow graph\n", "workflow = StateGraph(State)\n", "\n", "# Add nodes for each state in the workflow\n", "workflow.add_node(\"faiss_content_retriever\", faiss_content_retriever) # Initial categorization node\n", "workflow.add_node(\"grounded_response\", grounded_response) # Initial categorization node\n", "workflow.add_node(\"response_judge\", response_judge) # Initial categorization node\n", "workflow.add_node(\"web_response\", web_response) # Initial categorization node\n", "\n", "\n", "workflow.add_edge(START,\"faiss_content_retriever\")\n", "\n", "# Define the workflow edges\n", "workflow.add_edge(\"faiss_content_retriever\", \"grounded_response\")\n", "workflow.add_edge(\"grounded_response\", \"response_judge\")\n", "\n", "# Set up the conditional edge from \"response_judge\"\n", "# Mapping: if \"yes\" then route to END, if \"no\" then route to \"web_response\"\n", "workflow.add_conditional_edges(\n", " \"response_judge\",\n", " route_from_response_judge,\n", " {\n", " \"yes\": END,\n", " \"no\": \"web_response\"\n", " }\n", ")\n", "\n", "\n", "# Ensure that if the workflow goes to web_response, it then routes to END.\n", "workflow.add_edge(\"web_response\", END)\n", "# workflow.add_edge(\"web_response\", END)\n", "\n", "# workflow.add_edge(\"response_judge\", END)\n", "\n", "# Set the initial entry point to start the workflow at the categorize node\n", "workflow.set_entry_point(\"faiss_content_retriever\")\n", "\n", "# Compile the workflow graph into an application\n", "app = workflow.compile()\n" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Display the workflow graph as a PNG image using Mermaid\n", "display(\n", " Image(\n", " app.get_graph().draw_mermaid_png(\n", " draw_method=MermaidDrawMethod.API, # Uses Mermaid's API to generate the PNG image of the workflow graph\n", " )\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "def run_user_query(query: str) -> Dict[str, str]:\n", " \"\"\"Process a user query through the LangGraph workflow.\n", " \n", " Args:\n", " query (str): The user's query\n", " \n", " Returns:\n", " Dict[str, str]: A dictionary containing the query's category and response\n", " \"\"\"\n", " results = app.invoke({\"query\": query})\n", " return {\n", " # \"category\": results[\"category\"],\n", " \"response\": results[\"response\"]\n", " }" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Entering faiss_content_retriever\n", "\n", "Entering grounded_response\n", "You are an assistant that summarizes text. Given the following content:\n", "\n", "must identify what further evidence shall be brought on record at trial that could not be brought on record at the stage of summary judgment; and (f) the reply must state why, in light of the evidence or material on record if any, the Court should not proceed to summary judgment.\n", "\n", "comply with any order passed in a case management hearing, the court may, levy costs for such non-compliance; foreclose the non-complainant party’s right to file a \u0000 d a v i t s , c o n d u c t c r o s s examinations of witnesses, file written submissions, address oral arguments or make further arguments in trial; or, dismiss the plaint or allow the suit where such non-compliance is wilful, repeated and imposition of costs is not adequate to ensure compliance.vi. Parties are required to submit written arguments, 4 weeks prior to commencing oral arguments, followed by revised written arguments, if any, within 1 week of completion of oral arguments. Arguments are required to be closed no later than 6 months from the date of the first case management meeting. Judgment is required to be pronounced within 90 days of conclusion of arguments.186 Summary Suits in Civil Proceedings under Order 37 of the CPC\n", "\n", "commercial causes to be tried as an ordinary suit. Leave to defend may be unconditional, or conditional upon deposit by the defendant of the whole, or part of the claim amount. If no defence is made out, the court may pass summary judgment on the suit.19Summary Judgments under the Commercial Courts ActA party may apply for a summary judgment, at any time after the writ of summons is served on the defendant but prior to framing of issues.may make its decision without recording oral evidence.The court may pass such orders as deemed fit including:The court may give a summary judgment against a plainti\u0000 or defendant, if the court considers that, (a) the plainti\u0000 has no real prospect of succeeding in its claim or the defendant has no real prospect of successfully defending the claim; and (b) there is no other compelling reason why the claim should not be disposed of before recording of oral evidence.I.judgment on the claim;ii. conditional order;\n", "\n", "A plainti\u0000 may file a summary suit for monetary claims upon negotiable instruments (such as bills of exchange, hundis and promissory notes), or for recovery of debt or liquidated demand arising on a written contract, or on a guarantee. No relief other than amonetary decree may be claimed in such a suit. Where any other relief is sought, the plainti\u0000 must file a regular civil suit under ordinary civil procedure.Where a suit is instituted as a summary suit, the defendant is not entitled to6 Order 37, Rules 1-3 are set out in the End Note.26 2023 © Cyril Amarchand MangaldasGuide to Litigation in Indiadefend as a matter of right, but must apply to the court for leave to defend and while so applying, be able to establish a prima facie defence in his favour. If he / she establishes a defence to the satisfaction of the court, the defendant is granted leave to defend and the summary suit is transferred to the list of\n", "\n", "In light of the spread of the Covid-19 pandemic, the Supreme Court in exercise of its powers under Article 142 of the Constitution suspended the period of limitation for all claims for nearly 24 months, thereby permitting such claims to be brought even after the strict period of limitation had lapsed, subject to certain rules for the calculation of such limitation.Guide to Litigation in India10Civil Proceedings against the State\n", "\n", "Additionally, Order 1 Rule 8 of the CPC enables a group of plainti\u0000s to collectively file a civil suit, with the permission of the court, in a representative capacity for the benefit of a group or class of persons having a common interest in the subject matter of the suit. This provision is an exception to the general rule that all persons interested in a suit should be made parties thereto.A decree passed by the court is binding on all interested persons forming part of the group or class.7 Section 245(3) of the Companies Act read with Rule 2 of the National Company Law Tribunal (Second Amendment) Rules, 2019\n", "\n", "Meaning(iv) impose such other conditions, including providing security for restitution of losses that any party is likely to suffer during the pendency of the suit, as the Court may deem fit in its discretion; and (b) specify the consequences of the failure to comply with the conditional order, including passing a judgment against the party that have not complied with the conditional order.8. Power to impose costs.—The Court may make an order for payment of costs in an application for summary judgment in accordance with the provisions of sections 35 and 35A of the Code.Note: Order 13-A provides however, that an application for summary judgment under shall not be made in a suit in respect of any Commercial Dispute that is originally filed as a summary suit under Order 37.A Summons issued in prescribed form by the court calling upon the defendant to enter appearance and file its written statement of defence within the stipulated time.\n", "\n", "Summarize the content based on the query: \"Tell me about: Summary Suits in Civil Proceedings under Order 37 of the CPC \".\n", "\n", "Instructions:\n", "1. Provide a brief overall summary of the content.\n", "2. Extract the key content required to answer the query and list it in clear bullet points.\n", "3. Finally, provide only the final coherent answer that integrates these bullet points, without showing any intermediate steps.Finally, just answer the final coheren explaination without the 1st and 2nd step responses\n", "\n", "Generated response: Order 37 of the CPC allows for summary suits for monetary claims on negotiable instruments, recovery of debt, or liquidated demands from written contracts or guarantees. Only monetary decrees are permitted; other reliefs require a regular civil suit. The defendant doesn't have an automatic right to defend but must apply for leave to defend, showing a prima facie defense. If granted, the suit becomes an ordinary suit. The court can grant summary judgment if the plaintiff has no real prospect of success or the defendant has no real prospect of a successful defense, and there's no compelling reason to delay. The court can also impose conditions, costs, or dismiss the suit for non-compliance with orders.\n", "\n", "\n", "Entering response_judge\n", "\n", "Response sufficient: yes\n", "returning -yes\n" ] } ], "source": [ "\n", "# Define the user query.\n", "user_query = \"Tell me about: Summary Suits in Civil Proceedings under Order 37 of the CPC \"\n", "# user_query = \"How to make cake \"\n", "\n", "result = run_user_query(user_query)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Order 37 of the CPC allows for summary suits for monetary claims on negotiable instruments, recovery of debt, or liquidated demands from written contracts or guarantees. Only monetary decrees are permitted; other reliefs require a regular civil suit. The defendant doesn't have an automatic right to defend but must apply for leave to defend, showing a prima facie defense. If granted, the suit becomes an ordinary suit. The court can grant summary judgment if the plaintiff has no real prospect of success or the defendant has no real prospect of a successful defense, and there's no compelling reason to delay. The court can also impose conditions, costs, or dismiss the suit for non-compliance with orders.\n", "\n" ] } ], "source": [ "print(result[\"response\"])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "base", "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": 2 }