Seth0330 commited on
Commit
8bf44c2
·
verified ·
1 Parent(s): ed2ba1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -63
app.py CHANGED
@@ -1,18 +1,25 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import os
4
- import requests
 
5
  import json
6
  import re
7
 
8
  # — Page config
9
  st.set_page_config(page_title="CSV-Backed AI Agent", layout="wide")
10
 
11
- # — Title & (optional) image
12
  st.title("CSV-Backed AI Agent")
13
  st.image("./nadi-lok-image.png")
14
 
15
- # — Sidebar: CSV upload & preview (identical to your working code)
 
 
 
 
 
 
16
  st.sidebar.header("Upload CSV File")
17
  uploaded_file = st.sidebar.file_uploader("Choose a CSV file", type="csv")
18
 
@@ -20,96 +27,98 @@ if uploaded_file:
20
  try:
21
  df = pd.read_csv(uploaded_file)
22
  st.sidebar.success("File uploaded successfully!")
23
- st.sidebar.write("Preview of the uploaded file:")
24
  st.sidebar.dataframe(df.head())
25
- # Convert DataFrame back to CSV text to feed into the agent
26
- csv_text = df.to_csv(index=False)
27
  except Exception as e:
28
  st.sidebar.error(f"Error reading file: {e}")
29
  df = None
30
- csv_text = None
31
  else:
32
  df = None
33
- csv_text = None
34
 
35
- # — Show basic info about the loaded CSV
36
  if df is not None:
37
  st.markdown(f"**Loaded CSV:** {df.shape[0]} rows × {df.shape[1]} columns")
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  # — Prompt input
40
  prompt = st.text_area(
41
  "Enter your prompt for the agent",
42
  placeholder="e.g. Which products have price > 100?",
43
- height=150
44
  )
45
 
46
- # — Run the AI Agent
47
  if st.button("Run Agent"):
48
- # 1️⃣ Validation
49
  if df is None:
50
  st.error("Please upload a CSV file first.")
51
  elif not prompt.strip():
52
  st.error("Please enter a prompt.")
53
  else:
54
- # 2️⃣ Build the "memory + prompt" messages
 
 
 
 
 
 
 
 
 
 
 
 
55
  system_msg = {
56
  "role": "system",
57
  "content": (
58
- "You are an AI agent that reads the provided CSV data and answers the user's query. "
59
- "Return your answer strictly as JSON (no additional explanation)."
60
- )
61
  }
62
- csv_msg = {
63
  "role": "system",
64
- "content": f"CSV Data:\n{csv_text}\n<End of CSV>"
65
  }
66
  user_msg = {"role": "user", "content": prompt}
67
 
