Files
eveAI/eveai_chat_workers/specialists/base_specialist.py
Josako 1fdbd2ff45 - Move global config files to globals iso global folder, as the name global conflicts with python language
- Creation of Traicie Vancancy Definition specialist
- Allow to invoke non-interaction specialists from withing Evie's mgmt interface (eveai_app)
- Improvements to crewai specialized classes
- Introduction to json editor for showing specialists arguments and results in a better way
- Introduction of more complex pagination (adding extra arguments) by adding a global 'get_pagination_html'
- Allow follow-up of ChatSession / Specialist execution
- Improvement in logging of Specialists (but needs to be finished)
2025-05-26 11:26:03 +02:00

117 lines
4.5 KiB
Python

import importlib
from abc import ABC, abstractmethod
from typing import Dict, Any, List
from flask import current_app
from common.extensions import cache_manager
from common.models.interaction import SpecialistRetriever
from common.utils.execution_progress import ExecutionProgressTracker
from config.logging_config import TuningLogger
from eveai_chat_workers.retrievers.base import BaseRetriever
from eveai_chat_workers.retrievers.registry import RetrieverRegistry
from eveai_chat_workers.specialists.specialist_typing import SpecialistArguments, SpecialistResult
class BaseSpecialistExecutor(ABC):
"""Base class for all specialists"""
def __init__(self, tenant_id: int, specialist_id: int, session_id: str, task_id: str):
self.tenant_id = tenant_id
self.specialist_id = specialist_id
self.session_id = session_id
self.task_id = task_id
self.tuning = False
self.tuning_logger: TuningLogger = None
self._setup_tuning_logger()
self.ept = ExecutionProgressTracker()
@property
@abstractmethod
def type(self) -> str:
"""The type of the specialist"""
raise NotImplementedError
@property
@abstractmethod
def type_version(self) -> str:
"""The type version of the specialist"""
raise NotImplementedError
def _initialize_retrievers(self) -> List[BaseRetriever]:
"""Initialize all retrievers associated with this specialist"""
retrievers = []
# Get retriever associations from database
specialist_retrievers = (
SpecialistRetriever.query
.filter_by(specialist_id=self.specialist_id)
.all()
)
self.log_tuning("_initialize_retrievers", {"Nr of retrievers": len(specialist_retrievers)})
for spec_retriever in specialist_retrievers:
# Get retriever configuration from database
retriever = spec_retriever.retriever
retriever_class = RetrieverRegistry.get_retriever_class(retriever.type)
self.log_tuning("_initialize_retrievers", {
"Retriever id": spec_retriever.retriever_id,
"Retriever Type": retriever.type,
"Retriever Class": str(retriever_class),
})
# Initialize retriever with its configuration
retrievers.append(
retriever_class(
tenant_id=self.tenant_id,
retriever_id=retriever.id,
)
)
return retrievers
def _setup_tuning_logger(self):
try:
self.tuning_logger = TuningLogger(
'tuning',
tenant_id=self.tenant_id,
specialist_id=self.specialist_id,
session_id=self.session_id,
log_file=f"logs/tuning_{self.session_id}.log"
)
# Verify logger is working with a test message
if self.tuning:
self.tuning_logger.log_tuning('specialist', "Tuning logger initialized")
except Exception as e:
current_app.logger.error(f"Failed to setup tuning logger: {str(e)}")
raise
def log_tuning(self, message: str, data: Dict[str, Any] = None) -> None:
if self.tuning and self.tuning_logger:
try:
self.tuning_logger.log_tuning('specialist', message, data)
except Exception as e:
current_app.logger.error(f"Processor: Error in tuning logging: {e}")
def update_progress(self, processing_type, data) -> None:
self.ept.send_update(self.task_id, processing_type, data)
@abstractmethod
def execute_specialist(self, arguments: SpecialistArguments) -> SpecialistResult:
"""Execute the specialist's logic"""
raise NotImplementedError
def get_specialist_class(specialist_type: str, type_version: str):
major_minor = '_'.join(type_version.split('.')[:2])
specialist_config = cache_manager.specialists_config_cache.get_config(specialist_type, type_version)
partner = specialist_config.get("partner", None)
current_app.logger.debug(f"Specialist partner for {specialist_type} {type_version} is {partner}")
if partner:
module_path = f"eveai_chat_workers.specialists.{partner}.{specialist_type}.{major_minor}"
else:
module_path = f"eveai_chat_workers.specialists.{specialist_type}.{major_minor}"
current_app.logger.debug(f"Importing specialist class from {module_path}")
module = importlib.import_module(module_path)
return module.SpecialistExecutor