code: from typing import List
  
  from fastapi.responses import StreamingResponse
  
  from app.utils.json import json_to_model
  from app.utils.index import get_index
  from fastapi import APIRouter, Depends, HTTPException, Request, status
  from llama_index import VectorStoreIndex
  from llama_index.llms.base import MessageRole, ChatMessage
  from pydantic import BaseModel
  
  chat_router = r = APIRouter()
  
  
  class _Message(BaseModel):
      role: MessageRole
      content: str
  
  
  class _ChatData(BaseModel):
      messages: List[_Message]
  
  
  @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: _ChatData = Depends(json_to_model(_ChatData)),
      index: VectorStoreIndex = Depends(get_index),
  ):
      # 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
      chat_engine = index.as_chat_engine(
          chat_mode="context",
          sparse_top_k=12,
          vector_store_query_mode="hybrid",
          similarity_top_k=2,
          system_prompt=(
           "You are a chatbot, able to have normal interactions, as well as talk"
           " about an Grade 3 Unit Tests, Holidays and Dairy of the School."
          ),
          verbose=False,
      )
      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")
apis: llama_index.llms.base.ChatMessage
extract_api: [((374, 385), 'fastapi.APIRouter', 'APIRouter', ([], {}), '()\n', (383, 385), False, 'from fastapi import APIRouter, Depends, HTTPException, Request, status\n'), ((798, 816), 'fastapi.Depends', 'Depends', (['get_index'], {}), '(get_index)\n', (805, 816), False, 'from fastapi import APIRouter, Depends, HTTPException, Request, status\n'), ((741, 765), 'app.utils.json.json_to_model', 'json_to_model', (['_ChatData'], {}), '(_ChatData)\n', (754, 765), False, 'from app.utils.json import json_to_model\n'), ((914, 1004), '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", (927, 1004), False, 'from fastapi import APIRouter, Depends, HTTPException, Request, status\n'), ((1132, 1232), '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", (1145, 1232), False, 'from fastapi import APIRouter, Depends, HTTPException, Request, status\n'), ((1355, 1398), 'llama_index.llms.base.ChatMessage', 'ChatMessage', ([], {'role': 'm.role', 'content': 'm.content'}), '(role=m.role, content=m.content)\n', (1366, 1398), False, 'from llama_index.llms.base import MessageRole, ChatMessage\n')]