WebashalarForML commited on
Commit
942ac66
·
verified ·
1 Parent(s): d7bfcac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -68
app.py CHANGED
@@ -1,6 +1,7 @@
1
- from flask import Flask, render_template, request, redirect, url_for, flash
2
  from flask_socketio import SocketIO
3
  import os
 
4
  from dotenv import load_dotenv
5
  from werkzeug.utils import secure_filename
6
 
@@ -34,6 +35,8 @@ os.environ["MISTRAL_API_KEY"] = os.getenv("MISTRAL_API_KEY")
34
  # Flask and SocketIO setup
35
  flask_app = Flask(__name__)
36
  flask_app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
 
 
37
  socketio = SocketIO(flask_app, cors_allowed_origins="*")
38
 
39
  # Global state
@@ -41,16 +44,28 @@ agent_app = None
41
  abs_file_path = None
42
 
43
  def create_agent_app(db_path: str):
44
- from langchain_groq import ChatGroq
45
- llm = ChatGroq(model="llama3-70b-8192")
 
 
 
 
46
 
47
  abs_db_path = os.path.abspath(db_path)
48
- db_instance = SQLDatabase.from_uri(f"sqlite:///{abs_db_path}")
 
 
 
 
49
 
50
  @tool
51
  def db_query_tool(query: str) -> str:
52
- result = db_instance.run_no_throw(query)
53
- return result or "Error: Query failed. Please rewrite your query and try again."
 
 
 
 
54
 
55
  class SubmitFinalAnswer(BaseModel):
56
  final_answer: str = Field(...)
@@ -58,18 +73,26 @@ def create_agent_app(db_path: str):
58
  class State(TypedDict):
59
  messages: Annotated[list[AnyMessage], add_messages]
60
 
61
- query_check = ChatPromptTemplate.from_messages([
62
- ("system", "You are a SQL expert. Fix common issues in SQLite queries."),
63
- ("placeholder", "{messages}")
64
- ]) | llm.bind_tools([db_query_tool])
65
-
66
- query_gen = ChatPromptTemplate.from_messages([
67
- ("system", "You are a SQL expert. Generate SQLite query and return answer using SubmitFinalAnswer tool."),
68
- ("placeholder", "{messages}")
69
- ]) | llm.bind_tools([SubmitFinalAnswer])
70
-
71
- toolkit = SQLDatabaseToolkit(db=db_instance, llm=llm)
72
- tools_instance = toolkit.get_tools()
 
 
 
 
 
 
 
 
73
 
74
  def first_tool_call(state: State):
75
  return {"messages": [AIMessage(content="", tool_calls=[{"name": "sql_db_list_tables", "args": {}, "id": "tool_abcd123"}])]}
@@ -84,7 +107,11 @@ def create_agent_app(db_path: str):
84
  return ToolNode(tools_list).with_fallbacks([RunnableLambda(handle_tool_error)], exception_key="error")
85
 
86
  def query_gen_node(state: State):
87
- message = query_gen.invoke(state)
 
 
 
 
88
  tool_messages = []
89
  if message.tool_calls:
90
  for tc in message.tool_calls:
@@ -114,7 +141,7 @@ def create_agent_app(db_path: str):
114
  workflow.add_node("first_tool_call", first_tool_call)
115
  workflow.add_node("list_tables_tool", create_tool_node_with_fallback([list_tool]))
116
  workflow.add_node("get_schema_tool", create_tool_node_with_fallback([schema_tool]))
117
- # Corrected the unterminated string literal in the lambda function below:
118
  workflow.add_node("model_get_schema", lambda s: {"messages": [model_get_schema.invoke(s["messages"])]})
119
  workflow.add_node("query_gen", query_gen_node)
120
  workflow.add_node("correct_query", model_check_query)
@@ -133,87 +160,106 @@ def create_agent_app(db_path: str):
133
 
134
  @flask_app.route("/files/<path:filename>")
135
  def uploaded_file(filename):
136
- return send_from_directory(flask_app.config['UPLOAD_FOLDER'], filename)
 
 
 
 
 
137
  # -------------------------------------------------------------------------
138
  # Helper: run_agent runs the agent with the given prompt.
139
  # -------------------------------------------------------------------------
140
-
141
  def run_agent(prompt, socketio):
142
- global agent_app, abs_file_path, db_path
143
  if not abs_file_path:
144
  socketio.emit("log", {"message": "[ERROR]: No DB file uploaded."})
145
  socketio.emit("final", {"message": "No database available. Please upload one and try again."})
 
146
  return
147
  try:
148
  # Lazy agent initialization: use the previously uploaded DB.
149
  if agent_app is None:
150
- print("[INFO]: Initializing agent for the first time...")
151
  agent_app = create_agent_app(abs_file_path)
