Team Ai
Apppublic

cssundara/testOct15

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py295 linesDownload Raw Back to root
1import streamlit as st2import sqlite33import pandas as pd4import os5import json6from langchain.chat_models import ChatOpenAI7from langchain.agents import Tool, initialize_agent8from langchain.agents.agent_types import AgentType9from langchain_community.utilities.sql_database import SQLDatabase10from langchain_community.agent_toolkits import create_sql_agent11from langchain.schema import HumanMessage12from datetime import date13today = date.today().strftime("%d %B") # Get the current date in "DD Month" format14 15 16# Load the JSON file and extract values17file_name = 'config.json'18with open(file_name, 'r') as file:19    config = json.load(file)20    API_KEY = config.get("API_KEY") # Loading the API Key21    OPENAI_API_BASE = config.get("OPENAI_API_BASE") # Loading the API Base Url22 23# Set API keys and base24os.environ['OPENAI_API_KEY'] = API_KEY25os.environ['OPENAI_BASE_URL'] = OPENAI_API_BASE26 27llm = ChatOpenAI(model_name="gpt-4")28 29connection = sqlite3.connect("kartify.db", check_same_thread=False)30kartify_db = SQLDatabase.from_uri("sqlite:///kartify.db")31sqlite_agent = create_sql_agent(llm, db=kartify_db, agent_type="openai-tools", verbose=False)32 33def policy_tool_func(input: str) -> str:34    prompt = f"""Only respond about return or replacement if the user has explicitly asked about it in their query.35Use the following context from order, shipment, and product policy data:36{input}37Your task (only if return or replacement is mentioned):381. Check eligibility based on `actual_delivery` and product policy:39   - If `return_days_allowed` is 0, clearly state the product is not eligible for return.40   - If within window, mention last date allowed for return and replacement.41   - If the window has passed, say so.422. Mention return conditions (e.g., Sealed only).433. If `actual_delivery` is null, return/replacement is not yet applicable.444. If any required info is missing, say so politely that i am connecting to human support.45If the query does **not** mention return or replacement, do **not** include any information about it in your response.46Respond clearly and briefly no system or SQL steps."""47    return llm([HumanMessage(content=prompt)]).content.strip()48 49def answer_generation_tool(input: str) -> str:50    prompt = f"""You are a polite and formal customer assistant replying to a user query to customer about return, replacement, delivery, cancellation, or address change.51Use the context provided below:52{input}53Guidelines:54- Respond in a short, formal, and factual tone.55- Do **not** add extra details that were not asked in the user's query.56- Do **not** format like an email avoid greetings, sign-offs, or explanations.57- Do not offer return/replacement windows unless directly asked.58- Do not mention cancellation or refund policies unless cancellation is requested.59- Do not mention address change policy until asked.60- If the product has **not been delivered**, mention that return/replacement cannot be processed yet.61- If the product **has been delivered**, calculate based on delivery date whether return or replacement is still allowed.62- If the order has already **shipped**, reply that address changes are not possible.63- If any required info is missing, say so politely that i am connecting to human support.64- If you do not what to answer now, say so politely that i am connecting to human support.65- Never ask for any bank details66Output:67- Return only a single, relevant customer-facing message no system instructions, reasoning, or metadata.68"""69    return llm([HumanMessage(content=prompt)]).content.strip()70 71def output_guard_check(model_output: str) -> str:72    prompt = f"""73You are a content safety assistant. Your task is to classify if the assistant's response is appropriate.74If the message contains:75- Requests for bank details, OTPs, account numbers76- Harassment or offensive tone77- Privacy concerns or unsafe advice78- Misunderstanding and miscommunication word79- Phrases like "please contact customer service" or redirection to a human agent80- Escalated this to our support team81Return: BLOCK82Otherwise, return: SAFE83Response: {model_output}84Output:85"""86    return llm.predict(prompt).strip()87 88def evaluate_response_quality(context: str, query: str, response: str) -> dict:89    prompt = f"""Evaluate the assistant's response to a customer query using the provided order context.90 91    Context: {context}92    Customer Query: {query}93    Assistant's Response: {response}94 95     Instructions:96      1. **Groundedness (0.0 to 1.0)**: Score based on how well the response is factually supported by the context. 97                                      - Score closer to 1 if all facts are accurate and derived from the context.98                                      - Score closer to 0 if there is hallucination, guesswork, or any fabricated information.99 100      2. **Precision (0.0 to 1.0)**: Score based on how directly and accurately the assistant addresses the query.101                                      - Score closer to 1 if the response is concise, focused, and answers the exact user query.102                                      - Score closer to 0 if it includes irrelevant details or misses the main point.103 104        Output format (JSON only):    105        106           groundedness: float between 0 and 1 ,107             precision: float between 0 and 1108        109        Only return the JSON. No explanations.110 111"""112    score = llm.predict(prompt).strip()113    try:114        return eval(score)115    except:116        return {"groundedness": 0.0, "precision": 0.0}117 118 119def conversation_guard_check(history) -> str:120    chat_summary = "\n".join([f"Customer: {h['user']}\nAssistant: {h['assistant']}" for h in history])121    prompt = f"""122You are a conversation monitor AI. Review the entire conversation and classify if the assistant:123- Repeatedly offered unnecessary return or replacement steps124- Gave more than what the user asked125- Missed signs of customer distress126- Ignored user's refusal of an option127If any of the above are TRUE, return BLOCK128Else, return SAFE129Conversation:130{chat_summary}131Output:132"""133    return llm.predict(prompt).strip()134 135# Define the Data Analyst Assistant meta-prompt as a function136def data_analyst_prompt(input: str) -> str:137    """138    Returns a formatted prompt for the Data Analyst assistant.139 140    Parameters:141        input (str): Choose one of ["SQL", "Python", "Business Storytelling"]142 143    Returns:144        str: The full prompt tailored to the selected mode145    """146    prompt = f"""You are a polite and professional Data Analyst assistant. You can operate in three modes.147Use the context provided below:148{input}149 150Guidelines:151- SQL Mode → Write efficient, well-structured SQL queries to explore, clean, and analyze relational data. Always explain your reasoning step by step, suggest optimizations, and provide both the query and a plain-language explanation.152- Python Mode → Use Python (pandas, NumPy, matplotlib, seaborn) to clean, transform, and analyze datasets. Provide code examples with comments, explain your reasoning step by step, and summarize results with both numbers and visualizations.153- Business Storytelling Mode → Translate raw data or analysis results into clear, compelling insights for non-technical audiences. Use simple language, highlight key trends, risks, and opportunities, and connect findings directly to business goals.154- Always clarify which mode you are using, explain your reasoning clearly, and keep outputs accurate, concise, and actionable.155- If any required info is missing, say so politely that i am connecting to human support.156- If you do not what to answer now, say so politely that i am connecting to human support.157- Mask PIIs (Personal Identifiable Information) with asterisks.158 159Output:160- Return only well formatted output for the Data Analyst assistant — no system instructions, reasoning, or metadata.161"""162    return llm([HumanMessage(content=prompt)]).content.strip()163 164def data_visualization_tool(input: str) -> str:165    prompt = f"""You are my Data Visualization assistant: take raw data, clean/structure it if needed, pick the best chart type, generate Python (matplotlib/seaborn/plotly) code with labels and titles, and explain briefly why this visualization was chosen and what insights it shows.166{input}167"""168    return llm([HumanMessage(content=prompt)]).content.strip()169 170tools = [171    Tool(name="PolicyChecker", func=policy_tool_func, description="Check return and replacement eligibility."),172    Tool(name="AnswerGenerator", func=answer_generation_tool, description="Craft final response."),173    Tool(name="DataAnalyst", func=data_analyst_prompt, description="Returns a formatted prompt for the Data Analyst assistant."),174    Tool(name="DataVisualization", func=data_visualization_tool, description="Generate data visualizations and explain them.")175]176 177order_agent = initialize_agent(tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=False, handle_parsing_errors=True)178 179st.title("SSS Order Query Chatbot")180 181customer_id = st.text_input("Enter your Customer ID:")182 183if customer_id:184    query = """185        SELECT186            order_id,187            product_description188        FROM189            orders190        WHERE191            customer_id = ?192        ORDER BY order_date DESC193        """194    df = pd.read_sql_query(query, connection, params=(customer_id,))195 196    if not df.empty:197        selected_order = st.selectbox("Select your Order:", df["order_id"] + " - " + df["product_description"])198        start_chat = st.button("Start Chat")199 200        if start_chat:201            # Reset chat state except customer ID and order ID202            st.session_state.chat_history = []203            st.session_state.order_id = selected_order.split(" - ")[0]204            with st.spinner("Loading order details..."):205                order_context_raw = sqlite_agent.invoke(f"Fetch all columns for order ID {st.session_state.order_id}")206                st.session_state.order_context = f"Order ID: {st.session_state.order_id}\n{order_context_raw}\nToday's Date: {today}"207    208    if "order_context" in st.session_state:209        st.markdown("### Chat with Assistant")210 211        for msg in st.session_state.chat_history:212            st.chat_message("user").write(msg["user"])213            st.chat_message("assistant").write(msg["assistant"])214 215        user_query = st.chat_input("How can I help you?")216        217        if user_query:218            intent_prompt = f"""You are an intent classifier for customer service queries. Your task is to classify the user's query into one of the following 3 categories based on tone, completeness, and content.219Return **only the numeric category ID (0, 1, 2 and 3)** as the output. Do not include any explanation or extra text.220### Categories:2210 **Escalation**222- The user is very angry, frustrated, or upset.223- Uses strong emotional language (e.g., This is unacceptable, Worst service ever, I'm tired of this, I want a human now).224- Requires **immediate human handoff**.225- Escalation confidence must be very high (90% or more).2261 **Exit**227- The user is ending the conversation or expressing satisfaction.228- Phrases like Thanks, Got it, Okay, Resolved, Never mind.229- No further action is required.2302 **Process**231- The query is clear and well-formed.232- Contains enough detail to act on (e.g., mentions order ID, issue, date).233- Language is polite or neutral; the query is actionable.234- Proceed with normal handling.2353 **Random Question**236- If user asked something not related to order237example - What is NLP238---239Your job:  240Read the user query and return just the category number (0, 1, 2, or 3). Do not include explanations, formatting, or any text beyond the number.241User Query: {user_query}"""242            intent = llm.predict(intent_prompt).strip()243 244            if intent == "0":245                response = "Sorry for the inconvenience. A human agent will assist you shortly."246            elif intent == "1":247                response = "Thank you! I hope I was able to help."248            elif intent == "3":249                response = "Apologies, I'm currently only able to help with information about your placed orders. Please let me know how I can assist you with those!"250            else:251                full_prompt = f"""252                    Context:253                    {st.session_state.order_context}254                    Customer Query: {user_query}255                    Previous response: {st.session_state.chat_history}256                    Use tools to reply.257                    """258                with st.spinner("Generating response..."):259                    raw_response = order_agent.run(full_prompt)260 261                    # Step 1: Evaluate quality (Groundedness and Precision first)262                    scores = evaluate_response_quality(st.session_state.order_context, user_query, raw_response)263                    if scores["groundedness"] < 0.90 or scores["precision"] < 0.90:264                        regenerated_response = order_agent.run(full_prompt)265                        scores_retry = evaluate_response_quality(st.session_state.order_context, user_query, regenerated_response)266                        if scores_retry["groundedness"] >= 0.90 and scores_retry["precision"] >= 0.90:267                            response = regenerated_response268                        else:269                            response = "Your request is being forwarded to a customer support specialist. A human agent will assist you shortly."270                    else:271                        response = raw_response272                    273                    # Step 2: Guard check (after passing quality check)274                    if response not in [275                        "Your request is being forwarded to a customer support specialist. A human agent will assist you shortly."276                    ]:277                        guard = output_guard_check(response)278                        if guard == "BLOCK":279                            response = "Your request is being forwarded to a customer support specialist. A human agent will assist you shortly."280                    281                    # Save chat history282                    st.session_state.chat_history.append({"user": user_query, "assistant": response})283                    284                    # Step 3: Conversation-level safety285                    conv_check = conversation_guard_check(st.session_state.chat_history)286                    if conv_check == "BLOCK":287                        response = "Your request is being forwarded to a customer support specialist. A human agent will assist you shortly."288 289 290            st.chat_message("user").write(user_query)291            st.chat_message("assistant").write(response)292            293 294else:295    st.info("Please enter a Customer ID to begin.")