Viewing File: /home/ubuntu/codegamaai-test/efisupport_bot/main.py

from dotenv import load_dotenv

import openai
import sys, os
import logging
from llama_index import (
    SimpleDirectoryReader,
    LLMPredictor,
    GPTVectorStoreIndex,
    load_index_from_storage,
    set_global_service_context,
)
from llama_index.storage.storage_context import StorageContext
from llama_index.prompts import Prompt
from llama_index.indices.service_context import ServiceContext
from langchain.chat_models import ChatOpenAI
from llama_index.memory import ChatMemoryBuffer
from llama_index.llms import OpenAI
from src.constants import *
from src.chats import *
from src.utils import *
from llama_index.tools.tool_spec.base import BaseToolSpec
from llama_index.agent import OpenAIAgent
import qdrant_client
from llama_index.vector_stores.qdrant import QdrantVectorStore

load_dotenv()

openai.api_key = os.getenv("OPENAI_API_KEY")

#llm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0.2, model_name="gpt-3.5-turbo", max_tokens=1500))
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))

service_context = ServiceContext.from_defaults(llm=OpenAI(model_name="gpt-4", temperature=0.2, max_tokens=1500))

# Create dir_path list that contains all the directories in the DOCUMENTS_DIR
dir_path = []
for root, dirs, files in os.walk(os.environ['DOCUMENTS_DIR']):
    for name in dirs:
        dir_path.append(os.path.join(root, name))
    
dir_path_inr = os.path.join(os.environ['DOCUMENTS_DIR'], "efipay_doc")
dir_path_international = os.path.join(os.environ['DOCUMENTS_DIR'], "international_doc")

class Llama:
    indexes = {'INR': None, 'International': None}

    @staticmethod
    def init():
        #Llama.index = Llama.load_index(dir_path)
        Llama.indexes['efi_inr'] = Llama.load_index(dir_path_inr, "efi_inr_doc")
        Llama.indexes['efi_international'] = Llama.load_index(dir_path_international, "efi_international_doc")


    @staticmethod
    def load_index(dir_path, collection_name):
        documents = SimpleDirectoryReader(dir_path, filename_as_id=True).load_data() # removed the looped 
        print(f"Loaded documents with{len(documents)}pages for collection{collection_name}")
        client = qdrant_client.QdrantClient(
            location="http://54.39.104.93:6333"
        )
        vector_store = QdrantVectorStore(client=client, collection_name=collection_name)
        storage_context = StorageContext.from_defaults(vector_store=vector_store)
        try:
            index = GPTVectorStoreIndex.from_documents(documents, storage_context=storage_context)
            # storage_context = StorageContext.from_defaults(persist_dir=os.environ['STORAGE_DIR'])
            index = load_index_from_storage(storage_context)
            logging.info("Index loaded from storage.")
        except FileNotFoundError:
            logging.info("Index not found. Creating a new one...")
            index = GPTVectorStoreIndex.from_documents(documents)
            index.storage_context.persist()
            logging.info("New index created and persisted to storage.")

        refreshed_docs = index.refresh_ref_docs(documents,
                                                update_kwargs={"delete_kwargs": {'delete_from_docstore': True}})
        print(refreshed_docs)
        print('Number of newly inserted/refreshed docs: ', sum(refreshed_docs))

        index.storage_context.persist()
        logging.info("Index refreshed and persisted to storage.")

        return index

# Load the index when the server starts
Llama.init()

user_sessions = {}

def is_customer_support_related(query):
    try:
        response = openai.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "Your role is to determine if the incoming user query is directly related to specific customer support issues that involve sensitive information like order numbers, transaction numbers, or requires intervention due to technical problems with services. Answer 'yes' for queries needing direct intervention and 'no' for informational queries or those that can be answered based on general knowledge."},
                {"role": "user", "content": query},
                {"role": "assistant",
                 "content": """Based on the query and without revealing any sensitive information or implying the existence of specific documents, decide if it pertains directly to customer support issues such as troubleshooting requests, specific help with using features, or involves sensitive information like order or transaction numbers. Answer 'yes' for direct support intervention and 'no' for general information or knowledge base queries. Directly answer 'yes' or 'no'."
                 """
                 }
            ],
            max_tokens=10
        )
        print(response)
        assistant_response = response.choices[0].message.content.strip().lower()
        print("Assistant response:", assistant_response)
        return "yes" in assistant_response
    except Exception as e:
        print(f"Error in OpenAI call: {e}")
        return False