152
  socketio.emit("log", {"message": "[INFO]: Agent initialized."})
 
153
  query = {"messages": [("user", prompt)]}
154
  result = agent_app.invoke(query)
155
  try:
156
  result = result["messages"][-1].tool_calls[0]["args"]["final_answer"]
157
- except Exception:
158
  result = "Query failed or no valid answer found."
159
- print("final_answer------>", result)
160
  socketio.emit("final", {"message": result})
161
  except Exception as e:
162
- print(f"[ERROR]: {str(e)}")
163
- socketio.emit("log", {"message": f"[ERROR]: {str(e)}"})
164
  socketio.emit("final", {"message": "Generation failed."})
 
 
 
165
  # -------------------------------------------------------------------------
166
  # Route: index page.
167
  # -------------------------------------------------------------------------
168
-
169
  @flask_app.route("/")
170
  def index():
171
  return render_template("index.html")
 
172
  # -------------------------------------------------------------------------
173
  # Route: generate (POST) – receives a prompt and runs the agent.
174
  # -------------------------------------------------------------------------
175
-
176
  @flask_app.route("/generate", methods=["POST"])
177
  def generate():
178
  try:
179
- socketio.emit("log", {"message": "[STEP]: Entering query_gen..."})
180
  data = request.json
181
  prompt = data.get("prompt", "")
182
  socketio.emit("log", {"message": f"[INFO]: Received prompt: {prompt}"})
183
  thread = threading.Thread(target=run_agent, args=(prompt, socketio))
184
  socketio.emit("log", {"message": f"[INFO]: Starting thread: {thread}"})
185
  thread.start()
 
186
  return "OK", 200
187
  except Exception as e:
188
- print(f"[ERROR]: {str(e)}")
189
- socketio.emit("log", {"message": f"[ERROR]: {str(e)}"})
 
190
  return "ERROR", 500
 
191
  # -------------------------------------------------------------------------
192
  # Route: upload (GET/POST) – handles uploading the SQLite DB file.
193
  # -------------------------------------------------------------------------
194
-
195
  @flask_app.route("/upload", methods=["GET", "POST"])
196
  def upload():
197
- global abs_file_path, agent_app, db_path
198
  try:
199
  if request.method == "POST":
200
  file = request.files.get("file")
201
  if not file:
202
- print("No file uploaded")
203
  return "No file uploaded", 400
204
  filename = secure_filename(file.filename)
205
  if filename.endswith('.db'):
206
  db_path = os.path.join(flask_app.config['UPLOAD_FOLDER'], "uploaded.db")
207
- print("Saving file to:", db_path)
208
- file.save(db_path)
209
- abs_file_path = os.path.abspath(db_path) # Save it here; agent init will occur on first query.
210
- print(f"[INFO]: File '{filename}' uploaded. Agent will be initialized on first query.")
211
- socketio.emit("log", {"message": f"[INFO]: Database file '{filename}' uploaded."})
212
- return redirect(url_for("index"))
 
 
 
 
 
 
 
 
213
  return render_template("upload.html")
214
  except Exception as e:
215
- print(f"[ERROR]: {str(e)}")
216
- socketio.emit("log", {"message": f"[ERROR]: {str(e)}"})
 
217
  return render_template("upload.html")
218
 
219
  @socketio.on("user_input")
@@ -221,31 +267,9 @@ def handle_user_input(data):
221
  prompt = data.get("message")
222
  if not prompt:
223
  socketio.emit("log", {"message": "[ERROR]: Empty prompt."})
 
224
  return
225
- run_agent(prompt)
226
-
227
- '''
228
- def run_agent(prompt):
229
- global agent_app, abs_file_path
230
- if not abs_file_path:
231
- socketio.emit("final", {"message": "No DB uploaded."})
232
- return
233
- try:
234
- if agent_app is None:
235
- agent_app = create_agent_app(abs_file_path)
236
- socketio.emit("log", {"message": "[INFO]: Agent initialized."})
237
-
238
- query = {"messages": [("user", prompt)]}
239
- result = agent_app.invoke(query)
240
- try:
241
- result = result["messages"][-1].tool_calls[0]["args"]["final_answer"]
242
- except Exception:
243
- result = "Query failed or no valid answer found."
244
- socketio.emit("final", {"message": result})
245
- except Exception as e:
246
- socketio.emit("log", {"message": f"[ERROR]: {str(e)}"})
247
- socketio.emit("final", {"message": "Generation failed."})
248
- '''
249
 
250
  # Expose the Flask app as "app" for Gunicorn
251
  app = flask_app
 
1
+ from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
2
  from flask_socketio import SocketIO
3
  import os
