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 src.calculate import *
from llama_index.tools.tool_spec.base import BaseToolSpec
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))
service_context = ServiceContext.from_defaults(llm=OpenAI(model_name="gpt-4", temperature=0.2, max_tokens=1500 ))
directory_path = os.path.join(os.environ['DOCUMENTS_DIR'], "India")
class Llama:
index = None
@staticmethod
def init():
Llama.index = Llama.load_index(directory_path)
@staticmethod
def load_index(directory_path):
documents = SimpleDirectoryReader(directory_path, filename_as_id=True).load_data()
print(f"Loaded documents with {len(documents)} pages")
try:
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_tax_related(query):
try:
response = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": query},
{"role": "assistant", "content": "Is the above query about tax calculation? Return 'yes' if it is, otherwise return 'no'."}
]
)
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, user_id):
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)
if is_tax_related(input_text):
user_session["detail_prompted"] = True
user_session["awaiting_tax_details"] = True
if user_session["awaiting_tax_details"] and user_session["interaction_count"] > 1:
user_session["awaiting_tax_details"] = False
response_message = """To further assist you with tax calculation, please provide the following details:
1. **Basic Salary**: Your basic salary amount for the year.
2. **Dearness Allowances**: Total dearness allowances received throughout the year.
3. **HRA Received**: The HRA (House Rent Allowance) received from your company for the year.
4. **Special Allowance**: Any special allowance received throughout the year.
5. **PF Deduction**: Total Provident Fund deduction for the year.
6. **Deduction under 80C**: Investments or expenses qualifying for 80C deductions (like ELSS, PPF, etc.) up to a maximum limit of 1.5 lakhs.
7. **Deduction under 80D**: Medical insurance premium paid, up to a maximum limit of 25K.
8. **NPS Deduction**: Contributions to the National Pension Scheme (NPS), up to a maximum limit of 2 lakhs.
Providing these details will help us in accurately calculating your tax liability."""
return response_message
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 knowledege, update or repeat the existing answer.\n"
)
create_json(user_id)
# Get existing memory from user
history = read_json(user_id)
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)
refine_template = Prompt(refine_template_str)
text_qa_template = Prompt(text_qa_template_str)
system_prompt = """You are a Tax Helper Assistant, specialized in addressing and assisting with tax-related inquiries for the fiscal year 2023-24, including tax calculation guidance.
For general queries, provide clear explanations on tax matters and tax-saving strategies.
Respond accordingly don't deviate from context, If you not able respond Please respond with: I don't understand please try to rephrase your question
If User ask to proivde tax calculation for "50 Lakh" ("5000000") or above please respond with: `Please contact us directly at support@haive.tech for more detailed assistance. We can't provide tax calculation for 50 Lakh or above.`
"""
response = Llama.index.as_chat_engine(text_qa_template=text_qa_template, refine_template=refine_template,
chat_mode="context", memory=memory, system_promt=system_prompt,
).chat(input_text)
user_sessions[user_id] = user_session
# Update User Memory
save_response(response.response, user_id, input_text)
return response.response
def answer_question(question, user_id):
user_id = "static_user_id"
try:
# response = data_querying(question)
response = data_querying(question, user_id)
return response
except Exception as e:
return str(e)