Seth0330 commited on
Commit
fb5cdfa
·
verified ·
1 Parent(s): b66e512

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -60
app.py CHANGED
@@ -7,10 +7,10 @@ import json
7
  import re
8
 
9
  # — Page config
10
- st.set_page_config(page_title="CSV-Backed AI Agent", layout="wide")
11
 
12
  # — Title & image
13
- st.title("CSV-Backed AI Agent")
14
  st.image("./nadi-lok-image.png")
15
 
16
  # — Load API key
@@ -73,6 +73,32 @@ prompt = st.text_area(
73
  height=150,
74
  )
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  # — Run Agent
77
  if st.button("Run Agent"):
78
  if df is None:
@@ -80,71 +106,79 @@ if st.button("Run Agent"):
80
  elif not prompt.strip():
81
  st.error("Please enter a prompt.")
82
  else:
83
- # 1) Embed the prompt
84
- q_resp = requests.post(
85
- "https://api.openai.com/v1/embeddings",
86
- headers=HEADERS,
87
- json={"model": "text-embedding-ada-002", "input": [prompt]},
88
- timeout=60,
89
- )
90
- q_resp.raise_for_status()
91
- q_emb = np.array(q_resp.json()["data"][0]["embedding"])
92
-
93
- # 2) Compute cosine similarities
94
- norms = np.linalg.norm(embeddings, axis=1)
95
- q_norm = np.linalg.norm(q_emb)
96
- sims = embeddings.dot(q_emb) / (norms * q_norm + 1e-8)
97
-
98
- # 3) Select top-K relevant rows
99
- K = min(5, len(sims))
100
- top_idxs = sims.argsort()[-K:][::-1]
101
- relevant_rows = [row_texts[i] for i in top_idxs]
102
-
103
- # 4) Build the chat messages
104
- system_msg = {
105
- "role": "system",
106
- "content": (
107
- "You are an AI agent that reads the provided CSV rows and answers the user's query. "
108
- "Return your answer strictly as JSON (no extra explanation)."
109
- ),
110
- }
111
- memory_msg = {
112
- "role": "system",
113
- "content": "Relevant CSV rows:\n" + "\n".join(relevant_rows) + "\n<end of rows>",
114
- }
115
- user_msg = {"role": "user", "content": prompt}
116
-
117
- # 5) Call the Chat API
118
  chat_resp = requests.post(
119
  "https://api.openai.com/v1/chat/completions",
120
  headers=HEADERS,
121
  json={
122
- "model": "gpt-3.5-turbo",
123
- "messages": [system_msg, memory_msg, user_msg],
 
 
124
  "temperature": 0,
125
- "max_tokens": 1500,
126
  },
127
  timeout=60,
128
  )
129
  chat_resp.raise_for_status()
130
- answer = chat_resp.json()["choices"][0]["message"]["content"]
131
-
132
- # 6) Extract the JSON payload
133
- txt = re.sub(r"```(?:json)?", "", answer).strip()
134
- start = txt.find("{")
135
- end = txt.rfind("}") + 1
136
- parsed = None
137
- if start >= 0 and end > 0:
138
- frag = re.sub(r",\s*([}\]])", r"\1", txt[start:end])
139
- try:
140
- parsed = json.loads(frag)
141
- except json.JSONDecodeError:
142
- parsed = None
143
-
144
- # 7) Display results
145
- if parsed is not None:
146
- st.subheader(" JSON Output")
147
- st.json(parsed)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  else:
149
- st.subheader("🔍 Raw Output")
150
- st.text(answer)
 
 
7
  import re
8
 
9
  # — Page config
10
+ st.set_page_config(page_title="CSV-Backed AI Agent with Function Calling", layout="wide")
11
 
12
  # — Title & image
13
+ st.title("CSV-Backed AI Agent with Function Calling")
14
  st.image("./nadi-lok-image.png")
15
 
16
  # — Load API key
 
73
  height=150,
74
  )
75
 
76
+ # — Define function for OpenAI function calling
77
+ def search_csv(query: str):
78
+ # Run a Pandas query safely
79
+ try:
80
+ result_df = df.query(query)
81
+ return result_df.to_dict(orient="records")
82
+ except Exception as e:
83
+ return {"error": f"Query error: {str(e)}"}
84
+
85
+ function_schema = [
86
+ {
87
+ "name": "search_csv",
88
+ "description": "Filter the CSV rows by a Pandas query. Example: price > 100",
89
+ "parameters": {
90
+ "type": "object",
91
+ "properties": {
92
+ "query": {
93
+ "type": "string",
94
+ "description": "A Pandas query string, e.g. 'price > 100 and category == \"A\"'"
95
+ },
96
+ },
97
+ "required": ["query"],
98
+ },
99
+ }
100
+ ]
101
+
102
  # — Run Agent
103
  if st.button("Run Agent"):
104
  if df is None:
 
106
  elif not prompt.strip():
107
  st.error("Please enter a prompt.")
108
  else:
109
+ # 1) First call: ask OpenAI if it wants to use a function
110
+ messages = [
111
+ {
112
+ "role": "system",
113
+ "content": (
114
+ "You are an AI agent helping users analyze a CSV file. "
115
+ "If you need to search or filter the CSV, call the 'search_csv' function. "
116
+ "Only use the function when you need data from the CSV."
117
+ ),
118
+ },
119
+ {"role": "user", "content": prompt}
120
+ ]
121
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  chat_resp = requests.post(
123
  "https://api.openai.com/v1/chat/completions",
124
  headers=HEADERS,
125
  json={
126
+ "model": "gpt-3.5-turbo-1106", # or "gpt-4-1106-preview" if available
127
+ "messages": messages,
128
+ "functions": function_schema,
129
+ "function_call": "auto",
130
  "temperature": 0,
131
+ "max_tokens": 1000,
132
  },
133
  timeout=60,
134
  )
135
  chat_resp.raise_for_status()
136
+ response_json = chat_resp.json()
137
+ msg = response_json["choices"][0]["message"]
138
+
139
+ # 2) Check if function call is requested
140
+ if msg.get("function_call"):
141
+ func_name = msg["function_call"]["name"]
142
+ args_json = msg["function_call"]["arguments"]
143
+ args = json.loads(args_json)
144
+ # Only one function: search_csv
145
+ search_result = search_csv(args["query"])
146
+
147
+ # 3) Pass function result back to OpenAI for final answer
148
+ followup_messages = [
149
+ {
150
+ "role": "system",
151
+ "content": (
152
+ "You are an AI agent helping users analyze a CSV file."
153
+ ),
154
+ },
155
+ {"role": "user", "content": prompt},
156
+ {
157
+ "role": "function",
158
+ "name": func_name,
159
+ "content": json.dumps(search_result),
160
+ }
161
+ ]
162
+
163
+ final_resp = requests.post(
164
+ "https://api.openai.com/v1/chat/completions",
165
+ headers=HEADERS,
166
+ json={
167
+ "model": "gpt-3.5-turbo-1106", # or "gpt-4-1106-preview"
168
+ "messages": followup_messages,
169
+ "temperature": 0,
170
+ "max_tokens": 1500,
171
+ },
172
+ timeout=60,
173
+ )
174
+ final_resp.raise_for_status()
175
+ answer = final_resp.json()["choices"][0]["message"]["content"]
176
+
177
+ st.subheader("✅ Agent Answer")
178
+ st.markdown(answer)
179
+ st.subheader("📊 Filtered CSV Data")
180
+ st.json(search_result)
181
  else:
182
+ # No function call: model answered directly
183
+ st.subheader("✅ Agent Answer")
184
+ st.markdown(msg["content"])