OllamaInterface/OllamaWidget.py

changeset 8
3118d16e526e
parent 7
eb1dec15b2f0
child 9
c471738b75b3
equal deleted inserted replaced
7:eb1dec15b2f0 8:3118d16e526e
7 """ 7 """
8 8
9 import json 9 import json
10 import os 10 import os
11 11
12 from PyQt6.QtCore import QProcessEnvironment, Qt, QTimer, pyqtSlot 12 from PyQt6.QtCore import QProcess, QProcessEnvironment, Qt, QTimer, pyqtSlot, QUrl
13 from PyQt6.QtGui import QDesktopServices
13 from PyQt6.QtWidgets import ( 14 from PyQt6.QtWidgets import (
14 QDialog, 15 QDialog,
15 QInputDialog, 16 QInputDialog,
16 QLineEdit, 17 QLineEdit,
17 QMenu, 18 QMenu,
134 @pyqtSlot() 135 @pyqtSlot()
135 def on_reloadModelsButton_clicked(self): 136 def on_reloadModelsButton_clicked(self):
136 """ 137 """
137 Private slot to reload the list of available models. 138 Private slot to reload the list of available models.
138 """ 139 """
139 self.__client.list() 140 self.__finishSetup()
140 141
141 @pyqtSlot(str) 142 @pyqtSlot(str)
142 def on_modelComboBox_currentTextChanged(self, model): 143 def on_modelComboBox_currentTextChanged(self, model):
143 """ 144 """
144 Private slot handling the selection of a model. 145 Private slot handling the selection of a model.
597 """ 598 """
598 Private method to create the super menu and attach it to the super 599 Private method to create the super menu and attach it to the super
599 menu button. 600 menu button.
600 """ 601 """
601 # TODO: implement the menu and menu methods 602 # TODO: implement the menu and menu methods
602 # * Show Model Details
603 # * Show Model Processes
604 # * Pull Model 603 # * Pull Model
605 # * Show Model Shop (via a web browser)
606 # * Remove Model 604 # * Remove Model
607 # * Local Server
608 # * Start
609 # * Stop
610 ################################################################### 605 ###################################################################
611 ## Menu with Chat History related actions 606 ## Menu with Chat History related actions
612 ################################################################### 607 ###################################################################
613 608
614 self.__chatHistoryMenu = QMenu(self.tr("Chat History")) 609 self.__chatHistoryMenu = QMenu(self.tr("Chat History"))
620 self.__chatHistoryMenu.addSeparator() 615 self.__chatHistoryMenu.addSeparator()
621 self.__chatHistoryMenu.addAction(self.tr("Import"), self.__menuImportHistories) 616 self.__chatHistoryMenu.addAction(self.tr("Import"), self.__menuImportHistories)
622 self.__chatHistoryMenu.addAction(self.tr("Export"), self.__menuExportHistories) 617 self.__chatHistoryMenu.addAction(self.tr("Export"), self.__menuExportHistories)
623 618
624 ################################################################### 619 ###################################################################
620 ## Menu with Model related actions
621 ###################################################################
622
623 self.__modelMenu = QMenu(self.tr("Model Management"))
624 self.__modelMenu.addAction(self.tr("List Models"), self.__showModels)
625 self.__modelMenu.addAction(
626 self.tr("List Running Models"), self.__showRunningModels
627 )
628 self.__modelMenu.addSeparator()
629 self.__modelMenu.addAction(
630 self.tr("Show Model Library"), self.__showModelLibrary
631 )
632 self.__modelMenu.addSeparator()
633 self.__modelMenu.addAction(self.tr("Download Model"), self.__pullModel)
634 self.__modelMenu.addAction(self.tr("Remove Model"), self.__removeModel)
635
636 ###################################################################
625 ## Menu with Local Server related actions 637 ## Menu with Local Server related actions
626 ################################################################### 638 ###################################################################
627 639
628 self.__localServerMenu = QMenu(self.tr("Local Server")) 640 self.__localServerMenu = QMenu(self.tr("Local Server"))
629 self.__localServerStartMonitorAct = self.__localServerMenu.addAction( 641 self.__localServerStartMonitorAct = self.__localServerMenu.addAction(
641 ## Main menu 653 ## Main menu
642 ################################################################### 654 ###################################################################
643 655
644 self.__ollamaMenu = QMenu() 656 self.__ollamaMenu = QMenu()
645 self.__ollamaMenu.addMenu(self.__chatHistoryMenu) 657 self.__ollamaMenu.addMenu(self.__chatHistoryMenu)
658 self.__ollamaMenu.addSeparator()
659 self.__ollamaMenu.addMenu(self.__modelMenu)
646 self.__ollamaMenu.addSeparator() 660 self.__ollamaMenu.addSeparator()
647 self.__ollamaMenu.addMenu(self.__localServerMenu) 661 self.__ollamaMenu.addMenu(self.__localServerMenu)
648 self.__ollamaMenu.addSeparator() 662 self.__ollamaMenu.addSeparator()
649 self.__ollamaMenu.addAction(self.tr("Configure..."), self.__ollamaConfigure) 663 self.__ollamaMenu.addAction(self.tr("Configure..."), self.__ollamaConfigure)
650 664
768 def __startLocalServerMonitoring(self): 782 def __startLocalServerMonitoring(self):
769 """ 783 """
770 Private slot to open a dialog for running a local 'ollama' server instance 784 Private slot to open a dialog for running a local 'ollama' server instance
771 and monitor its output. 785 and monitor its output.
772 """ 786 """
773 # TODO: not implemented yet
774 from .RunOllamaServerDialog import RunOllamaServerDialog 787 from .RunOllamaServerDialog import RunOllamaServerDialog
775 788
776 self.__localServerDialog = RunOllamaServerDialog( 789 self.__localServerDialog = RunOllamaServerDialog(
777 self.__client, self.__plugin, self 790 self.__client, self.__plugin, self
778 ) 791 )
781 self.__localServerDialog.finished.connect(self.__serverDialogClosed) 794 self.__localServerDialog.finished.connect(self.__serverDialogClosed)
782 self.__localServerDialog.show() 795 self.__localServerDialog.show()
783 self.__localServerDialog.startServer() 796 self.__localServerDialog.startServer()
784 797
785 @pyqtSlot() 798 @pyqtSlot()
799 def __serverStarted(self):
800 """
801 Private slot to handle the start of a local server.
802 """
803 self.__client.setMode(True)
804 self.on_reloadModelsButton_clicked()
805
806 @pyqtSlot()
807 def __serverStopped(self):
808 """
809 Private slot to handle the stopping of a local server.
810 """
811 self.__client.setMode(False)
812 self.on_reloadModelsButton_clicked()
813
814 @pyqtSlot()
815 def __serverDialogClosed(self):
816 """
817 Private slot handling the closing of the local server dialog.
818 """
819 self.__localServerDialog.deleteLater()
820 self.__localServerDialog = None
821
822 @pyqtSlot()
786 def __startLocalServer(self): 823 def __startLocalServer(self):
787 """ 824 """
788 Private slot to start a local 'ollama' server instance in the background. 825 Private slot to start a local 'ollama' server instance in the background.
826 """
827 env = self.prepareServerRuntimeEnvironment()
828 self.__localServerProcess = QProcess()
829 self.__localServerProcess.setProcessEnvironment(env)
830 self.__localServerProcess.finished.connect(self.__localServerProcessFinished)
831
832 command = "ollama"
833 args = ["serve"]
834
835 self.__localServerProcess.start(command, args)
836 ok = self.__localServerProcess.waitForStarted(10000)
837 if not ok:
838 EricMessageBox.critical(
839 None,
840 self.tr("Run Local 'ollama' Server"),
841 self.tr("""The loacl 'ollama' server process could not be started."""),
842 )
843 self.__localServerProcess = None
844 else:
845 self.__serverStarted()
846
847 @pyqtSlot()
848 def __stopLocalServer(self):
849 """
850 Private slot to stop a running local 'ollama' server instance.
851 """
852 if self.__localServerProcess is not None:
853 self.__localServerProcess.terminate()
854
855 @pyqtSlot()
856 def __localServerProcessFinished(self):
857 """
858 Private slot handling the finishing of the local 'ollama' server process.
859 """
860 if (
861 self.__localServerProcess is not None
862 and self.__localServerProcess.state() != QProcess.ProcessState.NotRunning
863 ):
864 self.__localServerProcess.terminate()
865 QTimer.singleShot(2000, self.__localServerProcess.kill)
866 self.__localServerProcess.waitForFinished(3000)
867
868 self.__localServerProcess = None
869
870 self.__serverStopped()
871
872 @pyqtSlot()
873 def __showModels(self):
874 """
875 Private slot to ask the 'ollama' server for a list of available models with
876 some details.
877 """
878 from .OllamaDetailedModelsDialog import OllamaDetailedModelsDialog
879
880 models = self.__client.listDetails()
881 if models:
882 dlg = OllamaDetailedModelsDialog(models, self)
883 dlg.exec()
884 else:
885 EricMessageBox.information(
886 self,
887 self.tr("List Models"),
888 self.tr("There are no models available."),
889 )
890
891 @pyqtSlot()
892 def __showRunningModels(self):
893 """
894 Private slot to show a dialog with data of the running models.
895 """
896 from .OllamaRunningModelsDialog import OllamaRunningModelsDialog
897
898 models = self.__client.listRunning()
899 if models:
900 dlg = OllamaRunningModelsDialog(models, self)
901 dlg.exec()
902 else:
903 EricMessageBox.information(
904 self,
905 self.tr("List Running Models"),
906 self.tr("There are no models running."),
907 )
908
909 @pyqtSlot()
910 def __showModelLibrary(self):
911 """
912 Private slot to open the 'ollama' model librayr web site.
913 """
914 urlStr = self.__plugin.getPreferences("OllamaModelLibraryUrl")
915 url = QUrl.fromUserInput(urlStr)
916 QDesktopServices.openUrl(url)
917
918 @pyqtSlot()
919 def __pullModel(self):
920 """
921 Private slot to download a model from the 'ollama' model library.
789 """ 922 """
790 # TODO: not implemented yet 923 # TODO: not implemented yet
791 pass 924 pass
792 925
793 @pyqtSlot() 926 @pyqtSlot()
794 def __stopLocalServer(self): 927 def __removeModel(self):
795 """ 928 """
796 Private slot to stop a running local 'ollama' server instance. 929 Private slot to remove a model from the 'ollama' server.
797 """ 930 """
798 # TODO: not implemented yet 931 # TODO: not implemented yet
799 pass 932 pass
800
801 @pyqtSlot()
802 def __serverStarted(self):
803 """
804 Private slot to handle the start of a local server.
805 """
806 self.__client.setMode(True)
807 self.on_reloadModelsButton_clicked()
808
809 @pyqtSlot()
810 def __serverStopped(self):
811 """
812 Private slot to handle the stopping of a local server.
813 """
814 self.__client.setMode(False)
815 self.on_reloadModelsButton_clicked()
816
817 @pyqtSlot()
818 def __serverDialogClosed(self):
819 """
820 Private slot handling the closing of the local server dialog.
821 """
822 self.__localServerDialog.deleteLater()
823 self.__localServerDialog = None

eric ide

mercurial