cyyeh commited on
Commit
7df9c64
Β·
1 Parent(s): ebadafa

add new page and refactor

Browse files
src/apis.py CHANGED
@@ -3,6 +3,9 @@ from typing import Optional
3
  import requests
4
 
5
 
 
 
 
6
  def ask(
7
  api_key: str,
8
  project_id: str,
@@ -12,8 +15,7 @@ def ask(
12
  sample_size: int = 1000,
13
  ) -> tuple[dict, str]:
14
  """Ask a question and get an answer with SQL and explanation."""
15
- base_url = "https://cloud.getwren.ai/api/v1"
16
- endpoint = f"{base_url}/ask"
17
  headers = {
18
  "Authorization": f"Bearer {api_key}",
19
  "Content-Type": "application/json"
@@ -44,8 +46,7 @@ def generate_sql(
44
  return_sql_dialect: bool = False,
45
  ) -> tuple[dict, str]:
46
  """Generate SQL from natural language query."""
47
- base_url = "https://cloud.getwren.ai/api/v1"
48
- endpoint = f"{base_url}/generate_sql"
49
  headers = {
50
  "Authorization": f"Bearer {api_key}",
51
  "Content-Type": "application/json"
@@ -75,8 +76,7 @@ def run_sql(
75
  limit: int = 1000,
76
  ) -> tuple[dict, str]:
77
  """Execute SQL query and return results."""
78
- base_url = "https://cloud.getwren.ai/api/v1"
79
- endpoint = f"{base_url}/run_sql"
80
  headers = {
81
  "Authorization": f"Bearer {api_key}",
82
  "Content-Type": "application/json"
@@ -107,8 +107,7 @@ def generate_summary(
107
  sample_size: int = 1000,
108
  ) -> tuple[dict, str]:
109
  """Generate a summary of query results."""
110
- base_url = "https://cloud.getwren.ai/api/v1"
111
- endpoint = f"{base_url}/generate_summary"
112
  headers = {
113
  "Authorization": f"Bearer {api_key}",
114
  "Content-Type": "application/json"
@@ -136,8 +135,7 @@ def stream_explanation(
136
  query_id: str,
137
  ) -> tuple[dict, str]:
138
  """Stream explanation for a query."""
139
- base_url = "https://cloud.getwren.ai/api/v1"
140
- endpoint = f"{base_url}/stream_explanation/{query_id}"
141
  headers = {
142
  "Authorization": f"Bearer {api_key}",
143
  "Accept": "text/event-stream",
@@ -160,8 +158,7 @@ def generate_chart(
160
  sample_size: int = 1000,
161
  ) -> tuple[dict, str]:
162
  """Generate a chart from query results."""
163
- base_url = "https://cloud.getwren.ai/api/v1"
164
- endpoint = f"{base_url}/generate_vega_chart"
165
  headers = {
166
  "Authorization": f"Bearer {api_key}",
167
  "Content-Type": "application/json"
@@ -192,8 +189,7 @@ def stream_ask(
192
  sample_size: int = 1000,
193
  ) -> tuple[dict, str]:
194
  """Stream ask endpoint for real-time responses."""
195
- base_url = "https://cloud.getwren.ai/api/v1"
196
- endpoint = f"{base_url}/stream/ask"
197
  headers = {
198
  "Authorization": f"Bearer {api_key}",
199
  "Content-Type": "application/json",
@@ -211,7 +207,7 @@ def stream_ask(
211
  try:
212
  response = requests.post(endpoint, json=payload, headers=headers, stream=True)
213
  response.raise_for_status()
214
- return response.json(), ""
215
  except requests.exceptions.RequestException as e:
216
  return {}, str(e)
217
 
@@ -225,8 +221,7 @@ def stream_generate_sql(
225
  return_sql_dialect: bool = False,
226
  ) -> tuple[dict, str]:
227
  """Stream SQL generation endpoint for real-time responses."""
228
- base_url = "https://cloud.getwren.ai/api/v1"
229
- endpoint = f"{base_url}/stream/generate_sql"
230
  headers = {
231
  "Authorization": f"Bearer {api_key}",
232
  "Content-Type": "application/json",
@@ -254,8 +249,7 @@ def get_models(
254
  project_id: str,
255
  ) -> tuple[dict, str]:
256
  """Get latest deployed models for a project."""
257
- base_url = "https://cloud.getwren.ai/api/v1"
258
- endpoint = f"{base_url}/projects/{project_id}/models"
259
  headers = {
260
  "Authorization": f"Bearer {api_key}",
261
  }
@@ -273,8 +267,7 @@ def get_instructions(
273
  project_id: str,
274
  ) -> tuple[dict, str]:
275
  """Get all instructions for a project."""
276
- base_url = "https://cloud.getwren.ai/api/v1"
277
- endpoint = f"{base_url}/projects/{project_id}/knowledge/instructions"
278
  headers = {
279
  "Authorization": f"Bearer {api_key}",
280
  }
@@ -295,8 +288,7 @@ def create_instruction(
295
  questions: Optional[list[str]] = None,
296
  ) -> tuple[dict, str]:
297
  """Create a new instruction for a project."""
298
- base_url = "https://cloud.getwren.ai/api/v1"
299
- endpoint = f"{base_url}/projects/{project_id}/knowledge/instructions"
300
  headers = {
301
  "Authorization": f"Bearer {api_key}",
302
  "Content-Type": "application/json"
@@ -324,8 +316,7 @@ def update_instruction(
324
  questions: Optional[list[str]] = None,
325
  ) -> tuple[dict, str]:
326
  """Update an existing instruction."""
327
- base_url = "https://cloud.getwren.ai/api/v1"
328
- endpoint = f"{base_url}/projects/{project_id}/knowledge/instructions/{instruction_id}"
329
  headers = {
330
  "Authorization": f"Bearer {api_key}",
331
  "Content-Type": "application/json"
@@ -350,8 +341,7 @@ def delete_instruction(
350
  instruction_id: str,
351
  ) -> str:
352
  """Delete an instruction."""
353
- base_url = "https://cloud.getwren.ai/api/v1"
354
- endpoint = f"{base_url}/projects/{project_id}/knowledge/instructions/{instruction_id}"
355
  headers = {
356
  "Authorization": f"Bearer {api_key}",
357
  }
@@ -369,8 +359,7 @@ def get_sql_pairs(
369
  project_id: str,
370
  ) -> tuple[dict, str]:
371
  """Get all SQL pairs for a project."""
372
- base_url = "https://cloud.getwren.ai/api/v1"
373
- endpoint = f"{base_url}/projects/{project_id}/knowledge/sql_pairs"
374
  headers = {
375
  "Authorization": f"Bearer {api_key}",
376
  }
@@ -390,8 +379,7 @@ def create_sql_pair(
390
  sql: str,
391
  ) -> tuple[dict, str]:
392
  """Create a new SQL pair for a project."""
393
- base_url = "https://cloud.getwren.ai/api/v1"
394
- endpoint = f"{base_url}/projects/{project_id}/knowledge/sql_pairs"
395
  headers = {
396
  "Authorization": f"Bearer {api_key}",
397
  "Content-Type": "application/json"
@@ -417,8 +405,7 @@ def update_sql_pair(
417
  sql: str,
418
  ) -> tuple[dict, str]:
419
  """Update an existing SQL pair."""
420
- base_url = "https://cloud.getwren.ai/api/v1"
421
- endpoint = f"{base_url}/projects/{project_id}/knowledge/sql_pairs/{sql_pair_id}"
422
  headers = {
423
  "Authorization": f"Bearer {api_key}",
424
  "Content-Type": "application/json"
@@ -442,8 +429,7 @@ def delete_sql_pair(
442
  sql_pair_id: str,
443
  ) -> str:
444
  """Delete an SQL pair."""
445
- base_url = "https://cloud.getwren.ai/api/v1"
446
- endpoint = f"{base_url}/projects/{project_id}/knowledge/sql_pairs/{sql_pair_id}"
447
  headers = {
448
  "Authorization": f"Bearer {api_key}",
449
  }
 
3
  import requests
4
 
5
 
6
+ API_BASE_URL = "https://cloud.getwren.ai/api/v1"
7
+
8
+
9
  def ask(
10
  api_key: str,
11
  project_id: str,
 
15
  sample_size: int = 1000,
16
  ) -> tuple[dict, str]:
17
  """Ask a question and get an answer with SQL and explanation."""
18
+ endpoint = f"{API_BASE_URL}/ask"
 
19
  headers = {
20
  "Authorization": f"Bearer {api_key}",
21
  "Content-Type": "application/json"
 
46
  return_sql_dialect: bool = False,
47
  ) -> tuple[dict, str]:
48
  """Generate SQL from natural language query."""
49
+ endpoint = f"{API_BASE_URL}/generate_sql"
 
50
  headers = {
51
  "Authorization": f"Bearer {api_key}",
52
  "Content-Type": "application/json"
 
76
  limit: int = 1000,
77
  ) -> tuple[dict, str]:
78
  """Execute SQL query and return results."""
79
+ endpoint = f"{API_BASE_URL}/run_sql"
 
80
  headers = {
81
  "Authorization": f"Bearer {api_key}",
82
  "Content-Type": "application/json"
 
107
  sample_size: int = 1000,
108
  ) -> tuple[dict, str]:
109
  """Generate a summary of query results."""
110
+ endpoint = f"{API_BASE_URL}/generate_summary"
 
111
  headers = {
112
  "Authorization": f"Bearer {api_key}",
113
  "Content-Type": "application/json"
 
135
  query_id: str,
136
  ) -> tuple[dict, str]:
137
  """Stream explanation for a query."""
138
+ endpoint = f"{API_BASE_URL}/stream_explanation/{query_id}"
 
139
  headers = {
140
  "Authorization": f"Bearer {api_key}",
141
  "Accept": "text/event-stream",
 
158
  sample_size: int = 1000,
159
  ) -> tuple[dict, str]:
160
  """Generate a chart from query results."""
161
+ endpoint = f"{API_BASE_URL}/generate_vega_chart"
 
162
  headers = {
163
  "Authorization": f"Bearer {api_key}",
164
  "Content-Type": "application/json"
 
189
  sample_size: int = 1000,
190
  ) -> tuple[dict, str]:
191
  """Stream ask endpoint for real-time responses."""
192
+ endpoint = f"{API_BASE_URL}/stream/ask"
 
193
  headers = {
194
  "Authorization": f"Bearer {api_key}",
195
  "Content-Type": "application/json",
 
207
  try:
208
  response = requests.post(endpoint, json=payload, headers=headers, stream=True)
209
  response.raise_for_status()
210
+ return response, ""
211
  except requests.exceptions.RequestException as e:
212
  return {}, str(e)
213
 
 
221
  return_sql_dialect: bool = False,
222
  ) -> tuple[dict, str]:
223
  """Stream SQL generation endpoint for real-time responses."""
224
+ endpoint = f"{API_BASE_URL}/stream/generate_sql"
 
225
  headers = {
226
  "Authorization": f"Bearer {api_key}",
227
  "Content-Type": "application/json",
 
249
  project_id: str,
250
  ) -> tuple[dict, str]:
251
  """Get latest deployed models for a project."""
252
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/models"
 
253
  headers = {
254
  "Authorization": f"Bearer {api_key}",
255
  }
 
267
  project_id: str,
268
  ) -> tuple[dict, str]:
269
  """Get all instructions for a project."""
270
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/instructions"
 
271
  headers = {
272
  "Authorization": f"Bearer {api_key}",
273
  }
 
288
  questions: Optional[list[str]] = None,
289
  ) -> tuple[dict, str]:
290
  """Create a new instruction for a project."""
291
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/instructions"
 
292
  headers = {
293
  "Authorization": f"Bearer {api_key}",
294
  "Content-Type": "application/json"
 
316
  questions: Optional[list[str]] = None,
317
  ) -> tuple[dict, str]:
318
  """Update an existing instruction."""
319
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/instructions/{instruction_id}"
 
320
  headers = {
321
  "Authorization": f"Bearer {api_key}",
322
  "Content-Type": "application/json"
 
341
  instruction_id: str,
342
  ) -> str:
343
  """Delete an instruction."""
344
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/instructions/{instruction_id}"
 
345
  headers = {
346
  "Authorization": f"Bearer {api_key}",
347
  }
 
359
  project_id: str,
360
  ) -> tuple[dict, str]:
361
  """Get all SQL pairs for a project."""
362
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/sql_pairs"
 
363
  headers = {
364
  "Authorization": f"Bearer {api_key}",
365
  }
 
379
  sql: str,
380
  ) -> tuple[dict, str]:
381
  """Create a new SQL pair for a project."""
382
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/sql_pairs"
 
383
  headers = {
384
  "Authorization": f"Bearer {api_key}",
385
  "Content-Type": "application/json"
 
405
  sql: str,
406
  ) -> tuple[dict, str]:
407
  """Update an existing SQL pair."""
408
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/sql_pairs/{sql_pair_id}"
 
409
  headers = {
410
  "Authorization": f"Bearer {api_key}",
411
  "Content-Type": "application/json"
 
429
  sql_pair_id: str,
430
  ) -> str:
431
  """Delete an SQL pair."""
432
+ endpoint = f"{API_BASE_URL}/projects/{project_id}/knowledge/sql_pairs/{sql_pair_id}"
 
433
  headers = {
434
  "Authorization": f"Bearer {api_key}",
435
  }
src/pages/1_Query_And_Answer.py CHANGED
@@ -23,7 +23,11 @@ def main():
23
  # Sidebar for API configuration
24
  with st.sidebar:
25
  st.header("πŸ”§ Configuration")
26
- # Sample size configuration
 
 
 
 
27
  sample_size = st.slider(
28
  "Sample Size",
29
  min_value=100,
@@ -86,7 +90,7 @@ def main():
86
  # Generate response using ask API
87
  with st.chat_message("assistant"):
88
  with st.spinner("Generating answer..."):
89
- ask_response, error = ask(api_key, project_id, prompt, st.session_state.qa_thread_id, sample_size=sample_size)
90
 
91
  if ask_response:
92
  answer = ask_response.get("summary", "")
 
23
  # Sidebar for API configuration
24
  with st.sidebar:
25
  st.header("πŸ”§ Configuration")
26
+ language = st.text_input(
27
+ "Language",
28
+ "English",
29
+ help="Language of the response. Default is English."
30
+ )
31
  sample_size = st.slider(
32
  "Sample Size",
33
  min_value=100,
 
90
  # Generate response using ask API
91
  with st.chat_message("assistant"):
92
  with st.spinner("Generating answer..."):
93
+ ask_response, error = ask(api_key, project_id, prompt, st.session_state.qa_thread_id, sample_size=sample_size, language=language)
94
 
95
  if ask_response:
96
  answer = ask_response.get("summary", "")
src/pages/2_Chart_Generation.py CHANGED
@@ -22,7 +22,6 @@ def main():
22
  # Sidebar for API configuration
23
  with st.sidebar:
24
  st.header("πŸ”§ Configuration")
25
- # Sample size configuration
26
  sample_size = st.slider(
27
  "Chart Sample Size",
28
  min_value=100,
 
22
  # Sidebar for API configuration
23
  with st.sidebar:
24
  st.header("πŸ”§ Configuration")
 
25
  sample_size = st.slider(
26
  "Chart Sample Size",
27
  min_value=100,
src/pages/5_Ask_Streaming.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import requests
4
+ import json
5
+ import time
6
+ from typing import Iterator, Dict, Any
7
+
8
+ from apis import stream_ask, run_sql
9
+ from utils import format_sql
10
+
11
+
12
+ def stream_ask_api(api_key: str, project_id: str, question: str, thread_id: str = "",
13
+ language: str = "English", sample_size: int = 1000) -> Iterator[Dict[str, Any]]:
14
+ """Stream ask endpoint with proper SSE handling."""
15
+ try:
16
+ response, error = stream_ask(api_key, project_id, question, thread_id, language, sample_size)
17
+ if error:
18
+ raise Exception(error)
19
+
20
+ for line in response.iter_lines():
21
+ if line:
22
+ line_str = line.decode('utf-8')
23
+ if line_str.startswith('data: '):
24
+ data_str = line_str[6:] # Remove 'data: ' prefix
25
+ if data_str.strip() == '[DONE]':
26
+ break
27
+ try:
28
+ data = json.loads(data_str)
29
+ yield data
30
+ except json.JSONDecodeError:
31
+ continue
32
+ except requests.exceptions.RequestException as e:
33
+ yield {"error": str(e)}
34
+
35
+
36
+ def main():
37
+ st.title("πŸ’¬ Wren AI Cloud API Demo - Ask Streaming")
38
+
39
+ if "api_key" not in st.session_state or "project_id" not in st.session_state:
40
+ st.error("Please enter your API Key and Project ID in the sidebar of Home page to get started.")
41
+ return
42
+ if not st.session_state.api_key or not st.session_state.project_id:
43
+ st.error("Please enter your API Key and Project ID in the sidebar of Home page to get started.")
44
+ return
45
+
46
+ api_key = st.session_state.api_key
47
+ project_id = st.session_state.project_id
48
+
49
+ st.markdown('Using APIs: [Stream Ask](https://wrenai.readme.io/reference/post_stream-ask-1)')
50
+
51
+ # Sidebar for API configuration
52
+ with st.sidebar:
53
+ st.header("πŸ”§ Configuration")
54
+ language = st.text_input(
55
+ "Language",
56
+ "English",
57
+ help="Language of the response. Default is English."
58
+ )
59
+ sample_size = st.slider(
60
+ "Sample Size",
61
+ min_value=100,
62
+ max_value=10000,
63
+ value=1000,
64
+ step=100,
65
+ help="Number of data points to include in results"
66
+ )
67
+
68
+ # Initialize chat history
69
+ if "streaming_messages" not in st.session_state:
70
+ st.session_state.streaming_messages = []
71
+ if "streaming_thread_id" not in st.session_state:
72
+ st.session_state.streaming_thread_id = ""
73
+
74
+ # Display chat history
75
+ for message in st.session_state.streaming_messages:
76
+ with st.chat_message(message["role"]):
77
+ if message["role"] == "user":
78
+ st.write(message["content"])
79
+ else:
80
+ st.write(message["content"])
81
+ if "sql" in message:
82
+ with st.expander("= Generated SQL Query", expanded=False):
83
+ st.code(format_sql(message["sql"]), language="sql")
84
+
85
+ # Add button to run SQL
86
+ if st.button("πŸ”„ Run SQL Query", key=f"run_sql_{message.get('message_id', 'unknown')}"):
87
+ with st.spinner("Executing SQL query..."):
88
+ sql_result, error = run_sql(api_key, project_id, message["sql"], st.session_state.streaming_thread_id, sample_size)
89
+
90
+ if sql_result:
91
+ data = sql_result.get("records", [])
92
+ if data:
93
+ # Convert to DataFrame for better display
94
+ df = pd.DataFrame(data)
95
+ st.success("SQL query executed successfully!")
96
+ st.dataframe(df, use_container_width=True)
97
+ else:
98
+ st.info("Query executed but returned no data.")
99
+ else:
100
+ st.error(f"Error executing SQL: {error}")
101
+
102
+ # Chat input
103
+ if prompt := st.chat_input("Ask a question about your data..."):
104
+ # Add user message to chat history
105
+ st.session_state.streaming_messages.append({"role": "user", "content": prompt})
106
+
107
+ # Display user message
108
+ with st.chat_message("user"):
109
+ st.write(prompt)
110
+
111
+ # Generate response using stream ask API
112
+ with st.chat_message("assistant"):
113
+ # Create containers for streaming updates
114
+ status_container = st.empty()
115
+ progress_container = st.empty()
116
+ content_container = st.empty()
117
+
118
+ final_answer = ""
119
+ final_sql = ""
120
+ current_state = ""
121
+
122
+ # Stream the response
123
+ try:
124
+ for event in stream_ask_api(api_key, project_id, prompt, st.session_state.streaming_thread_id, sample_size=sample_size, language=language):
125
+ if "error" in event:
126
+ st.error(f"Error: {event['error']}")
127
+ break
128
+
129
+ # Handle different event types
130
+ if event.get("type") == "state":
131
+ current_state = event.get("data", {}).get("state", "")
132
+ rephrased_question = event.get("data", {}).get("rephrasedQuestion", "")
133
+ intent_reasoning = event.get("data", {}).get("intentReasoning", "")
134
+ retrieved_tables = event.get("data", {}).get("retrievedTables", "")
135
+ sql_generation_reasoning = event.get("data", {}).get("sqlGenerationReasoning", "")
136
+ current_state_message = f"πŸ’¬ {current_state}\n\n"
137
+ if rephrased_question:
138
+ current_state_message += f"\nRerephrased Question: \n{rephrased_question}\n"
139
+ if intent_reasoning:
140
+ current_state_message += f"\nIntent Reasoning: \n{intent_reasoning}\n"
141
+ if retrieved_tables:
142
+ current_state_message += f"\nRetrieved Tables: \n{retrieved_tables}\n"
143
+ if sql_generation_reasoning:
144
+ current_state_message += f"\nSQL Generation Reasoning: \n{sql_generation_reasoning}\n"
145
+
146
+ status_container.info(current_state_message)
147
+ elif event.get("type") == "content_block_delta":
148
+ delta = event.get("delta", {})
149
+ if delta.get("type") == "text_delta":
150
+ final_answer += delta.get("text", "")
151
+ content_container.markdown(final_answer)
152
+
153
+ elif event.get("type") == "message_stop":
154
+ # Extract final data from the event
155
+ if "summary" in event:
156
+ final_answer = event["summary"]
157
+ if "sql" in event:
158
+ final_sql = event["sql"]
159
+ if "threadId" in event:
160
+ st.session_state.streaming_thread_id = event["threadId"]
161
+ break
162
+
163
+ # Small delay to make streaming visible
164
+ time.sleep(0.1)
165
+
166
+ # Clear status and show final result
167
+ status_container.empty()
168
+ progress_container.empty()
169
+
170
+ if final_answer:
171
+ st.toast("Answer generated successfully!", icon="πŸŽ‰")
172
+
173
+ # Create unique message ID
174
+ message_id = len(st.session_state.streaming_messages)
175
+
176
+ # Store the response
177
+ assistant_message = {
178
+ "role": "assistant",
179
+ "content": final_answer,
180
+ "message_id": message_id
181
+ }
182
+
183
+ if final_sql:
184
+ assistant_message["sql"] = final_sql
185
+
186
+ st.session_state.streaming_messages.append(assistant_message)
187
+ content_container.write(final_answer)
188
+
189
+ # Display SQL query if available
190
+ if final_sql:
191
+ with st.expander("=Generated SQL Query", expanded=False):
192
+ st.code(format_sql(final_sql), language="sql")
193
+
194
+ # Add button to run SQL
195
+ if st.button("πŸ”„ Run SQL Query", key=f"run_sql_{message_id}"):
196
+ with st.spinner("Executing SQL query..."):
197
+ sql_result, error = run_sql(api_key, project_id, final_sql, st.session_state.streaming_thread_id, sample_size)
198
+
199
+ if sql_result:
200
+ data = sql_result.get("records", [])
201
+ if data:
202
+ # Convert to DataFrame for better display
203
+ df = pd.DataFrame(data)
204
+ st.success("SQL query executed successfully!")
205
+ st.dataframe(df, use_container_width=True)
206
+ else:
207
+ st.info("Query executed but returned no data.")
208
+ else:
209
+ st.error(f"Error executing SQL: {error}")
210
+ else:
211
+ st.toast("No answer was generated. Please try rephrasing your question.", icon="πŸ€”")
212
+ assistant_message = {
213
+ "role": "assistant",
214
+ "content": "I couldn't generate an answer for your question. Please try rephrasing it or make sure it's related to your data."
215
+ }
216
+ st.session_state.streaming_messages.append(assistant_message)
217
+ content_container.write(assistant_message["content"])
218
+
219
+ except Exception as e:
220
+ st.error(f"Error during streaming: {str(e)}")
221
+ assistant_message = {
222
+ "role": "assistant",
223
+ "content": "Sorry, I couldn't process your request. Please check your API credentials and try again."
224
+ }
225
+ st.session_state.streaming_messages.append(assistant_message)
226
+ content_container.write(assistant_message["content"])
227
+
228
+ # Clear chat button
229
+ if st.sidebar.button("🧹 Clear Chat History"):
230
+ st.session_state.streaming_messages = []
231
+ st.session_state.streaming_thread_id = ""
232
+ st.rerun()
233
+
234
+
235
+ if __name__ == "__main__":
236
+ main()