OllamaInterface/OllamaClient.py

changeset 9
c471738b75b3
parent 8
3118d16e526e
child 11
3641ea6b55d5
equal deleted inserted replaced
8:3118d16e526e 9:c471738b75b3
204 """ 204 """
205 Public method to ask the 'ollama' server to delete the given model. 205 Public method to ask the 'ollama' server to delete the given model.
206 206
207 @param model name of the model 207 @param model name of the model
208 @type str 208 @type str
209 """ 209 @return flag indicating success
210 # TODO: not implemented yet 210 @rtype bool
211 """
211 ollamaRequest = { 212 ollamaRequest = {
212 "name": model, 213 "model": model,
213 } 214 }
214 self.__sendRequest("delete", data=ollamaRequest) 215 _, status = self.__sendSyncRequest("delete", data=ollamaRequest, delete=True)
216 return status == 200 # HTTP status 200 OK
215 217
216 def list(self): 218 def list(self):
217 """ 219 """
218 Public method to request a list of models available locally from the 'ollama' 220 Public method to request a list of models available locally from the 'ollama'
219 server. 221 server.
230 models = [] 232 models = []
231 with contextlib.suppress(KeyError): 233 with contextlib.suppress(KeyError):
232 for model in response["models"]: 234 for model in response["models"]:
233 name = model["name"] 235 name = model["name"]
234 if name: 236 if name:
235 models.append(name.replace(":latest", "")) 237 models.append(name)
236 self.modelsList.emit(models) 238 self.modelsList.emit(models)
237 239
238 def listDetails(self): 240 def listDetails(self):
239 """ 241 """
240 Public method to request a list of models available locally from the 'ollama' 242 Public method to request a list of models available locally from the 'ollama'
241 server with some model details. 243 server with some model details.
242 """ 244
243 response = self.__sendSyncRequest("tags") 245 @return list of dictionaries containing the available models and related data
246 @rtype list[dict[str, Any]]
247 """
248 response, _ = self.__sendSyncRequest("tags")
244 249
245 models = [] 250 models = []
246 if response is not None: 251 if response is not None:
247 with contextlib.suppress(KeyError): 252 with contextlib.suppress(KeyError):
248 for model in response["models"]: 253 for model in response["models"]:
262 return models 267 return models
263 268
264 def listRunning(self): 269 def listRunning(self):
265 """ 270 """
266 Public method to request a list of running models from the 'ollama' server. 271 Public method to request a list of running models from the 'ollama' server.
267 """ 272
268 response = self.__sendSyncRequest("ps") 273 @return list of dictionaries containing the running models and related data
274 @rtype list[dict[str, Any]]
275 """
276 response, _ = self.__sendSyncRequest("ps")
269 277
270 models = [] 278 models = []
271 if response is not None: 279 if response is not None:
272 with contextlib.suppress(KeyError): 280 with contextlib.suppress(KeyError):
273 for model in response["models"]: 281 for model in response["models"]:
323 @return current client state 331 @return current client state
324 @rtype OllamaClientState 332 @rtype OllamaClientState
325 """ 333 """
326 return self.__state 334 return self.__state
327 335
328 def __getServerReply(self, endpoint, data=None): 336 def __getServerReply(self, endpoint, data=None, delete=False):
329 """ 337 """
330 Private method to send a request to the 'ollama' server and return a reply 338 Private method to send a request to the 'ollama' server and return a reply
331 object. 339 object.
332 340
333 @param endpoint 'ollama' API endpoint to be contacted 341 @param endpoint 'ollama' API endpoint to be contacted
334 @type str 342 @type str
335 @param data dictionary containing the data to send to the server 343 @param data dictionary containing the data to send to the server
336 (defaults to None) 344 (defaults to None)
337 @type dict (optional) 345 @type dict (optional)
346 @param delete flag indicating to send a delete request (defaults to False)
347 @type bool (optional)
338 @return 'ollama' server reply 348 @return 'ollama' server reply
339 @rtype QNetworkReply 349 @rtype QNetworkReply
340 """ 350 """
341 ollamaUrl = QUrl( 351 ollamaUrl = QUrl(
342 "{0}://{1}:{2}/api/{3}".format( 352 "{0}://{1}:{2}/api/{3}".format(
343 self.__plugin.getPreferences("OllamaScheme"), 353 self.__plugin.getPreferences("OllamaScheme"),
344 ( 354 (
345 "127.0.0.1" 355 "127.0.0.1"
346 if self.__localServer 356 if self.__localServer
358 if data is not None: 368 if data is not None:
359 request.setHeader( 369 request.setHeader(
360 QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json" 370 QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json"
361 ) 371 )
362 jsonData = json.dumps(data).encode("utf-8") 372 jsonData = json.dumps(data).encode("utf-8")
363 reply = self.__networkManager.post(request, jsonData) 373 if delete:
374 reply = self.__networkManager.sendCustomRequest(
375 request, b"DELETE", jsonData
376 )
377 else:
378 reply = self.__networkManager.post(request, jsonData)
364 else: 379 else:
365 reply = self.__networkManager.get(request) 380 reply = self.__networkManager.get(request)
366 reply.errorOccurred.connect(lambda error: self.__errorOccurred(error, reply)) 381 reply.errorOccurred.connect(lambda error: self.__errorOccurred(error, reply))
367 return reply 382 return reply
368 383
379 @param processResponse function handling the received data (defaults to None) 394 @param processResponse function handling the received data (defaults to None)
380 @type function (optional) 395 @type function (optional)
381 """ 396 """
382 self.__state = OllamaClientState.Requesting 397 self.__state = OllamaClientState.Requesting
383 398
384 ##ollamaUrl = QUrl(
385 ##"{0}://{1}:{2}/api/{3}".format(
386 ##self.__plugin.getPreferences("OllamaScheme"),
387 ##(
388 ##"127.0.0.1"
389 ##if self.__localServer
390 ##else self.__plugin.getPreferences("OllamaHost")
391 ##),
392 ##(
393 ##self.__plugin.getPreferences("OllamaLocalPort")
394 ##if self.__localServer
395 ##else self.__plugin.getPreferences("OllamaPort")
396 ##),
397 ##endpoint,
398 ##)
399 ##)
400 ##request = QNetworkRequest(ollamaUrl)
401 ##if data is not None:
402 ##request.setHeader(
403 ##QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json"
404 ##)
405 ##jsonData = json.dumps(data).encode("utf-8")
406 ##reply = self.__networkManager.post(request, jsonData)
407 ##else:
408 ##reply = self.__networkManager.get(request)
409 ##
410 reply = self.__getServerReply(endpoint=endpoint, data=data) 399 reply = self.__getServerReply(endpoint=endpoint, data=data)
411 reply.finished.connect(lambda: self.__replyFinished(reply)) 400 reply.finished.connect(lambda: self.__replyFinished(reply))
412 ##reply.errorOccurred.connect(lambda error: self.__errorOccurred(error, reply))
413 reply.readyRead.connect(lambda: self.__processData(reply, processResponse)) 401 reply.readyRead.connect(lambda: self.__processData(reply, processResponse))
414 self.__replies.append(reply) 402 self.__replies.append(reply)
415 403
416 def __replyFinished(self, reply): 404 def __replyFinished(self, reply):
417 """ 405 """
460 with contextlib.suppress(json.JSONDecodeError): 448 with contextlib.suppress(json.JSONDecodeError):
461 data = json.loads(buffer) 449 data = json.loads(buffer)
462 if data and processResponse: 450 if data and processResponse:
463 processResponse(data) 451 processResponse(data)
464 452
465 def __sendSyncRequest(self, endpoint, data=None): 453 def __sendSyncRequest(self, endpoint, data=None, delete=False):
466 """ 454 """
467 Private method to send a request to the 'ollama' server and handle its 455 Private method to send a request to the 'ollama' server and handle its
468 responses. 456 responses.
469 457
470 @param endpoint 'ollama' API endpoint to be contacted 458 @param endpoint 'ollama' API endpoint to be contacted
471 @type str 459 @type str
472 @param data dictionary containing the data to send to the server 460 @param data dictionary containing the data to send to the server
473 (defaults to None) 461 (defaults to None)
474 @type dict (optional) 462 @type dict (optional)
463 @param delete flag indicating to send a delete request (defaults to False)
464 @type bool (optional)
465 @return tuple containing the data sent by the 'ollama' server and the HTTP
466 status code
467 @rtype tuple of (Any, int)
475 """ 468 """
476 self.__state = OllamaClientState.Requesting 469 self.__state = OllamaClientState.Requesting
477 470
478 reply = self.__getServerReply(endpoint=endpoint, data=data) 471 reply = self.__getServerReply(endpoint=endpoint, data=data, delete=delete)
479 while not reply.isFinished(): 472 while not reply.isFinished():
480 QCoreApplication.processEvents() 473 QCoreApplication.processEvents()
481 QThread.msleep(100) 474 QThread.msleep(100)
482 475
483 reply.deleteLater() 476 reply.deleteLater()
484 477
485 self.__state = OllamaClientState.Finished 478 self.__state = OllamaClientState.Finished
479
480 statusCode = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute)
486 481
487 if reply.error() == QNetworkReply.NetworkError.NoError: 482 if reply.error() == QNetworkReply.NetworkError.NoError:
488 buffer = bytes(reply.readAll()) 483 buffer = bytes(reply.readAll())
489 with contextlib.suppress(json.JSONDecodeError): 484 with contextlib.suppress(json.JSONDecodeError):
490 data = json.loads(buffer) 485 data = json.loads(buffer)
491 return data 486 return data, statusCode
492 487
493 return None 488 return None, statusCode
494 489
495 def heartbeat(self): 490 def heartbeat(self):
496 """ 491 """
497 Public method to check, if the 'ollama' server has started and is responsive. 492 Public method to check, if the 'ollama' server has started and is responsive.
498 493

eric ide

mercurial