Coverage for mindsdb / api / http / namespaces / models.py: 75%
156 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
1from http import HTTPStatus
3import json
5from flask import request
6from flask_restx import Resource
7import pandas as pd
9from mindsdb.api.http.namespaces.configs.projects import ns_conf
10from mindsdb.api.http.utils import http_error
11from mindsdb.api.executor.controllers.session_controller import SessionController
12from mindsdb.metrics.metrics import api_endpoint_metrics
13from mindsdb.interfaces.model.functions import PredictorRecordNotFound
14from mindsdb.interfaces.storage.db import Predictor
15from mindsdb_sql_parser import parse_sql
16from mindsdb_sql_parser.ast.mindsdb import CreatePredictor
17from mindsdb.utilities.exception import EntityNotExistsError
18from mindsdb.utilities import log
20logger = log.getLogger(__name__)
23@ns_conf.route("/<project_name>/models")
24class ModelsList(Resource):
25 @ns_conf.doc("list_models")
26 @api_endpoint_metrics("GET", "/models")
27 def get(self, project_name):
28 """List all models"""
29 session = SessionController()
31 try:
32 session.database_controller.get_project(project_name)
33 except EntityNotExistsError:
34 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
36 return session.model_controller.get_models(with_versions=True, project_name=project_name)
38 @ns_conf.doc("train_model")
39 @api_endpoint_metrics("POST", "/models")
40 def post(self, project_name):
41 """Creates a new model and trains it"""
42 session = SessionController()
44 if "query" not in request.json:
45 return http_error(HTTPStatus.BAD_REQUEST, "Query required", 'Missing "query" SQL statement')
46 query = request.json["query"]
48 project_datanode = session.datahub.get(project_name)
49 if project_datanode is None:
50 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
52 try:
53 create_statement = parse_sql(query)
54 except Exception:
55 return http_error(
56 HTTPStatus.BAD_REQUEST, "Invalid query string", f"SQL CREATE statement is invalid: {query}"
57 )
59 if type(create_statement) is not CreatePredictor:
60 return http_error(
61 HTTPStatus.BAD_REQUEST,
62 "Invalid CREATE SQL statement",
63 f"SQL statement is not a CREATE model statement: {query}",
64 )
66 model_name = create_statement.name.parts[1].lower()
67 try:
68 session.model_controller.get_model(model_name, project_name=project_name)
69 return http_error(
70 HTTPStatus.CONFLICT, "Model already exists", f"Model with name {model_name} already exists"
71 )
72 except PredictorRecordNotFound:
73 pass
75 ml_integration = "lightwood"
76 if create_statement.using is not None: 76 ↛ 81line 76 didn't jump to line 81 because the condition on line 76 was always true
77 # Convert using to lowercase
78 create_statement.using = {k.lower(): v for k, v in create_statement.using.items()}
79 ml_integration = create_statement.using.pop("engine", ml_integration)
81 try:
82 ml_handler = session.integration_controller.get_ml_handler(ml_integration)
83 except Exception:
84 return http_error(
85 HTTPStatus.NOT_FOUND, "ML handler not found", f"Cannot find ML handler with name {ml_integration}"
86 )
88 try:
89 model_df = session.model_controller.create_model(create_statement, ml_handler)
90 # Consistent format with GET /projects/<project_name>/models/<model_name>
91 return {
92 "name": model_df.at[0, "NAME"],
93 "accuracy": None,
94 "active": model_df.at[0, "ACTIVE"],
95 "version": model_df.at[0, "VERSION"],
96 "status": model_df.at[0, "STATUS"],
97 "predict": model_df.at[0, "PREDICT"],
98 "mindsdb_version": model_df.at[0, "MINDSDB_VERSION"],
99 "error": model_df.at[0, "ERROR"],
100 "fetch_data_query": model_df.at[0, "SELECT_DATA_QUERY"],
101 "problem_definition": model_df.at[0, "TRAINING_OPTIONS"],
102 }, HTTPStatus.CREATED
103 except Exception as e:
104 logger.exception("Something went wrong while creating and training model")
105 return http_error(
106 HTTPStatus.INTERNAL_SERVER_ERROR,
107 "Unable to train model",
108 f"Something went wrong while creating and training model {model_name}: {e}",
109 )
112@ns_conf.route("/<project_name>/models/<model_name>")
113@ns_conf.param("project_name", "Name of the project")
114@ns_conf.param("model_name", "Name of the model")
115class ModelResource(Resource):
116 @ns_conf.doc("get_model")
117 @api_endpoint_metrics("GET", "/models/model")
118 def get(self, project_name, model_name):
119 """Get a model by name and version"""
120 session = SessionController()
122 project_datanode = session.datahub.get(project_name)
123 if project_datanode is None:
124 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
126 name_no_version, version = Predictor.get_name_and_version(model_name)
127 try:
128 return session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
129 except PredictorRecordNotFound:
130 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
132 @ns_conf.doc("update_model")
133 @api_endpoint_metrics("PUT", "/models/model")
134 def put(self, project_name, model_name):
135 """Update model"""
137 session = SessionController()
139 project_datanode = session.datahub.get(project_name)
140 if project_datanode is None:
141 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
143 if "problem_definition" not in request.json:
144 return http_error(
145 HTTPStatus.BAD_REQUEST, "problem_definition required", 'Missing "problem_definition" field'
146 )
148 problem_definition = request.json["problem_definition"]
150 model_name, version = Predictor.get_name_and_version(model_name)
152 session.model_controller.update_model(
153 session,
154 project_name,
155 model_name,
156 version=version,
157 problem_definition=problem_definition,
158 )
159 return session.model_controller.get_model(model_name, version=version, project_name=project_name)
161 @ns_conf.doc("delete_model")
162 @api_endpoint_metrics("DELETE", "/models/model")
163 def delete(self, project_name, model_name):
164 """Deletes a model by name"""
166 session = SessionController()
168 project_datanode = session.datahub.get(project_name)
169 if project_datanode is None:
170 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
172 name_no_version, version = Predictor.get_name_and_version(model_name)
173 try:
174 session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
175 except PredictorRecordNotFound:
176 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
178 try:
179 session.model_controller.delete_model(name_no_version, project_name, version=version)
180 except Exception as e:
181 logger.exception(f"Something went wrong while deleting model '{model_name}'")
182 return http_error(
183 HTTPStatus.INTERNAL_SERVER_ERROR,
184 "Error deleting model",
185 f"Something went wrong while deleting {model_name}: {e}",
186 )
188 return "", HTTPStatus.NO_CONTENT
191@ns_conf.route("/<project_name>/models/<model_name>/predict")
192@ns_conf.param("project_name", "Name of the project")
193@ns_conf.param("model_name", "Name of the model")
194class ModelPredict(Resource):
195 @ns_conf.doc("post_model_predict")
196 @api_endpoint_metrics("POST", "/models/model/predict")
197 def post(self, project_name, model_name):
198 """Call prediction"""
200 name_no_version, version = Predictor.get_name_and_version(model_name)
202 session = SessionController()
203 project_datanode = session.datahub.get(project_name)
204 if project_datanode is None:
205 return http_error(
206 HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist"
207 )
209 try:
210 session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
211 except PredictorRecordNotFound:
212 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
214 data = request.json["data"]
215 if isinstance(data, str):
216 # Support object or serialized object.
217 data = json.loads(data)
218 params = request.json.get("params")
220 predictions = project_datanode.predict(
221 model_name=name_no_version,
222 df=pd.DataFrame(data),
223 version=version,
224 params=params,
225 )
227 return predictions.to_dict("records")
230@ns_conf.route("/<project_name>/models/<model_name>/describe")
231@ns_conf.param("project_name", "Name of the project")
232@ns_conf.param("model_name", "Name of the model")
233class ModelDescribe(Resource):
234 @ns_conf.doc("describe_model")
235 @api_endpoint_metrics("GET", "/models/model/describe")
236 def get(self, project_name, model_name):
237 """Describes a model"""
238 session = SessionController()
240 project_datanode = session.datahub.get(project_name)
241 if project_datanode is None:
242 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
244 name_no_version, version = Predictor.get_name_and_version(model_name)
246 try:
247 session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
248 except PredictorRecordNotFound:
249 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
251 attribute = None
252 if "attribute" in request.json:
253 attribute = request.json["attribute"]
255 try:
256 description_df = session.model_controller.describe_model(
257 session, project_name, name_no_version, attribute, version=version
258 )
259 return description_df.to_dict("records")
260 except Exception:
261 return http_error(
262 HTTPStatus.BAD_REQUEST,
263 "ML handler unsupported",
264 f"ML handler for {model_name} does not support model description",
265 )