hardbyte / qabot

CLI based natural language queries on local or remote data
Apache License 2.0
238 stars 20 forks source link

Wrapping it around flask api #2

Closed mirfan899 closed 1 year ago

mirfan899 commented 1 year ago

Hi, I tried to wrap it around flask api but got this error. Here is my code.

from flask import Flask, request
from flask_restful import Resource, Api
from flask_restful import reqparse
from sqlalchemy import create_engine, text
from qabot.agent import create_agent_executor
from qabot.config import Settings
from qabot.caching import configure_caching
from qabot.duckdb_manual_data_loader import create_duckdb_from_files
import werkzeug
from werkzeug.utils import secure_filename
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = "./uploads"
api = Api(app, prefix="/api/v1")

parser = reqparse.RequestParser()
parser.add_argument('files', type=werkzeug.datastructures.FileStorage, location='files')
parser.add_argument('query', type=str, location='form')
settings = Settings()
ALLOWED_EXTENSIONS = {'csv'}

database_engine = create_engine("duckdb:///:memory:")
agent = create_agent_executor(
                database_engine=database_engine,
                tables=None,
                return_intermediate_steps=False,
                verbose=False
            )

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

class Query(Resource):
    def get(self):
        return {"message": "Welcome to Danish Sentiment API", "status": 200}

    def post(self):
        args = parser.parse_args()
        query = args['query']
        if query:
            result = agent(query)
            return result['output']
        else:
            return {"Error": "There is an issue with the query..."}

class Upload(Resource):
    def post(self):
        files = request.files.getlist("files")

        for f in files:
            if f and allowed_file(f.filename):
                filename = secure_filename(f.filename)
                path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
                f.save(path)
                create_duckdb_from_files([path])
                configure_caching(settings.QABOT_CACHE_DATABASE_URI)
            return {"Message": "Data loaded..."}
        else:
            return {"Error": "There is an issue with your request..."}

api.add_resource(Query, "/query")
api.add_resource(Upload, "/upload")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=False)

Error:

> Entering new AgentExecutor chain...
We need to find the number of passengers who survived, grouped by gender.
Action: Show Tables
Action Input: 
[2023-03-06 05:46:15,578] ERROR in app: Exception on /api/v1/query [POST]
Traceback (most recent call last):
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/flask/app.py", line 1823, in full_dispatch_request
    rv = self.dispatch_request()
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/flask_restful/__init__.py", line 467, in wrapper
    resp = resource(*args, **kwargs)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/flask/views.py", line 107, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/flask_restful/__init__.py", line 582, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/root/QABotAPI/api.py", line 45, in post
    result = agent(query)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/chains/base.py", line 168, in __call__
    raise e
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/chains/base.py", line 165, in __call__
    outputs = self._call(inputs)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/agents/agent.py", line 503, in _call
    next_step_output = self._take_next_step(
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/agents/agent.py", line 420, in _take_next_step
    observation = tool.run(
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/tools/base.py", line 71, in run
    raise e
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/tools/base.py", line 68, in run
    observation = self._run(tool_input)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/langchain/agents/tools.py", line 17, in _run
    return self.func(tool_input)
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/qabot/agent.py", line 70, in <lambda>
    func=lambda _: run_sql_catch_error(database_engine, "show tables;"),
  File "/root/.pyenv/versions/3.10.8/envs/QABotAPI/lib/python3.10/site-packages/qabot/duckdb_query.py", line 13, in run_sql_catch_error
    output = conn.sql(sql)
AttributeError: 'Engine' object has no attribute 'sql'

here is my post request.

curl --location --request POST '127.0.0.1:5000/api/v1/query' --form 'query="how many passengers survived by gender?"'
hardbyte commented 1 year ago

Great idea! It looks to me like you're using an old version. I've dropped sqlalchemy in favour of a more native connection to duckdb.

mirfan899 commented 1 year ago

same error with latest version.