68
- # 3️⃣ Call OpenAI
69
- api_key = os.getenv("OPENAI_API_KEY")
70
- if not api_key:
71
- st.error("❌ OPENAI_API_KEY not set in Secrets.")
72
- st.stop()
73
-
74
- response = requests.post(
75
- "https://api.openai.com/v1/chat/completions",
76
- headers={
77
- "Authorization": f"Bearer {api_key}",
78
- "Content-Type": "application/json",
79
- },
80
- json={
81
- "model": "gpt-3.5-turbo",
82
- "messages": [system_msg, csv_msg, user_msg],
83
- "temperature": 0,
84
- "max_tokens": 1500,
85
- },
86
- timeout=60,
87
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
- # 4️⃣ Handle API response
90
- if response.status_code != 200:
91
- st.error(f"API Error {response.status_code}: {response.text}")
 
92
  else:
93
- answer = response.json()["choices"][0]["message"]["content"]
94
-
95
- # Strip any ``` fences and pull out the JSON object
96
- txt = re.sub(r'```(?:json)?', '', answer).strip()
97
- start = txt.find("{")
98
- end = txt.rfind("}") + 1
99
- parsed = None
100
- if start >= 0 and end > 0:
101
- frag = txt[start:end]
102
- # remove trailing commas
103
- frag = re.sub(r',\s*([}\]])', r'\1', frag)
104
- try:
105
- parsed = json.loads(frag)
106
- except json.JSONDecodeError:
107
- parsed = None
108
-
109
- # 5️⃣ Display
110
- if parsed is not None:
111
- st.subheader("✅ JSON Output")
112
- st.json(parsed)
113
- else:
114
- st.subheader("🔍 Raw Output")
115
- st.text(answer)
 
1
  import streamlit as st
2
  import pandas as pd
3
  import os
4
+ import openai
5
+ import numpy as np
6
  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 your OpenAI key
17
+ openai.api_key = os.getenv("OPENAI_API_KEY")
18
+ if not openai.api_key:
19
+ st.error("❌ OPENAI_API_KEY not set in Settings → Secrets.")
20
+ st.stop()
21
+
22
+ # — Sidebar CSV upload
23
  st.sidebar.header("Upload CSV File")
24
  uploaded_file = st.sidebar.file_uploader("Choose a CSV file", type="csv")
25
 
 
27
  try:
28
  df = pd.read_csv(uploaded_file)
29
  st.sidebar.success("File uploaded successfully!")
30
+ st.sidebar.write("Preview:")
31
  st.sidebar.dataframe(df.head())
 
 
32
  except Exception as e:
33
  st.sidebar.error(f"Error reading file: {e}")
34
  df = None
 
35
  else:
36
  df = None
 
37
 
 
38
  if df is not None:
39
  st.markdown(f"**Loaded CSV:** {df.shape[0]} rows × {df.shape[1]} columns")
40
 
41
+ @st.cache_data(show_spinner=False)
42
+ def build_row_embeddings(df: pd.DataFrame):
43
+ # Serialize each row to a compact JSON string
44
+ texts = df.apply(lambda row: row.to_json(), axis=1).tolist()
45
+
46
+ # Batch‐call embeddings
47
+ all_embs = []
48
+ for i in range(0, len(texts), 100):
49
+ batch = texts[i : i + 100]
50
+ resp = openai.Embedding.create(model="text-embedding-ada-002", input=batch)
51
+ all_embs.extend([d["embedding"] for d in resp["data"]])
52
+
53
+ return np.array(all_embs), texts
54
+
55
+ embeddings, row_texts = build_row_embeddings(df)
56
+
57
  # — Prompt input
58
  prompt = st.text_area(
59
  "Enter your prompt for the agent",
60
  placeholder="e.g. Which products have price > 100?",
61
+ height=150,
62
  )
63
 
64
+ # — Run Agent
65
  if st.button("Run Agent"):
 
66
  if df is None:
67
  st.error("Please upload a CSV file first.")
68
  elif not prompt.strip():
69
  st.error("Please enter a prompt.")
70
  else:
71
+ # 1) Embed the prompt
72
+ q_resp = openai.Embedding.create(model="text-embedding-ada-002", input=[prompt])
73
+ q_emb = np.array(q_resp["data"][0]["embedding"])
74
+ # 2) Compute cosine similarities
75
+ row_norms = np.linalg.norm(embeddings, axis=1)
76
+ q_norm = np.linalg.norm(q_emb)
77
+ sims = embeddings.dot(q_emb) / (row_norms * q_norm + 1e-8)
78
+ # 3) Pick top K rows (e.g. 5)
79
+ K = min(5, len(sims))
80
+ top_idxs = sims.argsort()[-K:][::-1]
81
+ relevant_rows = [row_texts[i] for i in top_idxs]
82
+
83
+ # 4) Build the messages
84
  system_msg = {
85
  "role": "system",
86
  "content": (
87
+ "You are an AI agent that reads the provided CSV rows and answers the user's query. "
88
+ "Return your answer strictly as JSON (no extra explanation)."
89
+ ),
90
  }
91
+ memory_msg = {
92
  "role": "system",
93
+ "content": "Relevant CSV rows:\n" + "\n".join(relevant_rows) + "\n<end of rows>",
94
  }
95
  user_msg = {"role": "user", "content": prompt}
96
 
97
+ # 5) Call ChatCompletion
98
+ chat = openai.ChatCompletion.create(
99
+ model="gpt-3.5-turbo",
100
+ messages=[system_msg, memory_msg, user_msg],
101
+ temperature=0,
102
+ max_tokens=1500,
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  )
104
+ answer = chat.choices[0].message.content
105
+
106
+ # 6) Extract JSON
107
+ txt = re.sub(r"```(?:json)?", "", answer).strip()
108
+ start = txt.find("{")
109
+ end = txt.rfind("}") + 1
110
+ parsed = None
111
+ if start >= 0 and end > 0:
112
+ frag = re.sub(r",\s*([}\]])", r"\1", txt[start:end])
113
+ try:
114
+ parsed = json.loads(frag)
115
+ except json.JSONDecodeError:
116
+ parsed = None
117
 
118
+ # 7) Display
119
+ if parsed is not None:
120
+ st.subheader(" JSON Output")
121
+ st.json(parsed)
122
  else:
123
+ st.subheader("🔍 Raw Output")
124
+ st.text(answer)