code: import os
  import openai
  from dotenv import load_dotenv
  from langchain.chat_models import AzureChatOpenAI
  from langchain.chat_models import ChatOpenAI
  from langchain.embeddings import OpenAIEmbeddings
  from langchain.callbacks.base import BaseCallbackHandler
  
  
  from langchain.vectorstores import FAISS
  from langchain.chains import ConversationalRetrievalChain
  from langchain.chains.conversational_retrieval.base import BaseConversationalRetrievalChain
  from langchain.prompts import PromptTemplate
  
  from langchain.document_loaders import (UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader)
  import langchain.text_splitter as text_splitter
  from langchain.text_splitter import (RecursiveCharacterTextSplitter, CharacterTextSplitter)
  
  from typing import List
  import streamlit
  import glob
  
  REQUEST_TIMEOUT_DEFAULT = 10
  TEMPERATURE_DEFAULT = 0.0
  CHAT_MODEL_NAME_DEFAULT = "gpt-3.5-turbo"
  OPENAI_EMBEDDING_DEPLOYMENT_NAME_DEFAULT = "text-embedding-ada-002"
  CHUNK_SIZE_DEFAULT = 1000
  CHUNK_OVERLAP_DEFAULT = 0
  
  class StreamHandler(BaseCallbackHandler):
      def __init__(self, container, initial_text=""):
          self.container = container
          self.text = initial_text
  
      def on_llm_new_token(self, token: str, **kwargs) -> None:
          self.text += token
          self.container.markdown(self.text)
  
  
  class DocChatbot:
      llm: ChatOpenAI
      condense_question_llm: ChatOpenAI
      embeddings: OpenAIEmbeddings
      vector_db: FAISS
      chatchain: BaseConversationalRetrievalChain
  
      # configuration for API calls
      request_timeout: int
      temperature: float
      chat_model_name : str
      api_key : str
  
      def init_llm_openai(self, streaming: bool, condense_question_container = None, answer_container = None) -> None:
          # init for LLM using openai.com api
  
          self.llm = ChatOpenAI(
                  temperature=self.temperature,
                  openai_api_key=self.api_key,
                  request_timeout=self.request_timeout,
                  model=self.chat_model_name,  # Model name is needed for openai.com only
                  streaming=streaming,
                  callbacks=[StreamHandler(answer_container)] if streaming else []
              ) # type: ignore
  
          if streaming:
              self.condense_question_llm = ChatOpenAI(
                  temperature=self.temperature,
                  openai_api_key=self.api_key,
                  request_timeout=self.request_timeout,
                  streaming=True,
                  model=self.chat_model_name,
                  callbacks=[StreamHandler(condense_question_container, "🤔...")]
              ) # type: ignore
          else:
              self.condense_question_llm = self.llm
  
      def init_llm_azure(self, streaming: bool, condense_question_container = None, answer_container = None) -> None:
          # init for LLM using Azure OpenAI Service
          
          assert(os.getenv("OPENAI_GPT_DEPLOYMENT_NAME") is not None)
          assert(os.getenv("OPENAI_API_BASE") is not None)
          assert(os.getenv("OPENAI_EMBEDDING_DEPLOYMENT_NAME") is not None)
          assert(len(self.api_key) == 32)
  
          self.llm = AzureChatOpenAI(
              deployment_name=os.getenv("OPENAI_GPT_DEPLOYMENT_NAME"),
              temperature=self.temperature,
              openai_api_version="2023-05-15",
              openai_api_type="azure",
              openai_api_base=os.getenv("OPENAI_API_BASE"),
              openai_api_key=self.api_key,
              request_timeout=self.request_timeout,
              streaming=streaming,
              callbacks=[StreamHandler(answer_container)] if streaming else []
          ) # type: ignore
  
          if streaming:
              self.condense_question_llm = AzureChatOpenAI(
                  deployment_name=os.getenv("OPENAI_GPT_DEPLOYMENT_NAME"),
                  temperature=self.temperature,
                  openai_api_version="2023-05-15",
                  openai_api_type="azure",
                  openai_api_base=os.getenv("OPENAI_API_BASE"),
                  openai_api_key=os.getenv("OPENAI_API_KEY"),
                  request_timeout=self.request_timeout,
                  model=self.chat_model_name,
                  streaming=True,
                  callbacks=[StreamHandler(condense_question_container, "🤔...")]
              ) # type: ignore
          else:
              self.condense_question_llm = self.llm
  
      def __init__(self) -> None:
          #init for LLM and Embeddings, without support for streaming
  
          #load environment variables
          load_dotenv()
          assert(os.getenv("OPENAI_API_KEY") is not None)
          self.api_key = str(os.getenv("OPENAI_API_KEY"))
          self.request_timeout = REQUEST_TIMEOUT_DEFAULT if os.getenv("REQUEST_TIMEOUT") is None else int(os.getenv("REQUEST_TIMEOUT"))
          self.temperature = TEMPERATURE_DEFAULT if os.getenv("TEMPERATURE") is None else float(os.getenv("TEMPERATURE"))
          self.chat_model_name = CHAT_MODEL_NAME_DEFAULT if os.getenv("CHAT_MODEL_NAME") is None else str(os.getenv("CHAT_MODEL_NAME"))
  
          #check if user is using API from openai.com or Azure OpenAI Service by inspecting the api key
          if self.api_key.startswith("sk-"):
              # user is using API from openai.com
              assert(len(self.api_key) == 51)
              self.init_llm_openai(False)
          else:
              # user is using Azure OpenAI Service
              self.init_llm_azure(False)
  
          embedding_deployment = OPENAI_EMBEDDING_DEPLOYMENT_NAME_DEFAULT if os.getenv("OPENAI_EMBEDDING_DEPLOYMENT_NAME") is None else str(os.getenv("OPENAI_EMBEDDING_DEPLOYMENT_NAME"))
          self.embeddings = OpenAIEmbeddings(
              deployment=embedding_deployment,
              chunk_size=1
              ) # type: ignore
  
      def init_streaming(self, condense_question_container, answer_container) -> None:
          #init for LLM and Embeddings, with support for streaming
  
          if self.api_key.startswith("sk-"):
              # user is using API from openai.com
              self.init_llm_openai(True, condense_question_container, answer_container)
          else:
              # user is using Azure OpenAI Service
              self.init_llm_azure(True, condense_question_container, answer_container)
  
      # def init_streaming(self, condense_question_container, answer_container) -> None:
      #     #init for LLM and Embeddings, with support for streaming
  
      #     api_key = str(os.getenv("OPENAI_API_KEY"))
      #     temperature=float(os.getenv("TEMPERATURE"))
      #     request_timeout=int(os.getenv("REQUEST_TIMEOUT"))
      #     model_name=str(os.getenv("CHAT_MODEL_NAME"))
      #     if api_key.startswith("sk-"):
      #         # user is using API from openai.com
      #         self.llm = ChatOpenAI(
      #             temperature=temperature,
      #             openai_api_key=api_key,
      #             request_timeout=request_timeout,
      #             streaming=True,
      #             model=model_name,
      #             callbacks=[StreamHandler(answer_container)]
      #         ) # type: ignore
  
      #         self.condense_question_llm = ChatOpenAI(
      #             temperature=temperature,
      #             openai_api_key=api_key,
      #             request_timeout=request_timeout,
      #             streaming=True,
      #             model=model_name,
      #             callbacks=[StreamHandler(condense_question_container, "🤔...")]
      #         ) # type: ignore
      #     else:
      #         # user is using Azure OpenAI Service
      #         self.llm = AzureChatOpenAI(
      #             deployment_name=os.getenv("OPENAI_GPT_DEPLOYMENT_NAME"),
      #             temperature=temperature,
      #             openai_api_version="2023-05-15",
      #             openai_api_type="azure",
      #             openai_api_base=os.getenv("OPENAI_API_BASE"),
      #             openai_api_key=os.getenv("OPENAI_API_KEY"),
      #             request_timeout=request_timeout,
      #             model=model_name,
      #             streaming=True,
      #             callbacks=[StreamHandler(answer_container)]
      #         ) # type: ignore
  
      #         self.condense_question_llm = AzureChatOpenAI(
      #             deployment_name=os.getenv("OPENAI_GPT_DEPLOYMENT_NAME"),
      #             temperature=temperature,
      #             openai_api_version="2023-05-15",
      #             openai_api_type="azure",
      #             openai_api_base=os.getenv("OPENAI_API_BASE"),
      #             openai_api_key=os.getenv("OPENAI_API_KEY"),
      #             request_timeout=request_timeout,
      #             model=model_name,
      #             streaming=True,
      #             callbacks=[StreamHandler(condense_question_container, "🤔...")]
      #         ) # type: ignore
          
      def init_chatchain(self, chain_type : str = "stuff") -> None:
          # init for ConversationalRetrievalChain
          CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template("""Given the following conversation and a follow up input, rephrase the standalone question. 
          The standanlone question to be generated should be in the same language with the input. 
          For example, if the input is in Chinese, the follow up question or the standalone question below should be in Chinese too.
              Chat History:
              {chat_history}
  
              Follow Up Input:
              {question}
  
              Standalone Question:"""
              )                                 
          # stuff chain_type seems working better than others
          self.chatchain = ConversationalRetrievalChain.from_llm(llm=self.llm, 
                                                  retriever=self.vector_db.as_retriever(),
                                                  condense_question_prompt=CONDENSE_QUESTION_PROMPT,
                                                  condense_question_llm=self.condense_question_llm,
                                                  chain_type=chain_type,
                                                  return_source_documents=True,
                                                  verbose=False)
                                                  # combine_docs_chain_kwargs=dict(return_map_steps=False))
  
      # get answer from query, return answer and source documents
      def get_answer_with_source(self, query, chat_history):
          result = self.chatchain({
                  "question": query,
                  "chat_history": chat_history
          },
          return_only_outputs=True)
          
          return result['answer'], result['source_documents']
  
      # get answer from query. 
      # This function is for streamlit app and the chat history is in a format aligned with openai api
      def get_answer(self, query, chat_history):
          ''' 
          Here's the format for chat history:
          [{"role": "assistant", "content": "How can I help you?"}, {"role": "user", "content": "What is your name?"}]
          The input for the Chain is in a format like this:
          [("How can I help you?", "What is your name?")]
          That is, it's a list of question and answer pairs.
          So need to transform the chat history to the format for the Chain
          '''  
          chat_history_for_chain = []
  
          for i in range(0, len(chat_history), 2):
              chat_history_for_chain.append((
                  chat_history[i]['content'], 
                  chat_history[i+1]['content'] if chat_history[i+1] is not None else ""
                  ))
  
          result = self.chatchain({
                  "question": query,
                  "chat_history": chat_history_for_chain
          },
          return_only_outputs=True)
          
          return result['answer'], result['source_documents']
          
  
      # load vector db from local
      def load_vector_db_from_local(self, path: str, index_name: str):
          self.vector_db = FAISS.load_local(path, self.embeddings, index_name)
          print(f"Loaded vector db from local: {path}/{index_name}")
  
      # save vector db to local
      def save_vector_db_to_local(self, path: str, index_name: str):
          FAISS.save_local(self.vector_db, path, index_name)
          print("Vector db saved to local")
  
  
      # split documents, generate embeddings and ingest to vector db
      def init_vector_db_from_documents(self, file_list: List[str]):
          chunk_size = CHUNK_SIZE_DEFAULT if os.getenv("CHUNK_SIZE") is None else int(os.getenv("CHUNK_SIZE"))
          chunk_overlap = CHUNK_OVERLAP_DEFAULT if os.getenv("CHUNK_OVERLAP") is None else int(os.getenv("CHUNK_OVERLAP"))
          text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
  
          docs = []
          for file in file_list:
              print(f"Loading file: {file}")
              ext_name = os.path.splitext(file)[-1]
              # print(ext_name)
  
              if ext_name == ".pptx":
                  loader = UnstructuredPowerPointLoader(file)
              elif ext_name == ".docx":
                  loader = UnstructuredWordDocumentLoader(file)
              elif ext_name == ".pdf":
                  loader = PyPDFLoader(file)
              elif ext_name == ".csv":
                  loader = CSVLoader(file_path=file)
              elif ext_name == ".xml":
                  loader = MWDumpLoader(file_path=file, encoding="utf8")
              else:
                  # process .txt, .html
                  loader = UnstructuredFileLoader(file)
  
              doc = loader.load_and_split(text_splitter)            
              docs.extend(doc)
              print("Processed document: " + file)
      
          print("Generating embeddings and ingesting to vector db.")
          self.vector_db = FAISS.from_documents(docs, self.embeddings)
          print("Vector db initialized.")
  
      # Get indexes available
      def get_available_indexes(self, path: str):
          return [os.path.splitext(os.path.basename(file))[0] for file in glob.glob(f"{path}/*.faiss")]
          
