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.

Files changed (163) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +40 -29
  3. mindsdb/api/a2a/__init__.py +1 -1
  4. mindsdb/api/a2a/agent.py +16 -10
  5. mindsdb/api/a2a/common/server/server.py +7 -3
  6. mindsdb/api/a2a/common/server/task_manager.py +12 -5
  7. mindsdb/api/a2a/common/types.py +66 -0
  8. mindsdb/api/a2a/task_manager.py +65 -17
  9. mindsdb/api/common/middleware.py +10 -12
  10. mindsdb/api/executor/command_executor.py +51 -40
  11. mindsdb/api/executor/datahub/datanodes/datanode.py +2 -2
  12. mindsdb/api/executor/datahub/datanodes/information_schema_datanode.py +7 -13
  13. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +101 -49
  14. mindsdb/api/executor/datahub/datanodes/project_datanode.py +8 -4
  15. mindsdb/api/executor/datahub/datanodes/system_tables.py +3 -2
  16. mindsdb/api/executor/exceptions.py +29 -10
  17. mindsdb/api/executor/planner/plan_join.py +17 -3
  18. mindsdb/api/executor/planner/query_prepare.py +2 -20
  19. mindsdb/api/executor/sql_query/sql_query.py +74 -74
  20. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +1 -2
  21. mindsdb/api/executor/sql_query/steps/subselect_step.py +0 -1
  22. mindsdb/api/executor/utilities/functions.py +6 -6
  23. mindsdb/api/executor/utilities/sql.py +37 -20
  24. mindsdb/api/http/gui.py +5 -11
  25. mindsdb/api/http/initialize.py +75 -61
  26. mindsdb/api/http/namespaces/agents.py +10 -15
  27. mindsdb/api/http/namespaces/analysis.py +13 -20
  28. mindsdb/api/http/namespaces/auth.py +1 -1
  29. mindsdb/api/http/namespaces/chatbots.py +0 -5
  30. mindsdb/api/http/namespaces/config.py +15 -11
  31. mindsdb/api/http/namespaces/databases.py +140 -201
  32. mindsdb/api/http/namespaces/file.py +17 -4
  33. mindsdb/api/http/namespaces/handlers.py +17 -7
  34. mindsdb/api/http/namespaces/knowledge_bases.py +28 -7
  35. mindsdb/api/http/namespaces/models.py +94 -126
  36. mindsdb/api/http/namespaces/projects.py +13 -22
  37. mindsdb/api/http/namespaces/sql.py +33 -25
  38. mindsdb/api/http/namespaces/tab.py +27 -37
  39. mindsdb/api/http/namespaces/views.py +1 -1
  40. mindsdb/api/http/start.py +16 -10
  41. mindsdb/api/mcp/__init__.py +2 -1
  42. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +15 -20
  43. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +26 -50
  44. mindsdb/api/mysql/mysql_proxy/utilities/__init__.py +0 -1
  45. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +8 -2
  46. mindsdb/integrations/handlers/byom_handler/byom_handler.py +165 -190
  47. mindsdb/integrations/handlers/databricks_handler/databricks_handler.py +98 -46
  48. mindsdb/integrations/handlers/druid_handler/druid_handler.py +32 -40
  49. mindsdb/integrations/handlers/file_handler/file_handler.py +7 -0
  50. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +5 -2
  51. mindsdb/integrations/handlers/lightwood_handler/functions.py +45 -79
  52. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +438 -100
  53. mindsdb/integrations/handlers/mssql_handler/requirements_odbc.txt +3 -0
  54. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +235 -3
  55. mindsdb/integrations/handlers/oracle_handler/__init__.py +2 -0
  56. mindsdb/integrations/handlers/oracle_handler/connection_args.py +7 -1
  57. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +321 -16
  58. mindsdb/integrations/handlers/oracle_handler/requirements.txt +1 -1
  59. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +14 -2
  60. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +25 -12
  61. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +2 -1
  62. mindsdb/integrations/handlers/statsforecast_handler/requirements.txt +1 -0
  63. mindsdb/integrations/handlers/statsforecast_handler/requirements_extra.txt +1 -0
  64. mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +4 -4
  65. mindsdb/integrations/handlers/zendesk_handler/zendesk_tables.py +144 -111
  66. mindsdb/integrations/libs/api_handler.py +10 -10
  67. mindsdb/integrations/libs/base.py +4 -4
  68. mindsdb/integrations/libs/llm/utils.py +2 -2
  69. mindsdb/integrations/libs/ml_handler_process/create_engine_process.py +4 -7
  70. mindsdb/integrations/libs/ml_handler_process/func_call_process.py +2 -7
  71. mindsdb/integrations/libs/ml_handler_process/learn_process.py +37 -47
  72. mindsdb/integrations/libs/ml_handler_process/update_engine_process.py +4 -7
  73. mindsdb/integrations/libs/ml_handler_process/update_process.py +2 -7
  74. mindsdb/integrations/libs/process_cache.py +132 -140
  75. mindsdb/integrations/libs/response.py +18 -12
  76. mindsdb/integrations/libs/vectordatabase_handler.py +26 -0
  77. mindsdb/integrations/utilities/files/file_reader.py +6 -7
  78. mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/__init__.py +1 -0
  79. mindsdb/integrations/utilities/handlers/auth_utilities/snowflake/snowflake_jwt_gen.py +151 -0
  80. mindsdb/integrations/utilities/rag/config_loader.py +37 -26
  81. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +83 -30
  82. mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +4 -4
  83. mindsdb/integrations/utilities/rag/retrievers/sql_retriever.py +55 -133
  84. mindsdb/integrations/utilities/rag/settings.py +58 -133
  85. mindsdb/integrations/utilities/rag/splitters/file_splitter.py +5 -15
  86. mindsdb/interfaces/agents/agents_controller.py +2 -3
  87. mindsdb/interfaces/agents/constants.py +0 -2
  88. mindsdb/interfaces/agents/litellm_server.py +34 -58
  89. mindsdb/interfaces/agents/mcp_client_agent.py +10 -10
  90. mindsdb/interfaces/agents/mindsdb_database_agent.py +5 -5
  91. mindsdb/interfaces/agents/run_mcp_agent.py +12 -21
  92. mindsdb/interfaces/chatbot/chatbot_task.py +20 -23
  93. mindsdb/interfaces/chatbot/polling.py +30 -18
  94. mindsdb/interfaces/data_catalog/data_catalog_loader.py +16 -17
  95. mindsdb/interfaces/data_catalog/data_catalog_reader.py +15 -4
  96. mindsdb/interfaces/database/data_handlers_cache.py +190 -0
  97. mindsdb/interfaces/database/database.py +3 -3
  98. mindsdb/interfaces/database/integrations.py +7 -110
  99. mindsdb/interfaces/database/projects.py +2 -6
  100. mindsdb/interfaces/database/views.py +1 -4
  101. mindsdb/interfaces/file/file_controller.py +6 -6
  102. mindsdb/interfaces/functions/controller.py +1 -1
  103. mindsdb/interfaces/functions/to_markdown.py +2 -2
  104. mindsdb/interfaces/jobs/jobs_controller.py +5 -9
  105. mindsdb/interfaces/jobs/scheduler.py +3 -9
  106. mindsdb/interfaces/knowledge_base/controller.py +244 -128
  107. mindsdb/interfaces/knowledge_base/evaluate.py +36 -41
  108. mindsdb/interfaces/knowledge_base/executor.py +11 -0
  109. mindsdb/interfaces/knowledge_base/llm_client.py +51 -17
  110. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +40 -61
  111. mindsdb/interfaces/model/model_controller.py +172 -168
  112. mindsdb/interfaces/query_context/context_controller.py +14 -2
  113. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +10 -14
  114. mindsdb/interfaces/skills/retrieval_tool.py +43 -50
  115. mindsdb/interfaces/skills/skill_tool.py +2 -2
  116. mindsdb/interfaces/skills/skills_controller.py +1 -4
  117. mindsdb/interfaces/skills/sql_agent.py +25 -19
  118. mindsdb/interfaces/storage/db.py +16 -6
  119. mindsdb/interfaces/storage/fs.py +114 -169
  120. mindsdb/interfaces/storage/json.py +19 -18
  121. mindsdb/interfaces/tabs/tabs_controller.py +49 -72
  122. mindsdb/interfaces/tasks/task_monitor.py +3 -9
  123. mindsdb/interfaces/tasks/task_thread.py +7 -9
  124. mindsdb/interfaces/triggers/trigger_task.py +7 -13
  125. mindsdb/interfaces/triggers/triggers_controller.py +47 -52
  126. mindsdb/migrations/migrate.py +16 -16
  127. mindsdb/utilities/api_status.py +58 -0
  128. mindsdb/utilities/config.py +68 -2
  129. mindsdb/utilities/exception.py +40 -1
  130. mindsdb/utilities/fs.py +0 -1
  131. mindsdb/utilities/hooks/profiling.py +17 -14
  132. mindsdb/utilities/json_encoder.py +24 -10
  133. mindsdb/utilities/langfuse.py +40 -45
  134. mindsdb/utilities/log.py +272 -0
  135. mindsdb/utilities/ml_task_queue/consumer.py +52 -58
  136. mindsdb/utilities/ml_task_queue/producer.py +26 -30
  137. mindsdb/utilities/render/sqlalchemy_render.py +22 -20
  138. mindsdb/utilities/starters.py +0 -10
  139. mindsdb/utilities/utils.py +2 -2
  140. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/METADATA +293 -276
  141. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/RECORD +144 -158
  142. mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -14
  143. mindsdb/api/postgres/__init__.py +0 -0
  144. mindsdb/api/postgres/postgres_proxy/__init__.py +0 -0
  145. mindsdb/api/postgres/postgres_proxy/executor/__init__.py +0 -1
  146. mindsdb/api/postgres/postgres_proxy/executor/executor.py +0 -189
  147. mindsdb/api/postgres/postgres_proxy/postgres_packets/__init__.py +0 -0
  148. mindsdb/api/postgres/postgres_proxy/postgres_packets/errors.py +0 -322
  149. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_fields.py +0 -34
  150. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message.py +0 -31
  151. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_formats.py +0 -1265
  152. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_message_identifiers.py +0 -31
  153. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_packets.py +0 -253
  154. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +0 -477
  155. mindsdb/api/postgres/postgres_proxy/utilities/__init__.py +0 -10
  156. mindsdb/api/postgres/start.py +0 -11
  157. mindsdb/integrations/handlers/mssql_handler/tests/__init__.py +0 -0
  158. mindsdb/integrations/handlers/mssql_handler/tests/test_mssql_handler.py +0 -169
  159. mindsdb/integrations/handlers/oracle_handler/tests/__init__.py +0 -0
  160. mindsdb/integrations/handlers/oracle_handler/tests/test_oracle_handler.py +0 -32
  161. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/WHEEL +0 -0
  162. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/licenses/LICENSE +0 -0
  163. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.10.0rc1.dist-info}/top_level.txt +0 -0
