Spaces:
Sleeping
Sleeping
File size: 12,726 Bytes
5b2aed4 f46801a 414a697 2f4ecd3 7d3b780 48c0d8d 2f4ecd3 7d3b780 48c0d8d cfcb5f3 7d3b780 48c0d8d 7d3b780 cfcb5f3 7d3b780 48c0d8d 7d3b780 48c0d8d cfcb5f3 7d3b780 cfcb5f3 06b60e9 a1b124b c4c6959 cfcb5f3 7d3b780 06b60e9 c4c6959 06b60e9 48c0d8d 06b60e9 2f4ecd3 a1b124b 06b60e9 a1b124b 3b3aff1 48c0d8d a1b124b 2f4ecd3 a1b124b 06b60e9 a1b124b 3b3aff1 48c0d8d a1b124b 06b60e9 2f4ecd3 cfcb5f3 a1b124b 06b60e9 3b3aff1 06b60e9 3b3aff1 c4c6959 06b60e9 2f4ecd3 c4c6959 3b3aff1 c4c6959 3b3aff1 c4c6959 a1b124b cfcb5f3 a1b124b cfcb5f3 2f4ecd3 09bef47 2f4ecd3 3b3aff1 2f4ecd3 9a244e8 09bef47 06b60e9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
import os
import sys
import logging
import gradio as gr
import re
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
import asyncio
from crewai import Agent, Task, Crew
from huggingface_hub import InferenceClient
from langchain.tools import Tool
from langchain.agents import Tool as LangChainTool
import random
import json
import warnings
from langchain.deprecation import LangChainDeprecationWarning
# Suppress LangChain deprecation warnings
warnings.filterwarnings("ignore", category=LangChainDeprecationWarning)
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def get_huggingface_api_token():
token = os.getenv('HUGGINGFACEHUB_API_TOKEN')
if token:
logger.info("Hugging Face API token found in environment variables.")
return token
try:
with open('config.json', 'r') as config_file:
config = json.load(config_file)
token = config.get('HUGGINGFACEHUB_API_TOKEN')
if token:
logger.info("Hugging Face API token found in config.json file.")
return token
except FileNotFoundError:
logger.warning("Config file not found.")
except json.JSONDecodeError:
logger.error("Error reading the config file. Please check its format.")
logger.error("Hugging Face API token not found. Please set it up.")
return None
# Initialize the Hugging Face Inference Client
try:
hf_token = get_huggingface_api_token()
if not hf_token:
raise ValueError("Hugging Face API token is not set. Please set it up before running the application.")
client = InferenceClient(model="mistralai/Mistral-7B-Instruct-v0.2", token=hf_token)
logger.info("Hugging Face Inference Client initialized successfully.")
except Exception as e:
logger.error(f"Failed to initialize Hugging Face client: {e}")
sys.exit(1)
# Shared context for both agents
SHARED_CONTEXT = """You are part of a multi-agent system designed to provide respectful, empathetic, and accurate support for Zerodha, a leading Indian financial services company. Your role is crucial in ensuring all interactions uphold the highest standards of customer service while maintaining Zerodha's excellent reputation.
Key points about Zerodha:
1. India's largest discount broker, known for innovative technology and low-cost trading.
2. Flat fee structure: ₹20 per executed order for intraday and F&O trades, zero brokerage for delivery equity investments.
3. Main trading platform: Kite (web and mobile).
4. Coin platform for commission-free direct mutual fund investments.
5. Extensive educational resources through Varsity.
6. Additional tools: Sentinel (price alerts) and ChartIQ (advanced charting).
7. Console for account management and administrative tasks.
Always prioritize user safety, ethical investing practices, and transparent communication. Never provide information that could mislead users or bring disrepute to Zerodha."""
# Guardrail functions
def sanitize_input(input_text):
return re.sub(r'[<>&\']', '', input_text)
approved_topics = ['account opening', 'trading', 'fees', 'platforms', 'funds', 'regulations', 'support']
vectorizer = CountVectorizer()
classifier = MultinomialNB()
X = vectorizer.fit_transform(approved_topics)
y = np.arange(len(approved_topics))
classifier.fit(X, y)
def is_relevant_topic(query):
query_vector = vectorizer.transform([query])
prediction = classifier.predict(query_vector)
return prediction[0] in range(len(approved_topics))
def redact_sensitive_info(text):
text = re.sub(r'\b\d{10,12}\b', '[REDACTED]', text)
text = re.sub(r'[A-Z]{5}[0-9]{4}[A-Z]', '[REDACTED]', text)
return text
def check_response_content(response):
unauthorized_patterns = [
r'\b(guarantee|assured|certain)\b.*\b(returns|profit)\b',
r'\b(buy|sell)\b.*\b(specific stocks?|shares?)\b'
]
return not any(re.search(pattern, response, re.IGNORECASE) for pattern in unauthorized_patterns)
def check_confidence(response):
uncertain_phrases = ["I'm not sure", "It's possible", "I don't have enough information"]
return not any(phrase.lower() in response.lower() for phrase in uncertain_phrases)
async def generate_response(prompt):
try:
response = await client.text_generation(prompt, max_new_tokens=500, temperature=0.7)
return response
except Exception as e:
logger.error(f"Error generating response: {e}")
return "I apologize, but I'm having trouble generating a response at the moment. Please try again later."
def post_process_response(response):
response = re.sub(r'\b(stupid|dumb|idiotic|foolish)\b', 'mistaken', response, flags=re.IGNORECASE)
if not re.search(r'(Thank you|Is there anything else|Hope this helps|Let me know if you need more information)\s*$', response, re.IGNORECASE):
response += "\n\nIs there anything else I can help you with regarding Zerodha's services?"
if re.search(r'\b(invest|trade|buy|sell|market)\b', response, re.IGNORECASE):
response += "\n\nPlease note that this information is for educational purposes only and should not be considered as financial advice. Always do your own research and consider consulting with a qualified financial advisor before making investment decisions."
return response
# Define the tool for CrewAI
generate_response_tool = Tool(
name="GenerateResponse",
func=generate_response,
description="Generate a response using the Mistral model"
)
# CrewAI setup
communication_expert_crew = Agent(
role='Communication Expert',
goal='Interpret and rephrase user queries with empathy and respect',
backstory="""You are an expert in communication, specializing in understanding and rephrasing queries to ensure they are interpreted in the most positive and constructive light. Your role is crucial in setting the tone for respectful and empathetic interactions.""",
verbose=True,
allow_delegation=False,
tools=[generate_response_tool]
)
response_expert_crew = Agent(
role='Response Expert',
goal='Provide accurate, helpful, and emotionally intelligent responses to user queries',
backstory="""You are an expert in Zerodha's services and policies, with a keen ability to provide comprehensive and empathetic responses. Your role is to ensure that all user queries are addressed accurately while maintaining a respectful and supportive tone.""",
verbose=True,
allow_delegation=False,
tools=[generate_response_tool]
)
# Main function
async def zerodha_support(message, history, username):
try:
sanitized_message = sanitize_input(message)
if not is_relevant_topic(sanitized_message):
return "I'm sorry, but I can only assist with queries related to Zerodha's services and trading. Could you please ask a question about your Zerodha account, trading, or our platforms?"
sanitized_message = redact_sensitive_info(sanitized_message)
# Use crewAI for initial query rephrasing
try:
rephrase_task = Task(
description=f"Rephrase the following user query with empathy and respect: '{sanitized_message}'",
agent=communication_expert_crew
)
crew = Crew(
agents=[communication_expert_crew],
tasks=[rephrase_task],
verbose=2
)
rephrased_query = await crew.kickoff()
except Exception as e:
logger.error(f"Error in CrewAI rephrasing: {e}")
rephrased_query = sanitized_message # Fallback to original message if rephrasing fails
# Generate response using Response Expert
try:
response_task = Task(
description=f"Provide an accurate and helpful response to the user query: '{rephrased_query}'",
agent=response_expert_crew
)
crew = Crew(
agents=[response_expert_crew],
tasks=[response_task],
verbose=2
)
response = await crew.kickoff()
except Exception as e:
logger.error(f"Error in CrewAI response generation: {e}")
response = "I apologize, but I'm having trouble generating a response at the moment. Please try again later."
if not check_response_content(response):
response += "\n\nPlease note that I cannot provide specific investment advice or guarantee returns. For personalized guidance, please consult with a qualified financial advisor."
if not check_confidence(response):
return "I apologize, but I'm not confident in providing an accurate answer to this query. For the most up-to-date and accurate information, please contact Zerodha's customer support directly."
final_response = post_process_response(response)
return final_response
except Exception as e:
logger.error(f"Error in zerodha_support: {e}")
return "I apologize, but an error occurred while processing your request. Please try again later."
# Custom CSS for better styling
custom_css = """
.container {
max-width: 800px;
margin: auto;
padding: 20px;
}
.title {
text-align: center;
color: #387EF5;
font-size: 32px;
margin-bottom: 20px;
}
.description {
text-align: center;
color: #555;
margin-bottom: 30px;
}
.chatbot {
border: 1px solid #ddd;
border-radius: 10px;
overflow: hidden;
}
.user-info {
background-color: #f0f0f0;
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
}
"""
# Placeholder function for user authentication (you'd implement this with your backend)
def authenticate(username, password):
# This is a mock authentication. In a real scenario, you'd verify against a database.
return username == "demo" and password == "password"
# Function to generate a random support ticket number
def generate_ticket_number():
return f"ZRD-{random.randint(100000, 999999)}"
# Gradio interface setup
with gr.Blocks(css=custom_css) as demo:
gr.HTML("<div class='title'>Zerodha Support Assistant</div>")
gr.HTML("<div class='description'>Ask questions about Zerodha's services, trading, account management, and more.</div>")
with gr.Tab("Login"):
username_input = gr.Textbox(label="Username")
password_input = gr.Textbox(label="Password", type="password")
login_button = gr.Button("Login")
login_message = gr.Textbox(label="Login Status", interactive=False)
with gr.Tab("Support Chat"):
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=400)
message_input = gr.Textbox(label="Your Message", placeholder="Type your question here...")
submit_button = gr.Button("Send")
with gr.Column(scale=1):
gr.HTML("<div class='user-info'>")
user_display = gr.Textbox(label="Logged in as", interactive=False)
ticket_number = gr.Textbox(label="Support Ticket", value=generate_ticket_number(), interactive=False)
gr.HTML("</div>")
gr.HTML("<h4>Quick Links</h4>")
gr.HTML("<ul><li><a href='https://zerodha.com/varsity/' target='_blank'>Zerodha Varsity</a></li><li><a href='https://console.zerodha.com/' target='_blank'>Zerodha Console</a></li></ul>")
# Example queries
gr.Examples(
examples=[
"How do I open a Zerodha account?",
"What are the brokerage charges for intraday trading?",
"How can I withdraw funds from my Zerodha account?",
"What is the margin requirement for F&O trading?",
"How do I use the Kite mobile app?",
],
inputs=message_input,
)
# Login logic
def login(username, password):
if authenticate(username, password):
return "Login successful!", gr.Tabs.update(selected="Support Chat"), username
else:
return "Login failed. Please try again.", gr.Tabs.update(selected="Login"), ""
login_button.click(login, inputs=[username_input, password_input], outputs=[login_message, demo.tabs, user_display])
# Chat logic
submit_button.click(zerodha_support, inputs=[message_input, chatbot, user_display], outputs=chatbot)
message_input.submit(zerodha_support, inputs=[message_input, chatbot, user_display], outputs=chatbot)
if __name__ == "__main__":
demo.launch() |