from fastapi import Depends, HTTPException, status, Header
from typing import List, Any, Optional, Annotated
from sqlalchemy.orm import Session
from app.db import models
from app.db.session import SessionLocal
from app.core.retrievers.base_retriever import Retriever
from app.core.services.document import DocumentService
from app.core.services.rag import RAGService
from app.core.vector_store.faiss_store import FaissVectorStore
# This is a dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# Dependency to get current user object from X-User-ID header
async def get_current_user(
db: Session = Depends(get_db),
x_user_id: Annotated[Optional[str], Header()] = None
) -> models.User:
if not x_user_id:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="X-User-ID header is missing"
)
user = db.query(models.User).filter(models.User.id == x_user_id).first()
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found"
)
return user
class ServiceContainer:
"""
A flexible container for managing and providing various application services.
Services are added dynamically using the `with_service` method.
"""
def __init__(self):
# Use a dictionary to store services, mapping their names to instances
self._services = {}
self.document_service = None
self.rag_service = None
def with_service(self, name: str, service: Any):
"""
Adds a service to the container.
Args:
name (str): The name to assign to the service (e.g., 'tts_service').
service (Any): The service instance to add.
"""
setattr(self, name, service)
return self
def with_document_service(self, vector_store: Optional[FaissVectorStore]):
"""
Adds a DocumentService instance to the container.
"""
if vector_store:
self.document_service = DocumentService(vector_store=vector_store)
return self
def with_rag_service(self, retrievers: List[Retriever], prompt_service = None, tool_service = None, node_registry_service = None):
"""
Adds a RAGService instance to the container.
"""
self.rag_service = RAGService(retrievers=retrievers, prompt_service=prompt_service, tool_service=tool_service, node_registry_service=node_registry_service)
return self
def __getattr__(self, name: str) -> Any:
"""
Allows services to be accessed directly as attributes (e.g., container.rag_service).
"""
raise AttributeError(f"'{self.__class__.__name__}' object has no service named '{name}'")