@@ -27,51 +27,40 @@ logger = log.getLogger(__name__)
27
27
 
28
28
 
29
29
  def create_learn_mark():
30
- if os.name == 'posix':
31
- p = Path(tempfile.gettempdir()).joinpath('mindsdb/learn_processes/')
30
+ if os.name == "posix":
31
+ p = Path(tempfile.gettempdir()).joinpath("mindsdb/learn_processes/")
32
32
  p.mkdir(parents=True, exist_ok=True)
33
- p.joinpath(f'{os.getpid()}').touch()
33
+ p.joinpath(f"{os.getpid()}").touch()
34
34
 
35
35
 
36
36
  def delete_learn_mark():
37
- if os.name == 'posix':
38
- p = (
39
- Path(tempfile.gettempdir())
40
- .joinpath('mindsdb/learn_processes/')
41
- .joinpath(f'{os.getpid()}')
42
- )
37
+ if os.name == "posix":
38
+ p = Path(tempfile.gettempdir()).joinpath("mindsdb/learn_processes/").joinpath(f"{os.getpid()}")
43
39
  if p.exists():
44
40
  p.unlink()
45
41
 
46
42
 
47
- @mark_process(name='learn')
43
+ @mark_process(name="learn")
48
44
  @profiler.profile()
49
45
  def run_generate(df: DataFrame, predictor_id: int, model_storage, args: dict = None):
