code: from urllib import response
  import llama_index
  
  from pathlib import Path
  from typing import Annotated, List
  from fastapi.responses import StreamingResponse
  from fastapi import (
      File,
      Form,
      UploadFile,
      APIRouter,
      Depends,
      HTTPException,
      Request,
      status
  )
  from llama_index import StorageContext, VectorStoreIndex, SummaryIndex
  from llama_index.selectors.llm_selectors import LLMSingleSelector
  from llama_index.llms.types import MessageRole, ChatMessage
  from llama_index.retrievers import VectorIndexRetriever, SummaryIndexEmbeddingRetriever, RouterRetriever
  from llama_index.tools import RetrieverTool
  from llama_index.chat_engine import ContextChatEngine
  from llama_index.memory import ChatMemoryBuffer
  from llama_index.vector_stores import (
      MetadataFilter,
      MetadataFilters,
      FilterOperator
  )
  
  from llama_index.callbacks import CallbackManager, LlamaDebugHandler
  
  from app.utils.json_to import json_to_model
  from app.utils.index import get_index
  from app.utils.auth import decode_access_token
  from app.utils.fs import get_s3_fs, get_s3_boto_client
  from app.db.pg_vector import get_vector_store_singleton
  from app.db.crud import get_documents, create_documents, delete_document, is_user_existed
  from app.pydantic_models.chat import ChatData
  from app.orm_models import Document
  from app.core.ingest import ingest_user_documents
  from app.prompts.system import LLM_SYSTEM_MESSAGE
  from app.prompts.selector import MULTI_SELECT_PROMPT_TEMPLATE, SINGLE_SELECTOR_PROMPT_TEMPLATE
  
  chat_router = r = APIRouter()
  
  
  @r.post("")
  async def chat(
      request: Request,
      # Note: To support clients sending a JSON object using content-type "text/plain",
      # we need to use Depends(json_to_model(_ChatData)) here
      data: Annotated[ChatData, Depends(json_to_model(ChatData))],
      index: Annotated[dict, Depends(get_index)],
      token_payload: Annotated[dict, Depends(decode_access_token)]
  ):
      # logger = logging.getLogger("uvicorn")
      user_id = token_payload["user_id"]
      # Only need to retrieve indices from the current user.
      filters = MetadataFilters(
          filters=[
              MetadataFilter(
                  key="user_id",
                  operator=FilterOperator.EQ,
                  value=user_id),
          ]
      )
  
      # check preconditions and get last message
      if len(data.messages) == 0:
          raise HTTPException(
              status_code=status.HTTP_400_BAD_REQUEST,
              detail="No messages provided",
          )
      lastMessage = data.messages.pop()
      if lastMessage.role != MessageRole.USER:
          raise HTTPException(
              status_code=status.HTTP_400_BAD_REQUEST,
              detail="Last message must be from user",
          )
      # convert messages coming from the request to type ChatMessage
      messages = [
          ChatMessage(
              role=m.role,
              content=m.content,
          )
          for m in data.messages
      ]
  
      # query chat engine
      # system_message = (
      #     "You are a professional job candidate who will answer the recruiter question using the context information."
      #     "If the question is out of scope, kindly apologize and refuse to answer."
      # )
  
      # Callbacks for observability.
      # TODO: this is not working.
      llama_debug = LlamaDebugHandler(print_trace_on_end=True)
      callback_manager = CallbackManager([llama_debug])
  
      vs_retriever = VectorIndexRetriever(
          index=index["vector"],
          similarity_top_k=3,
          filters=filters,
      )
      summary_retriever = SummaryIndexEmbeddingRetriever(
          index=index["summary"],
          similarity_top_k=3,
      )
  
      vs_tool = RetrieverTool.from_defaults(
          retriever=vs_retriever,
          description="Useful for retrieving specific context from uploaded documents."
      )
      summary_tool = RetrieverTool.from_defaults(
          retriever=summary_retriever,
          description="Useful to retrieve all context from uploaded documents and summary tasks. Don't use if the question only requires more specific context."
      )
  
      # TODO: correct the prompt used by LLM to use router retriever.
      retriever = RouterRetriever(
          selector=LLMSingleSelector.from_defaults(
              # prompt_template_str=SINGLE_SELECTOR_PROMPT_TEMPLATE
          ),
          retriever_tools=[vs_tool, summary_tool]
      )
  
      chat_engine = ContextChatEngine(
          retriever=vs_retriever,
          llm=llama_index.global_service_context.llm,
          memory=ChatMemoryBuffer.from_defaults(token_limit=4096),
          prefix_messages=[ChatMessage(
              role="system", content=LLM_SYSTEM_MESSAGE)],
          callback_manager=callback_manager,
      )
      print(chat_engine._retriever.get_prompts())
  
      response = chat_engine.stream_chat(lastMessage.content, messages)
  
      # stream response
      async def event_generator():
          for token in response.response_gen:
              # If client closes connection, stop sending events
              if await request.is_disconnected():
                  break
              yield token
  
      return StreamingResponse(event_generator(), media_type="text/plain")
  
  
  @r.post("/upload/single")
  async def upload(
      description: Annotated[str, Form()],
      question: Annotated[str, Form()],
      file: Annotated[UploadFile, File()],
      token_payload: Annotated[dict, Depends(decode_access_token)]
  ) -> Document:
      vector_store = await get_vector_store_singleton()
      user_id = token_payload["user_id"]
      user_s3_folder = Path(f"talking-resume/{user_id}")
      nodes = []
  
      # Have to use boto because I don't know how to write temporary file to s3 using f3fs.
      s3 = get_s3_boto_client()
      doc = Document(
          s3_path=f"{user_id}/{file.filename}",
          is_active=True,
          description=description,
          question=question,
          user_id=user_id,
      )
      # Create new record in db.
      doc_in_db = create_documents([doc])[0]
      doc_uuid = str(doc_in_db.id)
  
      # Save the document to S3.
      s3.upload_fileobj(
          file.file,
          "talking-resume",
          doc.s3_path,
      )
      nodes = ingest_user_documents(
          doc_uuid,
          f"talking-resume/{doc.s3_path}",
          doc.description,
          doc.question,
          doc.user_id
      )
  
      # Save documents indices and embeddings.
      s3 = get_s3_fs()
      persist_dir = None
      if await is_user_existed(user_id):
          persist_dir = f"talking-resume/{user_id}"
  
      storage_context = StorageContext.from_defaults(
          vector_store=vector_store,
          persist_dir=persist_dir,
          fs=s3)
      # Vector store index.
      vector_index = VectorStoreIndex.from_documents(
          documents=nodes, storage_context=storage_context, show_progress=True)
      vector_index.set_index_id(f'vector_{user_id}')
      vector_index.storage_context.persist(persist_dir=user_s3_folder, fs=s3)
  
      # Summary index.
      summary_index = SummaryIndex.from_documents(
          documents=nodes, storage_context=storage_context, show_progress=True)
      summary_index.set_index_id(f'summary_{user_id}')
      summary_index.storage_context.persist(persist_dir=user_s3_folder, fs=s3)
  
      return doc_in_db
  
  
  @r.get("/upload")
  def get_upload(
      user_id: str,
      token_payload: Annotated[dict, Depends(decode_access_token)]
  ) -> List[Document]:
      documents = get_documents(user_id)
      for document in documents:
          s3 = get_s3_boto_client()
          s3_url = s3.generate_presigned_url(
              "get_object",
              Params={
                  "Bucket": "talking-resume",
                  "Key": document.s3_path,
                  "ResponseContentDisposition": "inline",
                  "ResponseContentType": "application/pdf"})
          document.s3_url = s3_url
      return documents
  
  
  @r.delete("/upload")
  async def delete_upload(
      document_id: str,
      user_id: str,
  ) -> None:
      await delete_document(document_id, user_id)
  
  
  @r.post("/upload/multiple")
  async def upload(
      descriptions: Annotated[List[str], Form()],
      questions: Annotated[List[str], Form()],
      files: Annotated[List[UploadFile], File()],
      token_payload: Annotated[dict, Depends(decode_access_token)]
  ) -> List[Document]:
      vector_store = await get_vector_store_singleton()
      user_id = token_payload["user_id"]
      user_s3_folder = Path(f"talking-resume/{user_id}")
  
      # TODO: smartly remove or inactivate documents instead of full deletion.
      # if await is_user_existed(user_id):
      #     await delete_all_documents_from_user(user_id)
  
      # Have to use boto because I don't know how to write temporary file to s3 using f3fs.
      s3 = get_s3_boto_client()
      nodes = []
      docs = []
      for user_document, description, question in zip(files, descriptions, questions):
          doc = Document(
              s3_path=f"{user_id}/{user_document.filename}",
              is_active=True,
              description=description,
              question=question,
              user_id=user_id,
          )
  
          # Save the document to S3.
          s3.upload_fileobj(
              user_document.file,
              "talking-resume",
              doc.s3_path,
          )
          nodes.extend(ingest_user_documents(
              f"talking-resume/{doc.s3_path}", doc.description, doc.question, doc.user_id))
          docs.append(doc)
  
      # Save documents indices and embeddings.
      s3 = get_s3_fs()
      storage_context = StorageContext.from_defaults(
          vector_store=vector_store, fs=s3)
  
      # Vector store index.
      vector_index = VectorStoreIndex.from_documents(
          documents=nodes, storage_context=storage_context)
      vector_index.set_index_id(user_id)
      vector_index.storage_context.persist(persist_dir=user_s3_folder, fs=s3)
  
      # Create new record in db.
      docs = create_documents(docs)
      return docs
  
