Coverage for mindsdb / api / http / namespaces / chatbots.py: 79%

151 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1from http import HTTPStatus 

2 

3from flask import request 

4from flask_restx import Resource 

5 

6from mindsdb.api.http.namespaces.configs.projects import ns_conf 

7from mindsdb.interfaces.agents.agents_controller import AgentsController 

8from mindsdb.api.executor.controllers.session_controller import SessionController 

9from mindsdb.api.http.utils import http_error 

10from mindsdb.metrics.metrics import api_endpoint_metrics 

11from mindsdb.interfaces.chatbot.chatbot_controller import ChatBotController 

12from mindsdb.interfaces.model.functions import PredictorRecordNotFound 

13from mindsdb.interfaces.storage.db import Predictor 

14from mindsdb.utilities.exception import EntityNotExistsError 

15 

16 

17def create_chatbot(project_name, name, chatbot): 

18 if name is None: 

19 return http_error(HTTPStatus.BAD_REQUEST, "Missing field", 'Missing "name" field for chatbot') 

20 

21 model_name = chatbot.get("model_name", None) 

22 agent_name = chatbot.get("agent_name", None) 

23 if model_name is None and agent_name is None: 

24 return http_error( 

25 HTTPStatus.BAD_REQUEST, 

26 "Missing field", 

27 'Must include either "model_name" or "agent_name" field for chatbot', 

28 ) 

29 

30 session_controller = SessionController() 

31 

32 if "database_id" in chatbot or "database_name" in chatbot or ("db_engine" in chatbot and "db_params" in chatbot): 

33 try: 

34 database_id = get_or_create_database_for_chatbot(chatbot, session_controller) 

35 except ValueError as value_error: 

36 return http_error(HTTPStatus.NOT_FOUND, "Database not found", str(value_error)) 

37 

38 else: 

39 return http_error( 

40 HTTPStatus.BAD_REQUEST, 

41 "Missing field", 

42 'Missing "database_id" or ("db_engine" and "database_param") fields for chatbot', 

43 ) 

44 

45 is_running = chatbot.get("is_running", False) 

46 params = chatbot.get("params", {}) 

47 

48 chatbot_controller = ChatBotController() 

49 

50 # Chatbot can't already exist. 

51 # TODO all checks should be inside of controller 

52 

53 try: 

54 existing_chatbot = chatbot_controller.get_chatbot(name, project_name=project_name) 

55 except EntityNotExistsError: 

56 # Project must exist. 

57 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist") 

58 if existing_chatbot is not None: 58 ↛ 59line 58 didn't jump to line 59 because the condition on line 58 was never true

59 return http_error( 

60 HTTPStatus.CONFLICT, 

61 "Chatbot already exists", 

62 f"Chatbot with name {name} already exists. Please use a different name", 

63 ) 

64 

65 # Model and agent need to exist. 

66 if agent_name is not None: 66 ↛ 67line 66 didn't jump to line 67 because the condition on line 66 was never true

67 agent = AgentsController().get_agent(agent_name, project_name) 

68 if agent is None: 

69 return http_error(HTTPStatus.NOT_FOUND, "Agent not found", f"Agent with name {agent_name} not found") 

70 model_name = agent.model_name 

71 

72 model_name_no_version, version = Predictor.get_name_and_version(model_name) 

73 try: 

74 session_controller.model_controller.get_model(model_name_no_version, version=version, project_name=project_name) 

75 except PredictorRecordNotFound: 

76 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found") 

77 

78 created_chatbot = chatbot_controller.add_chatbot( 

79 name, 

80 project_name, 

81 model_name=model_name, 

82 agent_name=agent_name, 

83 database_id=database_id, 

84 is_running=is_running, 

85 params=params, 

86 ) 

87 return created_chatbot.as_dict(), HTTPStatus.CREATED 

88 

89 

90def get_or_create_database_for_chatbot(chatbot: dict, session_controller: SessionController) -> int: 

