import os import sqlite3 import streamlit as st from werkzeug.security import generate_password_hash, check_password_hash from langchain_groq import ChatGroq from langchain_huggingface import HuggingFaceEmbeddings from langchain_community.document_loaders.csv_loader import CSVLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_core.vectorstores import InMemoryVectorStore from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools import Tool from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.messages import HumanMessage, AIMessage # --- Database Setup --- @st.cache_resource def init_db(): conn = sqlite3.connect('users.db', check_same_thread=False) c = conn.cursor() # Users table c.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, previous_chat_history TEXT, previous_products_bought TEXT)''') # Company settings table c.execute('''CREATE TABLE IF NOT EXISTS company_settings (id INTEGER PRIMARY KEY AUTOINCREMENT, company_name TEXT, company_business TEXT, agent_name TEXT, key_features TEXT)''') # Insert default settings if empty c.execute('SELECT COUNT(*) FROM company_settings') if c.fetchone()[0] == 0: c.execute('''INSERT INTO company_settings (company_name, company_business, agent_name, key_features) VALUES (?, ?, ?, ?)''', ("TechElectronics", "Consumer Electronics Retailer", "Alex", "Cutting-edge technology, Competitive pricing, Excellent customer service")) conn.commit() return conn conn = init_db() class User: # ... (existing User class remains unchanged) ... # --- AI Agent Setup --- os.environ["GROQ_API_KEY"] = st.secrets["GROQ_API_KEY"] llm = ChatGroq( temperature=0.1, model_name="llama3-8b-8192", api_key=st.secrets["GROQ_API_KEY"], ) embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") @st.cache_resource def load_data(data_version): loader = CSVLoader(file_path="electronics_products.csv") docs = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20) splits = text_splitter.split_documents(docs) vectorstore = InMemoryVectorStore.from_documents(documents=splits, embedding=embeddings) return vectorstore.as_retriever() # Initialize with default data version retriever = load_data(0) def get_company_settings(): conn = sqlite3.connect('users.db') c = conn.cursor() c.execute('SELECT * FROM company_settings WHERE id=1') settings = c.fetchone() conn.close() return { 'company_name': settings[1], 'company_business': settings[2], 'agent_name': settings[3], 'key_features': settings[4] } # --- Admin Dashboard --- def admin_dashboard(): st.header("Admin Dashboard") # Company Settings Form with st.expander("Company Settings"): settings = get_company_settings() with st.form("company_settings"): new_name = st.text_input("Company Name", value=settings['company_name']) new_business = st.text_input("Business", value=settings['company_business']) new_agent = st.text_input("Agent Name", value=settings['agent_name']) new_features = st.text_area("Key Features", value=settings['key_features']) if st.form_submit_button("Save Settings"): conn = sqlite3.connect('users.db') c = conn.cursor() c.execute('''UPDATE company_settings SET company_name=?, company_business=?, agent_name=?, key_features=? WHERE id=1''', (new_name, new_business, new_agent, new_features)) conn.commit() conn.close() st.success("Settings updated!") # Product Management with st.expander("Product Management"): st.subheader("Update Product Catalog") uploaded_file = st.file_uploader("Upload new CSV", type="csv") if uploaded_file is not None: # Save the uploaded file with open("electronics_products.csv", "wb") as f: f.write(uploaded_file.getbuffer()) # Update data version to refresh cache st.session_state.data_version = st.session_state.get("data_version", 0) + 1 st.success("Product catalog updated!") if st.button("Back to Main"): st.session_state.show_admin = False st.rerun() # --- Streamlit UI --- def main(): st.set_page_config(page_title="AI Sales Assistant", layout="wide") # Initialize session states if 'user' not in st.session_state: st.session_state.user = None st.session_state.chat_history = [] if 'show_admin' not in st.session_state: st.session_state.show_admin = False if 'data_version' not in st.session_state: st.session_state.data_version = 0 # Check admin status first if st.session_state.show_admin: admin_dashboard() return # Authentication if not st.session_state.user: st.header("Login/Register") tab1, tab2, tab3 = st.tabs(["Login", "Register", "Admin"]) with tab1: with st.form("Login"): username = st.text_input("Username") password = st.text_input("Password", type="password") if st.form_submit_button("Login"): user = User.get_by_username(username) if user and check_password_hash(user.password, password): st.session_state.user = user st.session_state.chat_history = user.chat_history st.rerun() else: st.error("Invalid credentials") with tab2: with st.form("Register"): new_user = st.text_input("New Username") new_pass = st.text_input("New Password", type="password") if st.form_submit_button("Register"): if User.get_by_username(new_user): st.error("Username already exists") else: user = User.create(new_user, new_pass) st.session_state.user = user st.session_state.chat_history = [] st.rerun() with tab3: with st.form("Admin Login"): admin_key = st.text_input("Admin Key", type="password") if st.form_submit_button("Enter Admin Dashboard"): if admin_key == st.secrets.get("ADMIN_KEY", "default_admin_key"): st.session_state.show_admin = True st.rerun() else: st.error("Invalid Admin Key") else: # Main Chat Interface settings = get_company_settings() st.title(f"{settings['company_name']} AI Sales Assistant 🤖") st.header(f"Welcome to {settings['company_name']}, {st.session_state.user.username} 😊!") # Reload data with current version global retriever retriever = load_data(st.session_state.data_version) # Dynamic system prompt system_prompt = f""" You are {settings['agent_name']}, the AI Sales Assistant for {settings['company_name']} ({settings['company_business']}). Company Profile: - Company Name: {settings['company_name']} - Business: {settings['company_business']} - Key Features: {settings['key_features']} Product Availability: - Only recommend and discuss products listed in the provided document. - Do not suggest unavailable or out-of-stock products. - Always verify product availability before making recommendations. Conversation Flow: 1. Introduction 2. Qualification 3. Understanding Needs 4. Needs Analysis 5. Solution Presentation (Only recommend available products) 6. Confirmation 7. If the prospect agrees to purchase, thank them and provide the payment link: https://www.example.com/payment Guidelines: - Maintain natural, professional conversations - Follow company policies - Be helpful and polite - Always cross-check product recommendations with the available inventory in the CSV document """ # Agent setup with dynamic prompt prompt = ChatPromptTemplate.from_messages([ ("system", system_prompt), MessagesPlaceholder(variable_name="chat_history"), ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad") ]) tool = Tool( name="retriever", func=lambda q: retriever.get_relevant_documents(q), description="Useful for retrieving product information" ) agent = create_tool_calling_agent(llm, [tool], prompt) agent_executor = AgentExecutor(agent=agent, tools=[tool], verbose=True) # Chat handling if prompt_input := st.chat_input("Type your message here..."): # Add user message with st.chat_message("user"): st.write(prompt_input) # Get AI response with st.chat_message("assistant"): response = agent_executor.invoke({ "input": prompt_input, "chat_history": [HumanMessage(content=msg["content"]) if msg["type"] == "human" else AIMessage(content=msg["content"]) for msg in st.session_state.chat_history] })["output"] st.write(response) if "https://www.example.com/payment" in response: st.session_state.user.update_products_bought(["Latest Product"]) st.success("Product added to your purchases!") # Update chat history new_messages = [ {"type": "human", "content": prompt_input}, {"type": "ai", "content": response} ] st.session_state.user.update_chat_history(new_messages) st.session_state.chat_history += new_messages if __name__ == "__main__": main()