main.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. media_storage = MediaStorage()
  21. self.media_storage = media_storage
  22. self.storage_path = CTS.CHATBOT_STORAGE_PATH
  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. docs = []
  38. if chat:
  39. # use chat to build up on existing store
  40. # save chat as doc in storage
  41. if not 'id' in chat:
  42. question = chat['chat'][0].split(':')[-1]
  43. chat['id'] = slugify(question)
  44. if not 'type' in chat:
  45. chat['type'] = 'instructions'
  46. if not 'category' in chat:
  47. chat['category'] = 'uncategorized'
  48. blob_name = chat['id']
  49. blob_ext = '.json'
  50. file_name = blob_name + blob_ext
  51. blob_dir = 'instructions/'
  52. blob_path = self.storage_path + blob_dir + file_name
  53. text = json.dumps(chat, ensure_ascii=False)
  54. path_bucket = os.path.join(self.media_storage.location, '/', blob_path)
  55. self.media_storage.save(path_bucket, BytesIO(text.encode("utf-8")))
  56. docs.append({
  57. 'id_': blob_name,
  58. 'text': text,
  59. 'metadata': {
  60. 'filename': file_name,
  61. 'category': chat['category']
  62. }
  63. })
  64. else:
  65. blob_dir = 'docs/'
  66. blobs = self.media_storage.list(self.storage_path + blob_dir)
  67. for blob in blobs:
  68. text = blob.download_as_bytes().decode('utf-8')
  69. if len(text)>0:
  70. obj = json.loads(text) if text.startswith('{') else text
  71. if not 'category' in obj:
  72. obj['category'] = 'uncategorized'
  73. file_name = blob.name.split('/')[-1]
  74. docs.append({
  75. 'id_': obj['id'],
  76. 'text': text,
  77. 'metadata': {
  78. 'filename': file_name,
  79. 'category': obj['category']
  80. }
  81. })
  82. # parse documents
  83. ai_documents = []
  84. for doc in docs:
  85. ai_documents.append(Document(**doc))
  86. # create/add to index
  87. if self.ai_index is None:
  88. self.ai_index = VectorStoreIndex.from_documents(ai_documents, show_progress=True)
  89. else:
  90. for ai_doc in ai_documents:
  91. self.ai_index.insert(ai_doc)
  92. # save index to disk
  93. self.ai_index.storage_context.persist()
  94. def chat (self, question=None):
  95. status = 400
  96. pre_prompt = [
  97. SystemMessagePromptTemplate.from_template(
  98. "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). "
  99. ),
  100. HumanMessagePromptTemplate.from_template(
  101. "Context information is below.\n"
  102. "---------------------\n"
  103. "{context_str}\n"
  104. "---------------------\n"
  105. "Given the context information and prior knowledge, "
  106. "answer the question: {query_str}\n"
  107. ),
  108. ]
  109. prompt_template = ChatPromptTemplate.from_messages(pre_prompt)
  110. text_qa_template = Prompt.from_langchain_prompt(prompt_template)
  111. answer = self.ai_index.as_query_engine(
  112. text_qa_template=text_qa_template
  113. ).query(question)
  114. print(answer)
  115. status = 200
  116. data = { 'answer': answer.response }
  117. return status, data
  118. # chat_engine = self.ai_index.as_chat_engine(
  119. # verbose=True
  120. # )
  121. # chat_engine.chat_repl()
  122. instance = Chatbot()