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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -101
app.py CHANGED
@@ -5,13 +5,10 @@ import requests
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,8 +51,18 @@ if uploaded_file is not None:
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,18 +70,13 @@ else:
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,6 +87,7 @@ def count_unique(column: str):
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,89 +119,19 @@ function_schema = [
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,6 +167,7 @@ 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":
@@ -270,13 +204,5 @@ def send_message():
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
- )
 
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
 
13
  # --- Load API key
14
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
 
51
  "If you use 'search_csv', use Pandas query syntax."
52
  ),
53
  }
54
+ # Only reset memory on new file load
55
+ if not st.session_state.messages or (
56
+ st.session_state.messages and
57
+ ("system" not in st.session_state.messages[0].get("role", ""))
58
+ ):
59
+ st.session_state.messages = [system_message]
60
+ elif (
61
+ st.session_state.messages and
62
+ st.session_state.messages[0].get("role", "") == "system" and
63
+ st.session_state.messages[0].get("content", "") != system_message["content"]
64
+ ):
65
+ st.session_state.messages[0] = system_message
66
  except Exception as e:
67
  st.sidebar.error(f"Error reading file: {e}")
68
  df = None
 
70
  df = None
71
 
72
  if df is not None:
73
+ st.markdown(f"**Loaded CSV:** {df.shape[0]} rows × {df.shape[1]} columns")
 
 
 
 
 
74
 
75
  # --- Functions for function calling
76
  def search_csv(query: str):
77
  try:
78
  result_df = df.query(query)
79
+ return result_df.head(10).to_dict(orient="records") # limit for safety
80
  except Exception as e:
81
  return {"error": f"Invalid query. Example: 'price > 100'. Details: {str(e)}"}
82
 
 
87
  except Exception as e:
88
  return {"error": f"Column '{column}' not found or not countable. Details: {str(e)}"}
89
 
90
+ # --- Function schemas for OpenAI
91
  function_schema = [
92
  {
93
  "name": "search_csv",
 
119
  }
120
  ]
121
 
122
+ # --- Chat interface
123
+ st.markdown("### Conversation")
124
+ for i, msg in enumerate(st.session_state.messages[1:]): # Skip system message for display
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  if msg["role"] == "user":
126
+ st.markdown(f"<div style='color: #4F8BF9;'><b>User:</b> {msg['content']}</div>", unsafe_allow_html=True)
127
  elif msg["role"] == "assistant":
128
+ st.markdown(f"<div style='color: #1C6E4C;'><b>Agent:</b> {msg['content']}</div>", unsafe_allow_html=True)
129
  elif msg["role"] == "function":
130
  try:
131
  result = json.loads(msg["content"])
132
+ st.markdown(f"<details><summary><b>Function '{msg['name']}' output:</b></summary><pre>{json.dumps(result, indent=2)}</pre></details>", unsafe_allow_html=True)
 
 
 
133
  except Exception:
134
+ st.markdown(f"<b>Function '{msg['name']}' output:</b> {msg['content']}", unsafe_allow_html=True)
 
 
135
 
136
  # --- Sending user input and OpenAI call logic using a callback
137
  def send_message():
 
167
  func_name = msg["function_call"]["name"]
168
  args_json = msg["function_call"]["arguments"]
169
  args = json.loads(args_json)
170
+ # --- FIXED: Only pass the expected arg for each function
171
  if func_name == "search_csv":
172
  function_result = search_csv(args.get("query", ""))
173
  elif func_name == "count_unique":
 
204
 
205
  st.session_state.temp_input = ""
206
 
 
207
  if df is not None:
208
+ st.text_input("Your message:", key="temp_input", on_change=send_message)