vidhyamathu commited on
Commit
ef25d62
·
verified ·
1 Parent(s): c9c0a13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -85
app.py CHANGED
@@ -1,16 +1,12 @@
1
  import os
2
  import re
3
  import json
 
4
  from typing import Any, Optional, Dict
5
  import streamlit as st
6
 
7
  from langchain_groq import ChatGroq
8
  from langchain_core.prompts import ChatPromptTemplate
9
- from langchain_core.messages import SystemMessage
10
- from langchain_community.utilities import SQLDatabase
11
- from langchain_community.agent_toolkits import SQLDatabaseToolkit
12
- from langchain_community.agent_toolkits.sql.base import create_sql_agent
13
-
14
 
15
  # ============================================================
16
  # CONFIG
@@ -18,56 +14,28 @@ from langchain_community.agent_toolkits.sql.base import create_sql_agent
18
  DB_PATH = "customer_orders.db"
19
  MODEL_NAME = "meta-llama/llama-4-scout-17b-16e-instruct"
20
 
21
-
22
  # ============================================================
23
- # LLM & AGENT INIT
24
  # ============================================================
25
  @st.cache_resource
26
  def init_llm():
27
- groq_key = os.getenv("GROQ_API_KEY") # HF Spaces secrets -> env vars
28
  if not groq_key:
29
- st.error("Missing GROQ_API_KEY. Add it in Hugging Face Space → Settings → Secrets.")
30
  st.stop()
31
 
32
- # Most compatible approach across langchain_groq versions
33
  os.environ["GROQ_API_KEY"] = groq_key
34
 
35
- return ChatGroq(model=MODEL_NAME, temperature=0, max_tokens=400, timeout=30, max_retries=2)
36
-
37
-
38
- @st.cache_resource
39
- def init_db_and_agent():
40
- if not os.path.exists(DB_PATH):
41
- st.error(f"Database file '{DB_PATH}' not found. Upload it to the Space root folder.")
42
- st.stop()
43
-
44
- db = SQLDatabase.from_uri(f"sqlite:///{DB_PATH}")
45
- llm = init_llm()
46
- toolkit = SQLDatabaseToolkit(db=db, llm=llm)
47
-
48
- system_message = """
49
- You are a read-only SQL assistant for FoodHub.
50
- Rules:
51
- - Use ONLY SELECT queries (no INSERT/UPDATE/DELETE/DROP).
52
- - Query only the existing tables/columns.
53
- - When asked for an order, filter by order_id exactly.
54
- - Return the final answer as a valid JSON object only (no extra text).
55
- """
56
-
57
- agent = create_sql_agent(
58
- llm=llm,
59
- toolkit=toolkit,
60
- verbose=False,
61
- system_message=SystemMessage(content=system_message),
62
  )
63
 
64
- return agent
65
-
66
-
67
- db_agent = init_db_and_agent()
68
  llm = init_llm()
69
 
70
-
71
  # ============================================================
72
  # HELPERS & LOGIC
73
  # ============================================================
@@ -82,66 +50,64 @@ def try_extract_order_id(text: str) -> Optional[str]:
82
 
83
  def fetch_order_as_json(order_id: str) -> Dict[str, Any]:
84
  """
85
- Calls SQL agent and tries to return a dict.
86
- If agent output isn't valid JSON, returns {_error: ...}.
 
87
  """
88
- prompt = f"""
89
- Return ONLY JSON (no explanation).
90
- Retrieve exactly one row from the orders table where order_id = '{order_id}'.
91
- JSON keys must include:
92
- order_id, cust_id, order_time, order_status, payment_status, item_in_order,
93
- preparing_eta, prepared_time, delivery_eta, delivery_time
94
- If not found, return: {{ "_error": "NOT_FOUND" }}.
95
- """
96
  try:
97
- res = db_agent.invoke({"input": prompt})
98
- raw = (res.get("output") or "").strip()
99
-
100
- # Try direct JSON parse
101
- try:
102
- parsed = json.loads(raw)
103
- if isinstance(parsed, dict):
104
- return parsed
105
- except Exception:
106
- pass
107
-
108
- # Try to extract the first JSON object block
109
- start = raw.find("{")
110
- end = raw.rfind("}")
111
- if start != -1 and end != -1 and end > start:
112
- candidate = raw[start:end+1]
113
- try:
114
- parsed = json.loads(candidate)
115
- if isinstance(parsed, dict):
116
- return parsed
117
- except Exception:
118
- pass
119
 
120
- return {"_error": "NOT_FOUND"}
121
  except Exception:
122
  return {"_error": "NOT_FOUND"}
123
 
124
 
125
  def chat_agent_response(user_query: str, session_order_id: str) -> str:
126
  oid = session_order_id or try_extract_order_id(user_query)
 
127
  if not oid:
128
  return "I’d be happy to help. Could you please share your Order ID (example: O12486)?"
129
 
130
  order_data = fetch_order_as_json(oid)
 
131
  if order_data.get("_error") == "NOT_FOUND":
132
- return f"I'm sorry — I couldn't find any details for Order ID **{oid}**. Please re-check the ID and try again."
133
 
134
- # Redact customer id
135
  if "cust_id" in order_data:
136
  order_data["cust_id"] = "[redacted]"
137
 
138
  prompt = ChatPromptTemplate.from_messages([
139
- ("system", "You are FoodHub Support. Be polite and concise (2–4 lines). Use only the provided context."),
140
- ("human", "User: {user_query}\n\nOrder Context (JSON): {context}\n\nReply:")
 
 
 
 
 
 
 
141
  ])
142
 
143
  chain = prompt | llm
144
- resp = chain.invoke({"user_query": user_query, "context": json.dumps(order_data)})
 
 
 
 
145
  return getattr(resp, "content", str(resp))
