🔧 fix(getters.py): add import statement for PluginService in getters.py to fix import error

 feat(plugins/base.py): add BasePlugin class with initialize, teardown, and get methods to serve as base class for plugins
 feat(plugins/factory.py): add PluginServiceFactory class to create PluginService instance and load plugins
 feat(plugins/langfuse.py): add LangfusePlugin class with initialize, teardown, and get methods to serve as a plugin for Langfuse
 feat(plugins/service.py): add PluginService class to manage plugins, load plugins, register plugins, get plugins, and teardown plugins
 feat(schema.py): add PLUGIN_SERVICE to ServiceType enum to support plugin service
🔧 fix(settings/base.py): add PLUGIN_DIR optional setting to support specifying plugin directory
🔧 fix(utils.py): add import statement for plugins_factory in utils.py to fix import error
This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-11-02 16:51:03 -03:00
commit faa2a79c2b
8 changed files with 100 additions and 0 deletions

View file

@ -9,9 +9,14 @@ if TYPE_CHECKING:
from langflow.services.session.service import SessionService
from langflow.services.task.service import TaskService
from langflow.services.chat.service import ChatService
from langflow.services.plugins.service import PluginService
from sqlmodel import Session
def get_plugins_service() -> "PluginService":
return service_manager.get(ServiceType.PLUGIN_SERVICE)
def get_settings_service() -> "SettingsService":
try:
return service_manager.get(ServiceType.SETTINGS_SERVICE)

View file

@ -0,0 +1,12 @@
from typing import Any
class BasePlugin:
def initialize(self):
pass
def teardown(self):
pass
def get(self) -> Any:
pass

View file

@ -0,0 +1,16 @@
from typing import TYPE_CHECKING
from langflow.services.plugins.service import PluginService
from langflow.services.factory import ServiceFactory
if TYPE_CHECKING:
from langflow.services.settings.service import SettingsService
class PluginServiceFactory(ServiceFactory):
def __init__(self):
super().__init__(PluginService)
def create(self, settings_service: "SettingsService"):
service = PluginService(settings_service)
service.load_plugins()
return service

View file

@ -1,4 +1,5 @@
from langflow.services.getters import get_settings_service
from langflow.services.plugins.base import BasePlugin
from langflow.utils.logger import logger
### Temporary implementation
@ -52,3 +53,14 @@ class LangfuseInstance:
if cls._instance is not None:
cls._instance.flush()
cls._instance = None
class LangfusePlugin(BasePlugin):
def initialize(self):
LangfuseInstance.create()
def teardown(self):
LangfuseInstance.teardown()
def get(self):
return LangfuseInstance.get()

View file

@ -0,0 +1,50 @@
import importlib
import inspect
import os
from langflow.services.base import Service
from langflow.services.plugins.base import BasePlugin
from typing import TYPE_CHECKING, Union
if TYPE_CHECKING:
from langflow.services.settings.service import SettingsService
class PluginService(Service):
name = "plugin_service"
def __init__(self, settings_service: "SettingsService"):
self.plugins = {}
plugin_dir = settings_service.settings.PLUGIN_DIR
self.plugin_dir = plugin_dir or os.path.dirname(__file__)
def load_plugins(self):
base_files = ["base.py", "service.py", "factory.py", "__init__.py"]
for module in os.listdir(self.plugin_dir):
if module.endswith(".py") and module not in base_files:
plugin_name = module[:-3]
module_path = f"{self.plugin_dir}.{plugin_name}"
mod = importlib.import_module(module_path)
for attr_name in dir(mod):
attr = getattr(mod, attr_name)
if (
inspect.isclass(attr)
and issubclass(attr, BasePlugin)
and attr is not BasePlugin
):
self.register_plugin(plugin_name, attr())
def register_plugin(self, plugin_name, plugin_instance):
self.plugins[plugin_name] = plugin_instance
plugin_instance.initialize()
def get_plugin(self, plugin_name) -> Union[BasePlugin, None]:
return self.plugins.get(plugin_name)
def get(self, plugin_name):
if plugin := self.get_plugin(plugin_name):
return plugin.get()
return None
def teardown(self):
for plugin in self.plugins.values():
plugin.teardown()

View file

@ -14,3 +14,4 @@ class ServiceType(str, Enum):
CHAT_SERVICE = "chat_service"
SESSION_SERVICE = "session_service"
TASK_SERVICE = "task_service"
PLUGIN_SERVICE = "plugin_service"

View file

@ -48,6 +48,8 @@ class Settings(BaseSettings):
REDIS_DB: int = 0
REDIS_CACHE_EXPIRE: int = 3600
PLUGIN_DIR: Optional[str] = None
LANGFUSE_SECRET_KEY: Optional[str] = None
LANGFUSE_PUBLIC_KEY: Optional[str] = None
LANGFUSE_HOST: Optional[str] = None

View file

@ -19,6 +19,7 @@ def get_factories_and_deps():
from langflow.services.auth import factory as auth_factory
from langflow.services.task import factory as task_factory
from langflow.services.session import factory as session_service_factory # type: ignore
from langflow.services.plugins import factory as plugins_factory
return [
(settings_factory.SettingsServiceFactory(), []),
@ -40,6 +41,7 @@ def get_factories_and_deps():
session_service_factory.SessionServiceFactory(),
[ServiceType.CACHE_SERVICE],
),
(plugins_factory.PluginServiceFactory(), [ServiceType.SETTINGS_SERVICE]),
]