MindsDB 25.9.2.0a1__py3-none-any.whl → 25.10.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of MindsDB might be problematic. Click here for more details.
- mindsdb/__about__.py +1 -1
- mindsdb/__main__.py +40 -29
- mindsdb/api/a2a/__init__.py +1 -1
- mindsdb/api/a2a/agent.py +16 -10
- mindsdb/api/a2a/common/server/server.py +7 -3
- mindsdb/api/a2a/common/server/task_manager.py +12 -5
- mindsdb/api/a2a/common/types.py +66 -0
- mindsdb/api/a2a/task_manager.py +65 -17
- mindsdb/api/common/middleware.py +10 -12
- mindsdb/api/executor/command_executor.py +51 -40
- mindsdb/api/executor/datahub/datanodes/datanode.py +2 -2
- mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +7 -13
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +101 -49
- mindsdb/api/executor/datahub/datanodes/project_datanode.py +8 -4
- mindsdb/api/executor/datahub/datanodes/system_tables.py +3 -2
- mindsdb/api/executor/exceptions.py +29 -10
- mindsdb/api/executor/planner/plan_join.py +17 -3
- mindsdb/api/executor/planner/query_prepare.py +2 -20
- mindsdb/api/executor/sql_query/sql_query.py +74 -74
- mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +1 -2
- mindsdb/api/executor/sql_query/steps/subselect_step.py +0 -1
- mindsdb/api/executor/utilities/functions.py +6 -6
- mindsdb/api/executor/utilities/sql.py +37 -20
- mindsdb/api/http/gui.py +5 -11
- mindsdb/api/http/initialize.py +75 -61
- mindsdb/api/http/namespaces/agents.py +10 -15
- mindsdb/api/http/namespaces/analysis.py +13 -20
- mindsdb/api/http/namespaces/auth.py +1 -1
- mindsdb/api/http/namespaces/chatbots.py +0 -5
- mindsdb/api/http/namespaces/config.py +15 -11
- mindsdb/api/http/namespaces/databases.py +140 -201
- mindsdb/api/http/namespaces/file.py +17 -4
- mindsdb/api/http/namespaces/handlers.py +17 -7
- mindsdb/api/http/namespaces/knowledge_bases.py +28 -7
- mindsdb/api/http/namespaces/models.py +94 -126
- mindsdb/api/http/namespaces/projects.py +13 -22
- mindsdb/api/http/namespaces/sql.py +33 -25
- mindsdb/api/http/namespaces/tab.py +27 -37
- mindsdb/api/http/namespaces/views.py +1 -1
- mindsdb/api/http/start.py +16 -10
- mindsdb/api/mcp/__init__.py +2 -1
- mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +15 -20
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +26 -50
- mindsdb/api/mysql/mysql_proxy/utilities/__init__.py +0 -1
- mindsdb/api/mysql/mysql_proxy/utilities/dump.py +8 -2
- mindsdb/integrations/handlers/byom_handler/byom_handler.py +165 -190
- mindsdb/integrations/handlers/databricks_handler/databricks_handler.py +98 -46
- mindsdb/integrations/handlers/druid_handler/druid_handler.py +32 -40
- mindsdb/integrations/handlers/file_handler/file_handler.py +7 -0
- mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +5 -2
- mindsdb/integrations/handlers/lightwood_handler/functions.py +45 -79
- mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +438 -100
- mindsdb/integrations/handlers/mssql_handler/requirements_odbc.txt +3 -0
- mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +235 -3
- mindsdb/integrations/handlers/oracle_handler/__init__.py +2 -0
- mindsdb/integrations/handlers/oracle_handler/connection_args.py +7 -1
- mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +321 -16
- mindsdb/integrations/handlers/oracle_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +14 -2
- mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +25 -12
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +2 -1
- mindsdb/integrations/handlers/statsforecast_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/statsforecast_handler/requirements_extra.txt +1 -0
- mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +4 -4
- mindsdb/integrations/handlers/zendesk_handler/zendesk_tables.py +144 -111
- mindsdb/integrations/libs/api_handler.py +10 -10
- mindsdb/integrations/libs/base.py +4 -4
- mindsdb/integrations/libs/llm/utils.py +2 -2
- mindsdb/integrations/libs/ml_handler_process/create_engine_process.py +4 -7
- mindsdb/integrations/libs/ml_handler_process/func_call_process.py +2 -7
- mindsdb/integrations/libs/ml_handler_process/learn_process.py +37 -47
- mindsdb/integrations/libs/ml_handler_process/update_engine_process.py +4 -7
- mindsdb/integrations/libs/ml_handler_process/update_process.py +2 -7
- mindsdb/integrations/libs/process_cache.py +132 -140
- mindsdb/integrations/libs/response.py +18 -12
- mindsdb/integrations/libs/vectordatabase_handler.py +26 -0
- mindsdb/integrations/utilities/files/file_reader.py +6 -7
- mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/__init__.py +1 -0
- mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/snowflake_jwt_gen.py +151 -0
- mindsdb/integrations/utilities/rag/config_loader.py +37 -26
- mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +83 -30
- mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +4 -4
- mindsdb/integrations/utilities/rag/retrievers/sql_retriever.py +55 -133
- mindsdb/integrations/utilities/rag/settings.py +58 -133
- mindsdb/integrations/utilities/rag/splitters/file_splitter.py +5 -15
- mindsdb/interfaces/agents/agents_controller.py +2 -3
- mindsdb/interfaces/agents/constants.py +0 -2
- mindsdb/interfaces/agents/litellm_server.py +34 -58
- mindsdb/interfaces/agents/mcp_client_agent.py +10 -10
- mindsdb/interfaces/agents/mindsdb_database_agent.py +5 -5
- mindsdb/interfaces/agents/run_mcp_agent.py +12 -21
- mindsdb/interfaces/chatbot/chatbot_task.py +20 -23
- mindsdb/interfaces/chatbot/polling.py +30 -18
- mindsdb/interfaces/data_catalog/data_catalog_loader.py +16 -17
- mindsdb/interfaces/data_catalog/data_catalog_reader.py +15 -4
- mindsdb/interfaces/database/data_handlers_cache.py +190 -0
- mindsdb/interfaces/database/database.py +3 -3
- mindsdb/interfaces/database/integrations.py +7 -110
- mindsdb/interfaces/database/projects.py +2 -6
- mindsdb/interfaces/database/views.py +1 -4
- mindsdb/interfaces/file/file_controller.py +6 -6
- mindsdb/interfaces/functions/controller.py +1 -1
- mindsdb/interfaces/functions/to_markdown.py +2 -2
- mindsdb/interfaces/jobs/jobs_controller.py +5 -9
- mindsdb/interfaces/jobs/scheduler.py +3 -9
- mindsdb/interfaces/knowledge_base/controller.py +244 -128
- mindsdb/interfaces/knowledge_base/evaluate.py +36 -41
- mindsdb/interfaces/knowledge_base/executor.py +11 -0
- mindsdb/interfaces/knowledge_base/llm_client.py +51 -17
- mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +40 -61
- mindsdb/interfaces/model/model_controller.py +172 -168
- mindsdb/interfaces/query_context/context_controller.py +14 -2
- mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +10 -14
- mindsdb/interfaces/skills/retrieval_tool.py +43 -50
- mindsdb/interfaces/skills/skill_tool.py +2 -2
- mindsdb/interfaces/skills/skills_controller.py +1 -4
- mindsdb/interfaces/skills/sql_agent.py +25 -19
- mindsdb/interfaces/storage/db.py +16 -6
- mindsdb/interfaces/storage/fs.py +114 -169
- mindsdb/interfaces/storage/json.py +19 -18
- mindsdb/interfaces/tabs/tabs_controller.py +49 -72
- mindsdb/interfaces/tasks/task_monitor.py +3 -9
- mindsdb/interfaces/tasks/task_thread.py +7 -9
- mindsdb/interfaces/triggers/trigger_task.py +7 -13
- mindsdb/interfaces/triggers/triggers_controller.py +47 -52
- mindsdb/migrations/migrate.py +16 -16
- mindsdb/utilities/api_status.py +58 -0
- mindsdb/utilities/config.py +68 -2
- mindsdb/utilities/exception.py +40 -1
- mindsdb/utilities/fs.py +0 -1
- mindsdb/utilities/hooks/profiling.py +17 -14
- mindsdb/utilities/json_encoder.py +24 -10
- mindsdb/utilities/langfuse.py +40 -45
- mindsdb/utilities/log.py +272 -0
- mindsdb/utilities/ml_task_queue/consumer.py +52 -58
- mindsdb/utilities/ml_task_queue/producer.py +26 -30
- mindsdb/utilities/render/sqlalchemy_render.py +22 -20
- mindsdb/utilities/starters.py +0 -10
- mindsdb/utilities/utils.py +2 -2
- {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/METADATA +293 -276
- {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/RECORD +144 -158
- mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -14
- mindsdb/api/postgres/__init__.py +0 -0
- mindsdb/api/postgres/postgres_proxy/__init__.py +0 -0
- mindsdb/api/postgres/postgres_proxy/executor/__init__.py +0 -1
- mindsdb/api/postgres/postgres_proxy/executor/executor.py +0 -189
- mindsdb/api/postgres/postgres_proxy/postgres_packets/__init__.py +0 -0
- mindsdb/api/postgres/postgres_proxy/postgres_packets/errors.py +0 -322
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_fields.py +0 -34
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message.py +0 -31
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +0 -1265
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_identifiers.py +0 -31
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_packets.py +0 -253
- mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +0 -477
- mindsdb/api/postgres/postgres_proxy/utilities/__init__.py +0 -10
- mindsdb/api/postgres/start.py +0 -11
- mindsdb/integrations/handlers/mssql_handler/tests/__init__.py +0 -0
- mindsdb/integrations/handlers/mssql_handler/tests/test_mssql_handler.py +0 -169
- mindsdb/integrations/handlers/oracle_handler/tests/__init__.py +0 -0
- mindsdb/integrations/handlers/oracle_handler/tests/test_oracle_handler.py +0 -32
- {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/WHEEL +0 -0
- {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/top_level.txt +0 -0
mindsdb/api/http/initialize.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import mimetypes
|
|
3
3
|
import threading
|
|
4
|
-
import traceback
|
|
5
4
|
import webbrowser
|
|
6
5
|
|
|
7
6
|
from pathlib import Path
|
|
@@ -9,8 +8,7 @@ from http import HTTPStatus
|
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
import requests
|
|
12
|
-
from flask import Flask, url_for,
|
|
13
|
-
from flask.json import dumps
|
|
11
|
+
from flask import Flask, url_for, request, send_from_directory
|
|
14
12
|
from flask_compress import Compress
|
|
15
13
|
from flask_restx import Api
|
|
16
14
|
from werkzeug.exceptions import HTTPException
|
|
@@ -48,7 +46,7 @@ from mindsdb.metrics.server import init_metrics
|
|
|
48
46
|
from mindsdb.utilities import log
|
|
49
47
|
from mindsdb.utilities.config import config
|
|
50
48
|
from mindsdb.utilities.context import context as ctx
|
|
51
|
-
from mindsdb.utilities.json_encoder import
|
|
49
|
+
from mindsdb.utilities.json_encoder import ORJSONProvider
|
|
52
50
|
from mindsdb.utilities.ps import is_pid_listen_port, wait_func_is_true
|
|
53
51
|
from mindsdb.utilities.sentry import sentry_sdk # noqa: F401
|
|
54
52
|
from mindsdb.utilities.otel import trace # noqa: F401
|
|
@@ -89,14 +87,8 @@ class Swagger_Api(Api):
|
|
|
89
87
|
return url_for(self.endpoint("specs"), _external=False)
|
|
90
88
|
|
|
91
89
|
|
|
92
|
-
def custom_output_json(data, code, headers=None):
|
|
93
|
-
resp = make_response(dumps(data, cls=CustomJSONProvider), code)
|
|
94
|
-
resp.headers.extend(headers or {})
|
|
95
|
-
return resp
|
|
96
|
-
|
|
97
|
-
|
|
98
90
|
def get_last_compatible_gui_version() -> Version | bool:
|
|
99
|
-
logger.debug("Getting last compatible frontend
|
|
91
|
+
logger.debug("Getting last compatible frontend...")
|
|
100
92
|
try:
|
|
101
93
|
res = requests.get(
|
|
102
94
|
"https://mindsdb-web-builds.s3.amazonaws.com/compatible-config.json",
|
|
@@ -154,8 +146,8 @@ def get_last_compatible_gui_version() -> Version | bool:
|
|
|
154
146
|
else:
|
|
155
147
|
all_lower_versions = [parse_version(x) for x in lower_versions.keys()]
|
|
156
148
|
gui_version_lv = gui_versions[all_lower_versions[-1].base_version]
|
|
157
|
-
except Exception
|
|
158
|
-
logger.
|
|
149
|
+
except Exception:
|
|
150
|
+
logger.exception("Error in compatible-config.json structure")
|
|
159
151
|
return False
|
|
160
152
|
|
|
161
153
|
logger.debug(f"Last compatible frontend version: {gui_version_lv}.")
|
|
@@ -179,7 +171,6 @@ def get_current_gui_version() -> Version:
|
|
|
179
171
|
|
|
180
172
|
|
|
181
173
|
def initialize_static():
|
|
182
|
-
logger.debug("Initializing static..")
|
|
183
174
|
last_gui_version_lv = get_last_compatible_gui_version()
|
|
184
175
|
current_gui_version_lv = get_current_gui_version()
|
|
185
176
|
required_gui_version = config["gui"].get("version")
|
|
@@ -207,22 +198,28 @@ def initialize_static():
|
|
|
207
198
|
return success
|
|
208
199
|
|
|
209
200
|
|
|
210
|
-
def initialize_app():
|
|
201
|
+
def initialize_app(is_restart: bool = False):
|
|
211
202
|
static_root = config["paths"]["static"]
|
|
212
203
|
logger.debug(f"Static route: {static_root}")
|
|
213
|
-
gui_exists = Path(static_root).joinpath("index.html").is_file()
|
|
214
|
-
logger.debug(f"Does GUI already exist.. {'YES' if gui_exists else 'NO'}")
|
|
215
204
|
init_static_thread = None
|
|
205
|
+
if not is_restart:
|
|
206
|
+
gui_exists = Path(static_root).joinpath("index.html").is_file()
|
|
207
|
+
logger.debug(f"Does GUI already exist.. {'YES' if gui_exists else 'NO'}")
|
|
208
|
+
|
|
209
|
+
if config["gui"]["autoupdate"] is True or (config["gui"]["open_on_start"] is True and gui_exists is False):
|
|
210
|
+
logger.debug("Initializing static...")
|
|
211
|
+
init_static_thread = threading.Thread(target=initialize_static, name="initialize_static")
|
|
212
|
+
init_static_thread.start()
|
|
213
|
+
else:
|
|
214
|
+
logger.debug(f"Skip initializing static: config['gui']={config['gui']}, gui_exists={gui_exists}")
|
|
216
215
|
|
|
217
|
-
|
|
218
|
-
init_static_thread = threading.Thread(target=initialize_static, name="initialize_static")
|
|
219
|
-
init_static_thread.start()
|
|
216
|
+
app, api = initialize_flask()
|
|
220
217
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
218
|
+
if not is_restart and config["gui"]["open_on_start"]:
|
|
219
|
+
if init_static_thread is not None:
|
|
220
|
+
init_static_thread.join()
|
|
221
|
+
open_gui(init_static_thread)
|
|
224
222
|
|
|
225
|
-
app, api = initialize_flask(config, init_static_thread)
|
|
226
223
|
Compress(app)
|
|
227
224
|
|
|
228
225
|
initialize_interfaces(app)
|
|
@@ -241,22 +238,30 @@ def initialize_app():
|
|
|
241
238
|
"The endpoint you are trying to access does not exist on the server.",
|
|
242
239
|
)
|
|
243
240
|
|
|
244
|
-
|
|
245
|
-
|
|
241
|
+
try:
|
|
242
|
+
# Ensure the requested path is within the static directory
|
|
243
|
+
# https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.is_relative_to
|
|
244
|
+
requested_path = (static_root / path).resolve()
|
|
245
|
+
|
|
246
|
+
if not requested_path.is_relative_to(static_root.resolve()):
|
|
247
|
+
return http_error(
|
|
248
|
+
HTTPStatus.FORBIDDEN,
|
|
249
|
+
"Forbidden",
|
|
250
|
+
"You are not allowed to access the requested resource.",
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
if requested_path.is_file():
|
|
254
|
+
return send_from_directory(static_root, path)
|
|
255
|
+
else:
|
|
256
|
+
return send_from_directory(static_root, "index.html")
|
|
246
257
|
|
|
247
|
-
|
|
248
|
-
if not full_path.startswith(str(static_root)):
|
|
258
|
+
except (ValueError, OSError):
|
|
249
259
|
return http_error(
|
|
250
|
-
HTTPStatus.
|
|
251
|
-
"
|
|
252
|
-
"
|
|
260
|
+
HTTPStatus.BAD_REQUEST,
|
|
261
|
+
"Bad Request",
|
|
262
|
+
"Invalid path requested.",
|
|
253
263
|
)
|
|
254
264
|
|
|
255
|
-
if os.path.isfile(full_path):
|
|
256
|
-
return send_from_directory(static_root, path)
|
|
257
|
-
else:
|
|
258
|
-
return send_from_directory(static_root, "index.html")
|
|
259
|
-
|
|
260
265
|
protected_namespaces = [
|
|
261
266
|
tab_ns,
|
|
262
267
|
utils_ns,
|
|
@@ -310,7 +315,6 @@ def initialize_app():
|
|
|
310
315
|
|
|
311
316
|
@app.before_request
|
|
312
317
|
def before_request():
|
|
313
|
-
logger.debug(f"HTTP {request.method}: {request.path}")
|
|
314
318
|
ctx.set_default()
|
|
315
319
|
|
|
316
320
|
h = request.headers.get("Authorization")
|
|
@@ -371,8 +375,8 @@ def initialize_app():
|
|
|
371
375
|
return app
|
|
372
376
|
|
|
373
377
|
|
|
374
|
-
def initialize_flask(
|
|
375
|
-
logger.debug("Initializing flask
|
|
378
|
+
def initialize_flask():
|
|
379
|
+
logger.debug("Initializing flask...")
|
|
376
380
|
# region required for windows https://github.com/mindsdb/mindsdb/issues/2526
|
|
377
381
|
mimetypes.add_type("text/css", ".css")
|
|
378
382
|
mimetypes.add_type("text/javascript", ".js")
|
|
@@ -393,7 +397,7 @@ def initialize_flask(config, init_static_thread):
|
|
|
393
397
|
|
|
394
398
|
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 60
|
|
395
399
|
app.config["SWAGGER_HOST"] = "http://localhost:8000/mindsdb"
|
|
396
|
-
app.json =
|
|
400
|
+
app.json = ORJSONProvider(app)
|
|
397
401
|
|
|
398
402
|
authorizations = {"apikey": {"type": "apiKey", "in": "header", "name": "Authorization"}}
|
|
399
403
|
|
|
@@ -407,30 +411,41 @@ def initialize_flask(config, init_static_thread):
|
|
|
407
411
|
doc="/doc/",
|
|
408
412
|
)
|
|
409
413
|
|
|
410
|
-
|
|
414
|
+
def __output_json_orjson(data, code, headers=None):
|
|
415
|
+
from flask import current_app, make_response
|
|
411
416
|
|
|
412
|
-
|
|
413
|
-
|
|
417
|
+
dumped = current_app.json.dumps(data)
|
|
418
|
+
resp = make_response(dumped, code)
|
|
419
|
+
if headers:
|
|
420
|
+
resp.headers.extend(headers)
|
|
421
|
+
resp.mimetype = "application/json"
|
|
422
|
+
return resp
|
|
414
423
|
|
|
415
|
-
|
|
416
|
-
if host in ("", "0.0.0.0"):
|
|
417
|
-
url = f"http://127.0.0.1:{port}/"
|
|
418
|
-
else:
|
|
419
|
-
url = f"http://{host}:{port}/"
|
|
420
|
-
logger.info(f" - GUI available at {url}")
|
|
421
|
-
|
|
422
|
-
pid = os.getpid()
|
|
423
|
-
thread = threading.Thread(
|
|
424
|
-
target=_open_webbrowser,
|
|
425
|
-
args=(url, pid, port, init_static_thread, config["paths"]["static"]),
|
|
426
|
-
daemon=True,
|
|
427
|
-
name="open_webbrowser",
|
|
428
|
-
)
|
|
429
|
-
thread.start()
|
|
424
|
+
api.representations["application/json"] = __output_json_orjson
|
|
430
425
|
|
|
431
426
|
return app, api
|
|
432
427
|
|
|
433
428
|
|
|
429
|
+
def open_gui(init_static_thread):
|
|
430
|
+
port = config["api"]["http"]["port"]
|
|
431
|
+
host = config["api"]["http"]["host"]
|
|
432
|
+
|
|
433
|
+
if host in ("", "0.0.0.0"):
|
|
434
|
+
url = f"http://127.0.0.1:{port}/"
|
|
435
|
+
else:
|
|
436
|
+
url = f"http://{host}:{port}/"
|
|
437
|
+
logger.info(f" - GUI available at {url}")
|
|
438
|
+
|
|
439
|
+
pid = os.getpid()
|
|
440
|
+
thread = threading.Thread(
|
|
441
|
+
target=_open_webbrowser,
|
|
442
|
+
args=(url, pid, port, init_static_thread, config["paths"]["static"]),
|
|
443
|
+
daemon=True,
|
|
444
|
+
name="open_webbrowser",
|
|
445
|
+
)
|
|
446
|
+
thread.start()
|
|
447
|
+
|
|
448
|
+
|
|
434
449
|
def initialize_interfaces(app):
|
|
435
450
|
app.integration_controller = integration_controller
|
|
436
451
|
app.database_controller = DatabaseController()
|
|
@@ -449,7 +464,6 @@ def _open_webbrowser(url: str, pid: int, port: int, init_static_thread, static_f
|
|
|
449
464
|
is_http_active = wait_func_is_true(func=is_pid_listen_port, timeout=15, pid=pid, port=port)
|
|
450
465
|
if is_http_active:
|
|
451
466
|
webbrowser.open(url)
|
|
452
|
-
except Exception
|
|
453
|
-
logger.
|
|
454
|
-
logger.error(traceback.format_exc())
|
|
467
|
+
except Exception:
|
|
468
|
+
logger.exception(f"Failed to open {url} in webbrowser with exception:")
|
|
455
469
|
db.session.close()
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import json
|
|
3
|
-
import traceback
|
|
4
3
|
from http import HTTPStatus
|
|
5
4
|
from typing import Dict, Iterable, List
|
|
6
5
|
|
|
@@ -27,9 +26,6 @@ def create_agent(project_name, name, agent):
|
|
|
27
26
|
if name is None:
|
|
28
27
|
return http_error(HTTPStatus.BAD_REQUEST, "Missing field", 'Missing "name" field for agent')
|
|
29
28
|
|
|
30
|
-
if not name.islower():
|
|
31
|
-
return http_error(HTTPStatus.BAD_REQUEST, "Wrong name", f"The name must be in lower case: {name}")
|
|
32
|
-
|
|
33
29
|
model_name = agent.get("model_name")
|
|
34
30
|
provider = agent.get("provider")
|
|
35
31
|
skills = agent.get("skills", [])
|
|
@@ -307,10 +303,10 @@ def _completion_event_generator(agent_name: str, messages: List[Dict], project_n
|
|
|
307
303
|
|
|
308
304
|
logger.info("Completion stream finished")
|
|
309
305
|
|
|
310
|
-
except Exception
|
|
311
|
-
|
|
312
|
-
logger.
|
|
313
|
-
yield json_serialize({"error":
|
|
306
|
+
except Exception:
|
|
307
|
+
error_message = "Error in completion event generator"
|
|
308
|
+
logger.exception(error_message)
|
|
309
|
+
yield json_serialize({"error": error_message})
|
|
314
310
|
|
|
315
311
|
finally:
|
|
316
312
|
yield json_serialize({"type": "end"})
|
|
@@ -337,12 +333,12 @@ class AgentCompletionsStream(Resource):
|
|
|
337
333
|
try:
|
|
338
334
|
existing_agent = session.agents_controller.get_agent(agent_name, project_name=project_name)
|
|
339
335
|
if existing_agent is None:
|
|
340
|
-
logger.
|
|
336
|
+
logger.warning(f"Agent {agent_name} not found in project {project_name}")
|
|
341
337
|
return http_error(
|
|
342
338
|
HTTPStatus.NOT_FOUND, "Agent not found", f"Agent with name {agent_name} does not exist"
|
|
343
339
|
)
|
|
344
340
|
except ValueError as e:
|
|
345
|
-
logger.
|
|
341
|
+
logger.warning(f"Project {project_name} not found: {e}")
|
|
346
342
|
return http_error(
|
|
347
343
|
HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist"
|
|
348
344
|
)
|
|
@@ -352,10 +348,9 @@ class AgentCompletionsStream(Resource):
|
|
|
352
348
|
logger.info(f"Starting streaming response for agent {agent_name}")
|
|
353
349
|
return Response(gen, mimetype="text/event-stream")
|
|
354
350
|
except Exception as e:
|
|
355
|
-
logger.
|
|
356
|
-
logger.error(traceback.format_exc())
|
|
351
|
+
logger.exception(f"Error during streaming for agent {agent_name}:")
|
|
357
352
|
return http_error(
|
|
358
|
-
HTTPStatus.INTERNAL_SERVER_ERROR, "Streaming error", f"An error occurred during streaming: {
|
|
353
|
+
HTTPStatus.INTERNAL_SERVER_ERROR, "Streaming error", f"An error occurred during streaming: {e}"
|
|
359
354
|
)
|
|
360
355
|
|
|
361
356
|
|
|
@@ -416,8 +411,8 @@ class AgentCompletions(Resource):
|
|
|
416
411
|
last_context = completion.iloc[-1]["context"]
|
|
417
412
|
if last_context:
|
|
418
413
|
context = json.loads(last_context)
|
|
419
|
-
except (json.JSONDecodeError, IndexError)
|
|
420
|
-
logger.
|
|
414
|
+
except (json.JSONDecodeError, IndexError):
|
|
415
|
+
logger.warning("Error decoding context:", exc_info=True)
|
|
421
416
|
pass # Keeping context as an empty list in case of error
|
|
422
417
|
|
|
423
418
|
response["message"]["context"] = context
|
|
@@ -36,6 +36,7 @@ def analyze_df(df: DataFrame) -> dict:
|
|
|
36
36
|
df.columns = cols
|
|
37
37
|
|
|
38
38
|
from dataprep_ml.insights import analyze_dataset
|
|
39
|
+
|
|
39
40
|
analysis = analyze_dataset(df)
|
|
40
41
|
return analysis.to_dict()
|
|
41
42
|
|
|
@@ -43,7 +44,7 @@ def analyze_df(df: DataFrame) -> dict:
|
|
|
43
44
|
@ns_conf.route("/query")
|
|
44
45
|
class QueryAnalysis(Resource):
|
|
45
46
|
@ns_conf.doc("post_query_to_analyze")
|
|
46
|
-
@api_endpoint_metrics(
|
|
47
|
+
@api_endpoint_metrics("POST", "/analysis/query")
|
|
47
48
|
def post(self):
|
|
48
49
|
data = request.json
|
|
49
50
|
query = data.get("query")
|
|
@@ -67,10 +68,8 @@ class QueryAnalysis(Resource):
|
|
|
67
68
|
try:
|
|
68
69
|
result = mysql_proxy.process_query(query)
|
|
69
70
|
except Exception as e:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
logger.error(traceback.format_exc())
|
|
73
|
-
return http_error(500, "Error", str(e))
|
|
71
|
+
logger.exception("Error during query analysis:")
|
|
72
|
+
return http_error(500, "Error", f"Unexpected error duting query analysis: {e}")
|
|
74
73
|
|
|
75
74
|
if result.type == SQL_RESPONSE_TYPE.ERROR:
|
|
76
75
|
return http_error(500, f"Error {result.error_code}", result.error_message)
|
|
@@ -83,14 +82,12 @@ class QueryAnalysis(Resource):
|
|
|
83
82
|
analysis = analyze_df(df)
|
|
84
83
|
except ImportError:
|
|
85
84
|
return {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
"analysis": {},
|
|
86
|
+
"timestamp": time.time(),
|
|
87
|
+
"error": 'To use this feature, please install the "dataprep_ml" package.',
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
query_tables = [
|
|
92
|
-
table.to_string() for table in get_query_tables(ast)
|
|
93
|
-
]
|
|
90
|
+
query_tables = [table.to_string() for table in get_query_tables(ast)]
|
|
94
91
|
|
|
95
92
|
return {
|
|
96
93
|
"analysis": analysis,
|
|
@@ -104,7 +101,7 @@ class QueryAnalysis(Resource):
|
|
|
104
101
|
@ns_conf.route("/data")
|
|
105
102
|
class DataAnalysis(Resource):
|
|
106
103
|
@ns_conf.doc("post_data_to_analyze")
|
|
107
|
-
@api_endpoint_metrics(
|
|
104
|
+
@api_endpoint_metrics("POST", "/analysis/data")
|
|
108
105
|
def post(self):
|
|
109
106
|
payload = request.json
|
|
110
107
|
column_names = payload.get("column_names")
|
|
@@ -116,15 +113,11 @@ class DataAnalysis(Resource):
|
|
|
116
113
|
return {"analysis": analysis, "timestamp": time.time()}
|
|
117
114
|
except ImportError:
|
|
118
115
|
return {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
"analysis": {},
|
|
117
|
+
"timestamp": timestamp,
|
|
118
|
+
"error": 'To use this feature, please install the "dataprep_ml" package.',
|
|
122
119
|
}
|
|
123
120
|
except Exception as e:
|
|
124
121
|
# Don't want analysis exceptions to show up on UI.
|
|
125
122
|
# TODO: Fix analysis so it doesn't throw exceptions at all.
|
|
126
|
-
return {
|
|
127
|
-
'analysis': {},
|
|
128
|
-
'timestamp': timestamp,
|
|
129
|
-
'error': str(e)
|
|
130
|
-
}
|
|
123
|
+
return {"analysis": {}, "timestamp": timestamp, "error": str(e)}
|
|
@@ -117,7 +117,7 @@ class Auth(Resource):
|
|
|
117
117
|
if resp.status_code != 200:
|
|
118
118
|
logger.warning(f"Wrong response from cloud server: {resp.status_code}")
|
|
119
119
|
except Exception as e:
|
|
120
|
-
logger.warning(f"Cant't send request to cloud server: {e}")
|
|
120
|
+
logger.warning(f"Cant't send request to cloud server: {e}", exc_info=True)
|
|
121
121
|
|
|
122
122
|
if request.path.endswith("/auth/callback/cloud_home"):
|
|
123
123
|
return redirect(f"https://{auth_server}")
|
|
@@ -18,9 +18,6 @@ def create_chatbot(project_name, name, chatbot):
|
|
|
18
18
|
if name is None:
|
|
19
19
|
return http_error(HTTPStatus.BAD_REQUEST, "Missing field", 'Missing "name" field for chatbot')
|
|
20
20
|
|
|
21
|
-
if not name.islower():
|
|
22
|
-
return http_error(HTTPStatus.BAD_REQUEST, "Wrong name", f"The name must be in lower case: {name}")
|
|
23
|
-
|
|
24
21
|
model_name = chatbot.get("model_name", None)
|
|
25
22
|
agent_name = chatbot.get("agent_name", None)
|
|
26
23
|
if model_name is None and agent_name is None:
|
|
@@ -241,8 +238,6 @@ class ChatBotResource(Resource):
|
|
|
241
238
|
"Chatbot already exists",
|
|
242
239
|
f"Chatbot with name {name} already exists. Please choose a different one.",
|
|
243
240
|
)
|
|
244
|
-
if not name.islower():
|
|
245
|
-
return http_error(HTTPStatus.BAD_REQUEST, "Wrong name", f"The name must be in lower case: {name}")
|
|
246
241
|
|
|
247
242
|
if existing_chatbot is None:
|
|
248
243
|
# Create
|
|
@@ -11,6 +11,7 @@ from flask import current_app as ca
|
|
|
11
11
|
from mindsdb.api.http.namespaces.configs.config import ns_conf
|
|
12
12
|
from mindsdb.api.http.utils import http_error
|
|
13
13
|
from mindsdb.metrics.metrics import api_endpoint_metrics
|
|
14
|
+
from mindsdb.utilities.api_status import get_api_status
|
|
14
15
|
from mindsdb.utilities import log
|
|
15
16
|
from mindsdb.utilities.functions import decrypt, encrypt
|
|
16
17
|
from mindsdb.utilities.config import Config
|
|
@@ -32,6 +33,13 @@ class GetConfig(Resource):
|
|
|
32
33
|
value = config.get(key)
|
|
33
34
|
if value is not None:
|
|
34
35
|
resp[key] = value
|
|
36
|
+
|
|
37
|
+
api_status = get_api_status()
|
|
38
|
+
api_configs = copy.deepcopy(config["api"])
|
|
39
|
+
for api_name, api_config in api_configs.items():
|
|
40
|
+
api_config["running"] = api_status.get(api_name, False)
|
|
41
|
+
resp["api"] = api_configs
|
|
42
|
+
|
|
35
43
|
return resp
|
|
36
44
|
|
|
37
45
|
@ns_conf.doc("put_config")
|
|
@@ -163,9 +171,7 @@ class Integration(Resource):
|
|
|
163
171
|
)
|
|
164
172
|
|
|
165
173
|
try:
|
|
166
|
-
engine = params
|
|
167
|
-
if engine is not None:
|
|
168
|
-
del params["type"]
|
|
174
|
+
engine = params.pop("type", None)
|
|
169
175
|
params.pop("publish", False)
|
|
170
176
|
storage = params.pop("storage", None)
|
|
171
177
|
ca.integration_controller.add(name, engine, params)
|
|
@@ -178,10 +184,10 @@ class Integration(Resource):
|
|
|
178
184
|
handler.handler_storage.import_files(export)
|
|
179
185
|
|
|
180
186
|
except Exception as e:
|
|
181
|
-
logger.error
|
|
187
|
+
logger.exception("An error occurred during the creation of the integration:")
|
|
182
188
|
if temp_dir is not None:
|
|
183
189
|
shutil.rmtree(temp_dir)
|
|
184
|
-
return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during config update: {
|
|
190
|
+
return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during config update: {e}")
|
|
185
191
|
|
|
186
192
|
if temp_dir is not None:
|
|
187
193
|
shutil.rmtree(temp_dir)
|
|
@@ -198,8 +204,8 @@ class Integration(Resource):
|
|
|
198
204
|
try:
|
|
199
205
|
ca.integration_controller.delete(name)
|
|
200
206
|
except Exception as e:
|
|
201
|
-
logger.error
|
|
202
|
-
return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration delete: {
|
|
207
|
+
logger.exception("An error occurred while deleting the integration")
|
|
208
|
+
return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration delete: {e}")
|
|
203
209
|
return "", 200
|
|
204
210
|
|
|
205
211
|
@ns_conf.doc("modify_integration")
|
|
@@ -223,8 +229,6 @@ class Integration(Resource):
|
|
|
223
229
|
ca.integration_controller.modify(name, params)
|
|
224
230
|
|
|
225
231
|
except Exception as e:
|
|
226
|
-
logger.error
|
|
227
|
-
return http_error(
|
|
228
|
-
HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration modification: {str(e)}"
|
|
229
|
-
)
|
|
232
|
+
logger.exception("An error occurred while modifying the integration")
|
|
233
|
+
return http_error(HTTPStatus.INTERNAL_SERVER_ERROR, "Error", f"Error during integration modification: {e}")
|
|
230
234
|
return "", 200
|