84 self.mainSplitter.setSizes([200, 2000]) |
84 self.mainSplitter.setSizes([200, 2000]) |
85 |
85 |
86 self.newChatButton.setEnabled(False) |
86 self.newChatButton.setEnabled(False) |
87 self.__handleServerStateChanged(False) |
87 self.__handleServerStateChanged(False) |
88 |
88 |
|
89 self.__pullProgressDialog = None |
|
90 self.__pulling = False |
|
91 |
89 self.__localServerDialog = None |
92 self.__localServerDialog = None |
90 self.__localServerProcess = None |
93 self.__localServerProcess = None |
91 |
94 |
92 self.__availableModels = [] |
95 self.__availableModels = [] |
93 |
96 |
108 self.__client.serverStateChanged.connect(self.__handleServerStateChanged) |
111 self.__client.serverStateChanged.connect(self.__handleServerStateChanged) |
109 self.__client.serverVersion.connect(self.__setHeaderLabel) |
112 self.__client.serverVersion.connect(self.__setHeaderLabel) |
110 self.__client.modelsList.connect(self.__populateModelSelector) |
113 self.__client.modelsList.connect(self.__populateModelSelector) |
111 self.__client.modelsList.connect(self.__checkHistoryModels) |
114 self.__client.modelsList.connect(self.__checkHistoryModels) |
112 self.__client.replyReceived.connect(self.__handleServerMessage) |
115 self.__client.replyReceived.connect(self.__handleServerMessage) |
|
116 self.__client.pullStatus.connect(self.__handlePullStatus) |
|
117 self.__client.pullError.connect(self.__handlePullError) |
|
118 |
|
119 self.__client.errorOccurred.connect(self.__handleClientError) |
|
120 self.__client.finished.connect(self.__handleClientFinished) |
113 |
121 |
114 @pyqtSlot(bool) |
122 @pyqtSlot(bool) |
115 def __handleServerStateChanged(self, ok): |
123 def __handleServerStateChanged(self, ok): |
116 """ |
124 """ |
117 Private slot handling a change in the 'ollama' server responsiveness. |
125 Private slot handling a change in the 'ollama' server responsiveness. |
603 def __initOllamaMenu(self): |
611 def __initOllamaMenu(self): |
604 """ |
612 """ |
605 Private method to create the super menu and attach it to the super |
613 Private method to create the super menu and attach it to the super |
606 menu button. |
614 menu button. |
607 """ |
615 """ |
608 # TODO: implement the menu and menu methods |
|
609 # * Pull Model |
|
610 ################################################################### |
616 ################################################################### |
611 ## Menu with Chat History related actions |
617 ## Menu with Chat History related actions |
612 ################################################################### |
618 ################################################################### |
613 |
619 |
614 self.__chatHistoryMenu = QMenu(self.tr("Chat History")) |
620 self.__chatHistoryMenu = QMenu(self.tr("Chat History")) |
633 self.__modelMenu.addSeparator() |
639 self.__modelMenu.addSeparator() |
634 self.__modelMenu.addAction( |
640 self.__modelMenu.addAction( |
635 self.tr("Show Model Library"), self.__showModelLibrary |
641 self.tr("Show Model Library"), self.__showModelLibrary |
636 ) |
642 ) |
637 self.__modelMenu.addSeparator() |
643 self.__modelMenu.addSeparator() |
638 self.__modelMenu.addAction(self.tr("Download Model"), self.__pullModel) |
644 self.__pullModelAct = self.__modelMenu.addAction( |
|
645 self.tr("Install Model"), self.__pullModel |
|
646 ) |
639 self.__removeModelAct = self.__modelMenu.addAction( |
647 self.__removeModelAct = self.__modelMenu.addAction( |
640 self.tr("Remove Model"), self.__removeModel |
648 self.tr("Remove Model"), self.__removeModel |
641 ) |
649 ) |
642 |
650 |
643 ################################################################### |
651 ################################################################### |
688 ) |
696 ) |
689 self.__stopLocalServerAct.setEnabled( |
697 self.__stopLocalServerAct.setEnabled( |
690 self.__localServerProcess is not None and self.__localServerDialog is None |
698 self.__localServerProcess is not None and self.__localServerDialog is None |
691 ) |
699 ) |
692 |
700 |
|
701 self.__pullModelAct.setEnabled(not self.__pulling) |
693 self.__removeModelAct.setEnabled(bool(self.__availableModels)) |
702 self.__removeModelAct.setEnabled(bool(self.__availableModels)) |
694 |
703 |
695 @pyqtSlot() |
704 @pyqtSlot() |
696 def __ollamaConfigure(self): |
705 def __ollamaConfigure(self): |
697 """ |
706 """ |
927 @pyqtSlot() |
936 @pyqtSlot() |
928 def __pullModel(self): |
937 def __pullModel(self): |
929 """ |
938 """ |
930 Private slot to download a model from the 'ollama' model library. |
939 Private slot to download a model from the 'ollama' model library. |
931 """ |
940 """ |
932 # TODO: not implemented yet |
941 from .OllamaPullProgressDialog import OllamaPullProgressDialog |
933 pass |
942 |
|
943 if self.__pulling: |
|
944 # only one pull operation supported |
|
945 return |
|
946 |
|
947 model, ok = QInputDialog.getText( |
|
948 self, |
|
949 self.tr("Install Model"), |
|
950 self.tr("Enter the name of the model to be installed:"), |
|
951 QLineEdit.EchoMode.Normal, |
|
952 ) |
|
953 if ok and model: |
|
954 self.__pulling = True |
|
955 |
|
956 if self.__pullProgressDialog is None: |
|
957 self.__pullProgressDialog = OllamaPullProgressDialog(self) |
|
958 self.__pullProgressDialog.abortPull.connect(self.__client.abortPull) |
|
959 |
|
960 self.__pullProgressDialog.setModel(model) |
|
961 self.__pullProgressDialog.clear() |
|
962 self.__pullProgressDialog.show() |
|
963 |
|
964 self.__client.pull(model) |
|
965 |
|
966 @pyqtSlot(str, str, "unsigned long int", "unsigned long int") |
|
967 def __handlePullStatus(self, status, idStr, total, completed): |
|
968 """ |
|
969 Private slot to handle a pull status update. |
|
970 |
|
971 @param status status message reported by the 'ollama' server |
|
972 @type str |
|
973 @param idStr ID of the file being pulled or empty |
|
974 @type str |
|
975 @param total size of the file being pulled or 0 in case of an empty ID |
|
976 @type int |
|
977 @param completed downloaded bytes or 0 in case of an empty ID |
|
978 @type int |
|
979 """ |
|
980 if self.__pullProgressDialog is not None: |
|
981 self.__pullProgressDialog.setStatus(status, idStr, total, completed) |
|
982 |
|
983 @pyqtSlot(str) |
|
984 def __handlePullError(self, errMsg): |
|
985 """ |
|
986 Private slot to handle an error during a pull operation. |
|
987 |
|
988 @param errMsg error message |
|
989 @type str |
|
990 """ |
|
991 if self.__pullProgressDialog is not None: |
|
992 self.__pullProgressDialog.showError(errMsg) |
934 |
993 |
935 @pyqtSlot() |
994 @pyqtSlot() |
936 def __removeModel(self): |
995 def __removeModel(self): |
937 """ |
996 """ |
938 Private slot to remove a model from the 'ollama' server. |
997 Private slot to remove a model from the 'ollama' server. |
964 self.tr( |
1023 self.tr( |
965 "<p>The model <b>{0}</b> could not be removed from the" |
1024 "<p>The model <b>{0}</b> could not be removed from the" |
966 " 'ollama' server.</p>" |
1025 " 'ollama' server.</p>" |
967 ).format(modelName), |
1026 ).format(modelName), |
968 ) |
1027 ) |
|
1028 |
|
1029 @pyqtSlot(str) |
|
1030 def __handleClientError(self, errMsg): |
|
1031 """ |
|
1032 Private slot to handle an error message sent by the server. |
|
1033 |
|
1034 @param errMsg error message |
|
1035 @type str |
|
1036 """ |
|
1037 EricMessageBox.warning( |
|
1038 self, |
|
1039 self.tr("Network Error"), |
|
1040 errMsg, |
|
1041 ) |
|
1042 |
|
1043 @pyqtSlot() |
|
1044 def __handleClientFinished(self): |
|
1045 """ |
|
1046 Private slot to handle the end of a client server interaction. |
|
1047 """ |
|
1048 if self.__pullProgressDialog is not None and self.__pulling: |
|
1049 self.__pullProgressDialog.setFinished(True) |
|
1050 self.__pulling = False |
|
1051 self.__client.list() |