4
+ import threading
5
  from dotenv import load_dotenv
6
  from werkzeug.utils import secure_filename
7
 
 
35
  # Flask and SocketIO setup
36
  flask_app = Flask(__name__)
37
  flask_app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
38
+ # Set secret key for flash messages:
39
+ flask_app.config['SECRET_KEY'] = os.getenv("FLASK_SECRET_KEY", "mysecretkey")
40
  socketio = SocketIO(flask_app, cors_allowed_origins="*")
41
 
42
  # Global state
 
44
  abs_file_path = None
45
 
46
  def create_agent_app(db_path: str):
47
+ try:
48
+ from langchain_groq import ChatGroq
49
+ llm = ChatGroq(model="llama3-70b-8192")
50
+ except Exception as e:
51
+ flash(f"[ERROR]: Failed to initialize ChatGroq: {e}", "error")
52
+ raise
53
 
54
  abs_db_path = os.path.abspath(db_path)
55
+ try:
56
+ db_instance = SQLDatabase.from_uri(f"sqlite:///{abs_db_path}")
57
+ except Exception as e:
58
+ flash(f"[ERROR]: Failed to connect to DB: {e}", "error")
59
+ raise
60
 
61
  @tool
62
  def db_query_tool(query: str) -> str:
63
+ try:
64
+ result = db_instance.run_no_throw(query)
65
+ return result or "Error: Query failed. Please rewrite your query and try again."
66
+ except Exception as e:
67
+ flash(f"[ERROR]: Exception during query execution: {e}", "error")
68
+ return f"Error: {str(e)}"
69
 
70
  class SubmitFinalAnswer(BaseModel):
71
  final_answer: str = Field(...)
 
73
  class State(TypedDict):
74
  messages: Annotated[list[AnyMessage], add_messages]
75
 
76
+ try:
77
+ query_check = ChatPromptTemplate.from_messages([
78
+ ("system", "You are a SQL expert. Fix common issues in SQLite queries."),
79
+ ("placeholder", "{messages}")
80
+ ]) | llm.bind_tools([db_query_tool])
81
+
82
+ query_gen = ChatPromptTemplate.from_messages([
83
+ ("system", "You are a SQL expert. Generate SQLite query and return answer using SubmitFinalAnswer tool."),
84
+ ("placeholder", "{messages}")
85
+ ]) | llm.bind_tools([SubmitFinalAnswer])
86
+ except Exception as e:
87
+ flash(f"[ERROR]: Failed to create prompt templates: {e}", "error")
88
+ raise
89
+
90
+ try:
91
+ toolkit = SQLDatabaseToolkit(db=db_instance, llm=llm)
92
+ tools_instance = toolkit.get_tools()
93
+ except Exception as e:
94
+ flash(f"[ERROR]: Failed to initialize SQL toolkit: {e}", "error")
95
+ raise
96
 
97
  def first_tool_call(state: State):
98
  return {"messages": [AIMessage(content="", tool_calls=[{"name": "sql_db_list_tables", "args": {}, "id": "tool_abcd123"}])]}
 
107
  return ToolNode(tools_list).with_fallbacks([RunnableLambda(handle_tool_error)], exception_key="error")
108
 
109
  def query_gen_node(state: State):
110
+ try:
111
+ message = query_gen.invoke(state)
112
+ except Exception as e:
113
+ flash(f"[ERROR]: Exception in query_gen_node: {e}", "error")
114
+ raise
115
  tool_messages = []
116
  if message.tool_calls:
117
  for tc in message.tool_calls:
 
141
  workflow.add_node("first_tool_call", first_tool_call)
142
  workflow.add_node("list_tables_tool", create_tool_node_with_fallback([list_tool]))
143
  workflow.add_node("get_schema_tool", create_tool_node_with_fallback([schema_tool]))
144
+ # Fixed unterminated string literal:
145
  workflow.add_node("model_get_schema", lambda s: {"messages": [model_get_schema.invoke(s["messages"])]})
146
  workflow.add_node("query_gen", query_gen_node)
147
  workflow.add_node("correct_query", model_check_query)
 
160
 
161
  @flask_app.route("/files/<path:filename>")
162
  def uploaded_file(filename):
163
+ try:
164
+ return send_from_directory(flask_app.config['UPLOAD_FOLDER'], filename)
165
+ except Exception as e:
166
+ flash(f"[ERROR]: Could not send file: {str(e)}", "error")
167
+ return redirect(url_for("index"))
168
+
169
  # -------------------------------------------------------------------------
170
  # Helper: run_agent runs the agent with the given prompt.
171
  # -------------------------------------------------------------------------
 
172
  def run_agent(prompt, socketio):
173
+ global agent_app, abs_file_path
174
  if not abs_file_path:
175
  socketio.emit("log", {"message": "[ERROR]: No DB file uploaded."})
176
  socketio.emit("final", {"message": "No database available. Please upload one and try again."})
177
+ flash("No database available. Please upload one and try again.", "error")
178
  return
179
  try:
180
  # Lazy agent initialization: use the previously uploaded DB.
181
  if agent_app is None:
182
+ socketio.emit("log", {"message": "[INFO]: Initializing agent for the first time..."})
183
  agent_app = create_agent_app(abs_file_path)
184
  socketio.emit("log", {"message": "[INFO]: Agent initialized."})
185
+ flash("Agent initialized.", "info")
186
  query = {"messages": [("user", prompt)]}
187
  result = agent_app.invoke(query)
188
  try:
189
  result = result["messages"][-1].tool_calls[0]["args"]["final_answer"]
190
+ except Exception as e:
191
  result = "Query failed or no valid answer found."
192
+ flash("Query failed or no valid answer found.", "warning")
193
  socketio.emit("final", {"message": result})
194
  except Exception as e:
195
+ error_message = f"Generation failed: {str(e)}"
196
+ socketio.emit("log", {"message": f"[ERROR]: {error_message}"})
197
  socketio.emit("final", {"message": "Generation failed."})
198
+ flash(error_message, "error")
199
+ traceback.print_exc()
200
+
201
  # -------------------------------------------------------------------------
202
  # Route: index page.
203
  # -------------------------------------------------------------------------
 
204
  @flask_app.route("/")
205
  def index():
206
  return render_template("index.html")
207
+
208
  # -------------------------------------------------------------------------
209
  # Route: generate (POST) – receives a prompt and runs the agent.
210
  # -------------------------------------------------------------------------
 
211
  @flask_app.route("/generate", methods=["POST"])
212
  def generate():
213
  try:
214
+ socketio.emit("log", {"message": "[STEP]: Entering query generation..."})
215
  data = request.json
216
  prompt = data.get("prompt", "")
217
  socketio.emit("log", {"message": f"[INFO]: Received prompt: {prompt}"})
218
  thread = threading.Thread(target=run_agent, args=(prompt, socketio))
219
  socketio.emit("log", {"message": f"[INFO]: Starting thread: {thread}"})
220
  thread.start()
221
+ flash("Query submitted successfully.", "info")
222
  return "OK", 200
223
  except Exception as e:
224
+ error_message = f"[ERROR]: {str(e)}"
225
+ socketio.emit("log", {"message": error_message})
226
+ flash(error_message, "error")
227
  return "ERROR", 500
228
+
229
  # -------------------------------------------------------------------------
230
  # Route: upload (GET/POST) – handles uploading the SQLite DB file.
231
  # -------------------------------------------------------------------------
 
232
  @flask_app.route("/upload", methods=["GET", "POST"])
233
  def upload():
234
+ global abs_file_path, agent_app
235
  try:
236
  if request.method == "POST":
237
  file = request.files.get("file")
238
  if not file:
239
+ flash("No file uploaded.", "error")
240
  return "No file uploaded", 400
241
  filename = secure_filename(file.filename)
242
  if filename.endswith('.db'):
243
  db_path = os.path.join(flask_app.config['UPLOAD_FOLDER'], "uploaded.db")
244
+ try:
245
+ file.save(db_path)
246
+ abs_file_path = os.path.abspath(db_path) # Save it here; agent init will occur on first query.
247
+ agent_app = None # Reset agent on upload.
248
+ flash(f"Database file '{filename}' uploaded successfully.", "info")
249
+ socketio.emit("log", {"message": f"[INFO]: Database file '{filename}' uploaded."})
250
+ return redirect(url_for("index"))
251
+ except Exception as save_err:
252
+ flash(f"Error saving file: {save_err}", "error")
253
+ socketio.emit("log", {"message": f"[ERROR]: Error saving file: {save_err}"})
254
+ return render_template("upload.html")
255
+ else:
256
+ flash("Only .db files are allowed.", "error")
257
+ return render_template("upload.html")
258
  return render_template("upload.html")
259
  except Exception as e:
260
+ error_message = f"[ERROR]: {str(e)}"
261
+ flash(error_message, "error")
262
+ socketio.emit("log", {"message": error_message})
263
  return render_template("upload.html")
264
 
265
  @socketio.on("user_input")
 
267
  prompt = data.get("message")
268
  if not prompt:
269
  socketio.emit("log", {"message": "[ERROR]: Empty prompt."})
270
+ flash("Empty prompt.", "error")
271
  return
272
+ run_agent(prompt, socketio)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
  # Expose the Flask app as "app" for Gunicorn
275
  app = flask_app