🔧 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:
parent
0a4de7ca94
commit
faa2a79c2b
8 changed files with 100 additions and 0 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
12
src/backend/langflow/services/plugins/base.py
Normal file
12
src/backend/langflow/services/plugins/base.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class BasePlugin:
|
||||||
|
def initialize(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def teardown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get(self) -> Any:
|
||||||
|
pass
|
||||||
16
src/backend/langflow/services/plugins/factory.py
Normal file
16
src/backend/langflow/services/plugins/factory.py
Normal 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
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
50
src/backend/langflow/services/plugins/service.py
Normal file
50
src/backend/langflow/services/plugins/service.py
Normal 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()
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue