Wed, 18 Sep 2024 13:11:38 +0200
Prepared new release.
# -*- coding: utf-8 -*- # Copyright (c) 2024 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the ollama Interface plug-in. """ import os from PyQt6.QtCore import QCoreApplication, QObject, Qt, QTranslator, pyqtSignal from PyQt6.QtGui import QKeySequence from eric7 import Globals, Preferences from eric7.EricGui import EricPixmapCache from eric7.EricGui.EricAction import EricAction from eric7.EricWidgets.EricApplication import ericApp try: from eric7.UI.UserInterface import UserInterfaceSide _Side = UserInterfaceSide.Right except ImportError: # backward compatibility for eric < 24.2 from eric7.UI.UserInterface import UserInterface _Side = UserInterface.RightSide # Start-Of-Header __header__ = { "name": "ollama Interface", "author": "Detlev Offenbach <detlev@die-offenbachs.de>", "autoactivate": True, "deactivateable": True, "version": "10.1.1", "className": "PluginOllamaInterface", "packageName": "OllamaInterface", "shortDescription": "Graphical 'ollama' client for eric-ide.", "longDescription": ( "Plug-in implementing an 'ollama' client and interface widgets." ), "needsRestart": False, "hasCompiledForms": True, "pyqtApi": 2, } # End-Of-Header error = "" # noqa: U200 ollamaInterfacePluginObject = None def createOllamaPage(_configDlg): """ Function to create the 'ollama' interface' configuration page. @param _configDlg reference to the configuration dialog @type ConfigurationWidget @return reference to the configuration page @rtype OllamaPage """ from OllamaInterface.ConfigurationPage.OllamaPage import OllamaPage global ollamaInterfacePluginObject page = OllamaPage(ollamaInterfacePluginObject) return page def getConfigData(): """ Function returning data as required by the configuration dialog. @return dictionary containing the relevant data @rtype dict """ usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "light" return { "ollamaPage": [ QCoreApplication.translate("PluginOllamaInterface", "ollama AI Interface"), os.path.join("OllamaInterface", "icons", "ollama22-{0}".format(iconSuffix)), createOllamaPage, None, None, ], } def prepareUninstall(): """ Function to prepare for an un-installation. """ Preferences.getSettings().remove(PluginOllamaInterface.PreferencesKey) def clearPrivateData(): """ Function to clear the private data of the plug-in. """ if ollamaInterfacePluginObject is not None: widget = ollamaInterfacePluginObject.getWidget() if widget is not None: widget.clearHistory() class PluginOllamaInterface(QObject): """ Class implementing the ollama Interface plug-in. @signal preferencesChanged() emitted to signal a change of preferences. This signal is simply relayed from the main UI. """ PreferencesKey = "Ollama" preferencesChanged = pyqtSignal() def __init__(self, ui): """ Constructor @param ui reference to the user interface object @type UI.UserInterface """ super().__init__(ui) self.__ui = ui self.__initialize() self.__defaults = { "OllamaScheme": "http", "OllamaHost": "localhost", "OllamaPort": 11434, "OllamaLocalPort": 11435, # port for locally started ollama server "OllamaHeartbeatInterval": 5, # 5 seconds heartbeat time; 0 = disabled "StreamingChatResponse": True, "OllamaModelLibraryUrl": "https://ollama.com/library", "OllamaDownloadUrl": "https://ollama.com/download", "OllamaBlogUrl": "https://ollama.com/blog", } self.__translator = None self.__loadTranslator() def __initialize(self): """ Private slot to (re)initialize the plugin. """ self.__widget = None def activate(self): """ Public method to activate this plug-in. @return tuple of None and activation status @rtype bool """ from OllamaInterface.OllamaWidget import OllamaWidget global error, ollamaInterfacePluginObject error = "" # clear previous error ollamaInterfacePluginObject = self usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "light" self.__widget = OllamaWidget(self, fromEric=True) iconName = ( "sbOllama96" if self.__ui.getLayoutType() == "Sidebars" else "ollama22-{0}".format(iconSuffix) ) self.__ui.addSideWidget( _Side, self.__widget, EricPixmapCache.getIcon(os.path.join("OllamaInterface", "icons", iconName)), self.tr("ollama AI Interface"), ) self.__activateAct = EricAction( self.tr("ollama AI Interface"), self.tr("ollama AI Interface"), QKeySequence(self.tr("Ctrl+Alt+Shift+O")), 0, self, "ollama_interface_activate", ) self.__activateAct.setStatusTip( self.tr("Switch the input focus to the ollama AI window.") ) self.__activateAct.setWhatsThis( self.tr( """<b>Activate ollama AI Interface</b>""" """<p>This switches the input focus to the ollama AI window.</p>""" ) ) self.__activateAct.triggered.connect(self.__activateWidget) self.__ui.addEricActions([self.__activateAct], "ui") menu = self.__ui.getMenu("subwindow") menu.addAction(self.__activateAct) self.__ui.preferencesChanged.connect(self.preferencesChanged) return None, True def deactivate(self): """ Public method to deactivate this plug-in. """ self.__ui.preferencesChanged.disconnect(self.preferencesChanged) menu = self.__ui.getMenu("subwindow") menu.removeAction(self.__activateAct) self.__ui.removeEricActions([self.__activateAct], "ui") self.__ui.removeSideWidget(self.__widget) self.__initialize() def __loadTranslator(self): """ Private method to load the translation file. """ if self.__ui is not None: loc = self.__ui.getLocale() if loc and loc != "C": locale_dir = os.path.join( os.path.dirname(__file__), "OllamaInterface", "i18n" ) translation = "ollama_{0}".format(loc) translator = QTranslator(None) loaded = translator.load(translation, locale_dir) if loaded: self.__translator = translator ericApp().installTranslator(self.__translator) else: print( "Warning: translation file '{0}' could not be" " loaded.".format(translation) ) print("Using default.") def getWidget(self): """ Public method to get a reference to the 'ollama' widget. @return reference to the 'ollama' widget @rtype OllamaWidget """ return self.__widget def __activateWidget(self): """ Private slot to handle the activation of the pipx interface. """ uiLayoutType = self.__ui.getLayoutType() if uiLayoutType == "Toolboxes": self.__ui.rToolboxDock.show() self.__ui.rToolbox.setCurrentWidget(self.__widget) elif uiLayoutType == "Sidebars": try: self.__ui.activateLeftRightSidebarWidget(self.__widget) except AttributeError: self.__activateLeftRightSidebarWidget(self.__widget) else: self.__widget.show() self.__widget.setFocus(Qt.FocusReason.ActiveWindowFocusReason) def getPreferences(self, key): """ Public method to retrieve the various settings values. @param key the key of the value to get @type str @return the requested setting value @rtype Any """ if key in ("OllamaPort", "OllamaLocalPort", "OllamaHeartbeatInterval"): return int( Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) ) elif key in ("StreamingChatResponse",): return Globals.toBool( Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) ) elif key in ( "OllamaHost", "OllamaModelLibraryUrl", "OllamaDownloadUrl", "OllamaBlogUrl", ): value = Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) if not value: # use default value if empty value = self.__defaults[key] return value else: return Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) return None def setPreferences(self, key, value): """ Public method to store the various settings values. @param key the key of the setting to be set @type str @param value the value to be set @type Any """ Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value) ############################################################################ ## Methods for backward compatibility with eric-ide < 24.9 ############################################################################ def __activateLeftRightSidebarWidget(self, widget): """ Private method to activate the given widget in the left or right sidebar. @param widget reference to the widget to be activated @type QWidget """ # This is for backward compatibility with eric-ide < 24.9. sidebar = ( self.__ui.leftSidebar if Preferences.getUI("CombinedLeftRightSidebar") else self.__ui.rightSidebar ) sidebar.show() sidebar.setCurrentWidget(widget) # # eflag: noqa = M801, U200