apis: langchain.document_loaders.MWDumpLoader langchain.prompts.PromptTemplate.from_template langchain.text_splitter.RecursiveCharacterTextSplitter langchain.document_loaders.UnstructuredFileLoader langchain.document_loaders.UnstructuredWordDocumentLoader langchain.vectorstores.FAISS.from_documents langchain.document_loaders.UnstructuredPowerPointLoader langchain.embeddings.OpenAIEmbeddings langchain.vectorstores.FAISS.load_local langchain.document_loaders.CSVLoader langchain.document_loaders.PyPDFLoader langchain.vectorstores.FAISS.save_local
extract_api: [((4507, 4520), 'dotenv.load_dotenv', 'load_dotenv', ([], {}), '()\n', (4518, 4520), False, 'from dotenv import load_dotenv\n'), ((5613, 5676), 'langchain.embeddings.OpenAIEmbeddings', 'OpenAIEmbeddings', ([], {'deployment': 'embedding_deployment', 'chunk_size': '(1)'}), '(deployment=embedding_deployment, chunk_size=1)\n', (5629, 5676), False, 'from langchain.embeddings import OpenAIEmbeddings\n'), ((8836, 9340), 'langchain.prompts.PromptTemplate.from_template', 'PromptTemplate.from_template', (['"""Given the following conversation and a follow up input, rephrase the standalone question. \n        The standanlone question to be generated should be in the same language with the input. \n        For example, if the input is in Chinese, the follow up question or the standalone question below should be in Chinese too.\n            Chat History:\n            {chat_history}\n\n            Follow Up Input:\n            {question}\n\n            Standalone Question:"""'], {}), '(\n    """Given the following conversation and a follow up input, rephrase the standalone question. \n        The standanlone question to be generated should be in the same language with the input. \n        For example, if the input is in Chinese, the follow up question or the standalone question below should be in Chinese too.\n            Chat History:\n            {chat_history}\n\n            Follow Up Input:\n            {question}\n\n            Standalone Question:"""\n    )\n', (8864, 9340), False, 'from langchain.prompts import PromptTemplate\n'), ((11740, 11791), 'langchain.vectorstores.FAISS.load_local', 'FAISS.load_local', (['path', 'self.embeddings', 'index_name'], {}), '(path, self.embeddings, index_name)\n', (11756, 11791), False, 'from langchain.vectorstores import FAISS\n'), ((11965, 12015), 'langchain.vectorstores.FAISS.save_local', 'FAISS.save_local', (['self.vector_db', 'path', 'index_name'], {}), '(self.vector_db, path, index_name)\n', (11981, 12015), False, 'from langchain.vectorstores import FAISS\n'), ((12448, 12535), 'langchain.text_splitter.RecursiveCharacterTextSplitter', 'RecursiveCharacterTextSplitter', ([], {'chunk_size': 'chunk_size', 'chunk_overlap': 'chunk_overlap'}), '(chunk_size=chunk_size, chunk_overlap=\n    chunk_overlap)\n', (12478, 12535), False, 'from langchain.text_splitter import RecursiveCharacterTextSplitter, CharacterTextSplitter\n'), ((13530, 13573), 'langchain.vectorstores.FAISS.from_documents', 'FAISS.from_documents', (['docs', 'self.embeddings'], {}), '(docs, self.embeddings)\n', (13550, 13573), False, 'from langchain.vectorstores import FAISS\n'), ((2909, 2948), 'os.getenv', 'os.getenv', (['"""OPENAI_GPT_DEPLOYMENT_NAME"""'], {}), "('OPENAI_GPT_DEPLOYMENT_NAME')\n", (2918, 2948), False, 'import os\n'), ((2977, 3005), 'os.getenv', 'os.getenv', (['"""OPENAI_API_BASE"""'], {}), "('OPENAI_API_BASE')\n", (2986, 3005), False, 'import os\n'), ((3034, 3079), 'os.getenv', 'os.getenv', (['"""OPENAI_EMBEDDING_DEPLOYMENT_NAME"""'], {}), "('OPENAI_EMBEDDING_DEPLOYMENT_NAME')\n", (3043, 3079), False, 'import os\n'), ((4536, 4563), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (4545, 4563), False, 'import os\n'), ((4604, 4631), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (4613, 4631), False, 'import os\n'), ((3198, 3237), 'os.getenv', 'os.getenv', (['"""OPENAI_GPT_DEPLOYMENT_NAME"""'], {}), "('OPENAI_GPT_DEPLOYMENT_NAME')\n", (3207, 3237), False, 'import os\n'), ((3391, 3419), 'os.getenv', 'os.getenv', (['"""OPENAI_API_BASE"""'], {}), "('OPENAI_API_BASE')\n", (3400, 3419), False, 'import os\n'), ((4691, 4719), 'os.getenv', 'os.getenv', (['"""REQUEST_TIMEOUT"""'], {}), "('REQUEST_TIMEOUT')\n", (4700, 4719), False, 'import os\n'), ((4737, 4765), 'os.getenv', 'os.getenv', (['"""REQUEST_TIMEOUT"""'], {}), "('REQUEST_TIMEOUT')\n", (4746, 4765), False, 'import os\n'), ((4817, 4841), 'os.getenv', 'os.getenv', (['"""TEMPERATURE"""'], {}), "('TEMPERATURE')\n", (4826, 4841), False, 'import os\n'), ((4861, 4885), 'os.getenv', 'os.getenv', (['"""TEMPERATURE"""'], {}), "('TEMPERATURE')\n", (4870, 4885), False, 'import os\n'), ((4945, 4973), 'os.getenv', 'os.getenv', (['"""CHAT_MODEL_NAME"""'], {}), "('CHAT_MODEL_NAME')\n", (4954, 4973), False, 'import os\n'), ((4991, 5019), 'os.getenv', 'os.getenv', (['"""CHAT_MODEL_NAME"""'], {}), "('CHAT_MODEL_NAME')\n", (5000, 5019), False, 'import os\n'), ((5477, 5522), 'os.getenv', 'os.getenv', (['"""OPENAI_EMBEDDING_DEPLOYMENT_NAME"""'], {}), "('OPENAI_EMBEDDING_DEPLOYMENT_NAME')\n", (5486, 5522), False, 'import os\n'), ((5540, 5585), 'os.getenv', 'os.getenv', (['"""OPENAI_EMBEDDING_DEPLOYMENT_NAME"""'], {}), "('OPENAI_EMBEDDING_DEPLOYMENT_NAME')\n", (5549, 5585), False, 'import os\n'), ((12237, 12260), 'os.getenv', 'os.getenv', (['"""CHUNK_SIZE"""'], {}), "('CHUNK_SIZE')\n", (12246, 12260), False, 'import os\n'), ((12278, 12301), 'os.getenv', 'os.getenv', (['"""CHUNK_SIZE"""'], {}), "('CHUNK_SIZE')\n", (12287, 12301), False, 'import os\n'), ((12352, 12378), 'os.getenv', 'os.getenv', (['"""CHUNK_OVERLAP"""'], {}), "('CHUNK_OVERLAP')\n", (12361, 12378), False, 'import os\n'), ((12396, 12422), 'os.getenv', 'os.getenv', (['"""CHUNK_OVERLAP"""'], {}), "('CHUNK_OVERLAP')\n", (12405, 12422), False, 'import os\n'), ((12647, 12669), 'os.path.splitext', 'os.path.splitext', (['file'], {}), '(file)\n', (12663, 12669), False, 'import os\n'), ((12766, 12800), 'langchain.document_loaders.UnstructuredPowerPointLoader', 'UnstructuredPowerPointLoader', (['file'], {}), '(file)\n', (12794, 12800), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n'), ((13763, 13791), 'glob.glob', 'glob.glob', (['f"""{path}/*.faiss"""'], {}), "(f'{path}/*.faiss')\n", (13772, 13791), False, 'import glob\n'), ((3760, 3799), 'os.getenv', 'os.getenv', (['"""OPENAI_GPT_DEPLOYMENT_NAME"""'], {}), "('OPENAI_GPT_DEPLOYMENT_NAME')\n", (3769, 3799), False, 'import os\n'), ((3969, 3997), 'os.getenv', 'os.getenv', (['"""OPENAI_API_BASE"""'], {}), "('OPENAI_API_BASE')\n", (3978, 3997), False, 'import os\n'), ((4030, 4057), 'os.getenv', 'os.getenv', (['"""OPENAI_API_KEY"""'], {}), "('OPENAI_API_KEY')\n", (4039, 4057), False, 'import os\n'), ((12864, 12900), 'langchain.document_loaders.UnstructuredWordDocumentLoader', 'UnstructuredWordDocumentLoader', (['file'], {}), '(file)\n', (12894, 12900), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n'), ((13724, 13746), 'os.path.basename', 'os.path.basename', (['file'], {}), '(file)\n', (13740, 13746), False, 'import os\n'), ((12963, 12980), 'langchain.document_loaders.PyPDFLoader', 'PyPDFLoader', (['file'], {}), '(file)\n', (12974, 12980), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n'), ((13043, 13068), 'langchain.document_loaders.CSVLoader', 'CSVLoader', ([], {'file_path': 'file'}), '(file_path=file)\n', (13052, 13068), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n'), ((13131, 13176), 'langchain.document_loaders.MWDumpLoader', 'MWDumpLoader', ([], {'file_path': 'file', 'encoding': '"""utf8"""'}), "(file_path=file, encoding='utf8')\n", (13143, 13176), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n'), ((13258, 13286), 'langchain.document_loaders.UnstructuredFileLoader', 'UnstructuredFileLoader', (['file'], {}), '(file)\n', (13280, 13286), False, 'from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, PyPDFLoader, UnstructuredFileLoader, CSVLoader, MWDumpLoader\n')]