91 """ 

92 Get or create a database for a chatbot, based on the chatbot configuration provided in the request. 

93 

94 Args: 

95 chatbot (dict): The chatbot configuration. 

96 session_controller (SessionController): The session controller. 

97 

98 Returns: 

99 int: The database ID. 

100 """ 

101 if "database_id" in chatbot: 

102 database_record = session_controller.integration_controller.get_by_id(chatbot["database_id"]) 

103 if database_record: 103 ↛ 106line 103 didn't jump to line 106 because the condition on line 103 was always true

104 return database_record["id"] 

105 else: 

106 raise ValueError(f"Database with ID {chatbot['database_id']} not found") 

107 

108 elif "database_name" in chatbot: 108 ↛ 109line 108 didn't jump to line 109 because the condition on line 108 was never true

109 database_record = session_controller.integration_controller.get(chatbot["database_name"]) 

110 if database_record: 

111 return database_record["id"] 

112 else: 

113 raise ValueError(f"Database with name {chatbot['database_name']} not found") 

114 

115 if "db_params" in chatbot and "db_engine" in chatbot: 115 ↛ 116line 115 didn't jump to line 116 because the condition on line 115 was never true

116 db_name = chatbot["name"] + "_db" 

117 

118 # try to drop 

119 existing_db = session_controller.integration_controller.get(db_name) 

120 if existing_db: 

121 # drop 

122 session_controller.integration_controller.delete(db_name) 

123 

124 return session_controller.integration_controller.add(db_name, chatbot["db_engine"], chatbot["db_params"]) 

125 

126 return None 

127 

128 

129@ns_conf.route("/<project_name>/chatbots") 

130class ChatBotsResource(Resource): 

131 @ns_conf.doc("list_chatbots") 

132 @api_endpoint_metrics("GET", "/chatbots") 

133 def get(self, project_name): 

134 """List all chatbots""" 

135 chatbot_controller = ChatBotController() 

136 try: 

137 all_bots = chatbot_controller.get_chatbots(project_name) 

138 except (ValueError, EntityNotExistsError): 

139 # Project needs to exist. 

140 return http_error( 

141 HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist" 

142 ) 

143 return all_bots 

144 

145 @ns_conf.doc("create_chatbot") 

146 @api_endpoint_metrics("POST", "/chatbots") 

147 def post(self, project_name): 

148 """Create a chatbot""" 

149 

150 # Check for required parameters. 

151 if "chatbot" not in request.json: 

152 return http_error( 

153 HTTPStatus.BAD_REQUEST, "Missing parameter", 'Must provide "chatbot" parameter in POST body' 

154 ) 

155 

156 chatbot = request.json["chatbot"] 

157 

158 name = chatbot.get("name") 

159 return create_chatbot(project_name, name, chatbot) 

160 

161 

162@ns_conf.route("/<project_name>/chatbots/<chatbot_name>") 

163@ns_conf.param("project_name", "Name of the project") 

164@ns_conf.param("chatbot_name", "Name of the chatbot") 

165class ChatBotResource(Resource): 

166 @ns_conf.doc("get_chatbot") 

167 @api_endpoint_metrics("GET", "/chatbots/chatbot") 

168 def get(self, project_name, chatbot_name): 

169 """Gets a chatbot by name""" 

170 chatbot_controller = ChatBotController() 

171 try: 

172 existing_chatbot = chatbot_controller.get_chatbot(chatbot_name, project_name=project_name) 

173 if existing_chatbot is None: 

174 return http_error( 

175 HTTPStatus.NOT_FOUND, "Chatbot not found", f"Chatbot with name {chatbot_name} does not exist" 

176 ) 

177 return existing_chatbot 

178 except (ValueError, EntityNotExistsError): 

179 # Project needs to exist. 

180 return http_error( 

181 HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist" 

182 ) 

183 

184 @ns_conf.doc("update_chatbot") 

