Seth0330 commited on
Commit
172b8f0
·
verified ·
1 Parent(s): b957a6b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -29
app.py CHANGED
@@ -5,11 +5,13 @@ import requests
5
  import json
6
 
7
  # --- Page config
8
- st.set_page_config(page_title="CSV-Backed AI Chat Agent", layout="wide")
9
 
10
- # --- Title & image
11
- st.title("CSV-Backed AI Chat Agent")
12
- st.image("./nadi-lok-image.png")
 
 
13
 
14
  # --- Load API key
15
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
@@ -52,18 +54,8 @@ if uploaded_file is not None:
52
  "If you use 'search_csv', use Pandas query syntax."
53
  ),
54
  }
55
- # Only reset memory on new file load
56
- if not st.session_state.messages or (
57
- st.session_state.messages and
58
- ("system" not in st.session_state.messages[0].get("role", ""))
59
- ):
60
- st.session_state.messages = [system_message]
61
- elif (
62
- st.session_state.messages and
63
- st.session_state.messages[0].get("role", "") == "system" and
64
- st.session_state.messages[0].get("content", "") != system_message["content"]
65
- ):
66
- st.session_state.messages[0] = system_message
67
  except Exception as e:
68
  st.sidebar.error(f"Error reading file: {e}")
69
  df = None
@@ -71,13 +63,18 @@ else:
71
  df = None
72
 
73
  if df is not None:
74
- st.markdown(f"**Loaded CSV:** {df.shape[0]} rows × {df.shape[1]} columns")
 
 
 
 
 
75
 
76
  # --- Functions for function calling
77
  def search_csv(query: str):
78
  try:
79
  result_df = df.query(query)
80
- return result_df.head(10).to_dict(orient="records") # limit for safety
81
  except Exception as e:
82
  return {"error": f"Invalid query. Example: 'price > 100'. Details: {str(e)}"}
83
 
@@ -88,7 +85,6 @@ def count_unique(column: str):
88
  except Exception as e:
89
  return {"error": f"Column '{column}' not found or not countable. Details: {str(e)}"}
90
 
91
- # --- Function schemas for OpenAI
92
  function_schema = [
93
  {
94
  "name": "search_csv",
@@ -120,19 +116,89 @@ function_schema = [
120
  }
121
  ]
122
 
123
- # --- Chat interface
124
- st.markdown("### Conversation")
125
- for i, msg in enumerate(st.session_state.messages[1:]): # Skip system message for display
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  if msg["role"] == "user":
127
- st.markdown(f"<div style='color: #4F8BF9;'><b>User:</b> {msg['content']}</div>", unsafe_allow_html=True)
128
  elif msg["role"] == "assistant":
129
- st.markdown(f"<div style='color: #1C6E4C;'><b>Agent:</b> {msg['content']}</div>", unsafe_allow_html=True)
130
  elif msg["role"] == "function":
131
  try:
132
  result = json.loads(msg["content"])
133
- st.markdown(f"<details><summary><b>Function '{msg['name']}' output:</b></summary><pre>{json.dumps(result, indent=2)}</pre></details>", unsafe_allow_html=True)
 
 
 
134
  except Exception:
135
- st.markdown(f"<b>Function '{msg['name']}' output:</b> {msg['content']}", unsafe_allow_html=True)
 
 
136
 
137
  # --- Sending user input and OpenAI call logic using a callback
138
  def send_message():
@@ -168,7 +234,6 @@ def send_message():
168
  func_name = msg["function_call"]["name"]
169
  args_json = msg["function_call"]["arguments"]
170
  args = json.loads(args_json)
171
- # --- FIXED: Only pass the expected arg for each function
172
  if func_name == "search_csv":
173
  function_result = search_csv(args.get("query", ""))
174
  elif func_name == "count_unique":
@@ -190,7 +255,7 @@ def send_message():
190
  "https://api.openai.com/v1/chat/completions",
191
  headers=HEADERS,
192
  json={
193
- "model": "gpt-4o",
194
  "messages": followup_messages,
195
  "temperature": 0,
196
  "max_tokens": 1500,
@@ -205,5 +270,13 @@ def send_message():
205
 
206
  st.session_state.temp_input = ""
207
 
 
208
  if df is not None:
209
- st.text_input("Your message:", key="temp_input", on_change=send_message)
 
 
 
 
 
 
 
 
5
  import json
6
 
7
  # --- Page config
8
+ st.set_page_config(page_title="CSV-Backed AI Chat Agent", layout="centered")
9
 
10
+ # --- Minimal title
11
+ st.markdown(
12
+ "<h2 style='text-align:center; margin-bottom:1rem;'>CSV-Backed AI Chat Agent</h2>",
13
+ unsafe_allow_html=True,
14
+ )
15
 
16
  # --- Load API key
17
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
 
54
  "If you use 'search_csv', use Pandas query syntax."
55
  ),
56
  }
57
+ # Reset memory on new file load
58
+ st.session_state.messages = [system_message]
 
 
 
 
 
 
 
 
 
 
59
  except Exception as e:
60
  st.sidebar.error(f"Error reading file: {e}")
61
  df = None
 
63
  df = None
64
 
65
  if df is not None:
66
+ st.markdown(
67
+ f"<div style='color: #888; font-size:0.95em; text-align:center;'>"
68
+ f"Loaded CSV: <b>{df.shape[0]}</b> rows × <b>{df.shape[1]}</b> columns"
69
+ f"</div><hr style='margin-top:0.5rem; margin-bottom:1rem;'>",
70
+ unsafe_allow_html=True,
71
+ )
72
 
