main.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import json
  2. import os
  3. import sys
  4. import logging
  5. from datetime import datetime, timedelta
  6. from io import BytesIO
  7. from django.utils.text import slugify
  8. import openai
  9. from llama_index import VectorStoreIndex, Document, StorageContext, load_index_from_storage
  10. from llama_index.prompts import Prompt
  11. from langchain.prompts.chat import (ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate)
  12. from adm.constants import CTS
  13. from adm.storage import MediaStorage
  14. from adm.services import ParameterService
  15. logger = logging.getLogger('dsp')
  16. class Chatbot():
  17. def __init__(self) -> None:
  18. objParameter = ParameterService()
  19. openai.api_key = objParameter.getParameterByKey("OPENAI_API_KEY").value
  20. self.storage_path = CTS.CHATBOT_STORAGE_PATH
  21. media_storage = MediaStorage(self.storage_path)
  22. self.media_storage = media_storage
  23. # load index
  24. self.ai_storage_context = None
  25. self.ai_index = None
  26. try:
  27. self.ai_storage_context = StorageContext.from_defaults(persist_dir='./storage')
  28. self.ai_index = load_index_from_storage(self.ai_storage_context)
  29. except BaseException as error:
  30. # exc_type, exc_obj, exc_tb = sys.exc_info()
  31. # fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
  32. # strErro = "ERRO: %s | %s | %s | %s" % (error, exc_type, fname, exc_tb.tb_lineno)
  33. logger.info('Chatbot() init: '+str(error))
  34. pass
  35. pass
  36. def train (self, chat=None):
  37. status = 400
  38. data = None
  39. docs = []
  40. if chat:
  41. # use chat to build up on existing store
  42. # save chat as doc in storage
  43. if not 'id' in chat:
  44. question = chat['chat'][0].split(':')[-1]
  45. chat['id'] = slugify(question)
  46. if not 'type' in chat:
  47. chat['type'] = 'instructions'
  48. if not 'category' in chat:
  49. chat['category'] = 'uncategorized'
  50. blob_name = chat['id']
  51. blob_ext = '.json'
  52. file_name = blob_name + blob_ext
  53. blob_dir = 'instructions/'
  54. blob_path = blob_dir + file_name
  55. text = json.dumps(chat, ensure_ascii=False)
  56. path_bucket = os.path.join(self.media_storage.location, '/', blob_path)
  57. self.media_storage.save(path_bucket, BytesIO(text.encode("utf-8")))
  58. docs.append({
  59. 'id_': blob_name,
  60. 'text': text,
  61. 'metadata': {
  62. 'filename': file_name,
  63. 'category': chat['category']
  64. }
  65. })
  66. else:
  67. blob_dir = 'docs/'
  68. blobs = self.media_storage.list(self.storage_path + '/' + blob_dir)
  69. for blob in blobs:
  70. text = blob.download_as_bytes().decode('utf-8')
  71. if len(text)>0:
  72. obj = json.loads(text) if text.startswith('{') else text
  73. if not 'category' in obj:
  74. obj['category'] = 'uncategorized'
  75. file_name = blob.name.split('/')[-1]
  76. docs.append({
  77. 'id_': obj['id'],
  78. 'text': text,
  79. 'metadata': {
  80. 'filename': file_name,
  81. 'category': obj['category']
  82. }
  83. })
  84. # parse documents
  85. ai_documents = []
  86. for doc in docs:
  87. ai_documents.append(Document(**doc))
  88. # create/add to index
  89. if self.ai_index is None:
  90. self.ai_index = VectorStoreIndex.from_documents(ai_documents, show_progress=True)
  91. else:
  92. for ai_doc in ai_documents:
  93. self.ai_index.insert(ai_doc)
  94. # save index to disk
  95. if ai_documents:
  96. self.ai_index.storage_context.persist()
  97. status = 200
  98. return status, data
  99. def chat (self, question=None):
  100. status = 400
  101. pre_prompt = [
  102. SystemMessagePromptTemplate.from_template(
  103. "Act as an IT Support Level 1 for the company Mobees. Your name is Mel. You must answer the company's Drivers questions in Brazilian Portuguese, as they only speak this language. Mobees Drivers access support through a chatbot interface in the company's app, which is the only channel for support. If you're not sure how to answer, respond with only the following `<assignee:support>` (this will let our system know it should forward the issue to our support team and take it from there). "
  104. ),
  105. HumanMessagePromptTemplate.from_template(
  106. "Context information is below.\n"
  107. "---------------------\n"
  108. "{context_str}\n"
  109. "---------------------\n"
  110. "Given the context information and prior knowledge, "
  111. "answer the question: {query_str}\n"
  112. ),
  113. ]
  114. prompt_template = ChatPromptTemplate.from_messages(pre_prompt)
  115. text_qa_template = Prompt.from_langchain_prompt(prompt_template)
  116. answer = self.ai_index.as_query_engine(
  117. text_qa_template=text_qa_template
  118. ).query(question)
  119. print(answer)
  120. status = 200
  121. data = { 'answer': answer.response }
  122. return status, data
  123. # chat_engine = self.ai_index.as_chat_engine(
  124. # verbose=True
  125. # )
  126. # chat_engine.chat_repl()
  127. instance = Chatbot()