apis: llama_index.VectorStoreIndex.from_documents llama_index.retrievers.SummaryIndexEmbeddingRetriever llama_index.llms.types.ChatMessage llama_index.vector_stores.MetadataFilter llama_index.callbacks.LlamaDebugHandler llama_index.selectors.llm_selectors.LLMSingleSelector.from_defaults llama_index.StorageContext.from_defaults llama_index.retrievers.VectorIndexRetriever llama_index.callbacks.CallbackManager llama_index.tools.RetrieverTool.from_defaults llama_index.memory.ChatMemoryBuffer.from_defaults llama_index.SummaryIndex.from_documents
extract_api: [((1534, 1545), 'fastapi.APIRouter', 'APIRouter', ([], {}), '()\n', (1543, 1545), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((3266, 3308), 'llama_index.callbacks.LlamaDebugHandler', 'LlamaDebugHandler', ([], {'print_trace_on_end': '(True)'}), '(print_trace_on_end=True)\n', (3283, 3308), False, 'from llama_index.callbacks import CallbackManager, LlamaDebugHandler\n'), ((3332, 3362), 'llama_index.callbacks.CallbackManager', 'CallbackManager', (['[llama_debug]'], {}), '([llama_debug])\n', (3347, 3362), False, 'from llama_index.callbacks import CallbackManager, LlamaDebugHandler\n'), ((3383, 3468), 'llama_index.retrievers.VectorIndexRetriever', 'VectorIndexRetriever', ([], {'index': "index['vector']", 'similarity_top_k': '(3)', 'filters': 'filters'}), "(index=index['vector'], similarity_top_k=3, filters=filters\n    )\n", (3403, 3468), False, 'from llama_index.retrievers import VectorIndexRetriever, SummaryIndexEmbeddingRetriever, RouterRetriever\n'), ((3519, 3593), 'llama_index.retrievers.SummaryIndexEmbeddingRetriever', 'SummaryIndexEmbeddingRetriever', ([], {'index': "index['summary']", 'similarity_top_k': '(3)'}), "(index=index['summary'], similarity_top_k=3)\n", (3549, 3593), False, 'from llama_index.retrievers import VectorIndexRetriever, SummaryIndexEmbeddingRetriever, RouterRetriever\n'), ((3632, 3767), 'llama_index.tools.RetrieverTool.from_defaults', 'RetrieverTool.from_defaults', ([], {'retriever': 'vs_retriever', 'description': '"""Useful for retrieving specific context from uploaded documents."""'}), "(retriever=vs_retriever, description=\n    'Useful for retrieving specific context from uploaded documents.')\n", (3659, 3767), False, 'from llama_index.tools import RetrieverTool\n'), ((3804, 4022), 'llama_index.tools.RetrieverTool.from_defaults', 'RetrieverTool.from_defaults', ([], {'retriever': 'summary_retriever', 'description': '"""Useful to retrieve all context from uploaded documents and summary tasks. Don\'t use if the question only requires more specific context."""'}), '(retriever=summary_retriever, description=\n    "Useful to retrieve all context from uploaded documents and summary tasks. Don\'t use if the question only requires more specific context."\n    )\n', (3831, 4022), False, 'from llama_index.tools import RetrieverTool\n'), ((5459, 5492), 'pathlib.Path', 'Path', (['f"""talking-resume/{user_id}"""'], {}), "(f'talking-resume/{user_id}')\n", (5463, 5492), False, 'from pathlib import Path\n'), ((5608, 5628), 'app.utils.fs.get_s3_boto_client', 'get_s3_boto_client', ([], {}), '()\n', (5626, 5628), False, 'from app.utils.fs import get_s3_fs, get_s3_boto_client\n'), ((5639, 5767), 'app.orm_models.Document', 'Document', ([], {'s3_path': 'f"""{user_id}/{file.filename}"""', 'is_active': '(True)', 'description': 'description', 'question': 'question', 'user_id': 'user_id'}), "(s3_path=f'{user_id}/{file.filename}', is_active=True, description=\n    description, question=question, user_id=user_id)\n", (5647, 5767), False, 'from app.orm_models import Document\n'), ((6056, 6169), 'app.core.ingest.ingest_user_documents', 'ingest_user_documents', (['doc_uuid', 'f"""talking-resume/{doc.s3_path}"""', 'doc.description', 'doc.question', 'doc.user_id'], {}), "(doc_uuid, f'talking-resume/{doc.s3_path}', doc.\n    description, doc.question, doc.user_id)\n", (6077, 6169), False, 'from app.core.ingest import ingest_user_documents\n'), ((6266, 6277), 'app.utils.fs.get_s3_fs', 'get_s3_fs', ([], {}), '()\n', (6275, 6277), False, 'from app.utils.fs import get_s3_fs, get_s3_boto_client\n'), ((6413, 6505), 'llama_index.StorageContext.from_defaults', 'StorageContext.from_defaults', ([], {'vector_store': 'vector_store', 'persist_dir': 'persist_dir', 'fs': 's3'}), '(vector_store=vector_store, persist_dir=\n    persist_dir, fs=s3)\n', (6441, 6505), False, 'from llama_index import StorageContext, VectorStoreIndex, SummaryIndex\n'), ((6571, 6677), 'llama_index.VectorStoreIndex.from_documents', 'VectorStoreIndex.from_documents', ([], {'documents': 'nodes', 'storage_context': 'storage_context', 'show_progress': '(True)'}), '(documents=nodes, storage_context=\n    storage_context, show_progress=True)\n', (6602, 6677), False, 'from llama_index import StorageContext, VectorStoreIndex, SummaryIndex\n'), ((6851, 6953), 'llama_index.SummaryIndex.from_documents', 'SummaryIndex.from_documents', ([], {'documents': 'nodes', 'storage_context': 'storage_context', 'show_progress': '(True)'}), '(documents=nodes, storage_context=\n    storage_context, show_progress=True)\n', (6878, 6953), False, 'from llama_index import StorageContext, VectorStoreIndex, SummaryIndex\n'), ((7266, 7288), 'app.db.crud.get_documents', 'get_documents', (['user_id'], {}), '(user_id)\n', (7279, 7288), False, 'from app.db.crud import get_documents, create_documents, delete_document, is_user_existed\n'), ((8235, 8268), 'pathlib.Path', 'Path', (['f"""talking-resume/{user_id}"""'], {}), "(f'talking-resume/{user_id}')\n", (8239, 8268), False, 'from pathlib import Path\n'), ((8544, 8564), 'app.utils.fs.get_s3_boto_client', 'get_s3_boto_client', ([], {}), '()\n', (8562, 8564), False, 'from app.utils.fs import get_s3_fs, get_s3_boto_client\n'), ((9271, 9282), 'app.utils.fs.get_s3_fs', 'get_s3_fs', ([], {}), '()\n', (9280, 9282), False, 'from app.utils.fs import get_s3_fs, get_s3_boto_client\n'), ((9305, 9367), 'llama_index.StorageContext.from_defaults', 'StorageContext.from_defaults', ([], {'vector_store': 'vector_store', 'fs': 's3'}), '(vector_store=vector_store, fs=s3)\n', (9333, 9367), False, 'from llama_index import StorageContext, VectorStoreIndex, SummaryIndex\n'), ((9423, 9509), 'llama_index.VectorStoreIndex.from_documents', 'VectorStoreIndex.from_documents', ([], {'documents': 'nodes', 'storage_context': 'storage_context'}), '(documents=nodes, storage_context=\n    storage_context)\n', (9454, 9509), False, 'from llama_index import StorageContext, VectorStoreIndex, SummaryIndex\n'), ((9672, 9694), 'app.db.crud.create_documents', 'create_documents', (['docs'], {}), '(docs)\n', (9688, 9694), False, 'from app.db.crud import get_documents, create_documents, delete_document, is_user_existed\n'), ((2361, 2451), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'status.HTTP_400_BAD_REQUEST', 'detail': '"""No messages provided"""'}), "(status_code=status.HTTP_400_BAD_REQUEST, detail=\n    'No messages provided')\n", (2374, 2451), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((2579, 2679), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'status.HTTP_400_BAD_REQUEST', 'detail': '"""Last message must be from user"""'}), "(status_code=status.HTTP_400_BAD_REQUEST, detail=\n    'Last message must be from user')\n", (2592, 2679), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((2802, 2845), 'llama_index.llms.types.ChatMessage', 'ChatMessage', ([], {'role': 'm.role', 'content': 'm.content'}), '(role=m.role, content=m.content)\n', (2813, 2845), False, 'from llama_index.llms.types import MessageRole, ChatMessage\n'), ((5370, 5398), 'app.db.pg_vector.get_vector_store_singleton', 'get_vector_store_singleton', ([], {}), '()\n', (5396, 5398), False, 'from app.db.pg_vector import get_vector_store_singleton\n'), ((5857, 5880), 'app.db.crud.create_documents', 'create_documents', (['[doc]'], {}), '([doc])\n', (5873, 5880), False, 'from app.db.crud import get_documents, create_documents, delete_document, is_user_existed\n'), ((6314, 6338), 'app.db.crud.is_user_existed', 'is_user_existed', (['user_id'], {}), '(user_id)\n', (6329, 6338), False, 'from app.db.crud import get_documents, create_documents, delete_document, is_user_existed\n'), ((7333, 7353), 'app.utils.fs.get_s3_boto_client', 'get_s3_boto_client', ([], {}), '()\n', (7351, 7353), False, 'from app.utils.fs import get_s3_fs, get_s3_boto_client\n'), ((7808, 7845), 'app.db.crud.delete_document', 'delete_document', (['document_id', 'user_id'], {}), '(document_id, user_id)\n', (7823, 7845), False, 'from app.db.crud import get_documents, create_documents, delete_document, is_user_existed\n'), ((8146, 8174), 'app.db.pg_vector.get_vector_store_singleton', 'get_vector_store_singleton', ([], {}), '()\n', (8172, 8174), False, 'from app.db.pg_vector import get_vector_store_singleton\n'), ((8693, 8829), 'app.orm_models.Document', 'Document', ([], {'s3_path': 'f"""{user_id}/{user_document.filename}"""', 'is_active': '(True)', 'description': 'description', 'question': 'question', 'user_id': 'user_id'}), "(s3_path=f'{user_id}/{user_document.filename}', is_active=True,\n    description=description, question=question, user_id=user_id)\n", (8701, 8829), False, 'from app.orm_models import Document\n'), ((4154, 4187), 'llama_index.selectors.llm_selectors.LLMSingleSelector.from_defaults', 'LLMSingleSelector.from_defaults', ([], {}), '()\n', (4185, 4187), False, 'from llama_index.selectors.llm_selectors import LLMSingleSelector\n'), ((4455, 4503), 'llama_index.memory.ChatMemoryBuffer.from_defaults', 'ChatMemoryBuffer.from_defaults', ([], {'token_limit': '(4096)'}), '(token_limit=4096)\n', (4485, 4503), False, 'from llama_index.memory import ChatMemoryBuffer\n'), ((9078, 9181), 'app.core.ingest.ingest_user_documents', 'ingest_user_documents', (['f"""talking-resume/{doc.s3_path}"""', 'doc.description', 'doc.question', 'doc.user_id'], {}), "(f'talking-resume/{doc.s3_path}', doc.description, doc\n    .question, doc.user_id)\n", (9099, 9181), False, 'from app.core.ingest import ingest_user_documents\n'), ((1836, 1854), 'fastapi.Depends', 'Depends', (['get_index'], {}), '(get_index)\n', (1843, 1854), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((1892, 1920), 'fastapi.Depends', 'Depends', (['decode_access_token'], {}), '(decode_access_token)\n', (1899, 1920), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((2128, 2200), 'llama_index.vector_stores.MetadataFilter', 'MetadataFilter', ([], {'key': '"""user_id"""', 'operator': 'FilterOperator.EQ', 'value': 'user_id'}), "(key='user_id', operator=FilterOperator.EQ, value=user_id)\n", (2142, 2200), False, 'from llama_index.vector_stores import MetadataFilter, MetadataFilters, FilterOperator\n'), ((4530, 4584), 'llama_index.llms.types.ChatMessage', 'ChatMessage', ([], {'role': '"""system"""', 'content': 'LLM_SYSTEM_MESSAGE'}), "(role='system', content=LLM_SYSTEM_MESSAGE)\n", (4541, 4584), False, 'from llama_index.llms.types import MessageRole, ChatMessage\n'), ((5177, 5183), 'fastapi.Form', 'Form', ([], {}), '()\n', (5181, 5183), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((5215, 5221), 'fastapi.Form', 'Form', ([], {}), '()\n', (5219, 5221), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((5256, 5262), 'fastapi.File', 'File', ([], {}), '()\n', (5260, 5262), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((5300, 5328), 'fastapi.Depends', 'Depends', (['decode_access_token'], {}), '(decode_access_token)\n', (5307, 5328), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((7199, 7227), 'fastapi.Depends', 'Depends', (['decode_access_token'], {}), '(decode_access_token)\n', (7206, 7227), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((7933, 7939), 'fastapi.Form', 'Form', ([], {}), '()\n', (7937, 7939), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((7978, 7984), 'fastapi.Form', 'Form', ([], {}), '()\n', (7982, 7984), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((8026, 8032), 'fastapi.File', 'File', ([], {}), '()\n', (8030, 8032), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((8070, 8098), 'fastapi.Depends', 'Depends', (['decode_access_token'], {}), '(decode_access_token)\n', (8077, 8098), False, 'from fastapi import File, Form, UploadFile, APIRouter, Depends, HTTPException, Request, status\n'), ((1782, 1805), 'app.utils.json_to.json_to_model', 'json_to_model', (['ChatData'], {}), '(ChatData)\n', (1795, 1805), False, 'from app.utils.json_to import json_to_model\n')]