46
+ model_storage.training_state_set(current_state_num=1, total_states=5, state_name="Generating problem definition")
47
+ json_ai_override = args.pop("using", {})
50
48
 
51
- model_storage.training_state_set(
52
- current_state_num=1, total_states=5, state_name='Generating problem definition'
53
- )
54
- json_ai_override = args.pop('using', {})
55
-
56
- if 'dtype_dict' in json_ai_override:
57
- args['dtype_dict'] = json_ai_override.pop('dtype_dict')
49
+ if "dtype_dict" in json_ai_override:
50
+ args["dtype_dict"] = json_ai_override.pop("dtype_dict")
58
51
 
59
- if 'problem_definition' in json_ai_override:
60
- args = {**args, **json_ai_override['problem_definition']}
52
+ if "problem_definition" in json_ai_override:
53
+ args = {**args, **json_ai_override["problem_definition"]}
61
54
 
62
- if 'timeseries_settings' in args:
63
- for tss_key in [
64
- f.name for f in dataclasses.fields(lightwood.api.TimeseriesSettings)
65
- ]:
66
- k = f'timeseries_settings.{tss_key}'
55
+ if "timeseries_settings" in args:
56
+ for tss_key in [f.name for f in dataclasses.fields(lightwood.api.TimeseriesSettings)]:
57
+ k = f"timeseries_settings.{tss_key}"
67
58
  if k in json_ai_override:
68
- args['timeseries_settings'][tss_key] = json_ai_override.pop(k)
59
+ args["timeseries_settings"][tss_key] = json_ai_override.pop(k)
69
60
 
70
61
  problem_definition = lightwood.ProblemDefinition.from_dict(args)
71
62
 
72
- model_storage.training_state_set(
73
- current_state_num=2, total_states=5, state_name='Generating JsonAI'
74
- )
63
+ model_storage.training_state_set(current_state_num=2, total_states=5, state_name="Generating JsonAI")
75
64
  json_ai = lightwood.json_ai_from_problem(df, problem_definition)
76
65
  json_ai = json_ai.to_dict()
77
66
  unpack_jsonai_old_args(json_ai_override)
@@ -79,9 +68,7 @@ def run_generate(df: DataFrame, predictor_id: int, model_storage, args: dict = N
79
68
  rep_recur(json_ai, json_ai_override)
80
69
  json_ai = JsonAI.from_dict(json_ai)
81
70
 
82
- model_storage.training_state_set(
83
- current_state_num=3, total_states=5, state_name='Generating code'
84
- )
71
+ model_storage.training_state_set(current_state_num=3, total_states=5, state_name="Generating code")
85
72
  code = lightwood.code_from_json_ai(json_ai)
86
73
 
87
74
  predictor_record = db.Predictor.query.with_for_update().get(predictor_id)
@@ -89,33 +76,27 @@ def run_generate(df: DataFrame, predictor_id: int, model_storage, args: dict = N
89
76
  db.session.commit()
90
77
 
91
78
  json_storage = get_json_storage(resource_id=predictor_id)
92
- json_storage.set('json_ai', json_ai.to_dict())
79
+ json_storage.set("json_ai", json_ai.to_dict())
93
80
 
94
81
 
95
- @mark_process(name='learn')
82
+ @mark_process(name="learn")
96
83
  @profiler.profile()
97
84
  def run_fit(predictor_id: int, df: pd.DataFrame, model_storage) -> None:
98
85
  try:
99
86
  predictor_record = db.Predictor.query.with_for_update().get(predictor_id)
100
87
  assert predictor_record is not None
101
88
 
102
- predictor_record.data = {'training_log': 'training'}
89
+ predictor_record.data = {"training_log": "training"}
103
90
  predictor_record.status = PREDICTOR_STATUS.TRAINING
104
91
  db.session.commit()
105
92
 
106
- model_storage.training_state_set(
107
- current_state_num=4, total_states=5, state_name='Training model'
108
- )
109
- predictor: lightwood.PredictorInterface = lightwood.predictor_from_code(
110
- predictor_record.code
111
- )
93
+ model_storage.training_state_set(current_state_num=4, total_states=5, state_name="Training model")
94
+ predictor: lightwood.PredictorInterface = lightwood.predictor_from_code(predictor_record.code)
112
95
  predictor.learn(df)
113
96
 
114
97
  db.session.refresh(predictor_record)
115
98
 
116
- fs = FileStorage(
117
- resource_group=RESOURCE_GROUP.PREDICTOR, resource_id=predictor_id, sync=True
118
- )
99
+ fs = FileStorage(resource_group=RESOURCE_GROUP.PREDICTOR, resource_id=predictor_id, sync=True)
119
100
  predictor.save(fs.folder_path / fs.folder_name)
120
101
  fs.push(compression_level=0)
121
102
 
@@ -124,9 +105,7 @@ def run_fit(predictor_id: int, df: pd.DataFrame, model_storage) -> None:
124
105
  # getting training time for each tried model. it is possible to do
125
106
  # after training only
126
107
  fit_mixers = list(
127
- predictor.runtime_log[x]
128
- for x in predictor.runtime_log
129
- if isinstance(x, tuple) and x[0] == "fit_mixer"
108
+ predictor.runtime_log[x] for x in predictor.runtime_log if isinstance(x, tuple) and x[0] == "fit_mixer"
130
109
  )
131
110
  submodel_data = predictor_record.data.get("submodel_data", [])
132
111
  # add training time to other mixers info
@@ -135,43 +114,39 @@ def run_fit(predictor_id: int, df: pd.DataFrame, model_storage) -> None:
135
114
  submodel_data[i]["training_time"] = tr_time
136
115
  predictor_record.data["submodel_data"] = submodel_data
137
116
 
138
- model_storage.training_state_set(
139
- current_state_num=5, total_states=5, state_name='Complete'
140
- )
117
+ model_storage.training_state_set(current_state_num=5, total_states=5, state_name="Complete")
141
118
  predictor_record.dtype_dict = predictor.dtype_dict
142
119
  db.session.commit()
143
120
  except Exception as e:
144
121
  db.session.refresh(predictor_record)
145
- predictor_record.data = {'error': f'{traceback.format_exc()}\nMain error: {e}'}
122
+ predictor_record.data = {"error": f"{traceback.format_exc()}\nMain error: {e}"}
146
123
  db.session.commit()
147
124
  raise e
148
125
 
149
126
 
150
- @mark_process(name='learn')
127
+ @mark_process(name="learn")
151
128
  def run_learn_remote(df: DataFrame, predictor_id: int) -> None:
152
129
  try:
153
130
  serialized_df = json.dumps(df.to_dict())
154
131
  predictor_record = db.Predictor.query.with_for_update().get(predictor_id)
155
132
  resp = requests.post(
156
- predictor_record.data['train_url'],
157
- json={'df': serialized_df, 'target': predictor_record.to_predict[0]},
133
+ predictor_record.data["train_url"],
134
+ json={"df": serialized_df, "target": predictor_record.to_predict[0]},
158
135
  )
159
136
 
160
137
  assert resp.status_code == 200
161
- predictor_record.data['status'] = 'complete'
138
+ predictor_record.data["status"] = "complete"
162
139
  except Exception:
163
- predictor_record.data['status'] = 'error'
164
- predictor_record.data['error'] = str(resp.text)
140
+ predictor_record.data["status"] = "error"
141
+ predictor_record.data["error"] = str(resp.text)
165
142
 
166
143
  db.session.commit()
167
144
 
168
145
 
169
- @mark_process(name='learn')
146
+ @mark_process(name="learn")
170
147
  def run_learn(df: DataFrame, args: dict, model_storage) -> None:
171
148
  if df is None or df.shape[0] == 0:
172
- raise Exception(
173
- 'No input data. Ensure the data source is healthy and try again.'
174
- )
149
+ raise Exception("No input data. Ensure the data source is healthy and try again.")
175
150
 
176
151
  predictor_id = model_storage.predictor_id
177
152
 
@@ -187,15 +162,13 @@ def run_learn(df: DataFrame, args: dict, model_storage) -> None:
187
162
  db.session.commit()
188
163
 
189
164
 
190
- @mark_process(name='finetune')
165
+ @mark_process(name="finetune")
191
166
  def run_finetune(df: DataFrame, args: dict, model_storage):
192
167
  try:
193
168
  if df is None or df.shape[0] == 0:
194
- raise Exception(
195
- 'No input data. Ensure the data source is healthy and try again.'
196
- )
169
+ raise Exception("No input data. Ensure the data source is healthy and try again.")
197
170
 
198
- base_predictor_id = args['base_model_id']
171
+ base_predictor_id = args["base_model_id"]
199
172
  base_predictor_record = db.Predictor.query.get(base_predictor_id)
200
173
  if base_predictor_record.status != PREDICTOR_STATUS.COMPLETE:
201
174
  raise Exception("Base model must be in status 'complete'")
@@ -204,11 +177,9 @@ def run_finetune(df: DataFrame, args: dict, model_storage):
204
177
  predictor_record = db.Predictor.query.get(predictor_id)
205
178
 
206
179
  # TODO move this to ModelStorage (don't work with database directly)
207
- predictor_record.data = {'training_log': 'training'}
180
+ predictor_record.data = {"training_log": "training"}
208
181
  predictor_record.training_start_at = datetime.now()
209
- predictor_record.status = (
210
- PREDICTOR_STATUS.FINETUNING
211
- ) # TODO: parallel execution block
182
+ predictor_record.status = PREDICTOR_STATUS.FINETUNING # TODO: parallel execution block
212
183
  db.session.commit()
213
184
 
214
185
  base_fs = FileStorage(
@@ -219,28 +190,23 @@ def run_finetune(df: DataFrame, args: dict, model_storage):
219
190
  predictor = lightwood.predictor_from_state(
220
191
  base_fs.folder_path / base_fs.folder_name, base_predictor_record.code
221
192
  )
222
- predictor.adjust(df, adjust_args=args.get('using', {}))
193
+ predictor.adjust(df, adjust_args=args.get("using", {}))
223
194
 
224
- fs = FileStorage(
225
- resource_group=RESOURCE_GROUP.PREDICTOR, resource_id=predictor_id, sync=True
226
- )
195
+ fs = FileStorage(resource_group=RESOURCE_GROUP.PREDICTOR, resource_id=predictor_id, sync=True)
227
196
  predictor.save(fs.folder_path / fs.folder_name)
228
197
  fs.push(compression_level=0)
229
198
 
230
- predictor_record.data = (
231
- predictor.model_analysis.to_dict()
232
- ) # todo: update accuracy in LW as post-finetune hook
199
+ predictor_record.data = predictor.model_analysis.to_dict() # todo: update accuracy in LW as post-finetune hook
233
200
  predictor_record.code = base_predictor_record.code
234
- predictor_record.update_status = 'up_to_date'
201
+ predictor_record.update_status = "up_to_date"
235
202
  predictor_record.status = PREDICTOR_STATUS.COMPLETE
236
203
  predictor_record.training_stop_at = datetime.now()
237
204
  db.session.commit()
238
205
 
239
206
  except Exception as e:
240
- logger.error(e)
207
+ logger.error("Unexpected error during Lightwood model finetune:", exc_info=True)
241
208
  predictor_id = model_storage.predictor_id
242
209
  predictor_record = db.Predictor.query.with_for_update().get(predictor_id)
243
- logger.error(traceback.format_exc())
244
210
  error_message = format_exception_error(e)
245
211
  predictor_record.data = {"error": error_message}
246
212
  predictor_record.status = PREDICTOR_STATUS.ERROR