File size: 3,352 Bytes
a8c7066
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import logging
from logging.handlers import TimedRotatingFileHandler
import os

from dotenv import load_dotenv

from src.adapters.outbound.embeddings.huggingface_embedding_adapter import HuggingFaceEmbeddingAdapter
from src.adapters.outbound.evaluation.noop_evaluation_adapter import NoOpEvaluationAdapter
from src.adapters.outbound.evaluation.ragas_evaluation_adapter import RagasEvaluationAdapter
from src.adapters.outbound.llm.gemini_llm_adapter import GeminiLlmAdapter
from src.adapters.outbound.llm.rag_prompt_builder_adapter import RagPromptBuilderAdapter
from src.adapters.outbound.observability.langfuse_observability_adapter import LangfuseObservabilityAdapter
from src.adapters.outbound.observability.logging_observability_adapter import LoggingObservabilityAdapter
from src.adapters.outbound.vectorstore.chroma_retrieval_adapter import NativeRetrievalAdapter
from src.application.use_cases.ask_question import AskQuestionService
from src.application.use_cases.submit_feedback import SubmitFeedbackService
from src.config.default_answer import DEFAULT_ANSWER


class Container:
    def __init__(self) -> None:
        load_dotenv()
        # 1. Création du handler quotidien
        handler = TimedRotatingFileHandler(
            filename=os.getenv("LOG_FILE", "./logs/app.log"),
            when="midnight",
            interval=1,
            backupCount=15,
            encoding="utf-8"
        )

        # 2. Configuration globale via basicConfig
        logging.basicConfig(
            level=logging.INFO,
            format="%(asctime)s - %(name)s - [%(levelname)s] - %(message)s",
            handlers=[handler]
        )

        embeddings = HuggingFaceEmbeddingAdapter()
        retrieval = NativeRetrievalAdapter(embedding_port=embeddings)
        prompt_builder = RagPromptBuilderAdapter()
        llm = GeminiLlmAdapter(prompt_builder=prompt_builder)
        observability = self._build_observability_adapter()
        evaluation = self._build_evaluation_adapter(observability, embeddings)

        self.ask_question = AskQuestionService(
            retrieval_port=retrieval,
            llm_port=llm,
            observability_port=observability,
            default_answer=os.getenv("DEFAULT_ANSWER", DEFAULT_ANSWER),
            evaluation_port=evaluation,
        )
        self.submit_feedback = SubmitFeedbackService(observability_port=observability)

    def _build_observability_adapter(self):
        if os.getenv("LANGFUSE_PUBLIC_KEY") and os.getenv("LANGFUSE_SECRET_KEY"):
            return LangfuseObservabilityAdapter()
        return LoggingObservabilityAdapter()

    def _build_evaluation_adapter(self, observability, embeddings):
        if os.getenv("ENABLE_RAGAS_EVAL", "true").lower() != "true":
            return NoOpEvaluationAdapter()

        try:
            ragas_llm_name = os.getenv("RAGAS_LLM_MODEL_NAME", "gpt-4o-mini")
            return RagasEvaluationAdapter(
                observability_port=observability,
                llm_name=ragas_llm_name,
                embedding_model_name=embeddings.get_model_name()
            )
        except Exception as exc:
            logging.getLogger("chatbot.backend.container").warning(
                "ragas.adapter.init_failed: %s",
                exc,
                exc_info=True,
            )
            return NoOpEvaluationAdapter()