def data_querying(input_text, group_id, user_uid, type_doc):
    user_id = group_id + "_" + user_uid
    global user_sessions
    if user_id not in user_sessions:
        user_sessions[user_id] = {"interaction_count": 0, "conversation_history": [], "awaiting_tax_details": False, "detail_prompted": False}

    user_session = user_sessions[user_id]
    user_session["interaction_count"] += 1
    print(f"Debug: User {user_id} interaction count: {user_session['interaction_count']}")
    user_session["conversation_history"].append(input_text)
    selected_index = Llama.indexes.get(type_doc)
    if selected_index is None:
        return {"response": "Invalid document type specified."}
    creation_queries = [
        "who made you",
    	"who created you",
    	"who is your creator",
    	"what company made you",
    	"are you open source",
    	"who developed you",
    	"who is responsible for your creation",
    	"which organization created you",
    	"who owns you",
    	"where do you come from",
    	"who built you",
    	"what's your origin",
    	"who programmed you",
    	"who is behind you",
    	"who is your developer",
    	"what entity created you",
    	"are you created by a company",
    	"who is your maker",
    	"what team developed you",
    	"which company are you a product of",
    	"are you the work of a specific person",
    	"who engineered you",
        "what model you use",
        "what model are you using",
        "what is your model architecture",
    	"what's the source of your intelligence",
    	"who gave you life",
    	"who is your parent company",
    ]
    name_queries = [
    	"what is your name",
    	"who are you",
    	"do you have a name",
    	"what should I call you",
    	"what's your name",
    	"tell me your name",
    	"your name please",
    	"who am I speaking with",
    	"what do they call you",
    	"are you named",
    	"do you go by a name",
    	"what name do you go by",
    	"may I know your name",
    	"who is this",
    	"what are you called",
    	"have you been given a name",
    	"what nickname do you have",
    	"what do people call you",
    	"how should I address you",
    ]
    if any(creation_query in input_text.lower() for creation_query in creation_queries):
        hardcoded_response = "I was developed by First Technology, leveraging state-of-the-art AI models to assist you. If you have any more questions or need help, feel free to ask!"
        return {"response": hardcoded_response, "reply_message": "no"}

    elif any(name_query in input_text.lower() for name_query in name_queries):
        hardcoded_response = "My name is EFIMarkets, your expert customer support assistant specialized in EFI Pay queries. How can I assist you today?"
        return {"response": hardcoded_response, "reply_message": "no"}

    create_json(group_id, user_uid)
    # Get existing memory from user
    history = read_json(group_id, user_uid)
    chat_history = convert_chat_message(history)
    if history:
        memory = ChatMemoryBuffer.from_defaults(token_limit=3900, chat_history=chat_history)
    else:
        memory = ChatMemoryBuffer.from_defaults(token_limit=3900)
    
    if is_customer_support_related(input_text):
        # response_message = "Hi, we will get back to you as soon as possible to try to resolve your query."
        response_message ="Thank you for reaching out to us! Your query is important to us, and we are committed to "\
        "providing you with the assistance you need. A member of our support team will review your "\
        "request and get back to you as soon as possible with a resolution. In the meantime, "\
        "if you have any additional information or questions, please feel free to share them. Your "\
        "patience and understanding are greatly appreciated."  
        user_sessions[user_id] = user_session  
        reply_message = "no"
        response_message = {"response": response_message, "reply_message": reply_message}
        return response_message
    else:
        text_qa_template_str = (
            "Context information is below.\n"
            "---------------------\n"
            "{context_str}\n"
            "---------------------\n"
            "Using both the context information and also using your own knowledge, "
            "answer the question: {query_str}\n"
            "If the context isn't helpful, Please respond with: I don't understand please try to rephrase your question\n"
        )
        refine_template_str = (
            "The original question is as follows: {query_str}\n"
            "We have provided an existing answer: {existing_answer}\n"
            "We have the opportunity to refine the existing answer "
            "(only if needed) with some more context below.\n"
            "------------\n"
            "{context_msg}\n"
            "------------\n"
            "Using both the new context and your own knowledge, update or repeat the existing answer.\n"
        )
        # memory = ChatMemoryBuffer.from_defaults(token_limit=1500)
        refine_template = Prompt(refine_template_str)
        text_qa_template = Prompt(text_qa_template_str)

        system_prompt_inr = """You are an expert customer support assistant specialized in EFI API queries. Your primary goal is to provide clear, accurate, and directly relevant assistance, focusing exclusively on the question asked without revealing any sensitive information, including the names or locations of documents, files, or any internal resources without referring to or implying the existence of any documents, files, or internal resources. Your responses should offer guidance and information based solely on the query provided, without alluding to any specific documentation or resources.
        Ensure your responses:
        - Are detailed and directly address the user's query.
        - Try to keep the response in simplified english which helps the user in better understanding   
        - You will only entertain queries related to EFI API and its usage and apart anything else just say this is beyond my context.
        - Include a reference link for further reading, where relevant the reference link is 'https://app.theneo.io/015b566c-c617-4357-a975-5968e062d3e1/efipay-api-documentation-payin-payout'
        - Maintain confidentiality by not disclosing any sensitive or specific information about internal processes or documents.
        - Encourage the user to follow best practices and refer to publicly available resources or the official documentation, without pointing to specific files.
        - Keep a professional tone, aiming to resolve queries efficiently and effectively, with a focus on safety and privacy."""

        system_prompt_international ="""You are an expert customer support assistant specialized in EFI API queries. Your primary goal is to provide clear, accurate, and directly relevant assistance, focusing exclusively on the question asked without revealing any sensitive information, including the names or locations of documents, files, or any internal resources without referring to or implying the existence of any documents, files, or internal resources. Your responses should offer guidance and information based solely on the query provided, without alluding to any specific documentation or resources.
        Ensure your responses:
        - Are detailed and directly address the user's query.
        - Try to keep the response in simplified english which helps the user in better understanding   
        - You will only entertain queries related to EFI API and its usage and apart anything else just say this is beyond my context.
        - Include a reference link for further reading, where relevant the reference link is 'https://devcenter.efipay.io/website/'
        - Maintain confidentiality by not disclosing any sensitive or specific information about internal processes or documents.
        - Encourage the user to follow best practices and refer to publicly available resources or the official documentation, without pointing to specific files.
        - Keep a professional tone, aiming to resolve queries efficiently and effectively, with a focus on safety and privacy."""

        if type_doc == "INR":
            system_prompt = system_prompt_inr
        elif type_doc == "International":
            system_prompt = system_prompt_international
        else:
            return {"response": "Invalid document type specified. Please choose either 'international' or 'INR'.", "reply_message": "yes"}


        response = selected_index.as_chat_engine(
            text_qa_template=text_qa_template,
            refine_template=refine_template,
            chat_mode="context",
            memory=memory,
            system_prompt=system_prompt,
        ).chat(input_text)

        user_sessions[user_id] = user_session
        reply_message = "yes"
    # Update User Memory
    save_response(response.response, group_id, user_uid, input_text)

    response_message = {"response": response.response, "reply_message": reply_message}
    return response_message


def answer_question(question, group_id, user_uid, type_doc):
    user_uid = "static_user_uid"
    try:
        # response = data_querying(question)
        response = data_querying(question, group_id, user_uid, type_doc)

        return response
    except Exception as e:
        return str(e)
Back to Directory File Manager