73
  # --- Functions for function calling
74
  def search_csv(query: str):
75
  try:
76
  result_df = df.query(query)
77
+ return result_df.head(10).to_dict(orient="records")
78
  except Exception as e:
79
  return {"error": f"Invalid query. Example: 'price > 100'. Details: {str(e)}"}
80
 
 
85
  except Exception as e:
86
  return {"error": f"Column '{column}' not found or not countable. Details: {str(e)}"}
87
 
 
88
  function_schema = [
89
  {
90
  "name": "search_csv",
 
116
  }
117
  ]
118
 
119
+ # --- Chat style (CSS for chat bubbles)
120
+ st.markdown("""
121
+ <style>
122
+ .chat-row-user {
123
+ background: #DCF8C6;
124
+ border-radius: 1rem 1rem 0.25rem 1rem;
125
+ margin: 0.25rem 0 0.75rem 25%;
126
+ padding: 0.6rem 1.1rem;
127
+ max-width: 70%;
128
+ text-align: right;
129
+ float: right;
130
+ clear: both;
131
+ box-shadow: 0 1px 2px #eee;
132
+ }
133
+ .chat-row-agent {
134
+ background: #F1F0F0;
135
+ border-radius: 1rem 1rem 1rem 0.25rem;
136
+ margin: 0.25rem 25% 0.75rem 0;
137
+ padding: 0.6rem 1.1rem;
138
+ max-width: 70%;
139
+ text-align: left;
140
+ float: left;
141
+ clear: both;
142
+ box-shadow: 0 1px 2px #eee;
143
+ }
144
+ .function-bubble {
145
+ background: #E3EDFA;
146
+ border-radius: 0.5rem;
147
+ margin: 0.1rem 15% 0.75rem 0;
148
+ padding: 0.4rem 1rem;
149
+ font-size: 0.97em;
150
+ color: #174075;
151
+ max-width: 80%;
152
+ box-shadow: 0 1px 2px #e2e6ea;
153
+ }
154
+ .reset-btn {
155
+ display: flex;
156
+ justify-content: flex-end;
157
+ margin-bottom: 0.8rem;
158
+ }
159
+ </style>
160
+ """, unsafe_allow_html=True)
161
+
162
+ # --- Chat interface header with reset
163
+ col1, col2 = st.columns([6, 1])
164
+ with col1:
165
+ st.markdown("### Conversation")
166
+ with col2:
167
+ if st.button("Reset chat", key="reset_chat", help="Clear conversation history."):
168
+ if df is not None:
169
+ columns = ", ".join(df.columns)
170
+ st.session_state.messages = [{
171
+ "role": "system",
172
+ "content": (
173
+ f"You are an AI data analyst for a CSV file with these columns: {columns}. "
174
+ "When the user asks a question, always use the most relevant function to get the answer directly. "
175
+ "Do not describe your plan or reasoning steps. Do not ask the user for clarification. "
176
+ "Just call the function needed and give the answer, as briefly as possible. "
177
+ "If you need to search or filter the CSV, use the 'search_csv' function. "
178
+ "If you need to count unique values, use the 'count_unique' function. "
179
+ "If you use 'search_csv', use Pandas query syntax."
180
+ ),
181
+ }]
182
+ else:
183
+ st.session_state.messages = []
184
+
185
+ # --- Display chat history
186
+ for i, msg in enumerate(st.session_state.messages[1:]): # Skip system message
187
  if msg["role"] == "user":
188
+ st.markdown(f"<div class='chat-row-user'>{msg['content']}</div>", unsafe_allow_html=True)
189
  elif msg["role"] == "assistant":
190
+ st.markdown(f"<div class='chat-row-agent'>{msg['content']}</div>", unsafe_allow_html=True)
191
  elif msg["role"] == "function":
192
  try:
193
  result = json.loads(msg["content"])
194
+ st.markdown(
195
+ f"<div class='function-bubble'><b>Function '{msg['name']}' output:</b>"
196
+ f"<pre style='background:transparent;'>{json.dumps(result, indent=2)}</pre></div>",
197
+ unsafe_allow_html=True)
198
  except Exception:
199
+ st.markdown(
200
+ f"<div class='function-bubble'><b>Function '{msg['name']}' output:</b> {msg['content']}</div>",
201
+ unsafe_allow_html=True)
202
 
203
  # --- Sending user input and OpenAI call logic using a callback
204
  def send_message():
 
234
  func_name = msg["function_call"]["name"]
235
  args_json = msg["function_call"]["arguments"]
236
  args = json.loads(args_json)
 
237
  if func_name == "search_csv":
238
  function_result = search_csv(args.get("query", ""))
239
  elif func_name == "count_unique":
 
255
  "https://api.openai.com/v1/chat/completions",
256
  headers=HEADERS,
257
  json={
258
+ "model": "gpt-4.1",
259
  "messages": followup_messages,
260
  "temperature": 0,
261
  "max_tokens": 1500,
 
270
 
271
  st.session_state.temp_input = ""
272
 
273
+ # --- User input box at bottom (styled like ChatGPT input)
274
  if df is not None:
275
+ st.markdown("<div style='height:18px;'></div>", unsafe_allow_html=True)
276
+ st.text_input(
277
+ "Type your question and press Enter...",
278
+ key="temp_input",
279
+ on_change=send_message,
280
+ placeholder="Ask anything about your CSV...",
281
+ label_visibility="collapsed",
282
+ )