MindsDB 25.4.4.0__py3-none-any.whl → 25.5.3.0__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 +107 -125
- mindsdb/api/executor/command_executor.py +14 -3
- mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +8 -0
- mindsdb/api/executor/datahub/datanodes/mindsdb_tables.py +2 -1
- mindsdb/api/executor/datahub/datanodes/system_tables.py +10 -13
- mindsdb/api/executor/planner/query_plan.py +1 -0
- mindsdb/api/executor/planner/query_planner.py +9 -1
- mindsdb/api/executor/sql_query/sql_query.py +24 -8
- mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +21 -3
- mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +3 -1
- mindsdb/api/http/initialize.py +20 -3
- mindsdb/api/http/namespaces/analysis.py +14 -1
- mindsdb/api/http/namespaces/config.py +19 -11
- mindsdb/api/http/namespaces/tree.py +1 -1
- mindsdb/api/http/start.py +7 -2
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +4 -8
- mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -4
- mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +2 -2
- mindsdb/integrations/handlers/bigquery_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/chromadb_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/gmail_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/google_analytics_handler/requirements.txt +2 -1
- mindsdb/integrations/handlers/google_books_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_calendar_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/google_content_shopping_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_fit_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/google_search_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/jira_handler/jira_handler.archived.py +75 -0
- mindsdb/integrations/handlers/jira_handler/jira_handler.py +113 -38
- mindsdb/integrations/handlers/jira_handler/jira_tables.py +229 -0
- mindsdb/integrations/handlers/jira_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/lightfm_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -2
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
- mindsdb/integrations/handlers/lindorm_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/ms_one_drive_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/ms_teams_handler/requirements.txt +3 -1
- mindsdb/integrations/handlers/openai_handler/helpers.py +3 -5
- mindsdb/integrations/handlers/openai_handler/openai_handler.py +25 -12
- mindsdb/integrations/handlers/snowflake_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/togetherai_handler/__about__.py +9 -0
- mindsdb/integrations/handlers/togetherai_handler/__init__.py +20 -0
- mindsdb/integrations/handlers/togetherai_handler/creation_args.py +14 -0
- mindsdb/integrations/handlers/togetherai_handler/icon.svg +15 -0
- mindsdb/integrations/handlers/togetherai_handler/model_using_args.py +5 -0
- mindsdb/integrations/handlers/togetherai_handler/requirements.txt +2 -0
- mindsdb/integrations/handlers/togetherai_handler/settings.py +33 -0
- mindsdb/integrations/handlers/togetherai_handler/togetherai_handler.py +234 -0
- mindsdb/integrations/handlers/vertex_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/youtube_handler/requirements.txt +1 -0
- mindsdb/integrations/utilities/files/file_reader.py +5 -2
- mindsdb/integrations/utilities/handler_utils.py +4 -0
- mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +360 -0
- mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +6 -346
- mindsdb/interfaces/agents/constants.py +14 -2
- mindsdb/interfaces/agents/langchain_agent.py +2 -4
- mindsdb/interfaces/database/projects.py +1 -7
- mindsdb/interfaces/functions/controller.py +14 -16
- mindsdb/interfaces/functions/to_markdown.py +9 -124
- mindsdb/interfaces/knowledge_base/controller.py +109 -92
- mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +28 -5
- mindsdb/interfaces/knowledge_base/utils.py +10 -15
- mindsdb/interfaces/model/model_controller.py +0 -2
- mindsdb/interfaces/query_context/context_controller.py +55 -15
- mindsdb/interfaces/query_context/query_task.py +19 -0
- mindsdb/interfaces/skills/sql_agent.py +33 -11
- mindsdb/interfaces/storage/db.py +2 -2
- mindsdb/interfaces/tasks/task_monitor.py +5 -1
- mindsdb/interfaces/tasks/task_thread.py +6 -0
- mindsdb/migrations/migrate.py +0 -2
- mindsdb/migrations/versions/2025-04-22_53502b6d63bf_query_database.py +27 -0
- mindsdb/utilities/config.py +15 -3
- mindsdb/utilities/context.py +2 -1
- mindsdb/utilities/functions.py +0 -36
- mindsdb/utilities/langfuse.py +19 -10
- mindsdb/utilities/otel/__init__.py +9 -193
- mindsdb/utilities/otel/metric_handlers/__init__.py +5 -1
- mindsdb/utilities/otel/prepare.py +198 -0
- mindsdb/utilities/sql.py +83 -0
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/METADATA +662 -592
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/RECORD +85 -69
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/WHEEL +1 -1
- mindsdb/api/mysql/mysql_proxy/classes/sql_statement_parser.py +0 -151
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.4.4.0.dist-info → mindsdb-25.5.3.0.dist-info}/top_level.txt +0 -0
|
@@ -15,6 +15,7 @@ from mindsdb.utilities.cache import get_cache
|
|
|
15
15
|
|
|
16
16
|
from mindsdb.interfaces.storage import db
|
|
17
17
|
from mindsdb.utilities.context import context as ctx
|
|
18
|
+
from mindsdb.utilities.config import config
|
|
18
19
|
|
|
19
20
|
from .last_query import LastQuery
|
|
20
21
|
|
|
@@ -24,9 +25,12 @@ class RunningQuery:
|
|
|
24
25
|
Query in progres
|
|
25
26
|
"""
|
|
26
27
|
|
|
28
|
+
OBJECT_TYPE = 'query'
|
|
29
|
+
|
|
27
30
|
def __init__(self, record: db.Queries):
|
|
28
31
|
self.record = record
|
|
29
32
|
self.sql = record.sql
|
|
33
|
+
self.database = record.database or config.get('default_project')
|
|
30
34
|
|
|
31
35
|
def get_partition_query(self, step_num: int, query: Select) -> Select:
|
|
32
36
|
"""
|
|
@@ -67,6 +71,44 @@ class RunningQuery:
|
|
|
67
71
|
|
|
68
72
|
return query
|
|
69
73
|
|
|
74
|
+
def get_info(self):
|
|
75
|
+
record = self.record
|
|
76
|
+
return {
|
|
77
|
+
'id': record.id,
|
|
78
|
+
'sql': record.sql,
|
|
79
|
+
'database': record.database,
|
|
80
|
+
'started_at': record.started_at,
|
|
81
|
+
'finished_at': record.finished_at,
|
|
82
|
+
'parameters': record.parameters,
|
|
83
|
+
'context': record.context,
|
|
84
|
+
'processed_rows': record.processed_rows,
|
|
85
|
+
'error': record.error,
|
|
86
|
+
'updated_at': record.updated_at,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def add_to_task(self):
|
|
90
|
+
|
|
91
|
+
task_record = db.Tasks(
|
|
92
|
+
company_id=ctx.company_id,
|
|
93
|
+
user_class=ctx.user_class,
|
|
94
|
+
|
|
95
|
+
object_type=self.OBJECT_TYPE,
|
|
96
|
+
object_id=self.record.id,
|
|
97
|
+
)
|
|
98
|
+
db.session.add(task_record)
|
|
99
|
+
db.session.commit()
|
|
100
|
+
|
|
101
|
+
def remove_from_task(self):
|
|
102
|
+
task = db.Tasks.query.filter(
|
|
103
|
+
db.Tasks.object_type == self.OBJECT_TYPE,
|
|
104
|
+
db.Tasks.object_id == self.record.id,
|
|
105
|
+
db.Tasks.company_id == ctx.company_id,
|
|
106
|
+
).first()
|
|
107
|
+
|
|
108
|
+
if task is not None:
|
|
109
|
+
db.session.delete(task)
|
|
110
|
+
db.session.commit()
|
|
111
|
+
|
|
70
112
|
def set_params(self, params: dict):
|
|
71
113
|
"""
|
|
72
114
|
Store parameters of the step which is about to be split into partitions
|
|
@@ -126,14 +168,21 @@ class RunningQuery:
|
|
|
126
168
|
|
|
127
169
|
db.session.commit()
|
|
128
170
|
|
|
129
|
-
def
|
|
171
|
+
def mark_as_run(self):
|
|
130
172
|
"""
|
|
131
|
-
|
|
173
|
+
Mark query as running and reset error of the query
|
|
132
174
|
"""
|
|
175
|
+
if self.record.finished_at is not None:
|
|
176
|
+
raise RuntimeError('The query already finished')
|
|
133
177
|
|
|
134
|
-
if self.record.
|
|
178
|
+
if self.record.started_at is None:
|
|
179
|
+
self.record.started_at = dt.datetime.now()
|
|
180
|
+
db.session.commit()
|
|
181
|
+
elif self.record.error is not None:
|
|
135
182
|
self.record.error = None
|
|
136
183
|
db.session.commit()
|
|
184
|
+
else:
|
|
185
|
+
raise RuntimeError('The query might be running already')
|
|
137
186
|
|
|
138
187
|
def get_state(self) -> dict:
|
|
139
188
|
"""
|
|
@@ -448,7 +497,7 @@ class QueryContextController:
|
|
|
448
497
|
raise RuntimeError(f'Query not found: {query_id}')
|
|
449
498
|
return RunningQuery(rec)
|
|
450
499
|
|
|
451
|
-
def create_query(self, query: ASTNode) -> RunningQuery:
|
|
500
|
+
def create_query(self, query: ASTNode, database: str = None) -> RunningQuery:
|
|
452
501
|
"""
|
|
453
502
|
Create a new running query from AST query
|
|
454
503
|
"""
|
|
@@ -463,6 +512,7 @@ class QueryContextController:
|
|
|
463
512
|
|
|
464
513
|
rec = db.Queries(
|
|
465
514
|
sql=str(query),
|
|
515
|
+
database=database,
|
|
466
516
|
company_id=ctx.company_id,
|
|
467
517
|
)
|
|
468
518
|
|
|
@@ -479,17 +529,7 @@ class QueryContextController:
|
|
|
479
529
|
db.Queries.company_id == ctx.company_id
|
|
480
530
|
)
|
|
481
531
|
return [
|
|
482
|
-
|
|
483
|
-
'id': record.id,
|
|
484
|
-
'sql': record.sql,
|
|
485
|
-
'started_at': record.started_at,
|
|
486
|
-
'finished_at': record.finished_at,
|
|
487
|
-
'parameters': record.parameters,
|
|
488
|
-
'context': record.context,
|
|
489
|
-
'processed_rows': record.processed_rows,
|
|
490
|
-
'error': record.error,
|
|
491
|
-
'updated_at': record.updated_at,
|
|
492
|
-
}
|
|
532
|
+
RunningQuery(record).get_info()
|
|
493
533
|
for record in query
|
|
494
534
|
]
|
|
495
535
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from mindsdb.api.executor.sql_query import SQLQuery
|
|
2
|
+
from mindsdb.interfaces.query_context.context_controller import query_context_controller
|
|
3
|
+
from mindsdb.api.executor.controllers.session_controller import SessionController
|
|
4
|
+
from mindsdb.interfaces.tasks.task import BaseTask
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class QueryTask(BaseTask):
|
|
8
|
+
def __init__(self, *args, **kwargs):
|
|
9
|
+
super().__init__(*args, **kwargs)
|
|
10
|
+
self.query_id = self.object_id
|
|
11
|
+
|
|
12
|
+
def run(self, stop_event):
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
session = SessionController()
|
|
16
|
+
SQLQuery(None, query_id=self.query_id, session=session, stop_event=stop_event)
|
|
17
|
+
finally:
|
|
18
|
+
# clear task
|
|
19
|
+
query_context_controller.get_query(self.query_id).remove_from_task()
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import re
|
|
3
2
|
import csv
|
|
4
3
|
import inspect
|
|
@@ -13,6 +12,7 @@ from mindsdb.utilities import log
|
|
|
13
12
|
from mindsdb.utilities.context import context as ctx
|
|
14
13
|
from mindsdb.integrations.utilities.query_traversal import query_traversal
|
|
15
14
|
from mindsdb.integrations.libs.response import INF_SCHEMA_COLUMNS_NAMES
|
|
15
|
+
from mindsdb.api.mysql.mysql_proxy.libs.constants.mysql import MYSQL_DATA_TYPE
|
|
16
16
|
|
|
17
17
|
logger = log.getLogger(__name__)
|
|
18
18
|
|
|
@@ -253,7 +253,7 @@ class SQLAgent:
|
|
|
253
253
|
for table in all_tables:
|
|
254
254
|
key = f"{ctx.company_id}_{table}_info"
|
|
255
255
|
table_info = self._cache.get(key) if self._cache else None
|
|
256
|
-
if table_info is None:
|
|
256
|
+
if True or table_info is None:
|
|
257
257
|
table_info = self._get_single_table_info(table)
|
|
258
258
|
if self._cache:
|
|
259
259
|
self._cache.set(key, table_info)
|
|
@@ -276,19 +276,41 @@ class SQLAgent:
|
|
|
276
276
|
dn = self._command_executor.session.datahub.get(integration)
|
|
277
277
|
|
|
278
278
|
fields, dtypes = [], []
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
279
|
+
try:
|
|
280
|
+
df = dn.get_table_columns_df(table_name, schema_name)
|
|
281
|
+
if not isinstance(df, pd.DataFrame) or df.empty:
|
|
282
|
+
logger.warning(f"Received empty or invalid DataFrame for table columns of {table_str}")
|
|
283
|
+
return f"Table named `{table_str}`:\n [No column information available]"
|
|
284
|
+
|
|
285
|
+
fields = df[INF_SCHEMA_COLUMNS_NAMES.COLUMN_NAME].to_list()
|
|
286
|
+
dtypes = [
|
|
287
|
+
mysql_data_type.value if isinstance(mysql_data_type, MYSQL_DATA_TYPE) else (data_type or 'UNKNOWN')
|
|
288
|
+
for mysql_data_type, data_type
|
|
289
|
+
in zip(
|
|
290
|
+
df[INF_SCHEMA_COLUMNS_NAMES.MYSQL_DATA_TYPE],
|
|
291
|
+
df[INF_SCHEMA_COLUMNS_NAMES.DATA_TYPE]
|
|
292
|
+
)
|
|
293
|
+
]
|
|
294
|
+
except Exception as e:
|
|
295
|
+
logger.error(f"Failed processing column info for {table_str}: {e}", exc_info=True)
|
|
296
|
+
raise ValueError(f"Failed to process column info for {table_str}") from e
|
|
297
|
+
|
|
298
|
+
if not fields:
|
|
299
|
+
logger.error(f"Could not extract column fields for {table_str}.")
|
|
300
|
+
return f"Table named `{table_str}`:\n [Could not extract column information]"
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
sample_rows_info = self._get_sample_rows(table_str, fields)
|
|
304
|
+
except Exception as e:
|
|
305
|
+
logger.warning(f"Could not get sample rows for {table_str}: {e}")
|
|
306
|
+
sample_rows_info = "\n\t [error] Couldn't retrieve sample rows!"
|
|
286
307
|
|
|
287
308
|
info = f'Table named `{table_str}`:\n'
|
|
288
309
|
info += f"\nSample with first {self._sample_rows_in_table_info} rows from table {table_str} in CSV format (dialect is 'excel'):\n"
|
|
289
|
-
info +=
|
|
310
|
+
info += sample_rows_info + "\n"
|
|
290
311
|
info += '\nColumn data types: ' + ",\t".join(
|
|
291
|
-
[f'\n`{field}` : `{dtype}`' for field, dtype in zip(fields, dtypes)]
|
|
312
|
+
[f'\n`{field}` : `{dtype}`' for field, dtype in zip(fields, dtypes)]
|
|
313
|
+
) + '\n'
|
|
292
314
|
return info
|
|
293
315
|
|
|
294
316
|
def _get_sample_rows(self, table: str, fields: List[str]) -> str:
|
mindsdb/interfaces/storage/db.py
CHANGED
|
@@ -571,9 +571,9 @@ class Queries(Base):
|
|
|
571
571
|
company_id: int = Column(Integer, nullable=True)
|
|
572
572
|
|
|
573
573
|
sql: str = Column(String, nullable=False)
|
|
574
|
-
|
|
574
|
+
database: str = Column(String, nullable=True)
|
|
575
575
|
|
|
576
|
-
started_at: datetime.datetime = Column(DateTime
|
|
576
|
+
started_at: datetime.datetime = Column(DateTime)
|
|
577
577
|
finished_at: datetime.datetime = Column(DateTime)
|
|
578
578
|
|
|
579
579
|
parameters = Column(JSON, default={})
|
|
@@ -2,6 +2,7 @@ import datetime as dt
|
|
|
2
2
|
import os
|
|
3
3
|
import socket
|
|
4
4
|
import time
|
|
5
|
+
from threading import Event
|
|
5
6
|
|
|
6
7
|
import sqlalchemy as sa
|
|
7
8
|
|
|
@@ -22,7 +23,7 @@ class TaskMonitor:
|
|
|
22
23
|
def __init__(self):
|
|
23
24
|
self._active_tasks = {}
|
|
24
25
|
|
|
25
|
-
def start(self):
|
|
26
|
+
def start(self, stop_event: Event = None):
|
|
26
27
|
config = Config()
|
|
27
28
|
db.init()
|
|
28
29
|
self.config = config
|
|
@@ -42,6 +43,9 @@ class TaskMonitor:
|
|
|
42
43
|
logger.error(e)
|
|
43
44
|
db.session.rollback()
|
|
44
45
|
|
|
46
|
+
if stop_event is not None and stop_event.is_set():
|
|
47
|
+
return
|
|
48
|
+
|
|
45
49
|
def stop_all_tasks(self):
|
|
46
50
|
|
|
47
51
|
active_tasks = list(self._active_tasks.keys())
|
|
@@ -6,6 +6,7 @@ from mindsdb.utilities import log
|
|
|
6
6
|
|
|
7
7
|
from mindsdb.interfaces.triggers.trigger_task import TriggerTask
|
|
8
8
|
from mindsdb.interfaces.chatbot.chatbot_task import ChatBotTask
|
|
9
|
+
from mindsdb.interfaces.query_context.query_task import QueryTask
|
|
9
10
|
|
|
10
11
|
logger = log.getLogger(__name__)
|
|
11
12
|
|
|
@@ -28,6 +29,7 @@ class TaskThread(threading.Thread):
|
|
|
28
29
|
ctx.company_id = task_record.company_id
|
|
29
30
|
if task_record.user_class is not None:
|
|
30
31
|
ctx.user_class = task_record.user_class
|
|
32
|
+
ctx.task_id = task_record.id
|
|
31
33
|
|
|
32
34
|
self.object_type = task_record.object_type
|
|
33
35
|
self.object_id = task_record.object_id
|
|
@@ -43,6 +45,10 @@ class TaskThread(threading.Thread):
|
|
|
43
45
|
bot = ChatBotTask(self.task_id, self.object_id)
|
|
44
46
|
bot.run(self._stop_event)
|
|
45
47
|
|
|
48
|
+
elif self.object_type == 'query':
|
|
49
|
+
query = QueryTask(self.task_id, self.object_id)
|
|
50
|
+
query.run(self._stop_event)
|
|
51
|
+
|
|
46
52
|
except Exception:
|
|
47
53
|
logger.error(traceback.format_exc())
|
|
48
54
|
task_record.last_error = str(traceback.format_exc())
|
mindsdb/migrations/migrate.py
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""query_database
|
|
2
|
+
|
|
3
|
+
Revision ID: 53502b6d63bf
|
|
4
|
+
Revises: fda503400e43
|
|
5
|
+
Create Date: 2025-04-22 16:30:15.139978
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
import mindsdb.interfaces.storage.db # noqa
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = '53502b6d63bf'
|
|
15
|
+
down_revision = 'fda503400e43'
|
|
16
|
+
branch_labels = None
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade():
|
|
21
|
+
with op.batch_alter_table('queries', schema=None) as batch_op:
|
|
22
|
+
batch_op.add_column(sa.Column('database', sa.String(), nullable=True))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade():
|
|
26
|
+
with op.batch_alter_table('queries', schema=None) as batch_op:
|
|
27
|
+
batch_op.drop_column('database')
|
mindsdb/utilities/config.py
CHANGED
|
@@ -143,7 +143,8 @@ class Config:
|
|
|
143
143
|
'auth': {
|
|
144
144
|
'http_auth_enabled': False,
|
|
145
145
|
"http_permanent_session_lifetime": datetime.timedelta(days=31),
|
|
146
|
-
"username": "mindsdb"
|
|
146
|
+
"username": "mindsdb",
|
|
147
|
+
"password": ""
|
|
147
148
|
},
|
|
148
149
|
"logging": {
|
|
149
150
|
"handlers": {
|
|
@@ -230,7 +231,9 @@ class Config:
|
|
|
230
231
|
"tasks": {
|
|
231
232
|
"disable": False
|
|
232
233
|
},
|
|
233
|
-
"default_project": "mindsdb"
|
|
234
|
+
"default_project": "mindsdb",
|
|
235
|
+
"default_llm": {},
|
|
236
|
+
"default_embedding_model": {}
|
|
234
237
|
}
|
|
235
238
|
# endregion
|
|
236
239
|
|
|
@@ -369,6 +372,15 @@ class Config:
|
|
|
369
372
|
if os.environ.get('MINDSDB_DEFAULT_PROJECT', '') != '':
|
|
370
373
|
self._env_config['default_project'] = os.environ['MINDSDB_DEFAULT_PROJECT'].lower()
|
|
371
374
|
|
|
375
|
+
if os.environ.get('MINDSDB_DEFAULT_LLM_API_KEY', '') != '':
|
|
376
|
+
self._env_config['default_llm'] = {
|
|
377
|
+
'api_key': os.environ['MINDSDB_DEFAULT_LLM_API_KEY']
|
|
378
|
+
}
|
|
379
|
+
if os.environ.get('MINDSDB_DEFAULT_EMBEDDING_MODEL_API_KEY', '') != '':
|
|
380
|
+
self._env_config['default_embedding_model'] = {
|
|
381
|
+
'api_key': os.environ['MINDSDB_DEFAULT_EMBEDDING_MODEL_API_KEY']
|
|
382
|
+
}
|
|
383
|
+
|
|
372
384
|
def parse_cmd_args(self) -> None:
|
|
373
385
|
"""Collect cmd args to self._cmd_args (accessable as self.cmd_args)
|
|
374
386
|
"""
|
|
@@ -448,7 +460,7 @@ class Config:
|
|
|
448
460
|
"""
|
|
449
461
|
updated = self.fetch_auto_config()
|
|
450
462
|
if updated:
|
|
451
|
-
self.
|
|
463
|
+
self.merge_configs()
|
|
452
464
|
|
|
453
465
|
def merge_configs(self) -> None:
|
|
454
466
|
"""Merge multiple configs to one.
|
mindsdb/utilities/context.py
CHANGED
|
@@ -18,6 +18,7 @@ class Context:
|
|
|
18
18
|
'user_id': None,
|
|
19
19
|
'company_id': None,
|
|
20
20
|
'session_id': "",
|
|
21
|
+
'task_id': None,
|
|
21
22
|
'user_class': 0,
|
|
22
23
|
'profiling': {
|
|
23
24
|
'level': 0,
|
|
@@ -53,7 +54,7 @@ class Context:
|
|
|
53
54
|
def load(self, storage: dict) -> None:
|
|
54
55
|
self._storage.set(storage)
|
|
55
56
|
|
|
56
|
-
def
|
|
57
|
+
def get_metadata(self, **kwargs) -> dict:
|
|
57
58
|
return {
|
|
58
59
|
'user_id': self.user_id or "",
|
|
59
60
|
'company_id': self.company_id or "",
|
mindsdb/utilities/functions.py
CHANGED
|
@@ -7,7 +7,6 @@ import textwrap
|
|
|
7
7
|
from functools import wraps
|
|
8
8
|
from collections.abc import Callable
|
|
9
9
|
|
|
10
|
-
import requests
|
|
11
10
|
from cryptography.fernet import Fernet
|
|
12
11
|
from mindsdb_sql_parser.ast import Identifier
|
|
13
12
|
|
|
@@ -72,41 +71,6 @@ def mark_process(name: str, custom_mark: str = None) -> Callable:
|
|
|
72
71
|
return mark_process_wrapper
|
|
73
72
|
|
|
74
73
|
|
|
75
|
-
def get_versions_where_predictors_become_obsolete():
|
|
76
|
-
""" Get list of MindsDB versions in which predictors should be retrained
|
|
77
|
-
Returns:
|
|
78
|
-
list of str or False
|
|
79
|
-
"""
|
|
80
|
-
versions_for_updating_predictors = []
|
|
81
|
-
try:
|
|
82
|
-
try:
|
|
83
|
-
res = requests.get(
|
|
84
|
-
'https://mindsdb-cloud-public-service-files.s3.us-east-2.amazonaws.com/version_for_updating_predictors.txt',
|
|
85
|
-
timeout=0.5
|
|
86
|
-
)
|
|
87
|
-
except (ConnectionError, requests.exceptions.ConnectionError) as e:
|
|
88
|
-
logger.error(f'Is no connection. {e}')
|
|
89
|
-
raise
|
|
90
|
-
except Exception as e:
|
|
91
|
-
logger.error(f'Is something wrong with getting version_for_updating_predictors.txt: {e}')
|
|
92
|
-
raise
|
|
93
|
-
|
|
94
|
-
if res.status_code != 200:
|
|
95
|
-
logger.error(f'Cant get version_for_updating_predictors.txt: returned status code = {res.status_code}')
|
|
96
|
-
raise
|
|
97
|
-
|
|
98
|
-
try:
|
|
99
|
-
versions_for_updating_predictors = res.text.replace(' \t\r', '').split('\n')
|
|
100
|
-
except Exception as e:
|
|
101
|
-
logger.error(f'Cant decode version_for_updating_predictors.txt: {e}')
|
|
102
|
-
raise
|
|
103
|
-
except Exception:
|
|
104
|
-
return False, versions_for_updating_predictors
|
|
105
|
-
|
|
106
|
-
versions_for_updating_predictors = [x for x in versions_for_updating_predictors if len(x) > 0]
|
|
107
|
-
return True, versions_for_updating_predictors
|
|
108
|
-
|
|
109
|
-
|
|
110
74
|
def init_lexer_parsers():
|
|
111
75
|
from mindsdb_sql_parser.lexer import MindsDBLexer
|
|
112
76
|
from mindsdb_sql_parser.parser import MindsDBParser
|
mindsdb/utilities/langfuse.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import typing
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
from mindsdb.utilities import log
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from langfuse.callback import CallbackHandler
|
|
8
|
-
from langfuse.
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from langfuse.callback import CallbackHandler
|
|
9
|
+
from langfuse.client import StatefulSpanClient
|
|
9
10
|
|
|
10
11
|
logger = log.getLogger(__name__)
|
|
11
12
|
|
|
@@ -98,6 +99,12 @@ class LangfuseClientWrapper:
|
|
|
98
99
|
logger.debug(f"LANGFUSE_TIMEOUT: {LANGFUSE_TIMEOUT}")
|
|
99
100
|
logger.debug(f"LANGFUSE_SAMPLE_RATE: {LANGFUSE_SAMPLE_RATE * 100}%")
|
|
100
101
|
|
|
102
|
+
try:
|
|
103
|
+
from langfuse import Langfuse
|
|
104
|
+
except ImportError:
|
|
105
|
+
logger.error("Langfuse is not installed. Please install it with `pip install langfuse`.")
|
|
106
|
+
return
|
|
107
|
+
|
|
101
108
|
self.client = Langfuse(
|
|
102
109
|
public_key=public_key,
|
|
103
110
|
secret_key=secret_key,
|
|
@@ -164,7 +171,7 @@ class LangfuseClientWrapper:
|
|
|
164
171
|
|
|
165
172
|
def start_span(self,
|
|
166
173
|
name: str,
|
|
167
|
-
input: typing.Optional[typing.Any] = None) -> typing.Optional[StatefulSpanClient]:
|
|
174
|
+
input: typing.Optional[typing.Any] = None) -> typing.Optional['StatefulSpanClient']:
|
|
168
175
|
"""
|
|
169
176
|
Create span. If Langfuse is disabled, nothing will be done.
|
|
170
177
|
|
|
@@ -180,7 +187,7 @@ class LangfuseClientWrapper:
|
|
|
180
187
|
return self.trace.span(name=name, input=input)
|
|
181
188
|
|
|
182
189
|
def end_span_stream(self,
|
|
183
|
-
span: typing.Optional[StatefulSpanClient] = None) -> None:
|
|
190
|
+
span: typing.Optional['StatefulSpanClient'] = None) -> None:
|
|
184
191
|
"""
|
|
185
192
|
End span. If Langfuse is disabled, nothing will happen.
|
|
186
193
|
Args:
|
|
@@ -195,7 +202,7 @@ class LangfuseClientWrapper:
|
|
|
195
202
|
self.trace.update()
|
|
196
203
|
|
|
197
204
|
def end_span(self,
|
|
198
|
-
span: typing.Optional[StatefulSpanClient] = None,
|
|
205
|
+
span: typing.Optional['StatefulSpanClient'] = None,
|
|
199
206
|
output: typing.Optional[typing.Any] = None) -> None:
|
|
200
207
|
"""
|
|
201
208
|
End trace. If Langfuse is disabled, nothing will be done.
|
|
@@ -227,7 +234,7 @@ class LangfuseClientWrapper:
|
|
|
227
234
|
except Exception as e:
|
|
228
235
|
logger.error(f'Something went wrong while processing Langfuse trace {self.trace.id}: {str(e)}')
|
|
229
236
|
|
|
230
|
-
def get_langchain_handler(self) -> typing.Optional[CallbackHandler]:
|
|
237
|
+
def get_langchain_handler(self) -> typing.Optional['CallbackHandler']:
|
|
231
238
|
"""
|
|
232
239
|
Get Langchain handler. If Langfuse is disabled, returns None.
|
|
233
240
|
"""
|
|
@@ -257,8 +264,10 @@ class LangfuseClientWrapper:
|
|
|
257
264
|
self.tags.append(self.release)
|
|
258
265
|
|
|
259
266
|
def _get_tool_usage(self) -> typing.Dict:
|
|
260
|
-
"""
|
|
261
|
-
Note: assumes trace marks an action with string `AgentAction`
|
|
267
|
+
"""Retrieves tool usage information from a langfuse trace.
|
|
268
|
+
Note: assumes trace marks an action with string `AgentAction`
|
|
269
|
+
"""
|
|
270
|
+
from langfuse.api.resources.commons.errors.not_found_error import NotFoundError as TraceNotFoundError
|
|
262
271
|
|
|
263
272
|
tool_usage = {}
|
|
264
273
|
|