{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "551abdb6-ca7d-4625-8526-8c1cd5b04219",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from dotenv import load_dotenv, find_dotenv\n",
    "_ = load_dotenv(find_dotenv())\n",
    "openai_api_key = os.environ[\"OPENAI_API_KEY\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48db5ec2-2584-439e-b0ac-c8f1410de8d2",
   "metadata": {},
   "source": [
    "## Chains\n",
    "Chains are sequences of operations. Usually, a chain combines:\n",
    "* a language model (LLM or Chat Model)\n",
    "* a prompt\n",
    "* other components"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43746676-aece-49a8-9205-be1e2844d873",
   "metadata": {},
   "source": [
    "## Simple chain with LLMChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "826a3c4c-7922-4d89-ad4c-d13c6cc84a52",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chains import LLMChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e0087663-b9b1-45af-9497-c914ea6de46a",
   "metadata": {},
   "outputs": [],
   "source": [
    "chat = ChatOpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3296aeb5-0720-4a11-a8c6-bb2d800859a7",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_template = ChatPromptTemplate.from_template(\n",
    "    \"What is the best name to describe a company that makes {product}?\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "21c38b38-a3fb-478f-a3ce-eec1de45f97b",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm_chain = LLMChain(\n",
    "    llm=chat,\n",
    "    prompt=prompt_template\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "655659b9-b3ec-47aa-9889-594caed654ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "product = \"AI Applications and AI Courses\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ffb90db2-1d9e-48dc-ba01-1d1ff426d823",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/juliocolomer/.pyenv/versions/3.11.4/envs/venv020124/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'AI Mastery'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_chain.run(product)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e52c0a5-a378-4e16-b40f-c83ab9a79d05",
   "metadata": {},
   "source": [
    "**The new way to do it with LangChain Expression Language**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "429da947-87a3-4a53-9ad5-d71c80227f76",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.schema import StrOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "40d36070-bd77-444c-8e73-365011de6b04",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_template = PromptTemplate.from_template(\n",
    "    \"What is a good name for a company that makes {product}?\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "74196a65-abfa-4d7a-9cd0-f821be7475e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_llm_chain = prompt_template | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "cd18e3ef-7fef-4ccc-8af1-af1b4eb52744",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1. AIverse Solutions\\n2. AI Academy\\n3. IntelliTech Solutions\\n4. AI Innovators\\n5. MindCraft AI\\n6. AI Wizardry\\n7. SynthAI Solutions\\n8. AI Mastery\\n9. CogniTech Academy\\n10. AI Prodigy\\n11. SmartAI Solutions\\n12. AI Nexus\\n13. AI Learners\\n14. TechGenius AI\\n15. AI Empowerment\\n16. Brainwave AI\\n17. AI Fusion\\n18. InsightAI Solutions\\n19. AI Mentors\\n20. AI Pathfinders'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_llm_chain.invoke(\n",
    "    {\"product\": product}\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa0ac6ff-45c7-4247-a302-e4abf1671218",
   "metadata": {},
   "source": [
    "## Sequential Chains with SequentialChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "846f107e-774b-4a3a-8838-8e2cd9db4284",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import SequentialChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "00e4a119-73e3-4347-a60d-cacd445514a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# prompt template 1: translate to Spanish\n",
    "first_prompt = ChatPromptTemplate.from_template(\n",
    "    \"Translate the following text to spanish:\"\n",
    "    \"\\n\\n{Text}\"\n",
    ")\n",
    "\n",
    "# chain 1: input= Text and output= Spanish_Translation\n",
    "chain_one = LLMChain(\n",
    "    llm=chat, \n",
    "    prompt=first_prompt, \n",
    "    output_key=\"Spanish_Translation\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "c093d793-2764-456e-b224-41557856ddee",
   "metadata": {},
   "outputs": [],
   "source": [
    "# prompt template 2: summarize\n",
    "second_prompt = ChatPromptTemplate.from_template(\n",
    "    \"Can you summarize the following text in 1 sentence:\"\n",
    "    \"\\n\\n{Text}\"\n",
    ")\n",
    "\n",
    "# chain 2: input= Text and output= summary\n",
    "chain_two = LLMChain(\n",
    "    llm=chat, \n",
    "    prompt=second_prompt, \n",
    "    output_key=\"summary\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "eabc82ab-1d5f-4fdf-a950-9045a5ddeaea",
   "metadata": {},
   "outputs": [],
   "source": [
    "# prompt template 3: identify language\n",
    "third_prompt = ChatPromptTemplate.from_template(\n",
    "    \"What language is the following text:\\n\\n{Spanish_Translation}\"\n",
    ")\n",
    "\n",
    "# chain 3: input= Spanish_Translation and output= language\n",
    "chain_three = LLMChain(\n",
    "    llm=chat, \n",
    "    prompt=third_prompt,\n",
    "    output_key=\"language\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "519fa7d9-f817-41d7-b9a1-d5f2821c169d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# prompt template 4: follow up message\n",
    "fourth_prompt = ChatPromptTemplate.from_template(\n",
    "    \"Write a follow up response to the following \"\n",
    "    \"summary in the specified language:\"\n",
    "    \"\\n\\nSummary: {summary}\\n\\nLanguage: {language}\"\n",
    ")\n",
    "# chain 4: input= summary, language and output= followup_message\n",
    "chain_four = LLMChain(\n",
    "    llm=chat, \n",
    "    prompt=fourth_prompt,\n",
    "    output_key=\"followup_message\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "60b59ca0-45a0-481c-b792-296b5bd20be0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# overall_chain: input= Text \n",
    "# and output= Spanish_Translation,summary, followup_message\n",
    "overall_chain = SequentialChain(\n",
    "    chains=[chain_one, chain_two, chain_three, chain_four],\n",
    "    input_variables=[\"Text\"],\n",
    "    output_variables=[\"Spanish_Translation\", \"summary\",\"followup_message\"],\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "bf9a5182-9c01-466e-80ba-353b9c8ac1c8",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/juliocolomer/.pyenv/versions/3.11.4/envs/venv020124/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SequentialChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'Text': \"\\nBeing in a start-up myself, I read this book to find comfort \\nand confirmation about the volatility and emotional roller-coaster \\nthat comes with a working at the brink of software-as-a service. \\nThis book was just what it promised - interviews from some of the \\ngreat successes in SV and elsewhere, their humble and sometimes \\ndifficult beginnings ('against all odds') that I am experiencing \\nright now. It's not a literary piece of work - never intended to \\nbe, on the contrary, I felt the writing style was just what fits \\nwith a life in the fast lane - little time, easy to read chapters, \\ninspiring and thank god, very 'down to earth.'\\n\\nThe one critical point I would like to make: I am somewhat \\nperplexed how the companies were chosen - there are so many \\nother companies that could have fit the profile which seem \\nmuch more of a success than some of the companies/products in \\nthe book (gmail? Comm'on, I guess the author wanted to have \\nGoogle in there, but didn't get an interview so she went with \\ngmail?). Other great companies are easy to find - they don't\\neven need to be in the consumer space. How about Salesforce.com? \\nI definitely liked the mix of 'new' and 'experienced' start ups. \\n\\nThis book was a breeze to read and insightful for us start-up \\nenterpreneurs.\\n\",\n",
       " 'Spanish_Translation': \"Siendo parte de una start-up, leí este libro para encontrar consuelo y confirmación sobre la volatilidad y la montaña rusa emocional que viene con trabajar en el límite del software como servicio. Este libro fue justo lo que prometía: entrevistas de algunos de los grandes éxitos en SV y otros lugares, sus humildes y a veces difíciles comienzos ('contra todo pronóstico') que estoy experimentando en este momento. No es una obra literaria, nunca fue la intención, al contrario, sentí que el estilo de escritura encajaba perfectamente con una vida en el carril rápido: poco tiempo, capítulos fáciles de leer, inspiradores y gracias a Dios, muy realistas.\\n\\nEl único punto crítico que me gustaría señalar: estoy algo perplejo acerca de cómo se eligieron las empresas. Hay tantas otras empresas que podrían haber encajado en el perfil y parecen ser mucho más exitosas que algunas de las empresas/productos en el libro (¿gmail? Vamos, supongo que la autora quería incluir a Google, pero no consiguió una entrevista, así que se fue por gmail). Otras grandes empresas son fáciles de encontrar, ni siquiera necesitan estar en el espacio del consumidor. ¿Qué tal Salesforce.com? Definitivamente me gustó la mezcla de start-ups 'nuevas' y 'experimentadas'.\\n\\nEste libro fue muy fácil de leer y esclarecedor para nosotros, los emprendedores de start-ups.\",\n",
       " 'summary': 'The text describes how the book provided comfort and confirmation for the author, who is experiencing the challenges of working in a start-up, and praises its easy-to-read style and inspiring content, while also criticizing the selection of companies featured in the book.',\n",
       " 'followup_message': 'Respuesta: El texto describe cómo el libro proporcionó consuelo y confirmación al autor, quien está experimentando los desafíos de trabajar en una start-up, y elogia su estilo fácil de leer y su contenido inspirador, al mismo tiempo que critica la selección de empresas destacadas en el libro.\\n\\nEstimado autor,\\n\\nAgradezco sinceramente su comentario sobre mi libro. Me complace saber que ha encontrado consuelo y confirmación a través de su lectura, especialmente considerando los desafíos que enfrenta al trabajar en una start-up. Es mi objetivo principal brindar inspiración y apoyo a través de mis escritos, y me alegra que haya resonado con usted de esa manera.\\n\\nAdemás, agradezco su elogio sobre el estilo fácil de leer del libro. Siempre me esfuerzo por hacer que mis obras sean accesibles para todo tipo de lectores, por lo que saber que ha encontrado mi estilo de escritura agradable es muy gratificante.\\n\\nSin embargo, también he tomado nota de su crítica sobre la selección de empresas destacadas en el libro. Aprecio su perspectiva y entiendo que cada lector tiene sus propias expectativas y preferencias. Lamento que las empresas presentadas no hayan cumplido con sus expectativas y espero que, a pesar de esto, haya encontrado valor en el contenido general del libro.\\n\\nLe agradezco nuevamente por compartir sus comentarios y espero que continúe disfrutando de mi trabajo. Si tiene alguna otra sugerencia o comentario, no dude en hacérmelo saber.\\n\\nAtentamente,\\n[Su nombre]'}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "review = \"\"\"\n",
    "Being in a start-up myself, I read this book to find comfort \n",
    "and confirmation about the volatility and emotional roller-coaster \n",
    "that comes with a working at the brink of software-as-a service. \n",
    "This book was just what it promised - interviews from some of the \n",
    "great successes in SV and elsewhere, their humble and sometimes \n",
    "difficult beginnings ('against all odds') that I am experiencing \n",
    "right now. It's not a literary piece of work - never intended to \n",
    "be, on the contrary, I felt the writing style was just what fits \n",
    "with a life in the fast lane - little time, easy to read chapters, \n",
    "inspiring and thank god, very 'down to earth.'\n",
    "\n",
    "The one critical point I would like to make: I am somewhat \n",
    "perplexed how the companies were chosen - there are so many \n",
    "other companies that could have fit the profile which seem \n",
    "much more of a success than some of the companies/products in \n",
    "the book (gmail? Comm'on, I guess the author wanted to have \n",
    "Google in there, but didn't get an interview so she went with \n",
    "gmail?). Other great companies are easy to find - they don't\n",
    "even need to be in the consumer space. How about Salesforce.com? \n",
    "I definitely liked the mix of 'new' and 'experienced' start ups. \n",
    "\n",
    "This book was a breeze to read and insightful for us start-up \n",
    "enterpreneurs.\n",
    "\"\"\"\n",
    "overall_chain(review)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8f3ad86-3204-482f-af67-319b3762e563",
   "metadata": {},
   "source": [
    "**The new way to do it with LangChain Expression Language**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "adf95299-4904-49b3-a257-3799633756d4",
   "metadata": {},
   "source": [
    "*Option 1: with the simpler syntax we get just the output.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "ae7040ba-d692-4bf7-92ee-f5bc3e55f2b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema import StrOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "9b662d70-c350-4853-8c8c-bc50eae5d69a",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_sequence_chain = {\"Spanish_Translation\": first_prompt | chat | StrOutputParser()} | third_prompt | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c0ebec43-fe94-4bae-b92f-51b1c37ec76b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The following text is in Spanish.'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_sequence_chain.invoke({\"Text\": review})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9210b61-fdae-4f51-b133-6791e5d4938c",
   "metadata": {},
   "source": [
    "*Option 2: with RunnablePassthrough we get input and output.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "f8207651-7cf0-41de-8f43-100f095e0754",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema.runnable import RunnablePassthrough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "6205f945-8c0f-4038-9c09-36af0a721413",
   "metadata": {},
   "outputs": [],
   "source": [
    "# input: Text, output: Spanish_Translation\n",
    "first_chain = first_prompt | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "0159cc78-7560-4365-a0ca-a92d2bc497be",
   "metadata": {},
   "outputs": [],
   "source": [
    "# input: Text, output: summary\n",
    "second_chain = second_prompt | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "7e888eee-1d0f-4e7b-baa3-6cb14017fe97",
   "metadata": {},
   "outputs": [],
   "source": [
    "# input: Spanish_Translation, output: language\n",
    "third_chain = third_prompt | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "da2e864a-1c3d-4917-8421-939dce2d33da",
   "metadata": {},
   "outputs": [],
   "source": [
    "# input: summary, output: followup_message\n",
    "fourth_chain = fourth_prompt | chat | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "2ee54257-86dc-4741-b9d5-6f21a1024616",
   "metadata": {},
   "outputs": [],
   "source": [
    "one_plus_three_sequence_chain = {\"Spanish_Translation\": first_chain} | RunnablePassthrough.assign(language=third_chain)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "1c1fff75-f3d3-4f60-a1b1-9aa24977d6aa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Spanish_Translation': 'Siendo parte de una startup yo mismo, leí este libro para encontrar consuelo y confirmación acerca de la volatilidad y montaña rusa emocional que viene con el trabajo al borde del software como servicio. Este libro fue justo lo que prometía: entrevistas de algunos de los grandes éxitos en SV y otros lugares, sus humildes y a veces difíciles comienzos (\\'contra todo pronóstico\\') que estoy experimentando en este momento. No es una obra literaria, nunca pretendió serlo, al contrario, sentí que el estilo de escritura era justo lo que se ajusta a una vida en la vía rápida: poco tiempo, capítulos fáciles de leer, inspiradores y gracias a Dios, muy realistas.\\n\\nEl único punto crítico que me gustaría hacer es que me siento algo perplejo acerca de cómo se eligieron las empresas: hay tantas otras empresas que podrían haber encajado en el perfil y que parecen ser mucho más exitosas que algunas de las empresas/productos en el libro (¿gmail? Vamos, supongo que la autora quería incluir a Google, pero no consiguió una entrevista, así que optó por gmail?). Otras grandes empresas son fáciles de encontrar, ni siquiera necesitan estar en el espacio de consumo. ¿Qué tal Salesforce.com? Definitivamente me gustó la mezcla de startups \"nuevas\" y \"experimentadas\".\\n\\nEste libro fue fácil de leer y esclarecedor para nosotros, los emprendedores de startups.',\n",
       " 'language': 'The following text is in Spanish.'}"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "one_plus_three_sequence_chain.invoke({\"Text\": review})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da1b3598-1265-45e0-9957-dec4eb8b7146",
   "metadata": {},
   "source": [
    "## Router Chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "930fa5b8-dede-49a3-b6f3-010d638e1442",
   "metadata": {},
   "outputs": [],
   "source": [
    "rock_template = \"\"\"You are a very smart rock and roll professor. \\\n",
    "You are great at answering questions about rock and roll in a concise\\\n",
    "and easy to understand manner.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "\n",
    "politics_template = \"\"\"You are a very good politics professor. \\\n",
    "You are great at answering politics questions..\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "\n",
    "history_template = \"\"\"You are a very good history teacher. \\\n",
    "You have an excellent knowledge of and understanding of people,\\\n",
    "events and contexts from a range of historical periods.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "\n",
    "sports_template = \"\"\" You are a sports teacher.\\\n",
    "You are great at answering sports questions.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "c30b8fc9-dfa5-45b5-8e30-2afb1ca65c06",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_infos = [\n",
    "    {\n",
    "        \"name\": \"rock\", \n",
    "        \"description\": \"Good for answering questions about rock and roll\", \n",
    "        \"prompt_template\": rock_template\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"politics\", \n",
    "        \"description\": \"Good for answering questions about politics\", \n",
    "        \"prompt_template\": politics_template\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"History\", \n",
    "        \"description\": \"Good for answering history questions\", \n",
    "        \"prompt_template\": history_template\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"sports\", \n",
    "        \"description\": \"Good for answering questions about sports\", \n",
    "        \"prompt_template\": sports_template\n",
    "    }\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "f1f918fd-7491-499f-910b-879b3b86477c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains.router import MultiPromptChain\n",
    "from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser\n",
    "from langchain.prompts import PromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "33ae3c67-712e-4c05-829d-907de1117be6",
   "metadata": {},
   "outputs": [],
   "source": [
    "destination_chains = {}\n",
    "\n",
    "for p_info in prompt_infos:\n",
    "    name = p_info[\"name\"]\n",
    "    prompt_template = p_info[\"prompt_template\"]\n",
    "    prompt = ChatPromptTemplate.from_template(template=prompt_template)\n",
    "    chain = LLMChain(llm=chat, prompt=prompt)\n",
    "    destination_chains[name] = chain  \n",
    "    \n",
    "destinations = [f\"{p['name']}: {p['description']}\" for p in prompt_infos]\n",
    "\n",
    "destinations_str = \"\\n\".join(destinations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f61bdf8b-4d9c-4be4-880b-725f78fe245c",
   "metadata": {},
   "outputs": [],
   "source": [
    "default_prompt = ChatPromptTemplate.from_template(\"{input}\")\n",
    "default_chain = LLMChain(llm=chat, prompt=default_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "cde9cfbb-24c1-4076-b559-ed6f9839e578",
   "metadata": {},
   "outputs": [],
   "source": [
    "MULTI_PROMPT_ROUTER_TEMPLATE = \"\"\"Given a raw text input to a \\\n",
    "language model select the model prompt best suited for the input. \\\n",
    "You will be given the names of the available prompts and a \\\n",
    "description of what the prompt is best suited for. \\\n",
    "You may also revise the original input if you think that revising\\\n",
    "it will ultimately lead to a better response from the language model.\n",
    "\n",
    "<< FORMATTING >>\n",
    "Return a markdown code snippet with a JSON object formatted to look like:\n",
    "```json\n",
    "{{{{\n",
    "    \"destination\": string \\ name of the prompt to use or \"DEFAULT\"\n",
    "    \"next_inputs\": string \\ a potentially modified version of the original input\n",
    "}}}}\n",
    "```\n",
    "\n",
    "REMEMBER: \"destination\" MUST be one of the candidate prompt \\\n",
    "names specified below OR it can be \"DEFAULT\" if the input is not\\\n",
    "well suited for any of the candidate prompts.\n",
    "\n",
    "REMEMBER: \"next_inputs\" can just be the original input \\\n",
    "if you don't think any modifications are needed.\n",
    "\n",
    "<< CANDIDATE PROMPTS >>\n",
    "{destinations}\n",
    "\n",
    "<< INPUT >>\n",
    "{{input}}\n",
    "\n",
    "<< OUTPUT (remember to include the ```json)>>\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "1626865b-1236-46cd-a2ce-0e5739a9f3d1",
   "metadata": {},
   "outputs": [],
   "source": [
    "router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(\n",
    "    destinations=destinations_str\n",
    ")\n",
    "router_prompt = PromptTemplate(\n",
    "    template=router_template,\n",
    "    input_variables=[\"input\"],\n",
    "    output_parser=RouterOutputParser(),\n",
    ")\n",
    "\n",
    "router_chain = LLMRouterChain.from_llm(\n",
    "    llm=chat, \n",
    "    prompt=router_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "16eb58bb-fee2-47a0-ae88-24ccff7d22b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = MultiPromptChain(router_chain=router_chain, \n",
    "                         destination_chains=destination_chains, \n",
    "                         default_chain=default_chain, verbose=True\n",
    "                        )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "725fc3c3-b7a7-42fb-86fa-00f0ad7c8a7e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/juliocolomer/.pyenv/versions/3.11.4/envs/venv020124/lib/python3.11/site-packages/langchain/chains/llm.py:316: UserWarning: The predict_and_parse method is deprecated, instead pass an output parser directly to LLMChain.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sports: {'input': 'Who was Joe DiMaggio?'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"Joe DiMaggio was a legendary American baseball player who played for the New York Yankees. He is considered one of the greatest baseball players of all time. He played as an outfielder and had an illustrious career from 1936 to 1951, during which he won numerous accolades and set several records. DiMaggio is best known for his 56-game hitting streak in 1941, a record that still stands today. He was a 13-time All-Star, a nine-time World Series champion, and a three-time Most Valuable Player (MVP) award winner. DiMaggio's skills, grace, and consistency made him a beloved figure in the world of baseball.\""
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"Who was Joe DiMaggio? Respond in less than 100 words\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "765a269b-97b2-492b-940e-ac7d2c79e0f2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/juliocolomer/.pyenv/versions/3.11.4/envs/venv020124/lib/python3.11/site-packages/langchain/chains/llm.py:316: UserWarning: The predict_and_parse method is deprecated, instead pass an output parser directly to LLMChain.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sports: {'input': 'What country won the last soccer world cup?'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'The last soccer World Cup was won by France. They emerged as the champions in the 2018 FIFA World Cup held in Russia.'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"What country won the last soccer world cup?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f76cb81-133f-449f-a626-a81c74bb0192",
   "metadata": {},
   "source": [
    "**How to do it with the new LangChain Expression Language**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "3e29463b-e3c8-4337-a830-8f668cd2b48c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "rock_template = \"\"\"You are a very smart rock and roll professor. \\\n",
    "You are great at answering questions about rock and roll in a concise\\\n",
    "and easy to understand manner.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "rock_prompt = PromptTemplate.from_template(rock_template)\n",
    "\n",
    "politics_template = \"\"\"You are a very good politics professor. \\\n",
    "You are great at answering politics questions..\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "politics_prompt = PromptTemplate.from_template(politics_template)\n",
    "\n",
    "history_template = \"\"\"You are a very good history teacher. \\\n",
    "You have an excellent knowledge of and understanding of people,\\\n",
    "events and contexts from a range of historical periods.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "history_prompt = PromptTemplate.from_template(history_template)\n",
    "\n",
    "sports_template = \"\"\" You are a sports teacher.\\\n",
    "You are great at answering sports questions.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "sports_prompt = PromptTemplate.from_template(sports_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "97c0e4ef-752e-4a93-a14c-2294ef53baa3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema.output_parser import StrOutputParser\n",
    "from langchain.schema.runnable import RunnableBranch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "1d83e739-6562-4060-a1bf-eedeabbcc476",
   "metadata": {},
   "outputs": [],
   "source": [
    "general_prompt = PromptTemplate.from_template(\n",
    "    \"You are a helpful assistant. Answer the question as accurately as you can.\\n\\n{input}\"\n",
    ")\n",
    "prompt_branch = RunnableBranch(\n",
    "  (lambda x: x[\"topic\"] == \"rock\", rock_prompt),\n",
    "  (lambda x: x[\"topic\"] == \"politics\", politics_prompt),\n",
    "  (lambda x: x[\"topic\"] == \"history\", history_prompt),\n",
    "  (lambda x: x[\"topic\"] == \"sports\", sports_prompt),\n",
    "  general_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "afa7b985-05b6-4285-970f-30c100ed6677",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/juliocolomer/.pyenv/versions/3.11.4/envs/venv020124/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `convert_pydantic_to_openai_function` was deprecated in LangChain 0.1.16 and will be removed in 0.2.0. Use langchain_core.utils.function_calling.convert_to_openai_function() instead.\n",
      "  warn_deprecated(\n"
     ]
    }
   ],
   "source": [
    "from typing import Literal\n",
    "\n",
    "from langchain.pydantic_v1 import BaseModel\n",
    "from langchain.output_parsers.openai_functions import PydanticAttrOutputFunctionsParser\n",
    "from langchain.utils.openai_functions import convert_pydantic_to_openai_function\n",
    "\n",
    "\n",
    "class TopicClassifier(BaseModel):\n",
    "    \"Classify the topic of the user question\"\n",
    "    \n",
    "    topic: Literal[\"rock\", \"politics\", \"history\", \"sports\"]\n",
    "    \"The topic of the user question. One of 'rock', 'politics', 'history', 'sports' or 'general'.\"\n",
    "\n",
    "\n",
    "classifier_function = convert_pydantic_to_openai_function(TopicClassifier)\n",
    "llm = ChatOpenAI().bind(functions=[classifier_function], function_call={\"name\": \"TopicClassifier\"}) \n",
    "parser = PydanticAttrOutputFunctionsParser(pydantic_schema=TopicClassifier, attr_name=\"topic\")\n",
    "classifier_chain = llm | parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "873263ad-0e81-4b8b-9a46-dd8f4615b047",
   "metadata": {},
   "outputs": [],
   "source": [
    "from operator import itemgetter\n",
    "\n",
    "from langchain.schema.output_parser import StrOutputParser\n",
    "from langchain.schema.runnable import RunnablePassthrough\n",
    "\n",
    "\n",
    "final_chain = (\n",
    "    RunnablePassthrough.assign(topic=itemgetter(\"input\") | classifier_chain) \n",
    "    | prompt_branch \n",
    "    | ChatOpenAI()\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "c3fe884d-5713-412c-85a5-0d61ca21384a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Thank you for the compliment! Napoleon Bonaparte was a prominent figure in history, known for his military genius and his impact on Europe during the late 18th and early 19th centuries. He was born on August 15, 1769, in Corsica, which was a French territory at the time. Napoleon rose to power during the French Revolution and eventually became the Emperor of France.\\n\\nNapoleon's military career began when he joined the French Army during the revolutionary years. He quickly rose through the ranks due to his tactical abilities and leadership qualities. In 1799, he staged a coup d'état and became the First Consul of France. In 1804, he declared himself Emperor Napoleon I.\\n\\nDuring his reign, Napoleon implemented several significant reforms in France, known as the Napoleonic Code. This legal system sought to establish equality before the law, religious toleration, and the protection of property rights. He also introduced various administrative, educational, and economic reforms that modernized the country.\\n\\nNapoleon's military campaigns were some of the most successful in history. He expanded the French Empire, conquering vast territories in Europe, including Italy, the Netherlands, Belgium, and parts of Germany. However, his ambitious conquests eventually led to resistance from other European powers, resulting in a series of wars known as the Napoleonic Wars.\\n\\nIn 1812, Napoleon faced a major setback when he invaded Russia but suffered a disastrous defeat due to the harsh Russian winter and guerilla warfare tactics. This marked the turning point in his military career. In 1814, he was forced to abdicate the throne and was exiled to the island of Elba.\\n\\nHowever, Napoleon escaped from Elba in 1815 and returned to France for a brief period known as the Hundred Days. He was ultimately defeated at the Battle of Waterloo by a coalition of European powers led by the British and Prussians. He was then exiled to the remote island of Saint Helena, where he died on May 5, 1821.\\n\\nNapoleon Bonaparte's legacy is a subject of debate among historians. Some view him as a military genius and a visionary leader who brought stability and reforms to France. Others criticize his autocratic rule and the enormous loss of life during his wars. Regardless, Napoleon's impact on Europe and his significant role in shaping the modern world cannot be denied.\""
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "final_chain.invoke(\n",
    "    {\"input\": \"Who was Napoleon Bonaparte?\"}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80e5c392-772c-4d70-bab4-2a044383be4a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "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.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