146
 
147
 
@@ -156,12 +122,12 @@ if "messages" not in st.session_state:
156
  if "order_id" not in st.session_state:
157
  st.session_state.order_id = ""
158
 
159
- # Display history
160
  for msg in st.session_state.messages:
161
  with st.chat_message(msg["role"]):
162
  st.markdown(msg["content"])
163
 
164
- # User Input
165
  user_text = st.chat_input("How can I help with your order?")
166
 
167
  if user_text:
@@ -169,9 +135,9 @@ if user_text:
169
  with st.chat_message("user"):
170
  st.markdown(user_text)
171
 
172
- detected_id = try_extract_order_id(user_text)
173
- if detected_id:
174
- st.session_state.order_id = detected_id
175
 
176
  with st.spinner("Checking FoodHub records..."):
177
  response = chat_agent_response(user_text, st.session_state.order_id)
@@ -179,3 +145,4 @@ if user_text:
179
  st.session_state.messages.append({"role": "assistant", "content": response})
180
  with st.chat_message("assistant"):
181
  st.markdown(response)
 
 
1
  import os
2
  import re
3
  import json
4
+ import sqlite3
5
  from typing import Any, Optional, Dict
6
  import streamlit as st
7
 
8
  from langchain_groq import ChatGroq
9
  from langchain_core.prompts import ChatPromptTemplate
 
 
 
 
 
10
 
11
  # ============================================================
12
  # CONFIG
 
14
  DB_PATH = "customer_orders.db"
15
  MODEL_NAME = "meta-llama/llama-4-scout-17b-16e-instruct"
16
 
 
17
  # ============================================================
18
+ # LLM INIT
19
  # ============================================================
20
  @st.cache_resource
21
  def init_llm():
22
+ groq_key = os.getenv("GROQ_API_KEY")
23
  if not groq_key:
24
+ st.error("Missing GROQ_API_KEY. Add it in Hugging Face → Settings → Secrets.")
25
  st.stop()
26
 
 
27
  os.environ["GROQ_API_KEY"] = groq_key
28
 
29
+ return ChatGroq(
30
+ model=MODEL_NAME,
31
+ temperature=0,
32
+ max_tokens=400,
33
+ timeout=30,
34
+ max_retries=2,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  )
36
 
 
 
 
 
37
  llm = init_llm()
38
 
 
39
  # ============================================================
40
  # HELPERS & LOGIC
41
  # ============================================================
 
50
 
51
  def fetch_order_as_json(order_id: str) -> Dict[str, Any]:
52
  """
53
+ FINAL FIX
54
+ Deterministic, read-only SQLite fetch.
55
+ Works the same in Colab and Hugging Face.
56
  """
 
 
 
 
 
 
 
 
57
  try:
58
+ conn = sqlite3.connect(DB_PATH)
59
+ conn.row_factory = sqlite3.Row
60
+ cur = conn.cursor()
61
+
62
+ cur.execute(
63
+ "SELECT * FROM orders WHERE order_id = ? LIMIT 1;",
64
+ (order_id,)
65
+ )
66
+ row = cur.fetchone()
67
+ conn.close()
68
+
69
+ if row is None:
70
+ return {"_error": "NOT_FOUND"}
71
+
72
+ return dict(row)
 
 
 
 
 
 
 
73
 
 
74
  except Exception:
75
  return {"_error": "NOT_FOUND"}
76
 
77
 
78
  def chat_agent_response(user_query: str, session_order_id: str) -> str:
79
  oid = session_order_id or try_extract_order_id(user_query)
80
+
81
  if not oid:
82
  return "I’d be happy to help. Could you please share your Order ID (example: O12486)?"
83
 
84
  order_data = fetch_order_as_json(oid)
85
+
86
  if order_data.get("_error") == "NOT_FOUND":
87
+ return f"I'm sorry — I couldn't find any details for Order ID **{oid}**. Please re-check and try again."
88
 
89
+ # Privacy guardrail
90
  if "cust_id" in order_data:
91
  order_data["cust_id"] = "[redacted]"
92
 
93
  prompt = ChatPromptTemplate.from_messages([
94
+ ("system",
95
+ "You are FoodHub customer support.\n"
96
+ "Write a polite, concise reply (2–4 lines).\n"
97
+ "Use ONLY the provided order context.\n"
98
+ "Do NOT expose customer identifiers.\n"),
99
+ ("human",
100
+ "User query:\n{user_query}\n\n"
101
+ "Order context (JSON):\n{context}\n\n"
102
+ "Final reply:")
103
  ])
104
 
105
  chain = prompt | llm
106
+ resp = chain.invoke({
107
+ "user_query": user_query,
108
+ "context": json.dumps(order_data)
109
+ })
110
+
111
  return getattr(resp, "content", str(resp))
112
 
113
 
 
122
  if "order_id" not in st.session_state:
123
  st.session_state.order_id = ""
124
 
125
+ # Show chat history
126
  for msg in st.session_state.messages:
127
  with st.chat_message(msg["role"]):
128
  st.markdown(msg["content"])
129
 
130
+ # User input
131
  user_text = st.chat_input("How can I help with your order?")
132
 
133
  if user_text:
 
135
  with st.chat_message("user"):
136
  st.markdown(user_text)
137
 
138
+ detected = try_extract_order_id(user_text)
139
+ if detected:
140
+ st.session_state.order_id = detected
141
 
142
  with st.spinner("Checking FoodHub records..."):
143
  response = chat_agent_response(user_text, st.session_state.order_id)
 
145
  st.session_state.messages.append({"role": "assistant", "content": response})
146
  with st.chat_message("assistant"):
147
  st.markdown(response)
148
+