🔧 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.session.service import SessionService
from langflow.services.task.service import TaskService from langflow.services.task.service import TaskService
from langflow.services.chat.service import ChatService from langflow.services.chat.service import ChatService
from langflow.services.plugins.service import PluginService
from sqlmodel import Session from sqlmodel import Session
def get_plugins_service() -> "PluginService":
return service_manager.get(ServiceType.PLUGIN_SERVICE)
def get_settings_service() -> "SettingsService": def get_settings_service() -> "SettingsService":
try: try:
return service_manager.get(ServiceType.SETTINGS_SERVICE) 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.getters import get_settings_service
from langflow.services.plugins.base import BasePlugin
from langflow.utils.logger import logger from langflow.utils.logger import logger
### Temporary implementation ### Temporary implementation
@ -52,3 +53,14 @@ class LangfuseInstance:
if cls._instance is not None: if cls._instance is not None:
cls._instance.flush() cls._instance.flush()
cls._instance = None 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" CHAT_SERVICE = "chat_service"
SESSION_SERVICE = "session_service" SESSION_SERVICE = "session_service"
TASK_SERVICE = "task_service" TASK_SERVICE = "task_service"
PLUGIN_SERVICE = "plugin_service"

View file

@ -48,6 +48,8 @@ class Settings(BaseSettings):
REDIS_DB: int = 0 REDIS_DB: int = 0
REDIS_CACHE_EXPIRE: int = 3600 REDIS_CACHE_EXPIRE: int = 3600
PLUGIN_DIR: Optional[str] = None
LANGFUSE_SECRET_KEY: Optional[str] = None LANGFUSE_SECRET_KEY: Optional[str] = None
LANGFUSE_PUBLIC_KEY: Optional[str] = None LANGFUSE_PUBLIC_KEY: Optional[str] = None
LANGFUSE_HOST: 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.auth import factory as auth_factory
from langflow.services.task import factory as task_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.session import factory as session_service_factory # type: ignore
from langflow.services.plugins import factory as plugins_factory
return [ return [
(settings_factory.SettingsServiceFactory(), []), (settings_factory.SettingsServiceFactory(), []),
@ -40,6 +41,7 @@ def get_factories_and_deps():
session_service_factory.SessionServiceFactory(), session_service_factory.SessionServiceFactory(),
[ServiceType.CACHE_SERVICE], [ServiceType.CACHE_SERVICE],
), ),
(plugins_factory.PluginServiceFactory(), [ServiceType.SETTINGS_SERVICE]),
] ]