185 @api_endpoint_metrics("PUT", "/chatbots/chatbot") 

186 def put(self, project_name, chatbot_name): 

187 """Updates a chatbot by name, creating one if it doesn't exist""" 

188 

189 # Check for required parameters. 

190 if "chatbot" not in request.json: 

191 return http_error( 

192 HTTPStatus.BAD_REQUEST, "Missing parameter", 'Must provide "chatbot" parameter in POST body' 

193 ) 

194 chatbot_controller = ChatBotController() 

195 

196 try: 

197 existing_chatbot = chatbot_controller.get_chatbot(chatbot_name, project_name=project_name) 

198 except EntityNotExistsError: 

199 # Project needs to exist. 

200 return http_error( 

201 HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist" 

202 ) 

203 

204 session = SessionController() 

205 

206 chatbot = request.json["chatbot"] 

207 name = chatbot.get("name", None) 

208 agent_name = chatbot.get("agent_name", None) 

209 model_name = chatbot.get("model_name", None) 

210 try: 

211 database_id = get_or_create_database_for_chatbot(chatbot, session) 

212 except ValueError as value_error: 

213 return http_error(HTTPStatus.NOT_FOUND, "Database not found", str(value_error)) 

214 is_running = chatbot.get("is_running", None) 

215 params = chatbot.get("params", None) 

216 

217 # Model needs to exist. 

218 if model_name is not None: 

219 model_name_no_version, version = Predictor.get_name_and_version(model_name) 

220 try: 

221 session.model_controller.get_model(model_name_no_version, version=version, project_name=project_name) 

222 except PredictorRecordNotFound: 

223 return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found") 

224 

225 # Agent needs to exist. 

226 if agent_name is not None: 226 ↛ 227line 226 didn't jump to line 227 because the condition on line 226 was never true

227 agent = session.agents_controller.get_agent(agent_name, project_name) 

228 if agent is None: 

229 return http_error(HTTPStatus.NOT_FOUND, "Agent not found", f"Agent with name {agent_name} not found") 

230 

231 # Chatbot must not exist with new name. 

232 if name is not None: 

233 if name != chatbot_name: 233 ↛ 234line 233 didn't jump to line 234 because the condition on line 233 was never true

234 chatbot_with_new_name = chatbot_controller.get_chatbot(name, project_name=project_name) 

235 if chatbot_with_new_name is not None: 

236 return http_error( 

237 HTTPStatus.CONFLICT, 

238 "Chatbot already exists", 

239 f"Chatbot with name {name} already exists. Please choose a different one.", 

240 ) 

241 

242 if existing_chatbot is None: 

243 # Create 

244 return create_chatbot(project_name, name, chatbot) 

245 

246 # Update 

247 updated_chatbot = chatbot_controller.update_chatbot( 

248 chatbot_name, 

249 project_name=project_name, 

250 name=name, 

251 model_name=model_name, 

252 agent_name=agent_name, 

253 database_id=database_id, 

254 is_running=is_running, 

255 params=params, 

256 ) 

257 return updated_chatbot.as_dict() 

258 

259 @ns_conf.doc("delete_chatbot") 

260 @api_endpoint_metrics("DELETE", "/chatbots/chatbot") 

261 def delete(self, project_name, chatbot_name): 

262 """Deletes a chatbot by name""" 

263 chatbot_controller = ChatBotController() 

264 try: 

265 existing_chatbot = chatbot_controller.get_chatbot(chatbot_name, project_name=project_name) 

266 if existing_chatbot is None: 

267 return http_error( 

268 HTTPStatus.NOT_FOUND, "Chatbot not found", f"Chatbot with name {chatbot_name} does not exist" 

269 ) 

270 except EntityNotExistsError: 

271 # Project needs to exist. 

272 return http_error( 

273 HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist" 

274 ) 

275 

276 chatbot_controller.delete_chatbot(chatbot_name, project_name=project_name) 

277 return "", HTTPStatus.NO_CONTENT